From 9679e58212ca4f8babc582c033775dde4ffd8087 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 14 Sep 2025 12:47:15 +0200 Subject: [PATCH] feat(frontend): Add samples for dashboard (#10306) * feat(forntend): Add sampels to dashboard Closes #9990 * add sessions storage to disable sample dash once cleared/removed --- .../components/dashboard/DashboardLayout.tsx | 184 +++++++++++++----- src/frontend/src/states/LocalState.tsx | 6 + 2 files changed, 144 insertions(+), 46 deletions(-) diff --git a/src/frontend/src/components/dashboard/DashboardLayout.tsx b/src/frontend/src/components/dashboard/DashboardLayout.tsx index 0a0d02aa3c..5edcf5cc26 100644 --- a/src/frontend/src/components/dashboard/DashboardLayout.tsx +++ b/src/frontend/src/components/dashboard/DashboardLayout.tsx @@ -1,5 +1,13 @@ import { t } from '@lingui/core/macro'; -import { Alert, Card, Center, Divider, Loader, Text } from '@mantine/core'; +import { + Alert, + Card, + Center, + Divider, + Loader, + Space, + Text +} from '@mantine/core'; import { useDisclosure, useHotkeys } from '@mantine/hooks'; import { IconExclamationCircle, IconInfoCircle } from '@tabler/icons-react'; import { useCallback, useEffect, useMemo, useState } from 'react'; @@ -21,15 +29,23 @@ export default function DashboardLayout() { const [widgets, setWidgets] = useState([]); // local/remote storage values for widget / layout - const [remoteWidgets, setRemoteWidgets, remoteLayouts, setRemoteLayouts] = - useLocalState( - useShallow((state) => [ - state.widgets, - state.setWidgets, - state.layouts, - state.setLayouts - ]) - ); + const [ + remoteWidgets, + setRemoteWidgets, + remoteLayouts, + setRemoteLayouts, + showSampleDashboard, + setShowSampleDashboard + ] = useLocalState( + useShallow((state) => [ + state.widgets, + state.setWidgets, + state.layouts, + state.setLayouts, + state.showSampleDashboard, + state.setShowSampleDashboard + ]) + ); const [editing, setEditing] = useDisclosure(false); const [removing, setRemoving] = useDisclosure(false); @@ -75,6 +91,9 @@ export default function DashboardLayout() { ); if (newWidget) { + if (showSampleDashboard) { + setShowSampleDashboard(false); + } setWidgets([...widgets, newWidget]); } @@ -195,10 +214,48 @@ export default function DashboardLayout() { // Clear all widgets from the dashboard const clearWidgets = useCallback(() => { + if (showSampleDashboard) { + setShowSampleDashboard(false); + } setWidgets([]); setLayouts({}); }, []); + const defaultLayouts = { + lg: [ + { + w: 6, + h: 4, + x: 0, + y: 0, + i: 'gstart', + minW: 5, + minH: 4, + moved: false, + static: false + }, + { + w: 6, + h: 4, + x: 6, + y: 0, + i: 'news', + minW: 5, + minH: 4, + moved: false, + static: false + } + ] + }; + const loadWigs = ['news', 'gstart']; + const defaultWidgets = useMemo(() => { + return loadWigs + .map((lwid: string) => + availableWidgets.items.find((wid) => wid.label === lwid) + ) + .filter((widget): widget is DashboardWidgetProps => widget !== undefined); + }, [availableWidgets.items, defaultLayouts]); + return ( <> {widgetLabels.length == 0 ? ( -
- - } - > - {t`Use the menu to add widgets to the dashboard`} - - -
+ <> +
+ + } + > + {t`Use the menu to add widgets to the dashboard`} + + +
+ {showSampleDashboard && ( + <> + + {WidgetGrid( + defaultLayouts, + () => {}, + editing, + defaultWidgets, + removing, + () => {} + )} + + )} + ) : ( - - {widgets.map((item: DashboardWidgetProps) => { - return DashboardWidget({ - item: item, - editing: editing, - removing: removing, - onRemove: () => { - removeWidget(item.label); - } - }); - })} - + WidgetGrid( + layouts, + onLayoutChange, + editing, + widgets, + removing, + removeWidget + ) )} ) : ( @@ -275,3 +330,40 @@ export default function DashboardLayout() { ); } + +function WidgetGrid( + layouts: {}, + onLayoutChange: (layout: any, newLayouts: any) => void, + editing: boolean, + widgets: DashboardWidgetProps[], + removing: boolean, + removeWidget: (widget: string) => void +) { + return ( + + {widgets.map((item: DashboardWidgetProps) => { + return DashboardWidget({ + item: item, + editing: editing, + removing: removing, + onRemove: () => { + removeWidget(item.label); + } + }); + })} + + ); +} diff --git a/src/frontend/src/states/LocalState.tsx b/src/frontend/src/states/LocalState.tsx index fcd9f6d5cb..93184d4285 100644 --- a/src/frontend/src/states/LocalState.tsx +++ b/src/frontend/src/states/LocalState.tsx @@ -31,6 +31,8 @@ interface LocalStateProps { setWidgets: (widgets: string[], noPatch?: boolean) => void; layouts: any; setLayouts: (layouts: any, noPatch?: boolean) => void; + showSampleDashboard: boolean; + setShowSampleDashboard: (value: boolean) => void; // panels lastUsedPanels: Record; setLastUsedPanel: (panelKey: string) => (value: string) => void; @@ -118,6 +120,10 @@ export const useLocalState = create()( if (!noPatch) patchUser('widgets', { widgets: get().widgets, layouts: newLayouts }); }, + showSampleDashboard: true, + setShowSampleDashboard: (value) => { + set({ showSampleDashboard: value }); + }, // panels lastUsedPanels: {}, setLastUsedPanel: (panelKey) => (value) => {