mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
[PUI] StockTrackingTable (#7273)
* Bare bones <StockTrackingTable /> component * Implement details panel for StockTrackingTable * Remove unused userState hook * Expand RenderInstance to include link * Allow inline renderers to display links
This commit is contained in:
parent
c1def12203
commit
76b298c43e
@ -1,17 +1,21 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { getDetailUrl } from '../../functions/urls';
|
||||
import { InstanceRenderInterface, RenderInlineModel } from './Instance';
|
||||
import { StatusRenderer } from './StatusRenderer';
|
||||
|
||||
/**
|
||||
* Inline rendering of a single BuildOrder instance
|
||||
*/
|
||||
export function RenderBuildOrder({
|
||||
instance
|
||||
}: Readonly<InstanceRenderInterface>): ReactNode {
|
||||
export function RenderBuildOrder(
|
||||
props: Readonly<InstanceRenderInterface>
|
||||
): ReactNode {
|
||||
const { instance } = props;
|
||||
|
||||
return (
|
||||
<RenderInlineModel
|
||||
{...props}
|
||||
primary={instance.reference}
|
||||
secondary={instance.title}
|
||||
suffix={StatusRenderer({
|
||||
@ -19,6 +23,7 @@ export function RenderBuildOrder({
|
||||
type: ModelType.build
|
||||
})}
|
||||
image={instance.part_detail?.thumbnail || instance.part_detail?.image}
|
||||
url={props.link ? getDetailUrl(ModelType.build, instance.pk) : undefined}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { getDetailUrl } from '../../functions/urls';
|
||||
import { InstanceRenderInterface, RenderInlineModel } from './Instance';
|
||||
|
||||
/**
|
||||
@ -25,16 +27,20 @@ export function RenderAddress({
|
||||
/**
|
||||
* Inline rendering of a single Company instance
|
||||
*/
|
||||
export function RenderCompany({
|
||||
instance
|
||||
}: Readonly<InstanceRenderInterface>): ReactNode {
|
||||
// TODO: Handle URL
|
||||
export function RenderCompany(
|
||||
props: Readonly<InstanceRenderInterface>
|
||||
): ReactNode {
|
||||
const { instance } = props;
|
||||
|
||||
return (
|
||||
<RenderInlineModel
|
||||
{...props}
|
||||
image={instance.thumnbnail || instance.image}
|
||||
primary={instance.name}
|
||||
secondary={instance.description}
|
||||
url={
|
||||
props.link ? getDetailUrl(ModelType.company, instance.pk) : undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -51,20 +57,25 @@ export function RenderContact({
|
||||
/**
|
||||
* Inline rendering of a single SupplierPart instance
|
||||
*/
|
||||
export function RenderSupplierPart({
|
||||
instance
|
||||
}: Readonly<InstanceRenderInterface>): ReactNode {
|
||||
// TODO: handle URL
|
||||
|
||||
let supplier = instance.supplier_detail ?? {};
|
||||
let part = instance.part_detail ?? {};
|
||||
export function RenderSupplierPart(
|
||||
props: Readonly<InstanceRenderInterface>
|
||||
): ReactNode {
|
||||
const { instance } = props;
|
||||
const supplier = instance.supplier_detail ?? {};
|
||||
const part = instance.part_detail ?? {};
|
||||
|
||||
return (
|
||||
<RenderInlineModel
|
||||
{...props}
|
||||
primary={supplier?.name}
|
||||
secondary={instance.SKU}
|
||||
image={part?.thumbnail ?? part?.image}
|
||||
suffix={part.full_name}
|
||||
url={
|
||||
props.link
|
||||
? getDetailUrl(ModelType.supplierpart, instance.pk)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -72,18 +83,25 @@ export function RenderSupplierPart({
|
||||
/**
|
||||
* Inline rendering of a single ManufacturerPart instance
|
||||
*/
|
||||
export function RenderManufacturerPart({
|
||||
instance
|
||||
}: Readonly<InstanceRenderInterface>): ReactNode {
|
||||
let part = instance.part_detail ?? {};
|
||||
let manufacturer = instance.manufacturer_detail ?? {};
|
||||
export function RenderManufacturerPart(
|
||||
props: Readonly<InstanceRenderInterface>
|
||||
): ReactNode {
|
||||
const { instance } = props;
|
||||
const part = instance.part_detail ?? {};
|
||||
const manufacturer = instance.manufacturer_detail ?? {};
|
||||
|
||||
return (
|
||||
<RenderInlineModel
|
||||
{...props}
|
||||
primary={manufacturer.name}
|
||||
secondary={instance.MPN}
|
||||
suffix={part.full_name}
|
||||
image={manufacturer?.thumnbnail ?? manufacturer.image}
|
||||
url={
|
||||
props.link
|
||||
? getDetailUrl(ModelType.manufacturerpart, instance.pk)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { t } from '@lingui/macro';
|
||||
import { Alert, Group, Space, Text } from '@mantine/core';
|
||||
import { ReactNode } from 'react';
|
||||
import { Alert, Anchor, Group, Space, Text } from '@mantine/core';
|
||||
import { ReactNode, useCallback } from 'react';
|
||||
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { navigateToLink } from '../../functions/navigation';
|
||||
import { Thumbnail } from '../images/Thumbnail';
|
||||
import { RenderBuildLine, RenderBuildOrder } from './Build';
|
||||
import {
|
||||
@ -36,6 +37,12 @@ type EnumDictionary<T extends string | symbol | number, U> = {
|
||||
[K in T]: U;
|
||||
};
|
||||
|
||||
export interface InstanceRenderInterface {
|
||||
instance: any;
|
||||
link?: boolean;
|
||||
navigate?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup table for rendering a model instance
|
||||
*/
|
||||
@ -68,31 +75,27 @@ const RendererLookup: EnumDictionary<
|
||||
[ModelType.user]: RenderUser
|
||||
};
|
||||
|
||||
// import { ApiFormFieldType } from "../forms/fields/ApiFormField";
|
||||
export type RenderInstanceProps = {
|
||||
model: ModelType | undefined;
|
||||
} & InstanceRenderInterface;
|
||||
|
||||
/**
|
||||
* Render an instance of a database model, depending on the provided data
|
||||
*/
|
||||
export function RenderInstance({
|
||||
model,
|
||||
instance
|
||||
}: {
|
||||
model: ModelType | undefined;
|
||||
instance: any;
|
||||
}): ReactNode {
|
||||
if (model === undefined) {
|
||||
export function RenderInstance(props: RenderInstanceProps): ReactNode {
|
||||
if (props.model === undefined) {
|
||||
console.error('RenderInstance: No model provided');
|
||||
return <UnknownRenderer model={model} />;
|
||||
return <UnknownRenderer model={props.model} />;
|
||||
}
|
||||
|
||||
const RenderComponent = RendererLookup[model];
|
||||
const RenderComponent = RendererLookup[props.model];
|
||||
|
||||
if (!RenderComponent) {
|
||||
console.error(`RenderInstance: No renderer for model ${model}`);
|
||||
return <UnknownRenderer model={model} />;
|
||||
console.error(`RenderInstance: No renderer for model ${props.model}`);
|
||||
return <UnknownRenderer model={props.model} />;
|
||||
}
|
||||
|
||||
return <RenderComponent instance={instance} />;
|
||||
return <RenderComponent {...props} />;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,7 +107,8 @@ export function RenderInlineModel({
|
||||
suffix,
|
||||
image,
|
||||
labels,
|
||||
url
|
||||
url,
|
||||
navigate
|
||||
}: {
|
||||
primary: string;
|
||||
secondary?: string;
|
||||
@ -112,15 +116,30 @@ export function RenderInlineModel({
|
||||
image?: string;
|
||||
labels?: string[];
|
||||
url?: string;
|
||||
navigate?: any;
|
||||
}): ReactNode {
|
||||
// TODO: Handle labels
|
||||
// TODO: Handle URL
|
||||
|
||||
const onClick = useCallback(
|
||||
(event: any) => {
|
||||
if (url && navigate) {
|
||||
navigateToLink(url, navigate, event);
|
||||
}
|
||||
},
|
||||
[url, navigate]
|
||||
);
|
||||
|
||||
return (
|
||||
<Group gap="xs" justify="space-between" wrap="nowrap">
|
||||
<Group gap="xs" justify="left" wrap="nowrap">
|
||||
{image && Thumbnail({ src: image, size: 18 })}
|
||||
{url ? (
|
||||
<Anchor href={url} onClick={(event: any) => onClick(event)}>
|
||||
<Text size="sm">{primary}</Text>
|
||||
</Anchor>
|
||||
) : (
|
||||
<Text size="sm">{primary}</Text>
|
||||
)}
|
||||
{secondary && <Text size="xs">{secondary}</Text>}
|
||||
</Group>
|
||||
{suffix && (
|
||||
@ -144,7 +163,3 @@ export function UnknownRenderer({
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
export interface InstanceRenderInterface {
|
||||
instance: any;
|
||||
}
|
||||
|
@ -2,20 +2,22 @@ import { t } from '@lingui/macro';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { getDetailUrl } from '../../functions/urls';
|
||||
import { InstanceRenderInterface, RenderInlineModel } from './Instance';
|
||||
import { StatusRenderer } from './StatusRenderer';
|
||||
|
||||
/**
|
||||
* Inline rendering of a single PurchaseOrder instance
|
||||
*/
|
||||
export function RenderPurchaseOrder({
|
||||
instance
|
||||
}: Readonly<InstanceRenderInterface>): ReactNode {
|
||||
let supplier = instance.supplier_detail || {};
|
||||
export function RenderPurchaseOrder(
|
||||
props: Readonly<InstanceRenderInterface>
|
||||
): ReactNode {
|
||||
const { instance } = props;
|
||||
const supplier = instance?.supplier_detail || {};
|
||||
|
||||
// TODO: Handle URL
|
||||
return (
|
||||
<RenderInlineModel
|
||||
{...props}
|
||||
primary={instance.reference}
|
||||
secondary={instance.description}
|
||||
suffix={StatusRenderer({
|
||||
@ -23,6 +25,11 @@ export function RenderPurchaseOrder({
|
||||
type: ModelType.purchaseorder
|
||||
})}
|
||||
image={supplier.thumnbnail || supplier.image}
|
||||
url={
|
||||
props.link
|
||||
? getDetailUrl(ModelType.purchaseorder, instance.pk)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -30,13 +37,15 @@ export function RenderPurchaseOrder({
|
||||
/**
|
||||
* Inline rendering of a single ReturnOrder instance
|
||||
*/
|
||||
export function RenderReturnOrder({
|
||||
instance
|
||||
}: Readonly<InstanceRenderInterface>): ReactNode {
|
||||
let customer = instance.customer_detail || {};
|
||||
export function RenderReturnOrder(
|
||||
props: Readonly<InstanceRenderInterface>
|
||||
): ReactNode {
|
||||
const { instance } = props;
|
||||
const customer = instance?.customer_detail || {};
|
||||
|
||||
return (
|
||||
<RenderInlineModel
|
||||
{...props}
|
||||
primary={instance.reference}
|
||||
secondary={instance.description}
|
||||
suffix={StatusRenderer({
|
||||
@ -44,6 +53,11 @@ export function RenderReturnOrder({
|
||||
type: ModelType.returnorder
|
||||
})}
|
||||
image={customer.thumnbnail || customer.image}
|
||||
url={
|
||||
props.link
|
||||
? getDetailUrl(ModelType.returnorder, instance.pk)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -51,15 +65,15 @@ export function RenderReturnOrder({
|
||||
/**
|
||||
* Inline rendering of a single SalesOrder instance
|
||||
*/
|
||||
export function RenderSalesOrder({
|
||||
instance
|
||||
}: Readonly<InstanceRenderInterface>): ReactNode {
|
||||
let customer = instance.customer_detail || {};
|
||||
|
||||
// TODO: Handle URL
|
||||
export function RenderSalesOrder(
|
||||
props: Readonly<InstanceRenderInterface>
|
||||
): ReactNode {
|
||||
const { instance } = props;
|
||||
const customer = instance?.customer_detail || {};
|
||||
|
||||
return (
|
||||
<RenderInlineModel
|
||||
{...props}
|
||||
primary={instance.reference}
|
||||
secondary={instance.description}
|
||||
suffix={StatusRenderer({
|
||||
@ -67,6 +81,9 @@ export function RenderSalesOrder({
|
||||
type: ModelType.salesorder
|
||||
})}
|
||||
image={customer.thumnbnail || customer.image}
|
||||
url={
|
||||
props.link ? getDetailUrl(ModelType.salesorder, instance.pk) : undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,22 +1,27 @@
|
||||
import { t } from '@lingui/macro';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { getDetailUrl } from '../../functions/urls';
|
||||
import { InstanceRenderInterface, RenderInlineModel } from './Instance';
|
||||
|
||||
/**
|
||||
* Inline rendering of a single Part instance
|
||||
*/
|
||||
export function RenderPart({
|
||||
instance
|
||||
}: Readonly<InstanceRenderInterface>): ReactNode {
|
||||
export function RenderPart(
|
||||
props: Readonly<InstanceRenderInterface>
|
||||
): ReactNode {
|
||||
const { instance } = props;
|
||||
const stock = t`Stock` + `: ${instance.in_stock}`;
|
||||
|
||||
return (
|
||||
<RenderInlineModel
|
||||
{...props}
|
||||
primary={instance.name}
|
||||
secondary={instance.description}
|
||||
suffix={stock}
|
||||
image={instance.thumnbnail || instance.image}
|
||||
url={props.link ? getDetailUrl(ModelType.part, instance.pk) : undefined}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -24,17 +29,22 @@ export function RenderPart({
|
||||
/**
|
||||
* Inline rendering of a PartCategory instance
|
||||
*/
|
||||
export function RenderPartCategory({
|
||||
instance
|
||||
}: Readonly<InstanceRenderInterface>): ReactNode {
|
||||
// TODO: Handle URL
|
||||
|
||||
let lvl = '-'.repeat(instance.level || 0);
|
||||
export function RenderPartCategory(
|
||||
props: Readonly<InstanceRenderInterface>
|
||||
): ReactNode {
|
||||
const { instance } = props;
|
||||
const lvl = '-'.repeat(instance.level || 0);
|
||||
|
||||
return (
|
||||
<RenderInlineModel
|
||||
{...props}
|
||||
primary={`${lvl} ${instance.name}`}
|
||||
secondary={instance.description}
|
||||
url={
|
||||
props.link
|
||||
? getDetailUrl(ModelType.partcategory, instance.pk)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,18 +1,28 @@
|
||||
import { t } from '@lingui/macro';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { getDetailUrl } from '../../functions/urls';
|
||||
import { InstanceRenderInterface, RenderInlineModel } from './Instance';
|
||||
|
||||
/**
|
||||
* Inline rendering of a single StockLocation instance
|
||||
*/
|
||||
export function RenderStockLocation({
|
||||
instance
|
||||
}: Readonly<InstanceRenderInterface>): ReactNode {
|
||||
export function RenderStockLocation(
|
||||
props: Readonly<InstanceRenderInterface>
|
||||
): ReactNode {
|
||||
const { instance } = props;
|
||||
|
||||
return (
|
||||
<RenderInlineModel
|
||||
{...props}
|
||||
primary={instance.name}
|
||||
secondary={instance.description}
|
||||
url={
|
||||
props.link
|
||||
? getDetailUrl(ModelType.stocklocation, instance.pk)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -32,9 +42,10 @@ export function RenderStockLocationType({
|
||||
);
|
||||
}
|
||||
|
||||
export function RenderStockItem({
|
||||
instance
|
||||
}: Readonly<InstanceRenderInterface>): ReactNode {
|
||||
export function RenderStockItem(
|
||||
props: Readonly<InstanceRenderInterface>
|
||||
): ReactNode {
|
||||
const { instance } = props;
|
||||
let quantity_string = '';
|
||||
|
||||
if (instance?.serial !== null && instance?.serial !== undefined) {
|
||||
@ -45,9 +56,13 @@ export function RenderStockItem({
|
||||
|
||||
return (
|
||||
<RenderInlineModel
|
||||
{...props}
|
||||
primary={instance.part_detail?.full_name}
|
||||
suffix={quantity_string}
|
||||
image={instance.part_detail?.thumbnail || instance.part_detail?.image}
|
||||
url={
|
||||
props.link ? getDetailUrl(ModelType.stockitem, instance.pk) : undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ import { AttachmentTable } from '../../tables/general/AttachmentTable';
|
||||
import InstalledItemsTable from '../../tables/stock/InstalledItemsTable';
|
||||
import { StockItemTable } from '../../tables/stock/StockItemTable';
|
||||
import StockItemTestResultTable from '../../tables/stock/StockItemTestResultTable';
|
||||
import { StockTrackingTable } from '../../tables/stock/StockTrackingTable';
|
||||
|
||||
export default function StockDetail() {
|
||||
const { id } = useParams();
|
||||
@ -269,7 +270,12 @@ export default function StockDetail() {
|
||||
{
|
||||
name: 'tracking',
|
||||
label: t`Stock Tracking`,
|
||||
icon: <IconHistory />
|
||||
icon: <IconHistory />,
|
||||
content: stockitem.pk ? (
|
||||
<StockTrackingTable itemId={stockitem.pk} />
|
||||
) : (
|
||||
<Skeleton />
|
||||
)
|
||||
},
|
||||
{
|
||||
name: 'allocations',
|
||||
|
220
src/frontend/src/tables/stock/StockTrackingTable.tsx
Normal file
220
src/frontend/src/tables/stock/StockTrackingTable.tsx
Normal file
@ -0,0 +1,220 @@
|
||||
import { t } from '@lingui/macro';
|
||||
import { Table, Text } from '@mantine/core';
|
||||
import { ReactNode, useCallback, useMemo } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { RenderBuildOrder } from '../../components/render/Build';
|
||||
import { RenderCompany } from '../../components/render/Company';
|
||||
import {
|
||||
RenderPurchaseOrder,
|
||||
RenderReturnOrder,
|
||||
RenderSalesOrder
|
||||
} from '../../components/render/Order';
|
||||
import { RenderPart } from '../../components/render/Part';
|
||||
import { StatusRenderer } from '../../components/render/StatusRenderer';
|
||||
import {
|
||||
RenderStockItem,
|
||||
RenderStockLocation
|
||||
} from '../../components/render/Stock';
|
||||
import { RenderUser } from '../../components/render/User';
|
||||
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { useTable } from '../../hooks/UseTable';
|
||||
import { apiUrl } from '../../states/ApiState';
|
||||
import { TableColumn } from '../Column';
|
||||
import { DateColumn, DescriptionColumn } from '../ColumnRenderers';
|
||||
import { InvenTreeTable } from '../InvenTreeTable';
|
||||
|
||||
type StockTrackingEntry = {
|
||||
label: string;
|
||||
key: string;
|
||||
details: ReactNode;
|
||||
};
|
||||
|
||||
export function StockTrackingTable({ itemId }: { itemId: number }) {
|
||||
const navigate = useNavigate();
|
||||
const table = useTable('stock_tracking');
|
||||
|
||||
// Render "details" for a stock tracking record
|
||||
const renderDetails = useCallback(
|
||||
(record: any) => {
|
||||
const deltas: any = record?.deltas ?? {};
|
||||
|
||||
let entries: StockTrackingEntry[] = [
|
||||
{
|
||||
label: t`Stock Item`,
|
||||
key: 'stockitem',
|
||||
details:
|
||||
deltas.stockitem_detail &&
|
||||
RenderStockItem({ instance: deltas.stockitem_detail })
|
||||
},
|
||||
{
|
||||
label: t`Status`,
|
||||
key: 'status',
|
||||
details:
|
||||
deltas.status &&
|
||||
StatusRenderer({ status: deltas.status, type: ModelType.stockitem })
|
||||
},
|
||||
{
|
||||
label: t`Quantity`,
|
||||
key: 'quantity',
|
||||
details: deltas.quantity
|
||||
},
|
||||
{
|
||||
label: t`Added`,
|
||||
key: 'added',
|
||||
details: deltas.added
|
||||
},
|
||||
{
|
||||
label: t`Removed`,
|
||||
key: 'removed',
|
||||
details: deltas.removed
|
||||
},
|
||||
{
|
||||
label: t`Part`,
|
||||
key: 'part',
|
||||
details:
|
||||
deltas.part_detail &&
|
||||
RenderPart({
|
||||
instance: deltas.part_detail,
|
||||
link: true,
|
||||
navigate: navigate
|
||||
})
|
||||
},
|
||||
{
|
||||
label: t`Location`,
|
||||
key: 'location',
|
||||
details:
|
||||
deltas.location_detail &&
|
||||
RenderStockLocation({
|
||||
instance: deltas.location_detail,
|
||||
link: true,
|
||||
navigate: navigate
|
||||
})
|
||||
},
|
||||
{
|
||||
label: t`Build Order`,
|
||||
key: 'buildorder',
|
||||
details:
|
||||
deltas.buildorder_detail &&
|
||||
RenderBuildOrder({
|
||||
instance: deltas.buildorder_detail,
|
||||
link: true,
|
||||
navigate: navigate
|
||||
})
|
||||
},
|
||||
{
|
||||
label: t`Purchase Order`,
|
||||
key: 'purchaseorder',
|
||||
details:
|
||||
deltas.purchaseorder_detail &&
|
||||
RenderPurchaseOrder({
|
||||
instance: deltas.purchaseorder_detail,
|
||||
link: true,
|
||||
navigate: navigate
|
||||
})
|
||||
},
|
||||
{
|
||||
label: t`Sales Order`,
|
||||
key: 'salesorder',
|
||||
details:
|
||||
deltas.salesorder_detail &&
|
||||
RenderSalesOrder({
|
||||
instance: deltas.salesorder_detail,
|
||||
link: true,
|
||||
navigate: navigate
|
||||
})
|
||||
},
|
||||
{
|
||||
label: t`Return Order`,
|
||||
key: 'returnorder',
|
||||
details:
|
||||
deltas.returnorder_detail &&
|
||||
RenderReturnOrder({
|
||||
instance: deltas.returnorder_detail,
|
||||
link: true,
|
||||
navigate: navigate
|
||||
})
|
||||
},
|
||||
{
|
||||
label: t`Customer`,
|
||||
key: 'customer',
|
||||
details:
|
||||
deltas.customer_detail &&
|
||||
RenderCompany({
|
||||
instance: deltas.customer_detail,
|
||||
link: true,
|
||||
navigate: navigate
|
||||
})
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<Table striped>
|
||||
<Table.Tbody>
|
||||
{entries.map(
|
||||
(entry) =>
|
||||
entry.details && (
|
||||
<Table.Tr key={entry.key}>
|
||||
<Table.Td>
|
||||
<Text>{entry.label}</Text>
|
||||
</Table.Td>
|
||||
<Table.Td>{entry.details}</Table.Td>
|
||||
</Table.Tr>
|
||||
)
|
||||
)}
|
||||
</Table.Tbody>
|
||||
</Table>
|
||||
);
|
||||
},
|
||||
[navigate]
|
||||
);
|
||||
|
||||
const tableColumns: TableColumn[] = useMemo(() => {
|
||||
return [
|
||||
DateColumn({
|
||||
switchable: false
|
||||
}),
|
||||
DescriptionColumn({
|
||||
accessor: 'label'
|
||||
}),
|
||||
{
|
||||
accessor: 'details',
|
||||
title: t`Details`,
|
||||
switchable: false,
|
||||
render: renderDetails
|
||||
},
|
||||
{
|
||||
accessor: 'notes',
|
||||
title: t`Notes`,
|
||||
sortable: false,
|
||||
switchable: true
|
||||
},
|
||||
{
|
||||
accessor: 'user',
|
||||
title: t`User`,
|
||||
render: (record: any) => {
|
||||
if (!record.user_detail) {
|
||||
return <Text size="sm" fs="italic">{t`No user information`}</Text>;
|
||||
}
|
||||
|
||||
return RenderUser({ instance: record.user_detail });
|
||||
}
|
||||
}
|
||||
];
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<InvenTreeTable
|
||||
tableState={table}
|
||||
url={apiUrl(ApiEndpoints.stock_tracking_list)}
|
||||
columns={tableColumns}
|
||||
props={{
|
||||
params: {
|
||||
item: itemId,
|
||||
user_detail: true
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user