From 295264deed371ebbfd48677cf33da4b8ee9421b1 Mon Sep 17 00:00:00 2001 From: Johnson Kwok <78053898+johnson-mage@users.noreply.github.com> Date: Thu, 25 Apr 2024 14:14:59 -0700 Subject: [PATCH] [jk] Allow disabling pipeline autosave (#4988) * [jk] Fix linting * [jk] Add file header menu item for disabling autosave --- .../MultiColumnController/index.style.tsx | 2 +- .../FileHeaderMenu/FileHeaderMenuItem.tsx | 4 ++- .../PipelineDetail/FileHeaderMenu/index.tsx | 26 ++++++++++++------- .../PipelineDetail/StatusFooter/index.tsx | 12 +++------ .../components/PipelineDetail/index.tsx | 5 +++- .../pages/pipelines/[pipeline]/edit.tsx | 21 +++++++++++++-- mage_ai/frontend/storage/constants.ts | 1 + 7 files changed, 48 insertions(+), 23 deletions(-) diff --git a/mage_ai/frontend/components/MultiColumnController/index.style.tsx b/mage_ai/frontend/components/MultiColumnController/index.style.tsx index 64a7e4599f00..eef8688a46fe 100644 --- a/mage_ai/frontend/components/MultiColumnController/index.style.tsx +++ b/mage_ai/frontend/components/MultiColumnController/index.style.tsx @@ -5,7 +5,7 @@ import { DRAGGABLE_WIDTH as DRAGGABLE_WIDTH_INIT } from '@components/TripleLayou import { transition } from '@oracle/styles/mixins'; import { ScrollbarStyledCss } from '@oracle/styles/scrollbars'; -export const DRAGGABLE_WIDTH = DRAGGABLE_WIDTH_INIT +export const DRAGGABLE_WIDTH = DRAGGABLE_WIDTH_INIT; export const DIVIDER_WIDTH = 2; export const ColumnStyle = styled.div<{ diff --git a/mage_ai/frontend/components/PipelineDetail/FileHeaderMenu/FileHeaderMenuItem.tsx b/mage_ai/frontend/components/PipelineDetail/FileHeaderMenu/FileHeaderMenuItem.tsx index 49821f108495..eef7e5b49ef3 100644 --- a/mage_ai/frontend/components/PipelineDetail/FileHeaderMenu/FileHeaderMenuItem.tsx +++ b/mage_ai/frontend/components/PipelineDetail/FileHeaderMenu/FileHeaderMenuItem.tsx @@ -11,6 +11,8 @@ type FileHeaderMenuItemProps = { muted?: boolean; }; +export const blankIcon =
; + function FileHeaderMenuItem({ beforeIcon, checked, @@ -23,7 +25,7 @@ function FileHeaderMenuItem({ ? beforeIcon : (checked ? - :
+ : blankIcon ) } diff --git a/mage_ai/frontend/components/PipelineDetail/FileHeaderMenu/index.tsx b/mage_ai/frontend/components/PipelineDetail/FileHeaderMenu/index.tsx index 10863e359ab1..966ec02a88fa 100644 --- a/mage_ai/frontend/components/PipelineDetail/FileHeaderMenu/index.tsx +++ b/mage_ai/frontend/components/PipelineDetail/FileHeaderMenu/index.tsx @@ -3,7 +3,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import Button from '@oracle/elements/Button'; import ClickOutside from '@oracle/components/ClickOutside'; import FlexContainer from '@oracle/components/FlexContainer'; -import FileHeaderMenuItem from './FileHeaderMenuItem'; +import FileHeaderMenuItem, { blankIcon } from './FileHeaderMenuItem'; import FlyoutMenu from '@oracle/components/FlyoutMenu'; import KernelOutputType from '@interfaces/KernelOutputType'; import PipelineType, { @@ -14,6 +14,7 @@ import Text from '@oracle/elements/Text'; import useKernel from '@utils/models/kernel/useKernel'; import useProject from '@utils/models/project/useProject'; import { + Check, LayoutSplit, LayoutStacked, } from '@oracle/icons'; @@ -31,7 +32,6 @@ import { KEY_CODE_ARROW_RIGHT, } from '@utils/hooks/keyboardShortcuts/constants'; import { SHARED_FILE_HEADER_BUTTON_PROPS } from './constants'; -import { ViewKeyEnum } from '@components/Sidekick/constants'; import { isMac } from '@utils/os'; import { randomNameGenerator } from '@utils/string'; import { useKeyboardContext } from '@context/Keyboard'; @@ -44,6 +44,7 @@ type FileHeaderMenuProps = { children?: any; collapseAllBlockOutputs?: (state: boolean) => void; createPipeline: (data: any) => void; + disableAutosave?: boolean; executePipeline: () => void; hideOutputOnExecution?: boolean; interruptKernel: () => void; @@ -52,16 +53,13 @@ type FileHeaderMenuProps = { restartKernel: () => void; savePipelineContent: () => void; scrollTogether?: boolean; - setActiveSidekickView: ( - newView: ViewKeyEnum, - pushHistory?: boolean, - ) => void; setMessages: (message: { [uuid: string]: KernelOutputType[]; }) => void; setScrollTogether?: (prev: any) => void; setSideBySideEnabled?: (prev: any) => void; sideBySideEnabled?: boolean; + toggleDisableAutosave?: () => void; toggleHideOutputOnExecution?: () => void; updatePipelineMetadata: (name: string, type?: string) => void; }; @@ -71,6 +69,7 @@ function FileHeaderMenu({ children, collapseAllBlockOutputs, createPipeline, + disableAutosave, executePipeline, hideOutputOnExecution, interruptKernel, @@ -79,11 +78,11 @@ function FileHeaderMenu({ restartKernel, savePipelineContent, scrollTogether, - setActiveSidekickView, setMessages, setScrollTogether, setSideBySideEnabled, sideBySideEnabled, + toggleDisableAutosave, toggleHideOutputOnExecution, updatePipelineMetadata, }: FileHeaderMenuProps) { @@ -102,6 +101,7 @@ function FileHeaderMenu({ const fileItems = [ { + beforeIcon: blankIcon, label: () => 'New standard pipeline', // @ts-ignore onClick: () => createPipeline({ @@ -112,6 +112,7 @@ function FileHeaderMenu({ uuid: 'new_standard_pipeline', }, { + beforeIcon: blankIcon, label: () => 'New streaming pipeline', // @ts-ignore onClick: () => createPipeline({ @@ -123,6 +124,7 @@ function FileHeaderMenu({ uuid: 'new_streaming_pipeline', }, { + beforeIcon: blankIcon, keyTextGroups: [[ isMac() ? KEY_SYMBOL_META : KEY_SYMBOL_CONTROL, KEY_SYMBOL_S, @@ -131,6 +133,12 @@ function FileHeaderMenu({ onClick: () => savePipelineContent(), uuid: 'save_pipeline', }, + { + beforeIcon: disableAutosave ? : blankIcon, + label: () => 'Disable autosave', + onClick: toggleDisableAutosave, + uuid: 'Disable_autosave', + }, ]; const runItems = useMemo(() => { const items = [ @@ -149,20 +157,20 @@ function FileHeaderMenu({ // uuid: 'Delete selected block', // }, { - label: () => 'Interrupt kernel', keyTextGroups: [ [KEY_SYMBOL_I], [KEY_SYMBOL_I], ], + label: () => 'Interrupt kernel', onClick: () => interruptKernel(), uuid: 'Interrupt kernel', }, { - label: () => 'Restart kernel', keyTextGroups: [ [KEY_CODE_NUMBERS_TO_NUMBER[KEY_CODE_NUMBER_0]], [KEY_CODE_NUMBERS_TO_NUMBER[KEY_CODE_NUMBER_0]], ], + label: () => 'Restart kernel', onClick: () => restartKernel(), uuid: 'Restart kernel', }, diff --git a/mage_ai/frontend/components/PipelineDetail/StatusFooter/index.tsx b/mage_ai/frontend/components/PipelineDetail/StatusFooter/index.tsx index c30f3ce0943b..e48334e268fa 100644 --- a/mage_ai/frontend/components/PipelineDetail/StatusFooter/index.tsx +++ b/mage_ai/frontend/components/PipelineDetail/StatusFooter/index.tsx @@ -1,11 +1,8 @@ import React from 'react'; -import moment from 'moment'; import { useMemo } from 'react'; import Divider from '@oracle/elements/Divider'; -import Flex from '@oracle/components/Flex'; import FlexContainer from '@oracle/components/FlexContainer'; -import KernelType from '@interfaces/KernelType'; import KeyboardText from '@oracle/elements/KeyboardText'; import Spacing from '@oracle/elements/Spacing'; import Text from '@oracle/elements/Text'; @@ -13,8 +10,6 @@ import Tooltip from '@oracle/components/Tooltip'; import useKernel from '@utils/models/kernel/useKernel'; import { AlertTriangle, File as FileIcon, HexagonAll, Lightning } from '@oracle/icons'; import { - KEY_CODE_ENTER, - KEY_CODE_META, KEY_SYMBOL_CONTROL, KEY_SYMBOL_META, KEY_SYMBOL_S, @@ -84,7 +79,6 @@ function StatusFooter({ - {usage && ( <> @@ -105,8 +99,8 @@ function StatusFooter({ small > CPU: = 90} + inline muted={cpu < 50} small warning={cpu >= 50 && cpu < 90} @@ -171,7 +165,7 @@ function StatusFooter({ - Or, go to + Or go to File {' › '} Save pipeline @@ -192,8 +186,8 @@ function StatusFooter({ )} {!pipelineContentTouched && ( )} diff --git a/mage_ai/frontend/components/PipelineDetail/index.tsx b/mage_ai/frontend/components/PipelineDetail/index.tsx index 523cced4d749..0349c2a553ae 100644 --- a/mage_ai/frontend/components/PipelineDetail/index.tsx +++ b/mage_ai/frontend/components/PipelineDetail/index.tsx @@ -125,6 +125,7 @@ type PipelineDetailProps = { }; dataProviders: DataProviderType[]; deleteBlock: (block: BlockType) => Promise; + disableAutosave?: boolean; disableShortcuts: boolean; fetchFileTree: () => void; fetchPipeline: () => void; @@ -223,6 +224,7 @@ function PipelineDetail({ blocksThatNeedToRefresh, dataProviders, deleteBlock, + disableAutosave, disableShortcuts, fetchFileTree, fetchPipeline, @@ -679,7 +681,7 @@ df = get_variable('${pipeline.uuid}', '${block.uuid}', 'output_0') useEffect(() => { const autoSaveInterval = setInterval(() => { - if (pipelineContentTouched) { + if (pipelineContentTouched && !disableAutosave) { savePipelineContent(); } }, 1000 * 10); @@ -688,6 +690,7 @@ df = get_variable('${pipeline.uuid}', '${block.uuid}', 'output_0') clearInterval(autoSaveInterval); }; }, [ + disableAutosave, pipelineContentTouched, savePipelineContent, ]); diff --git a/mage_ai/frontend/pages/pipelines/[pipeline]/edit.tsx b/mage_ai/frontend/pages/pipelines/[pipeline]/edit.tsx index 6ddc43054d9f..9032fce58df2 100644 --- a/mage_ai/frontend/pages/pipelines/[pipeline]/edit.tsx +++ b/mage_ai/frontend/pages/pipelines/[pipeline]/edit.tsx @@ -98,6 +98,7 @@ import { DEBUG } from '@utils/environment'; import { ErrorProvider } from '@context/Error'; import { INTERNAL_OUTPUT_REGEX } from '@utils/models/output'; import { + LOCAL_STORAGE_KEY_DISABLE_AUTOSAVE, LOCAL_STORAGE_KEY_PIPELINE_EDIT_BEFORE_TAB_SELECTED, LOCAL_STORAGE_KEY_PIPELINE_EDIT_BLOCK_OUTPUT_LOGS, LOCAL_STORAGE_KEY_PIPELINE_EDIT_HIDDEN_BLOCKS, @@ -489,6 +490,17 @@ function PipelineDetailPage({ hideBlockOutputOnExecutionUpdated, ); }, [hideBlockOutputOnExecution]); + const [disableAutosave, setDisableAutosave] = useState( + get(LOCAL_STORAGE_KEY_DISABLE_AUTOSAVE, false), + ); + const toggleDisableAutosave = useCallback(() => { + const disableAutosaveUpdated = !disableAutosave; + setDisableAutosave(disableAutosaveUpdated); + set( + LOCAL_STORAGE_KEY_DISABLE_AUTOSAVE, + disableAutosaveUpdated, + ); + }, [disableAutosave]); const dispatchEventChanged = useCallback(() => { const evt = new CustomEvent(CUSTOM_EVENT_CODE_BLOCK_CHANGED, { @@ -3119,6 +3131,7 @@ function PipelineDetailPage({ blocksThatNeedToRefresh={blocksThatNeedToRefresh} dataProviders={dataProviders} deleteBlock={deleteBlock} + disableAutosave={disableAutosave} disableShortcuts={disableShortcuts} fetchFileTree={fetchFiles} fetchPipeline={fetchPipeline} @@ -3126,9 +3139,9 @@ function PipelineDetailPage({ files={files} globalDataProducts={globalDataProducts} globalVariables={globalVariables} - hideOutputOnExecution={hideBlockOutputOnExecution} // @ts-ignore hiddenBlocks={hiddenBlocks} + hideOutputOnExecution={hideBlockOutputOnExecution} interactionsMapping={interactionsMapping} interruptKernel={interruptKernel} mainContainerRef={mainContainerRef} @@ -3185,6 +3198,7 @@ function PipelineDetailPage({ blocksThatNeedToRefresh, dataProviders, deleteBlock, + disableAutosave, disableShortcuts, fetchFiles, fetchPipeline, @@ -3236,6 +3250,7 @@ function PipelineDetailPage({ @@ -3257,6 +3272,7 @@ function PipelineDetailPage({ }, [ cancelPipeline, createPipeline, + disableAutosave, executePipeline, hideBlockOutputOnExecution, interruptKernel, @@ -3270,6 +3286,7 @@ function PipelineDetailPage({ setScrollTogether, setSideBySideEnabled, sideBySideEnabled, + toggleDisableAutosave, toggleHideBlockOutputOnExecution, updatePipelineMetadata, ]); diff --git a/mage_ai/frontend/storage/constants.ts b/mage_ai/frontend/storage/constants.ts index 50587531e3ba..8aefc7caa406 100644 --- a/mage_ai/frontend/storage/constants.ts +++ b/mage_ai/frontend/storage/constants.ts @@ -23,3 +23,4 @@ export const LOCAL_STORAGE_KEY_INCLUDE_SERVER_TIME_SECONDS = export const LOCAL_STORAGE_KEY_PIPELINE_EDITOR_SIDE_BY_SIDE_ENABLED = 'pipeline_editor_side_by_side_enabled'; export const LOCAL_STORAGE_KEY_PIPELINE_EDITOR_SIDE_BY_SIDE_SCROLL_TOGETHER = 'pipeline_editor_side_by_side_scroll_together'; export const LOCAL_STORAGE_KEY_HIDE_BLOCK_OUTPUT_ON_EXECUTION = 'hide_block_output_on_execution'; +export const LOCAL_STORAGE_KEY_DISABLE_AUTOSAVE = 'disable_autosave';