From 71392a415d8b289c4a787f2b9165eaf85b8522b1 Mon Sep 17 00:00:00 2001 From: cnathe Date: Fri, 3 Oct 2025 14:34:32 -0500 Subject: [PATCH 01/15] remove isValuePrecisionValid() and the related isPrecisionValid() --- packages/components/src/index.ts | 2 - .../samples/SampleAmountEditModal.test.tsx | 36 +-------------- .../samples/SampleAmountEditModal.tsx | 17 ++----- .../components/samples/StorageAmountInput.tsx | 12 +---- .../internal/components/samples/constants.ts | 2 - .../src/internal/util/measurement.test.ts | 44 ------------------- .../src/internal/util/measurement.ts | 12 ----- 7 files changed, 6 insertions(+), 119 deletions(-) diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index 95612eacb2..d011265baf 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -885,7 +885,6 @@ import { areUnitsCompatible, getAltUnitKeys, getMetricUnitOptions, - isValuePrecisionValid, MEASUREMENT_UNITS, UnitModel, } from './internal/util/measurement'; @@ -1527,7 +1526,6 @@ export { IssuesListDefDesignerPanels, IssuesListDefModel, isValidFilterField, - isValuePrecisionValid, ItemsLegend, JavaDocsLink, joinDateTimeFormat, diff --git a/packages/components/src/internal/components/samples/SampleAmountEditModal.test.tsx b/packages/components/src/internal/components/samples/SampleAmountEditModal.test.tsx index db29ac7fbf..d0c6d718bd 100644 --- a/packages/components/src/internal/components/samples/SampleAmountEditModal.test.tsx +++ b/packages/components/src/internal/components/samples/SampleAmountEditModal.test.tsx @@ -11,7 +11,7 @@ import { TEST_PROJECT_CONTAINER } from '../../containerFixtures'; import { renderWithAppContext } from '../../test/reactTestLibraryHelpers'; -import { isPrecisionValid, isValid, SampleAmountEditModal } from './SampleAmountEditModal'; +import { isValid, SampleAmountEditModal } from './SampleAmountEditModal'; describe('SampleAmountEditModal', () => { const testSchemaQuery = new SchemaQuery('schema', 'query', 'view'); @@ -206,35 +206,6 @@ describe('SampleAmountEditModal', () => { }); }); -describe('isPrecisionValid', () => { - test('no amount and no units', () => { - expect(isPrecisionValid(undefined, undefined)).toBe(true); - expect(isPrecisionValid(undefined, null)).toBe(true); - expect(isPrecisionValid(undefined, 'bogus')).toBe(true); - expect(isPrecisionValid(undefined, 'mL')).toBe(true); - expect(isPrecisionValid(undefined, 'mg')).toBe(true); - expect(isPrecisionValid(0, undefined)).toBe(true); - expect(isPrecisionValid(1, undefined)).toBe(true); - }); - - test('with amount and units', () => { - expect(isPrecisionValid(1, 'mg')).toBe(true); - expect(isPrecisionValid(0.1, 'mg')).toBe(true); - expect(isPrecisionValid(0.01, 'mg')).toBe(true); - expect(isPrecisionValid(0.001, 'mg')).toBe(true); - expect(isPrecisionValid(0.0001, 'mg')).toBe(true); - expect(isPrecisionValid(0.00001, 'mg')).toBe(true); - expect(isPrecisionValid(0.000001, 'mg')).toBe(true); - expect(isPrecisionValid(0.0000001, 'mg')).toBe(false); - expect(isPrecisionValid(10.0000001, 'mg')).toBe(false); - }); - - test('with negative amount', () => { - expect(isPrecisionValid(-1, 'mg')).toBe(false); - expect(isPrecisionValid(-0.001, 'mg')).toBe(false); - }); -}); - describe('isValid', () => { test('has neither', () => { expect(isValid(undefined, undefined)).toBe(true); @@ -256,9 +227,6 @@ describe('isValid', () => { expect(isValid(0, 'uL')).toBe(true); expect(isValid(10, 'uL')).toBe(true); expect(isValid(0.1, 'uL')).toBe(true); - expect(isValid(0.01, 'uL')).toBe(true); - expect(isValid(0.001, 'uL')).toBe(true); - expect(isValid(0.0001, 'uL')).toBe(false); - expect(isValid(10.0001, 'uL')).toBe(false); + expect(isValid(10.000000001, 'uL')).toBe(true); }); }); diff --git a/packages/components/src/internal/components/samples/SampleAmountEditModal.tsx b/packages/components/src/internal/components/samples/SampleAmountEditModal.tsx index 0b3dbaeaaf..49dc8bbaed 100644 --- a/packages/components/src/internal/components/samples/SampleAmountEditModal.tsx +++ b/packages/components/src/internal/components/samples/SampleAmountEditModal.tsx @@ -4,7 +4,7 @@ import { SchemaQuery } from '../../../public/SchemaQuery'; import { caseInsensitive } from '../../util/utils'; import { Alert } from '../base/Alert'; -import { isValuePrecisionValid, MEASUREMENT_UNITS, UnitModel } from '../../util/measurement'; +import { UnitModel } from '../../util/measurement'; import { Modal } from '../../Modal'; @@ -13,7 +13,7 @@ import { CommentTextArea } from '../forms/input/CommentTextArea'; import { useDataChangeCommentsRequired } from '../forms/input/useDataChangeCommentsRequired'; import { updateSampleStorageData } from './actions'; -import { AMOUNT_PRECISION_ERROR_TEXT, STORED_AMOUNT_FIELDS } from './constants'; +import { STORED_AMOUNT_FIELDS } from './constants'; import { StorageAmountInput } from './StorageAmountInput'; interface Props { @@ -24,12 +24,6 @@ interface Props { updateListener: () => void; } -// exported for jest testing -export const isPrecisionValid = (amount: number, storageUnits: string): boolean => { - const units = MEASUREMENT_UNITS[storageUnits?.toLowerCase()]; - return isValuePrecisionValid(amount, units?.displayPrecision); -}; - // exported for jest testing export const isValid = (amount: number, units: string): boolean => { const hasAmount = amount !== undefined && amount !== null; @@ -38,7 +32,7 @@ export const isValid = (amount: number, units: string): boolean => { const hasNeither = !hasAmount && !hasUnits; if (hasBoth) { - return amount >= 0 && isPrecisionValid(amount, units); + return amount >= 0; } return hasNeither; }; @@ -71,11 +65,6 @@ export const SampleAmountEditModal: FC = memo(props => { }, [onClose]); const handleUpdateSampleRow = (): Promise => { - // Issue 41931: html input number step value only validates to a certain precision - const precision = storageUnits ? MEASUREMENT_UNITS[storageUnits.toLowerCase()]?.displayPrecision : 2; - if (!isValuePrecisionValid(amount, precision)) { - return Promise.reject(AMOUNT_PRECISION_ERROR_TEXT); - } const sampleData = [ { materialId: rowId?.value, diff --git a/packages/components/src/internal/components/samples/StorageAmountInput.tsx b/packages/components/src/internal/components/samples/StorageAmountInput.tsx index 3c84b19ce9..6aaf98fe98 100644 --- a/packages/components/src/internal/components/samples/StorageAmountInput.tsx +++ b/packages/components/src/internal/components/samples/StorageAmountInput.tsx @@ -7,18 +7,10 @@ import { getMetricUnitOptions, getVolumeMinStep, isMeasurementUnitIgnoreCase, - isValuePrecisionValid, MEASUREMENT_UNITS, UnitModel, } from '../../util/measurement'; -import { AMOUNT_PRECISION_ERROR_TEXT } from './constants'; - -const deltaTooPreciseMessage = ( - - {AMOUNT_PRECISION_ERROR_TEXT} - -); const negativeValueMessage = ( Amount must be a non-negative value. @@ -41,7 +33,6 @@ export const StorageAmountInput: FC = memo(props => { props; const isNegativeValue = model?.value < 0; - const isDeltaValid = isValuePrecisionValid(model?.value, model?.unit?.displayPrecision); const unitText = model?.unit?.label || model.unitStr; let preferredUnitMessage; @@ -96,7 +87,7 @@ export const StorageAmountInput: FC = memo(props => { return ( <>
-
+
{tipText && ( @@ -119,7 +110,6 @@ export const StorageAmountInput: FC = memo(props => { {preferredUnitMessage}
{isNegativeValue ? negativeValueMessage : undefined} - {!isNegativeValue && !isDeltaValid ? deltaTooPreciseMessage : undefined} ); }); diff --git a/packages/components/src/internal/components/samples/constants.ts b/packages/components/src/internal/components/samples/constants.ts index b8db3de99f..3c5d309795 100644 --- a/packages/components/src/internal/components/samples/constants.ts +++ b/packages/components/src/internal/components/samples/constants.ts @@ -307,8 +307,6 @@ export const SAMPLE_DOMAIN_INVENTORY_SYSTEM_FIELDS = [ { Name: 'StorageCol', Label: 'Storage Col', DataType: 'Text', Required: false, Description: '', Disableable: true }, ]; -export const AMOUNT_PRECISION_ERROR_TEXT = 'Amount used is too precise for selected units.'; - export const STORED_AMOUNT_FIELDS = { ROWID: 'RowId', AMOUNT: 'StoredAmount', diff --git a/packages/components/src/internal/util/measurement.test.ts b/packages/components/src/internal/util/measurement.test.ts index 7fef7ca3fb..179a9655a0 100644 --- a/packages/components/src/internal/util/measurement.test.ts +++ b/packages/components/src/internal/util/measurement.test.ts @@ -2,7 +2,6 @@ import { areUnitsCompatible, getAltUnitKeys, getMetricUnitOptions, - isValuePrecisionValid, UnitModel, } from './measurement'; @@ -153,49 +152,6 @@ describe('MetricUnit utils', () => { }); }); -describe('isValuePrecisionValid', () => { - test('value prop missing', () => { - expect(isValuePrecisionValid(undefined, 0)).toBeTruthy(); - expect(isValuePrecisionValid(null, 0)).toBeTruthy(); - }); - - test('value prop negative', () => { - expect(isValuePrecisionValid(-1, 1)).toBeFalsy(); - expect(isValuePrecisionValid(-0.000000001, 1)).toBeFalsy(); - }); - - test('precision prop', () => { - expect(isValuePrecisionValid(1, 0)).toBeTruthy(); - expect(isValuePrecisionValid(1.0, 0)).toBeTruthy(); - expect(isValuePrecisionValid(1.1, 0)).toBeTruthy(); - - expect(isValuePrecisionValid(1, 1)).toBeTruthy(); - expect(isValuePrecisionValid(1.0, 1)).toBeTruthy(); - expect(isValuePrecisionValid(1.01, 1)).toBeFalsy(); - - expect(isValuePrecisionValid(0.000001, 6)).toBeTruthy(); - expect(isValuePrecisionValid(0.000001, 6)).toBeTruthy(); - expect(isValuePrecisionValid(0.0000011, 6)).toBeFalsy(); - expect(isValuePrecisionValid(0.0000019, 6)).toBeFalsy(); - expect(isValuePrecisionValid(1.000001, 6)).toBeTruthy(); - expect(isValuePrecisionValid(1.000001, 6)).toBeTruthy(); - expect(isValuePrecisionValid(1.0000011, 6)).toBeFalsy(); - expect(isValuePrecisionValid(1.0000019, 6)).toBeFalsy(); - expect(isValuePrecisionValid(1.100001, 6)).toBeTruthy(); - expect(isValuePrecisionValid(1.100001, 6)).toBeTruthy(); - expect(isValuePrecisionValid(1.1000011, 6)).toBeFalsy(); - expect(isValuePrecisionValid(1.1000019, 6)).toBeFalsy(); - expect(isValuePrecisionValid(0.999999, 6)).toBeTruthy(); - expect(isValuePrecisionValid(0.999999, 6)).toBeTruthy(); - expect(isValuePrecisionValid(0.9999991, 6)).toBeFalsy(); - expect(isValuePrecisionValid(0.9999999, 6)).toBeFalsy(); - expect(isValuePrecisionValid(1.999999, 6)).toBeTruthy(); - expect(isValuePrecisionValid(1.999999, 6)).toBeTruthy(); - expect(isValuePrecisionValid(1.9999991, 6)).toBeFalsy(); - expect(isValuePrecisionValid(1.9999999, 6)).toBeFalsy(); - }); -}); - describe('areUnitsCompatible', () => { test('true because of equal or empty', () => { expect(areUnitsCompatible(undefined, undefined)).toBeTruthy(); diff --git a/packages/components/src/internal/util/measurement.ts b/packages/components/src/internal/util/measurement.ts index f774ee4853..d7284495e1 100644 --- a/packages/components/src/internal/util/measurement.ts +++ b/packages/components/src/internal/util/measurement.ts @@ -234,15 +234,3 @@ export function getVolumeMinStep(sampleTypeUnit?: MeasurementUnit | string) { export function isMeasurementUnitIgnoreCase(expected: MeasurementUnit, val: string) { return expected.label.localeCompare(val, 'en-US', { sensitivity: 'base' }) === 0; } - -export function isValuePrecisionValid(value: number, precision: number): boolean { - if (!value || !precision) { - return true; - } - if (value < 0) { - return false; - } - - const valueValidator = new RegExp(`^\\d*(\\.\\d{0,${precision}})?$`); - return valueValidator.test(value.toString()); -} From a5838da3895d2d1447d7c02d1809332257d9f7d4 Mon Sep 17 00:00:00 2001 From: cnathe Date: Fri, 3 Oct 2025 14:36:03 -0500 Subject: [PATCH 02/15] use amount value instead of displayValue for EditableGrid and SampleAmountEditModal --- packages/components/releaseNotes/components.md | 6 ++++++ .../internal/components/editable/actions.test.ts | 13 ++++++++++++- .../src/internal/components/editable/actions.ts | 2 ++ .../components/samples/SampleAmountEditModal.tsx | 7 +++---- packages/components/src/public/QueryColumn.ts | 4 ++++ 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/packages/components/releaseNotes/components.md b/packages/components/releaseNotes/components.md index 60283cb066..71b7b526b2 100644 --- a/packages/components/releaseNotes/components.md +++ b/packages/components/releaseNotes/components.md @@ -1,6 +1,12 @@ # @labkey/components Components, models, actions, and utility functions for LabKey applications and pages +### version TBD +*Released*: TBD +- Issue 53934: Remove stored amount "too precise" validation check on setting amount modal + - remove isValuePrecisionValid() and the related isPrecisionValid() + - use amount value instead of displayValue for EditableGrid and SampleAmountEditModal + ### version 6.62.8 *Released*: 3 October 2025 - Issue 53328: AssayDefinitionModel.hasLookup to only consider the first sample lookup column for assay import cases diff --git a/packages/components/src/internal/components/editable/actions.test.ts b/packages/components/src/internal/components/editable/actions.test.ts index 7119c4400d..caf8ec7fb3 100644 --- a/packages/components/src/internal/components/editable/actions.test.ts +++ b/packages/components/src/internal/components/editable/actions.test.ts @@ -1168,6 +1168,15 @@ describe('loadEditorModelData', () => { fieldKeyPath: 'IntField$P$S$C$D$A', derivationDataScope: 'ParentOnly', name: 'IntField./,$&', + jsonType: 'int', + }), + new QueryColumn({ + fieldKey: 'DecField$P$S$C$D$A', + fieldKeyArray: ['DecField./,$&'], + fieldKeyPath: 'DecField$P$S$C$D$A', + derivationDataScope: 'ParentOnly', + name: 'DecField./,$&', + jsonType: 'float', }), new QueryColumn({ fieldKey: 'lkField$P$S$C$D$A', @@ -1241,7 +1250,7 @@ describe('loadEditorModelData', () => { 'DtTimeField./,$&': [{ displayValue: '2025-02-07 16:30', value: '2025-02-07 16:30:00.000' }], 'lkField./,$&': [{ displayValue: 'Assay Required File', value: 37721 }], RowId: 2805931, - 'DecField./,$&': 222, + 'DecField./,$&': { displayValue: 22.3, value: 22.26 }, 'aliqAndParent$,./': '888', StoredAmount: 99, Description: '111', @@ -1322,6 +1331,8 @@ describe('loadEditorModelData', () => { 'samplefield$p$s$c$d$a&&1': [{ display: '10-1-1', raw: 117334 }], 'intfield$p$s$c$d$a&&0': [{ display: 3, raw: 3 }], 'dtfield$p$s$c$d$a&&0': [{ display: '2025-Feb-04 00:00:11.234', raw: '2025-02-04 00:00:11.234' }], + 'decfield$p$s$c$d$a&&0': [{ display: 22, raw: 22 }], + 'decfield$p$s$c$d$a&&1': [{ display: 22.26, raw: 22.26 }], 'intfield$p$s$c$d$a&&1': [{ display: 333, raw: 333 }], 'aliqfield$d$c$p$s&&0': [{ display: '123', raw: '123' }], 'dtfield$p$s$c$d$a&&1': [{ display: '2025-Feb-07 00:00', raw: '2025-02-07 00:00:00.000' }], diff --git a/packages/components/src/internal/components/editable/actions.ts b/packages/components/src/internal/components/editable/actions.ts index 0336b3db88..64cd54ccc7 100644 --- a/packages/components/src/internal/components/editable/actions.ts +++ b/packages/components/src/internal/components/editable/actions.ts @@ -220,6 +220,8 @@ function resolveValueDescriptors( let display = value?.displayValue ?? raw; if (col.isTimeOrDateTimeColumn) { display = getDateTimeDisplayValueFromStr(raw, col); + } else if (col.isNumericJsonType) { + display = raw; // Issue 53934: don't use displayValue for numeric columns } return [ diff --git a/packages/components/src/internal/components/samples/SampleAmountEditModal.tsx b/packages/components/src/internal/components/samples/SampleAmountEditModal.tsx index 49dc8bbaed..d2951197bd 100644 --- a/packages/components/src/internal/components/samples/SampleAmountEditModal.tsx +++ b/packages/components/src/internal/components/samples/SampleAmountEditModal.tsx @@ -43,15 +43,14 @@ export const SampleAmountEditModal: FC = memo(props => { const { [STORED_AMOUNT_FIELDS.ROWID]: rowId, [STORED_AMOUNT_FIELDS.UNITS]: Units, - [STORED_AMOUNT_FIELDS.AMOUNT]: initStorageAmount, + [STORED_AMOUNT_FIELDS.AMOUNT]: StoredAmount, [STORED_AMOUNT_FIELDS.SAMPLE_TYPE_UNITS]: sampleTypeUnits, } = row; const sampleContainer = caseInsensitive(row, 'Container/Path')?.value; const initStorageUnits = Units?.value; - const [amount, setStorageAmount] = useState( - initStorageAmount?.displayValue ?? initStorageAmount?.value ?? undefined - ); + const initStorageAmount = StoredAmount?.value; + const [amount, setStorageAmount] = useState(initStorageAmount); const [storageUnits, setStorageUnits] = useState(initStorageUnits ?? null); const [comment, setComment] = useState(''); const [submitting, setSubmitting] = useState(false); diff --git a/packages/components/src/public/QueryColumn.ts b/packages/components/src/public/QueryColumn.ts index f2e47a0b15..cdc12b9475 100644 --- a/packages/components/src/public/QueryColumn.ts +++ b/packages/components/src/public/QueryColumn.ts @@ -452,6 +452,10 @@ export class QueryColumn implements IQueryColumn { return !!this.description || !!this.format || !!this.phiProtected; } + get isNumericJsonType(): boolean { + return this.jsonType === 'int' || this.jsonType === 'float' || this.jsonType === 'double'; + } + isIdentifiedByImportName(importName: string): boolean { if (!importName) return false; From 5da54075d08109562169b1643765d9f159e924b4 Mon Sep 17 00:00:00 2001 From: cnathe Date: Fri, 3 Oct 2025 14:37:06 -0500 Subject: [PATCH 03/15] 6.62.8-amountPrecision53934.0 --- packages/components/package-lock.json | 4 ++-- packages/components/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 7c14cb08c1..53085b168f 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "6.62.8", + "version": "6.62.8-amountPrecision53934.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "6.62.8", + "version": "6.62.8-amountPrecision53934.0", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@hello-pangea/dnd": "18.0.1", diff --git a/packages/components/package.json b/packages/components/package.json index 4089db5bfd..e3534811bb 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "6.62.8", + "version": "6.62.8-amountPrecision53934.0", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [ From ae3412c8eced5adba2924031cd22ae25e5ba7cc8 Mon Sep 17 00:00:00 2001 From: cnathe Date: Mon, 6 Oct 2025 09:40:44 -0500 Subject: [PATCH 04/15] adjust conditional in resolveValueDescriptors to not apply to col.isLookup() --- packages/components/src/internal/components/editable/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/internal/components/editable/actions.ts b/packages/components/src/internal/components/editable/actions.ts index 64cd54ccc7..17ff43ac03 100644 --- a/packages/components/src/internal/components/editable/actions.ts +++ b/packages/components/src/internal/components/editable/actions.ts @@ -220,7 +220,7 @@ function resolveValueDescriptors( let display = value?.displayValue ?? raw; if (col.isTimeOrDateTimeColumn) { display = getDateTimeDisplayValueFromStr(raw, col); - } else if (col.isNumericJsonType) { + } else if (!col.isLookup() && col.isNumericJsonType) { display = raw; // Issue 53934: don't use displayValue for numeric columns } From 814f466a041755c3cf06b200a7a096769f17440f Mon Sep 17 00:00:00 2001 From: cnathe Date: Mon, 6 Oct 2025 09:41:38 -0500 Subject: [PATCH 05/15] 6.62.8-amountPrecision53934.1 --- packages/components/package-lock.json | 4 ++-- packages/components/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 53085b168f..91e9f10178 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.0", + "version": "6.62.8-amountPrecision53934.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.0", + "version": "6.62.8-amountPrecision53934.1", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@hello-pangea/dnd": "18.0.1", diff --git a/packages/components/package.json b/packages/components/package.json index e3534811bb..2f6c458e35 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.0", + "version": "6.62.8-amountPrecision53934.1", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [ From b93ddd69bbdf7605940a4511915975d6728d4132 Mon Sep 17 00:00:00 2001 From: cnathe Date: Mon, 6 Oct 2025 10:16:32 -0500 Subject: [PATCH 06/15] jest tests for changes --- .../components/editable/actions.test.ts | 26 +++++++++++++++++++ .../internal/components/editable/actions.ts | 3 ++- .../components/src/public/QueryColumn.test.ts | 10 +++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/components/src/internal/components/editable/actions.test.ts b/packages/components/src/internal/components/editable/actions.test.ts index caf8ec7fb3..b7c2bbd1f2 100644 --- a/packages/components/src/internal/components/editable/actions.test.ts +++ b/packages/components/src/internal/components/editable/actions.test.ts @@ -23,6 +23,7 @@ import { parsePastedLookup, removeColumn, removeColumns, + resolveValueDescriptors, splitPrefixedNumber, validateAndInsertPastedData, } from './actions'; @@ -1389,3 +1390,28 @@ describe('loadEditorModelData', () => { expect(api.query.selectRows).toHaveBeenCalledTimes(2); }); }); + +describe('resolveValueDescriptors', () => { + test('default raw and displayValue', () => { + const col = new QueryColumn({ fieldKey: 'col1', name: 'col1' }); + expect(resolveValueDescriptors(col, {}, {}, 'cellKey', 1)).toStrictEqual([{ display: 1, raw: 1 }]); + expect(resolveValueDescriptors(col, {}, {}, 'cellKey', 'value')).toStrictEqual([{ display: 'value', raw: 'value' }]); + expect(resolveValueDescriptors(col, {}, {}, 'cellKey', true)).toStrictEqual([{ display: true, raw: true }]); + expect(resolveValueDescriptors(col, {}, {}, 'cellKey', false)).toStrictEqual([{ display: false, raw: false }]); + expect(resolveValueDescriptors(col, {}, {}, 'cellKey', null)).toStrictEqual([{ display: undefined, raw: undefined }]); + expect(resolveValueDescriptors(col, {}, {}, 'cellKey', undefined)).toStrictEqual([{ display: undefined, raw: undefined }]); + + expect(resolveValueDescriptors(col, {}, {}, 'cellKey', { value: 1 })).toStrictEqual([{ display: 1, raw: 1 }]); + expect(resolveValueDescriptors(col, {}, {}, 'cellKey', { value: 1, displayValue: '1.00' })).toStrictEqual([{ display: '1.00', raw: 1 }]); + }); + + test('isNumericJsonType, non lookup', () => { + const intCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'int' }); + const floatCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'float' }); + const intLookupCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'int', lookup: { keyColumn: 'id', displayColumn: 'name' } }); + expect(resolveValueDescriptors(intCol, {}, {}, 'cellKey', { value: 10, displayValue: '010' })).toStrictEqual([{ display: 10, raw: 10 }]); + expect(resolveValueDescriptors(floatCol, {}, {}, 'cellKey', { value: 1.005, displayValue: 1.01 })).toStrictEqual([{ display: 1.005, raw: 1.005 }]); + expect(resolveValueDescriptors(intCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' })).toStrictEqual([{ display: 1, raw: 1 }]); + expect(resolveValueDescriptors(intLookupCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' })).toStrictEqual([{ display: 'Sample 1', raw: 1 }]); + }); +}); diff --git a/packages/components/src/internal/components/editable/actions.ts b/packages/components/src/internal/components/editable/actions.ts index 17ff43ac03..bfb430aba3 100644 --- a/packages/components/src/internal/components/editable/actions.ts +++ b/packages/components/src/internal/components/editable/actions.ts @@ -193,7 +193,8 @@ interface MessageAndValue { type MessageAndValueMap = Record; -function resolveValueDescriptors( +// export for jest testing +export function resolveValueDescriptors( col: QueryColumn, lookupValues: MessageAndValueMap, cellMessages: Record, diff --git a/packages/components/src/public/QueryColumn.test.ts b/packages/components/src/public/QueryColumn.test.ts index 8823bc7393..78b6094e7a 100644 --- a/packages/components/src/public/QueryColumn.test.ts +++ b/packages/components/src/public/QueryColumn.test.ts @@ -479,6 +479,16 @@ describe('QueryColumn', () => { expect(new QueryColumn({ conceptURI: CALCULATED_CONCEPT_URI }).isCalculatedField).toBeTruthy(); }); + test('isNumericJsonType', () => { + expect(new QueryColumn({}).isNumericJsonType).toBeFalsy(); + expect(new QueryColumn({ jsonType: 'string' }).isNumericJsonType).toBeFalsy(); + expect(new QueryColumn({ jsonType: 'boolean' }).isNumericJsonType).toBeFalsy(); + expect(new QueryColumn({ jsonType: 'date' }).isNumericJsonType).toBeFalsy(); + expect(new QueryColumn({ jsonType: 'int' }).isNumericJsonType).toBeTruthy(); + expect(new QueryColumn({ jsonType: 'float' }).isNumericJsonType).toBeTruthy(); + expect(new QueryColumn({ jsonType: 'double' }).isNumericJsonType).toBeTruthy(); + }); + test('isSingleSampleTypeLookup', () => { expect(new QueryColumn({}).isCalculatedField).toBeFalsy(); From 1401fd797a5010801d333c2f387ed233b78a327f Mon Sep 17 00:00:00 2001 From: cnathe Date: Mon, 6 Oct 2025 15:07:52 -0500 Subject: [PATCH 07/15] scope the editable grid changes in resolveValueDescriptors to only apply to decimal fields --- .../internal/components/editable/actions.test.ts | 10 ++++++---- .../src/internal/components/editable/actions.ts | 2 +- .../components/src/public/QueryColumn.test.ts | 16 ++++++++-------- packages/components/src/public/QueryColumn.ts | 4 ++-- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/components/src/internal/components/editable/actions.test.ts b/packages/components/src/internal/components/editable/actions.test.ts index b7c2bbd1f2..c8ec0f8f6b 100644 --- a/packages/components/src/internal/components/editable/actions.test.ts +++ b/packages/components/src/internal/components/editable/actions.test.ts @@ -1405,13 +1405,15 @@ describe('resolveValueDescriptors', () => { expect(resolveValueDescriptors(col, {}, {}, 'cellKey', { value: 1, displayValue: '1.00' })).toStrictEqual([{ display: '1.00', raw: 1 }]); }); - test('isNumericJsonType, non lookup', () => { + test('isDecimalJsonType, non lookup', () => { const intCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'int' }); const floatCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'float' }); const intLookupCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'int', lookup: { keyColumn: 'id', displayColumn: 'name' } }); - expect(resolveValueDescriptors(intCol, {}, {}, 'cellKey', { value: 10, displayValue: '010' })).toStrictEqual([{ display: 10, raw: 10 }]); - expect(resolveValueDescriptors(floatCol, {}, {}, 'cellKey', { value: 1.005, displayValue: 1.01 })).toStrictEqual([{ display: 1.005, raw: 1.005 }]); - expect(resolveValueDescriptors(intCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' })).toStrictEqual([{ display: 1, raw: 1 }]); + const floatLookupCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'float', lookup: { keyColumn: 'id', displayColumn: 'name' } }); + expect(resolveValueDescriptors(intCol, {}, {}, 'cellKey', { value: 10, displayValue: '010' })).toStrictEqual([{ display: '010', raw: 10 }]); + expect(resolveValueDescriptors(intCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' })).toStrictEqual([{ display: 'Sample 1', raw: 1 }]); expect(resolveValueDescriptors(intLookupCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' })).toStrictEqual([{ display: 'Sample 1', raw: 1 }]); + expect(resolveValueDescriptors(floatCol, {}, {}, 'cellKey', { value: 1.005, displayValue: 1.01 })).toStrictEqual([{ display: 1.005, raw: 1.005 }]); + expect(resolveValueDescriptors(floatLookupCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' })).toStrictEqual([{ display: 'Sample 1', raw: 1 }]); }); }); diff --git a/packages/components/src/internal/components/editable/actions.ts b/packages/components/src/internal/components/editable/actions.ts index bfb430aba3..188c296f7d 100644 --- a/packages/components/src/internal/components/editable/actions.ts +++ b/packages/components/src/internal/components/editable/actions.ts @@ -221,7 +221,7 @@ export function resolveValueDescriptors( let display = value?.displayValue ?? raw; if (col.isTimeOrDateTimeColumn) { display = getDateTimeDisplayValueFromStr(raw, col); - } else if (!col.isLookup() && col.isNumericJsonType) { + } else if (!col.isLookup() && col.isDecimalJsonType) { display = raw; // Issue 53934: don't use displayValue for numeric columns } diff --git a/packages/components/src/public/QueryColumn.test.ts b/packages/components/src/public/QueryColumn.test.ts index 78b6094e7a..e9ff13ecba 100644 --- a/packages/components/src/public/QueryColumn.test.ts +++ b/packages/components/src/public/QueryColumn.test.ts @@ -479,14 +479,14 @@ describe('QueryColumn', () => { expect(new QueryColumn({ conceptURI: CALCULATED_CONCEPT_URI }).isCalculatedField).toBeTruthy(); }); - test('isNumericJsonType', () => { - expect(new QueryColumn({}).isNumericJsonType).toBeFalsy(); - expect(new QueryColumn({ jsonType: 'string' }).isNumericJsonType).toBeFalsy(); - expect(new QueryColumn({ jsonType: 'boolean' }).isNumericJsonType).toBeFalsy(); - expect(new QueryColumn({ jsonType: 'date' }).isNumericJsonType).toBeFalsy(); - expect(new QueryColumn({ jsonType: 'int' }).isNumericJsonType).toBeTruthy(); - expect(new QueryColumn({ jsonType: 'float' }).isNumericJsonType).toBeTruthy(); - expect(new QueryColumn({ jsonType: 'double' }).isNumericJsonType).toBeTruthy(); + test('isDecimalJsonType', () => { + expect(new QueryColumn({}).isDecimalJsonType).toBeFalsy(); + expect(new QueryColumn({ jsonType: 'string' }).isDecimalJsonType).toBeFalsy(); + expect(new QueryColumn({ jsonType: 'boolean' }).isDecimalJsonType).toBeFalsy(); + expect(new QueryColumn({ jsonType: 'date' }).isDecimalJsonType).toBeFalsy(); + expect(new QueryColumn({ jsonType: 'int' }).isDecimalJsonType).toBeFalsy(); + expect(new QueryColumn({ jsonType: 'float' }).isDecimalJsonType).toBeTruthy(); + expect(new QueryColumn({ jsonType: 'double' }).isDecimalJsonType).toBeTruthy(); }); test('isSingleSampleTypeLookup', () => { diff --git a/packages/components/src/public/QueryColumn.ts b/packages/components/src/public/QueryColumn.ts index cdc12b9475..49020245a7 100644 --- a/packages/components/src/public/QueryColumn.ts +++ b/packages/components/src/public/QueryColumn.ts @@ -452,8 +452,8 @@ export class QueryColumn implements IQueryColumn { return !!this.description || !!this.format || !!this.phiProtected; } - get isNumericJsonType(): boolean { - return this.jsonType === 'int' || this.jsonType === 'float' || this.jsonType === 'double'; + get isDecimalJsonType(): boolean { + return this.jsonType === 'float' || this.jsonType === 'double'; } isIdentifiedByImportName(importName: string): boolean { From 48d84371836ac1f34301ccc8834b8e57f1f41f61 Mon Sep 17 00:00:00 2001 From: cnathe Date: Mon, 6 Oct 2025 15:08:25 -0500 Subject: [PATCH 08/15] 6.62.8-amountPrecision53934.2 --- packages/components/package-lock.json | 4 ++-- packages/components/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 91e9f10178..0eaeaa6bf9 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.1", + "version": "6.62.8-amountPrecision53934.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.1", + "version": "6.62.8-amountPrecision53934.2", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@hello-pangea/dnd": "18.0.1", diff --git a/packages/components/package.json b/packages/components/package.json index 2f6c458e35..2aed1807c6 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.1", + "version": "6.62.8-amountPrecision53934.2", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [ From 498504530ae3d0b3f3d0c0d64206532ac0a02cbb Mon Sep 17 00:00:00 2001 From: cnathe Date: Tue, 7 Oct 2025 08:39:14 -0500 Subject: [PATCH 09/15] update casing --- .../internal/components/samples/SampleAmountEditModal.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/components/src/internal/components/samples/SampleAmountEditModal.tsx b/packages/components/src/internal/components/samples/SampleAmountEditModal.tsx index d2951197bd..bb72cf6f1c 100644 --- a/packages/components/src/internal/components/samples/SampleAmountEditModal.tsx +++ b/packages/components/src/internal/components/samples/SampleAmountEditModal.tsx @@ -42,14 +42,14 @@ export const SampleAmountEditModal: FC = memo(props => { const { [STORED_AMOUNT_FIELDS.ROWID]: rowId, - [STORED_AMOUNT_FIELDS.UNITS]: Units, - [STORED_AMOUNT_FIELDS.AMOUNT]: StoredAmount, + [STORED_AMOUNT_FIELDS.UNITS]: units, + [STORED_AMOUNT_FIELDS.AMOUNT]: storedAmount, [STORED_AMOUNT_FIELDS.SAMPLE_TYPE_UNITS]: sampleTypeUnits, } = row; const sampleContainer = caseInsensitive(row, 'Container/Path')?.value; - const initStorageUnits = Units?.value; - const initStorageAmount = StoredAmount?.value; + const initStorageUnits = units?.value; + const initStorageAmount = storedAmount?.value; const [amount, setStorageAmount] = useState(initStorageAmount); const [storageUnits, setStorageUnits] = useState(initStorageUnits ?? null); const [comment, setComment] = useState(''); From d1623e7428b3593ff148b2b6249e6796aba034c4 Mon Sep 17 00:00:00 2001 From: cnathe Date: Tue, 7 Oct 2025 08:39:49 -0500 Subject: [PATCH 10/15] 6.62.8-amountPrecision53934.3 --- packages/components/package-lock.json | 4 ++-- packages/components/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 0eaeaa6bf9..dfe42c5cc2 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.2", + "version": "6.62.8-amountPrecision53934.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.2", + "version": "6.62.8-amountPrecision53934.3", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@hello-pangea/dnd": "18.0.1", diff --git a/packages/components/package.json b/packages/components/package.json index 2aed1807c6..aa8a7687b1 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.2", + "version": "6.62.8-amountPrecision53934.3", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [ From 4ed72d9eda27a8818636b982a75c33023900c4a4 Mon Sep 17 00:00:00 2001 From: cnathe Date: Tue, 7 Oct 2025 09:47:38 -0500 Subject: [PATCH 11/15] fix rounding display issue in UnitModal.as() --- .../components/src/internal/util/measurement.test.ts | 10 ++++------ packages/components/src/internal/util/measurement.ts | 4 +++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/components/src/internal/util/measurement.test.ts b/packages/components/src/internal/util/measurement.test.ts index 179a9655a0..48feba594e 100644 --- a/packages/components/src/internal/util/measurement.test.ts +++ b/packages/components/src/internal/util/measurement.test.ts @@ -1,9 +1,4 @@ -import { - areUnitsCompatible, - getAltUnitKeys, - getMetricUnitOptions, - UnitModel, -} from './measurement'; +import { areUnitsCompatible, getAltUnitKeys, getMetricUnitOptions, UnitModel } from './measurement'; describe('UnitModel', () => { test('constructor and operators', () => { @@ -16,6 +11,9 @@ describe('UnitModel', () => { expect(new UnitModel(99999.13345678, 'mg').as('kg').toString()).toBe('0.099999133457 kg'); expect(new UnitModel(10, 'mL').as('L').toString()).toBe('0.01 L'); expect(new UnitModel(undefined, 'mL').as('L').toString()).toBe('undefined L'); + expect(new UnitModel(0.0005, 'mL').as('mL').toString()).toBe('0.0005 mL'); + expect(new UnitModel(0.0005, 'uL').as('mL').toString()).toBe('0.000001 mL'); + expect(new UnitModel(0.0005, 'L').as('mL').toString()).toBe('0.5 mL'); expect(new UnitModel(10, 'mL').compareTo(new UnitModel(9, 'mL')) > 0).toBeTruthy(); expect(new UnitModel(10, 'mL').compareTo(new UnitModel(9, 'L')) > 0).toBeFalsy(); diff --git a/packages/components/src/internal/util/measurement.ts b/packages/components/src/internal/util/measurement.ts index d7284495e1..dbba81dca2 100644 --- a/packages/components/src/internal/util/measurement.ts +++ b/packages/components/src/internal/util/measurement.ts @@ -46,7 +46,9 @@ export class UnitModel { } const newValue = this.value * (this.unit.ratio / newUnit.ratio); - return new UnitModel(parseFloat(newValue.toFixed(newUnit.displayPrecision)), newUnit.label.toLowerCase()); + const factor = Math.pow(10, newUnit.displayPrecision); + const displayValue = Math.round(newValue * factor) / factor; + return new UnitModel(displayValue, newUnit.label.toLowerCase()); } compareTo(other: UnitModel) { From 064ef37c5d612479d53e0f7290e2ed656fdff7c5 Mon Sep 17 00:00:00 2001 From: cnathe Date: Tue, 7 Oct 2025 09:48:05 -0500 Subject: [PATCH 12/15] 6.62.8-amountPrecision53934.4 --- packages/components/package-lock.json | 4 ++-- packages/components/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index dfe42c5cc2..d6512b7004 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.3", + "version": "6.62.8-amountPrecision53934.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.3", + "version": "6.62.8-amountPrecision53934.4", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@hello-pangea/dnd": "18.0.1", diff --git a/packages/components/package.json b/packages/components/package.json index aa8a7687b1..c2c41dfb4f 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.3", + "version": "6.62.8-amountPrecision53934.4", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [ From 7b1f225f86ad1d363c7b5f6bc820a11857a314c3 Mon Sep 17 00:00:00 2001 From: cnathe Date: Tue, 7 Oct 2025 13:43:22 -0500 Subject: [PATCH 13/15] npm run lint-branch-fix --- .../components/editable/actions.test.ts | 50 +++++++++++++++---- .../samples/SampleAmountEditModal.test.tsx | 4 +- packages/components/src/public/QueryColumn.ts | 6 +-- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/packages/components/src/internal/components/editable/actions.test.ts b/packages/components/src/internal/components/editable/actions.test.ts index c8ec0f8f6b..330e6fe78e 100644 --- a/packages/components/src/internal/components/editable/actions.test.ts +++ b/packages/components/src/internal/components/editable/actions.test.ts @@ -1395,25 +1395,53 @@ describe('resolveValueDescriptors', () => { test('default raw and displayValue', () => { const col = new QueryColumn({ fieldKey: 'col1', name: 'col1' }); expect(resolveValueDescriptors(col, {}, {}, 'cellKey', 1)).toStrictEqual([{ display: 1, raw: 1 }]); - expect(resolveValueDescriptors(col, {}, {}, 'cellKey', 'value')).toStrictEqual([{ display: 'value', raw: 'value' }]); + expect(resolveValueDescriptors(col, {}, {}, 'cellKey', 'value')).toStrictEqual([ + { display: 'value', raw: 'value' }, + ]); expect(resolveValueDescriptors(col, {}, {}, 'cellKey', true)).toStrictEqual([{ display: true, raw: true }]); expect(resolveValueDescriptors(col, {}, {}, 'cellKey', false)).toStrictEqual([{ display: false, raw: false }]); - expect(resolveValueDescriptors(col, {}, {}, 'cellKey', null)).toStrictEqual([{ display: undefined, raw: undefined }]); - expect(resolveValueDescriptors(col, {}, {}, 'cellKey', undefined)).toStrictEqual([{ display: undefined, raw: undefined }]); + expect(resolveValueDescriptors(col, {}, {}, 'cellKey', null)).toStrictEqual([ + { display: undefined, raw: undefined }, + ]); + expect(resolveValueDescriptors(col, {}, {}, 'cellKey', undefined)).toStrictEqual([ + { display: undefined, raw: undefined }, + ]); expect(resolveValueDescriptors(col, {}, {}, 'cellKey', { value: 1 })).toStrictEqual([{ display: 1, raw: 1 }]); - expect(resolveValueDescriptors(col, {}, {}, 'cellKey', { value: 1, displayValue: '1.00' })).toStrictEqual([{ display: '1.00', raw: 1 }]); + expect(resolveValueDescriptors(col, {}, {}, 'cellKey', { value: 1, displayValue: '1.00' })).toStrictEqual([ + { display: '1.00', raw: 1 }, + ]); }); test('isDecimalJsonType, non lookup', () => { const intCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'int' }); const floatCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'float' }); - const intLookupCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'int', lookup: { keyColumn: 'id', displayColumn: 'name' } }); - const floatLookupCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'float', lookup: { keyColumn: 'id', displayColumn: 'name' } }); - expect(resolveValueDescriptors(intCol, {}, {}, 'cellKey', { value: 10, displayValue: '010' })).toStrictEqual([{ display: '010', raw: 10 }]); - expect(resolveValueDescriptors(intCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' })).toStrictEqual([{ display: 'Sample 1', raw: 1 }]); - expect(resolveValueDescriptors(intLookupCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' })).toStrictEqual([{ display: 'Sample 1', raw: 1 }]); - expect(resolveValueDescriptors(floatCol, {}, {}, 'cellKey', { value: 1.005, displayValue: 1.01 })).toStrictEqual([{ display: 1.005, raw: 1.005 }]); - expect(resolveValueDescriptors(floatLookupCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' })).toStrictEqual([{ display: 'Sample 1', raw: 1 }]); + const intLookupCol = new QueryColumn({ + fieldKey: 'col1', + name: 'col1', + jsonType: 'int', + lookup: { keyColumn: 'id', displayColumn: 'name' }, + }); + const floatLookupCol = new QueryColumn({ + fieldKey: 'col1', + name: 'col1', + jsonType: 'float', + lookup: { keyColumn: 'id', displayColumn: 'name' }, + }); + expect(resolveValueDescriptors(intCol, {}, {}, 'cellKey', { value: 10, displayValue: '010' })).toStrictEqual([ + { display: '010', raw: 10 }, + ]); + expect( + resolveValueDescriptors(intCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' }) + ).toStrictEqual([{ display: 'Sample 1', raw: 1 }]); + expect( + resolveValueDescriptors(intLookupCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' }) + ).toStrictEqual([{ display: 'Sample 1', raw: 1 }]); + expect( + resolveValueDescriptors(floatCol, {}, {}, 'cellKey', { value: 1.005, displayValue: 1.01 }) + ).toStrictEqual([{ display: 1.005, raw: 1.005 }]); + expect( + resolveValueDescriptors(floatLookupCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' }) + ).toStrictEqual([{ display: 'Sample 1', raw: 1 }]); }); }); diff --git a/packages/components/src/internal/components/samples/SampleAmountEditModal.test.tsx b/packages/components/src/internal/components/samples/SampleAmountEditModal.test.tsx index d0c6d718bd..2ab5762c04 100644 --- a/packages/components/src/internal/components/samples/SampleAmountEditModal.test.tsx +++ b/packages/components/src/internal/components/samples/SampleAmountEditModal.test.tsx @@ -36,7 +36,9 @@ describe('SampleAmountEditModal', () => { expect(document.querySelector('textarea').getAttribute('value')).toBe(comment ?? null); expect(document.querySelectorAll('.alert')).toHaveLength(isNegative ? 1 : 0); if (isNegative) { - expect(document.querySelectorAll('.alert').item(0).textContent).toBe('Amount must be a non-negative value.'); + expect(document.querySelectorAll('.alert').item(0).textContent).toBe( + 'Amount must be a non-negative value.' + ); } validateSubmitButton(noun, canSave); } diff --git a/packages/components/src/public/QueryColumn.ts b/packages/components/src/public/QueryColumn.ts index 49020245a7..f8d666a328 100644 --- a/packages/components/src/public/QueryColumn.ts +++ b/packages/components/src/public/QueryColumn.ts @@ -271,7 +271,7 @@ export class QueryColumn implements IQueryColumn { declare tableCell: boolean; declare width: number; - constructor(rawColumn: Partial) { + constructor(rawColumn: Partial) { Object.assign(this, defaultQueryColumn, rawColumn); if (rawColumn && rawColumn.lookup !== undefined) { @@ -493,10 +493,10 @@ export class QueryColumn implements IQueryColumn { allowFaceting(): boolean { switch (this.facetingBehaviorType) { - case 'ALWAYS_ON': - return true; case 'ALWAYS_OFF': return false; + case 'ALWAYS_ON': + return true; case 'AUTOMATIC': // auto rules are if the column is a lookup or dimension // OR if it is of type : (boolean, int, date, text), multiline excluded From 42dbf3b6fd6d2343b23b791578280ac999703c60 Mon Sep 17 00:00:00 2001 From: cnathe Date: Tue, 7 Oct 2025 13:45:01 -0500 Subject: [PATCH 14/15] 6.62.9 --- packages/components/package-lock.json | 4 ++-- packages/components/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index d6512b7004..163cc4b510 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.4", + "version": "6.62.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.4", + "version": "6.62.9", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@hello-pangea/dnd": "18.0.1", diff --git a/packages/components/package.json b/packages/components/package.json index c2c41dfb4f..58368b0a1d 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "6.62.8-amountPrecision53934.4", + "version": "6.62.9", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [ From 4e6460946a7ab176c0c2eaa58770b8c24cfcb9c7 Mon Sep 17 00:00:00 2001 From: cnathe Date: Tue, 7 Oct 2025 13:45:36 -0500 Subject: [PATCH 15/15] Update release notes with version number and release date --- packages/components/releaseNotes/components.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/releaseNotes/components.md b/packages/components/releaseNotes/components.md index 71b7b526b2..e1cc4d49b6 100644 --- a/packages/components/releaseNotes/components.md +++ b/packages/components/releaseNotes/components.md @@ -1,8 +1,8 @@ # @labkey/components Components, models, actions, and utility functions for LabKey applications and pages -### version TBD -*Released*: TBD +### version 6.62.9 +*Released*: 7 October 2025 - Issue 53934: Remove stored amount "too precise" validation check on setting amount modal - remove isValuePrecisionValid() and the related isPrecisionValid() - use amount value instead of displayValue for EditableGrid and SampleAmountEditModal