@marimo-team/islands 0.25.3-dev275 → 0.25.3-dev279

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/{ErrorBoundary-BuIXiuc5.js → ErrorBoundary-DmTMuDPR.js} +1 -1
  2. package/dist/{chat-ui-SZ6lSH52.js → chat-ui-v1Fdh0NA.js} +270 -270
  3. package/dist/{code-visibility-BEAPMrC-.js → code-visibility-Dw4-TXN0.js} +2 -2
  4. package/dist/{common-CEmzaoJ8.js → common-BXMFi4lr.js} +4947 -4943
  5. package/dist/{data-grid-overlay-editor-CUo25_W8.js → data-grid-overlay-editor-hZzwX7Ia.js} +1 -1
  6. package/dist/{error-entries-B-1yUdcH.js → error-entries-C1S-Rmyt.js} +545 -535
  7. package/dist/{feedback-button-BqiR7zMO.js → feedback-button-6Ui2TDLR.js} +5 -5
  8. package/dist/{glide-data-editor-B7dguvqk.js → glide-data-editor-PZNlrSDI.js} +3 -3
  9. package/dist/{globals-CYykXfGI.js → globals-DX6FPZYq.js} +1 -1
  10. package/dist/{html-to-image-DC_pmZLs.js → html-to-image-CqGUd58T.js} +14452 -14452
  11. package/dist/main.js +6031 -6036
  12. package/dist/{number-overlay-editor-C4u7SJAJ.js → number-overlay-editor-D0CsL3_R.js} +1 -1
  13. package/dist/{process-output-DYu84VfZ.js → process-output-DskX9jLa.js} +2 -2
  14. package/dist/{reveal-component-DGi-irHV.js → reveal-component-D7xeI1QR.js} +906 -906
  15. package/package.json +1 -1
  16. package/src/__mocks__/executions.ts +4 -2
  17. package/src/__mocks__/notebook.ts +0 -2
  18. package/src/__tests__/CellStatus.test.tsx +6 -6
  19. package/src/components/editor/__tests__/data-attributes.test.tsx +0 -2
  20. package/src/components/editor/__tests__/output-persistence.test.tsx +20 -5
  21. package/src/components/editor/cell/CellStatus.tsx +6 -5
  22. package/src/components/editor/cell/__tests__/useRunCells.test.tsx +169 -0
  23. package/src/components/editor/cell/collapse.tsx +3 -4
  24. package/src/components/editor/cell/useRunCells.ts +32 -3
  25. package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +2 -3
  26. package/src/components/editor/notebook-cell.tsx +23 -37
  27. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +4 -10
  28. package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +0 -2
  29. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +8 -5
  30. package/src/components/slides/minimap.tsx +3 -2
  31. package/src/components/slides/reveal-component.tsx +3 -2
  32. package/src/components/slides/slide-cell-view.tsx +8 -8
  33. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +0 -101
  34. package/src/core/cells/__tests__/actions.test.ts +0 -1
  35. package/src/core/cells/__tests__/cell.test.ts +81 -17
  36. package/src/core/cells/__tests__/cells.test.ts +0 -100
  37. package/src/core/cells/__tests__/document.test.ts +2 -8
  38. package/src/core/cells/__tests__/utils.test.ts +93 -24
  39. package/src/core/cells/actions.ts +0 -1
  40. package/src/core/cells/cell.ts +37 -14
  41. package/src/core/cells/cells.ts +10 -99
  42. package/src/core/cells/document.ts +2 -13
  43. package/src/core/cells/types.ts +0 -23
  44. package/src/core/cells/utils.ts +44 -17
  45. package/src/core/codemirror/cells/extensions.ts +0 -14
  46. package/src/core/errors/__tests__/error-entries.test.ts +40 -1
  47. package/src/core/errors/error-entries.ts +2 -3
  48. package/src/core/executions/__tests__/freshness.test.ts +420 -0
  49. package/src/core/executions/__tests__/hooks.test.tsx +106 -0
  50. package/src/core/executions/atoms.ts +22 -0
  51. package/src/core/executions/freshness.ts +164 -0
  52. package/src/core/executions/hooks.ts +17 -1
  53. package/src/core/executions/index.ts +3 -1
  54. package/src/core/islands/bootstrap.ts +0 -1
  55. package/src/core/kernel/handlers.ts +0 -4
  56. package/src/core/session/useNotebookSession.tsx +2 -7
  57. package/src/stories/cell-status.stories.tsx +12 -14
  58. package/src/stories/cell.stories.tsx +44 -10
  59. package/src/stories/layout/vertical/one-column.stories.tsx +0 -10
  60. package/src/components/editor/cell/__tests__/useRunCells.test.ts +0 -45
