From 4c70df51d5186db029e4e946670a5c16aca1379a Mon Sep 17 00:00:00 2001 From: Myles Scolnick Date: Wed, 15 Jan 2025 11:18:42 -0500 Subject: [PATCH 1/2] feat: re-run all cells action (useful for external queries/dashboards) --- .../components/editor/actions/useNotebookActions.tsx | 10 ++++++++++ frontend/src/components/editor/cell/useRunCells.ts | 8 +++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/editor/actions/useNotebookActions.tsx b/frontend/src/components/editor/actions/useNotebookActions.tsx index aeaf79572dd..1430de370ef 100644 --- a/frontend/src/components/editor/actions/useNotebookActions.tsx +++ b/frontend/src/components/editor/actions/useNotebookActions.tsx @@ -29,6 +29,7 @@ import { SettingsIcon, XCircleIcon, FilePlus2Icon, + FastForwardIcon, } from "lucide-react"; import { commandPaletteAtom } from "../controls/command-palette"; import { @@ -69,6 +70,7 @@ import { settingDialogAtom } from "@/components/app-config/app-config-button"; import { renderShortcut } from "@/components/shortcuts/renderShortcut"; import { copyToClipboard } from "@/utils/copy"; import { newNotebookURL } from "@/utils/urls"; +import { useRunAllCells } from "../cell/useRunCells"; const NOOP_HANDLER = (event?: Event) => { event?.preventDefault(); @@ -86,6 +88,7 @@ export function useNotebookActions() { const { updateCellConfig, undoDeleteCell, clearAllCellOutputs } = useCellActions(); const restartKernel = useRestartKernel(); + const runAllCells = useRunAllCells(); const copyNotebook = useCopyNotebook(filename); const setCommandPaletteOpen = useSetAtom(commandPaletteAtom); const setSettingsDialogOpen = useSetAtom(settingDialogAtom); @@ -357,6 +360,13 @@ export function useNotebookActions() { clearAllCellOutputs(); }, }, + { + icon: , + label: "Re-run all cells", + handle: async () => { + runAllCells(); + }, + }, { icon: , label: "Undo cell deletion", diff --git a/frontend/src/components/editor/cell/useRunCells.ts b/frontend/src/components/editor/cell/useRunCells.ts index 8693bb2839c..f8856c9173e 100644 --- a/frontend/src/components/editor/cell/useRunCells.ts +++ b/frontend/src/components/editor/cell/useRunCells.ts @@ -5,7 +5,7 @@ import { getNotebook, useCellActions } from "@/core/cells/cells"; import useEvent from "react-use-event-hook"; import { getEditorCodeAsPython } from "@/core/codemirror/language/utils"; import { Logger } from "@/utils/Logger"; -import { staleCellIds } from "@/core/cells/utils"; +import { enabledCellIds, staleCellIds } from "@/core/cells/utils"; /** * Creates a function that runs all cells that have been edited or interrupted. @@ -30,6 +30,12 @@ export function useRunCell(cellId: CellId | undefined) { return runCell; } +export function useRunAllCells() { + const runCells = useRunCells(); + const runAllCells = useEvent(() => runCells(enabledCellIds(getNotebook()))); + return runAllCells; +} + /** * Creates a function that runs the given cells. */ From a8e7e0aa0e736bd7c6d611595327f6ee1e26d49b Mon Sep 17 00:00:00 2001 From: Myles Scolnick Date: Wed, 15 Jan 2025 11:43:08 -0500 Subject: [PATCH 2/2] allow empty hotkeys and setting them --- .../editor/actions/useNotebookActions.tsx | 1 + .../src/components/shortcuts/renderShortcut.tsx | 12 +++++++++--- frontend/src/core/edit-app.tsx | 9 ++++++++- frontend/src/core/hotkeys/hotkeys.ts | 14 ++++++++++++++ frontend/src/core/hotkeys/shortcuts.ts | 10 +++++++++- 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/editor/actions/useNotebookActions.tsx b/frontend/src/components/editor/actions/useNotebookActions.tsx index 1430de370ef..bed35d22886 100644 --- a/frontend/src/components/editor/actions/useNotebookActions.tsx +++ b/frontend/src/components/editor/actions/useNotebookActions.tsx @@ -363,6 +363,7 @@ export function useNotebookActions() { { icon: , label: "Re-run all cells", + hotkey: "global.runAll", handle: async () => { runAllCells(); }, diff --git a/frontend/src/components/shortcuts/renderShortcut.tsx b/frontend/src/components/shortcuts/renderShortcut.tsx index 3e6e1757ab8..f39b74dcfc1 100644 --- a/frontend/src/components/shortcuts/renderShortcut.tsx +++ b/frontend/src/components/shortcuts/renderShortcut.tsx @@ -1,5 +1,5 @@ /* Copyright 2024 Marimo. All rights reserved. */ -import type { HotkeyAction } from "@/core/hotkeys/hotkeys"; +import { type HotkeyAction, NOT_SET } from "@/core/hotkeys/hotkeys"; import { isPlatformMac } from "@/core/hotkeys/shortcuts"; import { Kbd } from "../ui/kbd"; import { DropdownMenuShortcut } from "../ui/dropdown-menu"; @@ -29,8 +29,11 @@ const Shortcut: React.FC<{ shortcut: HotkeyAction; includeName?: boolean }> = ({ export const KeyboardHotkeys: React.FC<{ className?: string; - shortcut: string; + shortcut: string | typeof NOT_SET; }> = ({ shortcut, className }) => { + if (shortcut === NOT_SET || shortcut === "") { + return ; + } const keys = shortcut.split("-"); return ( @@ -71,8 +74,11 @@ export const MinimalShortcut: React.FC<{ export const MinimalHotkeys: React.FC<{ className?: string; - shortcut: string; + shortcut: string | typeof NOT_SET; }> = ({ shortcut, className }) => { + if (shortcut === NOT_SET || shortcut === "") { + return ; + } const keys = shortcut.split("-"); return ( diff --git a/frontend/src/core/edit-app.tsx b/frontend/src/core/edit-app.tsx index b36a37b3b68..8adc0539c23 100644 --- a/frontend/src/core/edit-app.tsx +++ b/frontend/src/core/edit-app.tsx @@ -22,7 +22,10 @@ import { CellArray } from "../components/editor/renderers/CellArray"; import { RuntimeState } from "./kernel/RuntimeState"; import { CellsRenderer } from "../components/editor/renderers/cells-renderer"; import { useAtomValue, useSetAtom } from "jotai"; -import { useRunStaleCells } from "../components/editor/cell/useRunCells"; +import { + useRunAllCells, + useRunStaleCells, +} from "../components/editor/cell/useRunCells"; import { cn } from "@/utils/cn"; import { useFilename } from "./saving/filename"; import { getSessionId } from "./kernel/session"; @@ -92,6 +95,7 @@ export const EditApp: React.FC = ({ userConfig, appConfig }) => { }, [appConfig.width, previousWidth, mergeAllColumns, numColumns]); const runStaleCells = useRunStaleCells(); + const runAllCells = useRunAllCells(); const togglePresenting = useTogglePresenting(); // HOTKEYS @@ -104,6 +108,9 @@ export const EditApp: React.FC = ({ userConfig, appConfig }) => { useHotkey("global.hideCode", () => { togglePresenting(); }); + useHotkey("global.runAll", () => { + runAllCells(); + }); const editableCellsArray = ( boolean { +export function parseShortcut( + shortcut: string | typeof NOT_SET, +): (e: KeyboardEvent) => boolean { + // Handle empty shortcut, e.g. not set + if (shortcut === NOT_SET || shortcut === "") { + return () => false; + } + const separator = shortcut.includes("+") ? "+" : "-"; const keys = shortcut.split(separator).map(normalizeKey); return (e: KeyboardEvent) => areKeysPressed(keys, e);