Skip to content

Commit

Permalink
[PUI] StockTrackingTable (#7273)
Browse files Browse the repository at this point in the history
* Bare bones <StockTrackingTable /> component

* Implement details panel for StockTrackingTable

* Remove unused userState hook

* Expand RenderInstance to include link

* Allow inline renderers to display links
  • Loading branch information
SchrodingersGat authored May 21, 2024
1 parent c1def12 commit 76b298c
Show file tree
Hide file tree
Showing 8 changed files with 379 additions and 73 deletions.
11 changes: 8 additions & 3 deletions src/frontend/src/components/render/Build.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
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({
status: instance.status,
type: ModelType.build
})}
image={instance.part_detail?.thumbnail || instance.part_detail?.image}
url={props.link ? getDetailUrl(ModelType.build, instance.pk) : undefined}
/>
);
}
Expand Down
50 changes: 34 additions & 16 deletions src/frontend/src/components/render/Company.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ReactNode } from 'react';

import { ModelType } from '../../enums/ModelType';
import { getDetailUrl } from '../../functions/urls';
import { InstanceRenderInterface, RenderInlineModel } from './Instance';

/**
Expand All @@ -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
}
/>
);
}
Expand All @@ -51,39 +57,51 @@ 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
}
/>
);
}

/**
* 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
}
/>
);
}
61 changes: 38 additions & 23 deletions src/frontend/src/components/render/Instance.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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} />;
}

/**
Expand All @@ -104,23 +107,39 @@ export function RenderInlineModel({
suffix,
image,
labels,
url
url,
navigate
}: {
primary: string;
secondary?: string;
suffix?: ReactNode;
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 })}
<Text size="sm">{primary}</Text>
{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 && (
Expand All @@ -144,7 +163,3 @@ export function UnknownRenderer({
</Alert>
);
}

export interface InstanceRenderInterface {
instance: any;
}
47 changes: 32 additions & 15 deletions src/frontend/src/components/render/Order.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,88 @@ 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({
status: instance.status,
type: ModelType.purchaseorder
})}
image={supplier.thumnbnail || supplier.image}
url={
props.link
? getDetailUrl(ModelType.purchaseorder, instance.pk)
: undefined
}
/>
);
}

/**
* 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({
status: instance.status,
type: ModelType.returnorder
})}
image={customer.thumnbnail || customer.image}
url={
props.link
? getDetailUrl(ModelType.returnorder, instance.pk)
: undefined
}
/>
);
}

/**
* 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({
status: instance.status,
type: ModelType.salesorder
})}
image={customer.thumnbnail || customer.image}
url={
props.link ? getDetailUrl(ModelType.salesorder, instance.pk) : undefined
}
/>
);
}
Expand Down
Loading

0 comments on commit 76b298c

Please sign in to comment.