Skip to content

Explorer hooks for plugins: context-menu contributor, thumbnail badges, DICOMweb origin of a study - #950

Open
nroduit wants to merge 3 commits into
masterfrom
ups-explorer-hooks
Open

nroduit wants to merge 3 commits into
masterfrom
ups-explorer-hooks

Conversation

@nroduit

@nroduit nroduit commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Three small core extension points so a plugin can integrate in the DICOM explorer without patching it. First consumer: the UPS-RS User Agent of discussion #925 (phase 2 of PR #944, the "AI tasks" submenu and the pending-task badge).

What is added

  1. Series context-menu contributor (weasis-dicom-explorer): ExplorerMenuContributor service, ExplorerMenuContributors registry. The thumbnail popup asks the contributors after its built-in items, below a separator added only when something was contributed; a contributor that throws is logged and skipped. There is no study-level menu by design: the series knows its study through the model, as "Remove study" already does.
  2. Thumbnail badge provider (weasis-core): SeriesBadgeProvider services, listed in UICore.getSeriesBadgeProviders(), merged by SeriesThumbnail after the PR / KO / SEG icons, without duplicates. Two icons for the AI workflow, OtherIcon.AI_TASK (task pending) and OtherIcon.AI_RESULT (results ready), in the shared resources since badges resolve from weasis.resources.path.
  3. DICOMweb origin of a study (weasis-dicom-explorer, weasis-dicom-qr): DicomWebOrigin (base URL, authentication method uid, node id) under TagW.DicomWebOrigin, written by $dicom:rs, the WADO-RS manifests and the DICOMweb retrieve of the Q/R dialog. The $dicom:rs path kept an empty base URL in the series WadoParameters, so a plugin had no way to know which server to ask. The record can be recovered from a series, matched back to a configured DicomWebNode (by id, else longest URL prefix) and gives WADO-RS study / series / instance URLs. Also needed by the FHIR viewer evaluation.

The registries and the record carry no OSGi import; only the two activators track services, so the port to the 5.0 plugin framework is the registration only.

Validation

  • New tests: ExplorerMenuContributorsTest, SeriesBadgeProviderTest, DicomWebOriginTest.
  • Full suites of weasis-core (1162), weasis-dicom-explorer (173) and weasis-dicom-qr (31) green; full reactor build green.
  • Menu and badges checked in the running application with a throwaway bundle implementing both services (not included).
  • Not yet exercised against a live DICOMweb server: the origin tag has unit-test coverage only.

ExplorerMenuContributor is the extension point, ExplorerMenuContributors
the registry (no framework import, so the pf4j port only changes who
registers). The popup of the DICOM explorer asks the contributors after
its built-in items, below a separator added only when something was
contributed; a failing contributor is logged and skipped. The explorer
activator tracks the registered services.

