diff --git a/src/frontend/src/components/DashboardItemProxy.tsx b/src/frontend/src/components/DashboardItemProxy.tsx
new file mode 100644
index 0000000000..ef77e1ff69
--- /dev/null
+++ b/src/frontend/src/components/DashboardItemProxy.tsx
@@ -0,0 +1,50 @@
+import { t } from '@lingui/macro';
+import { useQuery } from '@tanstack/react-query';
+import { useEffect, useState } from 'react';
+
+import { api } from '../App';
+import { StatisticItem } from './items/DashboardItem';
+import { ErrorItem } from './items/ErrorItem';
+
+export function DashboardItemProxy({
+ id,
+ text,
+ url,
+ params,
+ autoupdate = true
+}: {
+ id: string;
+ text: string;
+ url: string;
+ params: any;
+ autoupdate: boolean;
+}) {
+ function fetchData() {
+ return api
+ .get(`${url}/?search=&offset=0&limit=25`, { params: params })
+ .then((res) => res.data);
+ }
+ const { isLoading, error, data, isFetching } = useQuery({
+ queryKey: [`dash_${id}`],
+ queryFn: fetchData,
+ refetchOnWindowFocus: autoupdate
+ });
+ const [dashdata, setDashData] = useState({ title: t`Title`, value: '000' });
+
+ useEffect(() => {
+ if (data) {
+ setDashData({ title: text, value: data.count });
+ }
+ }, [data]);
+
+ if (error != null) return ;
+ return (
+
+
+
+ );
+}
diff --git a/src/frontend/src/components/items/DashboardItem.tsx b/src/frontend/src/components/items/DashboardItem.tsx
new file mode 100644
index 0000000000..49b9b6bf46
--- /dev/null
+++ b/src/frontend/src/components/items/DashboardItem.tsx
@@ -0,0 +1,35 @@
+import { Group, LoadingOverlay, Paper, Text } from '@mantine/core';
+
+import { InvenTreeStyle } from '../../globalStyle';
+
+export interface StatisticItemProps {
+ title: string;
+ value: string;
+}
+
+export function StatisticItem({
+ id,
+ data,
+ isLoading
+}: {
+ id: string;
+ data: StatisticItemProps;
+ isLoading: boolean;
+}) {
+ const { classes } = InvenTreeStyle();
+
+ return (
+
+
+
+
+ {data.title}
+
+
+
+
+ {data.value}
+
+
+ );
+}
diff --git a/src/frontend/src/defaults/dashboardItems.tsx b/src/frontend/src/defaults/dashboardItems.tsx
new file mode 100644
index 0000000000..fe56a2450c
--- /dev/null
+++ b/src/frontend/src/defaults/dashboardItems.tsx
@@ -0,0 +1,123 @@
+import { t } from '@lingui/macro';
+
+export const dashboardItems = [
+ {
+ id: 'starred-parts',
+ text: t`Subscribed Parts`,
+ icon: 'fa-bell',
+ url: 'part',
+ params: { starred: true }
+ },
+ {
+ id: 'starred-categories',
+ text: t`Subscribed Categories`,
+ icon: 'fa-bell',
+ url: 'part/category',
+ params: { starred: true }
+ },
+ {
+ id: 'latest-parts',
+ text: t`Latest Parts`,
+ icon: 'fa-newspaper',
+ url: 'part',
+ params: { ordering: '-creation_date', limit: 10 }
+ },
+ {
+ id: 'bom-validation',
+ text: t`BOM Waiting Validation`,
+ icon: 'fa-times-circle',
+ url: 'part',
+ params: { bom_valid: false }
+ },
+ {
+ id: 'recently-updated-stock',
+ text: t`Recently Updated`,
+ icon: 'fa-clock',
+ url: 'stock',
+ params: { part_detail: true, ordering: '-updated', limit: 10 }
+ },
+ {
+ id: 'low-stock',
+ text: t`Low Stock`,
+ icon: 'fa-flag',
+ url: 'part',
+ params: { low_stock: true }
+ },
+ {
+ id: 'depleted-stock',
+ text: t`Depleted Stock`,
+ icon: 'fa-times',
+ url: 'part',
+ params: { depleted_stock: true }
+ },
+ {
+ id: 'stock-to-build',
+ text: t`Required for Build Orders`,
+ icon: 'fa-bullhorn',
+ url: 'part',
+ params: { stock_to_build: true }
+ },
+ {
+ id: 'expired-stock',
+ text: t`Expired Stock`,
+ icon: 'fa-calendar-times',
+ url: 'stock',
+ params: { expired: true }
+ },
+ {
+ id: 'stale-stock',
+ text: t`Stale Stock`,
+ icon: 'fa-stopwatch',
+ url: 'stock',
+ params: { stale: true, expired: true }
+ },
+ {
+ id: 'build-pending',
+ text: t`Build Orders In Progress`,
+ icon: 'fa-cogs',
+ url: 'build',
+ params: { active: true }
+ },
+ {
+ id: 'build-overdue',
+ text: t`Overdue Build Orders`,
+ icon: 'fa-calendar-times',
+ url: 'build',
+ params: { overdue: true }
+ },
+ {
+ id: 'po-outstanding',
+ text: t`Outstanding Purchase Orders`,
+ icon: 'fa-sign-in-alt',
+ url: 'order/po',
+ params: { supplier_detail: true, outstanding: true }
+ },
+ {
+ id: 'po-overdue',
+ text: t`Overdue Purchase Orders`,
+ icon: 'fa-calendar-times',
+ url: 'order/po',
+ params: { supplier_detail: true, overdue: true }
+ },
+ {
+ id: 'so-outstanding',
+ text: t`Outstanding Sales Orders`,
+ icon: 'fa-sign-out-alt',
+ url: 'order/so',
+ params: { customer_detail: true, outstanding: true }
+ },
+ {
+ id: 'so-overdue',
+ text: t`Overdue Sales Orders`,
+ icon: 'fa-calendar-times',
+ url: 'order/so',
+ params: { customer_detail: true, overdue: true }
+ },
+ {
+ id: 'news',
+ text: t`Current News`,
+ icon: 'fa-newspaper',
+ url: 'news',
+ params: {}
+ }
+];
diff --git a/src/frontend/src/defaults/links.tsx b/src/frontend/src/defaults/links.tsx
index 375a7288b8..eec78e43a3 100644
--- a/src/frontend/src/defaults/links.tsx
+++ b/src/frontend/src/defaults/links.tsx
@@ -19,7 +19,10 @@ export const footerLinks = [
key: 'demo'
}
];
-export const navTabs = [{ text: Home, name: 'home' }];
+export const navTabs = [
+ { text: Home, name: 'home' },
+ { text: Dashboard, name: 'dashboard' }
+];
export const docLinks = {
app: 'https://docs.inventree.org/en/latest/app/app/',
diff --git a/src/frontend/src/pages/Index/Dashboard.tsx b/src/frontend/src/pages/Index/Dashboard.tsx
new file mode 100644
index 0000000000..7b4e1d59a7
--- /dev/null
+++ b/src/frontend/src/pages/Index/Dashboard.tsx
@@ -0,0 +1,39 @@
+import { Trans } from '@lingui/macro';
+import { Chip, Group, SimpleGrid, Text } from '@mantine/core';
+
+import { DashboardItemProxy } from '../../components/DashboardItemProxy';
+import { StylishText } from '../../components/items/StylishText';
+import { dashboardItems } from '../../defaults/dashboardItems';
+import { useLocalState } from '../../states/LocalState';
+
+export default function Dashboard() {
+ const [autoupdate, toggleAutoupdate] = useLocalState((state) => [
+ state.autoupdate,
+ state.toggleAutoupdate
+ ]);
+
+ return (
+ <>
+
+
+ Dashboard
+
+ toggleAutoupdate()}>
+ Autoupdate
+
+
+
+
+ This page is a replacement for the old start page with the same
+ information. This page will be deprecated and replaced by the home
+ page.
+
+
+
+ {dashboardItems.map((item) => (
+
+ ))}
+
+ >
+ );
+}
diff --git a/src/frontend/src/router.tsx b/src/frontend/src/router.tsx
index 7b1b62ac85..43b1dbaf0b 100644
--- a/src/frontend/src/router.tsx
+++ b/src/frontend/src/router.tsx
@@ -8,6 +8,9 @@ export const LayoutComponent = Loadable(
lazy(() => import('./components/nav/Layout'))
);
export const Home = Loadable(lazy(() => import('./pages/Index/Home')));
+export const Dashboard = Loadable(
+ lazy(() => import('./pages/Index/Dashboard'))
+);
export const ErrorPage = Loadable(lazy(() => import('./pages/ErrorPage')));
export const Profile = Loadable(
lazy(() => import('./pages/Index/Profile/Profile'))
@@ -41,6 +44,10 @@ export const router = createBrowserRouter(
path: 'home/',
element:
},
+ {
+ path: 'dashboard/',
+ element:
+ },
{
path: '/profile/:tabValue',
element: