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:
@@ -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,
|
||||
|
@@ -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>
|
||||
);
|
||||
|
||||
|
@@ -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',
|
||||
|
@@ -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>
|
||||
)}
|
||||
|
@@ -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',
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
|
@@ -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`}
|
||||
/>
|
||||
|
@@ -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',
|
||||
|
@@ -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',
|
||||
|
@@ -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 {
|
||||
|
@@ -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`,
|
||||
|
@@ -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();
|
||||
});
|
||||
|
29
tasks.py
29
tasks.py
@@ -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,
|
||||
|
Reference in New Issue
Block a user