Work List
The workList.* namespace customizes the WorkList study-list route used as the default landing page in OHIF.
With the exception of workList.variant itself, the customizations below only apply when workList.variant is 'default'; they are ignored when the legacy study list is mounted.
workList.variant
Selects which study-list route is mounted at /.
'default'(default customization value): the new ui-next WorkList, introduced in 3.13.'legacy': the pre-3.13 WorkList (internallyLegacyWorkList). Use this as an opt-out while migrating to the new study list.
The customization is read once during route registration, so changing it requires a reload.
workList.previewSeriesView
Controls which series views are available in the preview panel that opens to the right of the study list.
'all'(default customization value): the thumbnails/list toggle is visible. The initial preview view is thumbnails.'thumbnails': the toggle is hidden; the preview is locked to thumbnails.'list': the toggle is hidden; the preview is locked to the series list.
Note: the preview is forced to 'list' when the active data source either declares thumbnailRendering as 'wadors' or 'thumbnailDirect', or declares thumbnailRequestStrategy as 'bulkDataRetrieve' (the default value for thumbnailRequestStrategy). In those cases, the customization is ignored and the technical override wins.
The customizations below often involve functions — workList.renderPreviewContent and workList.settingsMenuItems are functions, and workList.columns (a value) commonly carries cell/header renderers or an $apply transform. Those functions frequently need access to React hooks, the services manager, or the commands manager (e.g. to open modals, navigate, run commands, or build translated labels). They can be set from window.config, but they're generally easier to author in a custom extension's getCustomizationModule, where the services manager is in scope and components can use hooks normally. Plain config is best suited to simple tweaks like reordering, removing, or inserting items that only need static handlers.
workList.columns
The column set for the WorkList table, registered as a value — ColumnDef<StudyRow, unknown>[] — rather than a function. The default is StudyList.defaultColumns, so out of the box the table shows Patient, MRN, Study Date, Modalities, Description, Accession, Instances, and a trailing actions column in that order.
Because it is a plain array, you customize it with immutability-helper commands:
| Command | Use |
|---|---|
$splice | reorder, insert, or remove columns |
$set / $merge | tweak a column's meta (label, minWidth, priority, align) |
$set a cell/header | replace a column's renderer |
$apply: (cols) => cols | run your own function over the current columns and return the new array |
The first three commands cover the common, declarative tweaks. $apply is the general-purpose option for anything they don't express cleanly: instead of describing the change with a command, you receive the current ColumnDef[] and return the array you want. Because it's a plain function you can use normal JavaScript — find, filter, map, slice, conditionals — which makes it the right choice for moves, conditional inserts, or any edit that should be driven by a column's id rather than its position. For example, reordering by id:
'workList.columns': {
$apply: columns => {
// Move "Modalities" to the front, leaving everything else in order.
const modalities = columns.find(c => c.id === 'modalities');
return modalities ? [modalities, ...columns.filter(c => c.id !== 'modalities')] : columns;
},
}
For a simple, display-only column, StudyList.textColumn(id, label, meta?) fills in the accessor/header/cell wiring for you:
window.config = {
customizationService: [
{
'workList.columns': {
// Insert before the trailing actions column so it stays at row end.
$apply: columns => {
const at = columns.findIndex(c => c.id === 'actions');
const referring = StudyList.textColumn('referringPhysicianName', 'Referring Physician');
return [...columns.slice(0, at), referring, ...columns.slice(at)];
},
},
},
],
};
A pure-data tweak (e.g. relabel) needs no function at all:
'workList.columns': { 2: { meta: { label: { $set: 'Study Date / Time' } } } }
Surfacing an attribute the data source doesn't map yet
A column can only display data that's already on the study row. The default DICOMweb data source maps a fixed set of fields (patientName, mrn, date/time, accession, description, modalities, instances, studyInstanceUid, referringPhysicianName). To add a column for a DICOM attribute outside that set — say Requesting Physician (0032,1032) — extend the QIDO handling in extensions/default/src/DicomWebDataSource/qido.js:
-
Request the tag — add it to
includefieldinmapParams, so the server is asked to return it:const commaSeparatedFields = [
'00081030', // Study Description
'00080060', // Modality
'00080090', // Referring Physician's Name
'00321032', // Requesting Physician
].join(','); -
Map it onto the row — in
processResults(aPN-VR field, so it goes throughformatPN/getNamelikepatientName):requestingPhysician: utils.formatPN(getName(qidoStudy['00321032'])) || '',
Now any column can read row.requestingPhysician (e.g. StudyList.textColumn('requestingPhysician', 'Requesting Physician')). Note that StudyRow does not need editing — it carries an index signature, so data-source-mapped fields are readable without a type change.
Two caveats: the server must actually return the tag (it has to support includefield — see the data source's qidoSupportsIncludeField — and the studies must carry the attribute), and this is a data-source-wide change, not scoped to the worklist.
Gotchas and limitations
- Renderers aren't serializable. A column's
accessorFn,cell,header,filterFn, andsortingFnare functions.$set/$pushaccept them, but a column that renders anything beyond plain text still requires code — you can't express it as pure JSON config.StudyList.textColumncovers the simple text case. - The
actionscolumn should stay last (cosmetic). Its hover menu is right-aligned to anchor the row end, so placing it mid-row just looks wrong — it's not a functional requirement. Insert new columns before it (e.g.$spliceat its index, or the$applypattern above); a bare$pushlands after it, leaving the actions menu mid-row. - Index-based commands are position-fragile.
{ 2: { … } }targets whatever is at index 2, which shifts if earlier columns are added/removed. Prefer$applywith afindIndex/idlookup for edits that should survive reordering. - If the merged value is not an array, WorkList falls back to
StudyList.defaultColumns.
workList.renderPreviewContent
Render function for the preview panel that opens to the right of the study list. The customization receives the host React and the same data the built-in renderer uses — series and thumbnails are fetched by the SidePanelPreview shell and passed in as props.
type PreviewContentProps = {
study: StudyRow | null;
series: any[];
seriesView: 'all' | 'thumbnails' | 'list';
onThumbnailImageError: (seriesUID: string) => void;
};
type RenderPreviewContent = (
React: typeof import('react'),
props: PreviewContentProps
) => React.ReactNode;
Props
study— the currently selectedStudyRow(nullwhen no study is selected). Useful fields includestudyInstanceUid,patientName,mrn,date,modalities,description,accession, andinstances.series— the series belonging tostudy, sorted by series date. Each item has the raw fields returned by the data source (seriesInstanceUid,modality,description,seriesDate,seriesNumber,numSeriesInstances, etc.) plus athumbnailStatusadded by the shell:{ status: 'loading' }— a thumbnail fetch is in flight.{ status: 'ready', src }—srcis the URL (often ablob:URL) you can render in an<img>.{ status: 'notAvailable' }— the fetch failed oronThumbnailImageErrorwas called for this series.{ status: 'notApplicable' }— the modality has no displayable thumbnail (e.g. SR, KO).
seriesView—'all' | 'thumbnails' | 'list'. Resolved fromworkList.previewSeriesView, with'list'forced when the active data source useswadors/thumbnailDirectrendering orbulkDataRetrieveretrieval. Honor it if you want to respect the user's toggle and the data-source constraints; ignore it if your custom layout doesn't have a thumbnails/list distinction.onThumbnailImageError— call with a series UID when an<img>you render fails to load. The shell marks that series asnotAvailableand revokes its blob URL if needed. Wire it to your image element'sonErrorto keep the state consistent.
Use this customization to change the preview layout (e.g. a different patient summary, a custom series grid) while keeping the fetch, abort-on-selection-change, and bounded thumbnail worker pool intact. When the customization is unset (the default) or not a function, WorkList uses the built-in <StudyList.PreviewContainer> layout.
workList.settingsMenuItems
Builds the items in the WorkList settings popover (the gear menu in the top right). The customization is a function that receives the default items and must return a SettingsMenuItem[].
type SettingsMenuItem = {
id: string;
label: React.ReactNode;
onClick: () => void;
};
type WorkListSettingsMenuItems = (defaults: SettingsMenuItem[]) => SettingsMenuItem[];
The default items are:
about— opens the About modal (ohif.aboutModalcustomization).userPreferences— opens the User Preferences modal (ohif.userPreferencesModalcustomization).logout— only included whenappConfig.oidcis configured; navigates to/logout.
Use it to reorder, remove, or insert items (e.g. a "Help" link, a "Send feedback" action) without rebuilding the popover shell. If the customization returns a non-array value, WorkList falls back to the defaults.
workList.variant
| ID | workList.variant |
|---|---|
| Description | Selects which study-list route is mounted at /. Use 'default' (default customization value) for the new ui-next WorkList introduced in 3.13. Use 'legacy' to mount the pre-3.13 WorkList (internally LegacyWorkList) as an opt-out while migrating. The customization is read once during route registration, so changing it requires a reload. |
| Default Value | default |
| Example | |
workList.previewSeriesView
| ID | workList.previewSeriesView |
|---|---|
| Description | Controls which series views are available in the WorkList preview panel. Use 'all' (default customization value) to show the thumbnails/list toggle. The initial preview view is thumbnails. Use 'thumbnails' to lock the preview to thumbnails, or 'list' to lock it to the series list. The preview is forced to 'list' when the active data source declares thumbnailRendering as 'wadors' or 'thumbnailDirect', or declares thumbnailRequestStrategy as 'bulkDataRetrieve' (its default value), regardless of this setting. Currently only applies when workList.variant is 'default'. |
| Default Value | all |
| Example | |
workList.columns
| ID | workList.columns |
|---|---|
| Description | The column set for the WorkList table, as a ColumnDef[] value (default: StudyList.defaultColumns). Because it is a plain array, override it with immutability-helper commands — $splice to reorder/insert/remove, $set/$merge to tweak meta (label, width, priority), or $apply — a function that receives the current columns and returns the new array — for anything the other commands don't express cleanly (moves, conditional inserts, or edits keyed off a column's id rather than its position). Use StudyList.textColumn(id, label, meta?) for a simple display-only column. Gotchas: a column's cell/accessorFn/etc. are functions (not serializable, so non-text columns still need code); the trailing actions column should stay last for correct layout (cosmetic, not required), so insert before it with $splice rather than $push; and index-based edits are position-fragile (prefer $apply for id-based changes). If the merged value is not an array, WorkList falls back to the defaults. Currently only applies when workList.variant is 'default'. |
| Default Value | StudyList.defaultColumns |
| Example | |
workList.renderPreviewContent
| ID | workList.renderPreviewContent |
|---|---|
| Description | Render function for the preview panel content. Receives the host React and { study, series, seriesView, onThumbnailImageError } — the same data the built-in renderer uses, with series and thumbnails already fetched by the SidePanelPreview shell.
<StudyList.PreviewContainer> layout is used. Currently only applies when workList.variant is 'default'. |
| Default Value | undefined |
| Example | |
workList.settingsMenuItems
| ID | workList.settingsMenuItems |
|---|---|
| Description | Builds the items in the WorkList settings popover (the gear menu in the top right). The customization is a function that receives the default items and must return a SettingsMenuItem[] (each { id, label, onClick }). The defaults are about, userPreferences, and (when appConfig.oidc is configured) logout. Use it to reorder, remove, or insert items without rebuilding the popover shell. If the customization returns a non-array value, WorkList falls back to the defaults. Currently only applies when workList.variant is 'default'. |
| Default Value | (defaults) => defaults |
| Example | |