feat(WorkList): New Study List (WorkList based on ui-next); old study list renamed to LegacyWorklist (#6005)

---------

Co-authored-by: Dan Rukas <dan.rukas@gmail.com>
Co-authored-by: Bill Wallace <wayfarer3130@gmail.com>
This commit is contained in:
authored and GitHub committed 2026-05-28 12:26:30 -04:00
1 parent 9e7a3586ce
commit daae4c144e
121 files changed
+8071 -1468

No files matched your search

@@ -494,4 +494,54 @@ describe('CustomizationService - Registration + API Operations', () => {
expect(customization.title).toBe(undefined);
});
});
// Values can legitimately contain React elements (e.g. a column's
// `meta.headerContent`). React brands every element with `$$typeof`, which
// must NOT be mistaken for an immutability-helper command.
describe('React elements in values', () => {
const reactElement = {
$$typeof: Symbol.for('react.element'),
type: 'svg',
key: null,
ref: null,
props: {},
};
it('registers a default array containing a React element without throwing', () => {
const columns = [
{ id: 'a', meta: { label: 'A' } },
{ id: 'b', meta: { label: 'B', headerContent: reactElement } },
];
expect(() =>
customizationService.addReferences(
{ 'workList.columns': columns },
CustomizationScope.Default
)
).not.toThrow();
const result = customizationService.getCustomization('workList.columns');
expect(result).toEqual(columns);
expect(result[1].meta.headerContent).toBe(reactElement);
});
it('still applies $ commands over a default array containing a React element', () => {
const columns = [
{ id: 'a', meta: { label: 'A' } },
{ id: 'b', meta: { label: 'B', headerContent: reactElement } },
];
customizationService.addReferences(
{ 'workList.columns': columns },
CustomizationScope.Default
);
customizationService.setCustomizations({
'workList.columns': { $push: [{ id: 'c', meta: { label: 'C' } }] },
});
const result = customizationService.getCustomization('workList.columns');
expect(result.map(c => c.id)).toEqual(['a', 'b', 'c']);
expect(result[1].meta.headerContent).toBe(reactElement);
});
});
});
@@ -531,6 +531,13 @@ function hasDollarKey(value) {
}
}
} else if (value && typeof value === 'object') {
// React elements carry a `$$typeof` brand; they're values to render, not
// immutability-helper command specs, so don't scan into them (otherwise
// their `$$typeof` is misread as a command and `update()` runs on a value
// it shouldn't).
if (value.$$typeof) {
return false;
}
for (const key of Object.keys(value)) {
if (key.startsWith('$') && key !== '$transform') {
return true;
+3
View File
@@ -48,6 +48,7 @@ import calculateScanAxisNormal from './calculateScanAxisNormal';
import areAllImageOrientationsEqual from './areAllImageOrientationsEqual';
import { structuredCloneWithFunctions } from './structuredCloneWithFunctions';
import { buildButtonCommands } from './buildButtonCommands';
import { thumbnailNoImageModalities } from './thumbnailNoImageModalities';
import { downloadBlob, downloadUrl, downloadCsv, downloadDicom } from './downloadBlob';
@@ -103,6 +104,7 @@ const utils = {
getClosestOrientationFromIOP,
calculateScanAxisNormal,
areAllImageOrientationsEqual,
thumbnailNoImageModalities,
downloadBlob,
downloadUrl,
downloadCsv,
@@ -145,6 +147,7 @@ export {
MeasurementFilters,
getClosestOrientationFromIOP,
buildButtonCommands,
thumbnailNoImageModalities,
downloadBlob,
downloadUrl,
downloadCsv,
@@ -0,0 +1,10 @@
export const thumbnailNoImageModalities = [
'SR',
'SEG',
'RTSTRUCT',
'RTPLAN',
'RTDOSE',
'DOC',
'PMAP',
'RWV',
];