diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 7c14cb08c1..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", + "version": "6.62.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "6.62.8", + "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 4089db5bfd..58368b0a1d 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.9", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [ diff --git a/packages/components/releaseNotes/components.md b/packages/components/releaseNotes/components.md index 60283cb066..e1cc4d49b6 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 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 + ### 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/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/editable/actions.test.ts b/packages/components/src/internal/components/editable/actions.test.ts index 7119c4400d..330e6fe78e 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'; @@ -1168,6 +1169,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 +1251,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 +1332,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' }], @@ -1378,3 +1390,58 @@ 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('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 }]); + }); +}); diff --git a/packages/components/src/internal/components/editable/actions.ts b/packages/components/src/internal/components/editable/actions.ts index 0336b3db88..188c296f7d 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, @@ -220,6 +221,8 @@ function resolveValueDescriptors( let display = value?.displayValue ?? raw; if (col.isTimeOrDateTimeColumn) { display = getDateTimeDisplayValueFromStr(raw, col); + } else if (!col.isLookup() && col.isDecimalJsonType) { + display = raw; // Issue 53934: don't use displayValue for numeric columns } return [ diff --git a/packages/components/src/internal/components/samples/SampleAmountEditModal.test.tsx b/packages/components/src/internal/components/samples/SampleAmountEditModal.test.tsx index db29ac7fbf..2ab5762c04 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'); @@ -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); } @@ -206,35 +208,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 +229,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..bb72cf6f1c 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; }; @@ -48,16 +42,15 @@ 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.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 [amount, setStorageAmount] = useState( - initStorageAmount?.displayValue ?? initStorageAmount?.value ?? undefined - ); + const initStorageUnits = units?.value; + const initStorageAmount = storedAmount?.value; + const [amount, setStorageAmount] = useState(initStorageAmount); const [storageUnits, setStorageUnits] = useState(initStorageUnits ?? null); const [comment, setComment] = useState(''); const [submitting, setSubmitting] = useState(false); @@ -71,11 +64,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..48feba594e 100644 --- a/packages/components/src/internal/util/measurement.test.ts +++ b/packages/components/src/internal/util/measurement.test.ts @@ -1,10 +1,4 @@ -import { - areUnitsCompatible, - getAltUnitKeys, - getMetricUnitOptions, - isValuePrecisionValid, - UnitModel, -} from './measurement'; +import { areUnitsCompatible, getAltUnitKeys, getMetricUnitOptions, UnitModel } from './measurement'; describe('UnitModel', () => { test('constructor and operators', () => { @@ -17,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(); @@ -153,49 +150,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..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) { @@ -234,15 +236,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()); -} diff --git a/packages/components/src/public/QueryColumn.test.ts b/packages/components/src/public/QueryColumn.test.ts index 8823bc7393..e9ff13ecba 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('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', () => { expect(new QueryColumn({}).isCalculatedField).toBeFalsy(); diff --git a/packages/components/src/public/QueryColumn.ts b/packages/components/src/public/QueryColumn.ts index f2e47a0b15..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) { @@ -452,6 +452,10 @@ export class QueryColumn implements IQueryColumn { return !!this.description || !!this.format || !!this.phiProtected; } + get isDecimalJsonType(): boolean { + return this.jsonType === 'float' || this.jsonType === 'double'; + } + isIdentifiedByImportName(importName: string): boolean { if (!importName) return false; @@ -489,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