From 77fd6b6bb32d5b3286afb58cea20dcbd7d9c2268 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 5 Feb 2024 14:25:29 +1100 Subject: [PATCH] [PUI] Tweaks and refactor for "part details" page (#6405) * Add getModelInfo helper function - Extract model definition from provided modeltype * Improvements for details.tsx - Use defined URL functions, not strings - Catch potential errors * Fix PartDetail page - Use modeltype definitions - URL fixes --- .../src/components/render/ModelType.tsx | 15 ++++++++-- src/frontend/src/pages/part/PartDetail.tsx | 17 +++++------ src/frontend/src/tables/Details.tsx | 30 ++++++++++++------- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/frontend/src/components/render/ModelType.tsx b/src/frontend/src/components/render/ModelType.tsx index af24c8fa9b..d5718aa674 100644 --- a/src/frontend/src/components/render/ModelType.tsx +++ b/src/frontend/src/components/render/ModelType.tsx @@ -3,7 +3,7 @@ import { t } from '@lingui/macro'; import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ModelType } from '../../enums/ModelType'; -interface ModelInformationInterface { +export interface ModelInformationInterface { label: string; label_multiple: string; url_overview?: string; @@ -12,11 +12,11 @@ interface ModelInformationInterface { cui_detail?: string; } -type ModelDictory = { +export type ModelDict = { [key in keyof typeof ModelType]: ModelInformationInterface; }; -export const ModelInformationDict: ModelDictory = { +export const ModelInformationDict: ModelDict = { part: { label: t`Part`, label_multiple: t`Parts`, @@ -165,3 +165,12 @@ export const ModelInformationDict: ModelDictory = { api_endpoint: ApiEndpoints.user_list } }; + +/* + * Extract model definition given the provided type + * @param type - ModelType to extract information from + * @returns ModelInformationInterface + */ +export function getModelInfo(type: ModelType): ModelInformationInterface { + return ModelInformationDict[type]; +} diff --git a/src/frontend/src/pages/part/PartDetail.tsx b/src/frontend/src/pages/part/PartDetail.tsx index eab798de80..c2ecf2884d 100644 --- a/src/frontend/src/pages/part/PartDetail.tsx +++ b/src/frontend/src/pages/part/PartDetail.tsx @@ -44,6 +44,7 @@ import { PartCategoryTree } from '../../components/nav/PartCategoryTree'; import { NotesEditor } from '../../components/widgets/MarkdownEditor'; import { formatPriceRange } from '../../defaults/formatters'; import { ApiEndpoints } from '../../enums/ApiEndpoints'; +import { ModelType } from '../../enums/ModelType'; import { UserRoles } from '../../enums/Roles'; import { partFields } from '../../forms/PartForms'; import { useEditApiFormModal } from '../../hooks/UseForm'; @@ -122,8 +123,7 @@ export default function PartDetail() { type: 'link', name: 'variant_of', label: t`Variant of`, - path: ApiEndpoints.part_list, - dest: '/part/' + model: ModelType.part } ]); } @@ -226,8 +226,7 @@ export default function PartDetail() { type: 'link', name: 'category', label: t`Category`, - path: ApiEndpoints.category_list, - dest: '/part/category/' + model: ModelType.partcategory } ]); } @@ -336,7 +335,7 @@ export default function PartDetail() { const { data } = useSuspenseQuery({ queryKey: ['stocktake', id], queryFn: async () => { - const url = ApiEndpoints.part_stocktake_list; + const url = apiUrl(ApiEndpoints.part_stocktake_list); return api .get(url, { params: { part: id, ordering: 'date' } }) @@ -364,7 +363,7 @@ export default function PartDetail() { const { data } = useSuspenseQuery({ queryKey: ['stocktake', id], queryFn: async () => { - const url = ApiEndpoints.part_stocktake_list; + const url = apiUrl(ApiEndpoints.part_stocktake_list); return api .get(url, { params: { part: id, ordering: 'date' } }) @@ -392,8 +391,7 @@ export default function PartDetail() { type: 'link', name: 'default_location', label: t`Default Location`, - path: ApiEndpoints.stock_location_list, - dest: '/stock/location/' + model: ModelType.stocklocation } ]); } @@ -404,8 +402,7 @@ export default function PartDetail() { type: 'link', name: 'default_supplier', label: t`Default Supplier`, - path: ApiEndpoints.supplier_part_list, - dest: '/part/' + model: ModelType.supplierpart } ]); } diff --git a/src/frontend/src/tables/Details.tsx b/src/frontend/src/tables/Details.tsx index e62b8f23c8..d32dba6fbc 100644 --- a/src/frontend/src/tables/Details.tsx +++ b/src/frontend/src/tables/Details.tsx @@ -11,12 +11,15 @@ import { Tooltip } from '@mantine/core'; import { useSuspenseQuery } from '@tanstack/react-query'; -import { Suspense } from 'react'; +import { Suspense, useMemo } from 'react'; import { api } from '../App'; import { ProgressBar } from '../components/items/ProgressBar'; +import { getModelInfo } from '../components/render/ModelType'; import { ApiEndpoints } from '../enums/ApiEndpoints'; +import { ModelType } from '../enums/ModelType'; import { InvenTreeIcon } from '../functions/icons'; +import { getDetailUrl } from '../functions/urls'; import { apiUrl } from '../states/ApiState'; import { useGlobalSettingsState } from '../states/SettingsState'; @@ -53,8 +56,7 @@ type LinkDetailField = { } & (InternalLinkField | ExternalLinkField); type InternalLinkField = { - path: ApiEndpoints; - dest: string; + model: ModelType; }; type ExternalLinkField = { @@ -292,9 +294,15 @@ function TableAnchorValue(props: FieldProps) { } const { data } = useSuspenseQuery({ - queryKey: ['detail', props.field_data.path], + queryKey: ['detail', props.field_data.model, props.field_value], queryFn: async () => { - const url = apiUrl(props.field_data.path, props.field_value); + const modelDef = getModelInfo(props.field_data.model); + + if (!modelDef.api_endpoint) { + return {}; + } + + const url = apiUrl(modelDef.api_endpoint, props.field_value); return api .get(url) @@ -312,14 +320,16 @@ function TableAnchorValue(props: FieldProps) { } }); + const detailUrl = useMemo(() => { + return getDetailUrl(props.field_data.model, props.field_value); + }, [props.field_data.model, props.field_value]); + return ( }> {data.name ?? 'No name defined'}