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 { 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<DashboardWidgetProps[]>([]); | ||||
|  | ||||
|   // 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 ( | ||||
|     <> | ||||
|       <DashboardWidgetDrawer | ||||
| @@ -228,43 +285,41 @@ export default function DashboardLayout() { | ||||
|       {layouts && loaded && availableWidgets.loaded ? ( | ||||
|         <> | ||||
|           {widgetLabels.length == 0 ? ( | ||||
|             <Center> | ||||
|               <Card shadow='xs' padding='xl' style={{ width: '100%' }}> | ||||
|                 <Alert | ||||
|                   color='blue' | ||||
|                   title={t`No Widgets Selected`} | ||||
|                   icon={<IconInfoCircle />} | ||||
|                 > | ||||
|                   <Text>{t`Use the menu to add widgets to the dashboard`}</Text> | ||||
|                 </Alert> | ||||
|               </Card> | ||||
|             </Center> | ||||
|             <> | ||||
|               <Center> | ||||
|                 <Card shadow='xs' padding='xl' style={{ width: '100%' }}> | ||||
|                   <Alert | ||||
|                     color='blue' | ||||
|                     title={t`No Widgets Selected`} | ||||
|                     icon={<IconInfoCircle />} | ||||
|                   > | ||||
|                     <Text>{t`Use the menu to add widgets to the dashboard`}</Text> | ||||
|                   </Alert> | ||||
|                 </Card> | ||||
|               </Center> | ||||
|               {showSampleDashboard && ( | ||||
|                 <> | ||||
|                   <Space h='lg' /> | ||||
|                   {WidgetGrid( | ||||
|                     defaultLayouts, | ||||
|                     () => {}, | ||||
|                     editing, | ||||
|                     defaultWidgets, | ||||
|                     removing, | ||||
|                     () => {} | ||||
|                   )} | ||||
|                 </> | ||||
|               )} | ||||
|             </> | ||||
|           ) : ( | ||||
|             <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> | ||||
|             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 ( | ||||
|     <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; | ||||
|   layouts: any; | ||||
|   setLayouts: (layouts: any, noPatch?: boolean) => void; | ||||
|   showSampleDashboard: boolean; | ||||
|   setShowSampleDashboard: (value: boolean) => void; | ||||
|   // panels | ||||
|   lastUsedPanels: Record<string, string>; | ||||
|   setLastUsedPanel: (panelKey: string) => (value: string) => void; | ||||
| @@ -118,6 +120,10 @@ export const useLocalState = create<LocalStateProps>()( | ||||
|         if (!noPatch) | ||||
|           patchUser('widgets', { widgets: get().widgets, layouts: newLayouts }); | ||||
|       }, | ||||
|       showSampleDashboard: true, | ||||
|       setShowSampleDashboard: (value) => { | ||||
|         set({ showSampleDashboard: value }); | ||||
|       }, | ||||
|       // panels | ||||
|       lastUsedPanels: {}, | ||||
|       setLastUsedPanel: (panelKey) => (value) => { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user