Skip to content

Commit 09e8669

Browse files
committed
timetravel with git -- fix jupyter
1 parent ac08e0f commit 09e8669

File tree

2 files changed

+61
-36
lines changed

2 files changed

+61
-36
lines changed

src/packages/frontend/frame-editors/time-travel-editor/view-document.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { fromJS } from "immutable";
22
import type { Document } from "@cocalc/sync/editor/generic/types";
33
import { filenameMode } from "@cocalc/frontend/file-associations";
4+
import parseIpynb from "@cocalc/jupyter/ipynb/parse";
45

56
export function isObjectDoc(path) {
67
/* not a great way to tell if json lines or text? */
@@ -13,16 +14,24 @@ export class ViewDocument implements Document {
1314
private str: string;
1415

1516
constructor(path: string, str: string) {
16-
this.str = str;
17-
if (isObjectDoc(path)) {
18-
const v: any[] = [];
17+
let s = str;
18+
let v: any[] | null = null;
19+
if (path.endsWith(".ipynb")) {
20+
// Jupyter is a bit weird -- we parse the string ipynb to our internal jsonl format,
21+
// then work with that exclusively, and ALSO make to_str() return that.
22+
if (str.trim()) {
23+
const { cells } = parseIpynb(str);
24+
v = Object.values(cells);
25+
s = v.map((x) => JSON.stringify(x)).join("\n");
26+
}
27+
} else if (isObjectDoc(path)) {
28+
v = [];
1929
for (const x of str.split("\n")) {
2030
v.push(JSON.parse(x));
2131
}
22-
this.v = v;
23-
} else {
24-
this.v = null;
2532
}
33+
this.str = s;
34+
this.v = v;
2635
}
2736

2837
apply_patch(_patch): any {

src/packages/frontend/frame-editors/whiteboard-editor/canvas.tsx

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,18 @@ export default function Canvas({
165165
}: Props) {
166166
const isMountedRef = useIsMountedRef();
167167
const frame = useFrameContext();
168+
// note -- if a whiteboard is embedded for view purposes, e.g., in TimeTravel,
169+
// then this is how we know, and in this case the frame.actions are NOT whiteboard
170+
// actions but something else.
171+
const isBoard =
172+
frame.path.endsWith(".board") || frame.path.endsWith(".slides");
168173
const editFocus = frame.desc.get("editFocus");
169174
const canvasScale = scale0 ?? fontSizeToZoom(font_size);
170175
if (!margin) {
171176
margin = getMargin(mainFrameType, presentation);
172177
}
173-
const RenderElt = readOnly ? RenderReadOnlyElement : RenderElement;
178+
const RenderElt =
179+
readOnly || !isBoard ? RenderReadOnlyElement : RenderElement;
174180

175181
const backgroundDivRef = useRef<any>(null);
176182

@@ -260,11 +266,11 @@ export default function Canvas({
260266
// ensure values are in valid range, if possible.
261267
left = Math.min(
262268
0,
263-
Math.max(x, -e.offsetWidth * scaleRef.current + rect.width)
269+
Math.max(x, -e.offsetWidth * scaleRef.current + rect.width),
264270
);
265271
top = Math.min(
266272
0,
267-
Math.max(y, -e.offsetHeight * scaleRef.current + rect.height)
273+
Math.max(y, -e.offsetHeight * scaleRef.current + rect.height),
268274
);
269275
} else {
270276
// don't bother with ensuring values in valid range; this happens,
@@ -337,13 +343,13 @@ export default function Canvas({
337343
{
338344
target: canvasRef,
339345
disabled: isNavigator,
340-
}
346+
},
341347
);
342348

343349
const innerCanvasRef = useRef<any>(null);
344350

345351
const transformsRef = useRef<Transforms>(
346-
getTransforms(elements, margin, presentation)
352+
getTransforms(elements, margin, presentation),
347353
);
348354

349355
// This must happen before the render, hence the useLayoutEffect
@@ -400,6 +406,7 @@ export default function Canvas({
400406
} | null>(null);
401407

402408
useEffect(() => {
409+
if (!isBoard) return;
403410
// clear selection rect when changing pages.
404411
setSelectRect(null);
405412
frame.actions.clearSelection(frame.id);
@@ -427,12 +434,12 @@ export default function Canvas({
427434
penCanvasParamsRef.current = {
428435
scale: getMaxCanvasSizeScale(
429436
penDPIFactor * rect.width,
430-
penDPIFactor * rect.height
437+
penDPIFactor * rect.height,
431438
),
432439
rect,
433440
};
434441
}
435-
if (presentation) {
442+
if (presentation && isBoard) {
436443
// always re-fit to screen on resize in presentation mode.
437444
frame.actions.fitToScreen(frame.id, true);
438445
}
@@ -460,8 +467,8 @@ export default function Canvas({
460467

461468
// If no set viewport, fit to screen.
462469
useEffect(() => {
463-
if (isNavigator) return;
464-
if (frame.desc.get("viewport") == null) {
470+
if (isNavigator || !isBoard) return;
471+
if (frame.desc.get("viewport") == null && isBoard) {
465472
// document was never opened before in this browser,
466473
// so fit to screen.
467474
frame.actions.fitToScreen(frame.id, true);
@@ -514,7 +521,7 @@ export default function Canvas({
514521
// on the page; also set fitToScreen back to false in
515522
// frame tree data.
516523
useLayoutEffect(() => {
517-
if (isNavigator || !frame.desc.get("fitToScreen")) return;
524+
if (isNavigator || !frame.desc.get("fitToScreen") || !isBoard) return;
518525
try {
519526
const viewport = getViewportData();
520527
if (viewport == null) return;
@@ -537,7 +544,7 @@ export default function Canvas({
537544
const s =
538545
Math.min(
539546
2 / factor,
540-
Math.max(MIN_ZOOM, fitRectToRect(rect, viewport).scale * canvasScale)
547+
Math.max(MIN_ZOOM, fitRectToRect(rect, viewport).scale * canvasScale),
541548
) * factor;
542549
scale.set(s);
543550
frame.actions.set_font_size(frame.id, zoomToFontSize(s));
@@ -556,7 +563,9 @@ export default function Canvas({
556563
}, [frame.desc.get("fitToScreen")]);
557564

558565
const edgeStart =
559-
selectedTool == "edge" ? (frame.desc.getIn(["edgeStart", "id"]) as string | undefined) : undefined;
566+
selectedTool == "edge"
567+
? (frame.desc.getIn(["edgeStart", "id"]) as string | undefined)
568+
: undefined;
560569

561570
let selectionHandled = false;
562571
function processElement(element, isNavRectangle = false) {
@@ -586,10 +595,11 @@ export default function Canvas({
586595
selected={selection?.has(element.id)}
587596
previewMode={previewMode}
588597
onClick={(e) => {
598+
if (!isBoard) return;
589599
frame.actions.setSelection(
590600
frame.id,
591601
element.id,
592-
e.altKey || e.shiftKey || e.metaKey ? "add" : "only"
602+
e.altKey || e.shiftKey || e.metaKey ? "add" : "only",
593603
);
594604
}}
595605
/>
@@ -751,7 +761,7 @@ export default function Canvas({
751761
// in the selection.
752762
// TODO: This could be optimized with better data structures...
753763
const selectedElements = elements.filter((element) =>
754-
selection.has(element.id)
764+
selection.has(element.id),
755765
);
756766
const selectedRects: Element[] = [];
757767
let multi: undefined | boolean = undefined;
@@ -796,7 +806,7 @@ export default function Canvas({
796806
{!isAllEdges && (
797807
<RenderElt element={element} canvasScale={canvasScale} focused />
798808
)}
799-
</Focused>
809+
</Focused>,
800810
);
801811
}
802812

@@ -817,7 +827,7 @@ export default function Canvas({
817827
elementsMap={elementsMap}
818828
transforms={transformsRef.current}
819829
zIndex={0}
820-
/>
830+
/>,
821831
);
822832
}
823833

@@ -836,6 +846,7 @@ export default function Canvas({
836846
onStop={(_, data) => {
837847
if (visible == null) return;
838848
const { x, y } = centerOfRect(visible);
849+
if (!isBoard) return;
839850
frame.actions.setViewportCenter(frame.id, {
840851
x: x + data.x,
841852
y: y + data.y,
@@ -860,10 +871,10 @@ export default function Canvas({
860871
background: "rgba(200,200,200,0.2)",
861872
},
862873
},
863-
true
874+
true,
864875
)}
865876
</div>
866-
</Draggable>
877+
</Draggable>,
867878
);
868879
}
869880
}
@@ -890,7 +901,7 @@ export default function Canvas({
890901
function windowToData({ x, y }: Point): Point {
891902
return transformsRef.current.windowToDataNoScale(
892903
x / scaleRef.current,
893-
y / scaleRef.current
904+
y / scaleRef.current,
894905
);
895906
}
896907
function dataToWindow({ x, y }: Point): Point {
@@ -991,6 +1002,7 @@ export default function Canvas({
9911002
const saveViewport = isNavigator
9921003
? () => {}
9931004
: useMemo(() => {
1005+
if (!isBoard) return () => {};
9941006
return throttle(() => {
9951007
const viewport = getViewportData();
9961008
if (viewport) {
@@ -1069,7 +1081,7 @@ export default function Canvas({
10691081
const p1 = mousePath.current[1];
10701082
const rect = pointsToRect(
10711083
transformsRef.current.windowToDataNoScale(p0.x, p0.y),
1072-
transformsRef.current.windowToDataNoScale(p1.x, p1.y)
1084+
transformsRef.current.windowToDataNoScale(p1.x, p1.y),
10731085
);
10741086
if (selectedTool == "frame") {
10751087
// make a frame at the selection.
@@ -1085,7 +1097,7 @@ export default function Canvas({
10851097
frame.actions.createElement(
10861098
frame.id,
10871099
{ ...elt, ...rect, z: transformsRef.current.zMin - 1 },
1088-
true
1100+
true,
10891101
);
10901102
frame.actions.setSelectedTool(frame.id, "select");
10911103
// NOTE: we do NOT do "frame.actions.setSelection(frame.id, id);"
@@ -1176,7 +1188,7 @@ export default function Canvas({
11761188
data: { path: compressPath(path), ...getToolElement("pen").data },
11771189
type: "pen",
11781190
},
1179-
true
1191+
true,
11801192
);
11811193

11821194
return;
@@ -1204,7 +1216,7 @@ export default function Canvas({
12041216
e: {
12051217
clientX: number;
12061218
clientY: number;
1207-
} | null
1219+
} | null,
12081220
): { x: number; y: number } | undefined {
12091221
if (e == null) return;
12101222
const c = canvasRef.current;
@@ -1291,7 +1303,7 @@ export default function Canvas({
12911303
const path: Point[] = [];
12921304
const { rect } = penCanvasParamsRef.current;
12931305
for (const point of penPreviewPath.current.slice(
1294-
penPreviewPath.current.length - 2
1306+
penPreviewPath.current.length - 2,
12951307
)) {
12961308
path.push({
12971309
x: (point.x - rect.left) / penDPIFactor,
@@ -1328,7 +1340,7 @@ export default function Canvas({
13281340
if (point == null) return;
13291341
const { x, y } = transformsRef.current.windowToDataNoScale(
13301342
point.x,
1331-
point.y
1343+
point.y,
13321344
);
13331345
const size = Math.max(2, ERASE_SIZE / scaleRef.current);
13341346
const rect = {
@@ -1341,6 +1353,10 @@ export default function Canvas({
13411353
}
13421354
};
13431355

1356+
if (isNavigator && !isBoard) {
1357+
return null;
1358+
}
1359+
13441360
// if (!isNavigator) {
13451361
// window.x = {
13461362
// scaleDivRef,
@@ -1419,7 +1435,7 @@ export default function Canvas({
14191435
const encoded = encodeForCopy(selectedElements);
14201436
event.clipboardData.setData(
14211437
"application/x-cocalc-whiteboard",
1422-
encoded
1438+
encoded,
14231439
);
14241440
}
14251441
}
@@ -1437,7 +1453,7 @@ export default function Canvas({
14371453
const encoded = encodeForCopy(selectedElements);
14381454
event.clipboardData.setData(
14391455
"application/x-cocalc-whiteboard",
1440-
encoded
1456+
encoded,
14411457
);
14421458
frame.actions.deleteElements(selectedElements);
14431459
frame.actions.clearSelection(frame.id);
@@ -1449,7 +1465,7 @@ export default function Canvas({
14491465
: (event: ClipboardEvent<HTMLDivElement>) => {
14501466
if (editFocus) return;
14511467
const encoded = event.clipboardData.getData(
1452-
"application/x-cocalc-whiteboard"
1468+
"application/x-cocalc-whiteboard",
14531469
);
14541470
if (encoded) {
14551471
// copy/paste between whiteboards of their own structured data
@@ -1470,7 +1486,7 @@ export default function Canvas({
14701486
const ids = frame.actions.insertElements(
14711487
frame.id,
14721488
pastedElements,
1473-
target
1489+
target,
14741490
);
14751491
frame.actions.setSelectionMulti(frame.id, ids);
14761492
} else {
@@ -1584,7 +1600,7 @@ function getSelectedElements({
15841600

15851601
function getMargin(
15861602
mainFrameType: MainFrameType,
1587-
presentation?: boolean
1603+
presentation?: boolean,
15881604
): number {
15891605
if (presentation) {
15901606
return 0;

0 commit comments

Comments
 (0)