SupplierPart and ManufacturerPart
This commit is contained in:
parent
ed074810a4
commit
524cf0288c
|
|
@ -1,10 +1,12 @@
|
|||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import type { ReactNode } from 'react';
|
||||
import { ManufacturerPartPreviewComponent } from './models/ManufacturerPartPreview';
|
||||
import { PartPreviewComponent } from './models/PartPreview';
|
||||
import { PurchaseOrderPreviewComponent } from './models/PurchaseOrderPreview';
|
||||
import { ReturnOrderPreviewComponent } from './models/ReturnOrderPreview';
|
||||
import { SalesOrderPreviewComponent } from './models/SalesOrderPreview';
|
||||
import { StockPreviewComponent } from './models/StockPreview';
|
||||
import { SupplierPartPreviewComponent } from './models/SupplierPartPreview';
|
||||
|
||||
export interface PreviewType {
|
||||
preview: ReactNode;
|
||||
|
|
@ -37,6 +39,10 @@ export function getPreviewComponentForModel({
|
|||
return SalesOrderPreviewComponent({ instance, modelId });
|
||||
case ModelType.returnorder:
|
||||
return ReturnOrderPreviewComponent({ instance, modelId });
|
||||
case ModelType.supplierpart:
|
||||
return SupplierPartPreviewComponent({ instance, modelId });
|
||||
case ModelType.manufacturerpart:
|
||||
return ManufacturerPartPreviewComponent({ instance, modelId });
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { ManufacturerPartDetailsPanel } from '../../../pages/company/ManufacturerPartDetailsPanel';
|
||||
import type { PreviewType } from '../PreviewType';
|
||||
|
||||
export function ManufacturerPartPreviewComponent({
|
||||
instance,
|
||||
modelId
|
||||
}: Readonly<{
|
||||
instance: any;
|
||||
modelId: number;
|
||||
}>): PreviewType {
|
||||
const manufacturer =
|
||||
instance?.manufacturer_detail?.name ?? instance?.manufacturer_name;
|
||||
const mpn = instance?.MPN ?? `#${modelId}`;
|
||||
|
||||
let title = `${t`Manufacturer Part`} ${mpn}`;
|
||||
|
||||
if (manufacturer) {
|
||||
title += ` (${manufacturer})`;
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
preview: <ManufacturerPartDetailsPanel instance={instance} />
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { SupplierPartDetailsPanel } from '../../../pages/company/SupplierPartDetailsPanel';
|
||||
import type { PreviewType } from '../PreviewType';
|
||||
|
||||
export function SupplierPartPreviewComponent({
|
||||
instance,
|
||||
modelId
|
||||
}: Readonly<{
|
||||
instance: any;
|
||||
modelId: number;
|
||||
}>): PreviewType {
|
||||
const supplier = instance?.supplier_detail?.name ?? instance?.supplier_name;
|
||||
const sku = instance?.SKU ?? `#${modelId}`;
|
||||
|
||||
let title = `${t`Supplier Part`} ${sku}`;
|
||||
|
||||
if (supplier) {
|
||||
title += ` (${supplier})`;
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
preview: <SupplierPartDetailsPanel instance={instance} />
|
||||
};
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { Grid, Skeleton, Stack } from '@mantine/core';
|
||||
import { Skeleton, Stack } from '@mantine/core';
|
||||
import {
|
||||
IconBuildingWarehouse,
|
||||
IconInfoCircle,
|
||||
|
|
@ -8,20 +8,12 @@ import {
|
|||
import { useMemo } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import TagsList from '@lib/components/TagsList';
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { getDetailUrl } from '@lib/functions/Navigation';
|
||||
import type { PanelType } from '@lib/types/Panel';
|
||||
import AdminButton from '../../components/buttons/AdminButton';
|
||||
import {
|
||||
type DetailsField,
|
||||
DetailsTable
|
||||
} from '../../components/details/Details';
|
||||
import { DetailsImage } from '../../components/details/DetailsImage';
|
||||
import { ItemDetailsGrid } from '../../components/details/ItemDetails';
|
||||
import {
|
||||
DeleteItemAction,
|
||||
DuplicateItemAction,
|
||||
|
|
@ -44,6 +36,7 @@ import { useInstance } from '../../hooks/UseInstance';
|
|||
import { useUserState } from '../../states/UserState';
|
||||
import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
|
||||
import { StockItemTable } from '../../tables/stock/StockItemTable';
|
||||
import { ManufacturerPartDetailsPanel } from './ManufacturerPartDetailsPanel';
|
||||
|
||||
export default function ManufacturerPartDetail() {
|
||||
const { id } = useParams();
|
||||
|
|
@ -65,106 +58,19 @@ export default function ManufacturerPartDetail() {
|
|||
}
|
||||
});
|
||||
|
||||
const detailsPanel = useMemo(() => {
|
||||
if (instanceQuery.isFetching) {
|
||||
return <Skeleton />;
|
||||
}
|
||||
|
||||
const data = manufacturerPart ?? {};
|
||||
|
||||
const tl: DetailsField[] = [
|
||||
{
|
||||
type: 'link',
|
||||
name: 'part',
|
||||
label: t`Internal Part`,
|
||||
model: ModelType.part,
|
||||
hidden: !manufacturerPart.part
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'part_detail.IPN',
|
||||
label: t`IPN`,
|
||||
copy: true,
|
||||
icon: 'serial',
|
||||
hidden: !data.part_detail?.IPN
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'part_detail.description',
|
||||
label: t`Description`,
|
||||
copy: true,
|
||||
icon: 'info',
|
||||
hidden: !manufacturerPart.description
|
||||
}
|
||||
];
|
||||
|
||||
const tr: DetailsField[] = [
|
||||
{
|
||||
type: 'link',
|
||||
name: 'manufacturer',
|
||||
label: t`Manufacturer`,
|
||||
icon: 'manufacturers',
|
||||
model: ModelType.company,
|
||||
hidden: !manufacturerPart.manufacturer
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'MPN',
|
||||
label: t`Manufacturer Part Number`,
|
||||
copy: true,
|
||||
hidden: !manufacturerPart.MPN,
|
||||
icon: 'reference'
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'description',
|
||||
label: t`Description`,
|
||||
copy: true,
|
||||
hidden: !manufacturerPart.description,
|
||||
icon: 'info'
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
external: true,
|
||||
name: 'link',
|
||||
label: t`External Link`,
|
||||
copy: true,
|
||||
hidden: !manufacturerPart.link
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ItemDetailsGrid
|
||||
tables={[{ title: t`Manufacturer Details`, fields: tr, item: data }]}
|
||||
>
|
||||
<Stack gap='xs'>
|
||||
<Grid grow>
|
||||
<DetailsImage
|
||||
appRole={UserRoles.part}
|
||||
src={manufacturerPart?.part_detail?.image}
|
||||
apiPath={apiUrl(
|
||||
ApiEndpoints.part_list,
|
||||
manufacturerPart?.part_detail?.pk
|
||||
)}
|
||||
pk={manufacturerPart?.part_detail?.pk}
|
||||
/>
|
||||
<Grid.Col span={{ base: 12, sm: 8 }}>
|
||||
<DetailsTable title={t`Part Details`} fields={tl} item={data} />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<TagsList tags={manufacturerPart.tags} />
|
||||
</Stack>
|
||||
</ItemDetailsGrid>
|
||||
);
|
||||
}, [manufacturerPart, instanceQuery]);
|
||||
|
||||
const panels: PanelType[] = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
name: 'details',
|
||||
label: t`Manufacturer Part Details`,
|
||||
icon: <IconInfoCircle />,
|
||||
content: detailsPanel
|
||||
content: (
|
||||
<ManufacturerPartDetailsPanel
|
||||
instance={manufacturerPart}
|
||||
allowImageEdit
|
||||
refreshInstance={refreshInstance}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
name: 'stock',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { Grid, Skeleton, Stack } from '@mantine/core';
|
||||
|
||||
import TagsList from '@lib/components/TagsList';
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
|
||||
import {
|
||||
type DetailsField,
|
||||
DetailsTable
|
||||
} from '../../components/details/Details';
|
||||
import { DetailsImage } from '../../components/details/DetailsImage';
|
||||
import { ItemDetailsGrid } from '../../components/details/ItemDetails';
|
||||
import { useParameterDetailsGrid } from '../../components/details/ParameterDetailsGrid';
|
||||
|
||||
export function ManufacturerPartDetailsPanel({
|
||||
instance,
|
||||
allowImageEdit = false,
|
||||
refreshInstance
|
||||
}: Readonly<{
|
||||
instance: any;
|
||||
allowImageEdit?: boolean;
|
||||
refreshInstance?: () => void;
|
||||
}>) {
|
||||
const tl: DetailsField[] = [
|
||||
{
|
||||
type: 'link',
|
||||
name: 'part',
|
||||
label: t`Internal Part`,
|
||||
model: ModelType.part,
|
||||
hidden: !instance?.part
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'part_detail.IPN',
|
||||
label: t`IPN`,
|
||||
copy: true,
|
||||
icon: 'serial',
|
||||
hidden: !instance?.part_detail?.IPN
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'part_detail.description',
|
||||
label: t`Description`,
|
||||
copy: true,
|
||||
icon: 'info',
|
||||
hidden: !instance?.description
|
||||
}
|
||||
];
|
||||
|
||||
const tr: DetailsField[] = [
|
||||
{
|
||||
type: 'link',
|
||||
name: 'manufacturer',
|
||||
label: t`Manufacturer`,
|
||||
icon: 'manufacturers',
|
||||
model: ModelType.company,
|
||||
hidden: !instance?.manufacturer
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'MPN',
|
||||
label: t`Manufacturer Part Number`,
|
||||
copy: true,
|
||||
hidden: !instance?.MPN,
|
||||
icon: 'reference'
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'description',
|
||||
label: t`Description`,
|
||||
copy: true,
|
||||
hidden: !instance?.description,
|
||||
icon: 'info'
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
external: true,
|
||||
name: 'link',
|
||||
label: t`External Link`,
|
||||
copy: true,
|
||||
hidden: !instance?.link
|
||||
}
|
||||
];
|
||||
|
||||
const parametersTable = useParameterDetailsGrid({
|
||||
model_type: ModelType.manufacturerpart,
|
||||
model_id: instance?.pk
|
||||
});
|
||||
|
||||
if (!instance?.pk) return <Skeleton />;
|
||||
|
||||
return (
|
||||
<ItemDetailsGrid
|
||||
tables={[
|
||||
{ title: t`Manufacturer Details`, fields: tr, item: instance },
|
||||
parametersTable
|
||||
]}
|
||||
>
|
||||
<Stack gap='xs'>
|
||||
<Grid grow>
|
||||
<DetailsImage
|
||||
appRole={allowImageEdit ? UserRoles.part : undefined}
|
||||
src={instance?.part_detail?.image}
|
||||
apiPath={apiUrl(ApiEndpoints.part_list, instance?.part_detail?.pk)}
|
||||
pk={instance?.part_detail?.pk}
|
||||
refresh={refreshInstance}
|
||||
/>
|
||||
<Grid.Col span={{ base: 12, sm: 8 }}>
|
||||
<DetailsTable title={t`Part Details`} fields={tl} item={instance} />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<TagsList tags={instance?.tags} />
|
||||
</Stack>
|
||||
</ItemDetailsGrid>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { Grid, Skeleton, Stack } from '@mantine/core';
|
||||
import { Skeleton, Stack } from '@mantine/core';
|
||||
import {
|
||||
IconCurrencyDollar,
|
||||
IconInfoCircle,
|
||||
|
|
@ -9,22 +9,14 @@ import {
|
|||
import { type ReactNode, useMemo } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import TagsList from '@lib/components/TagsList';
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { formatDecimal } from '@lib/functions/Formatting';
|
||||
import { getDetailUrl } from '@lib/functions/Navigation';
|
||||
import type { PanelType } from '@lib/types/Panel';
|
||||
import AdminButton from '../../components/buttons/AdminButton';
|
||||
import {
|
||||
type DetailsField,
|
||||
DetailsTable
|
||||
} from '../../components/details/Details';
|
||||
import DetailsBadge from '../../components/details/DetailsBadge';
|
||||
import { DetailsImage } from '../../components/details/DetailsImage';
|
||||
import { ItemDetailsGrid } from '../../components/details/ItemDetails';
|
||||
import {
|
||||
BarcodeActionDropdown,
|
||||
DeleteItemAction,
|
||||
|
|
@ -49,6 +41,7 @@ import { useUserState } from '../../states/UserState';
|
|||
import { PurchaseOrderTable } from '../../tables/purchasing/PurchaseOrderTable';
|
||||
import SupplierPriceBreakTable from '../../tables/purchasing/SupplierPriceBreakTable';
|
||||
import { StockItemTable } from '../../tables/stock/StockItemTable';
|
||||
import { SupplierPartDetailsPanel } from './SupplierPartDetailsPanel';
|
||||
|
||||
export default function SupplierPartDetail() {
|
||||
const { id } = useParams();
|
||||
|
|
@ -73,190 +66,19 @@ export default function SupplierPartDetail() {
|
|||
}
|
||||
});
|
||||
|
||||
const detailsPanel = useMemo(() => {
|
||||
if (instanceQuery.isFetching) {
|
||||
return <Skeleton />;
|
||||
}
|
||||
|
||||
const data = supplierPart ?? {};
|
||||
|
||||
// Access nested data
|
||||
data.manufacturer =
|
||||
supplierPart.manufacturer || data.manufacturer_detail?.pk;
|
||||
data.MPN = supplierPart.MPN || data.manufacturer_part_detail?.MPN;
|
||||
data.manufacturer_part =
|
||||
supplierPart.manufacturer_part || data.manufacturer_part_detail?.pk;
|
||||
|
||||
const tl: DetailsField[] = [
|
||||
{
|
||||
type: 'link',
|
||||
name: 'part',
|
||||
label: t`Internal Part`,
|
||||
model: ModelType.part,
|
||||
hidden: !supplierPart.part
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'part_detail.IPN',
|
||||
label: t`IPN`,
|
||||
copy: true,
|
||||
hidden: !data.part_detail?.IPN,
|
||||
icon: 'serial'
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'part_detail.description',
|
||||
label: t`Part Description`,
|
||||
copy: true,
|
||||
icon: 'info',
|
||||
hidden: !data.part_detail?.description
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
external: true,
|
||||
name: 'link',
|
||||
label: t`External Link`,
|
||||
copy: true,
|
||||
hidden: !supplierPart.link
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'note',
|
||||
label: t`Note`,
|
||||
copy: true,
|
||||
hidden: !supplierPart.note
|
||||
}
|
||||
];
|
||||
|
||||
const bl: DetailsField[] = [
|
||||
{
|
||||
type: 'link',
|
||||
name: 'supplier',
|
||||
label: t`Supplier`,
|
||||
model: ModelType.company,
|
||||
icon: 'suppliers',
|
||||
hidden: !supplierPart.supplier
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'SKU',
|
||||
label: t`SKU`,
|
||||
copy: true,
|
||||
icon: 'reference'
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'description',
|
||||
label: t`Description`,
|
||||
copy: true,
|
||||
hidden: !data.description
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'manufacturer',
|
||||
label: t`Manufacturer`,
|
||||
model: ModelType.company,
|
||||
icon: 'manufacturers',
|
||||
hidden: !data.manufacturer
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'manufacturer_part',
|
||||
model_field: 'MPN',
|
||||
label: t`Manufacturer Part`,
|
||||
model: ModelType.manufacturerpart,
|
||||
icon: 'reference',
|
||||
hidden: !data.manufacturer_part
|
||||
}
|
||||
];
|
||||
|
||||
const br: DetailsField[] = [
|
||||
{
|
||||
type: 'string',
|
||||
name: 'packaging',
|
||||
label: t`Packaging`,
|
||||
copy: true,
|
||||
hidden: !data.packaging
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'pack_quantity',
|
||||
label: t`Pack Quantity`,
|
||||
copy: true,
|
||||
hidden: !data.pack_quantity,
|
||||
icon: 'packages'
|
||||
}
|
||||
];
|
||||
|
||||
const tr: DetailsField[] = [
|
||||
{
|
||||
type: 'number',
|
||||
name: 'in_stock',
|
||||
label: t`In Stock`,
|
||||
copy: true,
|
||||
icon: 'stock'
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'on_order',
|
||||
label: t`On Order`,
|
||||
copy: true,
|
||||
icon: 'purchase_orders'
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'available',
|
||||
label: t`Supplier Availability`,
|
||||
hidden: !data.availability_updated,
|
||||
copy: true,
|
||||
icon: 'packages'
|
||||
},
|
||||
{
|
||||
type: 'date',
|
||||
name: 'availability_updated',
|
||||
label: t`Availability Updated`,
|
||||
copy: true,
|
||||
hidden: !data.availability_updated,
|
||||
icon: 'calendar'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ItemDetailsGrid
|
||||
tables={[
|
||||
{ title: t`Supplier`, fields: bl, item: data },
|
||||
{ title: t`Packaging`, fields: br, item: data },
|
||||
{ title: t`Availability`, fields: tr, item: data }
|
||||
]}
|
||||
>
|
||||
<Stack gap='xs'>
|
||||
<Grid grow>
|
||||
<DetailsImage
|
||||
appRole={UserRoles.part}
|
||||
src={supplierPart?.part_detail?.image}
|
||||
apiPath={apiUrl(
|
||||
ApiEndpoints.part_list,
|
||||
supplierPart?.part_detail?.pk
|
||||
)}
|
||||
pk={supplierPart?.part_detail?.pk}
|
||||
/>
|
||||
<Grid.Col span={8}>
|
||||
<DetailsTable title={t`Part Details`} fields={tl} item={data} />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<TagsList tags={supplierPart.tags} />
|
||||
</Stack>
|
||||
</ItemDetailsGrid>
|
||||
);
|
||||
}, [supplierPart, instanceQuery.isFetching]);
|
||||
|
||||
const panels: PanelType[] = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
name: 'details',
|
||||
label: t`Supplier Part Details`,
|
||||
icon: <IconInfoCircle />,
|
||||
content: detailsPanel
|
||||
content: (
|
||||
<SupplierPartDetailsPanel
|
||||
instance={supplierPart}
|
||||
allowImageEdit
|
||||
refreshInstance={refreshInstance}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
name: 'stock',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,206 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { Grid, Skeleton, Stack } from '@mantine/core';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import TagsList from '@lib/components/TagsList';
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
|
||||
import {
|
||||
type DetailsField,
|
||||
DetailsTable
|
||||
} from '../../components/details/Details';
|
||||
import { DetailsImage } from '../../components/details/DetailsImage';
|
||||
import { ItemDetailsGrid } from '../../components/details/ItemDetails';
|
||||
import { useParameterDetailsGrid } from '../../components/details/ParameterDetailsGrid';
|
||||
|
||||
export function SupplierPartDetailsPanel({
|
||||
instance,
|
||||
allowImageEdit = false,
|
||||
refreshInstance
|
||||
}: Readonly<{
|
||||
instance: any;
|
||||
allowImageEdit?: boolean;
|
||||
refreshInstance?: () => void;
|
||||
}>) {
|
||||
const data = useMemo(() => {
|
||||
if (!instance) return {};
|
||||
return {
|
||||
...instance,
|
||||
manufacturer: instance.manufacturer || instance.manufacturer_detail?.pk,
|
||||
MPN: instance.MPN || instance.manufacturer_part_detail?.MPN,
|
||||
manufacturer_part:
|
||||
instance.manufacturer_part || instance.manufacturer_part_detail?.pk
|
||||
};
|
||||
}, [instance]);
|
||||
|
||||
const tl: DetailsField[] = [
|
||||
{
|
||||
type: 'link',
|
||||
name: 'part',
|
||||
label: t`Internal Part`,
|
||||
model: ModelType.part,
|
||||
hidden: !instance?.part
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'part_detail.IPN',
|
||||
label: t`IPN`,
|
||||
copy: true,
|
||||
hidden: !data.part_detail?.IPN,
|
||||
icon: 'serial'
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'part_detail.description',
|
||||
label: t`Part Description`,
|
||||
copy: true,
|
||||
icon: 'info',
|
||||
hidden: !data.part_detail?.description
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
external: true,
|
||||
name: 'link',
|
||||
label: t`External Link`,
|
||||
copy: true,
|
||||
hidden: !instance?.link
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'note',
|
||||
label: t`Note`,
|
||||
copy: true,
|
||||
hidden: !instance?.note
|
||||
}
|
||||
];
|
||||
|
||||
const bl: DetailsField[] = [
|
||||
{
|
||||
type: 'link',
|
||||
name: 'supplier',
|
||||
label: t`Supplier`,
|
||||
model: ModelType.company,
|
||||
icon: 'suppliers',
|
||||
hidden: !instance?.supplier
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'SKU',
|
||||
label: t`SKU`,
|
||||
copy: true,
|
||||
icon: 'reference'
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'description',
|
||||
label: t`Description`,
|
||||
copy: true,
|
||||
hidden: !data.description
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'manufacturer',
|
||||
label: t`Manufacturer`,
|
||||
model: ModelType.company,
|
||||
icon: 'manufacturers',
|
||||
hidden: !data.manufacturer
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'manufacturer_part',
|
||||
model_field: 'MPN',
|
||||
label: t`Manufacturer Part`,
|
||||
model: ModelType.manufacturerpart,
|
||||
icon: 'reference',
|
||||
hidden: !data.manufacturer_part
|
||||
}
|
||||
];
|
||||
|
||||
const br: DetailsField[] = [
|
||||
{
|
||||
type: 'string',
|
||||
name: 'packaging',
|
||||
label: t`Packaging`,
|
||||
copy: true,
|
||||
hidden: !data.packaging
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'pack_quantity',
|
||||
label: t`Pack Quantity`,
|
||||
copy: true,
|
||||
hidden: !data.pack_quantity,
|
||||
icon: 'packages'
|
||||
}
|
||||
];
|
||||
|
||||
const tr: DetailsField[] = [
|
||||
{
|
||||
type: 'number',
|
||||
name: 'in_stock',
|
||||
label: t`In Stock`,
|
||||
copy: true,
|
||||
icon: 'stock'
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'on_order',
|
||||
label: t`On Order`,
|
||||
copy: true,
|
||||
icon: 'purchase_orders'
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'available',
|
||||
label: t`Supplier Availability`,
|
||||
hidden: !data.availability_updated,
|
||||
copy: true,
|
||||
icon: 'packages'
|
||||
},
|
||||
{
|
||||
type: 'date',
|
||||
name: 'availability_updated',
|
||||
label: t`Availability Updated`,
|
||||
copy: true,
|
||||
hidden: !data.availability_updated,
|
||||
icon: 'calendar'
|
||||
}
|
||||
];
|
||||
|
||||
const parametersTable = useParameterDetailsGrid({
|
||||
model_type: ModelType.supplierpart,
|
||||
model_id: instance?.pk
|
||||
});
|
||||
|
||||
if (!instance?.pk) return <Skeleton />;
|
||||
|
||||
return (
|
||||
<ItemDetailsGrid
|
||||
tables={[
|
||||
{ title: t`Supplier`, fields: bl, item: data },
|
||||
{ title: t`Packaging`, fields: br, item: data },
|
||||
{ title: t`Availability`, fields: tr, item: data },
|
||||
parametersTable
|
||||
]}
|
||||
>
|
||||
<Stack gap='xs'>
|
||||
<Grid grow>
|
||||
<DetailsImage
|
||||
appRole={allowImageEdit ? UserRoles.part : undefined}
|
||||
src={instance?.part_detail?.image}
|
||||
apiPath={apiUrl(ApiEndpoints.part_list, instance?.part_detail?.pk)}
|
||||
pk={instance?.part_detail?.pk}
|
||||
refresh={refreshInstance}
|
||||
/>
|
||||
<Grid.Col span={8}>
|
||||
<DetailsTable title={t`Part Details`} fields={tl} item={data} />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<TagsList tags={instance?.tags} />
|
||||
</Stack>
|
||||
</ItemDetailsGrid>
|
||||
);
|
||||
}
|
||||
|
|
@ -741,6 +741,8 @@ export function InvenTreeTableInternal<T extends Record<string, any>>({
|
|||
const accessor = tableProps.modelField ?? 'pk';
|
||||
const pk = resolveItem(record, accessor);
|
||||
|
||||
console.log('row click:', tableProps.modelType, accessor, '->', pk);
|
||||
|
||||
if (pk) {
|
||||
cancelEvent(event);
|
||||
// If a model type is provided, navigate to the detail view for that model
|
||||
|
|
|
|||
Loading…
Reference in New Issue