diff --git a/src/frontend/src/components/tables/bom/BomTable.tsx b/src/frontend/src/components/tables/bom/BomTable.tsx index 9b86d5b4bf..17016a4623 100644 --- a/src/frontend/src/components/tables/bom/BomTable.tsx +++ b/src/frontend/src/components/tables/bom/BomTable.tsx @@ -10,9 +10,11 @@ import { useNavigate } from 'react-router-dom'; import { formatPriceRange } from '../../../defaults/formatters'; import { ApiPaths } from '../../../enums/ApiEndpoints'; +import { ModelType } from '../../../enums/ModelType'; import { UserRoles } from '../../../enums/Roles'; import { bomItemFields } from '../../../forms/BomForms'; import { openDeleteApiForm, openEditApiForm } from '../../../functions/forms'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { useUserState } from '../../../states/UserState'; @@ -364,7 +366,8 @@ export function BomTable({ sub_part_detail: true }, tableFilters: tableFilters, - onRowClick: (row) => navigate(`/part/${row.sub_part}`), + onRowClick: (row) => + navigate(getDetailUrl(ModelType.part, row.sub_part)), rowActions: rowActions }} /> diff --git a/src/frontend/src/components/tables/bom/UsedInTable.tsx b/src/frontend/src/components/tables/bom/UsedInTable.tsx index 15dcded36f..bf690b260c 100644 --- a/src/frontend/src/components/tables/bom/UsedInTable.tsx +++ b/src/frontend/src/components/tables/bom/UsedInTable.tsx @@ -3,6 +3,8 @@ import { useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { ApiPaths } from '../../../enums/ApiEndpoints'; +import { ModelType } from '../../../enums/ModelType'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { PartHoverCard } from '../../images/Thumbnail'; @@ -93,7 +95,7 @@ export function UsedInTable({ sub_part_detail: true }, tableFilters: tableFilters, - onRowClick: (row) => navigate(`/part/${row.part}`) + onRowClick: (row) => navigate(getDetailUrl(ModelType.part, row.part)) }} /> ); diff --git a/src/frontend/src/components/tables/build/BuildLineTable.tsx b/src/frontend/src/components/tables/build/BuildLineTable.tsx index 9fdcffb9db..9c704eb9f0 100644 --- a/src/frontend/src/components/tables/build/BuildLineTable.tsx +++ b/src/frontend/src/components/tables/build/BuildLineTable.tsx @@ -9,6 +9,8 @@ import { useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { ApiPaths } from '../../../enums/ApiEndpoints'; +import { ModelType } from '../../../enums/ModelType'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { useUserState } from '../../../states/UserState'; @@ -233,7 +235,7 @@ export default function BuildLineTable({ params = {} }: { params?: any }) { rowActions: rowActions, onRowClick: (row: any) => { if (row?.part_detail?.pk) { - navigate(`/part/${row.part_detail.pk}`); + navigate(getDetailUrl(ModelType.part, row.part_detail.pk)); } } }} diff --git a/src/frontend/src/components/tables/build/BuildOrderTable.tsx b/src/frontend/src/components/tables/build/BuildOrderTable.tsx index 2d9e5fb1df..1e3290848b 100644 --- a/src/frontend/src/components/tables/build/BuildOrderTable.tsx +++ b/src/frontend/src/components/tables/build/BuildOrderTable.tsx @@ -5,6 +5,7 @@ import { useNavigate } from 'react-router-dom'; import { renderDate } from '../../../defaults/formatters'; import { ApiPaths } from '../../../enums/ApiEndpoints'; import { ModelType } from '../../../enums/ModelType'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { PartHoverCard } from '../../images/Thumbnail'; @@ -144,7 +145,7 @@ export function BuildOrderTable({ params = {} }: { params?: any }) { part_detail: true }, tableFilters: tableFilters, - onRowClick: (row) => navigate(`/build/${row.pk}`) + onRowClick: (row) => navigate(getDetailUrl(ModelType.build, row.pk)) }} /> ); diff --git a/src/frontend/src/components/tables/part/PartCategoryTable.tsx b/src/frontend/src/components/tables/part/PartCategoryTable.tsx index 30d731d7bc..8b28089a9a 100644 --- a/src/frontend/src/components/tables/part/PartCategoryTable.tsx +++ b/src/frontend/src/components/tables/part/PartCategoryTable.tsx @@ -3,9 +3,11 @@ import { useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { ApiPaths } from '../../../enums/ApiEndpoints'; +import { ModelType } from '../../../enums/ModelType'; import { UserRoles } from '../../../enums/Roles'; import { partCategoryFields } from '../../../forms/PartForms'; import { openCreateApiForm, openEditApiForm } from '../../../functions/forms'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { useUserState } from '../../../states/UserState'; @@ -140,9 +142,8 @@ export function PartCategoryTable({ parentId }: { parentId?: any }) { tableFilters: tableFilters, tableActions: tableActions, rowActions: rowActions, - onRowClick: (record, index, event) => { - navigate(`/part/category/${record.pk}`); - } + onRowClick: (record, index, event) => + navigate(getDetailUrl(ModelType.partcategory, record.pk)) }} /> ); diff --git a/src/frontend/src/components/tables/part/PartTable.tsx b/src/frontend/src/components/tables/part/PartTable.tsx index 1bff34b1b3..49477b84a7 100644 --- a/src/frontend/src/components/tables/part/PartTable.tsx +++ b/src/frontend/src/components/tables/part/PartTable.tsx @@ -5,7 +5,9 @@ import { useNavigate } from 'react-router-dom'; import { formatPriceRange } from '../../../defaults/formatters'; import { ApiPaths } from '../../../enums/ApiEndpoints'; +import { ModelType } from '../../../enums/ModelType'; import { shortenString } from '../../../functions/tables'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { Thumbnail } from '../../images/Thumbnail'; @@ -280,9 +282,8 @@ export function PartListTable({ props }: { props: InvenTreeTableProps }) { ...props.params, category_detail: true }, - onRowClick: (record, _index, _event) => { - navigate(`/part/${record.pk}/`); - } + onRowClick: (record) => + navigate(getDetailUrl(ModelType.part, record.pk)) }} /> ); diff --git a/src/frontend/src/components/tables/purchasing/ManufacturerPartTable.tsx b/src/frontend/src/components/tables/purchasing/ManufacturerPartTable.tsx index 2982e2e8e9..ecaea0780a 100644 --- a/src/frontend/src/components/tables/purchasing/ManufacturerPartTable.tsx +++ b/src/frontend/src/components/tables/purchasing/ManufacturerPartTable.tsx @@ -3,10 +3,12 @@ import { ReactNode, useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { ApiPaths } from '../../../enums/ApiEndpoints'; +import { ModelType } from '../../../enums/ModelType'; import { UserRoles } from '../../../enums/Roles'; import { useManufacturerPartFields } from '../../../forms/CompanyForms'; import { openDeleteApiForm, openEditApiForm } from '../../../functions/forms'; import { notYetImplemented } from '../../../functions/notifications'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { useUserState } from '../../../states/UserState'; @@ -132,7 +134,7 @@ export function ManufacturerPartTable({ params }: { params: any }): ReactNode { tableActions: tableActions, onRowClick: (record: any) => { if (record?.pk) { - navigate(`/purchasing/manufacturer-part/${record.pk}/`); + navigate(getDetailUrl(ModelType.manufacturerpart, record.pk)); } } }} diff --git a/src/frontend/src/components/tables/purchasing/PurchaseOrderLineItemTable.tsx b/src/frontend/src/components/tables/purchasing/PurchaseOrderLineItemTable.tsx index 7cd81218f1..0029643049 100644 --- a/src/frontend/src/components/tables/purchasing/PurchaseOrderLineItemTable.tsx +++ b/src/frontend/src/components/tables/purchasing/PurchaseOrderLineItemTable.tsx @@ -2,12 +2,15 @@ import { t } from '@lingui/macro'; import { Text } from '@mantine/core'; import { IconSquareArrowRight } from '@tabler/icons-react'; import { useCallback, useMemo } from 'react'; +import { useNavigate } from 'react-router-dom'; import { ProgressBar } from '../../../components/items/ProgressBar'; import { ApiPaths } from '../../../enums/ApiEndpoints'; +import { ModelType } from '../../../enums/ModelType'; import { UserRoles } from '../../../enums/Roles'; import { purchaseOrderLineItemFields } from '../../../forms/PurchaseOrderForms'; import { openCreateApiForm, openEditApiForm } from '../../../functions/forms'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { useUserState } from '../../../states/UserState'; @@ -41,6 +44,7 @@ export function PurchaseOrderLineItemTable({ }) { const table = useTable('purchase-order-line-item'); + const navigate = useNavigate(); const user = useUserState(); const rowActions = useCallback( @@ -260,7 +264,12 @@ export function PurchaseOrderLineItemTable({ part_detail: true }, rowActions: rowActions, - tableActions: tableActions + tableActions: tableActions, + onRowClick: (row: any) => { + if (row.part) { + navigate(getDetailUrl(ModelType.supplierpart, row.part)); + } + } }} /> ); diff --git a/src/frontend/src/components/tables/purchasing/PurchaseOrderTable.tsx b/src/frontend/src/components/tables/purchasing/PurchaseOrderTable.tsx index 7416b24434..b80bd41e69 100644 --- a/src/frontend/src/components/tables/purchasing/PurchaseOrderTable.tsx +++ b/src/frontend/src/components/tables/purchasing/PurchaseOrderTable.tsx @@ -6,6 +6,7 @@ import { ApiPaths } from '../../../enums/ApiEndpoints'; import { ModelType } from '../../../enums/ModelType'; import { UserRoles } from '../../../enums/Roles'; import { notYetImplemented } from '../../../functions/notifications'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { useUserState } from '../../../states/UserState'; @@ -127,7 +128,7 @@ export function PurchaseOrderTable({ params }: { params?: any }) { tableActions: tableActions, onRowClick: (row: any) => { if (row.pk) { - navigate(`/purchasing/purchase-order/${row.pk}`); + navigate(getDetailUrl(ModelType.purchaseorder, row.pk)); } } }} diff --git a/src/frontend/src/components/tables/purchasing/SupplierPartTable.tsx b/src/frontend/src/components/tables/purchasing/SupplierPartTable.tsx index 2e2bd7278b..2def89a928 100644 --- a/src/frontend/src/components/tables/purchasing/SupplierPartTable.tsx +++ b/src/frontend/src/components/tables/purchasing/SupplierPartTable.tsx @@ -4,9 +4,11 @@ import { ReactNode, useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { ApiPaths } from '../../../enums/ApiEndpoints'; +import { ModelType } from '../../../enums/ModelType'; import { UserRoles } from '../../../enums/Roles'; import { useSupplierPartFields } from '../../../forms/CompanyForms'; import { openDeleteApiForm, openEditApiForm } from '../../../functions/forms'; +import { getDetailUrl } from '../../../functions/urls'; import { useCreateApiFormModal } from '../../../hooks/UseForm'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; @@ -234,7 +236,7 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode { tableActions: tableActions, onRowClick: (record: any) => { if (record?.pk) { - navigate(`/purchasing/supplier-part/${record.pk}/`); + navigate(getDetailUrl(ModelType.supplierpart, record.pk)); } } }} diff --git a/src/frontend/src/components/tables/sales/ReturnOrderTable.tsx b/src/frontend/src/components/tables/sales/ReturnOrderTable.tsx index 4dfad75c28..3dd3c1cb25 100644 --- a/src/frontend/src/components/tables/sales/ReturnOrderTable.tsx +++ b/src/frontend/src/components/tables/sales/ReturnOrderTable.tsx @@ -6,6 +6,7 @@ import { ApiPaths } from '../../../enums/ApiEndpoints'; import { ModelType } from '../../../enums/ModelType'; import { UserRoles } from '../../../enums/Roles'; import { notYetImplemented } from '../../../functions/notifications'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { useUserState } from '../../../states/UserState'; @@ -123,7 +124,7 @@ export function ReturnOrderTable({ params }: { params?: any }) { tableActions: tableActions, onRowClick: (row: any) => { if (row.pk) { - navigate(`/sales/return-order/${row.pk}/`); + navigate(getDetailUrl(ModelType.returnorder, row.pk)); } } }} diff --git a/src/frontend/src/components/tables/sales/SalesOrderTable.tsx b/src/frontend/src/components/tables/sales/SalesOrderTable.tsx index 69427ca259..c76fd39bba 100644 --- a/src/frontend/src/components/tables/sales/SalesOrderTable.tsx +++ b/src/frontend/src/components/tables/sales/SalesOrderTable.tsx @@ -6,6 +6,7 @@ import { ApiPaths } from '../../../enums/ApiEndpoints'; import { ModelType } from '../../../enums/ModelType'; import { UserRoles } from '../../../enums/Roles'; import { notYetImplemented } from '../../../functions/notifications'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { useUserState } from '../../../states/UserState'; @@ -124,7 +125,7 @@ export function SalesOrderTable({ params }: { params?: any }) { tableActions: tableActions, onRowClick: (row: any) => { if (row.pk) { - navigate(`/sales/sales-order/${row.pk}/`); + navigate(getDetailUrl(ModelType.salesorder, row.pk)); } } }} diff --git a/src/frontend/src/components/tables/stock/StockItemTable.tsx b/src/frontend/src/components/tables/stock/StockItemTable.tsx index 62365eeaf3..6e3e07fd2d 100644 --- a/src/frontend/src/components/tables/stock/StockItemTable.tsx +++ b/src/frontend/src/components/tables/stock/StockItemTable.tsx @@ -6,6 +6,7 @@ import { useNavigate } from 'react-router-dom'; import { formatCurrency, renderDate } from '../../../defaults/formatters'; import { ApiPaths } from '../../../enums/ApiEndpoints'; import { ModelType } from '../../../enums/ModelType'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { TableColumn } from '../Column'; @@ -345,7 +346,8 @@ export function StockItemTable({ params = {} }: { params?: any }) { enableDownload: true, enableSelection: true, tableFilters: tableFilters, - onRowClick: (record) => navigate(`/stock/item/${record.pk}`), + onRowClick: (record) => + navigate(getDetailUrl(ModelType.stockitem, 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 index e6d3b29457..c638272886 100644 --- a/src/frontend/src/components/tables/stock/StockLocationTable.tsx +++ b/src/frontend/src/components/tables/stock/StockLocationTable.tsx @@ -3,9 +3,11 @@ import { useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { ApiPaths } from '../../../enums/ApiEndpoints'; +import { ModelType } from '../../../enums/ModelType'; import { UserRoles } from '../../../enums/Roles'; import { stockLocationFields } from '../../../forms/StockForms'; import { openCreateApiForm, openEditApiForm } from '../../../functions/forms'; +import { getDetailUrl } from '../../../functions/urls'; import { useTable } from '../../../hooks/UseTable'; import { apiUrl } from '../../../states/ApiState'; import { useUserState } from '../../../states/UserState'; @@ -164,7 +166,7 @@ export function StockLocationTable({ parentId }: { parentId?: any }) { tableActions: tableActions, rowActions: rowActions, onRowClick: (record) => { - navigate(`/stock/location/${record.pk}`); + navigate(getDetailUrl(ModelType.stocklocation, record.pk)); } // TODO: allow for "tree view" with cascade }} diff --git a/src/frontend/src/functions/urls.tsx b/src/frontend/src/functions/urls.tsx new file mode 100644 index 0000000000..5920439c89 --- /dev/null +++ b/src/frontend/src/functions/urls.tsx @@ -0,0 +1,16 @@ +import { ModelInformationDict } from '../components/render/ModelType'; +import { ModelType } from '../enums/ModelType'; + +/** + * Returns the detail view URL for a given model type + */ +export function getDetailUrl(model: ModelType, pk: number | string): string { + const modelInfo = ModelInformationDict[model]; + + if (modelInfo && modelInfo.url_detail) { + return modelInfo.url_detail.replace(':pk', pk.toString()); + } + + console.error(`No detail URL found for model ${model}!`); + return ''; +}