2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-01 11:10:54 +00:00

[UI] Enhanced number formatting (#9799)

* Enhanced number formatting

* Support part units
This commit is contained in:
Oliver
2025-06-17 22:51:28 +10:00
committed by GitHub
parent 92667876fe
commit 130eb32f88
4 changed files with 51 additions and 17 deletions

View File

@ -24,7 +24,7 @@ import { getDetailUrl } from '@lib/functions/Navigation';
import { navigateToLink } from '@lib/functions/Navigation';
import type { InvenTreeIconType } from '@lib/types/Icons';
import { useApi } from '../../contexts/ApiContext';
import { formatDate } from '../../defaults/formatters';
import { formatDate, formatDecimal } from '../../defaults/formatters';
import { InvenTreeIcon } from '../../functions/icons';
import { useGlobalSettingsState } from '../../states/SettingsState';
import { CopyButton } from '../buttons/CopyButton';
@ -43,6 +43,7 @@ export type DetailsField = {
copy?: boolean;
value_formatter?: () => ValueFormatterReturn;
} & (
| NumberDetailField
| StringDetailField
| BooleanField
| LinkDetailField
@ -58,6 +59,11 @@ type StringDetailField = {
unit?: boolean;
};
type NumberDetailField = {
type: 'number';
unit?: boolean;
};
type BooleanField = {
type: 'boolean';
};
@ -262,6 +268,27 @@ function DateValue(props: Readonly<FieldProps>) {
return <Text size='sm'>{formatDate(props.field_value?.toString())}</Text>;
}
// Return a formatted "number" value, with optional unit
function NumberValue(props: Readonly<FieldProps>) {
const value = props?.field_value;
// Convert to double
const numberValue = Number.parseFloat(value.toString());
if (value === null || value === undefined) {
return <Text size='sm'>'---'</Text>;
}
return (
<Group wrap='nowrap' gap='xs' justify='left'>
<Text size='sm'>{formatDecimal(numberValue)}</Text>
{!!props.field_data?.unit && (
<Text size='xs'>[{props.field_data?.unit}]</Text>
)}
</Group>
);
}
/**
* Renders the value of a 'string' or 'text' field.
* If owner is defined, only renders a badge
@ -447,6 +474,8 @@ export function DetailsTableField({
return StatusValue;
case 'date':
return DateValue;
case 'number':
return NumberValue;
case 'text':
case 'string':
default:

View File

@ -1,5 +1,6 @@
import { Progress, Stack, Text } from '@mantine/core';
import { useMemo } from 'react';
import { formatDecimal } from '../../defaults/formatters';
export type ProgressBarProps = {
value: number;
@ -30,7 +31,7 @@ export function ProgressBar(props: Readonly<ProgressBarProps>) {
<Stack gap={2} style={{ flexGrow: 1, minWidth: '100px' }}>
{props.progressLabel && (
<Text ta='center' size='xs'>
{props.value} / {props.maximum}
{formatDecimal(props.value)} / {formatDecimal(props.maximum)}
</Text>
)}
<Progress

View File

@ -249,44 +249,45 @@ export default function PartDetail() {
// Top right - stock availability information
const tr: DetailsField[] = [
{
type: 'string',
type: 'number',
name: 'total_in_stock',
unit: true,
unit: part.units,
label: t`In Stock`
},
{
type: 'string',
type: 'number',
name: 'unallocated_stock',
unit: true,
unit: part.units,
label: t`Available Stock`,
hidden: part.total_in_stock == part.unallocated_stock
},
{
type: 'string',
type: 'number',
name: 'variant_stock',
unit: true,
unit: part.units,
label: t`Variant Stock`,
hidden: !part.variant_stock,
icon: 'stock'
},
{
type: 'string',
type: 'number',
name: 'minimum_stock',
unit: true,
unit: part.units,
label: t`Minimum Stock`,
hidden: part.minimum_stock <= 0
},
{
type: 'string',
type: 'number',
name: 'ordering',
label: t`On order`,
unit: true,
unit: part.units,
hidden: !part.purchaseable || part.ordering <= 0
},
{
type: 'string',
type: 'number',
name: 'required',
label: t`Required for Orders`,
unit: part.units,
hidden: part.required <= 0,
icon: 'stocktake'
},
@ -315,7 +316,7 @@ export default function PartDetail() {
part.allocated_to_sales_orders <= 0)
},
{
type: 'string',
type: 'number',
name: 'can_build',
unit: true,
label: t`Can Build`,

View File

@ -255,21 +255,24 @@ export default function StockDetail() {
)
},
{
type: 'text',
type: 'number',
name: 'quantity',
label: t`Quantity`,
unit: part?.units,
hidden: !!stockitem.serial && stockitem.quantity == 1
},
{
type: 'text',
type: 'number',
name: 'available_stock',
label: t`Available`,
unit: part?.units,
icon: 'stock'
},
{
type: 'text',
type: 'number',
name: 'allocated',
label: t`Allocated to Orders`,
unit: part?.units,
icon: 'tick_off',
hidden: !stockitem.allocated
},