Files
cosmos-explorer/src/Explorer/Notebook/NotebookComponent/reducers.ts
Laurent Nguyen 861042c27e Fix bug publish screenshot (#762)
[Preview this branch](https://cosmos-explorer-preview.azurewebsites.net/pull/762?feature.someFeatureFlagYouMightNeed=true)

The main change in this PR fixes the snapshot functionality in the Publish pane-related components. Because the code cell outputs are now rendered in their own iframes for security reasons, a single snapshot of the notebook is no longer possible: each cell output takes its own snapshot and the snapshots are collated on the main notebook snapshot.
- Move the snapshot functionality to notebook components: this removes the reference of the notebook DOM node that we must pass to the Publish pane via explorer.
- Add slice in the state and actions in notebook redux for notebook snapshot requests and result
- Add post robot message to take snapshots and receive results
- Add logic in `NotebookRenderer` to wait for all output snapshots done before taking the main one collating.
- Use `zustand` to share snapshot between Redux world and React world. This solves the issue of keeping the `PanelContainer` component generic, while being able to update its children (`PublishPanel` component) with the new snapshot.

Additional changes:
- Add `local()` in `@font-face` to check if font is already installed before downloading the font (must be done for Safari, but not Edge/Chrome)
- Add "Export output to image" menu item in notebook cell, since each cell output can take its own snapshot (which can be downloaded)
![image](https://user-images.githubusercontent.com/21954022/117454706-b5f16600-af46-11eb-8535-6bf99f3d9170.png)
2021-05-11 18:24:05 +00:00

103 lines
3.4 KiB
TypeScript

import { actions, CoreRecord, reducers as nteractReducers } from "@nteract/core";
import { Action } from "redux";
import * as cdbActions from "./actions";
import { CdbRecord } from "./types";
export const coreReducer = (state: CoreRecord, action: Action) => {
let typedAction;
switch (action.type) {
case cdbActions.CLOSE_NOTEBOOK: {
typedAction = action as cdbActions.CloseNotebookAction;
return state.setIn(
["entities", "contents", "byRef"],
state.entities.contents.byRef.delete(typedAction.payload.contentRef)
);
}
case actions.CHANGE_KERNEL_BY_NAME: {
// Update content metadata
typedAction = action as actions.ChangeKernelByName;
const kernelSpecName = typedAction.payload.kernelSpecName;
if (!state.currentKernelspecsRef) {
return state;
}
const currentKernelspecs = state.entities.kernelspecs.byRef.get(state.currentKernelspecsRef);
if (!currentKernelspecs) {
return state;
}
// Find kernelspecs by name
const kernelspecs = currentKernelspecs.byName.get(kernelSpecName);
if (!kernelspecs) {
return state;
}
const path = [
"entities",
"contents",
"byRef",
typedAction.payload.contentRef,
"model",
"notebook",
"metadata",
"kernelspec",
];
// Update metadata
return state
.setIn(path.concat("name"), kernelspecs.name)
.setIn(path.concat("displayName"), kernelspecs.displayName)
.setIn(path.concat("language"), kernelspecs.language);
}
default:
return nteractReducers.core(state as any, action as any);
}
};
export const cdbReducer = (state: CdbRecord, action: Action) => {
if (!state) {
return null;
}
switch (action.type) {
case cdbActions.UPDATE_KERNEL_RESTART_DELAY: {
const typedAction = action as cdbActions.UpdateKernelRestartDelayAction;
return state.set("kernelRestartDelayMs", typedAction.payload.delayMs);
}
case cdbActions.SET_HOVERED_CELL: {
const typedAction = action as cdbActions.SetHoveredCellAction;
return state.set("hoveredCellId", typedAction.payload.cellId);
}
case cdbActions.STORE_CELL_OUTPUT_SNAPSHOT: {
const typedAction = action as cdbActions.StoreCellOutputSnapshotAction;
state.cellOutputSnapshots.set(typedAction.payload.cellId, typedAction.payload.snapshot);
// TODO Simpler datastructure to instantiate new Map?
return state.set("cellOutputSnapshots", new Map(state.cellOutputSnapshots));
}
case cdbActions.STORE_NOTEBOOK_SNAPSHOT: {
const typedAction = action as cdbActions.StoreNotebookSnapshotAction;
// Clear pending request
return state.set("notebookSnapshot", typedAction.payload).set("pendingSnapshotRequest", undefined);
}
case cdbActions.TAKE_NOTEBOOK_SNAPSHOT: {
const typedAction = action as cdbActions.TakeNotebookSnapshotAction;
// Clear previous snapshots
return state
.set("cellOutputSnapshots", new Map())
.set("notebookSnapshot", undefined)
.set("notebookSnapshotError", undefined)
.set("pendingSnapshotRequest", typedAction.payload);
}
case cdbActions.NOTEBOOK_SNAPSHOT_ERROR: {
const typedAction = action as cdbActions.NotebookSnapshotErrorAction;
return state.set("notebookSnapshotError", typedAction.payload.error);
}
}
return state;
};