mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	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
This commit is contained in:
		| @@ -1,5 +1,13 @@ | |||||||
| import { t } from '@lingui/core/macro'; | 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 { useDisclosure, useHotkeys } from '@mantine/hooks'; | ||||||
| import { IconExclamationCircle, IconInfoCircle } from '@tabler/icons-react'; | import { IconExclamationCircle, IconInfoCircle } from '@tabler/icons-react'; | ||||||
| import { useCallback, useEffect, useMemo, useState } from 'react'; | import { useCallback, useEffect, useMemo, useState } from 'react'; | ||||||
| @@ -21,15 +29,23 @@ export default function DashboardLayout() { | |||||||
|   const [widgets, setWidgets] = useState<DashboardWidgetProps[]>([]); |   const [widgets, setWidgets] = useState<DashboardWidgetProps[]>([]); | ||||||
|  |  | ||||||
|   // local/remote storage values for widget / layout |   // local/remote storage values for widget / layout | ||||||
|   const [remoteWidgets, setRemoteWidgets, remoteLayouts, setRemoteLayouts] = |   const [ | ||||||
|     useLocalState( |     remoteWidgets, | ||||||
|       useShallow((state) => [ |     setRemoteWidgets, | ||||||
|         state.widgets, |     remoteLayouts, | ||||||
|         state.setWidgets, |     setRemoteLayouts, | ||||||
|         state.layouts, |     showSampleDashboard, | ||||||
|         state.setLayouts |     setShowSampleDashboard | ||||||
|       ]) |   ] = useLocalState( | ||||||
|     ); |     useShallow((state) => [ | ||||||
|  |       state.widgets, | ||||||
|  |       state.setWidgets, | ||||||
|  |       state.layouts, | ||||||
|  |       state.setLayouts, | ||||||
|  |       state.showSampleDashboard, | ||||||
|  |       state.setShowSampleDashboard | ||||||
|  |     ]) | ||||||
|  |   ); | ||||||
|  |  | ||||||
|   const [editing, setEditing] = useDisclosure(false); |   const [editing, setEditing] = useDisclosure(false); | ||||||
|   const [removing, setRemoving] = useDisclosure(false); |   const [removing, setRemoving] = useDisclosure(false); | ||||||
| @@ -75,6 +91,9 @@ export default function DashboardLayout() { | |||||||
|       ); |       ); | ||||||
|  |  | ||||||
|       if (newWidget) { |       if (newWidget) { | ||||||
|  |         if (showSampleDashboard) { | ||||||
|  |           setShowSampleDashboard(false); | ||||||
|  |         } | ||||||
|         setWidgets([...widgets, newWidget]); |         setWidgets([...widgets, newWidget]); | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -195,10 +214,48 @@ export default function DashboardLayout() { | |||||||
|  |  | ||||||
|   // Clear all widgets from the dashboard |   // Clear all widgets from the dashboard | ||||||
|   const clearWidgets = useCallback(() => { |   const clearWidgets = useCallback(() => { | ||||||
|  |     if (showSampleDashboard) { | ||||||
|  |       setShowSampleDashboard(false); | ||||||
|  |     } | ||||||
|     setWidgets([]); |     setWidgets([]); | ||||||
|     setLayouts({}); |     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 ( |   return ( | ||||||
|     <> |     <> | ||||||
|       <DashboardWidgetDrawer |       <DashboardWidgetDrawer | ||||||
| @@ -228,43 +285,41 @@ export default function DashboardLayout() { | |||||||
|       {layouts && loaded && availableWidgets.loaded ? ( |       {layouts && loaded && availableWidgets.loaded ? ( | ||||||
|         <> |         <> | ||||||
|           {widgetLabels.length == 0 ? ( |           {widgetLabels.length == 0 ? ( | ||||||
|             <Center> |             <> | ||||||
|               <Card shadow='xs' padding='xl' style={{ width: '100%' }}> |               <Center> | ||||||
|                 <Alert |                 <Card shadow='xs' padding='xl' style={{ width: '100%' }}> | ||||||
|                   color='blue' |                   <Alert | ||||||
|                   title={t`No Widgets Selected`} |                     color='blue' | ||||||
|                   icon={<IconInfoCircle />} |                     title={t`No Widgets Selected`} | ||||||
|                 > |                     icon={<IconInfoCircle />} | ||||||
|                   <Text>{t`Use the menu to add widgets to the dashboard`}</Text> |                   > | ||||||
|                 </Alert> |                     <Text>{t`Use the menu to add widgets to the dashboard`}</Text> | ||||||
|               </Card> |                   </Alert> | ||||||
|             </Center> |                 </Card> | ||||||
|  |               </Center> | ||||||
|  |               {showSampleDashboard && ( | ||||||
|  |                 <> | ||||||
|  |                   <Space h='lg' /> | ||||||
|  |                   {WidgetGrid( | ||||||
|  |                     defaultLayouts, | ||||||
|  |                     () => {}, | ||||||
|  |                     editing, | ||||||
|  |                     defaultWidgets, | ||||||
|  |                     removing, | ||||||
|  |                     () => {} | ||||||
|  |                   )} | ||||||
|  |                 </> | ||||||
|  |               )} | ||||||
|  |             </> | ||||||
|           ) : ( |           ) : ( | ||||||
|             <ReactGridLayout |             WidgetGrid( | ||||||
|               className='dashboard-layout' |               layouts, | ||||||
|               breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }} |               onLayoutChange, | ||||||
|               cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }} |               editing, | ||||||
|               rowHeight={64} |               widgets, | ||||||
|               layouts={layouts} |               removing, | ||||||
|               onLayoutChange={onLayoutChange} |               removeWidget | ||||||
|               compactType={'vertical'} |             ) | ||||||
|               isDraggable={editing} |  | ||||||
|               isResizable={editing} |  | ||||||
|               margin={[10, 10]} |  | ||||||
|               containerPadding={[0, 0]} |  | ||||||
|               resizeHandles={['ne', 'se', 'sw', 'nw']} |  | ||||||
|             > |  | ||||||
|               {widgets.map((item: DashboardWidgetProps) => { |  | ||||||
|                 return DashboardWidget({ |  | ||||||
|                   item: item, |  | ||||||
|                   editing: editing, |  | ||||||
|                   removing: removing, |  | ||||||
|                   onRemove: () => { |  | ||||||
|                     removeWidget(item.label); |  | ||||||
|                   } |  | ||||||
|                 }); |  | ||||||
|               })} |  | ||||||
|             </ReactGridLayout> |  | ||||||
|           )} |           )} | ||||||
|         </> |         </> | ||||||
|       ) : ( |       ) : ( | ||||||
| @@ -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 ( | ||||||
|  |     <ReactGridLayout | ||||||
|  |       className='dashboard-layout' | ||||||
|  |       breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }} | ||||||
|  |       cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }} | ||||||
|  |       rowHeight={64} | ||||||
|  |       layouts={layouts} | ||||||
|  |       onLayoutChange={onLayoutChange} | ||||||
|  |       compactType={'vertical'} | ||||||
|  |       isDraggable={editing} | ||||||
|  |       isResizable={editing} | ||||||
|  |       margin={[10, 10]} | ||||||
|  |       containerPadding={[0, 0]} | ||||||
|  |       resizeHandles={['ne', 'se', 'sw', 'nw']} | ||||||
|  |     > | ||||||
|  |       {widgets.map((item: DashboardWidgetProps) => { | ||||||
|  |         return DashboardWidget({ | ||||||
|  |           item: item, | ||||||
|  |           editing: editing, | ||||||
|  |           removing: removing, | ||||||
|  |           onRemove: () => { | ||||||
|  |             removeWidget(item.label); | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |       })} | ||||||
|  |     </ReactGridLayout> | ||||||
|  |   ); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -31,6 +31,8 @@ interface LocalStateProps { | |||||||
|   setWidgets: (widgets: string[], noPatch?: boolean) => void; |   setWidgets: (widgets: string[], noPatch?: boolean) => void; | ||||||
|   layouts: any; |   layouts: any; | ||||||
|   setLayouts: (layouts: any, noPatch?: boolean) => void; |   setLayouts: (layouts: any, noPatch?: boolean) => void; | ||||||
|  |   showSampleDashboard: boolean; | ||||||
|  |   setShowSampleDashboard: (value: boolean) => void; | ||||||
|   // panels |   // panels | ||||||
|   lastUsedPanels: Record<string, string>; |   lastUsedPanels: Record<string, string>; | ||||||
|   setLastUsedPanel: (panelKey: string) => (value: string) => void; |   setLastUsedPanel: (panelKey: string) => (value: string) => void; | ||||||
| @@ -118,6 +120,10 @@ export const useLocalState = create<LocalStateProps>()( | |||||||
|         if (!noPatch) |         if (!noPatch) | ||||||
|           patchUser('widgets', { widgets: get().widgets, layouts: newLayouts }); |           patchUser('widgets', { widgets: get().widgets, layouts: newLayouts }); | ||||||
|       }, |       }, | ||||||
|  |       showSampleDashboard: true, | ||||||
|  |       setShowSampleDashboard: (value) => { | ||||||
|  |         set({ showSampleDashboard: value }); | ||||||
|  |       }, | ||||||
|       // panels |       // panels | ||||||
|       lastUsedPanels: {}, |       lastUsedPanels: {}, | ||||||
|       setLastUsedPanel: (panelKey) => (value) => { |       setLastUsedPanel: (panelKey) => (value) => { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user