diff --git a/src/frontend/src/components/nav/PanelGroup.tsx b/src/frontend/src/components/nav/PanelGroup.tsx index b9dc3b66f3..eca3b61ea9 100644 --- a/src/frontend/src/components/nav/PanelGroup.tsx +++ b/src/frontend/src/components/nav/PanelGroup.tsx @@ -1,7 +1,9 @@ -import { Divider, Paper, Stack, Tabs, Text } from '@mantine/core'; +import { Divider, Paper, Stack, Tabs } from '@mantine/core'; import { ReactNode } from 'react'; import { useEffect, useState } from 'react'; +import { StylishText } from '../items/StylishText'; + /** * Type used to specify a single panel in a panel group */ @@ -81,7 +83,7 @@ export function PanelGroup({ !panel.hidden && ( - {panel.label} + {panel.label} {panel.content} diff --git a/src/frontend/src/components/tables/AttachmentTable.tsx b/src/frontend/src/components/tables/AttachmentTable.tsx index 895ab9722f..387f86deed 100644 --- a/src/frontend/src/components/tables/AttachmentTable.tsx +++ b/src/frontend/src/components/tables/AttachmentTable.tsx @@ -225,6 +225,7 @@ export function AttachmentTable({ tableKey={tableKey} columns={tableColumns} props={{ + noRecordsText: t`No attachments found`, enableSelection: true, customActionGroups: customActionGroups, rowActions: allowEdit && allowDelete ? rowActions : undefined, diff --git a/src/frontend/src/components/tables/stock/StockItemTable.tsx b/src/frontend/src/components/tables/stock/StockItemTable.tsx index 76b726b192..0c3a301c96 100644 --- a/src/frontend/src/components/tables/stock/StockItemTable.tsx +++ b/src/frontend/src/components/tables/stock/StockItemTable.tsx @@ -1,6 +1,7 @@ import { t } from '@lingui/macro'; import { Text } from '@mantine/core'; import { useMemo } from 'react'; +import { useNavigate } from 'react-router-dom'; import { notYetImplemented } from '../../../functions/notifications'; import { useTableRefresh } from '../../../hooks/TableRefresh'; @@ -120,6 +121,8 @@ export function StockItemTable({ params = {} }: { params?: any }) { return actions; } + const navigate = useNavigate(); + return ( navigate(`/stock/item/${record.pk}`), params: { ...params, part_detail: true, diff --git a/src/frontend/src/components/tables/stock/StockLocationTable.tsx b/src/frontend/src/components/tables/stock/StockLocationTable.tsx new file mode 100644 index 0000000000..afdda5a803 --- /dev/null +++ b/src/frontend/src/components/tables/stock/StockLocationTable.tsx @@ -0,0 +1,75 @@ +import { t } from '@lingui/macro'; +import { useMemo } from 'react'; +import { useNavigate } from 'react-router-dom'; + +import { useTableRefresh } from '../../../hooks/TableRefresh'; +import { TableColumn } from '../Column'; +import { InvenTreeTable } from '../InvenTreeTable'; + +/** + * Stock location table + */ +export function StockLocationTable({ params = {} }: { params?: any }) { + const { tableKey, refreshTable } = useTableRefresh('stocklocation'); + + const navigate = useNavigate(); + + const tableColumns: TableColumn[] = useMemo(() => { + return [ + { + accessor: 'name', + title: t`Name`, + switchable: false + }, + { + accessor: 'description', + title: t`Description`, + switchable: true + }, + { + accessor: 'pathstring', + title: t`Path`, + sortable: true, + switchable: true + }, + { + accessor: 'items', + title: t`Stock Items`, + switchable: true, + sortable: true + }, + { + accessor: 'structural', + title: t`Structural`, + switchable: true, + sortable: true, + render: (record: any) => (record.structural ? 'Y' : 'N') + // TODO: custom 'true / false' label, + }, + { + accessor: 'external', + title: t`External`, + switchable: true, + sortable: true, + render: (record: any) => (record.structural ? 'Y' : 'N') + // TODO: custom 'true / false' label, + } + ]; + }, [params]); + + return ( + { + navigate(`/stock/location/${record.pk}`); + } + // TODO: allow for "tree view" with cascade + }} + /> + ); +} diff --git a/src/frontend/src/pages/Index/Stock.tsx b/src/frontend/src/pages/Index/Stock.tsx deleted file mode 100644 index b9b6d7020d..0000000000 --- a/src/frontend/src/pages/Index/Stock.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { t } from '@lingui/macro'; -import { Stack } from '@mantine/core'; -import { IconPackages, IconSitemap } from '@tabler/icons-react'; -import { useMemo } from 'react'; - -import { PlaceholderPanel } from '../../components/items/Placeholder'; -import { PageDetail } from '../../components/nav/PageDetail'; -import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; -import { StockItemTable } from '../../components/tables/stock/StockItemTable'; - -export default function Stock() { - const categoryPanels: PanelType[] = useMemo(() => { - return [ - { - name: 'stock-items', - label: t`Stock Items`, - icon: , - content: - }, - { - name: 'sublocations', - label: t`Sublocations`, - icon: , - content: - } - ]; - }, []); - - return ( - <> - - - - - - ); -} diff --git a/src/frontend/src/pages/part/CategoryDetail.tsx b/src/frontend/src/pages/part/CategoryDetail.tsx index 9a554635cf..12f0622cef 100644 --- a/src/frontend/src/pages/part/CategoryDetail.tsx +++ b/src/frontend/src/pages/part/CategoryDetail.tsx @@ -1,5 +1,5 @@ import { t } from '@lingui/macro'; -import { Stack, Text } from '@mantine/core'; +import { LoadingOverlay, Stack, Text } from '@mantine/core'; import { IconCategory, IconListDetails, @@ -25,10 +25,11 @@ import { useInstance } from '../../hooks/UseInstance'; export default function CategoryDetail({}: {}) { const { id } = useParams(); - const { instance: category, refreshInstance } = useInstance( - '/part/category/', - id - ); + const { + instance: category, + refreshInstance, + instanceQuery + } = useInstance('/part/category/', id); const categoryPanels: PanelType[] = useMemo( () => [ @@ -70,6 +71,7 @@ export default function CategoryDetail({}: {}) { return ( + {category.name ?? 'Top level'}} diff --git a/src/frontend/src/pages/part/PartDetail.tsx b/src/frontend/src/pages/part/PartDetail.tsx index 5eb8baed37..b14b2fe840 100644 --- a/src/frontend/src/pages/part/PartDetail.tsx +++ b/src/frontend/src/pages/part/PartDetail.tsx @@ -134,7 +134,13 @@ export default function PartDetail() { name: 'attachments', label: t`Attachments`, icon: , - content: partAttachmentsTab() + content: ( + + ) }, { name: 'notes', @@ -145,16 +151,6 @@ export default function PartDetail() { ]; }, [part]); - function partAttachmentsTab(): React.ReactNode { - return ( - - ); - } - function partRelatedTab(): React.ReactNode { return ; } @@ -181,6 +177,7 @@ export default function PartDetail() { return ( <> + ]} /> - diff --git a/src/frontend/src/pages/stock/LocationDetail.tsx b/src/frontend/src/pages/stock/LocationDetail.tsx new file mode 100644 index 0000000000..5c91deb719 --- /dev/null +++ b/src/frontend/src/pages/stock/LocationDetail.tsx @@ -0,0 +1,75 @@ +import { t } from '@lingui/macro'; +import { LoadingOverlay, Stack, Text } from '@mantine/core'; +import { IconPackages, IconSitemap } from '@tabler/icons-react'; +import { useMemo } from 'react'; +import { useParams } from 'react-router-dom'; + +import { PageDetail } from '../../components/nav/PageDetail'; +import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; +import { StockItemTable } from '../../components/tables/stock/StockItemTable'; +import { StockLocationTable } from '../../components/tables/stock/StockLocationTable'; +import { useInstance } from '../../hooks/UseInstance'; + +export default function Stock() { + const { id } = useParams(); + + const { + instance: location, + refreshInstance, + instanceQuery + } = useInstance('/stock/location/', id); + + const locationPanels: PanelType[] = useMemo(() => { + return [ + { + name: 'stock-items', + label: t`Stock Items`, + icon: , + content: ( + + ) + }, + { + name: 'sublocations', + label: t`Sublocations`, + icon: , + content: ( + + ) + } + ]; + }, [location, id]); + + return ( + <> + + + {location.name ?? 'Top level'}} + breadcrumbs={ + location.pk + ? [ + { name: t`Stock`, url: '/stock' }, + { name: '...', url: '' }, + { + name: location.name ?? t`Top level`, + url: `/stock/location/${location.pk}` + } + ] + : [] + } + /> + + + + ); +} diff --git a/src/frontend/src/pages/stock/StockDetail.tsx b/src/frontend/src/pages/stock/StockDetail.tsx new file mode 100644 index 0000000000..b64f12da70 --- /dev/null +++ b/src/frontend/src/pages/stock/StockDetail.tsx @@ -0,0 +1,117 @@ +import { t } from '@lingui/macro'; +import { Alert, LoadingOverlay, Stack, Text } from '@mantine/core'; +import { + IconBookmark, + IconBoxPadding, + IconHistory, + IconInfoCircle, + IconNotes, + IconPaperclip, + IconSitemap, + IconTransferIn +} from '@tabler/icons-react'; +import { useEffect, useMemo } from 'react'; +import { useParams } from 'react-router-dom'; + +import { PlaceholderPanel } from '../../components/items/Placeholder'; +import { PageDetail } from '../../components/nav/PageDetail'; +import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; +import { AttachmentTable } from '../../components/tables/AttachmentTable'; +import { NotesEditor } from '../../components/widgets/MarkdownEditor'; +import { useInstance } from '../../hooks/UseInstance'; + +export default function StockDetail() { + const { id } = useParams(); + + const { + instance: stockitem, + refreshInstance, + instanceQuery + } = useInstance('/stock/', id, { + part_detail: true, + location_detail: true + }); + + const stockPanels: PanelType[] = useMemo(() => { + return [ + { + name: 'details', + label: t`Details`, + icon: , + content: + }, + { + name: 'tracking', + label: t`Stock Tracking`, + icon: , + content: + }, + { + name: 'allocations', + label: t`Allocations`, + icon: , + content: + }, + { + name: 'installed_items', + label: t`Installed Items`, + icon: , + content: + }, + { + name: 'child_items', + label: t`Child Items`, + icon: , + content: + }, + { + name: 'attachments', + label: t`Attachments`, + icon: , + content: ( + + ) + }, + { + name: 'notes', + label: t`Notes`, + icon: , + content: ( + + ) + } + ]; + }, [stockitem, id]); + + return ( + + + + Quantity: {stockitem.quantity ?? 'idk'} + + } + breadcrumbs={[ + { name: t`Stock`, url: '/stock' }, + { name: '...', url: '' }, + { + name: stockitem.part_detail?.full_name ?? 'name goes here', + url: `/stock/item/${stockitem.pk}` + } + ]} + /> + + + ); +} diff --git a/src/frontend/src/router.tsx b/src/frontend/src/router.tsx index 966b20fdd3..314efd23a8 100644 --- a/src/frontend/src/router.tsx +++ b/src/frontend/src/router.tsx @@ -19,7 +19,13 @@ export const PartDetail = Loadable( lazy(() => import('./pages/part/PartDetail')) ); -export const Stock = Loadable(lazy(() => import('./pages/Index/Stock'))); +export const LocationDetail = Loadable( + lazy(() => import('./pages/stock/LocationDetail')) +); + +export const StockDetail = Loadable( + lazy(() => import('./pages/stock/StockDetail')) +); export const BuildIndex = Loadable( lazy(() => import('./pages/build/BuildIndex')) @@ -102,7 +108,15 @@ export const router = createBrowserRouter( }, { path: 'stock/', - element: + element: + }, + { + path: 'stock/location/:id', + element: + }, + { + path: 'stock/item/:id', + element: }, { path: 'build/',