@@ -25,7 +25,11 @@ import { StopButton } from "@/components/editor/cell/StopButton";
25
25
  import { Toolbar, ToolbarItem } from "@/components/editor/cell/toolbar";
26
26
  import { Tooltip, TooltipProvider } from "@/components/ui/tooltip";
27
27
  import { aiCompletionCellAtom } from "@/core/ai/state";
28
- import { outputIsLoading, outputIsStale } from "@/core/cells/cell";
28
+ import {
29
+ consoleOutputIsStale,
30
+ outputIsLoading,
31
+ outputIsStale,
32
+ } from "@/core/cells/cell";
29
33
  import { isOutputEmpty } from "@/core/cells/outputs";
30
34
  import { useIsPendingCut } from "@/core/cells/pending-cut-service";
31
35
  import { autocompletionKeymap } from "@/core/codemirror/cm";
@@ -39,8 +43,10 @@ import { connectionAtom } from "@/core/network/connection";
39
43
  import { useRequestClient } from "@/core/network/requests";
40
44
  import {
41
45
  type CellExecutionView,
46
+ type CellFreshness,
42
47
  type CellRunStatus,
43
48
  useCellExecution,
49
+ useCellFreshness,
44
50
  } from "@/core/executions";
45
51
  import type { CellConfig } from "@/core/network/types";
46
52
  import { useResizeObserver } from "@/hooks/useResizeObserver";
