From e5cc2f68ddd879a45905cdcced27e9b673f3bc6b Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Wed, 4 Mar 2026 11:46:34 +0100 Subject: [PATCH] feat: persistent Db manager state in URI (#8134) * DB Manager state in URL * Fix state not saving * shorted uri params * infer db_type from prefix * Revert "infer db_type from prefix" This reverts commit 7415fbed3db0d570f321a0b86e0c5db6e876b430. * dbm syntax * infer database type * Omit main and public * remove legacy #dbmanager: * Preserve hash * nit * Fix remaining dbManagerDrawer objects --- .../src/lib/components/DBManagerDrawer.svelte | 77 +++---- .../src/lib/components/DatatablePicker.svelte | 5 +- .../src/lib/components/DucklakePicker.svelte | 5 +- .../lib/components/ExploreAssetButton.svelte | 7 +- .../src/lib/components/ResourcePicker.svelte | 4 +- frontend/src/lib/components/RunsPage.svelte | 4 +- .../lib/components/assets/AssetButtons.svelte | 3 - .../assets/AssetsDropdownButton.svelte | 4 +- .../components/assets/JobAssetsViewer.svelte | 4 +- .../components/dbManagerDrawerModel.svelte.ts | 207 ++++++++++++++++++ .../graph/renderers/nodes/AssetNode.svelte | 3 +- .../components/sidebar/FavoriteMenu.svelte | 2 +- .../CustomInstanceDbSelect.svelte | 4 - .../CustomInstanceDbWizardModal.svelte | 3 - .../DataTableSettings.svelte | 6 +- .../workspaceSettings/DucklakeSettings.svelte | 5 +- frontend/src/lib/stores.ts | 5 +- frontend/src/lib/svelte5UtilsKit.svelte.ts | 5 +- .../src/routes/(root)/(logged)/+layout.svelte | 28 +-- .../(root)/(logged)/assets/+page.svelte | 3 - .../(root)/(logged)/resources/+page.svelte | 6 +- 21 files changed, 266 insertions(+), 124 deletions(-) create mode 100644 frontend/src/lib/components/dbManagerDrawerModel.svelte.ts diff --git a/frontend/src/lib/components/DBManagerDrawer.svelte b/frontend/src/lib/components/DBManagerDrawer.svelte index c5986e18a4..5996d98075 100644 --- a/frontend/src/lib/components/DBManagerDrawer.svelte +++ b/frontend/src/lib/components/DBManagerDrawer.svelte @@ -6,27 +6,20 @@ import DrawerContent from './common/drawer/DrawerContent.svelte' import Select from './select/Select.svelte' import { ArrowLeft, Expand, LoaderCircle, Minimize, RefreshCcw } from 'lucide-svelte' - import type { DbInput } from './dbTypes' import DBManagerContent from './DBManagerContent.svelte' import { resource } from 'runed' + import { untrack } from 'svelte' + import type { DbManagerUriState } from './dbManagerDrawerModel.svelte' interface Props { + uriState: DbManagerUriState /** Z-index offset for the drawer, useful when opening from within modals */ offset?: number } - let { offset = 0 }: Props = $props() + let { uriState, offset = 0 }: Props = $props() - let input: DbInput | undefined = $state() - let open = $derived(!!input) - - // For datatable inputs, track the selected datatable separately - let selectedDatatable = $state(undefined) - - // Check if input is a datatable type - const isDatatableInput = $derived( - input?.type === 'database' && input.resourcePath.startsWith('datatable://') - ) + let open = $derived(uriState.open) // Load available datatables when drawer opens with datatable input const datatables = resource([], async () => { @@ -39,16 +32,6 @@ } }) - // Computed input that updates when selectedDatatable changes - const effectiveInput: DbInput | undefined = $derived.by(() => { - if (!input) return undefined - if (!isDatatableInput || !selectedDatatable) return input - return { - ...input, - resourcePath: `datatable://${selectedDatatable}` - } - }) - const datatableItems = $derived( datatables.current.map((dt) => ({ value: dt, @@ -56,32 +39,26 @@ })) ) - export function openDrawer(nInput: DbInput) { - input = nInput - if (isDatatableInput) { - datatables.refetch() + // Refetch datatables when switching to a datatable input + $effect(() => { + if (uriState.isDatatableInput) { + untrack(() => datatables.refetch()) } - // If it's a datatable input, extract the datatable name for the selector - if (nInput.type === 'database' && nInput.resourcePath.startsWith('datatable://')) { - selectedDatatable = nInput.resourcePath.replace('datatable://', '') - datatables.refetch() - } else { - selectedDatatable = undefined - } - } - export function closeDrawer() { - input = undefined - selectedDatatable = undefined + }) + + function handleClose() { + uriState.closeDrawer() dbManagerContent?.clearReplResult() - if (window.location.hash.startsWith('#dbmanager:')) - history.replaceState('', document.title, window.location.href.replace(/#dbmanager:.*$/, '')) } let windowWidth = $state(window.innerWidth) let expand = $state(false) $effect(() => { - if (!open) expand = false + if (!open) { + expand = false + uriState.closeDrawer() + } }) let dbManagerContent: DBManagerContent | undefined = $state() @@ -96,7 +73,7 @@ size={expand ? `${windowWidth}px` : '1200px'} preventEscape {offset} - on:close={closeDrawer} + on:close={handleClose} > - {#if effectiveInput && $workspaceStore} - {#key selectedDatatable} - + {#if uriState.effectiveInput && $workspaceStore} + {#key uriState.selectedDatatable} + {#snippet dbSelector()} - {#if isDatatableInput} + {#if uriState.isDatatableInput} {#if datatables.loading}
@@ -125,7 +108,7 @@