@@ -30,6 +30,12 @@ import {
3030} from "@/lib/datahub/bigtable" ;
3131import { ingestToDatasetLane } from "@/lib/datahub/bigtable/ingest" ;
3232import { init as initBigTableEngine } from "@/lib/datahub/bigtable/duckdb-client" ;
33+ import {
34+ getViewModePref ,
35+ setViewModePref ,
36+ getLinkedDatasetId ,
37+ setLinkedDatasetId ,
38+ } from "@/lib/datahub/bigtable/view-mode-pref" ;
3339import DatasetView from "@/components/datahub/bigtable/DatasetView" ;
3440import TransformBuilder from "@/components/datahub/bigtable/TransformBuilder" ;
3541import ManualSwitchControl from "@/components/datahub/bigtable/ManualSwitchControl" ;
@@ -531,6 +537,47 @@ export default function DataHubPage() {
531537 setConfirmDeleteTableId ( null ) ;
532538 } , [ selectedTableId ] ) ;
533539
540+ // Restore the last-viewed mode when a table is opened. If the user previously
541+ // converted this table to a dataset and was last viewing the dataset, reopen
542+ // the dataset view automatically. The preference is stored in localStorage
543+ // keyed by owner+tableId, so it persists across nav-away and back without any
544+ // on-disk data-shape change. A missing or "editable" preference is a no-op.
545+ // This runs after the table-switch clear above so it is not overwritten.
546+ //
547+ // Tracking: restorePendingId captures a tableId that has a "dataset" pref but
548+ // whose catalog entry has not loaded yet. A follow-up datasets-change fires the
549+ // restore once the linked dataset appears. Cleared as soon as we act on it.
550+ const restorePendingId = useRef < string | null > ( null ) ;
551+ useEffect ( ( ) => {
552+ if ( ! bigTableOn || ! currentUser || selectedTableId == null ) return ;
553+ const pref = getViewModePref ( currentUser , selectedTableId ) ;
554+ if ( pref !== "dataset" ) return ;
555+ const linkedId = getLinkedDatasetId ( currentUser , selectedTableId ) ;
556+ if ( ! linkedId ) return ;
557+ if ( datasets . some ( ( d ) => d . id === linkedId ) ) {
558+ // Dataset catalog is already loaded: restore now.
559+ setSelectedTableId ( null ) ;
560+ setSelectedDatasetId ( linkedId ) ;
561+ restorePendingId . current = null ;
562+ } else {
563+ // Dataset catalog not yet loaded: park the request so the datasets effect
564+ // below can complete the restore once the catalog arrives.
565+ restorePendingId . current = selectedTableId ;
566+ }
567+ } , [ selectedTableId , currentUser , bigTableOn , datasets ] ) ;
568+
569+ // Complete a deferred mode restore once the dataset catalog has loaded.
570+ useEffect ( ( ) => {
571+ const tableId = restorePendingId . current ;
572+ if ( ! tableId || ! currentUser || ! bigTableOn || datasets . length === 0 ) return ;
573+ const linkedId = getLinkedDatasetId ( currentUser , tableId ) ;
574+ if ( ! linkedId ) return ;
575+ if ( ! datasets . some ( ( d ) => d . id === linkedId ) ) return ;
576+ restorePendingId . current = null ;
577+ setSelectedTableId ( null ) ;
578+ setSelectedDatasetId ( linkedId ) ;
579+ } , [ datasets , currentUser , bigTableOn ] ) ;
580+
534581 // Apply a pending `?analysis=<id>` deep link once the deep-linked doc's content
535582 // has loaded. This runs after the table-switch clear above, so the analysis the
536583 // run navigated to is what wins, and the user lands on its result sheet rather
@@ -1441,7 +1488,13 @@ export default function DataHubPage() {
14411488 // Success: flip to the dataset view and clear the loader.
14421489 setConvertBoot ( null ) ;
14431490 setSelectedTableId ( null ) ;
1444- if ( newId ) setSelectedDatasetId ( newId ) ;
1491+ if ( newId ) {
1492+ // Persist both the table->dataset link and the view-mode preference so
1493+ // that nav-back reopens the dataset view rather than the editable grid.
1494+ setLinkedDatasetId ( owner , meta . id , newId ) ;
1495+ setViewModePref ( owner , meta . id , "dataset" ) ;
1496+ setSelectedDatasetId ( newId ) ;
1497+ }
14451498 } catch {
14461499 // The error phase was already emitted to convertBoot; the loader shows a
14471500 // retry. Leave convertBoot set so the user sees it (cleared on retry/cancel).
@@ -1450,6 +1503,33 @@ export default function DataHubPage() {
14501503 }
14511504 } , [ bigTableOn , currentUser , openContent , selectedMeta , queryClient ] ) ;
14521505
1506+ // Switch back from the dataset view to the editable grid for the table that was
1507+ // previously converted. Reads the linked tableId from localStorage and restores
1508+ // it. Sets the view-mode preference to "editable" so nav-back stays on the grid.
1509+ // The editable cell store was never touched, so switching back is non-destructive.
1510+ const handleSwitchBack = useCallback ( ( ) => {
1511+ if ( ! currentUser || ! selectedDatasetId ) return ;
1512+ // Find the editable tableId that links to this dataset.
1513+ const table = allTables . find (
1514+ ( t ) => getLinkedDatasetId ( currentUser , t . id ) === selectedDatasetId ,
1515+ ) ;
1516+ if ( ! table ) return ;
1517+ setViewModePref ( currentUser , table . id , "editable" ) ;
1518+ setSelectedDatasetId ( null ) ;
1519+ setSelectedTableId ( table . id ) ;
1520+ } , [ currentUser , selectedDatasetId , allTables ] ) ;
1521+
1522+ // Whether the currently-open dataset has a linked editable table (i.e. the user
1523+ // can switch back). Used to show/hide the switch-back affordance.
1524+ const linkedEditableTable = useMemo ( ( ) => {
1525+ if ( ! currentUser || ! selectedDatasetId ) return null ;
1526+ return (
1527+ allTables . find (
1528+ ( t ) => getLinkedDatasetId ( currentUser , t . id ) === selectedDatasetId ,
1529+ ) ?? null
1530+ ) ;
1531+ } , [ currentUser , selectedDatasetId , allTables ] ) ;
1532+
14531533 // The derived-table banner inputs. When the open table is derived, resolve its
14541534 // source meta from the catalog so the banner can name it and offer a jump to
14551535 // it. isDerived comes from the open content's link (the recompute path sets it),
@@ -2371,6 +2451,9 @@ export default function DataHubPage() {
23712451 } ) ;
23722452 setSelectedDatasetId ( null ) ;
23732453 } }
2454+ onSwitchToEditable = {
2455+ linkedEditableTable ? handleSwitchBack : undefined
2456+ }
23742457 />
23752458 )
23762459 ) : tablesInCollection . length === 0 && datasets . length === 0 ? (
0 commit comments