mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	[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
This commit is contained in:
		| @@ -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]; | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|         } | ||||
|       ]); | ||||
|     } | ||||
|   | ||||
| @@ -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 ( | ||||
|     <Suspense fallback={<Skeleton width={200} height={20} radius="xl" />}> | ||||
|       <Anchor | ||||
|         href={ | ||||
|           '/platform' + data.url ?? props.field_data.dest + props.field_value | ||||
|         } | ||||
|         target={data.external ? '_blank' : undefined} | ||||
|         rel={data.external ? 'noreferrer noopener' : undefined} | ||||
|         href={`/platform${detailUrl}`} | ||||
|         target={data?.external ? '_blank' : undefined} | ||||
|         rel={data?.external ? 'noreferrer noopener' : undefined} | ||||
|       > | ||||
|         <Text>{data.name ?? 'No name defined'}</Text> | ||||
|       </Anchor> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user