From 130eb32f88e2bdd0d761d927664a116e2dfa9fe8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 17 Jun 2025 22:51:28 +1000 Subject: [PATCH] [UI] Enhanced number formatting (#9799) * Enhanced number formatting * Support part units --- .../src/components/details/Details.tsx | 31 ++++++++++++++++++- .../src/components/items/ProgressBar.tsx | 3 +- src/frontend/src/pages/part/PartDetail.tsx | 25 ++++++++------- src/frontend/src/pages/stock/StockDetail.tsx | 9 ++++-- 4 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/frontend/src/components/details/Details.tsx b/src/frontend/src/components/details/Details.tsx index cb5f50e69f..4bc7062b6a 100644 --- a/src/frontend/src/components/details/Details.tsx +++ b/src/frontend/src/components/details/Details.tsx @@ -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) { return {formatDate(props.field_value?.toString())}; } +// Return a formatted "number" value, with optional unit +function NumberValue(props: Readonly) { + const value = props?.field_value; + + // Convert to double + const numberValue = Number.parseFloat(value.toString()); + + if (value === null || value === undefined) { + return '---'; + } + + return ( + + {formatDecimal(numberValue)} + {!!props.field_data?.unit && ( + [{props.field_data?.unit}] + )} + + ); +} + /** * 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: diff --git a/src/frontend/src/components/items/ProgressBar.tsx b/src/frontend/src/components/items/ProgressBar.tsx index dcbf5e51e7..d27f592f2b 100644 --- a/src/frontend/src/components/items/ProgressBar.tsx +++ b/src/frontend/src/components/items/ProgressBar.tsx @@ -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) { {props.progressLabel && ( - {props.value} / {props.maximum} + {formatDecimal(props.value)} / {formatDecimal(props.maximum)} )}