2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-08-01 17:41:33 +00:00

Table formatting (#10104)

* Format <BuildLineTable />

* More formatting

* Add helper function for running playwright tests

* Fix playwright test

* Further formatting updates

* Adjust order tables
This commit is contained in:
Oliver
2025-07-31 16:39:19 +10:00
committed by GitHub
parent b8ea75b2b4
commit 4794c6d860
13 changed files with 76 additions and 39 deletions

View File

@@ -184,14 +184,14 @@ export default function SupplierPartDetail() {
const tr: DetailsField[] = [
{
type: 'string',
type: 'number',
name: 'in_stock',
label: t`In Stock`,
copy: true,
icon: 'stock'
},
{
type: 'string',
type: 'number',
name: 'on_order',
label: t`On Order`,
copy: true,

View File

@@ -288,13 +288,13 @@ export function BomTable({
available_stock <= 0 ? (
<Text c='red' style={{ fontStyle: 'italic' }}>{t`No stock`}</Text>
) : (
available_stock
`${formatDecimal(available_stock)}`
);
if (record.external_stock > 0) {
extra.push(
<Text key='external'>
{t`External stock`}: {record.external_stock}
{t`External stock`}: {formatDecimal(record.external_stock)}
</Text>
);
}
@@ -303,7 +303,7 @@ export function BomTable({
extra.push(
<Text key='substitute'>
{t`Includes substitute stock`}:{' '}
{record.available_substitute_stock}
{formatDecimal(record.available_substitute_stock)}
</Text>
);
}
@@ -311,7 +311,8 @@ export function BomTable({
if (record.allow_variants && record.available_variant_stock > 0) {
extra.push(
<Text key='variant'>
{t`Includes variant stock`}: {record.available_variant_stock}
{t`Includes variant stock`}:{' '}
{formatDecimal(record.available_variant_stock)}
</Text>
);
}
@@ -363,7 +364,7 @@ export function BomTable({
fs={record.consumable && 'italic'}
c={can_build <= 0 && !record.consumable ? 'red' : undefined}
>
{can_build}
{formatDecimal(can_build)}
</Text>
);

View File

@@ -10,6 +10,7 @@ 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 type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import type { StockOperationProps } from '../../forms/StockForms';
@@ -133,13 +134,15 @@ export default function BuildAllocatedStockTable({
{
accessor: 'available',
title: t`Available Quantity`,
render: (record: any) => record?.stock_item_detail?.quantity
render: (record: any) =>
formatDecimal(record?.stock_item_detail?.quantity)
},
{
accessor: 'quantity',
title: t`Allocated Quantity`,
sortable: true,
switchable: false
switchable: false,
render: (record: any) => formatDecimal(record?.quantity)
},
LocationColumn({
accessor: 'location_detail',

View File

@@ -24,6 +24,7 @@ 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 type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
@@ -248,7 +249,7 @@ export default function BuildLineTable({
if (record.in_production > 0) {
extra.push(
<Text key='production' size='sm'>
{t`In production`}: {record.in_production}
{t`In production`}: {formatDecimal(record.in_production)}
</Text>
);
}
@@ -257,7 +258,7 @@ export default function BuildLineTable({
if (record.on_order > 0) {
extra.push(
<Text key='on-order' size='sm'>
{t`On order`}: {record.on_order}
{t`On order`}: {formatDecimal(record.on_order)}
</Text>
);
}
@@ -266,7 +267,7 @@ export default function BuildLineTable({
if (record.external_stock > 0) {
extra.push(
<Text key='external' size='sm'>
{t`External stock`}: {record.external_stock}
{t`External stock`}: {formatDecimal(record.external_stock)}
</Text>
);
}
@@ -287,7 +288,7 @@ export default function BuildLineTable({
iconColor={sufficient ? 'blue' : 'orange'}
value={
available > 0 ? (
available
`${formatDecimal(available)}`
) : (
<Text
c='red'
@@ -398,7 +399,8 @@ export default function BuildLineTable({
if (record?.bom_item_detail?.setup_quantity) {
extra.push(
<Text key='setup-quantity' size='sm'>
{t`Setup Quantity`}: {record.bom_item_detail.setup_quantity}
{t`Setup Quantity`}:{' '}
{formatDecimal(record.bom_item_detail.setup_quantity)}
</Text>
);
}
@@ -427,7 +429,7 @@ export default function BuildLineTable({
extra={extra}
value={
<Group justify='space-between' wrap='nowrap'>
<Text>{record.requiredQuantity}</Text>
<Text>{formatDecimal(record.requiredQuantity)}</Text>
{record?.part_detail?.units && (
<Text size='xs'>[{record.part_detail.units}]</Text>
)}

View File

@@ -12,7 +12,7 @@ import type { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import type { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import type { TableColumn } from '@lib/types/Tables';
import { formatCurrency } from '../../defaults/formatters';
import { formatCurrency, formatDecimal } from '../../defaults/formatters';
import { extraLineItemFields } from '../../forms/CommonForms';
import {
useCreateApiFormModal,
@@ -49,7 +49,8 @@ export default function ExtraLineItemTable({
DescriptionColumn({}),
{
accessor: 'quantity',
switchable: false
switchable: false,
render: (record: any) => formatDecimal(record.quantity)
},
{
accessor: 'price',

View File

@@ -14,7 +14,7 @@ import type { TableColumn } from '@lib/types/Tables';
import type { InvenTreeTableProps } from '@lib/types/Tables';
import { ActionDropdown } from '../../components/items/ActionDropdown';
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
import { formatPriceRange } from '../../defaults/formatters';
import { formatDecimal, formatPriceRange } from '../../defaults/formatters';
import { usePartFields } from '../../forms/PartForms';
import { InvenTreeIcon } from '../../functions/icons';
import {
@@ -80,14 +80,14 @@ function partTableColumns(): TableColumn[] {
const available = Math.max(0, stock - allocated);
const min_stock = record?.minimum_stock ?? 0;
let text = String(stock);
let text = String(formatDecimal(stock));
let color: string | undefined = undefined;
if (min_stock > stock) {
extra.push(
<Text key='min-stock' c='orange'>
{`${t`Minimum stock`}: ${min_stock}`}
{`${t`Minimum stock`}: ${formatDecimal(min_stock)}`}
</Text>
);
@@ -96,20 +96,20 @@ function partTableColumns(): TableColumn[] {
if (record.ordering > 0) {
extra.push(
<Text key='on-order'>{`${t`On Order`}: ${record.ordering}`}</Text>
<Text key='on-order'>{`${t`On Order`}: ${formatDecimal(record.ordering)}`}</Text>
);
}
if (record.building) {
extra.push(
<Text key='building'>{`${t`Building`}: ${record.building}`}</Text>
<Text key='building'>{`${t`Building`}: ${formatDecimal(record.building)}`}</Text>
);
}
if (record.allocated_to_build_orders > 0) {
extra.push(
<Text key='bo-allocations'>
{`${t`Build Order Allocations`}: ${record.allocated_to_build_orders}`}
{`${t`Build Order Allocations`}: ${formatDecimal(record.allocated_to_build_orders)}`}
</Text>
);
}
@@ -117,7 +117,7 @@ function partTableColumns(): TableColumn[] {
if (record.allocated_to_sales_orders > 0) {
extra.push(
<Text key='so-allocations'>
{`${t`Sales Order Allocations`}: ${record.allocated_to_sales_orders}`}
{`${t`Sales Order Allocations`}: ${formatDecimal(record.allocated_to_sales_orders)}`}
</Text>
);
}
@@ -125,7 +125,7 @@ function partTableColumns(): TableColumn[] {
if (available != stock) {
extra.push(
<Text key='available'>
{t`Available`}: {available}
{t`Available`}: {formatDecimal(available)}
</Text>
);
}
@@ -133,7 +133,7 @@ function partTableColumns(): TableColumn[] {
if (record.external_stock > 0) {
extra.push(
<Text key='external'>
{t`External stock`}: {record.external_stock}
{t`External stock`}: {formatDecimal(record.external_stock)}
</Text>
);
}

View File

@@ -17,6 +17,7 @@ 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 type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { useNavigate } from 'react-router-dom';
@@ -198,7 +199,7 @@ export function PurchaseOrderLineItemTable({
return (
<TableHoverCard
value={record.quantity}
value={formatDecimal(record.quantity)}
extra={extra}
title={t`Quantity`}
/>

View File

@@ -12,6 +12,7 @@ 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/index';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { useSupplierPartFields } from '../../forms/CompanyForms';
@@ -91,7 +92,8 @@ export function SupplierPartTable({
}),
{
accessor: 'in_stock',
sortable: true
sortable: true,
render: (record: any) => formatDecimal(record.in_stock)
},
{
accessor: 'packaging',

View File

@@ -29,7 +29,7 @@ import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { RenderPart } from '../../components/render/Part';
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
import { formatCurrency } from '../../defaults/formatters';
import { formatCurrency, formatDecimal } from '../../defaults/formatters';
import { useBuildOrderFields } from '../../forms/BuildForms';
import {
useAllocateToSalesOrderForm,
@@ -104,7 +104,8 @@ export default function SalesOrderLineItemTable({
},
{
accessor: 'quantity',
sortable: true
sortable: true,
render: (record: any) => formatDecimal(record.quantity)
},
{
accessor: 'sale_price',

View File

@@ -11,7 +11,11 @@ import { apiUrl } from '@lib/functions/Api';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
import { formatCurrency, formatPriceRange } from '../../defaults/formatters';
import {
formatCurrency,
formatDecimal,
formatPriceRange
} from '../../defaults/formatters';
import {
type StockOperationProps,
useStockFields
@@ -84,7 +88,7 @@ function stockItemTableColumns({
const quantity = record?.quantity ?? 0;
const allocated = record?.allocated ?? 0;
const available = quantity - allocated;
let text = quantity;
let text = formatDecimal(quantity);
const part = record?.part_detail ?? {};
const extra: ReactNode[] = [];
let color = undefined;
@@ -175,7 +179,7 @@ function stockItemTableColumns({
if (available > 0) {
extra.push(
<Text key='available' size='sm' c='orange'>
{`${t`Available`}: ${available}`}
{`${t`Available`}: ${formatDecimal(available)}`}
</Text>
);
} else {

View File

@@ -6,6 +6,7 @@ import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
import { formatDecimal } from '@lib/functions/Formatting';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { RenderBuildOrder } from '../../components/render/Build';
@@ -70,7 +71,7 @@ export function StockTrackingTable({ itemId }: Readonly<{ itemId: number }>) {
{
label: t`Quantity`,
key: 'quantity',
details: deltas.quantity
details: formatDecimal(deltas.quantity)
},
{
label: t`Added`,

View File

@@ -456,5 +456,5 @@ test('Build Order - BOM Quantity', async ({ browser }) => {
.getByRole('cell', { name: 'Thumbnail R_10K_0805_1%' })
.locator('div');
const row2 = await getRowFromCell(line);
await row2.getByText('1175').waitFor();
await row2.getByText('1,175').first().waitFor();
});

View File

@@ -1291,6 +1291,7 @@ def test(
help={
'dev': 'Set up development environment at the end',
'validate_files': 'Validate media files are correctly copied',
'use_ssh': 'Use SSH protocol for cloning the demo dataset (requires SSH key)',
}
)
def setup_test(
@@ -1298,6 +1299,7 @@ def setup_test(
ignore_update=False,
dev=False,
validate_files=False,
use_ssh=False,
path='inventree-demo-dataset',
):
"""Setup a testing environment."""
@@ -1313,12 +1315,15 @@ def setup_test(
info('Removing old data ...')
run(c, f'rm {template_dir} -r')
URL = 'https://github.com/inventree/demo-dataset'
if use_ssh:
# Use SSH protocol for cloning the demo dataset
URL = 'git@github.com:inventree/demo-dataset.git'
# Get test data
info('Cloning demo dataset ...')
run(
c,
f'git clone https://github.com/inventree/demo-dataset {template_dir} -v --depth=1',
)
run(c, f'git clone {URL} {template_dir} -v --depth=1')
# Make sure migrations are done - might have just deleted sqlite database
if not ignore_update:
@@ -1590,6 +1595,21 @@ def frontend_server(c):
yarn(c, 'yarn run dev --host')
@task
def frontend_test(c, host: str = '0.0.0.0'):
"""Start the playwright test runner for the frontend code."""
info('Starting frontend test runner')
frontend_path = local_dir().joinpath('src', 'frontend').resolve()
cmd = 'npx playwright test --ui'
if host:
cmd += f' --ui-host={host}'
run(c, cmd, path=frontend_path)
@task(
help={
'ref': 'git ref, default: current git ref',
@@ -1874,6 +1894,7 @@ development = Collection(
delete_data,
docs_server,
frontend_server,
frontend_test,
gunicorn,
import_fixtures,
schema,