mirror of
https://github.com/inventree/InvenTree.git
synced 2025-09-14 14:41:33 +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