diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 2593bef5d8..483d32dc92 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "7.45.6", + "version": "7.45.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "7.45.6", + "version": "7.45.7", "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 031cb7d1bf..0f8e5c98ea 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "7.45.6", + "version": "7.45.7", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [ diff --git a/packages/components/src/internal/components/editable/actions.test.ts b/packages/components/src/internal/components/editable/actions.test.ts index d5823c72eb..474a2faac6 100644 --- a/packages/components/src/internal/components/editable/actions.test.ts +++ b/packages/components/src/internal/components/editable/actions.test.ts @@ -1812,4 +1812,40 @@ describe('resolveValueDescriptors', () => { resolveValueDescriptors(floatLookupCol, {}, {}, 'cellKey', { value: 1, displayValue: 'Sample 1' }) ).toStrictEqual([{ display: 'Sample 1', raw: 1 }]); }); + + // Issue 1288: read-only columns (e.g. ancestor identifying fields) should keep the server's displayValue + // rather than re-deriving the display from the raw value. + test('readOnly columns use displayValue and skip reformatting', () => { + // Decimal: editable columns ignore displayValue in favor of the raw value (Issue 53934), but a + // read-only column should surface the server-formatted displayValue. + const floatCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'float' }); + const readOnlyFloatCol = new QueryColumn({ fieldKey: 'col1', name: 'col1', jsonType: 'float', readOnly: true }); + expect( + resolveValueDescriptors(floatCol, {}, {}, 'cellKey', { value: 1.005, displayValue: 1.01 }) + ).toStrictEqual([{ display: 1.005, raw: 1.005 }]); + expect( + resolveValueDescriptors(readOnlyFloatCol, {}, {}, 'cellKey', { value: 1.005, displayValue: 1.01 }) + ).toStrictEqual([{ display: 1.01, raw: 1.005 }]); + + // DateTime: a read-only column returns the server displayValue verbatim instead of running the raw + // value through the date formatter (which, for this column's format, would produce '2023-Feb-14 06:30'). + const readOnlyDateTimeCol = new QueryColumn({ + fieldKey: 'col1', + name: 'col1', + rangeURI: DATETIME_RANGE_URI, + format: 'yyyy-MMM-dd HH:mm', + readOnly: true, + }); + expect( + resolveValueDescriptors(readOnlyDateTimeCol, {}, {}, 'cellKey', { + value: '2023-02-14 06:30:00.000', + displayValue: '2023-02-14 06:30', + }) + ).toStrictEqual([{ display: '2023-02-14 06:30', raw: '2023-02-14 06:30:00.000' }]); + + // Read-only datetime with no displayValue falls back to the raw value (not reformatted). + expect( + resolveValueDescriptors(readOnlyDateTimeCol, {}, {}, 'cellKey', { value: '2023-02-14 06:30:00.000' }) + ).toStrictEqual([{ display: '2023-02-14 06:30:00.000', raw: '2023-02-14 06:30:00.000' }]); + }); }); diff --git a/packages/components/src/internal/components/editable/actions.ts b/packages/components/src/internal/components/editable/actions.ts index 180737cfdf..d8127fd757 100644 --- a/packages/components/src/internal/components/editable/actions.ts +++ b/packages/components/src/internal/components/editable/actions.ts @@ -254,10 +254,12 @@ export 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 + if (!col.readOnly) { + 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/entities/actions.test.ts b/packages/components/src/internal/components/entities/actions.test.ts index 3aaed54d36..377b87e2f3 100644 --- a/packages/components/src/internal/components/entities/actions.test.ts +++ b/packages/components/src/internal/components/entities/actions.test.ts @@ -119,4 +119,10 @@ describe('getFieldDisplayValue', () => { test('handles single-element array', () => { expect(getFieldDisplayValue({ value: ['only'] })).toBe('only'); }); + + test('returns empty string when fieldData is missing', () => { + expect(getFieldDisplayValue(undefined)).toBe(''); + expect(getFieldDisplayValue(null)).toBe(''); + expect(getFieldDisplayValue('')).toBe(''); + }); }); diff --git a/packages/components/src/internal/components/entities/actions.ts b/packages/components/src/internal/components/entities/actions.ts index df9edbcd90..abdfc528e6 100644 --- a/packages/components/src/internal/components/entities/actions.ts +++ b/packages/components/src/internal/components/entities/actions.ts @@ -1375,6 +1375,7 @@ export function getSingleSampleTypeQueryInfo(sampleIds: number[] | string[]): Pr // GitHub Issue 928: Spaces not shown between text choices in identifying fields in editable grid export function getFieldDisplayValue(fieldData: any): string { + if (!fieldData) return ''; const val = fieldData.formattedValue ?? fieldData.displayValue ?? fieldData.value; if (Array.isArray(val)) return val.join(', '); return val;