@@ -320,6 +326,7 @@ const ReadonlyCellComponent = forwardRef(
320
326
  const cellData = useCellData(cellId);
321
327
  const cellRuntime = useCellRuntime(cellId);
322
328
  const execution = useCellExecution(cellId);
329
+ const freshness = useCellFreshness(cellId);
323
330
  const errored = execution.outcome === "error";
324
331
  const interrupted = execution.outcome === "interrupted";
325
332
  const stopped = execution.outcome === "skipped";
@@ -354,11 +361,7 @@ const ReadonlyCellComponent = forwardRef(
354
361
  className={CSSClasses.outputArea}
355
362
  cellId={cellId}
356
363
  output={cellRuntime.output}
357
- stale={outputIsStale(
358
- execution,
359
- cellRuntime.staleInputs,
360
- cellData.edited,
361
- )}
364
+ stale={outputIsStale(execution, freshness, true)}
362
365
  loading={outputIsLoading(execution.status)}
363
366
  />
364
367
  </div>
@@ -387,6 +390,7 @@ const EditableCellComponent = ({
387
390
  const cellData = useCellData(cellId);
388
391
  const cellRuntime = useCellRuntime(cellId);
389
392
  const execution = useCellExecution(cellId);
393
+ const freshness = useCellFreshness(cellId);
390
394
  const errored = execution.outcome === "error";
391
395
  const interrupted = execution.outcome === "interrupted";
392
396
  const stopped = execution.outcome === "skipped";
@@ -408,9 +412,8 @@ const EditableCellComponent = ({
408
412
  const uninstantiated = isUninstantiated(execution);
409
413
 
410
414
  const needsRun = cellNeedsRun({
411
- edited: cellData.edited,
415
+ freshness,
412
416
  interrupted,
413
- staleInputs: cellRuntime.staleInputs,
414
417
  disabled: cellData.config.disabled,
415
418
  blocked: execution.blocked,
416
419
  });
@@ -441,11 +444,7 @@ const EditableCellComponent = ({
441
444
 
442
445
  // console output is cleared immediately on run, so check for queued instead
443
446
  // of loading to determine staleness
444
- const consoleOutputStale =
445
- (execution.status === "queued" ||
446
- cellData.edited ||
447
- cellRuntime.staleInputs) &&
448
- !interrupted;
447
+ const consoleOutputStale = consoleOutputIsStale(execution, freshness);
449
448
 
450
449
  // This getter is called during render, so useEvent cannot be used here.
451
450
  // oxlint-disable-next-line react/preserve-manual-memoization
@@ -481,11 +480,7 @@ const EditableCellComponent = ({
481
480
  const hasOutput = !isOutputEmpty(cellRuntime.output);
482
481
  // While presenting, pending edits do not dim the output as stale,
483
482
  // matching the read view.
484
- const isStaleCell = outputIsStale(
485
- execution,
486
- cellRuntime.staleInputs,
487
- cellData.edited && !isPresenting,
488
- );
483
+ const isStaleCell = outputIsStale(execution, freshness, !isPresenting);
489
484
  const hasConsoleOutput = cellRuntime.consoleOutputs.length > 0;
490
485
  const cellOutput = userConfig.display.cell_output;
491
486
 
@@ -685,7 +680,7 @@ const EditableCellComponent = ({
685
680
  <StagedAIDeletionMarker cellId={cellId} />
686
681
  <div className="absolute right-2 -top-4 z-10">
687
682
  <CellToolbar
688
- edited={cellData.edited}
683
+ edited={freshness.sourceChanged}
689
684
  status={execution.status}
690
685
  blocked={execution.blocked}
691
686
  cellConfig={cellData.config}
@@ -725,12 +720,11 @@ const EditableCellComponent = ({
725
720
  className={cn(
726
721
  isMarkdownCodeHidden && cellOutput === "below" && "top-14",
727
722
  )}
728
- edited={cellData.edited}
729
723
  execution={execution}
724
+ freshness={freshness}
730
725
  isCellStatusInline={isCellStatusInline}
731
726
  uninstantiated={uninstantiated}
732
727
  disabled={cellData.config.disabled}
733
- staleInputs={cellRuntime.staleInputs}
734
728
  />
735
729
  )}
736
730
  <div className="shoulder-bottom hover-action">
@@ -860,29 +854,26 @@ const CellRightSideActions = memo(
860
854
  (props: {
861
855
  className?: string;
862
856
  disabled: boolean | undefined;
863
- edited: boolean;
864
857
  execution: CellExecutionView;
858
+ freshness: CellFreshness;
865
859
  isCellStatusInline: boolean;
866
- staleInputs: boolean;
867
860
  uninstantiated: boolean;
868
861
  }) => {
869
862
  const {
870
863
  className,
871
864
  disabled = false,
872
- edited,
873
865
  execution,
866
+ freshness,
874
867
  isCellStatusInline,
875
- staleInputs,
876
868
  uninstantiated,
877
869
  } = props;
878
870
 
879
871
  const cellStatusComponent = (
880
872
  <CellStatusComponent
881
873
  status={execution.status}
882
- staleInputs={staleInputs}
874
+ freshness={freshness}
883
875
  interrupted={execution.outcome === "interrupted"}
884
876
  editing={true}
885
- edited={edited}
886
877
  disabled={disabled}
887
878
  elapsedTime={execution.duration}
888
879
  startedAt={execution.startedAt}
@@ -1059,6 +1050,7 @@ const SetupCellComponent = ({
1059
1050
  const cellData = useCellData(cellId);
1060
1051
  const cellRuntime = useCellRuntime(cellId);
1061
1052
  const execution = useCellExecution(cellId);
1053
+ const freshness = useCellFreshness(cellId);
1062
1054
  const errored = execution.outcome === "error";
1063
1055
  const interrupted = execution.outcome === "interrupted";
1064
1056
  const stopped = execution.outcome === "skipped";
@@ -1076,9 +1068,8 @@ const SetupCellComponent = ({
1076
1068
  const uninstantiated = isUninstantiated(execution);
1077
1069
 
1078
1070
  const needsRun = cellNeedsRun({
1079
- edited: cellData.edited,
1071
+ freshness,
1080
1072
  interrupted,
1081
- staleInputs: cellRuntime.staleInputs,
1082
1073
  disabled: cellData.config.disabled,
1083
1074
  blocked: execution.blocked,
1084
1075
  });
@@ -1087,11 +1078,7 @@ const SetupCellComponent = ({
1087
1078
 
1088
1079
  // console output is cleared immediately on run, so check for queued instead
1089
1080
  // of loading to determine staleness
1090
- const consoleOutputStale =
1091
- (execution.status === "queued" ||
1092
- cellData.edited ||
1093
- cellRuntime.staleInputs) &&
1094
- !interrupted;
1081
+ const consoleOutputStale = consoleOutputIsStale(execution, freshness);
1095
1082
 
1096
1083
  // This getter is called during render, so useEvent cannot be used here.
1097
1084
  // oxlint-disable-next-line react/preserve-manual-memoization
@@ -1199,7 +1186,7 @@ const SetupCellComponent = ({
1199
1186
  <StagedAIDeletionMarker cellId={cellId} />
1200
1187
  <div className="absolute right-2 -top-4 z-10">
1201
1188
  <CellToolbar
1202
- edited={cellData.edited}
1189
+ edited={freshness.sourceChanged}
1203
1190
  status={execution.status}
1204
1191
  blocked={execution.blocked}
1205
1192
  cellConfig={cellData.config}
@@ -1237,12 +1224,11 @@ const SetupCellComponent = ({
1237
1224
  frame for running cells. */}
1238
1225
  {!isPresenting && (
1239
1226
  <CellRightSideActions
1240
- edited={cellData.edited}
1241
1227
  execution={execution}
1228
+ freshness={freshness}
1242
1229
  isCellStatusInline={false}
1243
1230
  uninstantiated={uninstantiated}
1244
1231
  disabled={cellData.config.disabled}
1245
- staleInputs={cellRuntime.staleInputs}
1246
1232
  />
1247
1233
  )}
1248
1234
  <div className="shoulder-bottom hover-action">
@@ -37,7 +37,7 @@ import { NumberField } from "@/components/ui/number-field";
37
37
  import { Switch } from "@/components/ui/switch";
38
38
  import { outputIsLoading, outputIsStale } from "@/core/cells/cell";
39
39
  import type { CellId } from "@/core/cells/ids";
40
- import { useCellExecution } from "@/core/executions";
40
+ import { useCellExecution, useCellFreshness } from "@/core/executions";
41
41
  import type { AppMode } from "@/core/mode";
42
42
  import { useIsDragging } from "@/hooks/useIsDragging";
43
43
  import { cn } from "@/utils/cn";
@@ -228,7 +228,6 @@ export const GridLayoutRenderer: React.FC<Props> = ({
228
228
  mode={mode}
229
229
  cellId={cell.id}
230
230
  output={cell.output}
231
- staleInputs={cell.staleInputs}
232
231
  hideWithoutValue={true}
233
232
  isScrollable={isScrollable}
234
233
  side={side}
@@ -294,7 +293,6 @@ export const GridLayoutRenderer: React.FC<Props> = ({
294
293
  mode={mode}
295
294
  cellId={cell.id}
296
295
  output={cell.output}
297
- staleInputs={cell.staleInputs}
298
296
  hideWithoutValue={false}
299
297
  isScrollable={false}
300
298
  />
@@ -363,7 +361,6 @@ export const GridLayoutRenderer: React.FC<Props> = ({
363
361
  mode={mode}
364
362
  cellId={cell.id}
365
363
  output={cell.output}
366
- staleInputs={cell.staleInputs}
367
364
  hideWithoutValue={false}
368
365
  isScrollable={false}
369
366
  />
@@ -375,10 +372,7 @@ export const GridLayoutRenderer: React.FC<Props> = ({
375
372
  );
376
373
  };
377
374
 
378
- interface GridCellProps extends Pick<
379
- CellRuntimeState,
380
- "output" | "staleInputs"
381
- > {
375
+ interface GridCellProps extends Pick<CellRuntimeState, "output"> {
382
376
  className?: string;
383
377
  code: string;
384
378
  cellId: CellId;
@@ -392,7 +386,6 @@ interface GridCellProps extends Pick<
392
386
  const GridCell = memo(
393
387
  ({
394
388
  output,
395
- staleInputs,
396
389
  cellId,
397
390
  mode,
398
391
  code,
@@ -402,8 +395,9 @@ const GridCell = memo(
402
395
  className,
403
396
  }: GridCellProps) => {
404
397
  const execution = useCellExecution(cellId);
398
+ const freshness = useCellFreshness(cellId);
405
399
  const loading = outputIsLoading(execution.status);
406
- const stale = outputIsStale(execution, staleInputs, false);
400
+ const stale = outputIsStale(execution, freshness, false);
407
401
  const hidden =
408
402
  hideWithoutValue &&
409
403
  execution.outcome !== null &&
@@ -13,8 +13,6 @@ function makeCell(id: string, code = "print('hi')"): CellData {
13
13
  id: cellId(id),
14
14
  name: id,
15
15
  code,
16
- edited: false,
17
- lastCodeRun: null,
18
16
  config: { hide_code: false, disabled: false, column: null },
19
17
  };
20
18
  }
@@ -32,7 +32,11 @@ import { getReadonlyCodeDisplay } from "@/core/cells/readonly-code-display";
32
32
  import { MarkdownLanguageAdapter } from "@/core/codemirror/language/languages/markdown";
33
33
  import { useResolvedMarimoConfig } from "@/core/config/config";
34
34
  import { CSSClasses } from "@/core/constants";
35
- import { runtimeStatusAtom, useCellExecution } from "@/core/executions";
35
+ import {
36
+ runtimeStatusAtom,
37
+ useCellExecution,
38
+ useCellFreshness,
39
+ } from "@/core/executions";
36
40
  import { useNotebookCodeAvailable } from "@/core/meta/code-visibility";
37
41
  import { showCodeInRunModeAtom } from "@/core/meta/state";
38
42
  import {
@@ -103,7 +107,6 @@ const VerticalLayoutRenderer: React.FC<VerticalLayoutProps> = ({
103
107
  cellOutputArea={userConfig.display.cell_output}
104
108
  showCode={showCode && canShowCode}
105
109
  mode={mode}
106
- staleInputs={cell.staleInputs}
107
110
  name={cell.name}
108
111
  kiosk={kioskMode}
109
112
  showErrorTracebacks={userConfig.runtime.show_tracebacks ?? false}
@@ -300,7 +303,7 @@ const ActionButtons: React.FC<{
300
303
 
301
304
  interface VerticalCellProps extends Pick<
302
305
  CellRuntimeState,
303
- "output" | "consoleOutputs" | "staleInputs"
306
+ "output" | "consoleOutputs"
304
307
  > {
305
308
  cellOutputArea: "above" | "below";
306
309
  cellId: CellId;
@@ -320,7 +323,6 @@ const VerticalCell = memo(
320
323
  cellOutputArea,
321
324
  cellId,
322
325
  config,
323
- staleInputs,
324
326
  code,
325
327
  showCode,
326
328
  mode,
@@ -330,11 +332,12 @@ const VerticalCell = memo(
330
332
  }: VerticalCellProps) => {
331
333
  const cellRef = useRef<HTMLDivElement>(null);
332
334
  const execution = useCellExecution(cellId);
335
+ const freshness = useCellFreshness(cellId);
333
336
  const errored = execution.outcome === "error";
334
337
  const interrupted = execution.outcome === "interrupted";
335
338
  const stopped = execution.outcome === "skipped";
336
339
 
337
- const outputStale = outputIsStale(execution, staleInputs, false);
340
+ const outputStale = outputIsStale(execution, freshness, false);
338
341
  const loading = outputIsLoading(execution.status);
339
342
 
340
343
  // Kiosk and not presenting
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { useDeleteCellCallback } from "@/components/editor/cell/useDeleteCell";
4
4
  import { outputIsStale } from "@/core/cells/cell";
5
- import { useCellExecution } from "@/core/executions";
5
+ import { useCellExecution, useCellFreshness } from "@/core/executions";
6
6
  import { useCellActions } from "@/core/cells/actions";
7
7
  import type { CellId } from "@/core/cells/ids";
8
8
  import { type CellColumnId, type Layout, useLayout } from "@/core/cells/layout";
@@ -629,6 +629,7 @@ const SlideThumbnailCard = ({
629
629
  }: SlideThumbnailCardProps) => {
630
630
  const { width, height, scale } = dimensions;
631
631
  const execution = useCellExecution(cell.id);
632
+ const freshness = useCellFreshness(cell.id);
632
633
  const visual = isNoOutput ? NO_OUTPUT_VISUAL : getSlideTypeVisual(slideType);
633
634
  const isSkipped = isNoOutput || slideType === "skip";
634
635
 
@@ -679,7 +680,7 @@ const SlideThumbnailCard = ({
679
680
  cellId={cell.id}
680
681
  status={execution.status}
681
682
  output={cell.output}
682
- stale={outputIsStale(execution, cell.staleInputs, false)}
683
+ stale={outputIsStale(execution, freshness, false)}
683
684
  />
684
685
  )}
685
686
  </div>
@@ -20,7 +20,7 @@ import { Button } from "@/components/ui/button";
20
20
  import { useFullScreenElement } from "@/components/ui/fullscreen";
21
21
  import { Tooltip } from "@/components/ui/tooltip";
22
22
  import { outputIsStale } from "@/core/cells/cell";
23
- import { useCellExecution } from "@/core/executions";
23
+ import { useCellExecution, useCellFreshness } from "@/core/executions";
24
24
  import type { CellId } from "@/core/cells/ids";
25
25
  import type { RuntimeCell } from "@/core/cells/types";
26
26
  import type { RevealApi, RevealConfig } from "reveal.js";
@@ -354,13 +354,14 @@ function resolveSlideContentStyle(
354
354
  */
355
355
  export const CellOutputBlock = ({ cell }: { cell: RuntimeCell }) => {
356
356
  const execution = useCellExecution(cell.id);
357
+ const freshness = useCellFreshness(cell.id);
357
358
  return (
358
359
  <div className="flex flex-col" {...cellDomProps(cell.id, cell.name)}>
359
360
  <CellOutputSlide
360
361
  cellId={cell.id}
361
362
  status={execution.status}
362
363
  output={cell.output}
363
- stale={outputIsStale(execution, cell.staleInputs, false)}
364
+ stale={outputIsStale(execution, freshness, false)}
364
365
  />
365
366
  </div>
366
367
  );
@@ -23,7 +23,7 @@ import {
23
23
  } from "@/core/cells/utils";
24
24
  import type { CellData, CellRuntimeState } from "@/core/cells/types";
25
25
  import type { LanguageAdapterType } from "@/core/codemirror/language/types";
26
- import { useCellExecution } from "@/core/executions";
26
+ import { useCellExecution, useCellFreshness } from "@/core/executions";
27
27
  import { connectionAtom } from "@/core/network/connection";
28
28
  import { useTheme } from "@/theme/useTheme";
29
29
  import { cn } from "@/utils/cn";
@@ -64,6 +64,7 @@ export const SlideCellView = ({ cell }: { cell: RuntimeCell }) => {
64
64
  const cellOutputPosition = userConfig.display.cell_output;
65
65
  const hasOutput = cell.output != null;
66
66
  const execution = useCellExecution(cell.id);
67
+ const freshness = useCellFreshness(cell.id);
67
68
  const errored = execution.outcome === "error";
68
69
  const interrupted = execution.outcome === "interrupted";
69
70
  const stopped = execution.outcome === "skipped";
@@ -71,9 +72,8 @@ export const SlideCellView = ({ cell }: { cell: RuntimeCell }) => {
71
72
  const uninstantiated = isUninstantiated(execution);
72
73
 
73
74
  const needsRun = cellNeedsRun({
74
- edited: cell.edited,
75
+ freshness,
75
76
  interrupted,
76
- staleInputs: cell.staleInputs,
77
77
  disabled: cell.config.disabled,
78
78
  blocked: execution.blocked,
79
79
  });
@@ -96,7 +96,7 @@ export const SlideCellView = ({ cell }: { cell: RuntimeCell }) => {
96
96
  cellId={cell.id}
97
97
  status={execution.status}
98
98
  output={cell.output}
99
- stale={outputIsStale(execution, cell.staleInputs, false)}
99
+ stale={outputIsStale(execution, freshness, false)}
100
100
  />
101
101
  );
102
102
 
@@ -106,8 +106,7 @@ export const SlideCellView = ({ cell }: { cell: RuntimeCell }) => {
106
106
  editing={true}
107
107
  status={execution.status}
108
108
  disabled={cell.config.disabled ?? false}
109
- staleInputs={cell.staleInputs}
110
- edited={cell.edited}
109
+ freshness={freshness}
111
110
  interrupted={interrupted}
112
111
  elapsedTime={execution.duration}
113
112
  startedAt={execution.startedAt}
@@ -123,7 +122,7 @@ export const SlideCellView = ({ cell }: { cell: RuntimeCell }) => {
123
122
  />
124
123
  <div className="flex items-center shadow-none gap-1">
125
124
  <RunButton
126
- edited={cell.edited}
125
+ edited={freshness.sourceChanged}
127
126
  status={execution.status}
128
127
  blocked={execution.blocked}
129
128
  needsRun={needsRun}
@@ -192,6 +191,7 @@ export const SlideCellReadOnlyView = ({ cell }: { cell: RuntimeCell }) => {
192
191
  const [userConfig] = useUserConfig();
193
192
  const cellOutputPosition = userConfig.display.cell_output;
194
193
  const execution = useCellExecution(cell.id);
194
+ const freshness = useCellFreshness(cell.id);
195
195
 
196
196
  const display = useMemo(() => getReadonlyCodeDisplay(cell.code), [cell.code]);
197
197
 
@@ -200,7 +200,7 @@ export const SlideCellReadOnlyView = ({ cell }: { cell: RuntimeCell }) => {
200
200
  cellId={cell.id}
201
201
  status={execution.status}
202
202
  output={cell.output}
203
- stale={outputIsStale(execution, cell.staleInputs, false)}
203
+ stale={outputIsStale(execution, freshness, false)}
204
204
  />
205
205
  );
206
206