First consumer: the UPS-RS "AI tasks" submenu (discussion #925, PR #944).
SeriesBadgeProvider services, tracked by the core activator into
UICore.getSeriesBadgeProviders(), are consulted by SeriesThumbnail when it
paints the special-element icons: their icons follow the PR/KO/SEG ones,
without duplicates, and a failing provider never blanks a thumbnail.

Two badges for the AI workflow (OtherIcon.AI_TASK and AI_RESULT): a task
is pending on the study, or its results are ready to open. They live in
the shared resources because badges resolve from weasis.resources.path.
A study loaded through DICOMweb kept no trace of its server: the dicom:rs
path stores an empty base URL in the series WadoParameters and keeps the
real one in the query properties. DicomWebOrigin (base URL, authentication
method uid, node id) is now written under TagW.DicomWebOrigin by dicom:rs,
the WADO-RS manifests and the DICOMweb retrieve of the Q/R dialog; the
first origin of a study wins. It can be recovered from a series, matched
back to a configured DicomWebNode (by id, else longest URL prefix) and
gives the WADO-RS study, series and instance URLs.

Needed by the UPS-RS plugin (workitems of the study's server, Input
Information Sequence) and by the FHIR viewer evaluation.
@clicker71

Copy link
Copy Markdown

Thanks for the explorer hooks - exactly the three extension points phase 2 needs (context-menu contributor, thumbnail badges, DICOMweb origin).

Here is how we see phase 2 on top of them: Clarus as the origin, clinfer as the performer, one patient XRV-DEMO with a chest study (AI applies) and a knee study (it does not).

1. Availability. The badge is an availability indicator, not decoration: only the chest series carries it, because the catalogue task targets *lung* and the knee series has no matching BodyPartExamined. In the mergeable build this maps to AI_TASK / AI_RESULT through SeriesBadgeProvider.

Badge on the chest series, none on the knee

2. Done. Run (Create, RAD-80) -> clinfer claims -> COMPLETED. The badge flips to the result state, and "Show tasks" names the derived object by its own SOP Class UID (Secondary Capture), not a hard-coded one.

Done with the result named

3. Cancel. While a task is queued or running, the menu offers Cancel (Request Cancellation, 11.8).

Cancel while pending

Two questions on the menu behaviour:

  • After COMPLETED, "Run" stays enabled (Create-if-none allows a re-run). Should the menu grey the entry once the task has a completed workitem, or keep it re-runnable? Today we disable it only while SCHEDULED / IN PROGRESS.
  • The dialog lists each result as plain text. We would rather render it as a clickable entry that loads the object (image / SR / SEG) through the WADO-RS path - the performer already names the Series Instance UID (0020,000E) in the Output Information Sequence, so a direct retrieve URL is buildable. Is that the direction you want?

The workitem codes are minted under the private scheme 99CLARUS (PS3.3 Table 8.8-1) - the deployment vocabulary, not part of Weasis.

@nroduit

nroduit commented Oct 17, 2026

Copy link
Copy Markdown
Owner Author

Thanks, this is close to the target. Two principles first, then some suggestions. I have not tested the plugin against a real Task Manager and performer, so take the five points below as proposals to discuss, not as review requests; you know the Clarus and clinfer behaviour better than I do.

The plugin implements the IHE AIW-I roles as they are written: Weasis is the Task Requestor (Create UPS Workitem, RAD-80) grouped with a Watcher (Manage Subscription RAD-86, Open Event Channel RAD-109, Get Workitem RAD-83). Everything the UI shows should come from the workitem itself, Procedure Step State, Scheduled Workitem Code Sequence, Input and Output Information Sequences, so that the same menu works with any Task Manager and any performer. Deployment choices stay in the per-node catalog, which is what RAD-80 asks of a requestor ("sites configure the codes"); nothing in the plugin should need to know about a vendor, a modality or a body part.

  1. Run after COMPLETED could stay enabled. As I read Create-if-none, it should suppress a Create only while a non-terminal workitem with the same code and the same input set exists. A completed task is history: the Ready row keeps showing its result until it is opened, and Run creates a new workitem. Does that match what your Task Manager does?
  2. Results: opening them through the standard path seems the simplest. The Output Information Sequence names the series; build RsQueryParams from the DicomWebOrigin of the study (base URL and auth method uid, PR Explorer hooks for plugins: context-menu contributor, thumbnail badges, DICOMweb origin of a study #950) with that Series Instance UID and run it on DicomModel.LOADING_EXECUTOR, the same path as $dicom:rs. No retrieve URL assembled by hand, and the loaded SEG, SR or SC series then gets its own thumbnail and badges. Showing the SOP Class name rather than the UID would help the user.
  3. I would keep the badge for the workitem state, not for availability. Nothing drawn unless the worklist says there is something to do: AI_TASK while a workitem is SCHEDULED or IN PROGRESS, AI_RESULT when a completed one has outputs not yet loaded, nothing otherwise. A lung match on BodyPartExamined is a deployment rule; if a site wants it, it could be an applicability filter in the catalog entry that decides whether a Run entry is listed, rather than something on the thumbnail. What is the orange dot at the top-left of the thumbnail?
  4. State in the menu rows might replace the dialog. One row per workitem, labelled by Code Meaning: Queued: ‹meaning› › Cancel (Request Cancellation, 11.8), Running: ‹meaning›, Ready: ‹meaning› › Open results, with the value^scheme form in a tooltip. With the subscription and the event channel in the service, "Refresh" should become unnecessary; "Show tasks" may still be useful if it shows something the rows cannot.
  5. Input scope. Run could offer "On the whole study" and "On the selected series (n of m)", the selection of the popup being the Input Information Sequence. That is also why Create-if-none would compare the input set.

On the hooks and the roadmap: PR #950 is a minimal implementation, enough for this submenu and the badge on the current master, and I do not plan to extend it further.

Weasis 5 brings big changes in the architecture (pf4j extension points, command-first design) and in the explorer UI (see #947: modes by context, smart filters, objects as items), and the AI tasks integration will be designed against that explorer, not against the current popup. So I would rather focus on the final integration in Weasis 5 (#947) than refine the master version. The interfaces of #950 remain the contract: the service, the catalog and the menu logic of your plugin carry over as they are, and the port will be limited to the registration class and the command class.

@clicker71

Copy link
Copy Markdown

Dear Nicolas,

Thank you for the review. The two principles settle the architecture, and they
are exactly the correction I needed:

  1. The UI reads the workitem only (Procedure Step State, Scheduled Workitem
    Code Sequence, Input and Output Information Sequences), so the same menu
    works against any Task Manager and any performer.
  2. Deployment stays in the per-node catalog; the plugin knows nothing about a
    vendor, a modality or a body part.

Here is where I land on each point, and the one place Clarus differs from
what you read.

Badge: workitem state, not availability

Agreed. The availability badge (and the body-part check behind it) came out of
the demo's "available / running / done" framing, and it is the wrong layer: the
Requester must not replicate the Performer's applicability rules. I drop it.
The badge becomes:

  • AI_TASK while a workitem is SCHEDULED or IN PROGRESS;
  • AI_RESULT when a COMPLETED workitem has outputs not yet loaded;
  • nothing otherwise.

The body-part rule moves to the catalog as an applicability filter that decides
whether a "Run" entry is listed - a deployment rule, not plugin logic.

Run after COMPLETED, and create-if-none

Your reading matches Clarus: a completed task is history, and Run creates a new
workitem. I disable Run only while a non-terminal workitem of that code exists.

On create-if-none, to be precise because you asked: Clarus keys it on the Study
Instance UID (from the Referenced Request Sequence) and the code, not on the
full Input Information Sequence. PS3.4 Table CC.2.5-3 types the Referenced
Request Sequence as a Required matching key and the Input Information Sequence
as an Optional one. The reference implementation (dcm4chee-arc 5.35.2) behaves
identically: it filters by ReferencedRequestSequence.StudyInstanceUID and the
code, and ignores the input set. So the current behaviour is conformant, not a
bug.

My recommendation is to leave input-set comparison out of the baseline
contract. The workitem identity is the request - the code and the Referenced
Request Sequence - not the data it processes. At study scope the RRS already
names the study, so adding the input set risks false duplicates when inputs are
enumerated at different granularities. Only if Weasis 5 adopts a series-scope
model would input-set comparison be required - and then it is a small addition
on my side, not a fix.

Results: the standard path

Agreed. Build RsQueryParams from the study's DicomWebOrigin (base URL + auth
method UID) with the Series Instance UID from the Output Information Sequence,
and run it on DicomModel.LOADING_EXECUTOR - no hand-assembled retrieve URL. The
performer (clinfer) already writes the Series Instance UID (0020,000E) into the
Output Information Sequence, so the series is named and loadable. I will also
show the SOP Class name rather than the UID.

Menu rows instead of the dialog

Agreed. One row per workitem, labelled by Code Meaning: Queued / Running /
Ready with the matching action (Cancel, Open results), and value^scheme in a
tooltip. With the subscription and event channel in the service, Refresh goes
away; I will keep "Show tasks" only if it can surface something the rows
cannot.

Input scope

I will add the two scopes (whole study / selected series), with the selection
stored in the Input Information Sequence so each workitem records what it
processed. For the baseline, create-if-none remains keyed on the code and the
RRS Study Instance UID. Input-set comparison will be introduced only if the
series-scope model requires it.

Weasis 5 and #950

Understood: #950 stays a minimal contract and you will not extend it; the final
integration is designed against the Weasis 5 explorer (#947), with pf4j
extension points (#951). I will not refine the master popup. The service,
catalog and menu logic carry over as-is; the port is limited to the registration
class and the command class.

Two questions so I can plan that port:

  1. When do you expect Redesign DICOM explorer #947 (explorer) and Replace the OSGi framework (Apache Felix) with pf4j #951 (pf4j) to be in a buildable
    state (milestone 5.0.0)?
  2. Will the Explorer hooks for plugins: context-menu contributor, thumbnail badges, DICOMweb origin of a study #950 interfaces (SeriesBadgeProvider, ExplorerMenuContributor,
    DicomWebOrigin) be exposed as pf4j extension points in 5.0, or will their
    shape change?

I am not blocked by the 5.0 release date - the #950 master implementation is
stable and can stay there until the branch is ready. There is no time pressure
from my side: Clarus is my primary work and the Weasis integration is one
track among several, so please take whatever timeline suits your review flow.

The orange dot

You asked about the orange dot at the top-left of the thumbnail. That is
Weasis's own indicator that the series is open in a viewer - yellow when the
series is the selected, focused one, green otherwise (SeriesThumbnail
.drawOverIcon in weasis-core). It is not part of my plugin; my badge is drawn
at the bottom-right, and with the badge correction above it will show only the
workitem state.

Best regards,
Daniil

@nroduit

nroduit commented Oct 20, 2026

Copy link
Copy Markdown
Owner Author

Thanks for the feedback.

  1. Yes, I think this should be after the 4.8.0 release. A preview should be available before the end of the year.
  2. For the second point, I agree that the main change is more in the UI integration than in the underlying API itself. The important part is how it is exposed and integrated in the explorer UI, rather than the core functionality itself.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants