From 44aba60614ff3202b14ca4f45dfc5a6d7eb51cac Mon Sep 17 00:00:00 2001 From: Guilhem Date: Wed, 28 May 2025 17:55:04 +0200 Subject: [PATCH] Allow tabs to save state --- .../src/lib/components/FlowBuilder.svelte | 14 +++++- .../lib/components/common/tabs/Tabs.svelte | 16 +++++++ .../common/tabs/tabsState.svelte.ts | 47 +++++++++++++++++++ .../flows/content/FlowModuleComponent.svelte | 12 +++-- .../flows/edit/[...path]/+page.svelte | 4 ++ 5 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 frontend/src/lib/components/common/tabs/tabsState.svelte.ts diff --git a/frontend/src/lib/components/FlowBuilder.svelte b/frontend/src/lib/components/FlowBuilder.svelte index 0e3be901cb..52431ee1e8 100644 --- a/frontend/src/lib/components/FlowBuilder.svelte +++ b/frontend/src/lib/components/FlowBuilder.svelte @@ -88,6 +88,7 @@ setSplitPanesLayoutContext, type PanesLayout } from './splitPanes/SplitPanesLayout.svelte' + import { setTabStateContext, TabsState } from './common/tabs/tabsState.svelte' export let initialPath: string = '' export let pathStoreInit: string | undefined = undefined @@ -108,6 +109,7 @@ export let draftTriggersFromUrl: Trigger[] | undefined = undefined export let selectedTriggerIndexFromUrl: number | undefined = undefined export let savedSplitPanesLayout: Record | undefined = undefined + export let tabsStateFromUrl: Record | undefined = undefined let initialPathStore = writable(initialPath) $: initialPathStore.set(initialPath) @@ -143,12 +145,21 @@ const splitPanesLayout = new SplitPanesLayout(savedSplitPanesLayout ?? {}, saveSessionDraft) setSplitPanesLayoutContext(splitPanesLayout) + const tabsState = new TabsState(tabsStateFromUrl ?? {}, saveSessionDraft) + setTabStateContext(tabsState) + export function setSplitPanesLayout(layout: Record | undefined) { if (layout !== undefined) { splitPanesLayout.layout = layout } } + export function setTabsState(newTabsState: Record | undefined) { + if (newTabsState !== undefined) { + tabsState.selected = newTabsState + } + } + export function getInitialAndModifiedValues(): SavedAndModifiedValue { return { savedValue: savedFlow, @@ -506,7 +517,8 @@ selectedId: $selectedIdStore, draft_triggers: triggersState.getDraftTriggersSnapshot(), selected_trigger: triggersState.getSelectedTriggerSnapshot(), - split_panes_layout: splitPanesLayout.getLayoutSnapshot() + split_panes_layout: splitPanesLayout.getLayoutSnapshot(), + tabs_state: tabsState.getTabsStateSnapshot() }) ) } catch (err) { diff --git a/frontend/src/lib/components/common/tabs/Tabs.svelte b/frontend/src/lib/components/common/tabs/Tabs.svelte index 32017b3749..2c7eeb5c7d 100644 --- a/frontend/src/lib/components/common/tabs/Tabs.svelte +++ b/frontend/src/lib/components/common/tabs/Tabs.svelte @@ -12,6 +12,7 @@ import { createEventDispatcher } from 'svelte' import { twMerge } from 'tailwind-merge' import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted' + import { getTabStateContext, type TabsState } from './tabsState.svelte' const dispatch = createEventDispatcher() const dispatchIfMounted = createDispatcherIfMounted(dispatch) @@ -25,11 +26,14 @@ export let style = '' export let hashNavigation = false export let values: string[] | undefined = undefined + export let id: string | undefined = undefined // if provided, the tabs state will be stored in a parent context $: selected && updateSelected() const selectedStore = writable(selected) + let tabsState: TabsState | undefined = undefined + $: $selectedStore && dispatchIfMounted('selected', $selectedStore) $: hashValues = values ? values.map((x) => '#' + x) : undefined @@ -44,6 +48,9 @@ function updateSelected() { selectedStore.set(selected) + if (tabsState && id) { + tabsState.setSelected(id, selected) + } } function hashChange() { @@ -56,6 +63,15 @@ } } } + + if (id) { + tabsState = getTabStateContext() + console.log('dbg tabsState', tabsState) + const tabState = tabsState?.getSelected(id) + if (tabState) { + selected = tabState + } + } diff --git a/frontend/src/lib/components/common/tabs/tabsState.svelte.ts b/frontend/src/lib/components/common/tabs/tabsState.svelte.ts new file mode 100644 index 0000000000..8914c78608 --- /dev/null +++ b/frontend/src/lib/components/common/tabs/tabsState.svelte.ts @@ -0,0 +1,47 @@ +import { getContext, setContext } from 'svelte' + +const KEY = 'tabsState' + +export class TabsState { + #selected: Record = $state({}) + #changeCb: (() => void) | undefined = undefined + + constructor(selected: Record, changeCb?: () => void) { + this.#selected = selected + this.#changeCb = changeCb + } + + get selected() { + return this.#selected + } + + set selected(value: Record) { + this.#selected = value + this.#changeCb?.() + } + + setChangeCb(cb: () => void) { + this.#changeCb = cb + } + + getSelected(id: string) { + return this.#selected[id] + } + + setSelected(id: string, value: string) { + this.#selected[id] = value + this.#changeCb?.() + } + + getTabsStateSnapshot() { + return $state.snapshot(this.#selected) + } +} + +export function setTabStateContext(tabsState: TabsState) { + setContext(KEY, tabsState) +} + +export function getTabStateContext(): TabsState | undefined { + return getContext(KEY) +} diff --git a/frontend/src/lib/components/flows/content/FlowModuleComponent.svelte b/frontend/src/lib/components/flows/content/FlowModuleComponent.svelte index 5c64a3477f..90986d3053 100644 --- a/frontend/src/lib/components/flows/content/FlowModuleComponent.svelte +++ b/frontend/src/lib/components/flows/content/FlowModuleComponent.svelte @@ -456,7 +456,7 @@ - + {#if !preprocessorModule} Step Input {/if} @@ -512,7 +512,10 @@ bind:scriptProgress /> {:else if selected === 'advanced'} - + Retries {#if !$selectedId.includes('failure')} Runtime @@ -536,7 +539,10 @@ {/if} {#if advancedSelected === 'runtime'} - + Concurrency Timeout Priority diff --git a/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte index 0fad932fbf..cadf01914c 100644 --- a/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte @@ -65,6 +65,7 @@ let draftTriggersFromUrl: Trigger[] | undefined = undefined let selectedTriggerIndexFromUrl: number | undefined = undefined let splitPanesLayoutFromUrl: Record | undefined = undefined + let tabsStateFromUrl: Record | undefined = undefined let flowBuilder: FlowBuilder | undefined = undefined @@ -96,9 +97,11 @@ draftTriggersFromUrl = stateLoadedFromUrl.draft_triggers selectedTriggerIndexFromUrl = stateLoadedFromUrl.selected_trigger splitPanesLayoutFromUrl = stateLoadedFromUrl.split_panes_layout + tabsStateFromUrl = stateLoadedFromUrl.tabs_state flowBuilder?.setSplitPanesLayout(splitPanesLayoutFromUrl) flowBuilder?.setDraftTriggers(draftTriggersFromUrl) flowBuilder?.setSelectedTriggerIndex(selectedTriggerIndexFromUrl) + flowBuilder?.setTabsState(stateLoadedFromUrl.tabs_state) const selectedId = stateLoadedFromUrl?.selectedId ?? 'settings-metadata' const reloadAction = () => { stateLoadedFromUrl = undefined @@ -275,6 +278,7 @@ {savedPrimarySchedule} {draftTriggersFromUrl} {selectedTriggerIndexFromUrl} + {tabsStateFromUrl} bind:version bind:getInitialAndModifiedValues >