mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +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:
parent
7483fd203d
commit
77fd6b6bb3
@ -3,7 +3,7 @@ import { t } from '@lingui/macro';
|
|||||||
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||||
import { ModelType } from '../../enums/ModelType';
|
import { ModelType } from '../../enums/ModelType';
|
||||||
|
|
||||||
interface ModelInformationInterface {
|
export interface ModelInformationInterface {
|
||||||
label: string;
|
label: string;
|
||||||
label_multiple: string;
|
label_multiple: string;
|
||||||
url_overview?: string;
|
url_overview?: string;
|
||||||
@ -12,11 +12,11 @@ interface ModelInformationInterface {
|
|||||||
cui_detail?: string;
|
cui_detail?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModelDictory = {
|
export type ModelDict = {
|
||||||
[key in keyof typeof ModelType]: ModelInformationInterface;
|
[key in keyof typeof ModelType]: ModelInformationInterface;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ModelInformationDict: ModelDictory = {
|
export const ModelInformationDict: ModelDict = {
|
||||||
part: {
|
part: {
|
||||||
label: t`Part`,
|
label: t`Part`,
|
||||||
label_multiple: t`Parts`,
|
label_multiple: t`Parts`,
|
||||||
@ -165,3 +165,12 @@ export const ModelInformationDict: ModelDictory = {
|
|||||||
api_endpoint: ApiEndpoints.user_list
|
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 { NotesEditor } from '../../components/widgets/MarkdownEditor';
|
||||||
import { formatPriceRange } from '../../defaults/formatters';
|
import { formatPriceRange } from '../../defaults/formatters';
|
||||||
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||||
|
import { ModelType } from '../../enums/ModelType';
|
||||||
import { UserRoles } from '../../enums/Roles';
|
import { UserRoles } from '../../enums/Roles';
|
||||||
import { partFields } from '../../forms/PartForms';
|
import { partFields } from '../../forms/PartForms';
|
||||||
import { useEditApiFormModal } from '../../hooks/UseForm';
|
import { useEditApiFormModal } from '../../hooks/UseForm';
|
||||||
@ -122,8 +123,7 @@ export default function PartDetail() {
|
|||||||
type: 'link',
|
type: 'link',
|
||||||
name: 'variant_of',
|
name: 'variant_of',
|
||||||
label: t`Variant of`,
|
label: t`Variant of`,
|
||||||
path: ApiEndpoints.part_list,
|
model: ModelType.part
|
||||||
dest: '/part/'
|
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -226,8 +226,7 @@ export default function PartDetail() {
|
|||||||
type: 'link',
|
type: 'link',
|
||||||
name: 'category',
|
name: 'category',
|
||||||
label: t`Category`,
|
label: t`Category`,
|
||||||
path: ApiEndpoints.category_list,
|
model: ModelType.partcategory
|
||||||
dest: '/part/category/'
|
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -336,7 +335,7 @@ export default function PartDetail() {
|
|||||||
const { data } = useSuspenseQuery({
|
const { data } = useSuspenseQuery({
|
||||||
queryKey: ['stocktake', id],
|
queryKey: ['stocktake', id],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const url = ApiEndpoints.part_stocktake_list;
|
const url = apiUrl(ApiEndpoints.part_stocktake_list);
|
||||||
|
|
||||||
return api
|
return api
|
||||||
.get(url, { params: { part: id, ordering: 'date' } })
|
.get(url, { params: { part: id, ordering: 'date' } })
|
||||||
@ -364,7 +363,7 @@ export default function PartDetail() {
|
|||||||
const { data } = useSuspenseQuery({
|
const { data } = useSuspenseQuery({
|
||||||
queryKey: ['stocktake', id],
|
queryKey: ['stocktake', id],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const url = ApiEndpoints.part_stocktake_list;
|
const url = apiUrl(ApiEndpoints.part_stocktake_list);
|
||||||
|
|
||||||
return api
|
return api
|
||||||
.get(url, { params: { part: id, ordering: 'date' } })
|
.get(url, { params: { part: id, ordering: 'date' } })
|
||||||
@ -392,8 +391,7 @@ export default function PartDetail() {
|
|||||||
type: 'link',
|
type: 'link',
|
||||||
name: 'default_location',
|
name: 'default_location',
|
||||||
label: t`Default Location`,
|
label: t`Default Location`,
|
||||||
path: ApiEndpoints.stock_location_list,
|
model: ModelType.stocklocation
|
||||||
dest: '/stock/location/'
|
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -404,8 +402,7 @@ export default function PartDetail() {
|
|||||||
type: 'link',
|
type: 'link',
|
||||||
name: 'default_supplier',
|
name: 'default_supplier',
|
||||||
label: t`Default Supplier`,
|
label: t`Default Supplier`,
|
||||||
path: ApiEndpoints.supplier_part_list,
|
model: ModelType.supplierpart
|
||||||
dest: '/part/'
|
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,15 @@ import {
|
|||||||
Tooltip
|
Tooltip
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useSuspenseQuery } from '@tanstack/react-query';
|
import { useSuspenseQuery } from '@tanstack/react-query';
|
||||||
import { Suspense } from 'react';
|
import { Suspense, useMemo } from 'react';
|
||||||
|
|
||||||
import { api } from '../App';
|
import { api } from '../App';
|
||||||
import { ProgressBar } from '../components/items/ProgressBar';
|
import { ProgressBar } from '../components/items/ProgressBar';
|
||||||
|
import { getModelInfo } from '../components/render/ModelType';
|
||||||
import { ApiEndpoints } from '../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../enums/ApiEndpoints';
|
||||||
|
import { ModelType } from '../enums/ModelType';
|
||||||
import { InvenTreeIcon } from '../functions/icons';
|
import { InvenTreeIcon } from '../functions/icons';
|
||||||
|
import { getDetailUrl } from '../functions/urls';
|
||||||
import { apiUrl } from '../states/ApiState';
|
import { apiUrl } from '../states/ApiState';
|
||||||
import { useGlobalSettingsState } from '../states/SettingsState';
|
import { useGlobalSettingsState } from '../states/SettingsState';
|
||||||
|
|
||||||
@ -53,8 +56,7 @@ type LinkDetailField = {
|
|||||||
} & (InternalLinkField | ExternalLinkField);
|
} & (InternalLinkField | ExternalLinkField);
|
||||||
|
|
||||||
type InternalLinkField = {
|
type InternalLinkField = {
|
||||||
path: ApiEndpoints;
|
model: ModelType;
|
||||||
dest: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type ExternalLinkField = {
|
type ExternalLinkField = {
|
||||||
@ -292,9 +294,15 @@ function TableAnchorValue(props: FieldProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { data } = useSuspenseQuery({
|
const { data } = useSuspenseQuery({
|
||||||
queryKey: ['detail', props.field_data.path],
|
queryKey: ['detail', props.field_data.model, props.field_value],
|
||||||
queryFn: async () => {
|
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
|
return api
|
||||||
.get(url)
|
.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 (
|
return (
|
||||||
<Suspense fallback={<Skeleton width={200} height={20} radius="xl" />}>
|
<Suspense fallback={<Skeleton width={200} height={20} radius="xl" />}>
|
||||||
<Anchor
|
<Anchor
|
||||||
href={
|
href={`/platform${detailUrl}`}
|
||||||
'/platform' + data.url ?? props.field_data.dest + props.field_value
|
target={data?.external ? '_blank' : undefined}
|
||||||
}
|
rel={data?.external ? 'noreferrer noopener' : undefined}
|
||||||
target={data.external ? '_blank' : undefined}
|
|
||||||
rel={data.external ? 'noreferrer noopener' : undefined}
|
|
||||||
>
|
>
|
||||||
<Text>{data.name ?? 'No name defined'}</Text>
|
<Text>{data.name ?? 'No name defined'}</Text>
|
||||||
</Anchor>
|
</Anchor>
|
||||||
|
Loading…
Reference in New Issue
Block a user