@deephaven/dashboard 1.10.2 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,7 +17,7 @@ export type DashboardProps = {
17
17
  hydrate?: PanelHydrateFunction;
18
18
  dehydrate?: PanelDehydrateFunction;
19
19
  /** Component to wrap each panel with */
20
- panelWrapper?: ComponentType;
20
+ panelWrapper?: ComponentType<React.PropsWithChildren<PanelProps>>;
21
21
  };
22
22
  export declare function Dashboard({ id, children, emptyDashboard, layoutConfig, layoutSettings, onLayoutConfigChange, onGoldenLayoutChange, onLayoutInitialized, fallbackComponent, hydrate, dehydrate, panelWrapper, }: DashboardProps): JSX.Element;
23
23
  export default Dashboard;
@@ -1 +1 @@
1
- {"version":3,"file":"Dashboard.d.ts","sourceRoot":"","sources":["../src/Dashboard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EACZ,KAAK,aAAa,EAClB,KAAK,yBAAyB,EAC9B,KAAK,aAAa,EAKnB,MAAM,OAAO,CAAC;AAEf,OAAO,YAAY,MAAM,0BAA0B,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,4BAA4B,CAAC;AAIpC,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,UAAU,EAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,kBAAkB,CAAC;AAW1B,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;IAC/C,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,UAAU,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5D,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,iBAAiB,CAAC,EAAE,yBAAyB,CAC3C,UAAU,GAAG,aAAa,CAAC,cAAc,CAAC,CAC3C,CAAC;IACF,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,SAAS,CAAC,EAAE,sBAAsB,CAAC;IAEnC,wCAAwC;IACxC,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B,CAAC;AAEF,wBAAgB,SAAS,CAAC,EACxB,EAAc,EACd,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,cAA6B,EAC7B,oBAAuC,EACvC,oBAAuC,EACvC,mBAAsC,EACtC,iBAAoC,EACpC,OAAO,EACP,SAAS,EACT,YAAY,GACb,EAAE,cAAc,GAAG,GAAG,CAAC,OAAO,CA2F9B;AAED,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"Dashboard.d.ts","sourceRoot":"","sources":["../src/Dashboard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EACZ,KAAK,aAAa,EAClB,KAAK,yBAAyB,EAC9B,KAAK,aAAa,EAKnB,MAAM,OAAO,CAAC;AAEf,OAAO,YAAY,MAAM,0BAA0B,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,4BAA4B,CAAC;AAIpC,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,UAAU,EAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,kBAAkB,CAAC;AAW1B,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;IAC/C,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,UAAU,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5D,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,iBAAiB,CAAC,EAAE,yBAAyB,CAC3C,UAAU,GAAG,aAAa,CAAC,cAAc,CAAC,CAC3C,CAAC;IACF,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,SAAS,CAAC,EAAE,sBAAsB,CAAC;IAEnC,wCAAwC;IACxC,YAAY,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC;CACnE,CAAC;AAEF,wBAAgB,SAAS,CAAC,EACxB,EAAc,EACd,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,cAA6B,EAC7B,oBAAuC,EACvC,oBAAuC,EACvC,mBAAsC,EACtC,iBAAoC,EACpC,OAAO,EACP,SAAS,EACT,YAAY,GACb,EAAE,cAAc,GAAG,GAAG,CAAC,OAAO,CA2F9B;AAED,eAAe,SAAS,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Dashboard.js","names":["React","useEffect","useMemo","useRef","useState","throttle","GoldenLayout","useResizeObserver","LayoutUtils","PanelPlaceholder","DashboardLayout","LayoutManagerContext","DashboardIdContext","FiberProvider","jsx","_jsx","jsxs","_jsxs","RESIZE_THROTTLE","DEFAULT_CALLBACK","undefined","EMPTY_OBJECT","Object","freeze","Dashboard","_ref","id","children","emptyDashboard","layoutConfig","layoutSettings","onLayoutConfigChange","onGoldenLayoutChange","onLayoutInitialized","fallbackComponent","hydrate","dehydrate","panelWrapper","layoutElement","isInitialized","setIsInitialized","layout","setLayout","initDashboard","current","config","_objectSpread","makeDefaultLayout","settings","assign","content","newLayout","onInit","off","on","setFallbackComponent","init","destroy","handleResize","isInitialised","updateSize","className","ref","Provider","value","onLayoutChange"],"sources":["../src/Dashboard.tsx"],"sourcesContent":["import React, {\n type ComponentType,\n type ForwardRefExoticComponent,\n type RefAttributes,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport throttle from 'lodash.throttle';\nimport GoldenLayout from '@deephaven/golden-layout';\nimport type { ItemConfig, Settings } from '@deephaven/golden-layout';\nimport { useResizeObserver } from '@deephaven/react-hooks';\nimport './layout/GoldenLayout.scss';\nimport LayoutUtils from './layout/LayoutUtils';\nimport PanelPlaceholder from './PanelPlaceholder';\nimport DashboardLayout from './DashboardLayout';\nimport {\n type PanelDehydrateFunction,\n type PanelHydrateFunction,\n type PanelProps,\n} from './DashboardPlugin';\nimport './Dashboard.scss';\nimport { LayoutManagerContext } from './layout';\nimport { DashboardIdContext } from './useDashboardId';\nimport { FiberProvider } from './useFiber';\n\nconst RESIZE_THROTTLE = 100;\n\nconst DEFAULT_CALLBACK = (): void => undefined;\n\nconst EMPTY_OBJECT = Object.freeze({});\n\nexport type DashboardProps = {\n id?: string;\n children?: React.ReactNode | React.ReactNode[];\n emptyDashboard?: React.ReactNode;\n layoutConfig?: ItemConfig[];\n layoutSettings?: Partial<Settings>;\n onLayoutConfigChange?: () => void;\n onGoldenLayoutChange?: (goldenLayout: GoldenLayout) => void;\n onLayoutInitialized?: () => void;\n fallbackComponent?: ForwardRefExoticComponent<\n PanelProps & RefAttributes<HTMLDivElement>\n >;\n hydrate?: PanelHydrateFunction;\n dehydrate?: PanelDehydrateFunction;\n\n /** Component to wrap each panel with */\n panelWrapper?: ComponentType;\n};\n\nexport function Dashboard({\n id = 'default',\n children,\n emptyDashboard,\n layoutConfig,\n layoutSettings = EMPTY_OBJECT,\n onLayoutConfigChange = DEFAULT_CALLBACK,\n onGoldenLayoutChange = DEFAULT_CALLBACK,\n onLayoutInitialized = DEFAULT_CALLBACK,\n fallbackComponent = PanelPlaceholder,\n hydrate,\n dehydrate,\n panelWrapper,\n}: DashboardProps): JSX.Element {\n const layoutElement = useRef<HTMLDivElement>(null);\n const [isInitialized, setIsInitialized] = useState(false);\n const [layout, setLayout] = useState<GoldenLayout>();\n\n useEffect(\n function initDashboard() {\n if (!layoutElement.current) {\n setLayout(undefined);\n return;\n }\n const config = {\n ...LayoutUtils.makeDefaultLayout(),\n };\n if (config.settings === undefined) {\n config.settings = {};\n }\n Object.assign(config.settings, layoutSettings);\n\n // Load our content later after plugins have registered\n config.content = [];\n\n const newLayout = new GoldenLayout(config, layoutElement.current);\n\n const onInit = (): void => {\n newLayout.off('initialised', onInit);\n setIsInitialized(true);\n };\n newLayout.on('initialised', onInit);\n\n if (fallbackComponent != null) {\n newLayout.setFallbackComponent(fallbackComponent);\n }\n\n newLayout.init();\n\n setLayout(newLayout);\n\n onGoldenLayoutChange(newLayout);\n\n return () => {\n newLayout.destroy();\n };\n },\n [\n layoutSettings,\n fallbackComponent,\n onGoldenLayoutChange,\n setIsInitialized,\n setLayout,\n ]\n );\n\n const handleResize = useMemo(\n () =>\n throttle(() => {\n if (layout != null && layout.isInitialised) {\n layout?.updateSize();\n }\n }, RESIZE_THROTTLE),\n [layout]\n );\n\n useResizeObserver(layoutElement.current, handleResize);\n\n return (\n <div className=\"dashboard-container w-100 h-100\">\n <div className=\"w-100 h-100\" ref={layoutElement} />\n {isInitialized && layout && (\n <LayoutManagerContext.Provider value={layout}>\n <DashboardIdContext.Provider value={id}>\n <FiberProvider>\n <DashboardLayout\n emptyDashboard={emptyDashboard}\n id={id}\n layout={layout}\n layoutConfig={layoutConfig}\n onLayoutChange={onLayoutConfigChange}\n onLayoutInitialized={onLayoutInitialized}\n hydrate={hydrate}\n dehydrate={dehydrate}\n panelWrapper={panelWrapper}\n >\n {children}\n </DashboardLayout>\n </FiberProvider>\n </DashboardIdContext.Provider>\n </LayoutManagerContext.Provider>\n )}\n </div>\n );\n}\n\nexport default Dashboard;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"Dashboard.js","names":["React","useEffect","useMemo","useRef","useState","throttle","GoldenLayout","useResizeObserver","LayoutUtils","PanelPlaceholder","DashboardLayout","LayoutManagerContext","DashboardIdContext","FiberProvider","jsx","_jsx","jsxs","_jsxs","RESIZE_THROTTLE","DEFAULT_CALLBACK","undefined","EMPTY_OBJECT","Object","freeze","Dashboard","_ref","id","children","emptyDashboard","layoutConfig","layoutSettings","onLayoutConfigChange","onGoldenLayoutChange","onLayoutInitialized","fallbackComponent","hydrate","dehydrate","panelWrapper","layoutElement","isInitialized","setIsInitialized","layout","setLayout","initDashboard","current","config","_objectSpread","makeDefaultLayout","settings","assign","content","newLayout","onInit","off","on","setFallbackComponent","init","destroy","handleResize","isInitialised","updateSize","className","ref","Provider","value","onLayoutChange"],"sources":["../src/Dashboard.tsx"],"sourcesContent":["import React, {\n type ComponentType,\n type ForwardRefExoticComponent,\n type RefAttributes,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport throttle from 'lodash.throttle';\nimport GoldenLayout from '@deephaven/golden-layout';\nimport type { ItemConfig, Settings } from '@deephaven/golden-layout';\nimport { useResizeObserver } from '@deephaven/react-hooks';\nimport './layout/GoldenLayout.scss';\nimport LayoutUtils from './layout/LayoutUtils';\nimport PanelPlaceholder from './PanelPlaceholder';\nimport DashboardLayout from './DashboardLayout';\nimport {\n type PanelDehydrateFunction,\n type PanelHydrateFunction,\n type PanelProps,\n} from './DashboardPlugin';\nimport './Dashboard.scss';\nimport { LayoutManagerContext } from './layout';\nimport { DashboardIdContext } from './useDashboardId';\nimport { FiberProvider } from './useFiber';\n\nconst RESIZE_THROTTLE = 100;\n\nconst DEFAULT_CALLBACK = (): void => undefined;\n\nconst EMPTY_OBJECT = Object.freeze({});\n\nexport type DashboardProps = {\n id?: string;\n children?: React.ReactNode | React.ReactNode[];\n emptyDashboard?: React.ReactNode;\n layoutConfig?: ItemConfig[];\n layoutSettings?: Partial<Settings>;\n onLayoutConfigChange?: () => void;\n onGoldenLayoutChange?: (goldenLayout: GoldenLayout) => void;\n onLayoutInitialized?: () => void;\n fallbackComponent?: ForwardRefExoticComponent<\n PanelProps & RefAttributes<HTMLDivElement>\n >;\n hydrate?: PanelHydrateFunction;\n dehydrate?: PanelDehydrateFunction;\n\n /** Component to wrap each panel with */\n panelWrapper?: ComponentType<React.PropsWithChildren<PanelProps>>;\n};\n\nexport function Dashboard({\n id = 'default',\n children,\n emptyDashboard,\n layoutConfig,\n layoutSettings = EMPTY_OBJECT,\n onLayoutConfigChange = DEFAULT_CALLBACK,\n onGoldenLayoutChange = DEFAULT_CALLBACK,\n onLayoutInitialized = DEFAULT_CALLBACK,\n fallbackComponent = PanelPlaceholder,\n hydrate,\n dehydrate,\n panelWrapper,\n}: DashboardProps): JSX.Element {\n const layoutElement = useRef<HTMLDivElement>(null);\n const [isInitialized, setIsInitialized] = useState(false);\n const [layout, setLayout] = useState<GoldenLayout>();\n\n useEffect(\n function initDashboard() {\n if (!layoutElement.current) {\n setLayout(undefined);\n return;\n }\n const config = {\n ...LayoutUtils.makeDefaultLayout(),\n };\n if (config.settings === undefined) {\n config.settings = {};\n }\n Object.assign(config.settings, layoutSettings);\n\n // Load our content later after plugins have registered\n config.content = [];\n\n const newLayout = new GoldenLayout(config, layoutElement.current);\n\n const onInit = (): void => {\n newLayout.off('initialised', onInit);\n setIsInitialized(true);\n };\n newLayout.on('initialised', onInit);\n\n if (fallbackComponent != null) {\n newLayout.setFallbackComponent(fallbackComponent);\n }\n\n newLayout.init();\n\n setLayout(newLayout);\n\n onGoldenLayoutChange(newLayout);\n\n return () => {\n newLayout.destroy();\n };\n },\n [\n layoutSettings,\n fallbackComponent,\n onGoldenLayoutChange,\n setIsInitialized,\n setLayout,\n ]\n );\n\n const handleResize = useMemo(\n () =>\n throttle(() => {\n if (layout != null && layout.isInitialised) {\n layout?.updateSize();\n }\n }, RESIZE_THROTTLE),\n [layout]\n );\n\n useResizeObserver(layoutElement.current, handleResize);\n\n return (\n <div className=\"dashboard-container w-100 h-100\">\n <div className=\"w-100 h-100\" ref={layoutElement} />\n {isInitialized && layout && (\n <LayoutManagerContext.Provider value={layout}>\n <DashboardIdContext.Provider value={id}>\n <FiberProvider>\n <DashboardLayout\n emptyDashboard={emptyDashboard}\n id={id}\n layout={layout}\n layoutConfig={layoutConfig}\n onLayoutChange={onLayoutConfigChange}\n onLayoutInitialized={onLayoutInitialized}\n hydrate={hydrate}\n dehydrate={dehydrate}\n panelWrapper={panelWrapper}\n >\n {children}\n </DashboardLayout>\n </FiberProvider>\n </DashboardIdContext.Provider>\n </LayoutManagerContext.Provider>\n )}\n </div>\n );\n}\n\nexport default Dashboard;\n"],"mappings":"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","ignoreList":[]}
@@ -2,7 +2,7 @@ import React, { type ComponentType } from 'react';
2
2
  import type GoldenLayout from '@deephaven/golden-layout';
3
3
  import type { ItemConfig } from '@deephaven/golden-layout';
4
4
  import { type ClosedPanels } from './PanelManager';
5
- import { type PanelDehydrateFunction, type PanelHydrateFunction, type DehydratedPanelProps } from './DashboardPlugin';
5
+ import { type PanelDehydrateFunction, type PanelHydrateFunction, type PanelProps } from './DashboardPlugin';
6
6
  export type DashboardLayoutConfig = ItemConfig[];
7
7
  type DashboardData = {
8
8
  closed?: ClosedPanels;
@@ -18,7 +18,7 @@ type DashboardLayoutProps = React.PropsWithChildren<{
18
18
  data?: DashboardData;
19
19
  emptyDashboard?: React.ReactNode;
20
20
  /** Component to wrap each panel with */
21
- panelWrapper?: ComponentType<React.PropsWithChildren<DehydratedPanelProps>>;
21
+ panelWrapper?: ComponentType<React.PropsWithChildren<PanelProps>>;
22
22
  }>;
23
23
  /**
24
24
  * DashboardLayout component. Handles hydrating, dehydrating components, listening for dragging panels.
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardLayout.d.ts","sourceRoot":"","sources":["../src/DashboardLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EACZ,KAAK,aAAa,EAMnB,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAEV,UAAU,EAGX,MAAM,0BAA0B,CAAC;AAMlC,OAAqB,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAWjE,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EAEzB,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAC;AAI3B,MAAM,MAAM,qBAAqB,GAAG,UAAU,EAAE,CAAC;AAejD,KAAK,aAAa,GAAG;IACnB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,CAAC;AAEF,KAAK,oBAAoB,GAAG,KAAK,CAAC,iBAAiB,CAAC;IAClD,EAAE,EAAE,MAAM,CAAC;IAGX,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,MAAM,EAAE,YAAY,CAAC;IACrB,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,cAAc,CAAC,EAAE,CAAC,gBAAgB,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACnE,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAEjC,wCAAwC;IACxC,YAAY,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,iBAAiB,CAAC,oBAAoB,CAAC,CAAC,CAAC;CAC7E,CAAC,CAAC;AAEH;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAC9B,EAAE,EACF,QAAQ,EACR,cAA2E,EAC3E,MAAM,EACN,YAAoC,EACpC,cAAiC,EACjC,mBAAsC,EACtC,OAAwB,EACxB,SAA4B,EAC5B,YAAoC,GACrC,EAAE,oBAAoB,GAAG,GAAG,CAAC,OAAO,CA8RpC;AAED,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"DashboardLayout.d.ts","sourceRoot":"","sources":["../src/DashboardLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EACZ,KAAK,aAAa,EAMnB,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAEV,UAAU,EAGX,MAAM,0BAA0B,CAAC;AAMlC,OAAqB,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAWjE,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,UAAU,EAEhB,MAAM,mBAAmB,CAAC;AAI3B,MAAM,MAAM,qBAAqB,GAAG,UAAU,EAAE,CAAC;AAejD,KAAK,aAAa,GAAG;IACnB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,CAAC;AAEF,KAAK,oBAAoB,GAAG,KAAK,CAAC,iBAAiB,CAAC;IAClD,EAAE,EAAE,MAAM,CAAC;IAGX,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,MAAM,EAAE,YAAY,CAAC;IACrB,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,cAAc,CAAC,EAAE,CAAC,gBAAgB,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACnE,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAEjC,wCAAwC;IACxC,YAAY,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC;CACnE,CAAC,CAAC;AAEH;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAC9B,EAAE,EACF,QAAQ,EACR,cAA2E,EAC3E,MAAM,EACN,YAAoC,EACpC,cAAiC,EACjC,mBAAsC,EACtC,OAAwB,EACxB,SAA4B,EAC5B,YAAY,GACb,EAAE,oBAAoB,GAAG,GAAG,CAAC,OAAO,CAqSpC;AAED,eAAe,eAAe,CAAC"}
@@ -44,7 +44,7 @@ export function DashboardLayout(_ref) {
44
44
  onLayoutInitialized = DEFAULT_CALLBACK,
45
45
  hydrate = hydrateDefault,
46
46
  dehydrate = dehydrateDefault,
47
- panelWrapper = DashboardPanelWrapper
47
+ panelWrapper
48
48
  } = _ref;
49
49
  var dispatch = useDispatch();
50
50
  var data = (_useSelector = useSelector(state => getDashboardData(state, id))) !== null && _useSelector !== void 0 ? _useSelector : EMPTY_OBJECT;
@@ -71,6 +71,15 @@ export function DashboardLayout(_ref) {
71
71
  * state changes in the future and in functional components.
72
72
  */
73
73
  var hasRef = canHaveRef(CType);
74
+ var innerElem = hasRef ?
75
+ /*#__PURE__*/
76
+ // eslint-disable-next-line react/jsx-props-no-spreading
77
+ _jsx(CType, _objectSpread(_objectSpread({}, props), {}, {
78
+ ref: ref
79
+ })) :
80
+ /*#__PURE__*/
81
+ // eslint-disable-next-line react/jsx-props-no-spreading
82
+ _jsx(CType, _objectSpread({}, props));
74
83
 
75
84
  // Props supplied by GoldenLayout
76
85
  var {
@@ -83,16 +92,13 @@ export function DashboardLayout(_ref) {
83
92
  glEventHub: glEventHub,
84
93
  children: /*#__PURE__*/_jsx(PanelIdContext.Provider, {
85
94
  value: panelId,
86
- children: /*#__PURE__*/_jsx(PanelWrapperType, _objectSpread(_objectSpread({}, props), {}, {
87
- children: hasRef ?
95
+ children: /*#__PURE__*/_jsx(DashboardPanelWrapper, _objectSpread(_objectSpread({}, props), {}, {
96
+ children: PanelWrapperType == null ? innerElem :
88
97
  /*#__PURE__*/
89
98
  // eslint-disable-next-line react/jsx-props-no-spreading
90
- _jsx(CType, _objectSpread(_objectSpread({}, props), {}, {
91
- ref: ref
92
- })) :
93
- /*#__PURE__*/
94
- // eslint-disable-next-line react/jsx-props-no-spreading
95
- _jsx(CType, _objectSpread({}, props))
99
+ _jsx(PanelWrapperType, _objectSpread(_objectSpread({}, props), {}, {
100
+ children: innerElem
101
+ }))
96
102
  }))
97
103
  })
98
104
  });
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardLayout.js","names":["React","useCallback","useEffect","useMemo","useState","Log","usePrevious","useThrottledCallback","ErrorBoundary","useDispatch","useSelector","PanelManager","PanelErrorBoundary","LayoutUtils","isReactComponentConfig","canHaveRef","dehydrate","dehydrateDefault","hydrate","hydrateDefault","PanelEvent","useListener","getDashboardData","updateDashboardData","DashboardPanelWrapper","PanelIdContext","jsx","_jsx","Fragment","_Fragment","jsxs","_jsxs","log","module","EMPTY_OBJECT","Object","freeze","DEFAULT_LAYOUT_CONFIG","DEFAULT_CALLBACK","undefined","STATE_CHANGE_THROTTLE_MS","FALLBACK_CALLBACK","props","DashboardLayout","_ref","_useSelector","_closed","id","children","emptyDashboard","className","layout","layoutConfig","onLayoutChange","onLayoutInitialized","panelWrapper","dispatch","data","state","isDashboardEmpty","setIsDashboardEmpty","isItemDragging","setIsItemDragging","lastConfig","setLastConfig","initialClosedPanels","closed","layoutChildren","setLayoutChildren","getReactChildren","hydrateMap","Map","dehydrateMap","registerComponent","name","componentType","_componentType$displa","componentHydrate","arguments","length","componentDehydrate","debug2","wrappedComponent","ref","CType","PanelWrapperType","hasRef","glContainer","glEventHub","panelId","getIdFromContainer","Provider","value","_objectSpread","displayName","concat","cleanup","forwardRef","set","hydrateComponent","_hydrateMap$get","get","dehydrateComponent","config","_dehydrateMap$get","panelManager","_ref2","openedMap","throttledProcessDehydratedLayoutConfig","dehydratedLayoutConfig","hasChanged","isEqual","debug","root","contentItems","flushOnUnmount","flush","handleLayoutStateChanged","glConfig","toConfig","contentConfig","content","dehydrateLayoutConfig","handleLayoutItemPickedUp","component","componentId","eventHub","emit","DRAGGING","handleLayoutItemDropped","DROPPED","handleComponentCreated","item","element","cssComponent","replace","toLowerCase","cssClass","addClass","handleReactChildrenChange","TITLE_CHANGED","previousLayoutConfig","loadNewConfig","hydrateLayoutConfig","remove","i","addChild","Children","map","child","fallback","cloneElement"],"sources":["../src/DashboardLayout.tsx"],"sourcesContent":["import React, {\n type ComponentType,\n type ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport type GoldenLayout from '@deephaven/golden-layout';\nimport type {\n Container,\n ItemConfig,\n ReactComponentConfig,\n AbstractContentItem,\n} from '@deephaven/golden-layout';\nimport Log from '@deephaven/log';\nimport { usePrevious, useThrottledCallback } from '@deephaven/react-hooks';\nimport { ErrorBoundary } from '@deephaven/components';\nimport { type RootState } from '@deephaven/redux';\nimport { useDispatch, useSelector } from 'react-redux';\nimport PanelManager, { type ClosedPanels } from './PanelManager';\nimport PanelErrorBoundary from './PanelErrorBoundary';\nimport LayoutUtils, { isReactComponentConfig } from './layout/LayoutUtils';\nimport {\n canHaveRef,\n dehydrate as dehydrateDefault,\n hydrate as hydrateDefault,\n} from './DashboardUtils';\nimport PanelEvent from './PanelEvent';\nimport { useListener } from './layout';\nimport { getDashboardData, updateDashboardData } from './redux';\nimport {\n type PanelConfig,\n type PanelComponentType,\n type PanelDehydrateFunction,\n type PanelHydrateFunction,\n type PanelProps,\n type DehydratedPanelProps,\n} from './DashboardPlugin';\nimport DashboardPanelWrapper from './DashboardPanelWrapper';\nimport { PanelIdContext } from './usePanelId';\n\nexport type DashboardLayoutConfig = ItemConfig[];\n\nconst log = Log.module('DashboardLayout');\n\nconst EMPTY_OBJECT = Object.freeze({});\n\nconst DEFAULT_LAYOUT_CONFIG: DashboardLayoutConfig = [];\n\nconst DEFAULT_CALLBACK = (): void => undefined;\n\nconst STATE_CHANGE_THROTTLE_MS = 1000;\n\n// If a component isn't registered, just pass through the props so they are saved if a plugin is loaded later\nconst FALLBACK_CALLBACK = <P,>(props: P): P => props;\n\ntype DashboardData = {\n closed?: ClosedPanels;\n};\n\ntype DashboardLayoutProps = React.PropsWithChildren<{\n id: string;\n\n // Default hydrate/dehydration functions\n hydrate?: PanelHydrateFunction;\n dehydrate?: PanelDehydrateFunction;\n layout: GoldenLayout;\n layoutConfig?: DashboardLayoutConfig;\n onLayoutChange?: (dehydratedLayout: DashboardLayoutConfig) => void;\n onLayoutInitialized?: () => void;\n data?: DashboardData;\n emptyDashboard?: React.ReactNode;\n\n /** Component to wrap each panel with */\n panelWrapper?: ComponentType<React.PropsWithChildren<DehydratedPanelProps>>;\n}>;\n\n/**\n * DashboardLayout component. Handles hydrating, dehydrating components, listening for dragging panels.\n */\nexport function DashboardLayout({\n id,\n children,\n emptyDashboard = <div className=\"dashboard-empty\">Dashboard is empty.</div>,\n layout,\n layoutConfig = DEFAULT_LAYOUT_CONFIG,\n onLayoutChange = DEFAULT_CALLBACK,\n onLayoutInitialized = DEFAULT_CALLBACK,\n hydrate = hydrateDefault,\n dehydrate = dehydrateDefault,\n panelWrapper = DashboardPanelWrapper,\n}: DashboardLayoutProps): JSX.Element {\n const dispatch = useDispatch();\n const data =\n useSelector<RootState>(state => getDashboardData(state, id)) ??\n EMPTY_OBJECT;\n\n const [isDashboardEmpty, setIsDashboardEmpty] = useState(false);\n const [isItemDragging, setIsItemDragging] = useState(false);\n const [lastConfig, setLastConfig] = useState<DashboardLayoutConfig>();\n const [initialClosedPanels] = useState<ReactComponentConfig[] | undefined>(\n (data as DashboardData)?.closed ?? []\n );\n const [layoutChildren, setLayoutChildren] = useState(\n layout.getReactChildren()\n );\n\n const hydrateMap = useMemo(() => new Map<string, PanelHydrateFunction>(), []);\n const dehydrateMap = useMemo(\n () => new Map<string, PanelDehydrateFunction>(),\n []\n );\n const registerComponent = useCallback(\n (\n name: string,\n componentType: PanelComponentType,\n componentHydrate = hydrate,\n componentDehydrate = dehydrate\n ) => {\n log.debug2(\n 'registerComponent',\n name,\n componentType,\n componentHydrate,\n componentDehydrate\n );\n\n function wrappedComponent(\n props: PanelProps,\n ref: React.Ref<unknown>\n ): JSX.Element {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const CType = componentType as any;\n const PanelWrapperType = panelWrapper;\n\n /**\n * The ref is used to detect changes to class component state so we\n * can track changes to panelState. We should opt for more explicit\n * state changes in the future and in functional components.\n */\n const hasRef = canHaveRef(CType);\n\n // Props supplied by GoldenLayout\n const { glContainer, glEventHub } = props;\n const panelId = LayoutUtils.getIdFromContainer(glContainer);\n return (\n <PanelErrorBoundary glContainer={glContainer} glEventHub={glEventHub}>\n <PanelIdContext.Provider value={panelId as string | null}>\n {/* eslint-disable-next-line react/jsx-props-no-spreading */}\n <PanelWrapperType {...props}>\n {hasRef ? (\n // eslint-disable-next-line react/jsx-props-no-spreading\n <CType {...props} ref={ref} />\n ) : (\n // eslint-disable-next-line react/jsx-props-no-spreading\n <CType {...props} />\n )}\n </PanelWrapperType>\n </PanelIdContext.Provider>\n </PanelErrorBoundary>\n );\n }\n\n wrappedComponent.displayName = `DashboardWrapper(${\n componentType.displayName ?? name\n })`;\n\n const cleanup = layout.registerComponent(\n name,\n React.forwardRef(wrappedComponent)\n );\n hydrateMap.set(name, componentHydrate);\n dehydrateMap.set(name, componentDehydrate);\n return cleanup;\n },\n [hydrate, dehydrate, hydrateMap, dehydrateMap, layout, panelWrapper]\n );\n const hydrateComponent = useCallback(\n (name: string, props: DehydratedPanelProps) =>\n (hydrateMap.get(name) ?? (FALLBACK_CALLBACK as PanelHydrateFunction))(\n props,\n id\n ),\n [hydrateMap, id]\n );\n const dehydrateComponent = useCallback(\n (name: string, config: PanelConfig) =>\n (dehydrateMap.get(name) ?? (FALLBACK_CALLBACK as PanelDehydrateFunction))(\n config,\n id\n ),\n [dehydrateMap, id]\n );\n const panelManager = useMemo(\n () =>\n new PanelManager(\n layout,\n hydrateComponent,\n dehydrateComponent,\n new Map(),\n initialClosedPanels,\n ({ closed, openedMap }) => {\n dispatch(updateDashboardData(id, { closed, openedMap }));\n }\n ),\n [\n dehydrateComponent,\n dispatch,\n hydrateComponent,\n id,\n initialClosedPanels,\n layout,\n ]\n );\n\n // Throttle the calls so that we don't flood comparing these layouts\n const throttledProcessDehydratedLayoutConfig = useThrottledCallback(\n (dehydratedLayoutConfig: DashboardLayoutConfig) => {\n const hasChanged =\n lastConfig == null ||\n !LayoutUtils.isEqual(lastConfig, dehydratedLayoutConfig);\n\n log.debug('handleLayoutStateChanged', hasChanged, dehydratedLayoutConfig);\n\n if (hasChanged) {\n setIsDashboardEmpty(layout.root.contentItems.length === 0);\n\n setLastConfig(dehydratedLayoutConfig);\n\n onLayoutChange(dehydratedLayoutConfig);\n\n setLayoutChildren(layout.getReactChildren());\n }\n },\n STATE_CHANGE_THROTTLE_MS,\n { flushOnUnmount: true }\n );\n\n useEffect(\n () => () => throttledProcessDehydratedLayoutConfig.flush(),\n [throttledProcessDehydratedLayoutConfig]\n );\n\n const handleLayoutStateChanged = useCallback(() => {\n // we don't want to emit stateChanges that happen during item drags or else\n // we risk the last saved state being one without that panel in the layout entirely\n if (isItemDragging) return;\n\n const glConfig = layout.toConfig();\n const contentConfig = glConfig.content;\n const dehydratedLayoutConfig = LayoutUtils.dehydrateLayoutConfig(\n contentConfig,\n dehydrateComponent\n );\n throttledProcessDehydratedLayoutConfig(dehydratedLayoutConfig);\n }, [\n dehydrateComponent,\n isItemDragging,\n layout,\n throttledProcessDehydratedLayoutConfig,\n ]);\n\n const handleLayoutItemPickedUp = useCallback(\n (component: Container) => {\n const componentId = LayoutUtils.getIdFromContainer(component);\n layout.eventHub.emit(PanelEvent.DRAGGING, componentId);\n setIsItemDragging(true);\n },\n [layout.eventHub]\n );\n\n const handleLayoutItemDropped = useCallback(\n (component: Container) => {\n const componentId = LayoutUtils.getIdFromContainer(component);\n layout.eventHub.emit(PanelEvent.DROPPED, componentId);\n setIsItemDragging(false);\n },\n [layout.eventHub]\n );\n\n const handleComponentCreated = useCallback((item: AbstractContentItem) => {\n log.debug2('handleComponentCreated', item);\n\n if (\n item == null ||\n item.config == null ||\n !isReactComponentConfig(item.config) ||\n item.config.component == null ||\n item.element == null\n ) {\n return;\n }\n\n const cssComponent = item.config.component\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .toLowerCase();\n const cssClass = `${cssComponent}-component`;\n item.element.addClass(cssClass);\n }, []);\n\n const handleReactChildrenChange = useCallback(() => {\n setLayoutChildren(layout.getReactChildren());\n }, [layout]);\n\n useListener(layout, 'stateChanged', handleLayoutStateChanged);\n useListener(layout, 'itemPickedUp', handleLayoutItemPickedUp);\n useListener(layout, 'itemDropped', handleLayoutItemDropped);\n useListener(layout, 'componentCreated', handleComponentCreated);\n useListener(\n layout.eventHub,\n PanelEvent.TITLE_CHANGED,\n handleLayoutStateChanged\n );\n useListener(layout, 'reactChildrenChanged', handleReactChildrenChange);\n\n const previousLayoutConfig = usePrevious(layoutConfig);\n useEffect(\n function loadNewConfig() {\n if (\n previousLayoutConfig !== layoutConfig &&\n layoutConfig !== lastConfig\n ) {\n log.debug('Setting new layout content...');\n const content = LayoutUtils.hydrateLayoutConfig(\n layoutConfig,\n hydrateComponent\n );\n // Remove the old layout before add the new one\n while (layout.root.contentItems.length > 0) {\n layout.root.contentItems[0].remove();\n }\n\n // Add the new content. It is usally just one item from the root\n for (let i = 0; i < content.length; i += 1) {\n layout.root.addChild(content[i]);\n }\n\n setIsDashboardEmpty(layout.root.contentItems.length === 0);\n }\n },\n [\n hydrateComponent,\n layout,\n layoutConfig,\n lastConfig,\n panelManager,\n previousLayoutConfig,\n ]\n );\n\n // This should be the last hook called in this component\n // Ensures it runs after any other effects on mount\n // Fire only once after the layout is mounted\n // This should ensure DashboardPlugins have been mounted\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => onLayoutInitialized(), []);\n\n return (\n <>\n {isDashboardEmpty && emptyDashboard}\n {layoutChildren}\n {React.Children.map(children, child =>\n child != null ? (\n // Have fallback be an empty array so that we don't show the error message over entire app\n // Look into using toast message in the future\n <ErrorBoundary fallback={[]}>\n {React.cloneElement(child as ReactElement, {\n id,\n layout,\n panelManager,\n registerComponent,\n })}\n </ErrorBoundary>\n ) : null\n )}\n </>\n );\n}\n\nexport default DashboardLayout;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"DashboardLayout.js","names":["React","useCallback","useEffect","useMemo","useState","Log","usePrevious","useThrottledCallback","ErrorBoundary","useDispatch","useSelector","PanelManager","PanelErrorBoundary","LayoutUtils","isReactComponentConfig","canHaveRef","dehydrate","dehydrateDefault","hydrate","hydrateDefault","PanelEvent","useListener","getDashboardData","updateDashboardData","DashboardPanelWrapper","PanelIdContext","jsx","_jsx","Fragment","_Fragment","jsxs","_jsxs","log","module","EMPTY_OBJECT","Object","freeze","DEFAULT_LAYOUT_CONFIG","DEFAULT_CALLBACK","undefined","STATE_CHANGE_THROTTLE_MS","FALLBACK_CALLBACK","props","DashboardLayout","_ref","_useSelector","_closed","id","children","emptyDashboard","className","layout","layoutConfig","onLayoutChange","onLayoutInitialized","panelWrapper","dispatch","data","state","isDashboardEmpty","setIsDashboardEmpty","isItemDragging","setIsItemDragging","lastConfig","setLastConfig","initialClosedPanels","closed","layoutChildren","setLayoutChildren","getReactChildren","hydrateMap","Map","dehydrateMap","registerComponent","name","componentType","_componentType$displa","componentHydrate","arguments","length","componentDehydrate","debug2","wrappedComponent","ref","CType","PanelWrapperType","hasRef","innerElem","_objectSpread","glContainer","glEventHub","panelId","getIdFromContainer","Provider","value","displayName","concat","cleanup","forwardRef","set","hydrateComponent","_hydrateMap$get","get","dehydrateComponent","config","_dehydrateMap$get","panelManager","_ref2","openedMap","throttledProcessDehydratedLayoutConfig","dehydratedLayoutConfig","hasChanged","isEqual","debug","root","contentItems","flushOnUnmount","flush","handleLayoutStateChanged","glConfig","toConfig","contentConfig","content","dehydrateLayoutConfig","handleLayoutItemPickedUp","component","componentId","eventHub","emit","DRAGGING","handleLayoutItemDropped","DROPPED","handleComponentCreated","item","element","cssComponent","replace","toLowerCase","cssClass","addClass","handleReactChildrenChange","TITLE_CHANGED","previousLayoutConfig","loadNewConfig","hydrateLayoutConfig","remove","i","addChild","Children","map","child","fallback","cloneElement"],"sources":["../src/DashboardLayout.tsx"],"sourcesContent":["import React, {\n type ComponentType,\n type ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport type GoldenLayout from '@deephaven/golden-layout';\nimport type {\n Container,\n ItemConfig,\n ReactComponentConfig,\n AbstractContentItem,\n} from '@deephaven/golden-layout';\nimport Log from '@deephaven/log';\nimport { usePrevious, useThrottledCallback } from '@deephaven/react-hooks';\nimport { ErrorBoundary } from '@deephaven/components';\nimport { type RootState } from '@deephaven/redux';\nimport { useDispatch, useSelector } from 'react-redux';\nimport PanelManager, { type ClosedPanels } from './PanelManager';\nimport PanelErrorBoundary from './PanelErrorBoundary';\nimport LayoutUtils, { isReactComponentConfig } from './layout/LayoutUtils';\nimport {\n canHaveRef,\n dehydrate as dehydrateDefault,\n hydrate as hydrateDefault,\n} from './DashboardUtils';\nimport PanelEvent from './PanelEvent';\nimport { useListener } from './layout';\nimport { getDashboardData, updateDashboardData } from './redux';\nimport {\n type PanelConfig,\n type PanelComponentType,\n type PanelDehydrateFunction,\n type PanelHydrateFunction,\n type PanelProps,\n type DehydratedPanelProps,\n} from './DashboardPlugin';\nimport DashboardPanelWrapper from './DashboardPanelWrapper';\nimport { PanelIdContext } from './usePanelId';\n\nexport type DashboardLayoutConfig = ItemConfig[];\n\nconst log = Log.module('DashboardLayout');\n\nconst EMPTY_OBJECT = Object.freeze({});\n\nconst DEFAULT_LAYOUT_CONFIG: DashboardLayoutConfig = [];\n\nconst DEFAULT_CALLBACK = (): void => undefined;\n\nconst STATE_CHANGE_THROTTLE_MS = 1000;\n\n// If a component isn't registered, just pass through the props so they are saved if a plugin is loaded later\nconst FALLBACK_CALLBACK = <P,>(props: P): P => props;\n\ntype DashboardData = {\n closed?: ClosedPanels;\n};\n\ntype DashboardLayoutProps = React.PropsWithChildren<{\n id: string;\n\n // Default hydrate/dehydration functions\n hydrate?: PanelHydrateFunction;\n dehydrate?: PanelDehydrateFunction;\n layout: GoldenLayout;\n layoutConfig?: DashboardLayoutConfig;\n onLayoutChange?: (dehydratedLayout: DashboardLayoutConfig) => void;\n onLayoutInitialized?: () => void;\n data?: DashboardData;\n emptyDashboard?: React.ReactNode;\n\n /** Component to wrap each panel with */\n panelWrapper?: ComponentType<React.PropsWithChildren<PanelProps>>;\n}>;\n\n/**\n * DashboardLayout component. Handles hydrating, dehydrating components, listening for dragging panels.\n */\nexport function DashboardLayout({\n id,\n children,\n emptyDashboard = <div className=\"dashboard-empty\">Dashboard is empty.</div>,\n layout,\n layoutConfig = DEFAULT_LAYOUT_CONFIG,\n onLayoutChange = DEFAULT_CALLBACK,\n onLayoutInitialized = DEFAULT_CALLBACK,\n hydrate = hydrateDefault,\n dehydrate = dehydrateDefault,\n panelWrapper,\n}: DashboardLayoutProps): JSX.Element {\n const dispatch = useDispatch();\n const data =\n useSelector<RootState>(state => getDashboardData(state, id)) ??\n EMPTY_OBJECT;\n\n const [isDashboardEmpty, setIsDashboardEmpty] = useState(false);\n const [isItemDragging, setIsItemDragging] = useState(false);\n const [lastConfig, setLastConfig] = useState<DashboardLayoutConfig>();\n const [initialClosedPanels] = useState<ReactComponentConfig[] | undefined>(\n (data as DashboardData)?.closed ?? []\n );\n const [layoutChildren, setLayoutChildren] = useState(\n layout.getReactChildren()\n );\n\n const hydrateMap = useMemo(() => new Map<string, PanelHydrateFunction>(), []);\n const dehydrateMap = useMemo(\n () => new Map<string, PanelDehydrateFunction>(),\n []\n );\n const registerComponent = useCallback(\n (\n name: string,\n componentType: PanelComponentType,\n componentHydrate = hydrate,\n componentDehydrate = dehydrate\n ) => {\n log.debug2(\n 'registerComponent',\n name,\n componentType,\n componentHydrate,\n componentDehydrate\n );\n\n function wrappedComponent(\n props: PanelProps,\n ref: React.Ref<unknown>\n ): JSX.Element {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const CType = componentType as any;\n const PanelWrapperType = panelWrapper;\n\n /**\n * The ref is used to detect changes to class component state so we\n * can track changes to panelState. We should opt for more explicit\n * state changes in the future and in functional components.\n */\n const hasRef = canHaveRef(CType);\n\n const innerElem = hasRef ? (\n // eslint-disable-next-line react/jsx-props-no-spreading\n <CType {...props} ref={ref} />\n ) : (\n // eslint-disable-next-line react/jsx-props-no-spreading\n <CType {...props} />\n );\n\n // Props supplied by GoldenLayout\n const { glContainer, glEventHub } = props;\n const panelId = LayoutUtils.getIdFromContainer(glContainer);\n return (\n <PanelErrorBoundary glContainer={glContainer} glEventHub={glEventHub}>\n <PanelIdContext.Provider value={panelId as string | null}>\n {/* eslint-disable-next-line react/jsx-props-no-spreading */}\n <DashboardPanelWrapper {...props}>\n {PanelWrapperType == null ? (\n innerElem\n ) : (\n // eslint-disable-next-line react/jsx-props-no-spreading\n <PanelWrapperType {...props}>{innerElem}</PanelWrapperType>\n )}\n </DashboardPanelWrapper>\n </PanelIdContext.Provider>\n </PanelErrorBoundary>\n );\n }\n\n wrappedComponent.displayName = `DashboardWrapper(${\n componentType.displayName ?? name\n })`;\n\n const cleanup = layout.registerComponent(\n name,\n React.forwardRef(wrappedComponent)\n );\n hydrateMap.set(name, componentHydrate);\n dehydrateMap.set(name, componentDehydrate);\n return cleanup;\n },\n [hydrate, dehydrate, hydrateMap, dehydrateMap, layout, panelWrapper]\n );\n const hydrateComponent = useCallback(\n (name: string, props: DehydratedPanelProps) =>\n (hydrateMap.get(name) ?? (FALLBACK_CALLBACK as PanelHydrateFunction))(\n props,\n id\n ),\n [hydrateMap, id]\n );\n const dehydrateComponent = useCallback(\n (name: string, config: PanelConfig) =>\n (dehydrateMap.get(name) ?? (FALLBACK_CALLBACK as PanelDehydrateFunction))(\n config,\n id\n ),\n [dehydrateMap, id]\n );\n const panelManager = useMemo(\n () =>\n new PanelManager(\n layout,\n hydrateComponent,\n dehydrateComponent,\n new Map(),\n initialClosedPanels,\n ({ closed, openedMap }) => {\n dispatch(updateDashboardData(id, { closed, openedMap }));\n }\n ),\n [\n dehydrateComponent,\n dispatch,\n hydrateComponent,\n id,\n initialClosedPanels,\n layout,\n ]\n );\n\n // Throttle the calls so that we don't flood comparing these layouts\n const throttledProcessDehydratedLayoutConfig = useThrottledCallback(\n (dehydratedLayoutConfig: DashboardLayoutConfig) => {\n const hasChanged =\n lastConfig == null ||\n !LayoutUtils.isEqual(lastConfig, dehydratedLayoutConfig);\n\n log.debug('handleLayoutStateChanged', hasChanged, dehydratedLayoutConfig);\n\n if (hasChanged) {\n setIsDashboardEmpty(layout.root.contentItems.length === 0);\n\n setLastConfig(dehydratedLayoutConfig);\n\n onLayoutChange(dehydratedLayoutConfig);\n\n setLayoutChildren(layout.getReactChildren());\n }\n },\n STATE_CHANGE_THROTTLE_MS,\n { flushOnUnmount: true }\n );\n\n useEffect(\n () => () => throttledProcessDehydratedLayoutConfig.flush(),\n [throttledProcessDehydratedLayoutConfig]\n );\n\n const handleLayoutStateChanged = useCallback(() => {\n // we don't want to emit stateChanges that happen during item drags or else\n // we risk the last saved state being one without that panel in the layout entirely\n if (isItemDragging) return;\n\n const glConfig = layout.toConfig();\n const contentConfig = glConfig.content;\n const dehydratedLayoutConfig = LayoutUtils.dehydrateLayoutConfig(\n contentConfig,\n dehydrateComponent\n );\n throttledProcessDehydratedLayoutConfig(dehydratedLayoutConfig);\n }, [\n dehydrateComponent,\n isItemDragging,\n layout,\n throttledProcessDehydratedLayoutConfig,\n ]);\n\n const handleLayoutItemPickedUp = useCallback(\n (component: Container) => {\n const componentId = LayoutUtils.getIdFromContainer(component);\n layout.eventHub.emit(PanelEvent.DRAGGING, componentId);\n setIsItemDragging(true);\n },\n [layout.eventHub]\n );\n\n const handleLayoutItemDropped = useCallback(\n (component: Container) => {\n const componentId = LayoutUtils.getIdFromContainer(component);\n layout.eventHub.emit(PanelEvent.DROPPED, componentId);\n setIsItemDragging(false);\n },\n [layout.eventHub]\n );\n\n const handleComponentCreated = useCallback((item: AbstractContentItem) => {\n log.debug2('handleComponentCreated', item);\n\n if (\n item == null ||\n item.config == null ||\n !isReactComponentConfig(item.config) ||\n item.config.component == null ||\n item.element == null\n ) {\n return;\n }\n\n const cssComponent = item.config.component\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .toLowerCase();\n const cssClass = `${cssComponent}-component`;\n item.element.addClass(cssClass);\n }, []);\n\n const handleReactChildrenChange = useCallback(() => {\n setLayoutChildren(layout.getReactChildren());\n }, [layout]);\n\n useListener(layout, 'stateChanged', handleLayoutStateChanged);\n useListener(layout, 'itemPickedUp', handleLayoutItemPickedUp);\n useListener(layout, 'itemDropped', handleLayoutItemDropped);\n useListener(layout, 'componentCreated', handleComponentCreated);\n useListener(\n layout.eventHub,\n PanelEvent.TITLE_CHANGED,\n handleLayoutStateChanged\n );\n useListener(layout, 'reactChildrenChanged', handleReactChildrenChange);\n\n const previousLayoutConfig = usePrevious(layoutConfig);\n useEffect(\n function loadNewConfig() {\n if (\n previousLayoutConfig !== layoutConfig &&\n layoutConfig !== lastConfig\n ) {\n log.debug('Setting new layout content...');\n const content = LayoutUtils.hydrateLayoutConfig(\n layoutConfig,\n hydrateComponent\n );\n // Remove the old layout before add the new one\n while (layout.root.contentItems.length > 0) {\n layout.root.contentItems[0].remove();\n }\n\n // Add the new content. It is usally just one item from the root\n for (let i = 0; i < content.length; i += 1) {\n layout.root.addChild(content[i]);\n }\n\n setIsDashboardEmpty(layout.root.contentItems.length === 0);\n }\n },\n [\n hydrateComponent,\n layout,\n layoutConfig,\n lastConfig,\n panelManager,\n previousLayoutConfig,\n ]\n );\n\n // This should be the last hook called in this component\n // Ensures it runs after any other effects on mount\n // Fire only once after the layout is mounted\n // This should ensure DashboardPlugins have been mounted\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => onLayoutInitialized(), []);\n\n return (\n <>\n {isDashboardEmpty && emptyDashboard}\n {layoutChildren}\n {React.Children.map(children, child =>\n child != null ? (\n // Have fallback be an empty array so that we don't show the error message over entire app\n // Look into using toast message in the future\n <ErrorBoundary fallback={[]}>\n {React.cloneElement(child as ReactElement, {\n id,\n layout,\n panelManager,\n registerComponent,\n })}\n </ErrorBoundary>\n ) : null\n )}\n </>\n );\n}\n\nexport default DashboardLayout;\n"],"mappings":"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","ignoreList":[]}
@@ -1,4 +1,5 @@
1
1
  import { type PropsWithChildren } from 'react';
2
- export declare function DashboardPanelWrapper({ children, }: PropsWithChildren<object>): JSX.Element;
2
+ import type { PanelProps } from './DashboardPlugin';
3
+ export declare function DashboardPanelWrapper({ glContainer, children, }: PropsWithChildren<PanelProps>): JSX.Element;
3
4
  export default DashboardPanelWrapper;
4
5
  //# sourceMappingURL=DashboardPanelWrapper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPanelWrapper.d.ts","sourceRoot":"","sources":["../src/DashboardPanelWrapper.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAEtD,wBAAgB,qBAAqB,CAAC,EACpC,QAAQ,GACT,EAAE,iBAAiB,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAGzC;AAED,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"DashboardPanelWrapper.d.ts","sourceRoot":"","sources":["../src/DashboardPanelWrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAGtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD,wBAAgB,qBAAqB,CAAC,EACpC,WAAW,EACX,QAAQ,GACT,EAAE,iBAAiB,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,OAAO,CA6B7C;AAED,eAAe,qBAAqB,CAAC"}
@@ -1,11 +1,31 @@
1
- import React from 'react';
2
- import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
1
+ import { useCallback, useState } from 'react';
2
+ import Log from '@deephaven/log';
3
+ import { PersistentStateProvider } from "./PersistentStateContext.js";
4
+ import { jsx as _jsx } from "react/jsx-runtime";
5
+ var log = Log.module('DashboardPanelWrapper');
3
6
  export function DashboardPanelWrapper(_ref) {
4
7
  var {
8
+ glContainer,
5
9
  children
6
10
  } = _ref;
7
- // eslint-disable-next-line react/jsx-no-useless-fragment
8
- return /*#__PURE__*/_jsx(_Fragment, {
11
+ var handleDataChange = useCallback(data => {
12
+ glContainer.setPersistedState(data);
13
+ }, [glContainer]);
14
+ var {
15
+ persistedState
16
+ } = glContainer.getConfig();
17
+
18
+ // Use a state initializer so we can warn once if the persisted state is invalid
19
+ var [initialPersistedState] = useState(() => {
20
+ if (persistedState != null && !Array.isArray(persistedState)) {
21
+ log.warn("Persisted state is type ".concat(typeof persistedState, ". Expected array. Setting to empty array."));
22
+ return [];
23
+ }
24
+ return persistedState !== null && persistedState !== void 0 ? persistedState : [];
25
+ });
26
+ return /*#__PURE__*/_jsx(PersistentStateProvider, {
27
+ initialState: initialPersistedState,
28
+ onChange: handleDataChange,
9
29
  children: children
10
30
  });
11
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPanelWrapper.js","names":["React","Fragment","_Fragment","jsx","_jsx","DashboardPanelWrapper","_ref","children"],"sources":["../src/DashboardPanelWrapper.tsx"],"sourcesContent":["import React, { type PropsWithChildren } from 'react';\n\nexport function DashboardPanelWrapper({\n children,\n}: PropsWithChildren<object>): JSX.Element {\n // eslint-disable-next-line react/jsx-no-useless-fragment\n return <>{children}</>;\n}\n\nexport default DashboardPanelWrapper;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAkC,OAAO;AAAC,SAAAC,QAAA,IAAAC,SAAA,EAAAC,GAAA,IAAAC,IAAA;AAEtD,OAAO,SAASC,qBAAqBA,CAAAC,IAAA,EAEM;EAAA,IAFL;IACpCC;EACyB,CAAC,GAAAD,IAAA;EAC1B;EACA,oBAAOF,IAAA,CAAAF,SAAA;IAAAK,QAAA,EAAGA;EAAQ,CAAG,CAAC;AACxB;AAEA,eAAeF,qBAAqB","ignoreList":[]}
1
+ {"version":3,"file":"DashboardPanelWrapper.js","names":["useCallback","useState","Log","PersistentStateProvider","jsx","_jsx","log","module","DashboardPanelWrapper","_ref","glContainer","children","handleDataChange","data","setPersistedState","persistedState","getConfig","initialPersistedState","Array","isArray","warn","concat","initialState","onChange"],"sources":["../src/DashboardPanelWrapper.tsx"],"sourcesContent":["import { useCallback, useState, type PropsWithChildren } from 'react';\nimport Log from '@deephaven/log';\nimport { PersistentStateProvider } from './PersistentStateContext';\nimport type { PanelProps } from './DashboardPlugin';\n\nconst log = Log.module('DashboardPanelWrapper');\n\nexport function DashboardPanelWrapper({\n glContainer,\n children,\n}: PropsWithChildren<PanelProps>): JSX.Element {\n const handleDataChange = useCallback(\n (data: unknown) => {\n glContainer.setPersistedState(data);\n },\n [glContainer]\n );\n\n const { persistedState } = glContainer.getConfig();\n\n // Use a state initializer so we can warn once if the persisted state is invalid\n const [initialPersistedState] = useState(() => {\n if (persistedState != null && !Array.isArray(persistedState)) {\n log.warn(\n `Persisted state is type ${typeof persistedState}. Expected array. Setting to empty array.`\n );\n return [];\n }\n return persistedState ?? [];\n });\n\n return (\n <PersistentStateProvider\n initialState={initialPersistedState}\n onChange={handleDataChange}\n >\n {children}\n </PersistentStateProvider>\n );\n}\n\nexport default DashboardPanelWrapper;\n"],"mappings":"AAAA,SAASA,WAAW,EAAEC,QAAQ,QAAgC,OAAO;AACrE,OAAOC,GAAG,MAAM,gBAAgB;AAAC,SACxBC,uBAAuB;AAAA,SAAAC,GAAA,IAAAC,IAAA;AAGhC,IAAMC,GAAG,GAAGJ,GAAG,CAACK,MAAM,CAAC,uBAAuB,CAAC;AAE/C,OAAO,SAASC,qBAAqBA,CAAAC,IAAA,EAGU;EAAA,IAHT;IACpCC,WAAW;IACXC;EAC6B,CAAC,GAAAF,IAAA;EAC9B,IAAMG,gBAAgB,GAAGZ,WAAW,CACjCa,IAAa,IAAK;IACjBH,WAAW,CAACI,iBAAiB,CAACD,IAAI,CAAC;EACrC,CAAC,EACD,CAACH,WAAW,CACd,CAAC;EAED,IAAM;IAAEK;EAAe,CAAC,GAAGL,WAAW,CAACM,SAAS,CAAC,CAAC;;EAElD;EACA,IAAM,CAACC,qBAAqB,CAAC,GAAGhB,QAAQ,CAAC,MAAM;IAC7C,IAAIc,cAAc,IAAI,IAAI,IAAI,CAACG,KAAK,CAACC,OAAO,CAACJ,cAAc,CAAC,EAAE;MAC5DT,GAAG,CAACc,IAAI,4BAAAC,MAAA,CACqB,OAAON,cAAc,8CAClD,CAAC;MACD,OAAO,EAAE;IACX;IACA,OAAOA,cAAc,aAAdA,cAAc,cAAdA,cAAc,GAAI,EAAE;EAC7B,CAAC,CAAC;EAEF,oBACEV,IAAA,CAACF,uBAAuB;IACtBmB,YAAY,EAAEL,qBAAsB;IACpCM,QAAQ,EAAEX,gBAAiB;IAAAD,QAAA,EAE1BA;EAAQ,CACc,CAAC;AAE9B;AAEA,eAAeH,qBAAqB","ignoreList":[]}
@@ -0,0 +1,65 @@
1
+ import React from 'react';
2
+ export type PersistentStateContextType = {
3
+ /**
4
+ * Adds state to be persisted.
5
+ * @param hookId Unique ID for this hook instance
6
+ * @param dhId The dhId of the component/panel.
7
+ * @param state The state to persist. Needs to be JSON serializable.
8
+ */
9
+ addState: (hookId: string, dhId: string, state: PersistentState) => void;
10
+ /**
11
+ * Removes persisted state.
12
+ * @param hookId Unique ID for this hook instance
13
+ * @param dhId The dhId of the component/panel
14
+ * @param type The state type to remove
15
+ */
16
+ removeState: (hookId: string, dhId: string, type: string) => void;
17
+ /**
18
+ * Deregisters a hook instance so it no longer owns any state.
19
+ * This way we can accurately warn about multiple hooks trying to use the same (dhId, type) pair.
20
+ * @param hookId Unique ID for this hook instance
21
+ * @param dhId The dhId of the component/panel to deregister for
22
+ * @param type The state type to deregister for
23
+ */
24
+ deregisterHook: (hookId: string, dhId: string, type: string) => void;
25
+ /**
26
+ * Gets the state for the given dhId and type.
27
+ * Prepopulated with the initial state passed to the PersistentStateProvider.
28
+ * @param dhId The dhId of the component/panel
29
+ * @returns The iterator result containing the initial state value (state, version, type) if it exists.
30
+ */
31
+ getState: <S>(dhId: string, type: string) => PersistentState<S> | undefined;
32
+ };
33
+ /**
34
+ * Context that holds methods to track the state of all calls to usePersistentState below this provider.
35
+ */
36
+ export declare const PersistentStateContext: React.Context<PersistentStateContextType | null>;
37
+ export type PersistentState<S = unknown> = {
38
+ state: S;
39
+ version: number;
40
+ type: string;
41
+ };
42
+ export type PersistentStateProviderProps = React.PropsWithChildren<{
43
+ /**
44
+ * The initial state of all calls to usePersistentState.
45
+ * If there are more calls to usePersistentState than there are elements in this array,
46
+ * the state initializer of the usePersistentState call will be used for the rest.
47
+ */
48
+ initialState: [PersistentStateKey, PersistentState][] | PersistentState[];
49
+ /**
50
+ * Called when the state changes.
51
+ * The state is passed as an array of the values of all calls to usePersistentState.
52
+ * The order of the values is the same as the order of the calls to usePersistentState.
53
+ * @param state The state of all calls to usePersistentState.
54
+ */
55
+ onChange: (state: [PersistentStateKey, PersistentState][]) => void;
56
+ }>;
57
+ type PersistentStateKey = string;
58
+ /**
59
+ * Tracks all calls to the usePersistentState hook below this provider.
60
+ * Keeps track of the state based on dhId and state type, and calls onChange when the state changes.
61
+ * Limit to one state per (dhId, type) pair.
62
+ */
63
+ export declare function PersistentStateProvider(props: PersistentStateProviderProps): JSX.Element;
64
+ export {};
65
+ //# sourceMappingURL=PersistentStateContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PersistentStateContext.d.ts","sourceRoot":"","sources":["../src/PersistentStateContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAON,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,0BAA0B,GAAG;IACvC;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAEzE;;;;;OAKG;IACH,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAElE;;;;;;OAMG;IACH,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAErE;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,eAAe,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;CAC7E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,kDACqB,CAAC;AAGzD,MAAM,MAAM,eAAe,CAAC,CAAC,GAAG,OAAO,IAAI;IACzC,KAAK,EAAE,CAAC,CAAC;IACT,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,KAAK,CAAC,iBAAiB,CAAC;IACjE;;;;OAIG;IACH,YAAY,EAAE,CAAC,kBAAkB,EAAE,eAAe,CAAC,EAAE,GAAG,eAAe,EAAE,CAAC;IAE1E;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,kBAAkB,EAAE,eAAe,CAAC,EAAE,KAAK,IAAI,CAAC;CACpE,CAAC,CAAC;AAMH,KAAK,kBAAkB,GAAG,MAAM,CAAC;AAEjC;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,4BAA4B,GAClC,GAAG,CAAC,OAAO,CAmHb"}
@@ -0,0 +1,100 @@
1
+ import React, { createContext, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ /**
4
+ * Context that holds methods to track the state of all calls to usePersistentState below this provider.
5
+ */
6
+ export var PersistentStateContext = /*#__PURE__*/createContext(null);
7
+ PersistentStateContext.displayName = 'PersistentStateContext';
8
+ function makeKey(dhId, type) {
9
+ return "".concat(dhId, "::").concat(type);
10
+ }
11
+ /**
12
+ * Tracks all calls to the usePersistentState hook below this provider.
13
+ * Keeps track of the state based on dhId and state type, and calls onChange when the state changes.
14
+ * Limit to one state per (dhId, type) pair.
15
+ */
16
+ export function PersistentStateProvider(props) {
17
+ var {
18
+ initialState,
19
+ onChange,
20
+ children
21
+ } = props;
22
+ var isMounted = useRef(true);
23
+ useEffect(() => () => {
24
+ isMounted.current = false;
25
+ }, []);
26
+ var needsMigrationToMap = useRef(false);
27
+ var [stateMap] = useState(() => {
28
+ if (Array.isArray(initialState) && initialState.flat().length === 2 * initialState.length) {
29
+ return new Map(initialState);
30
+ }
31
+ needsMigrationToMap.current = true;
32
+ // Used to migrate from array to map
33
+ return new Map();
34
+ });
35
+
36
+ // Track which hookId currently owns each (dhId, type) pair
37
+ var hookOwnership = useRef(new Map());
38
+ var addState = useCallback((hookId, dhId, state) => {
39
+ var {
40
+ type
41
+ } = state;
42
+ var key = makeKey(dhId, type);
43
+ var currentOwner = hookOwnership.current.get(key);
44
+ if (currentOwner != null && currentOwner !== hookId) {
45
+ throw new Error("Detected multiple persistent states of type ".concat(type, " for dhId ").concat(dhId, ". Only one state per (dhId, type) pair is allowed."));
46
+ }
47
+ hookOwnership.current.set(key, hookId);
48
+ if (isMounted.current && stateMap.get(key) !== state) {
49
+ stateMap.set(key, state);
50
+ onChange([...stateMap.entries()]);
51
+ }
52
+ }, [isMounted, onChange, stateMap]);
53
+ var initialStateIterator = useRef(initialState[Symbol.iterator]());
54
+ var getState = useCallback((id, type) => {
55
+ var key = makeKey(id, type);
56
+ var state = stateMap.get(key);
57
+ if (state == null && needsMigrationToMap.current) {
58
+ var {
59
+ value
60
+ } = initialStateIterator.current.next();
61
+ var stateVal = value;
62
+ stateMap.set(key, stateVal);
63
+ return stateVal;
64
+ }
65
+ return state;
66
+ }, [stateMap]);
67
+ var removeState = useCallback((hookId, dhId, type) => {
68
+ var key = makeKey(dhId, type);
69
+ var currentOwner = hookOwnership.current.get(key);
70
+
71
+ // Only remove if this hookId is the current owner
72
+ if (currentOwner === hookId) {
73
+ stateMap.delete(key);
74
+ hookOwnership.current.delete(key);
75
+ if (isMounted.current) {
76
+ onChange([...stateMap.entries()]);
77
+ }
78
+ }
79
+ }, [isMounted, onChange, stateMap]);
80
+ var deregisterHook = useCallback((hookId, dhId, type) => {
81
+ var key = makeKey(dhId, type);
82
+ var currentOwner = hookOwnership.current.get(key);
83
+
84
+ // Only remove if this hookId is the current owner
85
+ if (currentOwner === hookId) {
86
+ hookOwnership.current.delete(key);
87
+ }
88
+ }, []);
89
+ var contextValue = useMemo(() => ({
90
+ addState,
91
+ removeState,
92
+ deregisterHook,
93
+ getState
94
+ }), [addState, getState, removeState, deregisterHook]);
95
+ return /*#__PURE__*/_jsx(PersistentStateContext.Provider, {
96
+ value: contextValue,
97
+ children: children
98
+ });
99
+ }
100
+ //# sourceMappingURL=PersistentStateContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PersistentStateContext.js","names":["React","createContext","useCallback","useEffect","useMemo","useRef","useState","jsx","_jsx","PersistentStateContext","displayName","makeKey","dhId","type","concat","PersistentStateProvider","props","initialState","onChange","children","isMounted","current","needsMigrationToMap","stateMap","Array","isArray","flat","length","Map","hookOwnership","addState","hookId","state","key","currentOwner","get","Error","set","entries","initialStateIterator","Symbol","iterator","getState","id","value","next","stateVal","removeState","delete","deregisterHook","contextValue","Provider"],"sources":["../src/PersistentStateContext.tsx"],"sourcesContent":["import React, {\n createContext,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nexport type PersistentStateContextType = {\n /**\n * Adds state to be persisted.\n * @param hookId Unique ID for this hook instance\n * @param dhId The dhId of the component/panel.\n * @param state The state to persist. Needs to be JSON serializable.\n */\n addState: (hookId: string, dhId: string, state: PersistentState) => void;\n\n /**\n * Removes persisted state.\n * @param hookId Unique ID for this hook instance\n * @param dhId The dhId of the component/panel\n * @param type The state type to remove\n */\n removeState: (hookId: string, dhId: string, type: string) => void;\n\n /**\n * Deregisters a hook instance so it no longer owns any state.\n * This way we can accurately warn about multiple hooks trying to use the same (dhId, type) pair.\n * @param hookId Unique ID for this hook instance\n * @param dhId The dhId of the component/panel to deregister for\n * @param type The state type to deregister for\n */\n deregisterHook: (hookId: string, dhId: string, type: string) => void;\n\n /**\n * Gets the state for the given dhId and type.\n * Prepopulated with the initial state passed to the PersistentStateProvider.\n * @param dhId The dhId of the component/panel\n * @returns The iterator result containing the initial state value (state, version, type) if it exists.\n */\n getState: <S>(dhId: string, type: string) => PersistentState<S> | undefined;\n};\n\n/**\n * Context that holds methods to track the state of all calls to usePersistentState below this provider.\n */\nexport const PersistentStateContext =\n createContext<PersistentStateContextType | null>(null);\nPersistentStateContext.displayName = 'PersistentStateContext';\n\nexport type PersistentState<S = unknown> = {\n state: S;\n version: number;\n type: string;\n};\n\nexport type PersistentStateProviderProps = React.PropsWithChildren<{\n /**\n * The initial state of all calls to usePersistentState.\n * If there are more calls to usePersistentState than there are elements in this array,\n * the state initializer of the usePersistentState call will be used for the rest.\n */\n initialState: [PersistentStateKey, PersistentState][] | PersistentState[];\n\n /**\n * Called when the state changes.\n * The state is passed as an array of the values of all calls to usePersistentState.\n * The order of the values is the same as the order of the calls to usePersistentState.\n * @param state The state of all calls to usePersistentState.\n */\n onChange: (state: [PersistentStateKey, PersistentState][]) => void;\n}>;\n\nfunction makeKey(dhId: string, type: string): PersistentStateKey {\n return `${dhId}::${type}`;\n}\n\ntype PersistentStateKey = string;\n\n/**\n * Tracks all calls to the usePersistentState hook below this provider.\n * Keeps track of the state based on dhId and state type, and calls onChange when the state changes.\n * Limit to one state per (dhId, type) pair.\n */\nexport function PersistentStateProvider(\n props: PersistentStateProviderProps\n): JSX.Element {\n const { initialState, onChange, children } = props;\n\n const isMounted = useRef(true);\n useEffect(\n () => () => {\n isMounted.current = false;\n },\n []\n );\n\n const needsMigrationToMap = useRef(false);\n\n const [stateMap] = useState(() => {\n if (\n Array.isArray(initialState) &&\n initialState.flat().length === 2 * initialState.length\n ) {\n return new Map<string, PersistentState>(\n initialState as [string, PersistentState][]\n );\n }\n needsMigrationToMap.current = true;\n // Used to migrate from array to map\n return new Map<string, PersistentState>();\n });\n\n // Track which hookId currently owns each (dhId, type) pair\n const hookOwnership = useRef(new Map<PersistentStateKey, string>());\n\n const addState = useCallback(\n (hookId: string, dhId: string, state: PersistentState) => {\n const { type } = state;\n const key = makeKey(dhId, type);\n const currentOwner = hookOwnership.current.get(key);\n\n if (currentOwner != null && currentOwner !== hookId) {\n throw new Error(\n `Detected multiple persistent states of type ${type} for dhId ${dhId}. Only one state per (dhId, type) pair is allowed.`\n );\n }\n\n hookOwnership.current.set(key, hookId);\n\n if (isMounted.current && stateMap.get(key) !== state) {\n stateMap.set(key, state);\n onChange([...stateMap.entries()]);\n }\n },\n [isMounted, onChange, stateMap]\n );\n\n const initialStateIterator = useRef(initialState[Symbol.iterator]());\n\n const getState = useCallback(\n <S,>(id: string, type: string): PersistentState<S> | undefined => {\n const key = makeKey(id, type);\n const state = stateMap.get(key);\n if (state == null && needsMigrationToMap.current) {\n const { value } = initialStateIterator.current.next();\n const stateVal = value as PersistentState<S> | undefined;\n stateMap.set(key, stateVal as PersistentState);\n return stateVal;\n }\n\n return state as PersistentState<S> | undefined;\n },\n [stateMap]\n );\n\n const removeState = useCallback(\n (hookId: string, dhId: string, type: string) => {\n const key = makeKey(dhId, type);\n const currentOwner = hookOwnership.current.get(key);\n\n // Only remove if this hookId is the current owner\n if (currentOwner === hookId) {\n stateMap.delete(key);\n hookOwnership.current.delete(key);\n if (isMounted.current) {\n onChange([...stateMap.entries()]);\n }\n }\n },\n [isMounted, onChange, stateMap]\n );\n\n const deregisterHook = useCallback(\n (hookId: string, dhId: string, type: string) => {\n const key = makeKey(dhId, type);\n const currentOwner = hookOwnership.current.get(key);\n\n // Only remove if this hookId is the current owner\n if (currentOwner === hookId) {\n hookOwnership.current.delete(key);\n }\n },\n []\n );\n\n const contextValue = useMemo(\n () => ({\n addState,\n removeState,\n deregisterHook,\n getState,\n }),\n [addState, getState, removeState, deregisterHook]\n );\n\n return (\n <PersistentStateContext.Provider value={contextValue}>\n {children}\n </PersistentStateContext.Provider>\n );\n}\n"],"mappings":"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","ignoreList":[]}
package/dist/index.d.ts CHANGED
@@ -20,4 +20,6 @@ export { default as TabEvent } from './TabEvent';
20
20
  export * from './useDashboardId';
21
21
  export * from './useDhId';
22
22
  export * from './usePanelId';
23
+ export * from './usePersistentState';
24
+ export * from './PersistentStateContext';
23
25
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,aAAa,CAAC;AAEpC,eAAe,SAAS,CAAC;AAEzB,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC7D,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,OAAO,EACL,KAAK,cAAc,EACnB,OAAO,IAAI,SAAS,EAEpB,OAAO,IAAI,KAAK,GACjB,MAAM,aAAa,CAAC;AACrB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,aAAa,CAAC;AAEpC,eAAe,SAAS,CAAC;AAEzB,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC7D,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,OAAO,EACL,KAAK,cAAc,EACnB,OAAO,IAAI,SAAS,EAEpB,OAAO,IAAI,KAAK,GACjB,MAAM,aAAa,CAAC;AACrB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC"}
package/dist/index.js CHANGED
@@ -22,4 +22,6 @@ export { default as TabEvent } from "./TabEvent.js";
22
22
  export * from "./useDashboardId.js";
23
23
  export * from "./useDhId.js";
24
24
  export * from "./usePanelId.js";
25
+ export * from "./usePersistentState.js";
26
+ export * from "./PersistentStateContext.js";
25
27
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["Dashboard","default","DashboardUtils","BasePanel","Panel","PanelErrorBoundary","PanelManager","TabEvent"],"sources":["../src/index.ts"],"sourcesContent":["import Dashboard from './Dashboard';\n\nexport default Dashboard;\n\nexport * from './Dashboard';\nexport * from './DashboardConstants';\nexport * from './DashboardEvents';\nexport * from './DashboardPlugin';\nexport * from './DashboardLayout';\nexport * from './DashboardUtils';\nexport { default as DashboardUtils } from './DashboardUtils';\nexport * from './LazyDashboard';\nexport * from './layout';\nexport * from './redux';\nexport {\n type BasePanelProps,\n default as BasePanel,\n // Alias for BasePanel\n default as Panel,\n} from './BasePanel';\nexport * from './PanelManager';\nexport * from './PanelEvent';\nexport * from './NavigationEvent';\nexport { default as PanelErrorBoundary } from './PanelErrorBoundary';\nexport { default as PanelManager } from './PanelManager';\nexport { default as TabEvent } from './TabEvent';\nexport * from './useDashboardId';\nexport * from './useDhId';\nexport * from './usePanelId';\n"],"mappings":"OAAOA,SAAS;AAEhB,eAAeA,SAAS;AAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAQhBC,OAAO,IAAIC,cAAc;AAAA;AAAA;AAAA;AAAA,SAMhCD,OAAO,IAAIE,SAAS;AACpB;AACAF,OAAO,IAAIG,KAAK;AAAA;AAAA;AAAA;AAAA,SAKTH,OAAO,IAAII,kBAAkB;AAAA,SAC7BJ,OAAO,IAAIK,YAAY;AAAA,SACvBL,OAAO,IAAIM,QAAQ;AAAA;AAAA;AAAA","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["Dashboard","default","DashboardUtils","BasePanel","Panel","PanelErrorBoundary","PanelManager","TabEvent"],"sources":["../src/index.ts"],"sourcesContent":["import Dashboard from './Dashboard';\n\nexport default Dashboard;\n\nexport * from './Dashboard';\nexport * from './DashboardConstants';\nexport * from './DashboardEvents';\nexport * from './DashboardPlugin';\nexport * from './DashboardLayout';\nexport * from './DashboardUtils';\nexport { default as DashboardUtils } from './DashboardUtils';\nexport * from './LazyDashboard';\nexport * from './layout';\nexport * from './redux';\nexport {\n type BasePanelProps,\n default as BasePanel,\n // Alias for BasePanel\n default as Panel,\n} from './BasePanel';\nexport * from './PanelManager';\nexport * from './PanelEvent';\nexport * from './NavigationEvent';\nexport { default as PanelErrorBoundary } from './PanelErrorBoundary';\nexport { default as PanelManager } from './PanelManager';\nexport { default as TabEvent } from './TabEvent';\nexport * from './useDashboardId';\nexport * from './useDhId';\nexport * from './usePanelId';\nexport * from './usePersistentState';\nexport * from './PersistentStateContext';\n"],"mappings":"OAAOA,SAAS;AAEhB,eAAeA,SAAS;AAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAQhBC,OAAO,IAAIC,cAAc;AAAA;AAAA;AAAA;AAAA,SAMhCD,OAAO,IAAIE,SAAS;AACpB;AACAF,OAAO,IAAIG,KAAK;AAAA;AAAA;AAAA;AAAA,SAKTH,OAAO,IAAII,kBAAkB;AAAA,SAC7BJ,OAAO,IAAIK,YAAY;AAAA,SACvBL,OAAO,IAAIM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA","ignoreList":[]}
@@ -0,0 +1,28 @@
1
+ import { type Dispatch, type SetStateAction } from 'react';
2
+ export type PersistentStateMigration = {
3
+ from: number;
4
+ migrate: (state: unknown) => unknown;
5
+ };
6
+ /**
7
+ * Functions identically to useState except that a PersistentStateProvider can be used to
8
+ * track all calls to this hook and persist the value for future page loads.
9
+ * Primarily used in Deephaven UI so we can persist state of multiple components within a panel.
10
+ *
11
+ * @param initialState The initial state if there is no previously persisted state.
12
+ * @param config.type The type of the state. This identifier is used to validate the state being rehydrated. Should be unique to your component.
13
+ * @param config.version The version of the state. This should be an integer, and is used to determine if the state needs to be migrated. Value should be incremented when data structure changes for this type.
14
+ * @param config.migrations An array of migrations to apply to the state if the version of the persisted state is below the current version. Each migration increments the version by 1.
15
+ * @param config.migrations.from The starting version of the migration. The migration will increment the version by 1.
16
+ * @param config.migrations.migrate The function to call to migrate the state.
17
+ * @param config.deleteOnUnmount If true, the state will be deleted from the PersistentStateProvider when the component using this hook is unmounted. Defaults to true.
18
+ * May be useful to set to false for components which are conditionally rendered within a panel like console creator settings.
19
+ * @returns [state, setState] tuple just like useState.
20
+ */
21
+ export declare function usePersistentState<S>(initialState: S | (() => S), config: {
22
+ type: string;
23
+ version: number;
24
+ migrations?: PersistentStateMigration[];
25
+ deleteOnUnmount?: boolean;
26
+ }): [state: S, setState: Dispatch<SetStateAction<S>>];
27
+ export default usePersistentState;
28
+ //# sourceMappingURL=usePersistentState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePersistentState.d.ts","sourceRoot":"","sources":["../src/usePersistentState.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,QAAQ,EACb,KAAK,cAAc,EACpB,MAAM,OAAO,CAAC;AAKf,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;CACtC,CAAC;AA0DF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,YAAY,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAC3B,MAAM,EAAE;IACN,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,wBAAwB,EAAE,CAAC;IACxC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GACA,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAqEnD;AAED,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,105 @@
1
+ import { useContext, useDebugValue, useEffect, useMemo, useState } from 'react';
2
+ import { nanoid } from 'nanoid';
3
+ import { PersistentStateContext } from "./PersistentStateContext.js";
4
+ import { useDhId } from "./useDhId.js";
5
+ /**
6
+ * Migrates persisted state to the provided version using the provided migrations.
7
+ *
8
+ * @param state The current state
9
+ * @param from The current version
10
+ * @param to The version to migrate to
11
+ * @param migrations The list of all migrations (may include those already applied)
12
+ * @param type The type of the state. Used for better error messages
13
+ * @returns The state at the new version
14
+ * @throws Error if trying to migrate backwards or no migration exists for the to version
15
+ */
16
+ function migrateState(state, from, to, migrations, type) {
17
+ if (from > to) {
18
+ throw new Error("Persisted state ".concat(type, " is a newer version than the current version. Persisted version: ").concat(from, ". Current version: ").concat(to));
19
+ }
20
+ var migratedState = state;
21
+ var currentVersion = from;
22
+ while (currentVersion < to) {
23
+ // eslint-disable-next-line no-loop-func
24
+ var possibleMigration = migrations.filter(m => m.from === currentVersion);
25
+ if (possibleMigration.length === 0) {
26
+ throw new Error("No migration found for persisted state ".concat(type, " from version ").concat(currentVersion));
27
+ }
28
+ if (possibleMigration.length > 1) {
29
+ throw new Error("Multiple migrations found for persisted state ".concat(type, " from version ").concat(currentVersion));
30
+ }
31
+ var migration = possibleMigration[0];
32
+ try {
33
+ migratedState = migration.migrate(migratedState);
34
+ currentVersion += 1;
35
+ } catch (e) {
36
+ throw new Error("Error migrating persisted state ".concat(type, " from version ").concat(migration.from, ": ").concat(e), {
37
+ cause: e
38
+ });
39
+ }
40
+ }
41
+ return migratedState;
42
+ }
43
+
44
+ /**
45
+ * Functions identically to useState except that a PersistentStateProvider can be used to
46
+ * track all calls to this hook and persist the value for future page loads.
47
+ * Primarily used in Deephaven UI so we can persist state of multiple components within a panel.
48
+ *
49
+ * @param initialState The initial state if there is no previously persisted state.
50
+ * @param config.type The type of the state. This identifier is used to validate the state being rehydrated. Should be unique to your component.
51
+ * @param config.version The version of the state. This should be an integer, and is used to determine if the state needs to be migrated. Value should be incremented when data structure changes for this type.
52
+ * @param config.migrations An array of migrations to apply to the state if the version of the persisted state is below the current version. Each migration increments the version by 1.
53
+ * @param config.migrations.from The starting version of the migration. The migration will increment the version by 1.
54
+ * @param config.migrations.migrate The function to call to migrate the state.
55
+ * @param config.deleteOnUnmount If true, the state will be deleted from the PersistentStateProvider when the component using this hook is unmounted. Defaults to true.
56
+ * May be useful to set to false for components which are conditionally rendered within a panel like console creator settings.
57
+ * @returns [state, setState] tuple just like useState.
58
+ */
59
+ export function usePersistentState(initialState, config) {
60
+ var panelId = useDhId();
61
+ var hookId = useMemo(() => nanoid(), []);
62
+ var context = useContext(PersistentStateContext);
63
+ var {
64
+ type,
65
+ version,
66
+ migrations = [],
67
+ deleteOnUnmount = true
68
+ } = config;
69
+ var [state, setState] = useState(() => {
70
+ var persistedData = panelId != null ? context === null || context === void 0 ? void 0 : context.getState(panelId, type) : undefined;
71
+ if (persistedData == null) {
72
+ return typeof initialState === 'function' ? initialState() : initialState;
73
+ }
74
+ if (persistedData.version !== version) {
75
+ return migrateState(persistedData.state, persistedData.version, version, migrations, type);
76
+ }
77
+ return persistedData.state;
78
+ });
79
+ var stateWithConfig = useMemo(() => ({
80
+ type,
81
+ version,
82
+ state
83
+ }), [state, type, version]);
84
+ useDebugValue(stateWithConfig);
85
+ useEffect(function addState() {
86
+ if (panelId != null) {
87
+ context === null || context === void 0 || context.addState(hookId, panelId, stateWithConfig);
88
+ }
89
+ }, [context, hookId, panelId, stateWithConfig]);
90
+ useEffect(function removeOnUnmount() {
91
+ return () => {
92
+ if (deleteOnUnmount && panelId != null) {
93
+ context === null || context === void 0 || context.removeState(hookId, panelId, type);
94
+ }
95
+ };
96
+ }, [context, deleteOnUnmount, hookId, panelId, type]);
97
+ useEffect(() => () => {
98
+ if (panelId != null) {
99
+ context === null || context === void 0 || context.deregisterHook(hookId, panelId, type);
100
+ }
101
+ }, [context, hookId, panelId, type]);
102
+ return [state, setState];
103
+ }
104
+ export default usePersistentState;
105
+ //# sourceMappingURL=usePersistentState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePersistentState.js","names":["useContext","useDebugValue","useEffect","useMemo","useState","nanoid","PersistentStateContext","useDhId","migrateState","state","from","to","migrations","type","Error","concat","migratedState","currentVersion","possibleMigration","filter","m","length","migration","migrate","e","cause","usePersistentState","initialState","config","panelId","hookId","context","version","deleteOnUnmount","setState","persistedData","getState","undefined","stateWithConfig","addState","removeOnUnmount","removeState","deregisterHook"],"sources":["../src/usePersistentState.ts"],"sourcesContent":["import {\n useContext,\n useDebugValue,\n useEffect,\n useMemo,\n useState,\n type Dispatch,\n type SetStateAction,\n} from 'react';\nimport { nanoid } from 'nanoid';\nimport { PersistentStateContext } from './PersistentStateContext';\nimport { useDhId } from './useDhId';\n\nexport type PersistentStateMigration = {\n from: number;\n migrate: (state: unknown) => unknown;\n};\n\n/**\n * Migrates persisted state to the provided version using the provided migrations.\n *\n * @param state The current state\n * @param from The current version\n * @param to The version to migrate to\n * @param migrations The list of all migrations (may include those already applied)\n * @param type The type of the state. Used for better error messages\n * @returns The state at the new version\n * @throws Error if trying to migrate backwards or no migration exists for the to version\n */\nfunction migrateState(\n state: unknown,\n from: number,\n to: number,\n migrations: PersistentStateMigration[],\n type: string\n): unknown {\n if (from > to) {\n throw new Error(\n `Persisted state ${type} is a newer version than the current version. Persisted version: ${from}. Current version: ${to}`\n );\n }\n\n let migratedState = state;\n let currentVersion = from;\n while (currentVersion < to) {\n // eslint-disable-next-line no-loop-func\n const possibleMigration = migrations.filter(m => m.from === currentVersion);\n if (possibleMigration.length === 0) {\n throw new Error(\n `No migration found for persisted state ${type} from version ${currentVersion}`\n );\n }\n\n if (possibleMigration.length > 1) {\n throw new Error(\n `Multiple migrations found for persisted state ${type} from version ${currentVersion}`\n );\n }\n\n const migration = possibleMigration[0];\n\n try {\n migratedState = migration.migrate(migratedState);\n currentVersion += 1;\n } catch (e) {\n throw new Error(\n `Error migrating persisted state ${type} from version ${migration.from}: ${e}`,\n { cause: e }\n );\n }\n }\n return migratedState;\n}\n\n/**\n * Functions identically to useState except that a PersistentStateProvider can be used to\n * track all calls to this hook and persist the value for future page loads.\n * Primarily used in Deephaven UI so we can persist state of multiple components within a panel.\n *\n * @param initialState The initial state if there is no previously persisted state.\n * @param config.type The type of the state. This identifier is used to validate the state being rehydrated. Should be unique to your component.\n * @param config.version The version of the state. This should be an integer, and is used to determine if the state needs to be migrated. Value should be incremented when data structure changes for this type.\n * @param config.migrations An array of migrations to apply to the state if the version of the persisted state is below the current version. Each migration increments the version by 1.\n * @param config.migrations.from The starting version of the migration. The migration will increment the version by 1.\n * @param config.migrations.migrate The function to call to migrate the state.\n * @param config.deleteOnUnmount If true, the state will be deleted from the PersistentStateProvider when the component using this hook is unmounted. Defaults to true.\n * May be useful to set to false for components which are conditionally rendered within a panel like console creator settings.\n * @returns [state, setState] tuple just like useState.\n */\nexport function usePersistentState<S>(\n initialState: S | (() => S),\n config: {\n type: string;\n version: number;\n migrations?: PersistentStateMigration[];\n deleteOnUnmount?: boolean;\n }\n): [state: S, setState: Dispatch<SetStateAction<S>>] {\n const panelId = useDhId();\n const hookId = useMemo(() => nanoid(), []);\n const context = useContext(PersistentStateContext);\n const { type, version, migrations = [], deleteOnUnmount = true } = config;\n\n const [state, setState] = useState<S>(() => {\n const persistedData =\n panelId != null ? context?.getState<S>(panelId, type) : undefined;\n if (persistedData == null) {\n return typeof initialState === 'function'\n ? (initialState as () => S)()\n : initialState;\n }\n\n if (persistedData.version !== version) {\n return migrateState(\n persistedData.state,\n persistedData.version,\n version,\n migrations,\n type\n ) as S;\n }\n\n return persistedData.state;\n });\n\n const stateWithConfig = useMemo(\n () => ({\n type,\n version,\n state,\n }),\n [state, type, version]\n );\n\n useDebugValue(stateWithConfig);\n\n useEffect(\n function addState() {\n if (panelId != null) {\n context?.addState(hookId, panelId, stateWithConfig);\n }\n },\n [context, hookId, panelId, stateWithConfig]\n );\n\n useEffect(\n function removeOnUnmount() {\n return () => {\n if (deleteOnUnmount && panelId != null) {\n context?.removeState(hookId, panelId, type);\n }\n };\n },\n [context, deleteOnUnmount, hookId, panelId, type]\n );\n\n useEffect(\n () => () => {\n if (panelId != null) {\n context?.deregisterHook(hookId, panelId, type);\n }\n },\n [context, hookId, panelId, type]\n );\n\n return [state, setState];\n}\n\nexport default usePersistentState;\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deephaven/dashboard",
3
- "version": "1.10.2",
3
+ "version": "1.11.0",
4
4
  "description": "Deephaven Dashboard",
5
5
  "author": "Deephaven Data Labs LLC",
6
6
  "license": "Apache-2.0",
@@ -22,11 +22,11 @@
22
22
  "build:sass": "sass --embed-sources --load-path=../../node_modules ./src:./dist"
23
23
  },
24
24
  "dependencies": {
25
- "@deephaven/components": "^1.10.0",
26
- "@deephaven/golden-layout": "^1.10.2",
25
+ "@deephaven/components": "^1.11.0",
26
+ "@deephaven/golden-layout": "^1.11.0",
27
27
  "@deephaven/log": "^1.8.0",
28
28
  "@deephaven/react-hooks": "^1.10.0",
29
- "@deephaven/redux": "^1.10.2",
29
+ "@deephaven/redux": "^1.11.0",
30
30
  "@deephaven/utils": "^1.10.0",
31
31
  "classnames": "^2.3.1",
32
32
  "fast-deep-equal": "^3.1.3",
@@ -53,5 +53,5 @@
53
53
  "publishConfig": {
54
54
  "access": "public"
55
55
  },
56
- "gitHead": "39e389c481a4ec75bfed7a45d1ffaf5a98d8f98e"
56
+ "gitHead": "7b2a23ea3b33c11f136e7b9d44a204880c674866"
57
57
  }