# Technical Documentation: OHIF/Viewers

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/OHIF/Viewers)

### Overview (README.md)

<div align="center">
  <h1>OHIF Medical Imaging Viewer</h1>
  <p><strong>The OHIF Viewer</strong> is a zero-footprint medical image viewer
provided by the <a href="https://ohif.org/">Open Health Imaging Foundation (OHIF)</a>. It is a configurable and extensible progressive web application with out-of-the-box support for image archives which support <a href="https://www.dicomstandard.org/using/dicomweb/">DICOMweb</a>.</p>
</div>


<div align="center">
  <a href="https://docs.ohif.org/"><strong>Read The Docs</strong></a>
</div>
<div align="center">
  <a href="https://viewer.ohif.org/">Live Demo</a> |
  <a href="https://ui.ohif.org/">Component Library</a>
</div>
<div align="center">
  📰 <a href="https://ohif.org/news/"><strong>Join OHIF Newsletter</strong></a> 📰
</div>
<div align="center">
  📰 <a href="https://ohif.org/news/"><strong>Join OHIF Newsletter</strong></a> 📰
</div>



<hr />

[![NPM version][npm-version-image]][npm-url]
[![MIT License][license-image]][license-url]
[











|     |  | |
| :-: | :---  | :--- |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-measurements.webp?raw=true" alt="Measurement tracking" width="350"/> | Measurement Tracking | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-segmentation.webp?raw=true" alt="Segmentations" width="350"/> | Labelmap Segmentations  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-ptct.webp?raw=true" alt="Hanging Protocols" width="350"/> | Fusion and Custom Hanging protocols  | [Demo](https://viewer.ohif.org/tmtv?StudyInstanceUIDs=1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-volume-rendering.webp?raw=true" alt="Volume Rendering" width="350"/> | Volume Rendering  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&hangingprotocolId=mprAnd3DVolumeViewport) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-pdf.webp?raw=true" alt="PDF" width="350"/> | PDF  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.317377619501274872606137091638706705333) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-rtstruct.webp?raw=true" alt="RTSTRUCT" width="350"/> | RT STRUCT  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.5962.99.1.2968617883.1314880426.1493322302363.3.0) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-4d.webp?raw=true" alt="4D" width="350"/> | 4D  | [Demo](https://viewer.ohif.org/dynamic-volume?StudyInstanceUIDs=2.25.232704420736447710317909004159492840763) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-video.webp?raw=true" alt="VIDEO" width="350"/> | Video  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.96975534054447904995905761963464388233) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/microscopy.webp?raw=true" alt="microscopy" width="350"/> | Slide Microscopy  | [Demo](https://viewer.ohif.org/microscopy?StudyInstanceUIDs=2.25.141277760791347900862109212450152067508) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-ecg.webp?raw=true" alt="ECG" width="350"/> | ECG Waveform  | [Demo](https://viewer-dev.ohif.org/viewer?StudyInstanceUIDs=2.25.209974489360710696739324151261716440238) |

## About

The OHIF Viewer can retrieve
and load images from most sources and formats, render sets in 2D, 3D, and
reconstructed representations; allows for the manipulation, annotation, and
serialization of observations; supports internationalization, OpenID Connect,
offline use, hotkeys, and many more features.

Almost everything offers some degree of customization and configuration. If it
doesn't support something you need, we accept pull requests and have an ever
improving Extension System.

## Why Choose Us

### Community & Experience

The OHIF Viewer is a collaborative effort that has served as the basis for many
active, production, and FDA Cleared medical imaging viewers. It benefits from
our extensive community's collective experience, and from the sponsored
contributions of individuals, research groups, and commercial organizations.

### Built to Adapt

After more than 8-years of integrating with many companies and organizations,
The OHIF Viewer has been rebuilt from the ground up to better address the
varying workflow and configuration needs of its many users. All of the Viewer's
core features are built using its own extension system. The same extensibility
that allows us to offer:

- 2D and 3D medical image viewing
- Multiplanar Reconstruction (MPR)
- Maximum Intensity Project (MIP)
- Whole slide microscopy viewing
- PDF and Dicom Structured Report rendering
- Segmentation rendering as labelmaps and contours
- User Access Control (UAC)
- Context specific toolbar and side panel content
- and many others

Can be leveraged by you to customize the viewer for your workflow, and to add
any new functionality you may need (and wish to maintain privately without
forking).

### Support

- [Report a Bug 🐛](https://github.com/OHIF/Viewers/issues/new?assignees=&labels=Community%3A+Report+%3Abug%3A%2CAwaiting+Reproduction&projects=&template=bug-report.yml&title=%5BBug%5D+)
- [Request a Feature 🚀](https://github.com/OHIF/Viewers/issues/new?assignees=&labels=Community%3A+Request+%3Ahand%3A&projects=&template=feature-request.yml&title=%5BFeature+Request%5D+)
- [Ask a Question 🤗](community.ohif.org)
- [Slack Channel](https://join.slack.com/t/cornerstonejs/shared_invite/zt-1r8xb2zau-dOxlD6jit3TN0Uwf928w9Q)

For commercial support, academic collaborations, and answers to common
questions; please use [Get Support](https://ohif.org/get-support/) to contact
us.

## Developing

### Branches

#### `master` branch - The latest dev (beta) release

- `master` - The latest dev release

This is typically where the latest development happens. Code that is in the master branch has passed code reviews and automated tests, but it may not be deemed ready for production. This branch usually contains the most recent changes and features being worked on by the development team. It's often the starting point for creating feature branches (where new features are developed) and hotfix branches (for urgent fixes).

Each package is tagged with beta version numbers, and published to npm such as `@ohif/ui@3.6.0-beta.1`

### `release/*` branches - The latest stable releases
Once the `master` branch code reaches a stable, release-ready state, we conduct a comprehensive code review and QA testing. Upon approval, we create a new release branch from `master`. These branches represent the latest stable version considered ready for production.

For example, `release/3.5` is the branch for version 3.5.0, and `release/3.6` is for version 3.6.0. After each release, we wait a few days to ensure no critical bugs. If any are found, we fix them in the release branch and create a new release with a minor version bump, e.g., 3.5.1 in the `release/3.5` branch.

Each package is tagged with version numbers and published to npm, such as `@ohif/ui@3.5.0`. Note that `master` is always ahead of the `release` branch. We publish docker builds for both beta and stable releases.

Here is a schematic representation of our development workflow:







### Requirements

- [Yarn 1.20.0+](https://yarnpkg.com/en/docs/install)
- [Node 18+](https://nodejs.org/en/)
- Yarn Workspaces should be enabled on your machine:
  - `yarn config set workspaces-experimental true`

### Getting Started

1. [Fork this repository][how-to-fork]
2. [Clone your forked repository][how-to-clone]
   - `git clone https://github.com/YOUR-USERNAME/Viewers.git`
3. Navigate to the cloned project's directory
4. Add this repo as a `remote` named `upstream`
   - `git remote add upstream https://github.com/OHIF/Viewers.git`
5. `yarn install --frozen-lockfile` to restore dependencies and link projects

:::danger
In general run `yarn install` with the `--frozen-lockfile` flag to help avoid
supply chain attacks by enforcing reproducible dependencies. That is, if the
`yarn.lock` file is clean and does NOT reference compromised packages, then
no compromised packages should land on your machine by using this flag.
:::

#### To Develop

_From this repository's root directory:_

```bash
# Enable Yarn Workspaces
yarn config set workspaces-experimental true

# Restore dependencies
yarn install --frozen-lockfile
```

### Cornerstone3D Integration Testing

OHIF's Playwright end-to-end tests can run against a **CS3D branch** or a
**published CS3D version**, allowing changes that span both repositories to be
validated together before merging.

#### Setting up an integration build

Add a `CS3D_REF:` line to the PR body. No label is involved — the line itself is
the request.

The line must sit at the top level of the body. A line inside a fenced code
block, inside an indented code block (four spaces or more), or inside an HTML
comment is an example rather than a request, so you can document this syntax in
a PR without triggering it. The PR template is mostly HTML comments, so write
the line outside them. The workflow prints a warning when it ignores a
`CS3D_REF:` line for one of these reasons, and it fails when the block that
hides the line is never closed.

```
CS3D_REF: feat/my-feature
```

The line takes one of three forms:

| Form | Meaning |
|------|---------|
| `CS3D_REF: feat/my-feature` | A branch or tag in `cornerstonejs/cornerstone3D`. The workflow clones it, builds CS3D from source with `pnpm run build:esm`, and symlinks the built packages into OHIF's `node_modules`. |
| `CS3D_REF: 5.10.6` | A published version. The workflow rewrites every `@cornerstonejs/*` entry across the workspace to that version and reinstalls. The accepted forms are `5.10.6`, `5.11.0-beta.1`, `5.x`, `5.10.x` and `4.19+`. A two-part number such as `5.10` is not one of them; write `5.10.x`. |
| `CS3D_REF: feat/my-feature now 5.10.6` | The branch, and the concrete release it became. See [Retiring a branch ref](#retiring-a-branch-ref) below. |

Three rules are worth knowing:

- **The branch must live in `cornerstonejs/cornerstone3D`.** The
  `<owner>:<branch>` form is no longer accepted: it let a PR point the clone at
  any GitHub account and run that account's install scripts on the shared
  self-hosted runner. Push your branch to the CS3D repository instead.
- **There is no default.** A PR with no `CS3D_REF` line runs the ordinary
  Playwright suite against the CS3D version this repo already pins. The same
  holds for a manual run with an empty `cs3d_ref` box.
- **From a fork, an integration run needs approval.** The run waits on the
  `cs3d-integration` environment until one of the named reviewers approves that
  specific run, because it builds and executes CS3D code on a shared machine.
  A PR from a branch in this repository proceeds unattended.

The workflow can also be triggered manually via **workflow_dispatch** with a
`cs3d_ref` input, which accepts the same three forms.

#### What happens in CI

The [Playwright workflow](.github/workflows/playwright.yml) runs three jobs:

| Job | Purpose |
|-----|---------|
| **Gate** | Runs on GitHub's own runners and never checks out the repository. It decides whether the PR may reach the self-hosted runner at all, reads and validates any `CS3D_REF` line, and decides whether the run needs a reviewer's approval. |
| **Playwright Tests** | Builds OHIF (with CS3D linked or version-swapped), runs the full Playwright suite, and uploads test results and coverage. When a `CS3D_REF` line changes the tree under test, it also deploys a Netlify preview. |
| **CS3D Branch Merge Guard** | Reports when `CS3D_REF` names a branch rather than a published version, because merging would leave `master` depending on unreleased CS3D code. It is **advisory**: it reports a red result, but it does not block the merge button. |

#### Playwright does not run on every fork PR

A PR from a fork that changes a CI-defining file does not run Playwright on the
self-hosted runner. It runs once the change is reviewed and merged. The affected
paths are `.github/`, `.scripts/`, `pnpm-workspace.yaml`, `preinstall.js`, any
root pnpmfile, and **every** `.npmrc` in the workspace, not only the one in the
root directory.

`package.json` and `pnpm-lock.yaml` are not on the list, so a fork PR that adds
a dependency or moves a module between workspace packages runs Playwright as
usual. Changes to the root `package.json` and `pnpm-lock.yaml` still need a code
owner's review before merge. A PR from a branch in this repository is not
affected by either rule.

#### Testing changes that span both repos

If a feature requires changes in both Cornerstone3D and OHIF:

1. Create your feature branch in the `cornerstonejs/cornerstone3D` repository and
   push it.
2. Create a matching branch in OHIF.
3. In the PR body, add: `CS3D_REF: <your-cs3d-branch>`.
4. Playwright tests build CS3D from source, link it, and run the full suite. The
   merge guard reports a red result for as long as the line names a branch, so
   you can see the test results and the preview deploy while you iterate.
5. Once the CS3D side is merged and published, change the line to the retiring
   form below.

#### Retiring a branch ref

Once the CS3D fix ships, change the line rather than deleting it:

```
CS3D_REF: feat/my-feature now 5.10.6
```

The version after `now` is a **record, not a request**. It never moves the pin
backwards: on every run the workflow compares it against the version this repo
pins and keeps whichever is newer. So a line still saying `now 5.10.6` in a repo
that has moved on to 5.11.0 tests 5.11.0, not 5.10.6.

That is what lets the line stay in place as history — the branch name remains
visible as the reason the pinned version moved, and the line stops changing what
the run does. Once the repo pins that version or something newer, no rewrite
happens, no reinstall happens, and no preview is built or deployed. The version
must be one concrete release, such as `5.10.6` or `5.11.0-beta.1`, not a range.

A fork PR still asks for the `cs3d-integration` approval while the line is
present, even after the line is spent, because the gate has no checkout and
cannot tell which version the repo pins. Delete the line to stop the prompt.

#### Preview deploys

When a `CS3D_REF` line changes the tree under test, the Playwright workflow also
builds the OHIF viewer and deploys it to Netlify as a preview. This gives you a
live URL to manually test the combined CS3D + OHIF changes without running
anything locally. A spent retiring form tests the same tree as an ordinary run,
so it does not produce a preview.

For details on linking CS3D locally for development, see the
[Cornerstone3D README](libs/@cornerstonejs/README.md#local-development-linking--unlinking).

## Commands

These commands are available from the root directory. Each project directory
also supports a number of commands that can be found in their respective
`README.md` and `package.json` files.

| Yarn Commands                | Description                                                   |
| ---------------------------- | ------------------------------------------------------------- |
| **Develop**                  |                                                               |
| `dev`              | Default development experience for Viewer                     |
| `dev:fast`             | Our experimental fast dev mode that uses rsbuild instead of webpack                     |
| `test:unit`                  | Jest multi-project test runner; overall coverage              |
| **Deploy**                   |                                                               |
| `build`\*                    | Builds production output for our PWA Viewer                   |  |

\* - For more information on different builds, check out our [Deploy
Docs][deployment-docs]

### Which config each command uses

The dev server and the production build select a different default
[configuration file][config-file] when `APP_CONFIG` is not set explicitly:

| Command                         | Default config       | Data sources | `?customization=` |
| ------------------------------- | -------------------- | ------------ | ----------------- |
| `dev`, `dev:fast`, `start`      | `config/dev.js`      | Full set     | Enabled           |
| `build`                         | `config/default.js`  | One demo source | Disabled       |

- **`config/dev.js`** is the full-featured local-development config: every data
  source is enabled, the `?customization=` URL feature is turned on (via
  `customizationUrlPrefixes`), and it is kept at parity with the public demo
  (`config/netlify.js`) so customizations behave locally the same way they do on
  the demo.
- **`config/netlify.js`** is the public demo / Netlify deploy config
  (`build:viewer:ci`), with the same full data-source set and `?customization=`
  enabled.
- **`config/default.js`** is a locked-down baseline and is now **only** the
  default for a plain production build (`build` with no `APP_CONFIG`): a single
  read-only demo data source and `?customization=` off.

Any explicit `APP_CONFIG` overrides the default, e.g.
`APP_CONFIG=config/default.js pnpm run dev` or
`APP_CONFIG=config/netlify.js pnpm run build`.

## Project

The OHIF Medical Image Viewing Platform is maintained as a
[`monorepo`][monorepo]. This means that this repository, instead of containing a
single project, contains many projects. If you explore our project structure,
you'll see the following:

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Acknowledgments

To acknowledge the OHIF Viewer in an academic publication, please cite

> _Open Health Imaging Foundation Viewer: An Extensible Open-Source Framework
> for Building Web-Based Imaging Applications to Support Cancer Research_
>
> Erik Ziegler, Trinity Urban, Danny Brown, James Petts, Steve D. Pieper, Rob
> Lewis, Chris Hafey, and Gordon J. Harris
>
> _JCO Clinical Cancer Informatics_, no. 4 (2020), 336-345, DOI:
> [10.1200/CCI.19.00131](https://www.doi.org/10.1200/CCI.19.00131)
>
> Open-Access on Pubmed Central:
> https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7259879/

or, for v1, please cite:

> _LesionTracker: Extensible Open-Source Zero-Footprint Web Viewer for Cancer
> Imaging Research and Clinical Trials_
>
> Trinity Urban, Erik Ziegler, Rob Lewis, Chris Hafey, Cheryl Sadow, Annick D.
> Van den Abbeele and Gordon J. Harris
>
> _Cancer Research_, November 1 2017 (77) (21) e119-e122 DOI:
> [10.1158/0008-5472.CAN-17-0334](https://www.doi.org/10.1158/0008-5472.CAN-17-0334)

**Note:** If you use or find this repository helpful, please take the time to
star this repository on GitHub. This is an easy way for us to assess adoption
and it can help us obtain future funding for the project.

This work is supported primarily by the National Institutes of Health, National
Cancer Institute, Informatics Technology for Cancer Research (ITCR) program,
under a
[grant to Dr. Gordon Harris at Massachusetts General Hospital (U24 CA199460)](https://projectreporter.nih.gov/project_info_description.cfm?aid=8971104).

[NCI Imaging Data Commons (IDC) project](https://imaging.datacommons.cancer.gov/) supported the development of new features and bug fixes marked with ["IDC:priority"](https://github.com/OHIF/Viewers/issues?q=is%3Aissue+is%3Aopen+label%3AIDC%3Apriority),
["IDC:candidate"](https://github.com/OHIF/Viewers/issues?q=is%3Aissue+is%3Aopen+label%3AIDC%3Acandidate) or ["IDC:collaboration"](https://github.com/OHIF/Viewers/issues?q=is%3Aissue+is%3Aopen+label%3AIDC%3Acollaboration). NCI Imaging Data Commons is supported by contract number 19X037Q from
Leidos Biomedical Research under Task Order HHSN26100071 from NCI. [IDC Viewer](https://learn.canceridc.dev/portal/visualization) is a customized version of the OHIF Viewer.

This project is tested with BrowserStack. Thank you for supporting open-source!

## License

MIT © [OHIF](https://github.com/OHIF)





[lerna-image]: https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg
[lerna-url]: https://lerna.js.org/
[netlify-image]: https://api.netlify.com/api/v1/badges/32708787-c9b0-4634-b50f-7ca41952da77/deploy-status
[netlify-url]: https://app.netlify.com/sites/ohif-dev/deploys
[all-contributors-image]: https://img.shields.io/badge/all_contributors-0-orange.svg?style=flat-square
[circleci-image]: https://circleci.com/gh/OHIF/Viewers.svg?style=svg
[circleci-url]: https://circleci.com/gh/OHIF/Viewers
[codecov-image]: https://codecov.io/gh/OHIF/Viewers/branch/master/graph/badge.svg
[codecov-url]: https://codecov.io/gh/OHIF/Viewers/branch/master
[prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square
[prettier-url]: https://github.com/prettier/prettier
[semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
[semantic-url]: https://github.com/semantic-release/semantic-release

[npm-url]: https://npmjs.org/package/@ohif/app
[npm-downloads-image]: https://img.shields.io/npm/dm/@ohif/app.svg?style=flat-square
[npm-version-image]: https://img.shields.io/npm/v/@ohif/app.svg?style=flat-square
[docker-pulls-img]: https://img.shields.io/docker/pulls/ohif/viewer.svg?style=flat-square
[docker-image-url]: https://hub.docker.com/r/ohif/app
[license-image]: https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square
[license-url]: LICENSE
[percy-image]: https://percy.io/static/images/percy-badge.svg
[percy-url]: https://percy.io/Open-Health-Imaging-Foundation/OHIF-Viewer

[monorepo]: https://en.wikipedia.org/wiki/Monorepo
[how-to-fork]: https://help.github.com/en/articles/fork-a-repo
[how-to-clone]: https://help.github.com/en/articles/fork-a-repo#step-2-create-a-local-clone-of-your-fork
[ohif-architecture]: https://docs.ohif.org/architecture/index.html
[ohif-extensions]: https://docs.ohif.org/architecture/index.html
[deployment-docs]: https://docs.ohif.org/deployment/
[config-file]: https://docs.ohif.org/configuration/configurationFiles
[react-url]: https://reactjs.org/
[pwa-url]: https://developers.google.com/web/progressive-web-apps/
[ohif-viewer-url]: https://www.npmjs.com/package/@ohif/app
[configuration-url]: https://docs.ohif.org/configuring/
[extensions-url]: https://docs.ohif.org/extensions/

[platform-core]: platform/core/README.md
[core-npm]: https://www.npmjs.com/package/@ohif/core
[platform-i18n]: platform/i18n/README.md
[i18n-npm]: https://www.npmjs.com/package/@ohif/i18n
[platform-ui]: platform/ui/README.md
[ui-npm]: https://www.npmjs.com/package/@ohif/ui
[platform-viewer]: platform/app/README.md
[viewer-npm]: https://www.npmjs.com/package/@ohif/app

[extension-cornerstone]: extensions/cornerstone/README.md
[cornerstone-npm]: https://www.npmjs.com/package/@ohif/extension-cornerstone
[extension-dicom-html]: extensions/dicom-html/README.md
[html-npm]: https://www.npmjs.com/package/@ohif/extension-dicom-html
[extension-dicom-microscopy]: extensions/dicom-microscopy/README.md
[microscopy-npm]: https://www.npmjs.com/package/@ohif/extension-dicom-microscopy
[extension-dicom-pdf]: extensions/dicom-pdf/README.md
[pdf-npm]: https://www.npmjs.com/package/@ohif/extension-dicom-pdf
[extension-vtk]: extensions/vtk/README.md
[vtk-npm]: https://www.npmjs.com/package/@ohif/extension-vtk


[](https://app.fossa.com/projects/git%2Bgithub.com%2FOHIF%2FViewers?ref=badge_large&issueType=license)

---

### Platform Docs README (`platform/docs/README.md`)

# Website

This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.

## Installation

```console
yarn install --frozen-lockfile
```

## Local Development

```console
yarn start
```

This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.

## Build

```console
yarn build
```

This command generates static content into the `build` directory and can be served using any static contents hosting service.

## Deployment

```console
GIT_USER=<Your GitHub username> USE_SSH=true yarn deploy
```

If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.

---

### Platform Docs Docs README (`platform/docs/docs/README.md`)

---
id: Introduction
slug: /
sidebar_position: 1
---

The [Open Health Imaging Foundation][ohif-org] (OHIF) Viewer is an open source,
web-based, medical imaging platform. It aims to provide a core framework for
building complex imaging applications.

Key features:

- Designed to load large radiology studies as quickly as possible. Retrieves
  metadata ahead of time and streams in imaging pixel data as needed.
- Leverages [Cornerstone3D](https://github.com/cornerstonejs/cornerstone3D-beta) for decoding,
  rendering, and annotating medical images.
- Works out-of-the-box with Image Archives that support [DICOMWeb][dicom-web].
  Offers a Data Source API for communicating with archives over proprietary API
  formats.
- Provides a plugin framework for creating task-based workflow modes which can
  reuse core functionality.
- Beautiful user interface (UI) designed with extensibility in mind. UI
  components available in a reusable component library built with React.js and
  Tailwind CSS


<div style={{ textAlign: 'center' }}>
    <div style={{ display: 'flex', gap: '1rem', justifyContent: 'center' }}>
        <a style={{
            backgroundColor: '#4042af',
            color: 'white',
            padding: '0.5rem 1rem',
            borderRadius: '0.25rem',
            textDecoration: 'none',
            ':hover': {
                backgroundColor: '#2a2b74'
            }
        }} href="https://ohif.org/news/">Subscribe to our newsletter</a>
        <a style={{
            backgroundColor: '#4042af',
            color: 'white',
            padding: '0.5rem 1rem',
            borderRadius: '0.25rem',
            textDecoration: 'none',
            ':hover': {
                backgroundColor: '#2a2b74'
            }
        }} href="./release-notes">Release Notes</a>
    </div>
</div>

<br/>
<br/>



|     |  | |
| :-: | :---  | :--- |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-measurements.webp?raw=true" alt="Measurement tracking" width="350"/> | Measurement Tracking | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-segmentation.webp?raw=true" alt="Segmentations" width="350"/> | Labelmap Segmentations  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-ptct.webp?raw=true" alt="Hanging Protocols" width="350"/> | Fusion and Custom Hanging protocols  | [Demo](https://viewer.ohif.org/tmtv?StudyInstanceUIDs=1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-volume-rendering.webp?raw=true" alt="Volume Rendering" width="350"/> | Volume Rendering  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&hangingprotocolId=mprAnd3DVolumeViewport) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-pdf.webp?raw=true" alt="PDF" width="350"/> | PDF  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.317377619501274872606137091638706705333) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-rtstruct.webp?raw=true" alt="RTSTRUCT" width="350"/> | RT STRUCT  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.5962.99.1.2968617883.1314880426.1493322302363.3.0) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-4d.webp?raw=true" alt="4D" width="350"/> | 4D  | [Demo](https://viewer.ohif.org/dynamic-volume?StudyInstanceUIDs=2.25.232704420736447710317909004159492840763) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-video.webp?raw=true" alt="VIDEO" width="350"/> | Video  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.96975534054447904995905761963464388233) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/microscopy.webp?raw=true" alt="microscopy" width="350"/> | Slide Microscopy  | [Demo](https://viewer.ohif.org/microscopy?StudyInstanceUIDs=2.25.141277760791347900862109212450152067508) |



## Where to next?

The Open Health Imaging Foundation intends to provide an imaging viewer
framework which can be easily extended for specific uses. If you find yourself
unable to extend the viewer for your purposes, please reach out via our [GitHub
issues][gh-issues]. We are actively seeking feedback on ways to improve our
integration and extension points.

Check out these helpful links:

- Ready to dive into some code? Check out our
  [Getting Started Guide](./development/getting-started.md).
- We're an active, vibrant community.
  [Learn how you can be more involved.](./development/contributing.md)
- Feeling lost? Read our [help page](/help).

## Citing OHIF

To cite the OHIF Viewer in an academic publication, please cite

> _Open Health Imaging Foundation Viewer: An Extensible Open-Source Framework
> for Building Web-Based Imaging Applications to Support Cancer Research_
>
>  Erik Ziegler, Trinity Urban, Danny Brown, James Petts, Steve D. Pieper, Rob
> Lewis, Chris Hafey, and Gordon J. Harris _JCO Clinical Cancer Informatics_, no. 4 (2020), 336-345, DOI:
> [10.1200/CCI.19.00131](https://www.doi.org/10.1200/CCI.19.00131)

This article is freely available on Pubmed Central: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7259879/


or, for Lesion Tracker of OHIF v1, please cite:

> _LesionTracker: Extensible Open-Source Zero-Footprint Web Viewer for Cancer
> Imaging Research and Clinical Trials_
>
> Trinity Urban, Erik Ziegler, Rob Lewis, Chris Hafey, Cheryl Sadow, Annick D.
> Van den Abbeele and Gordon J. Harris _Cancer Research_, November 1 2017 (77) (21) e119-e122 DOI:
> [10.1158/0008-5472.CAN-17-0334](https://www.doi.org/10.1158/0008-5472.CAN-17-0334)

This article is freely available on Pubmed Central.
https://pubmed.ncbi.nlm.nih.gov/29092955/


**Note:** If you use or find this repository helpful, please take the time to
star this repository on Github. This is an easy way for us to assess adoption,
and it can help us obtain future funding for the project.

## License

MIT © [OHIF](https://github.com/OHIF)

&nbsp;




[ohif-org]: https://www.ohif.org
[ohif-demo]: http://viewer.ohif.org/
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
[gh-issues]: https://github.com/OHIF/Viewers/issues

---

### Platform Docs Scripts README (`platform/docs/scripts/README.md`)

# OHIF Viewer Documentation Scripts

This directory contains utility scripts for the OHIF Viewer documentation.

## prepare-markdown-files.js

This script copies all markdown files from the docs directory (excluding `api/` and `assets/`) to a `/llm` directory in the build output, making them available as static markdown files that can be accessed directly without the Docusaurus UI.

### Purpose

These files are made available for easy access by LLMs and other tools that need to retrieve the raw markdown content without the surrounding Docusaurus UI elements.

### Access URLs

After deployment, the markdown files can be accessed at URLs like:

- `https://docs.ohif.org/llm/platform/extensions/modules/commands.md`
- `https://docs.ohif.org/llm/platform/services/ui/index.md`

### Implementation

The script is automatically run as part of the `build:docs` command and will:

1. Find all markdown files in the `/platform/docs/docs/` directory (excluding api/ and assets/)
2. Copy them to `/platform/docs/build/llm/` preserving the directory structure
3. These files are then deployed to the website along with the rest of the built documentation

You can also run this script manually with:

```bash
cd platform/docs
yarn run prepare-markdown-files
```

## generate-llms-txt.js

This script generates a llms.txt file that follows the [llms.txt specification](https://llmstxt.site) by creating an index of all the markdown files that have been copied to the `/llm` directory.

### Purpose

The llms.txt file provides an overview of all available documentation in a format that's optimized for use with Large Language Models (LLMs). It creates a structured index that LLMs can use to efficiently navigate and find information in the documentation.

### Access URL

After deployment, the llms.txt file can be accessed at:

- `https://docs.ohif.org/llms.txt`

### Implementation

The script is automatically run as part of the `build:docs` command (after `prepare-markdown-files.js`) and will:

1. Scan all the markdown files that were copied to the `/llm` directory
2. Extract titles and summaries from the frontmatter of each file
3. Organize them into sections based on their directory structure
4. Generate a single llms.txt file in the standard format with links to all the documentation files
5. Save the file to the build directory root so it will be accessible at the root of the website

You can also run this script manually with (after running `prepare-markdown-files.js`):

```bash
cd platform/docs
yarn run generate-llms-txt
```

## generate-llms-full-txt.js

This script generates an llms-full.txt file by concatenating the content of all markdown files from the `/llm` directory into a single giant file, similar to the approach used by bun.sh.

### Purpose

The llms-full.txt file provides the complete content of all documentation in a single file, which can be useful for LLMs that need to search or reference the entire documentation at once. This approach allows for contextual understanding across multiple documentation pages.

### Access URL

After deployment, the llms-full.txt file can be accessed at:

- `https://docs.ohif.org/llms-full.txt`

### Implementation

The script is automatically run as part of the `build:docs` command (after `generate-llms-txt.js`) and will:

1. Scan all the markdown files that were copied to the `/llm` directory
2. Remove frontmatter from each file to clean up the content
3. Add clear section headers and source URLs for each file
4. Concatenate all the content into a single file with proper organization by section
5. Save the file to the build directory root so it will be accessible at the root of the website

The output file has the following structure:
- Title and introduction for OHIF Viewer
- Files are organized by their directory structure (e.g., platform, extensions, services)
- Each file has a header with its title and source URL
- Separator lines between files for clarity

You can also run this script manually with (after running `prepare-markdown-files.js`):

```bash
cd platform/docs
yarn run generate-llms-full-txt
```

---

### Platform Docs Docs Behaviours README (`platform/docs/docs/behaviours/README.md`)

---
id: README
title: Behaviours
sidebar_position: 0
---

# Behaviours

This section documents **how the system and UI actually behave** — the
end-to-end behaviours that emerge from the interaction of services, extensions,
the data source, and Cornerstone3D, rather than the API of any single module.

It is the place for:

- **Observed behaviours** — how a feature works today across the stack (e.g. how
  a DICOM SEG is fetched, decoded, and rendered; what the viewport does on study
  change; how measurements round-trip to SR).
- **Design proposals** — proposed or in-progress changes to a behaviour, captured
  before/while they are implemented so the intent and trade-offs are recorded.
  These are clearly marked as proposals until they land.
- **Edge cases and failure modes** — what happens when something is missing,
  slow, or malformed, and how the system is expected to degrade.

The goal is a durable, discoverable record of *behaviour* — the kind of
cross-cutting knowledge that is otherwise only in people's heads or scattered
across code comments. Prefer linking to the relevant source files (with line
references) so each behaviour doc stays anchored to the code it describes.

## Index

- [Segmentation: loading a multiframe SEG as a single Part 10 instance](./segmentation-multiframe-part10-prefetch.md)
  — _implemented, enabled by default_. Prefetch the whole instance in one request
  and register it into the Cornerstone3D NATURALIZED frame registry so the
  per-frame load path (WADO-RS and WADO-URI) is served locally, while keeping the
  standard decode path unchanged. Per-frame loading is the exception — disable
  via `loadMultiframeAsPart10: false` (data source config or the
  `cornerstone.segmentation.loadMultiframeAsPart10` customization).

- [Report dialog: where a save goes, and what the series is called](./report-dialog-save-destinations.md)
  — _implemented_. The three destinations of a save, the `predecessorImageId`
  rule that decides which loaded series the dialog offers, the four names that a
  new series starts from, and the descriptions that the viewer remembers.

## Writing a new behaviour doc

1. Add a `kebab-case.md` file in this directory.
2. State whether it documents **current behaviour** or is a **proposal**.
3. Link to the code (`path:line`) that implements or will implement it.
4. Add it to the **Index** above.

---

### Platform Docs Docs Deployment Index (`platform/docs/docs/deployment/index.md`)

---
sidebar_position: 1
sidebar_label: Overview
title: Deployment Overview
summary: Comprehensive guide to deploying the OHIF Viewer as a standalone web application or embedded iframe, covering data source configuration, security considerations, and various deployment options with examples for different hosting environments.
---

# Deployment

The OHIF Viewer can be served as a stand-alone PWA ([progressive web
application][pwa-url]) by building and hosting a collection of static assets or be embedded in other web applications via an iframe if needed. In
either case, you will need to configure your instance of the Viewer so that it
can connect to your data source (the database or PACS that provides the data
your Viewer will display).

:::tip
Our goal is to make deployment as simple and painless as possible; however,
there is an inherent amount of complexity in configuring and deploying web
applications. If you find yourself a little lost, please don't hesitate to
reach out to for help.
:::

## Deployment Scenarios

### Stand-alone Viewer

Deploying the OHIF Viewer as a stand-alone web application provides many
benefits, but comes at the cost of time and complexity. Some benefits include:

_Today:_

- Leverage [extensions](../platform/extensions/index.md) and
  [modes](../platform/modes/index.md) to drop-in powerful new features
- Add routes and customize the viewer's workflow
- Finer control over styling and whitelabeling

_In the future:_

- The ability to package the viewer for [App Store distribution][app-store]

#### Hosted Static Assets

At the end of the day, a production OHIF Viewer instance is a collection of
HTML, CSS, JS, Font Files, and Images. We "build" those files from our
`source code` with configuration specific to our project. We then make those
files publicly accessible by hosting them on a Web Server.

##### Part 1 - Build Production Assets

"Building", or creating, the files you will need is the same regardless of the
web host you choose. You can find detailed instructions on how to configure and
build the OHIF Viewer in our
["Build for Production" guide](./build-for-production.md).

##### Part 2 - Host Your App

There are a lot of [benefits to hosting static assets][host-static-assets] over
dynamic content. You can find instructions on how to host your build's output
via one of these guides:

_Drag-n-drop_

- [Netlify: Drop](./static-assets.md#netlify-drop)

_Easy_

- [Surge.sh](./static-assets.md#surgesh)
- [GitHub Pages](./static-assets.md#github-pages)

_Advanced_

- [AWS S3 + Cloudfront](./static-assets.md#aws-s3--cloudfront)
- [GCP + Cloudflare](./static-assets.md#gcp--cloudflare)
- [Azure](./static-assets.md#azure)

### Embedded Viewer (iframe)

`OHIF-v3` has deprecated deploying the viewer as an embedded viewer via a script
tag as the number of underlying libraries that run web workers are increasing for OHIF. An example of these libraries is OHIF's 3D rendering functionality that is provided by
`vtk-js`.

However, you can still embed the viewer using an iframe. You can utilize the iframe element to load the OHIF viewer and establish communication with it using the postMessage API if needed.
Read more about how to use the iframe [here](./iframe.md).


## Data

The OHIF Viewer is able to connect to any data source that implements the [DICOM
Web Standard][dicom-web-standard]. [DICOM Web][dicom-web] refers to RESTful
DICOM Services -- a recently standardized set of guidelines for exchanging
medical images and imaging metadata over the internet. Not all archives fully
support it yet, but it is gaining wider adoption.

### Configure Connection

If you have an existing archive and intend to host the OHIF Viewer at the same
domain name as your archive, then connecting the two is as simple as following
the steps laid out in our
[Configuration Essentials Guide](./../configuration/configurationFiles.md).

#### What if I don't have an imaging archive?

We provide some guidance on configuring a local image archive in our
[Data Source Essentials](./../configuration/dataSources/introduction.md)
guide. Hosting an archive remotely is a little trickier. You can check out some
of our [advanced recipes](#recipes) for modeled setups that may work for you.

#### What if I intend to host the OHIF Viewer at a different domain?

There are two important steps to making sure this setup works:

1. Your Image Archive needs to be exposed, in some way, to the open web. This
   can be directly, or through a `reverse proxy`, but the Viewer needs _some
   way_ to request its data.
2. \* Your Image Archive needs to have appropriate CORS (Cross-Origin Resource
   Sharing) Headers

> \* Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional
> HTTP headers to tell a browser to let a web application running at one origin
> (domain) have permission to access selected resources from a server at a
> different origin. - [MDN Web Docs: Web - Http - CORS][cors]

Most image archives do not provide either of these features "out of the box".
It's common to use IIS, Nginx, or Apache to route incoming requests and append
appropriate headers. You can find an example of this setup in our
[Nginx + Image Archive Deployment Recipe](./nginx--image-archive.md).

#### What if my archive doesn't support DicomWeb?

It's possible to supply all Study data via JSON format, in the event you do not
have a DicomWeb endpoint. You can host all of the relevant files on any web
accessible server (Amazon S3, Azure Blob Storage, Local file server etc.)

This JSON is supplied via the '?url=' query parameter. It should reference an
endpoint that returns **application/json** formatted text.

If you do not have an API, you can simply return a text file containing the JSON
from any web server.

You tell the OHIF viewer to use JSON by using the `dicomjson` datasource and
appending `'?url='` query to your mode's route:

e.g.
`https://my-test-ohif-server/myMode/dicomjson?url=https://my-json-server/study-uid.json`

The returned JSON object must contain a single root object with a 'studies'
array.

You can read more about using different data sources for mode's routes
[here](../platform/modes/routes.md#route-path)

_Sample JSON format:_

```
/* Detailed source-code truncated for AI context efficiency. */
```

More info on this JSON format can be found here
[Issue #1500](https://github.com/OHIF/Viewers/issues/1500)

**Implementation Notes:**



1. For each instance url (dicom object) in the returned JSON, you must prefix
   the `url` with `dicomjson:` in order for the cornerstone image loader to
   retrieve it correctly. eg. `https://image-server/my-image.dcm` --->
   `dicomjson:https://image-server/my-image.dcm`
2. The JSON format above is compatible with >= v3.7.8 of the application in `V2`
   version. Older versions of the viewer used a different JSON format. As of
   20/04/20 the public [https://viewer.ohif.org/] is a pre 3.0 version that does
   not support this format yet.
3. The JSON format is case-sensitive. Please ensure you have matched casing with
   the naturalised Dicom format referenced in
   [Issue #1500](https://github.com/OHIF/Viewers/issues/1500).

_CORS Issues (Cross-Origin Resource Sharing)_

If you host a JSON API or Images on a different domain from the app itself,
you will likely have CORS issues. This will also happen when testing from
Localhost and reaching out to remote servers. Even if the domain is the same,
different ports, subdomains or protocols (https vs http) will also cause CORS
errors. You will to need add a configuration on each server hosting these assets
to allow your App server origin.

For example:

Let's assume your application is hosted on `https://my-ohif-server.com`.

Your JSON API is hosted on `https://my-json-api.aws.com`

And your images are stored on Amazon S3 at `https://my-s3-bucket.aws.com`

When you first start your application, browsing to
`https://my-ohif-server.com/myMode/dicomjson?url=https://my-json-api.aws.com/api/my-json-study-info.json`,
you will likely get a CORS error in the browser console as it tries to connect
to `https://my-json-api.aws.com`.

Adding a setting on the JSON server to allow the CORS origin =
`https://my-ohif-server.com` should solve this.

Next, you will likely get a similar CORS error, as the browser tries to go to
`https://my-s3-bucket.aws.com`. You will need to go to the S3 bucket
configuration, and add a CORS setting to allow origin =
`https://my-ohif-server.com`.

Essentially, whenever the application connects to a remote resource, you will
need to add the applications url to the allowed CORS Origins on that resource.
Adding an origin similar to https://localhost:3000 will also allow for local
testing.

### Securing Your Data

Coming soon



### Recipes

We've included a few recipes for common deployment scenarios. There are many,
many possible configurations, so please don't feel limited to these setups.
Please feel free to suggest or contribute your own recipes.

- [Build for Production](./build-for-production.md)
- [Static](./static-assets.md)
- [Nginx + Image Archive](./nginx--image-archive.md)
- [User Account Control](./user-account-control.md)




[viewer-npm]: https://www.npmjs.com/package/@ohif/app
[pwa-url]: https://developers.google.com/web/progressive-web-apps/
[static-assets-url]: https://www.maxcdn.com/one/visual-glossary/static-content/
[app-store]: https://medium.freecodecamp.org/i-built-a-pwa-and-published-it-in-3-app-stores-heres-what-i-learned-7cb3f56daf9b
[dicom-web-standard]: https://www.dicomstandard.org/dicomweb/
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
[host-static-assets]: https://www.netlify.com/blog/2016/05/18/9-reasons-your-site-should-be-static/
[cors]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
[code-flows]: https://medium.com/@darutk/diagrams-of-all-the-openid-connect-flows-6968e3990660
[code-sandbox]: https://codesandbox.io/s/viewer-script-tag-tprch

---

### Platform Docs Docs Development Getting Started (`platform/docs/docs/development/getting-started.md`)

---
sidebar_position: 1
sidebar_label: Getting Started
title: Getting Started with OHIF Development
summary: Quick start guide for OHIF development, covering repository setup options, branch organization, development environment requirements, project initialization, and steps for building production-ready assets.
---

# Getting Started

## Setup

### Fork & Clone

If you intend to contribute back changes, or if you would like to pull updates
we make to the OHIF Viewer, then follow these steps:

- [Fork][fork-a-repo] the [OHIF/Viewers][ohif-viewers-repo] repository
- [Create a local clone][clone-a-repo] of your fork
  - `git clone https://github.com/YOUR-USERNAME/Viewers`
- Add OHIF/Viewers as a [remote repository][add-remote-repo] labeled `upstream`
  - Navigate to the cloned project's directory
  - `git remote add upstream https://github.com/OHIF/Viewers.git`

With this setup, you can now [sync your fork][sync-changes] to keep it
up-to-date with the upstream (original) repository. This is called a "Triangular
Workflow" and is common for Open Source projects. The GitHub blog has a [good
graphic that illustrates this setup][triangular-workflow].


### Private

Alternatively, if you intend to use the OHIF Viewer as a starting point, and you
aren't as concerned with syncing updates, then follow these steps:

1. Navigate to the [OHIF/Viewers][ohif-viewers] repository
2. Click `Clone or download`, and then `Download ZIP`
3. Use the contents of the `.zip` file as a starting point for your viewer

> NOTE: It is still possible to sync changes using this approach. However,
> submitting pull requests for fixes and features are best done with the
> separate, forked repository setup described in "Fork & Clone"

## Developing


### Branches

#### `master` branch - The latest dev (beta) release

- `master` - The latest dev release

This is typically where the latest development happens. Code that is in the master branch has passed code reviews and automated tests, but it may not be deemed ready for production. This branch usually contains the most recent changes and features being worked on by the development team. It's often the starting point for creating feature branches (where new features are developed) and hotfix branches (for urgent fixes).

Each package is tagged with beta version numbers, and published to npm such as `@ohif/ui@3.6.0-beta.1`

### `release/*` branches - The latest stable releases
Once the `master` branch code reaches a stable, release-ready state, we conduct a comprehensive code review and QA testing. Upon approval, we create a new release branch from `master`. These branches represent the latest stable version considered ready for production.

For example, `release/3.5` is the branch for version 3.5.0, and `release/3.6` is for version 3.6.0. After each release, we wait a few days to ensure no critical bugs. If any are found, we fix them in the release branch and create a new release with a minor version bump, e.g., 3.5.1 in the `release/3.5` branch.

Each package is tagged with version numbers and published to npm, such as `@ohif/ui@3.5.0`. Note that `master` is always ahead of the `release` branch. We publish docker builds for both beta and stable releases.

Here is a schematic representation of our development workflow:





### Requirements

- [Node.js & NPM](https://nodejs.org/en/)
- [Yarn](https://yarnpkg.com/en/)
- Yarn workspaces should be enabled:
  - `yarn config set workspaces-experimental true`

### Kick the tires

Navigate to the root of the project's directory in your terminal and run the
following commands:

```bash
# Restore dependencies
yarn install --frozen-lockfile

# Start local development server
yarn run dev
```
:::danger
In general run `yarn install` with the `--frozen-lockfile` flag to help avoid
supply chain attacks by enforcing reproducible dependencies. That is, if the
`yarn.lock` file is clean and does NOT reference compromised packages, then
no compromised packages should land on your machine by using this flag.
:::

You should see the following output:

```bash
@ohif/app: i ｢wds｣: Project is running at http://localhost:3000/
@ohif/app: i ｢wds｣: webpack output is served from /
@ohif/app: i ｢wds｣: Content not from webpack is served from D:\code\ohif\Viewers\platform\viewer
@ohif/app: i ｢wds｣: 404s will fallback to /index.html

# And a list of all generated files
```

### 🎉 Celebrate 🎉

<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/843233770?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>

### Building for Production

> More comprehensive guides for building and publishing can be found in our
> [deployment docs](./../deployment/index.md)

```bash
# Build static assets to host a PWA
yarn run build
```

### Updating Dependencies
In general you will typically not be updating the various `package.json` files.
But for the case when you do, you will have to also update the various OHIF lock files
and as such you will have to do both a `yarn` and `bun` `install` without
the `--frozen-lockfile` flag.

:::danger
Updating the package.json must be done with care so as to avoid incorporating
vulnerable, third-party packages and/or versions. Please research the added
packages and/or versions for vulnerabilities.

Here is what you should do when adding new packages and/or versions prior to
committing and pushing your code:
1. Do your due diligence researching the added packages and/or versions for vulnerabilities.
2. Update the `package.json` files.
3. Execute `yarn run install:update-lockfile`. This updates both the `yarn.lock` and
the `bun.lock` files.
4. Execute `yarn run audit` for a last security check. This runs both `yarn audit` and
`bun audit`.
6. Include both the `yarn.lock` and `bun.lock` files as part of your commit.

If any of your research or auditing for vulnerabilities find HIGH risk vulnerabilities
do NOT commit or push your changes! Low and moderate risk vulnerabilities are acceptable.
:::

## Troubleshooting

- If you receive a _"No Studies Found"_ message and do not see your studies, try
  changing the Study Date filters to a wider range.
- If you see a 'Loading' message which never resolves, check your browser's
  JavaScript console inside the Developer Tools to identify any errors.




[fork-a-repo]: https://help.github.com/en/articles/fork-a-repo
[clone-a-repo]: https://help.github.com/en/articles/fork-a-repo#step-2-create-a-local-clone-of-your-fork
[add-remote-repo]: https://help.github.com/en/articles/fork-a-repo#step-3-configure-git-to-sync-your-fork-with-the-original-spoon-knife-repository
[sync-changes]: https://help.github.com/en/articles/syncing-a-fork
[triangular-workflow]: https://github.blog/2015-07-29-git-2-5-including-multiple-worktrees-and-triangular-workflows/#improved-support-for-triangular-workflows
[ohif-viewers-repo]: https://github.com/OHIF/Viewers/
[ohif-viewers]: https://github.com/OHIF/Viewers

---

### Platform Docs Docs Faq Index (`platform/docs/docs/faq/index.md`)

---
id: index
title: OHIF Viewer FAQ
summary: Comprehensive list of frequently asked questions about the OHIF Viewer, covering common inquiries about reporting bugs, requesting features, academic collaborations, regulatory status, and obtaining demo studies.
---


# General FAQ


## How do I report a bug?

Navigate to our [GitHub Repository][new-issue], and submit a new bug report.
Follow the steps outlined in the [Bug Report Template][bug-report-template].

## How can I request a new feature?

At the moment we are in the process of defining our roadmap and will do our best
to communicate this to the community. If your requested feature is on the
roadmap, then it will most likely be built at some point. If it is not, you are
welcome to build it yourself and [contribute it](../development/contributing.md).
If you have resources and would like to fund the development of a feature,
please [contact us](https://ohif.org/get-support).


## Who should I contact about Academic Collaborations?

[Gordon J. Harris](https://www.dfhcc.harvard.edu/insider/member-detail/member/gordon-j-harris-phd/)
at Massachusetts General Hospital is the primary contact for any academic
collaborators. We are always happy to hear about new groups interested in using
the OHIF framework, and may be able to provide development support if the
proposed collaboration has an impact on cancer research.

## Does OHIF offer support?

yes, you can contact us for more information [here](https://ohif.org/get-support)


## Does The OHIF Viewer have [510(k) Clearance][501k-clearance] from the U.S. F.D.A or [CE Marking][ce-marking] from the European Commission?

**NO.** The OHIF Viewer is **NOT** F.D.A. cleared or CE Marked. It is the users'
responsibility to ensure compliance with applicable rules and regulations. The
[License](https://github.com/OHIF/Viewers/blob/master/LICENSE) for the OHIF
Platform does not prevent your company or group from seeking F.D.A. clearance
for a product built using the platform.

If you have gone this route (or are going there), please let us know because we
would be interested to hear about your experience.

## Is there a DICOM Conformance Statement for the OHIF Viewer?

Yes, check it here [DICOM Conformance Statement](https://docs.google.com/document/d/1hbDlUApX4svX33gAUGxGfD7fXXZNaBsX0hSePbc-hNA/edit?usp=sharing)

## Is The OHIF Viewer [HIPAA][hipaa-def] Compliant?

**NO.** The OHIF Viewer **DOES NOT** fulfill all of the criteria to become HIPAA
Compliant. It is the users' responsibility to ensure compliance with applicable
rules and regulations.

## Could you provide me with a particular study from the OHIF Viewer Demo?

You can check out the studies that we have put in this [Dropbox link](https://www.dropbox.com/scl/fo/66xidsx13pn0zf3b9cbfq/ADaCgn7aT29WMlnTdT_WRXM?rlkey=rratvx6g4kfxnswjdbupewjye&dl=0)






[general]: #general
[technical]: #technicalß˚
[report-bug]: #how-do-i-report-a-bug
[new-feature]: #how-can-i-request-a-new-feature
[commercial-support]: #does-ohif-offer-commercial-support
[academic]: #who-should-i-contact-about-academic-collaborations
[fda-clearance]: #does-the-ohif-viewer-have-510k-clearance-from-the-us-fda-or-ce-marking-from-the-european-commission
[hipaa]: #is-the-ohif-viewer-hipaa-compliant
[501k-clearance]: https://www.fda.gov/MedicalDevices/DeviceRegulationandGuidance/HowtoMarketYourDevice/PremarketSubmissions/PremarketNotification510k/
[ce-marking]: https://ec.europa.eu/growth/single-market/ce-marking_en
[hipaa-def]: https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act
[new-issue]: https://github.com/OHIF/Viewers/issues/new/choose
[bug-report-template]: https://github.com/OHIF/Viewers/issues/new?assignees=&labels=Bug+Report+%3Abug%3A&template=---bug-report.md&title=

---

### Platform Docs Docs Migration Guide Index (`platform/docs/docs/migration-guide/index.md`)

---
id: index
title: Migration Guides Overview
summary: Introduction to OHIF migration guides covering the upgrade paths between different versions of the platform, with links to version-specific guides for migrating from one OHIF version to another.
---


import DocCardList from '@theme/DocCardList';

# Migration Guides

Based on the version you are migrating from, you can find the migration guide for the latest version of the platform.

<DocCardList />

---

### Platform Docs Docs User Guide Index (`platform/docs/docs/user-guide/index.md`)

---
sidebar_position: 2
sidebar_label: Study List
---

# Study List

## Overview

The first page you will see when the viewer is loaded is the `Study List`. In
this page you can explore all the studies that are stored on the configured
server for the `OHIF Viewer`.



## Study Limit

To accommodate the various data sources that support various query parameters for
paging and limiting results it was decided to handle paging in the OHIF client.
This nicely handles those data sources that do not support paging and query limits.
For those that support the `limit` query parameter, there is a data source
configuration parameter `queryLimit` that will be passed for study list searches
so as to cap the result. When not specified, this value defaults to `101`.

## Sorting

When the Study List is opened, the application queries the PACS for 101 studies
by default. If there are greater than 100 studies returned, the default sort for
the study list is dictated by the image archive that hosts these studies for the
viewer and study list sorting will be disabled. If there are less than or equal
to 100 studies returned, they will be sorted by study date (most recent to
oldest) and study list sorting will be enabled. Whenever a query returns greater
than 100 studies, use filters to narrow results below 100 studies to enable
Study List sorting.

## Filters

There are certain filters that can be used to limit the study list to the
desired criteria.

- Patient Name: Searches between patients names
- MRN: Searches between patients Medical Record Number
- Study Date: Filters the date of the acquisition
- Description: Searches between study descriptions
- Modality: Filters the modalities
- Accession: Searches between patients accession number

An example of using study list filter is shown below:



Below the study list are pagination options for 25, 50, or 100 studies per page.



For static wado servers, you can enable fuzzy matching by setting the `supportsFuzzyMatching` property to true, after enabling it, fuzzy matching will be peformed on the patient name field, for example, if PatientName is "John^Doe", then "jo", "Do" and "John Doe" will all match. However "ohn" will not match.

## Study Summary

Click on a study to expand the study summary panel.



A summary of series available in the study is shown, which contains the series
description, series number, modality of the series, instances in the series, and
buttons to launch viewer modes to display the study.

## Study Specific Modes

All available modes are seen in the study expanded view. Modes can be enabled or
disabled for a study based on the modalities contained within the study.

In the screenshot below, there are two modes shown for the selected study

- Basic Viewer: Default mode that enables rendering and measurement tracking

- PET/CT Fusion: Mode for visualizing the PET CT study in a 3x3 format.

Based on the mode configurations (e.g., available modalities), PET/CT mode is
disabled for studies that do not contain PET AND CT images.





The previous screenshot shows a study containing PET and CT images and both
Basic Viewer and PET/CT Mode are available.

## View Study

The `Basic Viewer` mode is available for all studies by default. Click on the
mode button to launch the viewer.

---

### Platform Docs Versioned Docs Version 3.11 README (`platform/docs/versioned_docs/version-3.11/README.md`)

---
id: Introduction
slug: /
sidebar_position: 1
---

The [Open Health Imaging Foundation][ohif-org] (OHIF) Viewer is an open source,
web-based, medical imaging platform. It aims to provide a core framework for
building complex imaging applications.

Key features:

- Designed to load large radiology studies as quickly as possible. Retrieves
  metadata ahead of time and streams in imaging pixel data as needed.
- Leverages [Cornerstone3D](https://github.com/cornerstonejs/cornerstone3D-beta) for decoding,
  rendering, and annotating medical images.
- Works out-of-the-box with Image Archives that support [DICOMWeb][dicom-web].
  Offers a Data Source API for communicating with archives over proprietary API
  formats.
- Provides a plugin framework for creating task-based workflow modes which can
  reuse core functionality.
- Beautiful user interface (UI) designed with extensibility in mind. UI
  components available in a reusable component library built with React.js and
  Tailwind CSS


<div style={{ textAlign: 'center' }}>
    <div style={{ display: 'flex', gap: '1rem', justifyContent: 'center' }}>
        <a style={{
            backgroundColor: '#4042af',
            color: 'white',
            padding: '0.5rem 1rem',
            borderRadius: '0.25rem',
            textDecoration: 'none',
            ':hover': {
                backgroundColor: '#2a2b74'
            }
        }} href="https://ohif.org/news/">Subscribe to our newsletter</a>
        <a style={{
            backgroundColor: '#4042af',
            color: 'white',
            padding: '0.5rem 1rem',
            borderRadius: '0.25rem',
            textDecoration: 'none',
            ':hover': {
                backgroundColor: '#2a2b74'
            }
        }} href="./release-notes">Release Notes</a>
    </div>
</div>

<br/>
<br/>



|     |  | |
| :-: | :---  | :--- |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-measurements.webp?raw=true" alt="Measurement tracking" width="350"/> | Measurement Tracking | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-segmentation.webp?raw=true" alt="Segmentations" width="350"/> | Labelmap Segmentations  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-ptct.webp?raw=true" alt="Hanging Protocols" width="350"/> | Fusion and Custom Hanging protocols  | [Demo](https://viewer.ohif.org/tmtv?StudyInstanceUIDs=1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-volume-rendering.webp?raw=true" alt="Volume Rendering" width="350"/> | Volume Rendering  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&hangingprotocolId=mprAnd3DVolumeViewport) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-pdf.webp?raw=true" alt="PDF" width="350"/> | PDF  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.317377619501274872606137091638706705333) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-rtstruct.webp?raw=true" alt="RTSTRUCT" width="350"/> | RT STRUCT  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.5962.99.1.2968617883.1314880426.1493322302363.3.0) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-4d.webp?raw=true" alt="4D" width="350"/> | 4D  | [Demo](https://viewer.ohif.org/dynamic-volume?StudyInstanceUIDs=2.25.232704420736447710317909004159492840763) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-video.webp?raw=true" alt="VIDEO" width="350"/> | Video  | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.96975534054447904995905761963464388233) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/microscopy.webp?raw=true" alt="microscopy" width="350"/> | Slide Microscopy  | [Demo](https://viewer.ohif.org/microscopy?StudyInstanceUIDs=2.25.141277760791347900862109212450152067508) |



## Where to next?

The Open Health Imaging Foundation intends to provide an imaging viewer
framework which can be easily extended for specific uses. If you find yourself
unable to extend the viewer for your purposes, please reach out via our [GitHub
issues][gh-issues]. We are actively seeking feedback on ways to improve our
integration and extension points.

Check out these helpful links:

- Ready to dive into some code? Check out our
  [Getting Started Guide](./development/getting-started.md).
- We're an active, vibrant community.
  [Learn how you can be more involved.](./development/contributing.md)
- Feeling lost? Read our [help page](/help).

## Citing OHIF

To cite the OHIF Viewer in an academic publication, please cite

> _Open Health Imaging Foundation Viewer: An Extensible Open-Source Framework
> for Building Web-Based Imaging Applications to Support Cancer Research_
>
>  Erik Ziegler, Trinity Urban, Danny Brown, James Petts, Steve D. Pieper, Rob
> Lewis, Chris Hafey, and Gordon J. Harris _JCO Clinical Cancer Informatics_, no. 4 (2020), 336-345, DOI:
> [10.1200/CCI.19.00131](https://www.doi.org/10.1200/CCI.19.00131)

This article is freely available on Pubmed Central: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7259879/


or, for Lesion Tracker of OHIF v1, please cite:

> _LesionTracker: Extensible Open-Source Zero-Footprint Web Viewer for Cancer
> Imaging Research and Clinical Trials_
>
> Trinity Urban, Erik Ziegler, Rob Lewis, Chris Hafey, Cheryl Sadow, Annick D.
> Van den Abbeele and Gordon J. Harris _Cancer Research_, November 1 2017 (77) (21) e119-e122 DOI:
> [10.1158/0008-5472.CAN-17-0334](https://www.doi.org/10.1158/0008-5472.CAN-17-0334)

This article is freely available on Pubmed Central.
https://pubmed.ncbi.nlm.nih.gov/29092955/


**Note:** If you use or find this repository helpful, please take the time to
star this repository on Github. This is an easy way for us to assess adoption,
and it can help us obtain future funding for the project.

## License

MIT © [OHIF](https://github.com/OHIF)

&nbsp;




[ohif-org]: https://www.ohif.org
[ohif-demo]: http://viewer.ohif.org/
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
[gh-issues]: https://github.com/OHIF/Viewers/issues

---

### Platform Docs Docs Migration Guide 3p10 To 3p11 Index (`platform/docs/docs/migration-guide/3p10-to-3p11/index.md`)

---
id: index
sidebar_position: 1
sidebar_label: 3.10 -> 3.11
title: 3.10 to 3.11 Migration Guide
---

import DocCardList from '@theme/DocCardList';

# 3.10 to 3.11 Migration Guide

Here you can find the migration guides for upgrading from OHIF version 3.10 to version 3.11.

<DocCardList />

---

### Platform Docs Docs Migration Guide 3p11 To 3p12 Index (`platform/docs/docs/migration-guide/3p11-to-3p12/index.md`)

---
sidebar_position: 1
sidebar_label: 3.11 -> 3.12
---

# Migration Guide

This guide provides information about migrating from OHIF version 3.11 to version 3.12

## Optional: Migrate modes to extend `modes/basic`

There is a lot of support for the basic mode definition contained in the
`modes/basic` module.  Using this framework will allow your mode to avoid
creating a lot of boilerplate code that may not upgrade very well.

This is an OPTIONAL change - your existing mode definitions will continue to work,
but using the new basic mode as a basis will reduce the amount of effort when
there are changes unrelated to your custom mode.


## ui button with text size

Using the class text size with the ui-button is inconsistent as to whether
it will apply or not.  Instead, create a new size value to assign the desired size.
To support this, a new size enum is created, smallTall, which is used in the worklist
for an over-ride.

## `createReportDialogPrompt`

The create report dialog prompt (which is MOSTLY an internal component) has
change the API a bit.  The input is now:

 - `title` shown in the dialog
 - `modality` being stored, used to query existing series
 - `minSeriesNumber` is the start of new series of this modality type.
    Will get set to 4000 if not determined by the modality
 - predecessorImageId is the image id that this series was currently loaded
   from.  That allows defaulting the dialog to show the specified series instead
   of always creating a new series.

The minSeries and predecessor are both optional, so the input doesn't have to be
updated.

The output has been enhanced with:

  - `series`, is the series to store do, as referenced by a predecessorImageId value.
    This allows exactly specifying which item to replace, which allows selecting it in the
    menu by default instead of just guessing what value is being replaced.
  - `priorSeriesNumber` is the previously lowest series number at least minSeriesNumber
     of all the seris of the given modality type.  This allows adding an instance to the
     `next` series number by adding 1 to this value.

The priorSeriesNumber will default to 4000 for an unknown modality type, or
3000 for sr, 3100 for seg and 3200 for rtstruct.

## metadataProvider and formatted metadata

The metadata provider has been formatting some fields, which causes inconsistency
between different metadata providers and use of the instance object.  The
specific fields that have changed are:

- `patientName`
- `studyDate`, `studyTime`
- `seriesDate`, `seriesTime`

If these fields need formatted versions, it is recommended to add a secondary/computed
metadata provider which simply gets the base metadata module and adds the
formatting.  That way different metadata providers are all handled identically.

---

### Platform Docs Docs Migration Guide 3p12 To 3p13 Index (`platform/docs/docs/migration-guide/3p12-to-3p13/index.md`)

---
id: index
sidebar_position: 1
sidebar_label: 3.12 -> 3.13
title: 3.12 to 3.13 Migration Guide
---

import DocCardList from '@theme/DocCardList';

# 3.12 to 3.13 Migration Guide

This guide covers changes when upgrading from OHIF version 3.12 to version 3.13.

The largest changes in 3.13 are infrastructure-level:

- **[Package Manager](./package-manager.md)** — the monorepo moves from
  yarn + lerna to **pnpm workspaces**, with new install/run commands
  and a `workspace:*` syntax for cross-package dependencies.
- **[Build Tooling](./build-tooling.md)** — Webpack is replaced with
  **Rspack v2** across the app and every extension/mode, with new
  plugin imports and faster build commands.
- **[Node Version](./node-version.md)** — the minimum Node.js runtime
  is now **24**.
- **[SegmentationService](./segmentation-service.md)** — the
  `removeSegmentationRepresentations` method was renamed.
- **[DICOM video viewport](./dicom-video.md)** — the
  `@ohif/extension-dicom-video.viewportModule.dicom-video` namespace was
  removed; route DICOM video display sets through the Cornerstone viewport.
- **[Deployment recipes](./deployment-recipes.md)** — the Keycloak recipes
  now require a `.env` file and a generated client secret before
  `docker compose up`, and the nginx recipes no longer send wildcard CORS
  headers (cross-origin deployments must set an explicit origin).

<DocCardList />

---

### Platform Docs Docs Migration Guide 3p13 To 3p14 Index (`platform/docs/docs/migration-guide/3p13-to-3p14/index.md`)

---
id: index
sidebar_position: 1
sidebar_label: 3.13 -> 3.14
title: 3.13 to 3.14 Migration Guide
---

import DocCardList from '@theme/DocCardList';

# 3.13 to 3.14 Migration Guide

This guide covers changes when upgrading from OHIF version 3.13 to version 3.14.

- **[React 19](./react-19.md)** — the monorepo moves to **React 19.2.7**.
  `@ohif/ui-next` now declares react/react-dom as `peerDependencies`, so
  consuming applications must supply React 19, and extensions and modes require
  it too.
- **[SmartScrollbar](./smart-scrollbar.md)** — `SmartScrollbarFill` and
  `SmartScrollbarEndpoints` now require the `marked` array to change identity when
  its contents change. The `version` prop is deprecated and no longer invalidates.
- **[WorkList](./work-list.md)** — `LegacyWorkList` and the `workList.variant`
  customization still work in 3.14 and are deprecated. A future release removes
  both; migrate to the `workList.*` customizations on the ui-next `WorkList`.
- **[DataTable / TanStack Table v9](./data-table.md)** — `@ohif/ui-next` upgrades
  `@tanstack/react-table` to v9. Column definitions need the `DataTableFeatures`
  generic and the `sortFn` rename; programmatic visibility toggles should go
  through `useToggleColumnVisibility`.

- **[useSegmentationExpanded](./segmentation-expanded-context.md)** — the hook
  returns `undefined` outside a `SegmentationExpandedProvider` instead of
  throwing, and no longer takes a component-name argument. Callers that wrapped
  it in `try/catch` should check for `undefined`; callers that require the
  provider should assert for themselves.

- **[Viewport element hooks](./use-viewport-refs.md)** — `useViewportRef` and
  `useViewportRefs` are replaced by `useViewportElement` for readers and
  `useViewportElementRegistration` for the viewport that owns the element, and
  `ViewportRefsProvider` is renamed `ViewportElementsProvider`. The element is now
  a subscribed value rather than a snapshot read during render.

- **[Save/report dialog](./report-dialog.md)** — the dialog for storing
  measurements, segmentations and contours replaces its series drop down with an
  explicit choice of three destinations: **Save to current**, **Save as new** and
  **Replace existing**.  The series number of a new series is editable, and the
  series descriptions used before are remembered per type of item and offered as
  completions.  `createReportDialogPrompt` takes `defaultSeriesDescription`,
  `itemType` and `rememberedDescriptionCount`, and returns a `seriesNumber`.  A
  stored instance is now identified like a loaded one, so the object just saved
  becomes the predecessor of the next save of the same data.
- **[Display set date/time ordering](./display-set-ordering.md)** — derived
  display sets are ordered by the creation date/time of the instance they show
  rather than by their series date/time, comparators registered with
  `addSameSeriesCompare` now actually run, instances tie-break by creation
  date/time before the SOP instance UID, and saved reports and segmentations are
  stamped with a creation date/time and an instance number.

- **[useCustomization](./use-customization.md)** — `@ohif/core` adds a
  `useCustomization` hook. A component that calls
  `customizationService.getCustomization` during render can now freeze at a stale
  value, because the React Compiler caches the call on the service reference,
  which never changes. Move such reads to the hook. Event handlers and non-React
  code keep calling the service directly.

- **[InputNumber](./input-number.md)** — `InputNumber.HorizontalControls` and
  `InputNumber.VerticalControls` now share `min`, `max`, `step` and `disabled`
  through a nested provider rather than by writing onto the root context object.
  That fixes constraints being discarded on every keystroke, but it means only
  **descendants** of the controls receive them; an `InputNumber.Input` rendered as
  a sibling silently falls back to `min=0, max=100, step=1`.

- **[createContext helper](./create-context.md)** — the internal
  `ui-next/lib/createContext` helper is removed. It was never exported from
  `@ohif/ui-next`; if you imported it from source, use React's own
  `createContext` and `useContext` — the compiler now provides the memoization it
  was hand-rolling.

<DocCardList />

---

### Platform Docs Docs Migration Guide 3p8 To 3p9 Index (`platform/docs/docs/migration-guide/3p8-to-3p9/index.md`)

---
id: 3p8-to-3p9
title: 3.8 -> 3.9
sidebar_position: 2
summary: Migration guide for upgrading from OHIF 3.8 to 3.9, covering segmentation architecture changes, renamings, data sources, measurements, viewport action corners, state sync service, RT structure improvements, UI changes, and other refactorings.
---


import DocCardList from '@theme/DocCardList';

## Migration Guide Sections

<DocCardList />

---

### Platform Docs Docs Migration Guide 3p9 To 3p10 Index (`platform/docs/docs/migration-guide/3p9-to-3p10/index.md`)

---
sidebar_position: 1
sidebar_label: 3.9 -> 3.10
title: Migration Guide from 3.9 to 3.10 beta
summary: Migration guide for upgrading from OHIF 3.9 to 3.10 beta, covering general changes, customization service improvements, UI component upgrades, command handling, hotkey updates, routing changes, and testing strategies.
---

# Migration Guide


## General

---

### Platform Docs Docs Platform Extensions Index (`platform/docs/docs/platform/extensions/index.md`)

---
sidebar_position: 1
sidebar_label: Introduction
title: OHIF Extensions Introduction
summary: Comprehensive introduction to the OHIF viewer extension system, explaining how extensions provide modular functionality through different module types, and how they're configured and accessed in modes to build customized viewer experiences.
---

# Introduction

We have re-designed the architecture of the `OHIF-v3` to enable building
applications that are easily extensible to various use cases (modes) that behind
the scene would utilize desired functionalities (extensions) to reach the goal
of the use case.

Previously, extensions were “additive” and could not easily be mixed and matched
within the same viewer for different use cases. Previous `OHIF-v2` architecture
meant that any minor extension alteration usually would require the user to hard
fork. E.g. removing some tools from the toolbar of the cornerstone
extension meant you had to hard fork it, which was frustrating if the
implementation was otherwise the same as master.

> - Developers should make packages of _reusable_ functionality as extensions,
>   and can consume publicly available extensions.
> - Any conceivable radiological workflow or viewer setup will be able to be
>   built with the platform through _modes_.

Practical examples of extensions include:

- A set of segmentation tools that build on top of the `cornerstone` viewport
- A set of rendering functionalities to volume render the data
- [See our maintained extensions for more examples of what's possible](#maintained-extensions)

**Diagram showing how extensions are configured and accessed.**



## Extension Skeleton

An extension is a plain JavaScript object that has `id` and `version` properties, and one or
more [modules](#modules) and/or [lifecycle hooks](#lifecycle-hooks).

```js
// prettier-ignore
export default {
  /**
   * Required properties. Should be a unique value across all extensions.
   */
  id,

  // Lifecycle
  preRegistration() { /* */ },
  onModeEnter() { /* */ },
  onModeExit() { /* */ },
  // Modules
  getLayoutTemplateModule() { /* */ },
  getDataSourcesModule() { /* */ },
  getSopClassHandlerModule() { /* */ },
  getPanelModule() { /* */ },
  getViewportModule() { /* */ },
  getCommandsModule() { /* */ },
  getContextModule() { /* */ },
  getToolbarModule() { /* */ },
  getHangingProtocolModule() { /* */ },
  getUtilityModule() { /* */ },
}
```

## OHIF-Maintained Extensions

A small number of powerful extensions for popular use cases are maintained by
OHIF. They're co-located in the [`OHIF/Viewers`][viewers-repo] repository, in
the top level [`extensions/`][ext-source] directory.

<table>
    <thead>
        <tr>
            <th>Extension</th>
            <th>Description</th>
            <th>Modules</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <a href="">
                    default
                </a>
            </td>
            <td>
                Default extension provides default viewer layout, a study/series
                browser, and a datasource that maps to a DICOMWeb compliant backend
            </td>
            <td>commandsModule, ContextModule, DataSourceModule, HangingProtocolModule, LayoutTemplateModule, PanelModule, SOPClassHandlerModule, ToolbarModule</td>
        </tr>
        <tr>
            <td>
                <a href="">
                    cornerstone
                </a>
            </td>
            <td>
                Provides 2d and 3d rendering functionalities
            </td>
            <td>ViewportModule, CommandsModule, UtilityModule</td>
        </tr>
        <tr>
            <td>
                <a href="">dicom-pdf</a>
            </td>
            <td>
                Renders PDFs for a <a href="https://github.com/OHIF/Viewers/blob/master/extensions/dicom-pdf/src/OHIFDicomPDFSopClassHandler.js#L4-L6">specific SopClassUID</a>.
            </td>
            <td>Viewport, SopClassHandler</td>
        </tr>
        <tr>
            <td>
                <a href="">dicom-video</a>
            </td>
            <td>
                Renders DICOM Video files.
            </td>
            <td>Viewport, SopClassHandler</td>
        </tr>
        <tr>
            <td>
                <a href="">cornerstone-dicom-sr</a>
            </td>
            <td>
                Maintained extensions for cornerstone and visualization of DICOM Structured Reports
            </td>
           <td>ViewportModule, CommandsModule, SOPClassHandlerModule</td>
        </tr>
        <tr>
            <td>
                <a href="">measurement-tracking</a>
            </td>
            <td>
                Tracking measurements in the measurement panel
            </td>
            <td> ContextModule,PanelModule,ViewportModule,CommandsModule</td>
        </tr>
    </tbody>
</table>

## Registering of Extensions

`viewer` starts by registering all the extensions specified inside the
`pluginConfig.json`, by default we register all extensions in the repo.


```js title=platform/app/pluginConfig.json
// Simplified version of the `pluginConfig.json` file
{
  "extensions": [
    {
      "packageName": "@ohif/extension-cornerstone",
      "version": "3.4.0"
    },
    {
      "packageName": "@ohif/extension-measurement-tracking",
      "version": "3.4.0"
    },
    // ...
  ],
  "modes": [
    {
      "packageName": "@ohif/mode-longitudinal",
      "version": "3.4.0"
    }
  ]
}
```

:::note
You can register extensions by editing the `pluginConfig.json` file directly.
The provided `cli` can also add/remove/install/uninstall extensions
([read more](../../development/ohif-cli.md)), but it is being phased out in
favour of generating extensions with an agent.
:::

For the full set of fields (`packageName`, `version`, `default`, `directory`,
the `public` section) and the three ways a plugin can be located (in-tree,
out-of-tree `directory`, or installed dependency), see the
[pluginConfig.json reference](./pluginConfig.md).

The final registration and import of the extensions happen inside a non-tracked file `pluginImport.js` (this file is also for internal use only).

After an extension gets registered within the `viewer`,
each [module](#modules) defined by the extension becomes available to the modes
via the `ExtensionManager` by requesting it via its id.
[Read more about Extension Manager](#extension-manager)

## Lifecycle Hooks

Currently, there are three lifecycle hook for extensions:

[`preRegistration`](./lifecycle/#preRegistration) This hook is called once on
initialization of the entire viewer application, used to initialize the
extensions state, and consume user defined extension configuration. If an
extension defines the [`preRegistration`](./lifecycle/#preRegistration)
lifecycle hook, it is called before any modules are registered in the
`ExtensionManager`. It's most commonly used to wire up extensions to
[services](./../services/index.md) and [commands](./modules/commands.md), and to
bootstrap 3rd party libraries.

[`onModeEnter`](./lifecycle#onModeEnter): This hook is called whenever a new
mode is entered, or a mode’s data or datasource is switched. This hook can be
used to initialize data.

[`onModeExit`](./lifecycle#onModeExit): Similarly to onModeEnter, this hook is
called when navigating away from a mode, or before a mode’s data or datasource
is changed. This can be used to cache data for reuse later, but since it
isn't known which mode will be entered next, the state after exiting should be
clean, that is, the same as the state on a clean start.  This is called BEFORE
service clean up, and after mode specific onModeExit handling.

## Modules

Modules are the meat of extensions, the `blocks` that we have been talking about
a lot. They provide "definitions", components, and filtering/mapping logic that
are then made available to modes and services.

Each module type has a special purpose, and is consumed by our viewer
differently.

<table>
  <thead>
    <tr>
      <th align="left" width="30%">
        Types
      </th>
      <th align="left">Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td align="left">
        <a href="./modules/layout-template">
          LayoutTemplate
        </a>
      </td>
      <td align="left">Control Layout of a route</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/data-source">
          DataSource
        </a>
      </td>
      <td align="left">Control the mapping from DICOM metadata to OHIF-metadata</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/sop-class-handler">
          SOPClassHandler
        </a>
      </td>
      <td align="left">Determines how retrieved study data is split into "DisplaySets"</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/panel">
          Panel
        </a>
      </td>
      <td align="left">Adds left or right hand side panels</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/viewport">
          Viewport
        </a>
      </td>
      <td align="left">Adds a component responsible for rendering a "DisplaySet"</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/commands">
          Commands
        </a>
      </td>
      <td align="left">Adds named commands, scoped to a context, to the CommandsManager</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/toolbar">
          Toolbar
        </a>
      </td>
      <td align="left">Adds buttons or custom components to the toolbar</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/contextModule">
          Context
        </a>
      </td>
      <td align="left">Shared state for a workflow or set of extension module definitions</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/hpModule">
          HangingProtocol
        </a>
      </td>
      <td align="left">Adds hanging protocol rules</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/hpModule">
          Utility
        </a>
      </td>
      <td align="left">Expose utility functions to the outside of extensions</td>
    </tr>
  </tbody>
</table>

<span style={{"textAlign": 'center', 'fontStyle': 'italic'}}>Tbl. Module types
with abridged descriptions and examples. Each module links to a dedicated
documentation page.</span>

### Contexts

The `@ohif/app` tracks "active contexts" that extensions can use to scope
their functionality. Some example contexts being:

- Route: `ROUTE:VIEWER`, `ROUTE:STUDY_LIST`
- Active Viewport: `ACTIVE_VIEWPORT:CORNERSTONE`, `ACTIVE_VIEWPORT:VTK`

An extension module can use these to say "Only show this Toolbar Button if the
active viewport is a Cornerstone viewport." This helps us use the appropriate UI
and behaviors depending on the current contexts.

For example, if we have hotkey that "rotates the active viewport", each Viewport
module that supports this behavior can add a command with the same name, scoped
to the appropriate context. When the `command` is fired, the "active contexts"
are used to determine the appropriate implementation of the rotation behavior.




[viewers-repo]: https://github.com/OHIF/Viewers
[ext-source]: https://github.com/OHIF/Viewers/tree/master/extensions
[module-types]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/extensions/MODULE_TYPES.js

---

### Platform Docs Docs Platform Hooks Index (`platform/docs/docs/platform/hooks/index.md`)

---
title: Hooks
summary: List of React hooks available in the platform, these are custom hooks that are used to access the state of the platform
---

# Hooks

## [useMeasurements](./useMeasurements.md)
A React hook that provides mapped measurements from the measurement service with automatic updates when measurements change.

## [useViewportSegmentations](./useViewportSegmentations.md)
A React hook that provides segmentation data and representations for the active viewport with automatic updates when segmentations change.

## [useMeasurementTracking](./useMeasurementTracking.md)
A React hook that provides measurement tracking information for a specific viewport, including tracking state and tracked measurement UIDs.

## [useViewportDisplaySets](./useViewportDisplaySets.md)
A React hook that provides access to display sets associated with a viewport, including background, foreground, overlay, and potential display sets.

## [useViewportHover](./useViewportHover.md)
A React hook that tracks mouse hover state and active status for a specific viewport.

## [usePatientInfo](./usePatientInfo.md)
A React hook that provides patient information from the active display sets and detects when multiple patients are loaded.

## [useSearchParams](./useSearchParams.md)
A React hook that provides access to URL search parameters from both the query string and hash fragment.

## [useDynamicMaxHeight](./useDynamicMaxHeight.md)
A React hook that calculates the maximum height for an element based on its position in the viewport, with automatic recalculation on window resize or data changes.

## [useSessionStorage](./useSessionStorage.md)
A React hook that provides sessionStorage access with automatic JSON parsing/stringifying and an option to clear data when the page unloads.

---

### Platform Docs Docs Platform Managers Index (`platform/docs/docs/platform/managers/index.md`)

---
sidebar_position: 1
sidebar_label: Introduction
title: Managers Introduction
summary: Overview of OHIF's manager system, which handles critical application infrastructure including extension registration, service management, command execution, and hotkey binding to coordinate functionality across the platform.
---

# Managers

## Overview

`OHIF` uses `Managers` to accomplish various purposes such as registering new
services, dependency injection, and aggregating and exposing `extension`
features.

`OHIF-v3` provides the following managers which we will discuss in depth.

<table>
    <thead>
        <tr>
            <th>Manager</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <a href="./extension">
                    Extension Manager
                </a>
            </td>
            <td>
                Aggregating and exposing modules and features through out the app
            </td>
        </tr>
        <tr>
            <td>
                <a href="./service">
                    Services Manager
                </a>
            </td>
            <td>
                Single point of registration for all internal and external services
            </td>
        </tr>
        <tr>
            <td>
                <a href="./commands">
                    Commands Manager
                </a>
            </td>
            <td>
                Register commands with specific context and run commands in the app
            </td>
        </tr>
        <tr>
            <td>
                <a href="./hotkeys">
                    Hotkeys Manager
                </a>
            </td>
            <td>
                For keyboard keys assignment to commands
            </td>
        </tr>
    </tbody>
</table>





[core-services]: https://github.com/OHIF/Viewers/tree/master/platform/core/src/services
[services-manager]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/services/ServicesManager.js
[cross-cutting-concerns]: https://en.wikipedia.org/wiki/Cross-cutting_concern

---

### Platform Docs Docs Platform Modes Index (`platform/docs/docs/platform/modes/index.md`)

---
sidebar_position: 1
sidebar_label: Introduction
title: Modes Introduction
summary: Overview of OHIF Modes, which are specialized viewer configurations for specific clinical workflows, allowing multiple purpose-specific applications to coexist within a single OHIF deployment.
---

# Modes

## Overview

A mode can be thought of as a viewer app configured to perform a specific task,
such as tracking measurements over time, 3D segmentation, a guided radiological
workflow, etc. Addition of modes enables _application_ with many _applications_
as each mode become a mini _app configuration_ behind the scene.

Upon initialization the viewer will consume extensions and modes and build up
the route desired, these can then be accessed via the study list, or directly
via url parameters.



OHIF-v3 architecture can be seen in the following:



> Note: Templates are now a part of “extensions” Routes are configured by modes
> and/or app

As mentioned, modes are tied to a specific route in the viewer, and multiple
modes/routes can be present within a single application. This allows for
tremendously more flexibility than before you can now:

- Simultaneously host multiple viewers with for different use cases from within
  the same app deploy.
- Make radiological viewers for specific purposes/workflows, e.g.:
  - Tracking the size of lesions over time.
  - PET/CT fusion workflows.
  - Guided review workflows optimized for a specific clinical trial.
- Still host one single feature-rich viewer if you desire.

## Anatomy

A mode configuration has a `route` name which is dynamically transformed into a
viewer route on initialization of the application. Modes that are available to a
study will appear in the study list.



The mode configuration specifies which `extensions` the mode requires, which
`LayoutTemplate` to use, and what props to pass to the template. For the default
template this defines which `side panels` will be available, as well as what
`viewports` and which `displaySets` they may hang.

Mode's config is composed of these elements:
- `id`: the mode `id`
- `modeFactory`: the function that returns the mode specific configuration
- `modeInstance`: An optional configuration used by the default modeFactory
      exported by the basic mode.  This allows specifying or updating the
      default mode values.
- `extensionDependencies`: the list of extensions that the mode requires


that return a config object with certain
properties, the high-level view of this config object is:

```js title="modes/example/src/index.js"
function modeFactory({modeConfiguration}) {
  return { ...this.modeInstance, ...modeConfiguration };

}

const mode = {
  id,
  modeFactory,
  modeInstance: {
    id: '',
    version: '',
    hide: true,
    displayName: '',
    onModeEnter: () => {},
    onModeExit: () => {},
    validationTags: {},
    isValidMode: () => {},
    routes: [
      {
        path: '',
        init: () => {},
        layoutInstance: {
          id,
          props: {
            leftPanels: [],
            leftPanelResizable: true,
            rightPanels: [],
            rightPanelClosed: true,
            rightPanelResizable: true,
            viewports: [],
          },
        },
        layoutTemplate: function() { return this.layoutInstance },
      },
    ],
    extensions: extensionDependencies,
    hangingProtocol: [],
    sopClassHandlers: [],
    hotkeys: [],
    nonModeModalities: [],
    modeModalities: [],
  },
  extensionDependencies,
};

export default mode;
```

<table>
  <thead>
    <tr>
      <th align="left">Property</th>
      <th align="left">Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td align="left">
          id
      </td>
      <td align="left">unique mode id used to refer to the mode</td>
    </tr>
    <tr>
      <td align="left">
          hide
      </td>
      <td align="left">Set to true to hide this mode on the worklist, but allow it in the path</td>
    </tr>
    <tr>
      <td align="left">
          displayName
      </td>
      <td align="left">actual name of the mode being displayed for each study in the study summary panel</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./lifecycle#onModeEnter">
          onModeEnter
        </a>
      </td>
      <td align="left">hook is called when the mode is entered by the specified route</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./lifecycle#onModeExit">
          onModeExit
        </a>
      </td>
      <td align="left">hook is called when the mode exited</td>
    </tr>
    <tr>
      <td align="left">
        <a href="">
          validationTags
        </a>
      </td>
      <td align="left">validationTags</td>
    </tr>
    <tr>
      <td align="left">
        <a href="">
          isValidMode
        </a>
      </td>
      <td align="left">Checks if the mode is valid for a study</td>
    </tr>
    <tr>
      <td align="left">
        <a href="">
          routes
        </a>
      </td>
      <td align="left">route config which defines the route address, and the layout for it</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./index#consuming-extensions">
          extensionDependencies
        </a>
      </td>
      <td align="left">extensions needed by the mode</td>
    </tr>
    <tr>
      <td align="left">
        <a href="">
          hanging protocol
        </a>
      </td>
      <td align="left">list of hanging protocols that the mode applies initially, choosing the highest scoring match</td>
    </tr>
    <tr>
      <td align="left">
        <a href="">
          sopClassHandlers
        </a>
      </td>
      <td align="left">list of SOPClass modules needed by the mode </td>
    </tr>
    <tr>
      <td align="left">
        <a href="">
          hotkeys
        </a>
      </td>
      <td align="left">hotkeys</td>
    </tr>
    <tr>
      <td align="left">
          modeModalities
      </td>
      <td align="left">If non-empty, then the default isValidMode will only return true when the modalities list has all of the elements of one of the mode modalities.  Eg `[` [CT,PT], [MR,PT] ]` would mean that the mode supports a CT AND a PT,  OR an MR and a PT</td>
    </tr>
    <tr>
      <td align="left">
          nonModeModalities
      </td>
      <td align="left">Enable the mode if the modalities list contains a modality OTHER than those in the array</td>
    </tr>
    <tr>
      <td align="left">
          excludedModalities
      </td>
      <td align="left">The default isValidMode returns false when the modalities list contains ANY of these</td>
    </tr>
    <tr>
      <td align="left">
          excludedStudies
      </td>
      <td align="left">A list of study attribute objects; the default isValidMode returns false for a study matching every attribute of any entry, e.g. <code>[&#123; mrn: 'M1' &#125;]</code></td>
    </tr>
    <tr>
      <td align="left">
          toolbarSections
      </td>
      <td align="left">Toolbar section composition: a list of section-layout packs (as <code>$reference</code> markers) and/or literal section objects; seeded onto the Mode scope on enter</td>
    </tr>
    <tr>
      <td align="left">
          toolbarButtons
      </td>
      <td align="left">Toolbar button composition: a list of button packs (as <code>$reference</code> markers) and/or literal button definitions; seeded onto the Mode scope on enter</td>
    </tr>
    <tr>
      <td align="left">
          toolGroupAdditions
      </td>
      <td align="left">Per-tool-group composition: a map of tool-group id to a list of tool packs (as <code>$reference</code> markers) and/or literal tool blocks, layered onto the mode's tool groups after creation</td>
    </tr>
    <tr>
      <td align="left">
          initToolGroups
      </td>
      <td align="left">Tool group setup function called by the shared onModeEnter as <code>initToolGroups(&#123; extensionManager, toolGroupService, commandsManager, servicesManager &#125;)</code>; extending modes can substitute their own</td>
    </tr>
    <tr>
      <td align="left">
          modeCustomizations
      </td>
      <td align="left">The mode's own customizations, applied by the mode route as the bottom layer of the mode scope on enter — before the app config / URL <code>mode</code> phase blocks, and below global-scope customizations, so final values are decided purely by scope precedence and application order. Usually the name of a block the extension registers at default scope (e.g. <code>basicModeCustomizations</code>, which sets <code>panelSegmentation.disableEditing</code>); may also be a literal object of immutability-helper commands or an array mixing those with customization module reference strings</td>
    </tr>
    <tr>
      <td align="left">
          activatePanelTriggers
      </td>
      <td align="left">Data-driven ActivatePanel event triggers: a list of <code>&#123; panelId, sourceServiceName, sourceEvents, forceActive? &#125;</code> entries wired up on mode enter (e.g. activating the segmentation panel when a segmentation is added). Empty by default; see <code>defaultActivatePanelTriggers</code> in the basic mode</td>
    </tr>


  </tbody>
</table>

### Extending Modes

The `basic` mode provides support for creating mode extensions without having
to redeclare the entire mode.  See `longitudinal/src/index.ts` for an example
mode that builds on top of the basic mode.  Also see `basic/src/index.tsx` for
some default functions which can be used to create your own modes.  Doing a mode
this way makes the definition of new modes based on your existing mode much easier,
and the upgrade to new versions of modes tends to be more consistent.

The **`segmentation`** and **`tmtv`** modes now follow this same pattern. Like
`longitudinal`, each one exports a `modeInstance` object and reuses the `basic`
mode's `modeFactory`, so they are extensible in two complementary ways:

1. **Build a derived mode** — create a new mode package (for example
   `mySegmentation`) that imports the shipped mode and overrides only the parts
   you need, exactly like `longitudinal` builds on `basic`.
2. **Customize an existing mode at runtime** — change a shipped mode's toolbar,
   tools, or panels through per-mode customization keys, with no new package.

#### Building a derived mode

A derived mode imports the shipped mode's default export (which carries the
`modeFactory`) and its `modeInstance`, then spreads and overrides. Because the
default `modeFactory` applies [immutability-helper][immutability-helper]
commands from `modeConfiguration` onto `modeInstance`, you can also override
via `modeConfiguration` rather than editing the instance directly.

```js title="modes/my-segmentation/src/index.tsx"
import segmentationMode, { modeInstance as segModeInstance } from '@ohif/mode-segmentation';

const id = 'mySegmentation';

export const modeInstance = {
  ...segModeInstance,
  id,
  routeName: 'mySegmentation',
  displayName: 'My Segmentation',
  // Override only what you need. Toolbar buttons/sections and tool group
  // additions are plain composition arrays on the instance naming the
  // capability packs the mode uses (see below); panel lists are literal
  // arrays in the layout. Both are customized at runtime via the `mode` phase.
};

const mode = {
  ...segmentationMode, // carries modeFactory + extensionDependencies
  id,
  modeInstance,
};

export default mode;
```

The `tmtv` mode is extended the same way — import `@ohif/mode-tmtv` and its
`modeInstance`, then override.

#### Customizing a mode at runtime

The `basic`, `longitudinal`, `segmentation`, and `tmtv` modes declare their toolbar
buttons, toolbar sections, and tool-group additions as plain composition arrays on
the mode instance that name the capability packs the mode uses with `{ $reference }`
markers (for example
`toolbarButtons: [{ $reference: 'cornerstone.toolbarButtons' }, { $reference: 'cornerstone.segmentationToolbarButtons' }]`).
The mode route seeds these onto the Mode customization scope on enter, alongside the
`leftPanels` / `rightPanels` panel lists. Because the values are lists whose
`{ $reference }` entries the customization service expands at read time, a `window.config`
entry or a `?customization=` JSON module can add a whole capability pack (such as the
segmentation editing tools), remove a default, or swap the panels — targeting the mode
through a `mode` phase block (`mode.basic`, `mode.segmentation`, ...) without building
a new mode. See [Compose whole capability blocks into a mode][compose-capability-blocks] in the
Customization Service docs for the full key table, the reusable capability
blocks, and worked examples (adding segmentation editing to the basic and
longitudinal modes, and enabling annotation tools inside the segmentation mode).

[immutability-helper]: https://github.com/kolodny/immutability-helper
[compose-capability-blocks]: ../services/customization-service/specificCustomizations.md#4-compose-whole-capability-blocks-into-a-mode

### Consuming Extensions

As mentioned in the [Extensions](../extensions/index.md) section, in `OHIF-v3`
developers write their extensions to create reusable functionalities that later
can be used by `modes`. Now, it is time to describe how the registered
extensions will get utilized for a workflow mode via its `id`.

Each `mode` has a list of its `extensions dependencies` which are the
the `extension` name and version number. In addition, to use a module element you can use the
`${extensionId}.${moduleType}.${element.name}` schema. For instance, if a mode
requires the left panel with name of `AIPanel` that is added by the
`myAIExtension` via the following `getPanelModule` code, it should address it as
`myAIExtension.panelModule.AIPanel` inside the mode configuration file. In the
background `OHIF` will handle grabbing the correct panel via `ExtensionManager`.

```js title="extensions/myAIExtension/getPanelModule.js"
import PanelAI from './PanelAI.js';

function getPanelModule({
  commandsManager,
  extensionManager,
  servicesManager,
}) {
  const wrappedAIPanel = () => {
    return (
      <PanelAI
        commandsManager={commandsManager}
        servicesManager={servicesManager}
      />
    );
  };

  return [
    {
      name: 'AIPanel',
      iconName: 'list-bullets',
      iconLabel: '',
      label: 'AI Panel',
      isDisabled: studies => {}, // optional
      component: wrappedAIPanel,
    },
  ];
}
```

Now, let's look at a simplified code of the `basic viewer` mode which consumes various functionalities
from different extensions.

```js

const extensionDependencies = {
  '@ohif/extension-default': '^3.0.0',
  '@ohif/extension-cornerstone': '^3.0.0',
  '@ohif/extension-measurement-tracking': '^3.0.0',
};

const id = 'viewer';
const version = '3.0.0';

function modeFactory({ modeConfiguration }) {
  return {
    id,
    // ...
    routes: [
      {
        // ...
        layoutTemplate: ({ location, servicesManager }) => {
          return {
            id: ohif.layout,
            props: {
              leftPanels: ['@ohif/extension-measurement-tracking.panelModule.seriesList'],
              rightPanels: ['@ohif/extension-measurement-tracking.panelModule.trackedMeasurements'],
              viewports: [
                {
                  namespace: '@ohif/extension-measurement-tracking.viewportModule.cornerstone-tracked',
                  displaySetsToDisplay: ['@ohif/extension-default.sopClassHandlerModule.stack'],
                },
              ],
            },
          };
        },
      },
    ],
    extensions: extensionDependencies,
    hangingProtocol: ['@ohif/extension-default.hangingProtocolModule.petCT'],
    sopClassHandlers: ['@ohif/extension-default.sopClassHandlerModule.stack'],
    // ...
  };
}

const mode = {
  id,
  modeFactory,
  extensionDependencies,
}

export default mode
```

### Routes

routes config is an array of route settings, and the overall look and behavior
of the viewer at the designated route is defined by the `layoutTemplate` and
`init` functions for the route. We will learn more about each of the above
properties inside the [route documentation](./routes.md)


### HangingProtocols

Currently, you can pass your defined hanging protocols inside the
`hangingProtocols` property of the mode's config. If you specify the hanging protocol
explicitly by its name (only string and not array), it will be THE hanging protocol
that the mode runs with. However, if you specify an array of hanging protocols,
they will get ranked based on the displaySetSelector requirements and the winner
will be the hanging protocol that the mode runs with.


### SopClassHandlers

Mode's configuration also accepts the `sopClassHandler` modules that have been
added by the extensions. This information will get used to initialize `DisplaySetService` with the provided SOPClass modules which
handles creation of the displaySets.


### Hotkeys

`hotkeys` is another property in the configuration of a mode that can be defined
to add the specific hotkeys to the viewer on the mode route.  Additionally, the
name under which the hotkeys are stored can be configured as `hotkeyName`.
This allows user customization of the mode specific hotkeys.

```js
// default hotkeys
import { utils } from '@ohif/ui';

const { hotkeys } = utils;

const myHotkeys = [
  {
    commandName: 'setToolActive',
    commandOptions: { toolName: 'Zoom' },
    label: 'Zoom',
    keys: ['z'],
    isEditable: true,
  },
  {
    commandName: 'scaleUpViewport',
    label: 'Zoom In',
    keys: ['+'],
    isEditable: true,
  },
]

function modeFactory() {
  return {
    id: '',
    displayName: '',
    /*
    ...
    */
    hotkeys: {
      // The name in preferences to use for this set of hotkeys
      // Allows defining different sets for different modes
      name: 'custom-hotkey-name',
      // And the actual custom values here.
      hotkeys:[..hotkeys.defaults.hotkeyBindings, ...myHotkeys]
    },
  }
}

// exports
```





## Registration

Similar to extension registration, `viewer` will look inside the `pluginConfig.json` to
find the `modes` to register.


```js title=platform/app/pluginConfig.json
// Simplified version of the `pluginConfig.json` file
{
  "extensions": [
    {
      "packageName": "@ohif/extension-cornerstone",
      "version": "3.4.0"
    },
    // ...
  ],
  "modes": [
    {
      "packageName": "@ohif/mode-longitudinal",
      "version": "3.4.0"
    }
  ]
}
```

:::note
You can register modes by editing the `pluginConfig.json` file directly.
The provided `cli` can also add/remove/install/uninstall modes
([read more](../../development/ohif-cli.md)), but it is being phased out in
favour of generating modes with an agent.
:::

For the full set of entry fields and the three ways a plugin can be located
(in-tree, out-of-tree `directory`, or installed dependency), see the
[pluginConfig.json reference](../extensions/pluginConfig.md).

The final registration and import of the modes happen inside a non-tracked file `pluginImport.js` (this file is also for internal use only).


:::note
You can stack multiple panel components on top of each other by providing an array of panel components in the `rightPanels` or `leftPanels` properties.

For instance we can use

```
rightPanels: [[dicomSeg.panel, tracked.measurements], [dicomSeg.panel, tracked.measurements]]
```

This will result in two panels, one with `dicomSeg.panel` and `tracked.measurements` and the other with `dicomSeg.panel` and `tracked.measurements` stacked on top of each other.

:::

## APP Configuration of Modes

Modes based on the `basic` mode allow for customization using the `immutability-helper`
api within the `app-config.js` file as specified by the build process.  For example,
to list the `basic` mode by default, and hide the `longitudinal` mode, the following
configuration from `config/kheops.js` can be used:

```
... app config file
  modesConfiguration: {
    '@ohif/mode-basic': {
      hide: { $set: false },
      displayName: { $set: 'Basic' },
    },
    '@ohif/mode-longitudinal': {
      hide: { $set: true },
    },
  },
```

## Default Modes

There are a number of modes provided in a default OHIF installation.  These
are described here, along with some amount of information about extending/configuration
of those modes.

Modes which are loaded by default, but which are hidden can be activated by
using a direct URL launch.  For example, to show a study in the `basic` mode,
use the URL for the `longitudinal` mode, and replace the `/viewer` with `/basic`

### Basic (NOT `Basic Viewer`, which got assigned to `longitudinal`)

The basic mode is a mode that demonstrates the base capabilities of the OHIF
system, without including features such as longitudinal tracking, segmentation editing
or other custom capabilities. The left hand panel uses the study browser thumbnails
without tracking, and the right hand panel uses the basic segmentation panel and the
measurements without tracking (longitudinal) layouts.  This makes it a good overall
base for using when the tracking behaviour of longitudinal mode is not desired.

It can be used in a default install by direct URL launch to the `/basic` endpoint
instead of the `/viewer` endpoint.

### Longitudinal (The `Basic Viewer` label in OHIF)

The longitudinal mode adds the tracking for measurements in the study browser
and in the measurements panel, and is otherwise identical to the `basic` mode.

---

### Platform Docs Docs Platform Services Index (`platform/docs/docs/platform/services/index.md`)

---
sidebar_position: 1
sidebar_label: Introduction
title: OHIF Services
summary: Overview of OHIF's services architecture, which provides modular, concern-specific code components that manage state and operations throughout the application, including both data services and UI services that follow a pub/sub pattern to reduce coupling.
---

# Services

## Overview

Services are "concern-specific" code modules that can be consumed across layers.
Services provide a set of operations, often tied to some shared state, and are
made available to through out the app via the `ServicesManager`. Services are
particularly well suited to address [cross-cutting
concerns][cross-cutting-concerns].

Each service should be:

- self-contained
- able to fail and/or be removed without breaking the application
- completely interchangeable with another module implementing the same interface

> In `OHIF-v3` we have added multiple non-UI services and have introduced
> **pub/sub** pattern to reduce coupling between layers.
>
> [Read more about Pub/Sub](./pubsub.md)

## Services

The following services is available in the `OHIF-v3`.

<table>
    <thead>
        <tr>
            <th>Service</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <a href="./data/DicomMetadataStore">
                    DicomMetadataStore
                </a>
            </td>
            <td>Data Service</td>
            <td>
                DicomMetadataStore
            </td>
        </tr>
        <tr>
            <td>
                <a href="./data/DisplaySetService">
                    DisplaySetService
                </a>
            </td>
            <td>Data Service</td>
            <td>
                DisplaySetService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./data/SegmentationService">
                    segmentationService
                </a>
            </td>
            <td>Segmentation Service</td>
            <td>
                segmentationService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./data/HangingProtocolService">
                    HangingProtocolService
                </a>
            </td>
            <td>Data Service</td>
            <td>
                HangingProtocolService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./data/MeasurementService">
                    MeasurementService (MODIFIED)
                </a>
            </td>
            <td>Data Service</td>
            <td>
                MeasurementService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./data/ToolBarService">
                    ToolBarService
                </a>
            </td>
            <td>Data Service</td>
            <td>
                ToolBarService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./data/ViewedDataService">
                    ViewedDataService
                </a>
            </td>
            <td>Data Service</td>
            <td>
                viewedDataService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./ui/viewport-grid-service">
                    ViewportGridService
                </a>
            </td>
            <td>UI Service</td>
            <td>
                ViewportGridService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./ui/cine-service">
                    Cine Service
                </a>
            </td>
            <td>UI Service</td>
            <td>
                cine
            </td>
        </tr>
        <tr>
            <td>
                <a href="./customization-service">
                    CustomizationService
                </a>
            </td>
            <td>UI Service</td>
            <td>
                customizationService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./ui/ui-dialog-service">
                    UIDialogService
                </a>
            </td>
            <td>UI Service</td>
            <td>
                UIDialogService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./ui/ui-modal-service">
                    UIModalService
                </a>
            </td>
            <td>UI Service</td>
            <td>
                UIModalService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./ui/ui-notification-service">
                    UINotificationService
                </a>
            </td>
            <td>UI Service</td>
            <td>
                UINotificationService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./ui/ui-viewport-dialog-service">
                    UIViewportDialogService
                </a>
            </td>
            <td>UI Service</td>
            <td>
                UIViewportDialogService
            </td>
        </tr>
    </tbody>
</table>





[core-services]: https://github.com/OHIF/Viewers/tree/master/platform/core/src/services
[services-manager]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/services/ServicesManager.js
[cross-cutting-concerns]: https://en.wikipedia.org/wiki/Cross-cutting_concern

---

### Platform Docs Docs User Guide Viewer Index (`platform/docs/docs/user-guide/viewer/index.md`)

---
sidebar_position: 1
sidebar_label: Overview
---


# Overview
When you open a mode, viewport, toolbar and panels of the mode get shown.
It is important to note that each mode has a different UI, which serves its purpose.
Here we explain various components of `Basic Viewer` mode which includes measurement
tracking functionalities.

Basic viewer mode (longitudinal):



Let's break different aspects of the viewer to the main components:

- Left Panel (study panel): displays series thumbnails with series details
- Viewport: renders the image and displays annotations
- Right Panel (measurements): displays annotations details
- Toolbar: displays tools and logo






Now, we explain each component and its sub-elements in detail.

---

### Platform Docs Versioned Docs Version 3.11 Deployment Index (`platform/docs/versioned_docs/version-3.11/deployment/index.md`)

---
sidebar_position: 1
sidebar_label: Overview
title: Deployment Overview
summary: Comprehensive guide to deploying the OHIF Viewer as a standalone web application or embedded iframe, covering data source configuration, security considerations, and various deployment options with examples for different hosting environments.
---

# Deployment

The OHIF Viewer can be served as a stand-alone PWA ([progressive web
application][pwa-url]) by building and hosting a collection of static assets or be embedded in other web applications via an iframe if needed. In
either case, you will need to configure your instance of the Viewer so that it
can connect to your data source (the database or PACS that provides the data
your Viewer will display).

:::tip
Our goal is to make deployment as simple and painless as possible; however,
there is an inherent amount of complexity in configuring and deploying web
applications. If you find yourself a little lost, please don't hesitate to
reach out to for help.
:::

## Deployment Scenarios

### Stand-alone Viewer

Deploying the OHIF Viewer as a stand-alone web application provides many
benefits, but comes at the cost of time and complexity. Some benefits include:

_Today:_

- Leverage [extensions](../platform/extensions/index.md) and
  [modes](../platform/modes/index.md) to drop-in powerful new features
- Add routes and customize the viewer's workflow
- Finer control over styling and whitelabeling

_In the future:_

- The ability to package the viewer for [App Store distribution][app-store]

#### Hosted Static Assets

At the end of the day, a production OHIF Viewer instance is a collection of
HTML, CSS, JS, Font Files, and Images. We "build" those files from our
`source code` with configuration specific to our project. We then make those
files publicly accessible by hosting them on a Web Server.

##### Part 1 - Build Production Assets

"Building", or creating, the files you will need is the same regardless of the
web host you choose. You can find detailed instructions on how to configure and
build the OHIF Viewer in our
["Build for Production" guide](./build-for-production.md).

##### Part 2 - Host Your App

There are a lot of [benefits to hosting static assets][host-static-assets] over
dynamic content. You can find instructions on how to host your build's output
via one of these guides:

_Drag-n-drop_

- [Netlify: Drop](./static-assets.md#netlify-drop)

_Easy_

- [Surge.sh](./static-assets.md#surgesh)
- [GitHub Pages](./static-assets.md#github-pages)

_Advanced_

- [AWS S3 + Cloudfront](./static-assets.md#aws-s3--cloudfront)
- [GCP + Cloudflare](./static-assets.md#gcp--cloudflare)
- [Azure](./static-assets.md#azure)

### Embedded Viewer (iframe)

`OHIF-v3` has deprecated deploying the viewer as an embedded viewer via a script
tag as the number of underlying libraries that run web workers are increasing for OHIF. An example of these libraries is OHIF's 3D rendering functionality that is provided by
`vtk-js`.

However, you can still embed the viewer using an iframe. You can utilize the iframe element to load the OHIF viewer and establish communication with it using the postMessage API if needed.
Read more about how to use the iframe [here](./iframe.md).


## Data

The OHIF Viewer is able to connect to any data source that implements the [DICOM
Web Standard][dicom-web-standard]. [DICOM Web][dicom-web] refers to RESTful
DICOM Services -- a recently standardized set of guidelines for exchanging
medical images and imaging metadata over the internet. Not all archives fully
support it yet, but it is gaining wider adoption.

### Configure Connection

If you have an existing archive and intend to host the OHIF Viewer at the same
domain name as your archive, then connecting the two is as simple as following
the steps laid out in our
[Configuration Essentials Guide](./../configuration/configurationFiles.md).

#### What if I don't have an imaging archive?

We provide some guidance on configuring a local image archive in our
[Data Source Essentials](./../configuration/dataSources/introduction.md)
guide. Hosting an archive remotely is a little trickier. You can check out some
of our [advanced recipes](#recipes) for modeled setups that may work for you.

#### What if I intend to host the OHIF Viewer at a different domain?

There are two important steps to making sure this setup works:

1. Your Image Archive needs to be exposed, in some way, to the open web. This
   can be directly, or through a `reverse proxy`, but the Viewer needs _some
   way_ to request its data.
2. \* Your Image Archive needs to have appropriate CORS (Cross-Origin Resource
   Sharing) Headers

> \* Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional
> HTTP headers to tell a browser to let a web application running at one origin
> (domain) have permission to access selected resources from a server at a
> different origin. - [MDN Web Docs: Web - Http - CORS][cors]

Most image archives do not provide either of these features "out of the box".
It's common to use IIS, Nginx, or Apache to route incoming requests and append
appropriate headers. You can find an example of this setup in our
[Nginx + Image Archive Deployment Recipe](./nginx--image-archive.md).

#### What if my archive doesn't support DicomWeb?

It's possible to supply all Study data via JSON format, in the event you do not
have a DicomWeb endpoint. You can host all of the relevant files on any web
accessible server (Amazon S3, Azure Blob Storage, Local file server etc.)

This JSON is supplied via the '?url=' query parameter. It should reference an
endpoint that returns **application/json** formatted text.

If you do not have an API, you can simply return a text file containing the JSON
from any web server.

You tell the OHIF viewer to use JSON by using the `dicomjson` datasource and
appending `'?url='` query to your mode's route:

e.g.
`https://my-test-ohif-server/myMode/dicomjson?url=https://my-json-server/study-uid.json`

The returned JSON object must contain a single root object with a 'studies'
array.

You can read more about using different data sources for mode's routes
[here](../platform/modes/routes.md#route-path)

_Sample JSON format:_

```
/* Detailed source-code truncated for AI context efficiency. */
```

More info on this JSON format can be found here
[Issue #1500](https://github.com/OHIF/Viewers/issues/1500)

**Implementation Notes:**



1. For each instance url (dicom object) in the returned JSON, you must prefix
   the `url` with `dicomjson:` in order for the cornerstone image loader to
   retrieve it correctly. eg. `https://image-server/my-image.dcm` --->
   `dicomjson:https://image-server/my-image.dcm`
2. The JSON format above is compatible with >= v3.7.8 of the application in `V2`
   version. Older versions of the viewer used a different JSON format. As of
   20/04/20 the public [https://viewer.ohif.org/] is a pre 3.0 version that does
   not support this format yet.
3. The JSON format is case-sensitive. Please ensure you have matched casing with
   the naturalised Dicom format referenced in
   [Issue #1500](https://github.com/OHIF/Viewers/issues/1500).

_CORS Issues (Cross-Origin Resource Sharing)_

If you host a JSON API or Images on a different domain from the app itself,
you will likely have CORS issues. This will also happen when testing from
Localhost and reaching out to remote servers. Even if the domain is the same,
different ports, subdomains or protocols (https vs http) will also cause CORS
errors. You will to need add a configuration on each server hosting these assets
to allow your App server origin.

For example:

Let's assume your application is hosted on `https://my-ohif-server.com`.

Your JSON API is hosted on `https://my-json-api.aws.com`

And your images are stored on Amazon S3 at `https://my-s3-bucket.aws.com`

When you first start your application, browsing to
`https://my-ohif-server.com/myMode/dicomjson?url=https://my-json-api.aws.com/api/my-json-study-info.json`,
you will likely get a CORS error in the browser console as it tries to connect
to `https://my-json-api.aws.com`.

Adding a setting on the JSON server to allow the CORS origin =
`https://my-ohif-server.com` should solve this.

Next, you will likely get a similar CORS error, as the browser tries to go to
`https://my-s3-bucket.aws.com`. You will need to go to the S3 bucket
configuration, and add a CORS setting to allow origin =
`https://my-ohif-server.com`.

Essentially, whenever the application connects to a remote resource, you will
need to add the applications url to the allowed CORS Origins on that resource.
Adding an origin similar to https://localhost:3000 will also allow for local
testing.

### Securing Your Data

Coming soon



### Recipes

We've included a few recipes for common deployment scenarios. There are many,
many possible configurations, so please don't feel limited to these setups.
Please feel free to suggest or contribute your own recipes.

- [Build for Production](./build-for-production.md)
- [Static](./static-assets.md)
- [Nginx + Image Archive](./nginx--image-archive.md)
- [User Account Control](./user-account-control.md)




[viewer-npm]: https://www.npmjs.com/package/@ohif/app
[pwa-url]: https://developers.google.com/web/progressive-web-apps/
[static-assets-url]: https://www.maxcdn.com/one/visual-glossary/static-content/
[app-store]: https://medium.freecodecamp.org/i-built-a-pwa-and-published-it-in-3-app-stores-heres-what-i-learned-7cb3f56daf9b
[dicom-web-standard]: https://www.dicomstandard.org/dicomweb/
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
[host-static-assets]: https://www.netlify.com/blog/2016/05/18/9-reasons-your-site-should-be-static/
[cors]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
[code-flows]: https://medium.com/@darutk/diagrams-of-all-the-openid-connect-flows-6968e3990660
[code-sandbox]: https://codesandbox.io/s/viewer-script-tag-tprch

---

### Platform Docs Versioned Docs Version 3.11 Development Getting Started (`platform/docs/versioned_docs/version-3.11/development/getting-started.md`)

---
sidebar_position: 1
sidebar_label: Getting Started
title: Getting Started with OHIF Development
summary: Quick start guide for OHIF development, covering repository setup options, branch organization, development environment requirements, project initialization, and steps for building production-ready assets.
---

# Getting Started

## Setup

### Fork & Clone

If you intend to contribute back changes, or if you would like to pull updates
we make to the OHIF Viewer, then follow these steps:

- [Fork][fork-a-repo] the [OHIF/Viewers][ohif-viewers-repo] repository
- [Create a local clone][clone-a-repo] of your fork
  - `git clone https://github.com/YOUR-USERNAME/Viewers`
- Add OHIF/Viewers as a [remote repository][add-remote-repo] labeled `upstream`
  - Navigate to the cloned project's directory
  - `git remote add upstream https://github.com/OHIF/Viewers.git`

With this setup, you can now [sync your fork][sync-changes] to keep it
up-to-date with the upstream (original) repository. This is called a "Triangular
Workflow" and is common for Open Source projects. The GitHub blog has a [good
graphic that illustrates this setup][triangular-workflow].


### Private

Alternatively, if you intend to use the OHIF Viewer as a starting point, and you
aren't as concerned with syncing updates, then follow these steps:

1. Navigate to the [OHIF/Viewers][ohif-viewers] repository
2. Click `Clone or download`, and then `Download ZIP`
3. Use the contents of the `.zip` file as a starting point for your viewer

> NOTE: It is still possible to sync changes using this approach. However,
> submitting pull requests for fixes and features are best done with the
> separate, forked repository setup described in "Fork & Clone"

## Developing


### Branches

#### `master` branch - The latest dev (beta) release

- `master` - The latest dev release

This is typically where the latest development happens. Code that is in the master branch has passed code reviews and automated tests, but it may not be deemed ready for production. This branch usually contains the most recent changes and features being worked on by the development team. It's often the starting point for creating feature branches (where new features are developed) and hotfix branches (for urgent fixes).

Each package is tagged with beta version numbers, and published to npm such as `@ohif/ui@3.6.0-beta.1`

### `release/*` branches - The latest stable releases
Once the `master` branch code reaches a stable, release-ready state, we conduct a comprehensive code review and QA testing. Upon approval, we create a new release branch from `master`. These branches represent the latest stable version considered ready for production.

For example, `release/3.5` is the branch for version 3.5.0, and `release/3.6` is for version 3.6.0. After each release, we wait a few days to ensure no critical bugs. If any are found, we fix them in the release branch and create a new release with a minor version bump, e.g., 3.5.1 in the `release/3.5` branch.

Each package is tagged with version numbers and published to npm, such as `@ohif/ui@3.5.0`. Note that `master` is always ahead of the `release` branch. We publish docker builds for both beta and stable releases.

Here is a schematic representation of our development workflow:





### Requirements

- [Node.js & NPM](https://nodejs.org/en/)
- [Yarn](https://yarnpkg.com/en/)
- Yarn workspaces should be enabled:
  - `yarn config set workspaces-experimental true`

### Kick the tires

Navigate to the root of the project's directory in your terminal and run the
following commands:

```bash
# Restore dependencies
yarn install

# Start local development server
yarn run dev
```

You should see the following output:

```bash
@ohif/app: i ｢wds｣: Project is running at http://localhost:3000/
@ohif/app: i ｢wds｣: webpack output is served from /
@ohif/app: i ｢wds｣: Content not from webpack is served from D:\code\ohif\Viewers\platform\viewer
@ohif/app: i ｢wds｣: 404s will fallback to /index.html

# And a list of all generated files
```

### 🎉 Celebrate 🎉

<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/843233770?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>

### Building for Production

> More comprehensive guides for building and publishing can be found in our
> [deployment docs](./../deployment/index.md)

```bash
# Build static assets to host a PWA
yarn run build
```

## Troubleshooting

- If you receive a _"No Studies Found"_ message and do not see your studies, try
  changing the Study Date filters to a wider range.
- If you see a 'Loading' message which never resolves, check your browser's
  JavaScript console inside the Developer Tools to identify any errors.




[fork-a-repo]: https://help.github.com/en/articles/fork-a-repo
[clone-a-repo]: https://help.github.com/en/articles/fork-a-repo#step-2-create-a-local-clone-of-your-fork
[add-remote-repo]: https://help.github.com/en/articles/fork-a-repo#step-3-configure-git-to-sync-your-fork-with-the-original-spoon-knife-repository
[sync-changes]: https://help.github.com/en/articles/syncing-a-fork
[triangular-workflow]: https://github.blog/2015-07-29-git-2-5-including-multiple-worktrees-and-triangular-workflows/#improved-support-for-triangular-workflows
[ohif-viewers-repo]: https://github.com/OHIF/Viewers/
[ohif-viewers]: https://github.com/OHIF/Viewers

---

### Platform Docs Versioned Docs Version 3.11 Faq Index (`platform/docs/versioned_docs/version-3.11/faq/index.md`)

---
id: index
title: OHIF Viewer FAQ
summary: Comprehensive list of frequently asked questions about the OHIF Viewer, covering common inquiries about reporting bugs, requesting features, academic collaborations, regulatory status, and obtaining demo studies.
---


# General FAQ


## How do I report a bug?

Navigate to our [GitHub Repository][new-issue], and submit a new bug report.
Follow the steps outlined in the [Bug Report Template][bug-report-template].

## How can I request a new feature?

At the moment we are in the process of defining our roadmap and will do our best
to communicate this to the community. If your requested feature is on the
roadmap, then it will most likely be built at some point. If it is not, you are
welcome to build it yourself and [contribute it](../development/contributing.md).
If you have resources and would like to fund the development of a feature,
please [contact us](https://ohif.org/get-support).


## Who should I contact about Academic Collaborations?

[Gordon J. Harris](https://www.dfhcc.harvard.edu/insider/member-detail/member/gordon-j-harris-phd/)
at Massachusetts General Hospital is the primary contact for any academic
collaborators. We are always happy to hear about new groups interested in using
the OHIF framework, and may be able to provide development support if the
proposed collaboration has an impact on cancer research.

## Does OHIF offer support?

yes, you can contact us for more information [here](https://ohif.org/get-support)


## Does The OHIF Viewer have [510(k) Clearance][501k-clearance] from the U.S. F.D.A or [CE Marking][ce-marking] from the European Commission?

**NO.** The OHIF Viewer is **NOT** F.D.A. cleared or CE Marked. It is the users'
responsibility to ensure compliance with applicable rules and regulations. The
[License](https://github.com/OHIF/Viewers/blob/master/LICENSE) for the OHIF
Platform does not prevent your company or group from seeking F.D.A. clearance
for a product built using the platform.

If you have gone this route (or are going there), please let us know because we
would be interested to hear about your experience.

## Is there a DICOM Conformance Statement for the OHIF Viewer?

Yes, check it here [DICOM Conformance Statement](https://docs.google.com/document/d/1hbDlUApX4svX33gAUGxGfD7fXXZNaBsX0hSePbc-hNA/edit?usp=sharing)

## Is The OHIF Viewer [HIPAA][hipaa-def] Compliant?

**NO.** The OHIF Viewer **DOES NOT** fulfill all of the criteria to become HIPAA
Compliant. It is the users' responsibility to ensure compliance with applicable
rules and regulations.

## Could you provide me with a particular study from the OHIF Viewer Demo?

You can check out the studies that we have put in this [Dropbox link](https://www.dropbox.com/scl/fo/66xidsx13pn0zf3b9cbfq/ADaCgn7aT29WMlnTdT_WRXM?rlkey=rratvx6g4kfxnswjdbupewjye&dl=0)






[general]: #general
[technical]: #technicalß˚
[report-bug]: #how-do-i-report-a-bug
[new-feature]: #how-can-i-request-a-new-feature
[commercial-support]: #does-ohif-offer-commercial-support
[academic]: #who-should-i-contact-about-academic-collaborations
[fda-clearance]: #does-the-ohif-viewer-have-510k-clearance-from-the-us-fda-or-ce-marking-from-the-european-commission
[hipaa]: #is-the-ohif-viewer-hipaa-compliant
[501k-clearance]: https://www.fda.gov/MedicalDevices/DeviceRegulationandGuidance/HowtoMarketYourDevice/PremarketSubmissions/PremarketNotification510k/
[ce-marking]: https://ec.europa.eu/growth/single-market/ce-marking_en
[hipaa-def]: https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act
[new-issue]: https://github.com/OHIF/Viewers/issues/new/choose
[bug-report-template]: https://github.com/OHIF/Viewers/issues/new?assignees=&labels=Bug+Report+%3Abug%3A&template=---bug-report.md&title=

---

### Platform Docs Versioned Docs Version 3.11 Migration Guide Index (`platform/docs/versioned_docs/version-3.11/migration-guide/index.md`)

---
id: index
title: Migration Guides Overview
summary: Introduction to OHIF migration guides covering the upgrade paths between different versions of the platform, with links to version-specific guides for migrating from one OHIF version to another.
---


import DocCardList from '@theme/DocCardList';

# Migration Guides

Based on the version you are migrating from, you can find the migration guide for the latest version of the platform.

<DocCardList />

---

### Platform Docs Versioned Docs Version 3.11 User Guide Index (`platform/docs/versioned_docs/version-3.11/user-guide/index.md`)

---
sidebar_position: 2
sidebar_label: Study List
---

# Study List

## Overview

The first page you will see when the viewer is loaded is the `Study List`. In
this page you can explore all the studies that are stored on the configured
server for the `OHIF Viewer`.



## Sorting

When the Study List is opened, the application queries the PACS for 101 studies
by default. If there are greater than 100 studies returned, the default sort for
the study list is dictated by the image archive that hosts these studies for the
viewer and study list sorting will be disabled. If there are less than or equal
to 100 studies returned, they will be sorted by study date (most recent to
oldest) and study list sorting will be enabled. Whenever a query returns greater
than 100 studies, use filters to narrow results below 100 studies to enable
Study List sorting.

## Filters

There are certain filters that can be used to limit the study list to the
desired criteria.

- Patient Name: Searches between patients names
- MRN: Searches between patients Medical Record Number
- Study Date: Filters the date of the acquisition
- Description: Searches between study descriptions
- Modality: Filters the modalities
- Accession: Searches between patients accession number

An example of using study list filter is shown below:



Below the study list are pagination options for 25, 50, or 100 studies per page.



For static wado servers, you can enable fuzzy matching by setting the `supportsFuzzyMatching` property to true, after enabling it, fuzzy matching will be peformed on the patient name field, for example, if PatientName is "John^Doe", then "jo", "Do" and "John Doe" will all match. However "ohn" will not match.

## Study Summary

Click on a study to expand the study summary panel.



A summary of series available in the study is shown, which contains the series
description, series number, modality of the series, instances in the series, and
buttons to launch viewer modes to display the study.

## Study Specific Modes

All available modes are seen in the study expanded view. Modes can be enabled or
disabled for a study based on the modalities contained within the study.

In the screenshot below, there are two modes shown for the selected study

- Basic Viewer: Default mode that enables rendering and measurement tracking

- PET/CT Fusion: Mode for visualizing the PET CT study in a 3x3 format.

Based on the mode configurations (e.g., available modalities), PET/CT mode is
disabled for studies that do not contain PET AND CT images.





The previous screenshot shows a study containing PET and CT images and both
Basic Viewer and PET/CT Mode are available.

## View Study

The `Basic Viewer` mode is available for all studies by default. Click on the
mode button to launch the viewer.

---

### Platform Docs Docs Migration Guide 3p8 To 3p9 1 Segmentation Index (`platform/docs/docs/migration-guide/3p8-to-3p9/1-segmentation/index.md`)

---
id: segmentation-index
title: Segmentation
sidebar_position: 1
summary: Migration guide for segmentation architecture changes in OHIF 3.9, covering the shift from tool group-centric to viewport-centric architecture to support advanced visualization capabilities and more flexible segmentation handling.
---

import DocCardList from '@theme/DocCardList';

:::info
This migration involves significant architectural changes to the segmentation system. While we typically aim for incremental updates, the shift from a tool group-centric to a viewport-centric architecture was necessary to support OHIF 3.9's advanced visualization capabilities, and more flexible segmentation handling.

Don't worry - we'll guide you through each change step by step!
:::


<DocCardList />

---

### Platform Docs Docs Migration Guide 3p9 To 3p10 2 CustomizationService Index (`platform/docs/docs/migration-guide/3p9-to-3p10/2-CustomizationService/index.md`)

---
sidebar_position: 2
title: Customization Service
summary: Migration guide for OHIF's Customization Service from 3.9 to 3.10, covering unified customization getters, simplified registration, new commands, renamed customizations, and updated patterns for modifying UI components.
---

# CustomizationService



**Key Changes:**


1. **Unified Customization Getter:**
   - The `getCustomization` method now uniformly retrieves customizations, prioritizing `global`, then `mode`, and finally `default` customizations.
   - The `defaultValue` parameter in `getCustomization` is no longer used for setting defaults. It simply returns if no customization is found.
   - The methods `getModeCustomization` and `getGlobalCustomization` are deprecated.

2. **Simplified Customization Registration:**
   - The `customizationType` property in customization definitions is renamed to `inheritsFrom`.
   - The `merge` property in customization definitions is removed. Instead, a customization is merged using the helper methods. The basic update commands are listed in the table below, and you can learn more about the helper methods [here](../../../platform/services/customization-service/customizationService.md).

     | Command  | Description                               | Example                                           |
     | :------- | :---------------------------------------- | :------------------------------------------------ |
     | `$set`   | Replace a value entirely                 | Replace a list or object                        |
     | `$push`  | Append items to an array                 | Add to the end of a list                        |
     | `$unshift` | Prepend items to an array                | Add to the start of a list                      |
     | `$splice` | Insert, remove, or replace at specific index | Modify specific indices in a list                 |
     | `$merge` | Update specific fields in an object      | Change a subset of fields                       |
     | `$apply` | Compute the new value dynamically        | Apply a function to transform values              |
     | `$filter` | Find and update specific items in arrays | Target nested structures based on matching criteria |


3. **New `$transform` command:**
   - If you were using the `transform` command, you should now use the `$transform` command. Just a simple rename to make it more consistent with the other commands.


5. **Renamed `CornerstoneOverlay` customizations:**
   - The `cornerstoneOverlay` customizations (`cornerstoneOverlayTopLeft`, `cornerstoneOverlayTopRight`, `cornerstoneOverlayBottomLeft`, `cornerstoneOverlayBottomRight`) have been renamed to `viewportOverlay.topLeft`, `viewportOverlay.topRight`, `viewportOverlay.bottomLeft`, and `viewportOverlay.bottomRight`. See dedicated page for customizing viewport overlays [here](../../../platform/services/customization-service/viewportOverlay.md).

6. **Renamed `customRoutes`:**
   - The `customRoutes` customization is renamed to `routes.customRoutes`.

7.  **`contextMenu` customization:**
    - The `contextMenu` customization now uses the `inheritsFrom` property to inherit from other context menus, previously it was called `customizationType`

8. **New `immutability-helper` dependency:**
   The `immutability-helper` library is now used for merging customizations. If you encounter an error related to it, you'll need to install it - though OHIF should really handle the installation for you, so this is pretty much just a heads up.

**Migration Steps:**

1. **Replace `getModeCustomization` and `getGlobalCustomization` with `getCustomization`:**

   - **Before:**

     ```javascript
     const tools = customizationService.getModeCustomization(
       'cornerstone.overlayViewportTools'
     )?.tools;
     const globalValue = customizationService.getGlobalCustomization('someGlobalKey');
     ```

   - **After:**

     ```javascript
     const tools = customizationService.getCustomization('cornerstone.overlayViewportTools');
     const globalValue = customizationService.getCustomization('someGlobalKey');
     ```


     :::note
     The returned value is the actual customization value, not an object that needs to be broken down.
     :::

2. **Update Customization Definitions:**
   - We've moved away from using random items in the customization definition, and now we use the `id` property to identify the customization as a value. Previously, it was referred to as `value`, `values`, and so on, but now an `id` is used to reference the customization. This approach really simplifies things - when you need to grab the customization, you can just use the `id` to get it, and you don't have to bother with destructuring the value from the object.




**Example: Customizing a Panel**

**Before (v3.9):**

```javascript
// the default value was hardcoded inside the panel itself - bad idea!
// default was given in the panel itself

// PanelSegmentation.tsx

// Retrieve the onSegmentationAdd customization
const { onSegmentationAdd } = customizationService.getCustomization(
  'PanelSegmentation.onSegmentationAdd',
  {
    id: 'segmentation.onSegmentationAdd',
    onSegmentationAdd: handlers.onSegmentationAdd,
  }
);

// Retrieve the disableEditing customization
const { disableEditing } = customizationService.getCustomization(
  'PanelSegmentation.disableEditing',
  {
    id: 'default.disableEditing',
    disableEditing: false,
  }
);



// mode was customizing it via
customizationService.addModeCustomizations([
  {
    id: 'PanelSegmentation.tableMode',
    mode: 'expanded',
  },
  {
    id: 'PanelSegmentation.showAddSegment',
    showAddSegment: false,
  },
]);

```

**After (v3.10):**

```javascript
// cornerstone extension getCustomizationModule
// centralized customization location for all extensions - good!
function getCustomizationModule() {
  return [
    {
      name: 'default',
      value: {
        'panelSegmentation.disableEditing': false,
        'panelSegmentation.showAddSegment': true,
      },
    },
  ];
}


// inside panelSegmentation.tsx
const disableEditing = customizationService.getCustomization('panelSegmentation.disableEditing');
const showAddSegment = customizationService.getCustomization('panelSegmentation.showAddSegment');


// mode can customize it via $ operators for mode customizations
customizationService.setCustomizations({
  'panelSegmentation.disableEditing': { $set: true },
  'panelSegmentation.showAddSegment': { $set: false },
});


//or via configuration for global customizations
window.config = {
  // rest of config
  customizationService: [
    {
      'panelSegmentation.disableEditing': {
        $set: true, // Disables editing of segmentations in the panel
      },
    },
  ],
  // rest of config
};
```



**Example: Updating a Customization**

Let's say you have a customization in v3.9 that adds a custom overlay item to the top-left corner:

**Before (v3.9):**

```javascript
// In your mode's onModeEnter
customizationService.addModeCustomizations([
  {
    id: 'cornerstoneOverlayTopLeft',
    items: [
      {
        id: 'myCustomOverlay',
        customizationType: 'ohif.overlayItem',
        attribute: 'PatientName',
        label: 'Patient:',
      },
    ],
  },
]);
```

**After (v3.10):**

```javascript
// In your mode's onModeEnter or elsewhere
customizationService.setCustomizations({
  'viewportOverlay.topLeft': {
    $push: [
      {
        id: 'myCustomOverlay',
        inheritsFrom: 'ohif.overlayItem',
        attribute: 'PatientName',
        label: 'Patient:',
      },
    ],
  },
});
```
```
**Example: Customizing viewport action Menu**

**Before (v3.9):**

```javascript
// In your configuration for global customizations
window.config = {
    // rest of config
    addWindowLevelActionMenu: true,
};
```

**After (v3.10):**

```javascript
// you can now handle each action menu item (windowLevelActionMenu and segmentationOverlay) separately

// cornerstone extension getCustomizationModule
function getCustomizationModule() {
    return [
        {
            name: 'default',
            value: {
                'viewportActionMenu.windowLevelActionMenu': {
                    enabled: true,
                    location: viewportActionCornersService.LOCATIONS.topRight,
                },
                'viewportActionMenu.segmentationOverlay': {
                    enabled: true,
                    location: viewportActionCornersService.LOCATIONS.topRight,
                },
            },
        },
    ];
}


// Accessing customizations within your component (e.g., OHIFCornerstoneViewport.tsx)
const windowLevelActionMenu = customizationService.getCustomization('viewportActionMenu.windowLevelActionMenu');
const segmentationOverlay = customizationService.getCustomization('viewportActionMenu.segmentationOverlay');

// Modifying customizations at runtime, for example, in your mode's onModeEnter
customizationService.setCustomizations({
    'viewportActionMenu.windowLevelActionMenu': {
        $set: {
            enabled: false,
            location: viewportActionCornersService.LOCATIONS.bottomLeft,
        },
    },
    'viewportActionMenu.segmentationOverlay': {
        $set: {
            enabled: true,
            location: viewportActionCornersService.LOCATIONS.topLeft,
        },
    },
});

// Alternatively, setting global customizations via configuration
window.config = {
    // rest of config
    customizationService: [
        {
            'viewportActionMenu.windowLevelActionMenu': {
                $set: {
                    enabled: false,
                    location: 1,
                },
            },
            'viewportActionMenu.segmentationOverlay': {
                $set: {
                    enabled: true,
                    location: 1,
                },
            },
        },
    ],
    // rest of config
};
```

**Note:**

- The `customizationType` is replaced with `inheritsFrom`.





## Renaming

To keep our customization system consistent, you should be aware of a few key renaming conventions. We now follow a straightforward naming convention for customizations: `scopeName.customizationItem`.



| Customization Key (Old)                     | Customization Key (New)                      | Description                                                                 |
| :------------------------------------------ | :------------------------------------------- | :-------------------------------------------------------------------------- |
| `PanelMeasurement.disableEditing`             | `panelMeasurement.disableEditing`              | Disables editing measurements in the Measurement Panel and after SR hydration. |
| `PanelSegmentation.CustomDropdownMenuContent` | `panelSegmentation.customDropdownMenuContent`  | Custom content for the dropdown menu in the Segmentation Panel.             |
| `PanelSegmentation.disableEditing`             | `panelSegmentation.disableEditing`              | Disables editing segmentations in the Segmentation Panel.                    |
| `PanelSegmentation.showAddSegment`             | `panelSegmentation.showAddSegment`              | Controls visibility of the "Add Segment" button in the Segmentation Panel.    |
| `PanelSegmentation.onSegmentationAdd`          | `panelSegmentation.onSegmentationAdd`           | Custom function to execute when a new segmentation is added.                 |
| `PanelSegmentation.tableMode`                | `panelSegmentation.tableMode`                 | Controls the table mode (collapsed/expanded) in the Segmentation Panel.       |
| `PanelSegmentation.readableText`             | `panelSegmentation.readableText`              | Custom readable text labels for the Segmentation Panel.                       |
| `PanelStudyBrowser.studyMode`                | `studyBrowser.studyMode`                     | Controls the study mode (all/primary/recent) in the Study Browser Panel.      |
| `customRoutes`                                | `routes.customRoutes`                         | Defines custom routes for the application.                                  |
| `cornerstoneOverlayTopLeft`                   | `viewportOverlay.topLeft`                    | Custom overlay items for the top-left corner of the viewport.                  |
| `cornerstoneOverlayTopRight`                  | `viewportOverlay.topRight`                   | Custom overlay items for the top-right corner of the viewport.                 |
| `cornerstoneOverlayBottomLeft`                | `viewportOverlay.bottomLeft`                 | Custom overlay items for the bottom-left corner of the viewport.              |
| `cornerstoneOverlayBottomRight`               | `viewportOverlay.bottomRight`                | Custom overlay items for the bottom-right corner of the viewport.             |
| (New)                                         | `viewportActionMenu.windowLevelActionMenu`   | Controls the display and the location of the window level action menu in the viewport.      |
| (New)                                         | `viewportActionMenu.segmentationOverlay`     | Controls the display and the location of segmentation overlays in the viewport.      |

---

### Platform Docs Docs Platform Services Data Index (`platform/docs/docs/platform/services/data/index.md`)

---
sidebar_position: 1
sidebar_label: Overview
title: Data Services Overview
summary: Overview of OHIF's data services architecture, which replaced the Redux store with a more modular approach using service-specific state management and a pub/sub pattern for communication between components.
---

# Overview

Data services are the first category of services which deal with handling non-ui
related state Each service have their own internal state which they handle.

> We have replaced the _redux_ store. Instead, we have introduced various
> services and a pub/sub pattern to subscribe and run, which makes the `OHIF-v3`
> architecture nice and clean.

We maintain the following non-ui Services:

- [DicomMetadata Store](./../data/DicomMetadataStore.md)
- [DisplaySet Service](./../data/DisplaySetService.md)
- [Hanging Protocol Service](../data/HangingProtocolService.md)
- [Toolbar Service](./ToolbarService.md)
- [Measurement Service](../data/MeasurementService.md)
- [Customization Service](./../customization-service/customizationService.md)
- [Panel Service](../data/PanelService.md)
- [Viewed Data Service](../data/ViewedDataService.md)

## Service Architecture



> We have explained services and how to create a custom service in the
> [`ServicesManager`](../../managers/service.md) section of the docs

To recap: The simplest service return a new object that has a `name` property,
and `Create` method which instantiate the service class. The "Factory Function"
that creates the service is provided with the implementation (this is slightly
different for UI Services).

```js
// extensions/customExtension/src/services/backEndService/index.js
import backEndService from './backEndService';

export default function WrappedBackEndService(servicesManager) {
  return {
    name: 'myService',
    create: ({ configuration = {} }) => {
      return new backEndService(servicesManager);
    },
  };
}
```

A service, once created, can be registered with the `ServicesManager` to make it
accessible to extensions. Similarly, the application code can access named
services from the `ServicesManager`.

[Read more of how to design a new custom service and register it](../../managers/service.md)

---

### Platform Docs Docs Platform Services Ui Index (`platform/docs/docs/platform/services/ui/index.md`)

---
sidebar_position: 1
sidebar_label: Overview
title: UI Services Overview
summary: Overview of OHIF's UI services architecture, which enables consistent UI interactions across the application through React context providers and service implementations, allowing extensions to leverage components like modals, notifications, and dialogs.
---

# Overview



A typical web application will have components and state for common UI like
modals, notifications, dialogs, etc. A UI service makes it possible to leverage
these components from an extension.

We maintain the following UI Services:

- [UI Notification Service](ui-notification-service.md)
- [UI Modal Service](ui-modal-service.md)
- [UI Dialog Service](ui-dialog-service.md)
- [UI Viewport Dialog Service](ui-viewport-dialog-service.md)
- [CINE Service](cine-service.md)
- [Viewport Grid Service](viewport-grid-service.md)







## Providers for UI services

**There are several context providers that wraps the application routes. This
makes the context values exposed in the app, and service's `setImplementation`
can get run to override the implementation of the service.**

```js title="platform/app/src/App.jsx"
function App({ config, defaultExtensions }) {
  /**...**/
  /**...**/
  return (
    /**...**/
    <ViewportGridProvider service={ViewportGridService}>
      <ViewportDialogProvider service={UIViewportDialogService}>
        <CineProvider service={CineService}>
          <SnackbarProvider service={UINotificationService}>
            <DialogProvider service={UIDialogService}>
              <ModalProvider modal={Modal} service={UIModalService}>
                {appRoutes}
              </ModalProvider>
            </DialogProvider>
          </SnackbarProvider>
        </CineProvider>
      </ViewportDialogProvider>
    </ViewportGridProvider>
    /**...**/
  );
}
```

## Example

For instance `UIModalService` has the following Public API:

```js title="platform/core/src/services/UIModalService/index.js"
const publicAPI = {
  name,
  hide: _hide,
  show: _show,
  setServiceImplementation,
};

function setServiceImplementation({
  hide: hideImplementation,
  show: showImplementation,
}) {
  /** ... **/
  serviceImplementation._hide = hideImplementation;
  serviceImplementation._show = showImplementation;
  /** ... **/
}

export default {
  name: 'UIModalService',
  create: ({ configuration = {} }) => {
    return publicAPI;
  },
};
```

`UIModalService` implementation can be set (override) in its context provider.
For instance in `ModalProvider` we have:

```
/* Detailed source-code truncated for AI context efficiency. */
```

Therefore, anywhere in the app that we have access to react context we can use
it by calling the `useModal` from `@ohif/ui-next`. As a matter of fact, we are
utilizing the modal for the preference window which shows the hotkeys after
clicking on the gear button on the right side of the header.

A `simplified` code for our viewer header is:

```tsx title="extensions/default/src/ViewerLayout/ViewerHeader.tsx"
import { Header, useModal } from '@ohif/ui-next';
import { useSystem } from '@ohif/core';

function ViewerHeader({ appConfig }) {
  const { servicesManager } = useSystem();
  const { customizationService } = servicesManager.services;
  const { show } = useModal();

  const AboutModal = customizationService.getCustomization('ohif.aboutModal');
  const UserPreferencesModal = customizationService.getCustomization(
    'ohif.userPreferencesModal'
  );

  const menuOptions = [
    {
      title: AboutModal?.menuTitle ?? t('Header:About'),
      icon: 'info',
      onClick: () =>
        show({
          content: AboutModal,
          title: AboutModal?.title ?? t('AboutModal:About OHIF Viewer'),
          containerClassName: AboutModal?.containerClassName ?? 'max-w-md',
        }),
    },
    {
      title: UserPreferencesModal.menuTitle ?? t('Header:Preferences'),
      icon: 'settings',
      onClick: () =>
        show({
          content: UserPreferencesModal,
          title: UserPreferencesModal.title ?? t('UserPreferencesModal:User preferences'),
          containerClassName:
            UserPreferencesModal?.containerClassName ?? 'flex max-w-4xl p-6 flex-col',
        }),
    },
  ];

  /** ... **/

  return <Header menuOptions={menuOptions} /** ... **/ />;
}
```







## Tips & Tricks

It's important to remember that all we're doing is making it possible to control
bits of the application's UI from an extension. Here are a few non-obvious
takeaways worth mentioning:

- Your application code should continue to use React context
  (consumers/providers) as it normally would
- You can substitute our "out of the box" UI implementations with your own
- You can create and register your own UI services
- You can choose not to register a service or provide a service implementation
- In extensions, you can provide fallback/alternative behavior if an expected
  service is not registered
  - No `UIModalService`? Use the `UINotificationService` to notify users.
- You can technically register a service in an extension and expose it to the
  core application

> Note: These are recommended patterns, not hard and fast rules. Following them
> will help reduce confusion and interoperability with the larger OHIF
> community, but they're not silver bullets. Please speak up, create an issue,
> if you would like to discuss new services or improvements to this pattern.

---

### Platform Docs Versioned Docs Version 3.11 Migration Guide 3p10 To 3p11 Index (`platform/docs/versioned_docs/version-3.11/migration-guide/3p10-to-3p11/index.md`)

---
sidebar_position: 1
sidebar_label: 3.10 -> 3.11
---

# Migration Guide

This guide provides information about migrating from OHIF version 3.10 to version 3.11.

---

### Platform Docs Versioned Docs Version 3.11 Migration Guide 3p11 To 3p12 Index (`platform/docs/versioned_docs/version-3.11/migration-guide/3p11-to-3p12/index.md`)

---
sidebar_position: 1
sidebar_label: 3.11 -> 3.12 beta
---

# Migration Guide

This guide provides information about migrating from OHIF version 3.11 to version 3.12 beta

---

### Platform Docs Versioned Docs Version 3.11 Migration Guide 3p8 To 3p9 Index (`platform/docs/versioned_docs/version-3.11/migration-guide/3p8-to-3p9/index.md`)

---
id: 3p8-to-3p9
title: 3.8 -> 3.9
sidebar_position: 2
summary: Migration guide for upgrading from OHIF 3.8 to 3.9, covering segmentation architecture changes, renamings, data sources, measurements, viewport action corners, state sync service, RT structure improvements, UI changes, and other refactorings.
---


import DocCardList from '@theme/DocCardList';

## Migration Guide Sections

<DocCardList />

---

### Platform Docs Versioned Docs Version 3.11 Migration Guide 3p9 To 3p10 Index (`platform/docs/versioned_docs/version-3.11/migration-guide/3p9-to-3p10/index.md`)

---
sidebar_position: 1
sidebar_label: 3.9 -> 3.10
title: Migration Guide from 3.9 to 3.10 beta
summary: Migration guide for upgrading from OHIF 3.9 to 3.10 beta, covering general changes, customization service improvements, UI component upgrades, command handling, hotkey updates, routing changes, and testing strategies.
---

# Migration Guide


## General

---

### Platform Docs Versioned Docs Version 3.11 Platform Extensions Index (`platform/docs/versioned_docs/version-3.11/platform/extensions/index.md`)

---
sidebar_position: 1
sidebar_label: Introduction
title: OHIF Extensions Introduction
summary: Comprehensive introduction to the OHIF viewer extension system, explaining how extensions provide modular functionality through different module types, and how they're configured and accessed in modes to build customized viewer experiences.
---

# Introduction

We have re-designed the architecture of the `OHIF-v3` to enable building
applications that are easily extensible to various use cases (modes) that behind
the scene would utilize desired functionalities (extensions) to reach the goal
of the use case.

Previously, extensions were “additive” and could not easily be mixed and matched
within the same viewer for different use cases. Previous `OHIF-v2` architecture
meant that any minor extension alteration usually would require the user to hard
fork. E.g. removing some tools from the toolbar of the cornerstone
extension meant you had to hard fork it, which was frustrating if the
implementation was otherwise the same as master.

> - Developers should make packages of _reusable_ functionality as extensions,
>   and can consume publicly available extensions.
> - Any conceivable radiological workflow or viewer setup will be able to be
>   built with the platform through _modes_.

Practical examples of extensions include:

- A set of segmentation tools that build on top of the `cornerstone` viewport
- A set of rendering functionalities to volume render the data
- [See our maintained extensions for more examples of what's possible](#maintained-extensions)

**Diagram showing how extensions are configured and accessed.**



## Extension Skeleton

An extension is a plain JavaScript object that has `id` and `version` properties, and one or
more [modules](#modules) and/or [lifecycle hooks](#lifecycle-hooks).

```js
// prettier-ignore
export default {
  /**
   * Required properties. Should be a unique value across all extensions.
   */
  id,

  // Lifecycle
  preRegistration() { /* */ },
  onModeEnter() { /* */ },
  onModeExit() { /* */ },
  // Modules
  getLayoutTemplateModule() { /* */ },
  getDataSourcesModule() { /* */ },
  getSopClassHandlerModule() { /* */ },
  getPanelModule() { /* */ },
  getViewportModule() { /* */ },
  getCommandsModule() { /* */ },
  getContextModule() { /* */ },
  getToolbarModule() { /* */ },
  getHangingProtocolModule() { /* */ },
  getUtilityModule() { /* */ },
}
```

## OHIF-Maintained Extensions

A small number of powerful extensions for popular use cases are maintained by
OHIF. They're co-located in the [`OHIF/Viewers`][viewers-repo] repository, in
the top level [`extensions/`][ext-source] directory.

<table>
    <thead>
        <tr>
            <th>Extension</th>
            <th>Description</th>
            <th>Modules</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <a href="">
                    default
                </a>
            </td>
            <td>
                Default extension provides default viewer layout, a study/series
                browser, and a datasource that maps to a DICOMWeb compliant backend
            </td>
            <td>commandsModule, ContextModule, DataSourceModule, HangingProtocolModule, LayoutTemplateModule, PanelModule, SOPClassHandlerModule, ToolbarModule</td>
        </tr>
        <tr>
            <td>
                <a href="">
                    cornerstone
                </a>
            </td>
            <td>
                Provides 2d and 3d rendering functionalities
            </td>
            <td>ViewportModule, CommandsModule, UtilityModule</td>
        </tr>
        <tr>
            <td>
                <a href="">dicom-pdf</a>
            </td>
            <td>
                Renders PDFs for a <a href="https://github.com/OHIF/Viewers/blob/master/extensions/dicom-pdf/src/OHIFDicomPDFSopClassHandler.js#L4-L6">specific SopClassUID</a>.
            </td>
            <td>Viewport, SopClassHandler</td>
        </tr>
        <tr>
            <td>
                <a href="">dicom-video</a>
            </td>
            <td>
                Renders DICOM Video files.
            </td>
            <td>Viewport, SopClassHandler</td>
        </tr>
        <tr>
            <td>
                <a href="">cornerstone-dicom-sr</a>
            </td>
            <td>
                Maintained extensions for cornerstone and visualization of DICOM Structured Reports
            </td>
           <td>ViewportModule, CommandsModule, SOPClassHandlerModule</td>
        </tr>
        <tr>
            <td>
                <a href="">measurement-tracking</a>
            </td>
            <td>
                Tracking measurements in the measurement panel
            </td>
            <td> ContextModule,PanelModule,ViewportModule,CommandsModule</td>
        </tr>
    </tbody>
</table>

## Registering of Extensions

`viewer` starts by registering all the extensions specified inside the
`pluginConfig.json`, by default we register all extensions in the repo.


```js title=platform/app/pluginConfig.json
// Simplified version of the `pluginConfig.json` file
{
  "extensions": [
    {
      "packageName": "@ohif/extension-cornerstone",
      "version": "3.4.0"
    },
    {
      "packageName": "@ohif/extension-measurement-tracking",
      "version": "3.4.0"
    },
    // ...
  ],
  "modes": [
    {
      "packageName": "@ohif/mode-longitudinal",
      "version": "3.4.0"
    }
  ]
}
```

:::note Important
You SHOULD NOT directly register extensions in the `pluginConfig.json` file.
Use the provided `cli` to add/remove/install/uninstall extensions. Read more [here](../../development/ohif-cli.md)
:::

The final registration and import of the extensions happen inside a non-tracked file `pluginImport.js` (this file is also for internal use only).

After an extension gets registered within the `viewer`,
each [module](#modules) defined by the extension becomes available to the modes
via the `ExtensionManager` by requesting it via its id.
[Read more about Extension Manager](#extension-manager)

## Lifecycle Hooks

Currently, there are three lifecycle hook for extensions:

[`preRegistration`](./lifecycle/#preRegistration) This hook is called once on
initialization of the entire viewer application, used to initialize the
extensions state, and consume user defined extension configuration. If an
extension defines the [`preRegistration`](./lifecycle/#preRegistration)
lifecycle hook, it is called before any modules are registered in the
`ExtensionManager`. It's most commonly used to wire up extensions to
[services](./../services/index.md) and [commands](./modules/commands.md), and to
bootstrap 3rd party libraries.

[`onModeEnter`](./lifecycle#onModeEnter): This hook is called whenever a new
mode is entered, or a mode’s data or datasource is switched. This hook can be
used to initialize data.

[`onModeExit`](./lifecycle#onModeExit): Similarly to onModeEnter, this hook is
called when navigating away from a mode, or before a mode’s data or datasource
is changed. This can be used to cache data for reuse later, but since it
isn't known which mode will be entered next, the state after exiting should be
clean, that is, the same as the state on a clean start.  This is called BEFORE
service clean up, and after mode specific onModeExit handling.

## Modules

Modules are the meat of extensions, the `blocks` that we have been talking about
a lot. They provide "definitions", components, and filtering/mapping logic that
are then made available to modes and services.

Each module type has a special purpose, and is consumed by our viewer
differently.

<table>
  <thead>
    <tr>
      <th align="left" width="30%">
        Types
      </th>
      <th align="left">Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td align="left">
        <a href="./modules/layout-template">
          LayoutTemplate
        </a>
      </td>
      <td align="left">Control Layout of a route</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/data-source">
          DataSource
        </a>
      </td>
      <td align="left">Control the mapping from DICOM metadata to OHIF-metadata</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/sop-class-handler">
          SOPClassHandler
        </a>
      </td>
      <td align="left">Determines how retrieved study data is split into "DisplaySets"</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/panel">
          Panel
        </a>
      </td>
      <td align="left">Adds left or right hand side panels</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/viewport">
          Viewport
        </a>
      </td>
      <td align="left">Adds a component responsible for rendering a "DisplaySet"</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/commands">
          Commands
        </a>
      </td>
      <td align="left">Adds named commands, scoped to a context, to the CommandsManager</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/toolbar">
          Toolbar
        </a>
      </td>
      <td align="left">Adds buttons or custom components to the toolbar</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/contextModule">
          Context
        </a>
      </td>
      <td align="left">Shared state for a workflow or set of extension module definitions</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/hpModule">
          HangingProtocol
        </a>
      </td>
      <td align="left">Adds hanging protocol rules</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./modules/hpModule">
          Utility
        </a>
      </td>
      <td align="left">Expose utility functions to the outside of extensions</td>
    </tr>
  </tbody>
</table>

<span style={{"textAlign": 'center', 'fontStyle': 'italic'}}>Tbl. Module types
with abridged descriptions and examples. Each module links to a dedicated
documentation page.</span>

### Contexts

The `@ohif/app` tracks "active contexts" that extensions can use to scope
their functionality. Some example contexts being:

- Route: `ROUTE:VIEWER`, `ROUTE:STUDY_LIST`
- Active Viewport: `ACTIVE_VIEWPORT:CORNERSTONE`, `ACTIVE_VIEWPORT:VTK`

An extension module can use these to say "Only show this Toolbar Button if the
active viewport is a Cornerstone viewport." This helps us use the appropriate UI
and behaviors depending on the current contexts.

For example, if we have hotkey that "rotates the active viewport", each Viewport
module that supports this behavior can add a command with the same name, scoped
to the appropriate context. When the `command` is fired, the "active contexts"
are used to determine the appropriate implementation of the rotation behavior.




[viewers-repo]: https://github.com/OHIF/Viewers
[ext-source]: https://github.com/OHIF/Viewers/tree/master/extensions
[module-types]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/extensions/MODULE_TYPES.js

---

### Platform Docs Versioned Docs Version 3.11 Platform Hooks Index (`platform/docs/versioned_docs/version-3.11/platform/hooks/index.md`)

---
title: Hooks
summary: List of React hooks available in the platform, these are custom hooks that are used to access the state of the platform
---

# Hooks

## [useMeasurements](./useMeasurements.md)
A React hook that provides mapped measurements from the measurement service with automatic updates when measurements change.

## [useViewportSegmentations](./useViewportSegmentations.md)
A React hook that provides segmentation data and representations for the active viewport with automatic updates when segmentations change.

## [useMeasurementTracking](./useMeasurementTracking.md)
A React hook that provides measurement tracking information for a specific viewport, including tracking state and tracked measurement UIDs.

## [useViewportDisplaySets](./useViewportDisplaySets.md)
A React hook that provides access to display sets associated with a viewport, including background, foreground, overlay, and potential display sets.

## [useViewportHover](./useViewportHover.md)
A React hook that tracks mouse hover state and active status for a specific viewport.

## [usePatientInfo](./usePatientInfo.md)
A React hook that provides patient information from the active display sets and detects when multiple patients are loaded.

## [useSearchParams](./useSearchParams.md)
A React hook that provides access to URL search parameters from both the query string and hash fragment.

## [useDynamicMaxHeight](./useDynamicMaxHeight.md)
A React hook that calculates the maximum height for an element based on its position in the viewport, with automatic recalculation on window resize or data changes.

## [useSessionStorage](./useSessionStorage.md)
A React hook that provides sessionStorage access with automatic JSON parsing/stringifying and an option to clear data when the page unloads.

---

### Platform Docs Versioned Docs Version 3.11 Platform Managers Index (`platform/docs/versioned_docs/version-3.11/platform/managers/index.md`)

---
sidebar_position: 1
sidebar_label: Introduction
title: Managers Introduction
summary: Overview of OHIF's manager system, which handles critical application infrastructure including extension registration, service management, command execution, and hotkey binding to coordinate functionality across the platform.
---

# Managers

## Overview

`OHIF` uses `Managers` to accomplish various purposes such as registering new
services, dependency injection, and aggregating and exposing `extension`
features.

`OHIF-v3` provides the following managers which we will discuss in depth.

<table>
    <thead>
        <tr>
            <th>Manager</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <a href="./extension">
                    Extension Manager
                </a>
            </td>
            <td>
                Aggregating and exposing modules and features through out the app
            </td>
        </tr>
        <tr>
            <td>
                <a href="./service">
                    Services Manager
                </a>
            </td>
            <td>
                Single point of registration for all internal and external services
            </td>
        </tr>
        <tr>
            <td>
                <a href="./commands">
                    Commands Manager
                </a>
            </td>
            <td>
                Register commands with specific context and run commands in the app
            </td>
        </tr>
        <tr>
            <td>
                <a href="./hotkeys">
                    Hotkeys Manager
                </a>
            </td>
            <td>
                For keyboard keys assignment to commands
            </td>
        </tr>
    </tbody>
</table>





[core-services]: https://github.com/OHIF/Viewers/tree/master/platform/core/src/services
[services-manager]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/services/ServicesManager.js
[cross-cutting-concerns]: https://en.wikipedia.org/wiki/Cross-cutting_concern

---

### Platform Docs Versioned Docs Version 3.11 Platform Modes Index (`platform/docs/versioned_docs/version-3.11/platform/modes/index.md`)

---
sidebar_position: 1
sidebar_label: Introduction
title: Modes Introduction
summary: Overview of OHIF Modes, which are specialized viewer configurations for specific clinical workflows, allowing multiple purpose-specific applications to coexist within a single OHIF deployment.
---

# Modes

## Overview

A mode can be thought of as a viewer app configured to perform a specific task,
such as tracking measurements over time, 3D segmentation, a guided radiological
workflow, etc. Addition of modes enables _application_ with many _applications_
as each mode become a mini _app configuration_ behind the scene.

Upon initialization the viewer will consume extensions and modes and build up
the route desired, these can then be accessed via the study list, or directly
via url parameters.



OHIF-v3 architecture can be seen in the following:



> Note: Templates are now a part of “extensions” Routes are configured by modes
> and/or app

As mentioned, modes are tied to a specific route in the viewer, and multiple
modes/routes can be present within a single application. This allows for
tremendously more flexibility than before you can now:

- Simultaneously host multiple viewers with for different use cases from within
  the same app deploy.
- Make radiological viewers for specific purposes/workflows, e.g.:
  - Tracking the size of lesions over time.
  - PET/CT fusion workflows.
  - Guided review workflows optimized for a specific clinical trial.
- Still host one single feature-rich viewer if you desire.

## Anatomy

A mode configuration has a `route` name which is dynamically transformed into a
viewer route on initialization of the application. Modes that are available to a
study will appear in the study list.



The mode configuration specifies which `extensions` the mode requires, which
`LayoutTemplate` to use, and what props to pass to the template. For the default
template this defines which `side panels` will be available, as well as what
`viewports` and which `displaySets` they may hang.

Mode's config is composed of three elements:
- `id`: the mode `id`
- `modeFactory`: the function that returns the mode specific configuration
- `extensionDependencies`: the list of extensions that the mode requires


that return a config object with certain
properties, the high-level view of this config object is:

```js title="modes/example/src/index.js"
function modeFactory() {
  return {
    id: '',
    version: '',
    displayName: '',
    onModeEnter: () => {},
    onModeExit: () => {},
    validationTags: {},
    isValidMode: () => {},
    routes: [
      {
        path: '',
        init: () => {},
        layoutTemplate: () => {},
      },
    ],
    extensions: extensionDependencies,
    hangingProtocol: [],
    sopClassHandlers: [],
    hotkeys: []
  };
}

const mode = {
  id,
  modeFactory,
  extensionDependencies,
};

export default mode;
```

<table>
  <thead>
    <tr>
      <th align="left">Property</th>
      <th align="left">Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td align="left">
          id
      </td>
      <td align="left">unique mode id used to refer to the mode</td>
    </tr>
    <tr>
      <td align="left">
          displayName
      </td>
      <td align="left">actual name of the mode being displayed for each study in the study summary panel</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./lifecycle#onModeEnter">
          onModeEnter
        </a>
      </td>
      <td align="left">hook is called when the mode is entered by the specified route</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./lifecycle#onModeExit">
          onModeExit
        </a>
      </td>
      <td align="left">hook is called when the mode exited</td>
    </tr>
    <tr>
      <td align="left">
        <a href="">
          validationTags
        </a>
      </td>
      <td align="left">validationTags</td>
    </tr>
    <tr>
      <td align="left">
        <a href="">
          isValidMode
        </a>
      </td>
      <td align="left">Checks if the mode is valid for a study</td>
    </tr>
    <tr>
      <td align="left">
        <a href="">
          routes
        </a>
      </td>
      <td align="left">route config which defines the route address, and the layout for it</td>
    </tr>
    <tr>
      <td align="left">
        <a href="./index#consuming-extensions">
          extensionDependencies
        </a>
      </td>
      <td align="left">extensions needed by the mode</td>
    </tr>
    <tr>
      <td align="left">
        <a href="">
          hanging protocol
        </a>
      </td>
      <td align="left">list of hanging protocols that the mode should have access to</td>
    </tr>
    <tr>
      <td align="left">
        <a href="">
          sopClassHandlers
        </a>
      </td>
      <td align="left">list of SOPClass modules needed by the mode </td>
    </tr>
    <tr>
      <td align="left">
        <a href="">
          hotkeys
        </a>
      </td>
      <td align="left">hotkeys</td>
    </tr>

  </tbody>
</table>

### Consuming Extensions

As mentioned in the [Extensions](../extensions/index.md) section, in `OHIF-v3`
developers write their extensions to create reusable functionalities that later
can be used by `modes`. Now, it is time to describe how the registered
extensions will get utilized for a workflow mode via its `id`.

Each `mode` has a list of its `extensions dependencies` which are the
the `extension` name and version number. In addition, to use a module element you can use the
`${extensionId}.${moduleType}.${element.name}` schema. For instance, if a mode
requires the left panel with name of `AIPanel` that is added by the
`myAIExtension` via the following `getPanelModule` code, it should address it as
`myAIExtension.panelModule.AIPanel` inside the mode configuration file. In the
background `OHIF` will handle grabbing the correct panel via `ExtensionManager`.

```js title="extensions/myAIExtension/getPanelModule.js"
import PanelAI from './PanelAI.js';

function getPanelModule({
  commandsManager,
  extensionManager,
  servicesManager,
}) {
  const wrappedAIPanel = () => {
    return (
      <PanelAI
        commandsManager={commandsManager}
        servicesManager={servicesManager}
      />
    );
  };

  return [
    {
      name: 'AIPanel',
      iconName: 'list-bullets',
      iconLabel: '',
      label: 'AI Panel',
      isDisabled: studies => {}, // optional
      component: wrappedAIPanel,
    },
  ];
}
```

Now, let's look at a simplified code of the `basic viewer` mode which consumes various functionalities
from different extensions.

```js

const extensionDependencies = {
  '@ohif/extension-default': '^3.0.0',
  '@ohif/extension-cornerstone': '^3.0.0',
  '@ohif/extension-measurement-tracking': '^3.0.0',
};

const id = 'viewer';
const version = '3.0.0';

function modeFactory({ modeConfiguration }) {
  return {
    id,
    // ...
    routes: [
      {
        // ...
        layoutTemplate: ({ location, servicesManager }) => {
          return {
            id: ohif.layout,
            props: {
              leftPanels: ['@ohif/extension-measurement-tracking.panelModule.seriesList'],
              rightPanels: ['@ohif/extension-measurement-tracking.panelModule.trackedMeasurements'],
              viewports: [
                {
                  namespace: '@ohif/extension-measurement-tracking.viewportModule.cornerstone-tracked',
                  displaySetsToDisplay: ['@ohif/extension-default.sopClassHandlerModule.stack'],
                },
              ],
            },
          };
        },
      },
    ],
    extensions: extensionDependencies,
    hangingProtocol: ['@ohif/extension-default.hangingProtocolModule.petCT'],
    sopClassHandlers: ['@ohif/extension-default.sopClassHandlerModule.stack'],
    // ...
  };
}

const mode = {
  id,
  modeFactory,
  extensionDependencies,
}

export default mode
```

### Routes

routes config is an array of route settings, and the overall look and behavior
of the viewer at the designated route is defined by the `layoutTemplate` and
`init` functions for the route. We will learn more about each of the above
properties inside the [route documentation](./routes.md)


### HangingProtocols

Currently, you can pass your defined hanging protocols inside the
`hangingProtocols` property of the mode's config. If you specify the hanging protocol
explicitly by its name (only string and not array), it will be THE hanging protocol
that the mode runs with. However, if you specify an array of hanging protocols,
they will get ranked based on the displaySetSelector requirements and the winner
will be the hanging protocol that the mode runs with.


### SopClassHandlers

Mode's configuration also accepts the `sopClassHandler` modules that have been
added by the extensions. This information will get used to initialize `DisplaySetService` with the provided SOPClass modules which
handles creation of the displaySets.


### Hotkeys

`hotkeys` is another property in the configuration of a mode that can be defined
to add the specific hotkeys to the viewer on the mode route.  Additionally, the
name under which the hotkeys are stored can be configured as `hotkeyName`.
This allows user customization of the mode specific hotkeys.

```js
// default hotkeys
import { utils } from '@ohif/ui';

const { hotkeys } = utils;

const myHotkeys = [
  {
    commandName: 'setToolActive',
    commandOptions: { toolName: 'Zoom' },
    label: 'Zoom',
    keys: ['z'],
    isEditable: true,
  },
  {
    commandName: 'scaleUpViewport',
    label: 'Zoom In',
    keys: ['+'],
    isEditable: true,
  },
]

function modeFactory() {
  return {
    id: '',
    id: '',
    displayName: '',
    /*
    ...
    */
    hotkeys: {
      // The name in preferences to use for this set of hotkeys
      // Allows defining different sets for different modes
      name: 'custom-hotkey-name',
      // And the actual custom values here.
      hotkeys:[..hotkeys.defaults.hotkeyBindings, ...myHotkeys]
    },
  }
}

// exports
```





## Registration

Similar to extension registration, `viewer` will look inside the `pluginConfig.json` to
find the `modes` to register.


```js title=platform/app/pluginConfig.json
// Simplified version of the `pluginConfig.json` file
{
  "extensions": [
    {
      "packageName": "@ohif/extension-cornerstone",
      "version": "3.4.0"
    },
    // ...
  ],
  "modes": [
    {
      "packageName": "@ohif/mode-longitudinal",
      "version": "3.4.0"
    }
  ]
}
```

:::note Important
You SHOULD NOT directly register modes in the `pluginConfig.json` file.
Use the provided `cli` to add/remove/install/uninstall modes. Read more [here](../../development/ohif-cli.md)
:::

The final registration and import of the modes happen inside a non-tracked file `pluginImport.js` (this file is also for internal use only).


:::note
You can stack multiple panel components on top of each other by providing an array of panel components in the `rightPanels` or `leftPanels` properties.

For instance we can use

```
rightPanels: [[dicomSeg.panel, tracked.measurements], [dicomSeg.panel, tracked.measurements]]
```

This will result in two panels, one with `dicomSeg.panel` and `tracked.measurements` and the other with `dicomSeg.panel` and `tracked.measurements` stacked on top of each other.

:::

---

### Platform Docs Versioned Docs Version 3.11 Platform Services Index (`platform/docs/versioned_docs/version-3.11/platform/services/index.md`)

---
sidebar_position: 1
sidebar_label: Introduction
title: OHIF Services
summary: Overview of OHIF's services architecture, which provides modular, concern-specific code components that manage state and operations throughout the application, including both data services and UI services that follow a pub/sub pattern to reduce coupling.
---

# Services

## Overview

Services are "concern-specific" code modules that can be consumed across layers.
Services provide a set of operations, often tied to some shared state, and are
made available to through out the app via the `ServicesManager`. Services are
particularly well suited to address [cross-cutting
concerns][cross-cutting-concerns].

Each service should be:

- self-contained
- able to fail and/or be removed without breaking the application
- completely interchangeable with another module implementing the same interface

> In `OHIF-v3` we have added multiple non-UI services and have introduced
> **pub/sub** pattern to reduce coupling between layers.
>
> [Read more about Pub/Sub](./pubsub.md)

## Services

The following services is available in the `OHIF-v3`.

<table>
    <thead>
        <tr>
            <th>Service</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <a href="./data/DicomMetadataStore">
                    DicomMetadataStore
                </a>
            </td>
            <td>Data Service</td>
            <td>
                DicomMetadataStore
            </td>
        </tr>
        <tr>
            <td>
                <a href="./data/DisplaySetService">
                    DisplaySetService
                </a>
            </td>
            <td>Data Service</td>
            <td>
                DisplaySetService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./data/SegmentationService">
                    segmentationService
                </a>
            </td>
            <td>Segmentation Service</td>
            <td>
                segmentationService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./data/HangingProtocolService">
                    HangingProtocolService
                </a>
            </td>
            <td>Data Service</td>
            <td>
                HangingProtocolService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./data/MeasurementService">
                    MeasurementService (MODIFIED)
                </a>
            </td>
            <td>Data Service</td>
            <td>
                MeasurementService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./data/ToolBarService">
                    ToolBarService
                </a>
            </td>
            <td>Data Service</td>
            <td>
                ToolBarService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./ui/viewport-grid-service">
                    ViewportGridService
                </a>
            </td>
            <td>UI Service</td>
            <td>
                ViewportGridService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./ui/cine-service">
                    Cine Service
                </a>
            </td>
            <td>UI Service</td>
            <td>
                cine
            </td>
        </tr>
        <tr>
            <td>
                <a href="./customization-service">
                    CustomizationService
                </a>
            </td>
            <td>UI Service</td>
            <td>
                customizationService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./ui/ui-dialog-service">
                    UIDialogService
                </a>
            </td>
            <td>UI Service</td>
            <td>
                UIDialogService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./ui/ui-modal-service">
                    UIModalService
                </a>
            </td>
            <td>UI Service</td>
            <td>
                UIModalService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./ui/ui-notification-service">
                    UINotificationService
                </a>
            </td>
            <td>UI Service</td>
            <td>
                UINotificationService
            </td>
        </tr>
        <tr>
            <td>
                <a href="./ui/ui-viewport-dialog-service">
                    UIViewportDialogService
                </a>
            </td>
            <td>UI Service</td>
            <td>
                UIViewportDialogService
            </td>
        </tr>
    </tbody>
</table>





[core-services]: https://github.com/OHIF/Viewers/tree/master/platform/core/src/services
[services-manager]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/services/ServicesManager.js
[cross-cutting-concerns]: https://en.wikipedia.org/wiki/Cross-cutting_concern

---

### Platform Docs Versioned Docs Version 3.11 User Guide Viewer Index (`platform/docs/versioned_docs/version-3.11/user-guide/viewer/index.md`)

---
sidebar_position: 1
sidebar_label: Overview
---


# Overview
When you open a mode, viewport, toolbar and panels of the mode get shown.
It is important to note that each mode has a different UI, which serves its purpose.
Here we explain various components of `Basic Viewer` mode which includes measurement
tracking functionalities.

Basic viewer mode (longitudinal):



Let's break different aspects of the viewer to the main components:

- Left Panel (study panel): displays series thumbnails with series details
- Viewport: renders the image and displays annotations
- Right Panel (measurements): displays annotations details
- Toolbar: displays tools and logo






Now, we explain each component and its sub-elements in detail.

---

### Platform Docs Versioned Docs Version 3.11 Migration Guide 3p8 To 3p9 1 Segmentation Index (`platform/docs/versioned_docs/version-3.11/migration-guide/3p8-to-3p9/1-segmentation/index.md`)

---
id: segmentation-index
title: Segmentation
sidebar_position: 1
summary: Migration guide for segmentation architecture changes in OHIF 3.9, covering the shift from tool group-centric to viewport-centric architecture to support advanced visualization capabilities and more flexible segmentation handling.
---

import DocCardList from '@theme/DocCardList';

:::info
This migration involves significant architectural changes to the segmentation system. While we typically aim for incremental updates, the shift from a tool group-centric to a viewport-centric architecture was necessary to support OHIF 3.9's advanced visualization capabilities, and more flexible segmentation handling.

Don't worry - we'll guide you through each change step by step!
:::


<DocCardList />

---

### Platform Docs Versioned Docs Version 3.11 Migration Guide 3p9 To 3p10 2 CustomizationService Index (`platform/docs/versioned_docs/version-3.11/migration-guide/3p9-to-3p10/2-CustomizationService/index.md`)

---
sidebar_position: 2
title: Customization Service
summary: Migration guide for OHIF's Customization Service from 3.9 to 3.10, covering unified customization getters, simplified registration, new commands, renamed customizations, and updated patterns for modifying UI components.
---

# CustomizationService



**Key Changes:**


1. **Unified Customization Getter:**
   - The `getCustomization` method now uniformly retrieves customizations, prioritizing `global`, then `mode`, and finally `default` customizations.
   - The `defaultValue` parameter in `getCustomization` is no longer used for setting defaults. It simply returns if no customization is found.
   - The methods `getModeCustomization` and `getGlobalCustomization` are deprecated.

2. **Simplified Customization Registration:**
   - The `customizationType` property in customization definitions is renamed to `inheritsFrom`.
   - The `merge` property in customization definitions is removed. Instead, a customization is merged using the helper methods. The basic update commands are listed in the table below, and you can learn more about the helper methods [here](../../../platform/services/customization-service/customizationService.md).

     | Command  | Description                               | Example                                           |
     | :------- | :---------------------------------------- | :------------------------------------------------ |
     | `$set`   | Replace a value entirely                 | Replace a list or object                        |
     | `$push`  | Append items to an array                 | Add to the end of a list                        |
     | `$unshift` | Prepend items to an array                | Add to the start of a list                      |
     | `$splice` | Insert, remove, or replace at specific index | Modify specific indices in a list                 |
     | `$merge` | Update specific fields in an object      | Change a subset of fields                       |
     | `$apply` | Compute the new value dynamically        | Apply a function to transform values              |
     | `$filter` | Find and update specific items in arrays | Target nested structures based on matching criteria |


3. **New `$transform` command:**
   - If you were using the `transform` command, you should now use the `$transform` command. Just a simple rename to make it more consistent with the other commands.


5. **Renamed `CornerstoneOverlay` customizations:**
   - The `cornerstoneOverlay` customizations (`cornerstoneOverlayTopLeft`, `cornerstoneOverlayTopRight`, `cornerstoneOverlayBottomLeft`, `cornerstoneOverlayBottomRight`) have been renamed to `viewportOverlay.topLeft`, `viewportOverlay.topRight`, `viewportOverlay.bottomLeft`, and `viewportOverlay.bottomRight`. See dedicated page for customizing viewport overlays [here](../../../platform/services/customization-service/viewportOverlay.md).

6. **Renamed `customRoutes`:**
   - The `customRoutes` customization is renamed to `routes.customRoutes`.

7.  **`contextMenu` customization:**
    - The `contextMenu` customization now uses the `inheritsFrom` property to inherit from other context menus, previously it was called `customizationType`

8. **New `immutability-helper` dependency:**
   The `immutability-helper` library is now used for merging customizations. If you encounter an error related to it, you'll need to install it - though OHIF should really handle the installation for you, so this is pretty much just a heads up.

**Migration Steps:**

1. **Replace `getModeCustomization` and `getGlobalCustomization` with `getCustomization`:**

   - **Before:**

     ```javascript
     const tools = customizationService.getModeCustomization(
       'cornerstone.overlayViewportTools'
     )?.tools;
     const globalValue = customizationService.getGlobalCustomization('someGlobalKey');
     ```

   - **After:**

     ```javascript
     const tools = customizationService.getCustomization('cornerstone.overlayViewportTools');
     const globalValue = customizationService.getCustomization('someGlobalKey');
     ```


     :::note
     The returned value is the actual customization value, not an object that needs to be broken down.
     :::

2. **Update Customization Definitions:**
   - We've moved away from using random items in the customization definition, and now we use the `id` property to identify the customization as a value. Previously, it was referred to as `value`, `values`, and so on, but now an `id` is used to reference the customization. This approach really simplifies things - when you need to grab the customization, you can just use the `id` to get it, and you don't have to bother with destructuring the value from the object.




**Example: Customizing a Panel**

**Before (v3.9):**

```javascript
// the default value was hardcoded inside the panel itself - bad idea!
// default was given in the panel itself

// PanelSegmentation.tsx

// Retrieve the onSegmentationAdd customization
const { onSegmentationAdd } = customizationService.getCustomization(
  'PanelSegmentation.onSegmentationAdd',
  {
    id: 'segmentation.onSegmentationAdd',
    onSegmentationAdd: handlers.onSegmentationAdd,
  }
);

// Retrieve the disableEditing customization
const { disableEditing } = customizationService.getCustomization(
  'PanelSegmentation.disableEditing',
  {
    id: 'default.disableEditing',
    disableEditing: false,
  }
);



// mode was customizing it via
customizationService.addModeCustomizations([
  {
    id: 'PanelSegmentation.tableMode',
    mode: 'expanded',
  },
  {
    id: 'PanelSegmentation.showAddSegment',
    showAddSegment: false,
  },
]);

```

**After (v3.10):**

```javascript
// cornerstone extension getCustomizationModule
// centralized customization location for all extensions - good!
function getCustomizationModule() {
  return [
    {
      name: 'default',
      value: {
        'panelSegmentation.disableEditing': false,
        'panelSegmentation.showAddSegment': true,
      },
    },
  ];
}


// inside panelSegmentation.tsx
const disableEditing = customizationService.getCustomization('panelSegmentation.disableEditing');
const showAddSegment = customizationService.getCustomization('panelSegmentation.showAddSegment');


// mode can customize it via $ operators for mode customizations
customizationService.setCustomizations({
  'panelSegmentation.disableEditing': { $set: true },
  'panelSegmentation.showAddSegment': { $set: false },
});


//or via configuration for global customizations
window.config = {
  // rest of config
  customizationService: [
    {
      'panelSegmentation.disableEditing': {
        $set: true, // Disables editing of segmentations in the panel
      },
    },
  ],
  // rest of config
};
```



**Example: Updating a Customization**

Let's say you have a customization in v3.9 that adds a custom overlay item to the top-left corner:

**Before (v3.9):**

```javascript
// In your mode's onModeEnter
customizationService.addModeCustomizations([
  {
    id: 'cornerstoneOverlayTopLeft',
    items: [
      {
        id: 'myCustomOverlay',
        customizationType: 'ohif.overlayItem',
        attribute: 'PatientName',
        label: 'Patient:',
      },
    ],
  },
]);
```

**After (v3.10):**

```javascript
// In your mode's onModeEnter or elsewhere
customizationService.setCustomizations({
  'viewportOverlay.topLeft': {
    $push: [
      {
        id: 'myCustomOverlay',
        inheritsFrom: 'ohif.overlayItem',
        attribute: 'PatientName',
        label: 'Patient:',
      },
    ],
  },
});
```
```
**Example: Customizing viewport action Menu**

**Before (v3.9):**

```javascript
// In your configuration for global customizations
window.config = {
    // rest of config
    addWindowLevelActionMenu: true,
};
```

**After (v3.10):**

```javascript
// you can now handle each action menu item (windowLevelActionMenu and segmentationOverlay) separately

// cornerstone extension getCustomizationModule
function getCustomizationModule() {
    return [
        {
            name: 'default',
            value: {
                'viewportActionMenu.windowLevelActionMenu': {
                    enabled: true,
                    location: viewportActionCornersService.LOCATIONS.topRight,
                },
                'viewportActionMenu.segmentationOverlay': {
                    enabled: true,
                    location: viewportActionCornersService.LOCATIONS.topRight,
                },
            },
        },
    ];
}


// Accessing customizations within your component (e.g., OHIFCornerstoneViewport.tsx)
const windowLevelActionMenu = customizationService.getCustomization('viewportActionMenu.windowLevelActionMenu');
const segmentationOverlay = customizationService.getCustomization('viewportActionMenu.segmentationOverlay');

// Modifying customizations at runtime, for example, in your mode's onModeEnter
customizationService.setCustomizations({
    'viewportActionMenu.windowLevelActionMenu': {
        $set: {
            enabled: false,
            location: viewportActionCornersService.LOCATIONS.bottomLeft,
        },
    },
    'viewportActionMenu.segmentationOverlay': {
        $set: {
            enabled: true,
            location: viewportActionCornersService.LOCATIONS.topLeft,
        },
    },
});

// Alternatively, setting global customizations via configuration
window.config = {
    // rest of config
    customizationService: [
        {
            'viewportActionMenu.windowLevelActionMenu': {
                $set: {
                    enabled: false,
                    location: 1,
                },
            },
            'viewportActionMenu.segmentationOverlay': {
                $set: {
                    enabled: true,
                    location: 1,
                },
            },
        },
    ],
    // rest of config
};
```

**Note:**

- The `customizationType` is replaced with `inheritsFrom`.





## Renaming

To keep our customization system consistent, you should be aware of a few key renaming conventions. We now follow a straightforward naming convention for customizations: `scopeName.customizationItem`.



| Customization Key (Old)                     | Customization Key (New)                      | Description                                                                 |
| :------------------------------------------ | :------------------------------------------- | :-------------------------------------------------------------------------- |
| `PanelMeasurement.disableEditing`             | `panelMeasurement.disableEditing`              | Disables editing measurements in the Measurement Panel and after SR hydration. |
| `PanelSegmentation.CustomDropdownMenuContent` | `panelSegmentation.customDropdownMenuContent`  | Custom content for the dropdown menu in the Segmentation Panel.             |
| `PanelSegmentation.disableEditing`             | `panelSegmentation.disableEditing`              | Disables editing segmentations in the Segmentation Panel.                    |
| `PanelSegmentation.showAddSegment`             | `panelSegmentation.showAddSegment`              | Controls visibility of the "Add Segment" button in the Segmentation Panel.    |
| `PanelSegmentation.onSegmentationAdd`          | `panelSegmentation.onSegmentationAdd`           | Custom function to execute when a new segmentation is added.                 |
| `PanelSegmentation.tableMode`                | `panelSegmentation.tableMode`                 | Controls the table mode (collapsed/expanded) in the Segmentation Panel.       |
| `PanelSegmentation.readableText`             | `panelSegmentation.readableText`              | Custom readable text labels for the Segmentation Panel.                       |
| `PanelStudyBrowser.studyMode`                | `studyBrowser.studyMode`                     | Controls the study mode (all/primary/recent) in the Study Browser Panel.      |
| `customRoutes`                                | `routes.customRoutes`                         | Defines custom routes for the application.                                  |
| `cornerstoneOverlayTopLeft`                   | `viewportOverlay.topLeft`                    | Custom overlay items for the top-left corner of the viewport.                  |
| `cornerstoneOverlayTopRight`                  | `viewportOverlay.topRight`                   | Custom overlay items for the top-right corner of the viewport.                 |
| `cornerstoneOverlayBottomLeft`                | `viewportOverlay.bottomLeft`                 | Custom overlay items for the bottom-left corner of the viewport.              |
| `cornerstoneOverlayBottomRight`               | `viewportOverlay.bottomRight`                | Custom overlay items for the bottom-right corner of the viewport.             |
| (New)                                         | `viewportActionMenu.windowLevelActionMenu`   | Controls the display and the location of the window level action menu in the viewport.      |
| (New)                                         | `viewportActionMenu.segmentationOverlay`     | Controls the display and the location of segmentation overlays in the viewport.      |

---

### Platform Docs Versioned Docs Version 3.11 Platform Services Data Index (`platform/docs/versioned_docs/version-3.11/platform/services/data/index.md`)

---
sidebar_position: 1
sidebar_label: Overview
title: Data Services Overview
summary: Overview of OHIF's data services architecture, which replaced the Redux store with a more modular approach using service-specific state management and a pub/sub pattern for communication between components.
---

# Overview

Data services are the first category of services which deal with handling non-ui
related state Each service have their own internal state which they handle.

> We have replaced the _redux_ store. Instead, we have introduced various
> services and a pub/sub pattern to subscribe and run, which makes the `OHIF-v3`
> architecture nice and clean.

We maintain the following non-ui Services:

- [DicomMetadata Store](./../data/DicomMetadataStore.md)
- [DisplaySet Service](./../data/DisplaySetService.md)
- [Hanging Protocol Service](../data/HangingProtocolService.md)
- [Toolbar Service](./ToolbarService.md)
- [Measurement Service](../data/MeasurementService.md)
- [Customization Service](./../customization-service/customizationService.md)
- [Panel Service](../data/PanelService.md)

## Service Architecture



> We have explained services and how to create a custom service in the
> [`ServicesManager`](../../managers/service.md) section of the docs

To recap: The simplest service return a new object that has a `name` property,
and `Create` method which instantiate the service class. The "Factory Function"
that creates the service is provided with the implementation (this is slightly
different for UI Services).

```js
// extensions/customExtension/src/services/backEndService/index.js
import backEndService from './backEndService';

export default function WrappedBackEndService(servicesManager) {
  return {
    name: 'myService',
    create: ({ configuration = {} }) => {
      return new backEndService(servicesManager);
    },
  };
}
```

A service, once created, can be registered with the `ServicesManager` to make it
accessible to extensions. Similarly, the application code can access named
services from the `ServicesManager`.

[Read more of how to design a new custom service and register it](../../managers/service.md)

---

### Platform Docs Versioned Docs Version 3.11 Platform Services Ui Index (`platform/docs/versioned_docs/version-3.11/platform/services/ui/index.md`)

---
sidebar_position: 1
sidebar_label: Overview
title: UI Services Overview
summary: Overview of OHIF's UI services architecture, which enables consistent UI interactions across the application through React context providers and service implementations, allowing extensions to leverage components like modals, notifications, and dialogs.
---

# Overview



A typical web application will have components and state for common UI like
modals, notifications, dialogs, etc. A UI service makes it possible to leverage
these components from an extension.

We maintain the following UI Services:

- [UI Notification Service](ui-notification-service.md)
- [UI Modal Service](ui-modal-service.md)
- [UI Dialog Service](ui-dialog-service.md)
- [UI Viewport Dialog Service](ui-viewport-dialog-service.md)
- [CINE Service](cine-service.md)
- [Viewport Grid Service](viewport-grid-service.md)







## Providers for UI services

**There are several context providers that wraps the application routes. This
makes the context values exposed in the app, and service's `setImplementation`
can get run to override the implementation of the service.**

```js title="platform/app/src/App.jsx"
function App({ config, defaultExtensions }) {
  /**...**/
  /**...**/
  return (
    /**...**/
    <ViewportGridProvider service={ViewportGridService}>
      <ViewportDialogProvider service={UIViewportDialogService}>
        <CineProvider service={CineService}>
          <SnackbarProvider service={UINotificationService}>
            <DialogProvider service={UIDialogService}>
              <ModalProvider modal={Modal} service={UIModalService}>
                {appRoutes}
              </ModalProvider>
            </DialogProvider>
          </SnackbarProvider>
        </CineProvider>
      </ViewportDialogProvider>
    </ViewportGridProvider>
    /**...**/
  );
}
```

## Example

For instance `UIModalService` has the following Public API:

```js title="platform/core/src/services/UIModalService/index.js"
const publicAPI = {
  name,
  hide: _hide,
  show: _show,
  setServiceImplementation,
};

function setServiceImplementation({
  hide: hideImplementation,
  show: showImplementation,
}) {
  /** ... **/
  serviceImplementation._hide = hideImplementation;
  serviceImplementation._show = showImplementation;
  /** ... **/
}

export default {
  name: 'UIModalService',
  create: ({ configuration = {} }) => {
    return publicAPI;
  },
};
```

`UIModalService` implementation can be set (override) in its context provider.
For instance in `ModalProvider` we have:

```
/* Detailed source-code truncated for AI context efficiency. */
```

Therefore, anywhere in the app that we have access to react context we can use
it by calling the `useModal` from `@ohif/ui`. As a matter of fact, we are
utilizing the modal for the preference window which shows the hotkeys after
clicking on the gear button on the right side of the header.

A `simplified` code for our worklist is:

```js title="platform/app/src/routes/WorkList/WorkList.jsx"
import { useModal, Header } from '@ohif/ui';

function WorkList({
  history,
  data: studies,
  dataTotal: studiesTotal,
  isLoadingData,
  dataSource,
  hotkeysManager,
}) {
  const { show, hide } = useModal();

  /** ... **/

  const menuOptions = [
    {
      title: t('Header:About'),
      icon: 'info',
      onClick: () => show({ content: AboutModal, title: 'About OHIF Viewer' }),
    },
    {
      title: t('Header:Preferences'),
      icon: 'settings',
      onClick: () =>
        show({
          title: t('UserPreferencesModal:User Preferences'),
          content: UserPreferences,
          contentProps: {
            hotkeyDefaults: hotkeysManager.getValidHotkeyDefinitions(
              hotkeyDefaults
            ),
            hotkeyDefinitions,
            onCancel: hide,
            currentLanguage: currentLanguage(),
            availableLanguages,
            defaultLanguage,
            onSubmit: state => {
              i18n.changeLanguage(state.language.value);
              hotkeysManager.setHotkeys(state.hotkeyDefinitions);
              hide();
            },
            onReset: () => hotkeysManager.restoreDefaultBindings(),
          },
        }),
    },
  ];
  /** ... **/
  return (
    <div>
      /** ... **/
      <Header isSticky menuOptions={menuOptions} isReturnEnabled={false} />
      /** ... **/
    </div>
  );
}
```







## Tips & Tricks

It's important to remember that all we're doing is making it possible to control
bits of the application's UI from an extension. Here are a few non-obvious
takeaways worth mentioning:

- Your application code should continue to use React context
  (consumers/providers) as it normally would
- You can substitute our "out of the box" UI implementations with your own
- You can create and register your own UI services
- You can choose not to register a service or provide a service implementation
- In extensions, you can provide fallback/alternative behavior if an expected
  service is not registered
  - No `UIModalService`? Use the `UINotificationService` to notify users.
- You can technically register a service in an extension and expose it to the
  core application

> Note: These are recommended patterns, not hard and fast rules. Following them
> will help reduce confusion and interoperability with the larger OHIF
> community, but they're not silver bullets. Please speak up, create an issue,
> if you would like to discuss new services or improvements to this pattern.

---

### Platform Docs CHANGELOG (`platform/docs/CHANGELOG.md`)

# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# [3.13.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.88...v3.13.0-beta.89) (2026-06-10)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.87...v3.13.0-beta.88) (2026-06-05)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.86...v3.13.0-beta.87) (2026-05-29)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.85...v3.13.0-beta.86) (2026-05-28)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.84...v3.13.0-beta.85) (2026-05-28)


### Features

* **WorkList:** New Study List (WorkList based on ui-next); old study list renamed to LegacyWorklist ([#6005](https://github.com/OHIF/Viewers/issues/6005)) ([daae4c1](https://github.com/OHIF/Viewers/commit/daae4c144e7cb80bbee7c05d9fceef8b332ed2a0))





# [3.13.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.83...v3.13.0-beta.84) (2026-05-27)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.82...v3.13.0-beta.83) (2026-05-26)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.81...v3.13.0-beta.82) (2026-05-22)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.80...v3.13.0-beta.81) (2026-05-21)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.79...v3.13.0-beta.80) (2026-05-20)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.78...v3.13.0-beta.79) (2026-05-19)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.77...v3.13.0-beta.78) (2026-05-19)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.76...v3.13.0-beta.77) (2026-05-19)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.75...v3.13.0-beta.76) (2026-05-19)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.74...v3.13.0-beta.75) (2026-05-18)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.73...v3.13.0-beta.74) (2026-05-15)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.72...v3.13.0-beta.73) (2026-05-13)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.71...v3.13.0-beta.72) (2026-05-12)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.70...v3.13.0-beta.71) (2026-05-07)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.69...v3.13.0-beta.70) (2026-05-07)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.68...v3.13.0-beta.69) (2026-05-06)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.67...v3.13.0-beta.68) (2026-05-05)


### Bug Fixes

* **ToolGroupService:** Centralize tool binding persistence and provide API to add and remove persisted bindings. ([#5989](https://github.com/OHIF/Viewers/issues/5989)) ([979d619](https://github.com/OHIF/Viewers/commit/979d619f7ccb426beb75d59721b01c98175d5241))





# [3.13.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.66...v3.13.0-beta.67) (2026-04-30)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.65...v3.13.0-beta.66) (2026-04-29)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.64...v3.13.0-beta.65) (2026-04-29)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.63...v3.13.0-beta.64) (2026-04-27)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.62...v3.13.0-beta.63) (2026-04-27)


### Bug Fixes

* **security:** refine dynamic config URL trust policy and document trusted-origin behavior ([#5973](https://github.com/OHIF/Viewers/issues/5973)) ([f3cca21](https://github.com/OHIF/Viewers/commit/f3cca21e49729fbf4bab85aa1de64b9dcfebd0ce))





# [3.13.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.61...v3.13.0-beta.62) (2026-04-23)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.60...v3.13.0-beta.61) (2026-04-23)


### Features

* **slice scrollbar:** Integrate ViewportSliceProgressScrollbar with customizations and docs ([#5960](https://github.com/OHIF/Viewers/issues/5960)) ([8fc0dc1](https://github.com/OHIF/Viewers/commit/8fc0dc16e97f3262fdac902ecf2d7c20cb8f78cc))





# [3.13.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.59...v3.13.0-beta.60) (2026-04-21)


### Bug Fixes

* **configuration:** Harden dynamic datasource URL trust boundaries and credential handling. ([#5963](https://github.com/OHIF/Viewers/issues/5963)) ([eede569](https://github.com/OHIF/Viewers/commit/eede569a88ed6a3177bbdea8552dfb93ca13cac5))





# [3.13.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.58...v3.13.0-beta.59) (2026-04-16)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.57...v3.13.0-beta.58) (2026-04-14)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.56...v3.13.0-beta.57) (2026-04-13)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.55...v3.13.0-beta.56) (2026-04-10)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.54...v3.13.0-beta.55) (2026-04-10)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.53...v3.13.0-beta.54) (2026-04-08)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.52...v3.13.0-beta.53) (2026-04-06)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.51...v3.13.0-beta.52) (2026-04-06)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.50...v3.13.0-beta.51) (2026-04-03)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.49...v3.13.0-beta.50) (2026-04-02)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.48...v3.13.0-beta.49) (2026-04-02)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.47...v3.13.0-beta.48) (2026-04-01)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.46...v3.13.0-beta.47) (2026-03-28)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.45...v3.13.0-beta.46) (2026-03-27)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.44...v3.13.0-beta.45) (2026-03-27)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.43...v3.13.0-beta.44) (2026-03-27)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.42...v3.13.0-beta.43) (2026-03-17)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.41...v3.13.0-beta.42) (2026-03-17)


### Features

* Add combined build ([#5895](https://github.com/OHIF/Viewers/issues/5895)) ([1df671e](https://github.com/OHIF/Viewers/commit/1df671e9ab67d43f98bf09f6838ddc0a5f220277))





# [3.13.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.40...v3.13.0-beta.41) (2026-03-16)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.39...v3.13.0-beta.40) (2026-03-13)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.38...v3.13.0-beta.39) (2026-03-13)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.37...v3.13.0-beta.38) (2026-03-12)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.36...v3.13.0-beta.37) (2026-03-12)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.35...v3.13.0-beta.36) (2026-03-11)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.34...v3.13.0-beta.35) (2026-03-09)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.33...v3.13.0-beta.34) (2026-03-09)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.32...v3.13.0-beta.33) (2026-03-05)


### Bug Fixes

* **security:** Bump svgo and tar to fix vulnerabilities. ([#5877](https://github.com/OHIF/Viewers/issues/5877)) ([61a1fcc](https://github.com/OHIF/Viewers/commit/61a1fccd7d47965831a6c80357219eed979ce4d6))





# [3.13.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.31...v3.13.0-beta.32) (2026-03-05)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.30...v3.13.0-beta.31) (2026-03-04)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.29...v3.13.0-beta.30) (2026-03-04)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.28...v3.13.0-beta.29) (2026-03-04)


### Bug Fixes

* **security:** Address various security vulnerabilities. ([#5869](https://github.com/OHIF/Viewers/issues/5869)) ([be8e266](https://github.com/OHIF/Viewers/commit/be8e266a80f13d03ce9dc4a21a0227d3e1bc36ac))





# [3.13.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.27...v3.13.0-beta.28) (2026-03-03)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.26...v3.13.0-beta.27) (2026-03-02)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.25...v3.13.0-beta.26) (2026-02-28)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.24...v3.13.0-beta.25) (2026-02-26)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.23...v3.13.0-beta.24) (2026-02-24)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.22...v3.13.0-beta.23) (2026-02-23)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.21...v3.13.0-beta.22) (2026-02-23)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.20...v3.13.0-beta.21) (2026-02-23)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.19...v3.13.0-beta.20) (2026-02-21)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.18...v3.13.0-beta.19) (2026-02-20)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.17...v3.13.0-beta.18) (2026-02-19)


### Bug Fixes

* **segmentation overlay:** update viewport ds list upon seg delete - OHIF-2425 ([#5729](https://github.com/OHIF/Viewers/issues/5729)) ([b353541](https://github.com/OHIF/Viewers/commit/b35354120a01d89b27844f967c32c052bba8b096))





# [3.13.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.16...v3.13.0-beta.17) (2026-02-19)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.15...v3.13.0-beta.16) (2026-02-18)


### Bug Fixes

* **security:** Bump tar to 7.5.9 and lerna to 9.0.4 to fix CVE-2026-26960. ([#5824](https://github.com/OHIF/Viewers/issues/5824)) ([3d59c0d](https://github.com/OHIF/Viewers/commit/3d59c0d9d3783336eaa8d37cfc0172818942bf00))





# [3.13.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.14...v3.13.0-beta.15) (2026-02-17)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.14](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.13...v3.13.0-beta.14) (2026-02-13)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.13](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.12...v3.13.0-beta.13) (2026-02-12)


### Bug Fixes

* **colors:** Replace hardcoded black with background color token ([#5815](https://github.com/OHIF/Viewers/issues/5815)) ([dbc31a5](https://github.com/OHIF/Viewers/commit/dbc31a5d4ec5b2238683a580af96aff23d9fafeb))





# [3.13.0-beta.12](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.11...v3.13.0-beta.12) (2026-02-12)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.11](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.10...v3.13.0-beta.11) (2026-02-12)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.10](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.9...v3.13.0-beta.10) (2026-02-11)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.9](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.6...v3.13.0-beta.9) (2026-02-11)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.8](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.6...v3.13.0-beta.8) (2026-02-11)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.7](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.6...v3.13.0-beta.7) (2026-02-10)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.6](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.5...v3.13.0-beta.6) (2026-02-10)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.5](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.4...v3.13.0-beta.5) (2026-02-10)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.4](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.3...v3.13.0-beta.4) (2026-02-10)


### Bug Fixes

* Better handle octet stream case ([#5789](https://github.com/OHIF/Viewers/issues/5789)) ([037402f](https://github.com/OHIF/Viewers/commit/037402f7f6a1fc07593be302e4f578f6c4870c6e))





# [3.13.0-beta.3](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.2...v3.13.0-beta.3) (2026-02-10)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.2](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.1...v3.13.0-beta.2) (2026-02-10)


### Bug Fixes

* **cine:** prevent crash on second view/hydration of SR series  ([#5724](https://github.com/OHIF/Viewers/issues/5724)) ([f70c9b9](https://github.com/OHIF/Viewers/commit/f70c9b932db2bb14173acae675d38ce250d244fa))





# [3.13.0-beta.1](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.0...v3.13.0-beta.1) (2026-02-09)

**Note:** Version bump only for package ohif-docs





# [3.13.0-beta.0](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.135...v3.13.0-beta.0) (2026-02-07)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.134...v3.12.0-beta.135) (2026-02-05)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.133...v3.12.0-beta.134) (2026-02-05)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.132...v3.12.0-beta.133) (2026-02-04)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.131...v3.12.0-beta.132) (2026-01-30)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.130...v3.12.0-beta.131) (2026-01-30)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.129...v3.12.0-beta.130) (2026-01-28)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.128...v3.12.0-beta.129) (2026-01-27)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.127...v3.12.0-beta.128) (2026-01-27)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.126...v3.12.0-beta.127) (2026-01-22)


### Bug Fixes

* Navigate to contour should work ([#5718](https://github.com/OHIF/Viewers/issues/5718)) ([0fd517d](https://github.com/OHIF/Viewers/commit/0fd517d6ab583652a3667f9af49413648f2755db))





# [3.12.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.125...v3.12.0-beta.126) (2026-01-22)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.124...v3.12.0-beta.125) (2026-01-21)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.123...v3.12.0-beta.124) (2026-01-16)


### Bug Fixes

* **microscopy:** Update microscope to 0.48.17 to fix a measurement exception. ([#5710](https://github.com/OHIF/Viewers/issues/5710)) ([4a1f509](https://github.com/OHIF/Viewers/commit/4a1f5098654dc7afef4c135f2e2198a0e785f4b9))





# [3.12.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.122...v3.12.0-beta.123) (2026-01-14)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.121...v3.12.0-beta.122) (2026-01-13)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.120...v3.12.0-beta.121) (2026-01-12)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.119...v3.12.0-beta.120) (2026-01-09)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.119](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.118...v3.12.0-beta.119) (2026-01-08)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.118](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.117...v3.12.0-beta.118) (2026-01-07)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.117](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.116...v3.12.0-beta.117) (2026-01-06)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.116](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.115...v3.12.0-beta.116) (2026-01-06)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.115](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.114...v3.12.0-beta.115) (2026-01-05)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.114](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.113...v3.12.0-beta.114) (2026-01-05)


### Bug Fixes

* **security:** update qs package to fix vulnerability CVE-2025-15284 ([#5686](https://github.com/OHIF/Viewers/issues/5686)) ([ca364a3](https://github.com/OHIF/Viewers/commit/ca364a3af7a29dc98d5c5b8e4c73abebc107c7ce))





# [3.12.0-beta.113](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.112...v3.12.0-beta.113) (2025-12-19)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.111...v3.12.0-beta.112) (2025-12-19)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.110...v3.12.0-beta.111) (2025-12-18)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.109...v3.12.0-beta.110) (2025-12-18)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.108...v3.12.0-beta.109) (2025-12-18)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.107...v3.12.0-beta.108) (2025-12-17)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.106...v3.12.0-beta.107) (2025-12-16)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.105...v3.12.0-beta.106) (2025-12-16)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.104...v3.12.0-beta.105) (2025-12-15)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.103...v3.12.0-beta.104) (2025-12-12)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.102...v3.12.0-beta.103) (2025-12-12)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.101...v3.12.0-beta.102) (2025-12-10)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.100...v3.12.0-beta.101) (2025-12-09)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.99...v3.12.0-beta.100) (2025-12-05)


### Features

* **notification:** add custom notification component support ([#5605](https://github.com/OHIF/Viewers/issues/5605)) ([c4e5a46](https://github.com/OHIF/Viewers/commit/c4e5a4616db87b39df5e16b75f1ba3c18407468f))





# [3.12.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.98...v3.12.0-beta.99) (2025-12-04)


### Bug Fixes

* Initial sort not consistent ([#5224](https://github.com/OHIF/Viewers/issues/5224)) ([77f9f8e](https://github.com/OHIF/Viewers/commit/77f9f8e1c4af6b5d22ecf9332b5edf503cd5b848))





# [3.12.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.97...v3.12.0-beta.98) (2025-12-03)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.96...v3.12.0-beta.97) (2025-12-03)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.95...v3.12.0-beta.96) (2025-12-02)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.94...v3.12.0-beta.95) (2025-12-02)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.93...v3.12.0-beta.94) (2025-12-02)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.92...v3.12.0-beta.93) (2025-11-25)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.91...v3.12.0-beta.92) (2025-11-24)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.90...v3.12.0-beta.91) (2025-11-21)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.89...v3.12.0-beta.90) (2025-11-21)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.88...v3.12.0-beta.89) (2025-11-20)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.87...v3.12.0-beta.88) (2025-11-20)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.86...v3.12.0-beta.87) (2025-11-19)


### Bug Fixes

* **SegmentationStyle:** Fix inactive contour visibility and styling. ([#5563](https://github.com/OHIF/Viewers/issues/5563)) ([5c17c26](https://github.com/OHIF/Viewers/commit/5c17c262eaa5c1229033cfff4b3e7709e874611f))





# [3.12.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.85...v3.12.0-beta.86) (2025-11-13)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.84...v3.12.0-beta.85) (2025-11-11)


### Bug Fixes

* **interpolation:** Auto accept interpolation when the interpolation process is completed. ([#5555](https://github.com/OHIF/Viewers/issues/5555)) ([834ae3c](https://github.com/OHIF/Viewers/commit/834ae3c762ca309187afebdf77bad1ad9a57f03f))





# [3.12.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.83...v3.12.0-beta.84) (2025-11-10)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.82...v3.12.0-beta.83) (2025-11-06)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.81...v3.12.0-beta.82) (2025-11-05)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.80...v3.12.0-beta.81) (2025-11-05)


### Bug Fixes

* **SegmentationTools:** [Bug] Changes of brush/eraser radius with hotkey do not reflect on segmentation tool ([#5535](https://github.com/OHIF/Viewers/issues/5535)) ([29bd87c](https://github.com/OHIF/Viewers/commit/29bd87c8c0592a9a1350e687b862f5452627aece))





# [3.12.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.79...v3.12.0-beta.80) (2025-11-05)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.78...v3.12.0-beta.79) (2025-10-30)


### Bug Fixes

* **security:** Exact versioning and docs dependabot alerts ([#5536](https://github.com/OHIF/Viewers/issues/5536)) ([000e42e](https://github.com/OHIF/Viewers/commit/000e42e9a6eaa4f0878cbf877f03b09a459ad18e))





# [3.12.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.77...v3.12.0-beta.78) (2025-10-29)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.76...v3.12.0-beta.77) (2025-10-28)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.75...v3.12.0-beta.76) (2025-10-27)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.74...v3.12.0-beta.75) (2025-10-24)


### Bug Fixes

* **security:** For bun, enforce frozen lockfile. For yarn, strongly suggest using frozen lockfile. ([#5508](https://github.com/OHIF/Viewers/issues/5508)) ([1009c60](https://github.com/OHIF/Viewers/commit/1009c6091107d2db0768622120f916208a391343))





# [3.12.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.73...v3.12.0-beta.74) (2025-10-23)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.72...v3.12.0-beta.73) (2025-10-22)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.71...v3.12.0-beta.72) (2025-10-22)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.70...v3.12.0-beta.71) (2025-10-21)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.69...v3.12.0-beta.70) (2025-10-20)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.68...v3.12.0-beta.69) (2025-10-20)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.67...v3.12.0-beta.68) (2025-10-18)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.66...v3.12.0-beta.67) (2025-10-17)


### Bug Fixes

* **ErrorBoundary:** Allow for details to be shown in production. ([#5504](https://github.com/OHIF/Viewers/issues/5504)) ([4620cc3](https://github.com/OHIF/Viewers/commit/4620cc3acf89f218c3feaaf4c153a3dc8b023b23))





# [3.12.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.65...v3.12.0-beta.66) (2025-10-17)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.64...v3.12.0-beta.65) (2025-10-17)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.63...v3.12.0-beta.64) (2025-10-15)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.62...v3.12.0-beta.63) (2025-10-15)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.61...v3.12.0-beta.62) (2025-10-15)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.60...v3.12.0-beta.61) (2025-10-15)


### Bug Fixes

* **docs:** Set exact version for glob. ([#5497](https://github.com/OHIF/Viewers/issues/5497)) ([0d2f4e7](https://github.com/OHIF/Viewers/commit/0d2f4e715a941fa458ebf8e64972088580a04952))





# [3.12.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.59...v3.12.0-beta.60) (2025-10-15)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.58...v3.12.0-beta.59) (2025-10-14)


### Bug Fixes

* **security:** Use exact versioning for dependencies in package.json files. ([#5494](https://github.com/OHIF/Viewers/issues/5494)) ([c7d2017](https://github.com/OHIF/Viewers/commit/c7d2017f081c5803a70bab6c75bba0c975028125))





# [3.12.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.57...v3.12.0-beta.58) (2025-10-14)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.56...v3.12.0-beta.57) (2025-10-14)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.55...v3.12.0-beta.56) (2025-10-10)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.54...v3.12.0-beta.55) (2025-10-09)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.53...v3.12.0-beta.54) (2025-10-08)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.52...v3.12.0-beta.53) (2025-10-07)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.51...v3.12.0-beta.52) (2025-10-07)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.50...v3.12.0-beta.51) (2025-10-07)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.49...v3.12.0-beta.50) (2025-10-07)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.48...v3.12.0-beta.49) (2025-10-07)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.47...v3.12.0-beta.48) (2025-10-07)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.46...v3.12.0-beta.47) (2025-10-07)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.45...v3.12.0-beta.46) (2025-10-06)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.44...v3.12.0-beta.45) (2025-10-06)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.43...v3.12.0-beta.44) (2025-10-06)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.42...v3.12.0-beta.43) (2025-10-06)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.41...v3.12.0-beta.42) (2025-10-03)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.40...v3.12.0-beta.41) (2025-10-03)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.39...v3.12.0-beta.40) (2025-10-02)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.38...v3.12.0-beta.39) (2025-10-01)


### Features

* Add inherit from basic/longitudinal modes ([#5435](https://github.com/OHIF/Viewers/issues/5435)) ([9ad0d7f](https://github.com/OHIF/Viewers/commit/9ad0d7fc8cf34867fa2cfc2bf2b2f63451ec03e5))





# [3.12.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.37...v3.12.0-beta.38) (2025-09-30)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.36...v3.12.0-beta.37) (2025-09-30)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.35...v3.12.0-beta.36) (2025-09-30)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.34...v3.12.0-beta.35) (2025-09-29)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.33...v3.12.0-beta.34) (2025-09-29)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.32...v3.12.0-beta.33) (2025-09-29)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.31...v3.12.0-beta.32) (2025-09-26)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.30...v3.12.0-beta.31) (2025-09-25)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.29...v3.12.0-beta.30) (2025-09-25)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.28...v3.12.0-beta.29) (2025-09-22)


### Features

* **Segmentation:** Segmentation highlight animation function selection ([#5401](https://github.com/OHIF/Viewers/issues/5401)) ([69dbe27](https://github.com/OHIF/Viewers/commit/69dbe2778493cdfc7a8da5e757c95217bb31edc2))





# [3.12.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.27...v3.12.0-beta.28) (2025-09-19)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.26...v3.12.0-beta.27) (2025-09-17)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.25...v3.12.0-beta.26) (2025-09-17)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.24...v3.12.0-beta.25) (2025-09-16)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.23...v3.12.0-beta.24) (2025-09-10)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.22...v3.12.0-beta.23) (2025-09-05)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.21...v3.12.0-beta.22) (2025-08-29)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.20...v3.12.0-beta.21) (2025-08-29)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.19...v3.12.0-beta.20) (2025-08-28)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.18...v3.12.0-beta.19) (2025-08-28)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.17...v3.12.0-beta.18) (2025-08-28)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.16...v3.12.0-beta.17) (2025-08-28)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.15...v3.12.0-beta.16) (2025-08-25)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.14...v3.12.0-beta.15) (2025-08-25)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.14](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.13...v3.12.0-beta.14) (2025-08-25)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.13](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.12...v3.12.0-beta.13) (2025-08-25)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.12](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.11...v3.12.0-beta.12) (2025-08-25)


### Bug Fixes

* Segmentation stats customization module ([#5324](https://github.com/OHIF/Viewers/issues/5324)) ([b9d6f55](https://github.com/OHIF/Viewers/commit/b9d6f558cbe5957f83e6d92305a78662a0b186ed))





# [3.12.0-beta.11](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.10...v3.12.0-beta.11) (2025-08-25)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.10](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.9...v3.12.0-beta.10) (2025-08-22)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.9](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.8...v3.12.0-beta.9) (2025-08-22)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.8](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.7...v3.12.0-beta.8) (2025-08-20)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.7](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.6...v3.12.0-beta.7) (2025-08-15)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.6](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.5...v3.12.0-beta.6) (2025-08-13)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.5](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.4...v3.12.0-beta.5) (2025-08-11)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.4](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.3...v3.12.0-beta.4) (2025-08-11)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.3](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.2...v3.12.0-beta.3) (2025-08-11)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.2](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.1...v3.12.0-beta.2) (2025-08-08)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.1](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.0...v3.12.0-beta.1) (2025-08-05)

**Note:** Version bump only for package ohif-docs





# [3.12.0-beta.0](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.116...v3.12.0-beta.0) (2025-08-05)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.116](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.115...v3.11.0-beta.116) (2025-08-05)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.115](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.114...v3.11.0-beta.115) (2025-07-31)


### Features

* add support to scoord3d ([#5016](https://github.com/OHIF/Viewers/issues/5016)) ([735405a](https://github.com/OHIF/Viewers/commit/735405a8554c7ee6283faa83fc42ff8bb9ac34ff))





# [3.11.0-beta.114](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.113...v3.11.0-beta.114) (2025-07-30)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.113](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.112...v3.11.0-beta.113) (2025-07-30)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.111...v3.11.0-beta.112) (2025-07-28)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.110...v3.11.0-beta.111) (2025-07-28)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.109...v3.11.0-beta.110) (2025-07-28)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.108...v3.11.0-beta.109) (2025-07-28)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.107...v3.11.0-beta.108) (2025-07-25)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.106...v3.11.0-beta.107) (2025-07-25)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.105...v3.11.0-beta.106) (2025-07-24)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.104...v3.11.0-beta.105) (2025-07-23)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.103...v3.11.0-beta.104) (2025-07-23)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.102...v3.11.0-beta.103) (2025-07-23)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.101...v3.11.0-beta.102) (2025-07-23)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.100...v3.11.0-beta.101) (2025-07-23)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.99...v3.11.0-beta.100) (2025-07-23)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.98...v3.11.0-beta.99) (2025-07-23)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.97...v3.11.0-beta.98) (2025-07-23)


### Bug Fixes

* **docs:** Added docs for multimonitor and local linking ([#5247](https://github.com/OHIF/Viewers/issues/5247)) ([83ea0ad](https://github.com/OHIF/Viewers/commit/83ea0ad93e6cd278e9a585c1bd1c27fccd426d5a))





# [3.11.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.96...v3.11.0-beta.97) (2025-07-22)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.95...v3.11.0-beta.96) (2025-07-22)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.94...v3.11.0-beta.95) (2025-07-21)


### Bug Fixes

* **docs:** Added entry for the showStudyList configuration setting. ([#5235](https://github.com/OHIF/Viewers/issues/5235)) ([bde0eb1](https://github.com/OHIF/Viewers/commit/bde0eb1f07698b7375f7c4a58753d0368703e5bf))





# [3.11.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.93...v3.11.0-beta.94) (2025-07-21)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.92...v3.11.0-beta.93) (2025-07-21)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.91...v3.11.0-beta.92) (2025-07-18)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.90...v3.11.0-beta.91) (2025-07-17)


### Bug Fixes

* image slices are displayed in reverse order, if we switch from common layout to 2D MPR ([#5022](https://github.com/OHIF/Viewers/issues/5022)) ([6a4ca70](https://github.com/OHIF/Viewers/commit/6a4ca7083623f21ae4c810507da0c4634bc10de9))





# [3.11.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.89...v3.11.0-beta.90) (2025-07-16)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.88...v3.11.0-beta.89) (2025-07-16)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.87...v3.11.0-beta.88) (2025-07-16)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.86...v3.11.0-beta.87) (2025-07-15)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.85...v3.11.0-beta.86) (2025-07-14)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.84...v3.11.0-beta.85) (2025-07-14)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.83...v3.11.0-beta.84) (2025-07-14)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.82...v3.11.0-beta.83) (2025-07-11)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.81...v3.11.0-beta.82) (2025-07-11)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.80...v3.11.0-beta.81) (2025-07-11)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.79...v3.11.0-beta.80) (2025-07-11)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.78...v3.11.0-beta.79) (2025-07-11)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.77...v3.11.0-beta.78) (2025-07-11)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.76...v3.11.0-beta.77) (2025-07-10)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.75...v3.11.0-beta.76) (2025-07-10)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.74...v3.11.0-beta.75) (2025-07-09)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.73...v3.11.0-beta.74) (2025-07-08)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.72...v3.11.0-beta.73) (2025-07-07)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.71...v3.11.0-beta.72) (2025-07-03)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.70...v3.11.0-beta.71) (2025-07-03)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.69...v3.11.0-beta.70) (2025-07-03)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.68...v3.11.0-beta.69) (2025-07-02)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.67...v3.11.0-beta.68) (2025-06-27)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.66...v3.11.0-beta.67) (2025-06-27)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.65...v3.11.0-beta.66) (2025-06-27)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.64...v3.11.0-beta.65) (2025-06-26)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.63...v3.11.0-beta.64) (2025-06-26)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.62...v3.11.0-beta.63) (2025-06-26)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.61...v3.11.0-beta.62) (2025-06-25)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.60...v3.11.0-beta.61) (2025-06-25)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.59...v3.11.0-beta.60) (2025-06-24)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.58...v3.11.0-beta.59) (2025-06-20)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.57...v3.11.0-beta.58) (2025-06-18)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.56...v3.11.0-beta.57) (2025-06-18)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.55...v3.11.0-beta.56) (2025-06-13)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.54...v3.11.0-beta.55) (2025-06-11)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.53...v3.11.0-beta.54) (2025-06-11)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.52...v3.11.0-beta.53) (2025-06-11)


### Bug Fixes

* data-viewportId name is illegal, renamed to data-viewportid ([#5121](https://github.com/OHIF/Viewers/issues/5121)) ([75271ca](https://github.com/OHIF/Viewers/commit/75271ca416173ddb71972ed311f9d729443cf763))





# [3.11.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.51...v3.11.0-beta.52) (2025-06-10)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.50...v3.11.0-beta.51) (2025-06-09)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.49...v3.11.0-beta.50) (2025-06-09)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.48...v3.11.0-beta.49) (2025-06-07)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.47...v3.11.0-beta.48) (2025-06-05)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.46...v3.11.0-beta.47) (2025-06-02)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.45...v3.11.0-beta.46) (2025-06-02)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.44...v3.11.0-beta.45) (2025-05-30)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.43...v3.11.0-beta.44) (2025-05-29)


### Features

* create memo when manually adding and removing annotations ([#5051](https://github.com/OHIF/Viewers/issues/5051)) ([5891505](https://github.com/OHIF/Viewers/commit/5891505c51f82ecad22fb8182b88fb3fb52255b3))





# [3.11.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.42...v3.11.0-beta.43) (2025-05-29)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.41...v3.11.0-beta.42) (2025-05-28)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.40...v3.11.0-beta.41) (2025-05-26)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.39...v3.11.0-beta.40) (2025-05-26)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.38...v3.11.0-beta.39) (2025-05-26)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.37...v3.11.0-beta.38) (2025-05-24)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.36...v3.11.0-beta.37) (2025-05-16)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.35...v3.11.0-beta.36) (2025-05-16)


### Bug Fixes

* backward compatibility with toolbar service ([#5052](https://github.com/OHIF/Viewers/issues/5052)) ([9b1b501](https://github.com/OHIF/Viewers/commit/9b1b501d83502d13b285050bd5fca102b7f7612c))





# [3.11.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.34...v3.11.0-beta.35) (2025-05-16)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.33...v3.11.0-beta.34) (2025-05-15)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.32...v3.11.0-beta.33) (2025-05-15)


### Features

* **actions:** simplify action corner api through the toolbarService ([#5033](https://github.com/OHIF/Viewers/issues/5033)) ([7c15bb8](https://github.com/OHIF/Viewers/commit/7c15bb8901001eefedc72498176ac24f6662bfab))





# [3.11.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.31...v3.11.0-beta.32) (2025-05-13)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.30...v3.11.0-beta.31) (2025-05-12)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.29...v3.11.0-beta.30) (2025-05-09)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.28...v3.11.0-beta.29) (2025-05-08)


### Features

* **app:** Decouple colorbar UI from service and enable action menu programatic control ([#5018](https://github.com/OHIF/Viewers/issues/5018)) ([1445e12](https://github.com/OHIF/Viewers/commit/1445e1212415e6e6957fce4a8fc6908aed69a93c))





# [3.11.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.27...v3.11.0-beta.28) (2025-05-08)


### Features

* **thumbnails:** Enhance DICOM Thumbnail Rendering with different strategies ([#5004](https://github.com/OHIF/Viewers/issues/5004)) ([578c393](https://github.com/OHIF/Viewers/commit/578c3939f0271f762d6a1290216dbc4bf59dd88b))





# [3.11.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.26...v3.11.0-beta.27) (2025-05-07)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.25...v3.11.0-beta.26) (2025-05-07)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.24...v3.11.0-beta.25) (2025-05-06)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.23...v3.11.0-beta.24) (2025-05-05)


### Features

* **data overlay:** add foreground background control plus orientation change in the UI and add RTDOSE support ([#5007](https://github.com/OHIF/Viewers/issues/5007)) ([cd4e640](https://github.com/OHIF/Viewers/commit/cd4e6408bc2964e5ee27427cdc328751eaf4d088))





# [3.11.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.22...v3.11.0-beta.23) (2025-05-05)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.21...v3.11.0-beta.22) (2025-05-02)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.20...v3.11.0-beta.21) (2025-05-02)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.19...v3.11.0-beta.20) (2025-05-01)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.18...v3.11.0-beta.19) (2025-05-01)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.17...v3.11.0-beta.18) (2025-04-30)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.16...v3.11.0-beta.17) (2025-04-29)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.15...v3.11.0-beta.16) (2025-04-29)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.14...v3.11.0-beta.15) (2025-04-22)


### Bug Fixes

* **docs:** Fix SSR build errors by dynamically importing UI components and resolving other issues ([#4991](https://github.com/OHIF/Viewers/issues/4991)) ([09ac43f](https://github.com/OHIF/Viewers/commit/09ac43f297fa81101d3a3eaa9b5cfef8e01ea214))





# [3.11.0-beta.14](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.13...v3.11.0-beta.14) (2025-04-22)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.13](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.12...v3.11.0-beta.13) (2025-04-22)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.12](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.11...v3.11.0-beta.12) (2025-04-22)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.11](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.10...v3.11.0-beta.11) (2025-04-18)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.10](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.9...v3.11.0-beta.10) (2025-04-17)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.9](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.8...v3.11.0-beta.9) (2025-04-17)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.8](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.7...v3.11.0-beta.8) (2025-04-16)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.7](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.6...v3.11.0-beta.7) (2025-04-16)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.6](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.5...v3.11.0-beta.6) (2025-04-16)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.5](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.4...v3.11.0-beta.5) (2025-04-14)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.4](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.3...v3.11.0-beta.4) (2025-04-11)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.3](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.2...v3.11.0-beta.3) (2025-04-11)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.2](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.1...v3.11.0-beta.2) (2025-04-11)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.1](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.0...v3.11.0-beta.1) (2025-04-10)

**Note:** Version bump only for package ohif-docs





# [3.11.0-beta.0](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.159...v3.11.0-beta.0) (2025-04-10)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.159](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.158...v3.10.0-beta.159) (2025-04-09)


### Bug Fixes

* **ui:** Enhance UI Components and Update CornerstoneJS Dependencies and resizable panels ([#4938](https://github.com/OHIF/Viewers/issues/4938)) ([43bc142](https://github.com/OHIF/Viewers/commit/43bc142439aab1a6514ba1711f86d64ac8bb1acb))





# [3.10.0-beta.158](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.157...v3.10.0-beta.158) (2025-04-09)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.157](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.156...v3.10.0-beta.157) (2025-04-09)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.156](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.155...v3.10.0-beta.156) (2025-04-08)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.155](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.154...v3.10.0-beta.155) (2025-04-08)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.154](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.153...v3.10.0-beta.154) (2025-04-08)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.153](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.152...v3.10.0-beta.153) (2025-04-08)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.152](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.151...v3.10.0-beta.152) (2025-04-07)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.151](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.150...v3.10.0-beta.151) (2025-04-07)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.150](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.149...v3.10.0-beta.150) (2025-04-04)


### Bug Fixes

* **cine:** Resolve Cine Player Faults on DisplaySet Update ([#4909](https://github.com/OHIF/Viewers/issues/4909)) ([746f252](https://github.com/OHIF/Viewers/commit/746f2524eb5e3ec1d36fbb35dc2cc5b55c7ba99f))





# [3.10.0-beta.149](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.148...v3.10.0-beta.149) (2025-04-04)


### Features

* **image capture:** Enhance SEG and RTSS Support with Dependency Updates and Bug Fixes ([#4924](https://github.com/OHIF/Viewers/issues/4924)) ([fc33bd0](https://github.com/OHIF/Viewers/commit/fc33bd0d594a1ac8de79b11080ead48630a8ca27))





# [3.10.0-beta.148](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.147...v3.10.0-beta.148) (2025-04-04)


### Features

* Automate tracking prompts for a less disruptive annotation workflow ([#4822](https://github.com/OHIF/Viewers/issues/4822)) ([54fded5](https://github.com/OHIF/Viewers/commit/54fded554e934f2f75e00d456ebad7692d561225))





# [3.10.0-beta.147](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.146...v3.10.0-beta.147) (2025-04-03)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.146](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.145...v3.10.0-beta.146) (2025-04-02)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.145](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.144...v3.10.0-beta.145) (2025-04-02)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.144](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.143...v3.10.0-beta.144) (2025-04-01)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.143](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.142...v3.10.0-beta.143) (2025-04-01)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.142](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.141...v3.10.0-beta.142) (2025-03-31)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.141](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.140...v3.10.0-beta.141) (2025-03-28)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.140](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.139...v3.10.0-beta.140) (2025-03-27)


### Bug Fixes

* routerBasename setting ([#4891](https://github.com/OHIF/Viewers/issues/4891)) ([459b0d2](https://github.com/OHIF/Viewers/commit/459b0d223a5867aaaabe1b5b61fd22b040ce5602))





# [3.10.0-beta.139](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.138...v3.10.0-beta.139) (2025-03-27)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.138](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.137...v3.10.0-beta.138) (2025-03-26)


### Bug Fixes

* remove duplicated deleteMeasurements code ([#4895](https://github.com/OHIF/Viewers/issues/4895)) ([9bde644](https://github.com/OHIF/Viewers/commit/9bde644fce6db56d7d0dd62a876312559b7b2beb))





# [3.10.0-beta.137](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.136...v3.10.0-beta.137) (2025-03-26)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.136](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.135...v3.10.0-beta.136) (2025-03-25)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.134...v3.10.0-beta.135) (2025-03-25)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.133...v3.10.0-beta.134) (2025-03-20)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.132...v3.10.0-beta.133) (2025-03-20)


### Features

* add customization to PanelStudyBrowser dbl click callback ([#4871](https://github.com/OHIF/Viewers/issues/4871)) ([01c3726](https://github.com/OHIF/Viewers/commit/01c3726ced9afaa75b7c78fd22b380b42151c671))





# [3.10.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.131...v3.10.0-beta.132) (2025-03-20)


### Features

* Group findings table values with custom components/grouping functions ([#4712](https://github.com/OHIF/Viewers/issues/4712)) ([df8efba](https://github.com/OHIF/Viewers/commit/df8efba82c268633ea05b5cb915061bceaec912c))





# [3.10.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.130...v3.10.0-beta.131) (2025-03-19)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.129...v3.10.0-beta.130) (2025-03-19)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.128...v3.10.0-beta.129) (2025-03-18)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.127...v3.10.0-beta.128) (2025-03-18)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.126...v3.10.0-beta.127) (2025-03-18)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.125...v3.10.0-beta.126) (2025-03-18)


### Features

* **segmentation:** segment statistics, labelmap interpolation and segment bidirectional ([#4865](https://github.com/OHIF/Viewers/issues/4865)) ([ec79b55](https://github.com/OHIF/Viewers/commit/ec79b5523e262efd775149cd86b87b870d05d6bc))





# [3.10.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.124...v3.10.0-beta.125) (2025-03-17)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.123...v3.10.0-beta.124) (2025-03-17)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.122...v3.10.0-beta.123) (2025-03-17)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.121...v3.10.0-beta.122) (2025-03-17)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.120...v3.10.0-beta.121) (2025-03-11)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.119...v3.10.0-beta.120) (2025-03-11)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.119](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.118...v3.10.0-beta.119) (2025-03-10)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.118](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.117...v3.10.0-beta.118) (2025-03-07)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.117](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.116...v3.10.0-beta.117) (2025-03-07)


### Features

* **toolbox:** Refactor Toolbar and Toolbox to enable sections ([#4825](https://github.com/OHIF/Viewers/issues/4825)) ([cc5cdfb](https://github.com/OHIF/Viewers/commit/cc5cdfb08158eaa1fa576875f959a665e72f9d5e))





# [3.10.0-beta.116](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.115...v3.10.0-beta.116) (2025-03-06)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.115](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.114...v3.10.0-beta.115) (2025-02-28)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.114](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.113...v3.10.0-beta.114) (2025-02-28)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.113](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.112...v3.10.0-beta.113) (2025-02-28)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)


### Features

* separate checks for addWindowLevelActionMenu and addSegmentationOverlay ([#4813](https://github.com/OHIF/Viewers/issues/4813)) ([7f0cc0f](https://github.com/OHIF/Viewers/commit/7f0cc0f60e74a2e0ac2aea1fe6a786582b495c4e))





# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)


### Features

* **hotkeys:** Migrate hotkeys to customization service and fix issues with overrides ([#4777](https://github.com/OHIF/Viewers/issues/4777)) ([3e6913b](https://github.com/OHIF/Viewers/commit/3e6913b097569280a5cc2fa5bbe4add52f149305))





# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)


### Bug Fixes

* **core:** Address 3D reconstruction and Android compatibility issues and clean up 4D data mode ([#4762](https://github.com/OHIF/Viewers/issues/4762)) ([149d6d0](https://github.com/OHIF/Viewers/commit/149d6d049cd333b9e5846576b403ff387558a66f))





# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)


### Features

* **ui:** Add support for Custom Modal component in Modal Service ([#4752](https://github.com/OHIF/Viewers/issues/4752)) ([2c183aa](https://github.com/OHIF/Viewers/commit/2c183aa4a777d7b5a0417ebcc8576a0fc2631ad2))





# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)


### Features

* **ui:** customization option for viewport notification ([#4638](https://github.com/OHIF/Viewers/issues/4638)) ([8acbd76](https://github.com/OHIF/Viewers/commit/8acbd760d801dcaf624c5d9fb636a029201b91e1))





# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)


### Features

* Add customization support for more UI components  ([#4634](https://github.com/OHIF/Viewers/issues/4634)) ([f15eb44](https://github.com/OHIF/Viewers/commit/f15eb44b4cf49de1b73a22512571cec02effaef3))





# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)


### Features

* **customization:** enable custom onDropHandler for viewportGrid ([#4641](https://github.com/OHIF/Viewers/issues/4641)) ([054b262](https://github.com/OHIF/Viewers/commit/054b262e9cbeb0f44de65d05641efe1e8944a4f5))





# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)


### Bug Fixes

* **dependencies:** Update dcmjs library and improve documentation links ([#4741](https://github.com/OHIF/Viewers/issues/4741)) ([d554f02](https://github.com/OHIF/Viewers/commit/d554f02f7cdb876e4132fb94e3b3df8d11b7bb5c))





# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.75...v3.10.0-beta.76) (2025-01-27)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.74...v3.10.0-beta.75) (2025-01-27)


### Features

* **static-wado:** add support for case-insensitive searching ([#4603](https://github.com/OHIF/Viewers/issues/4603)) ([ac6e674](https://github.com/OHIF/Viewers/commit/ac6e674b4d094f942556d045178011bbf3f81796))





# [3.10.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.73...v3.10.0-beta.74) (2025-01-27)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.72...v3.10.0-beta.73) (2025-01-24)


### Bug Fixes

* **docs:** image in customization ([#4735](https://github.com/OHIF/Viewers/issues/4735)) ([28fb921](https://github.com/OHIF/Viewers/commit/28fb92108988c3304344690792947c847bad72a6))





# [3.10.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.71...v3.10.0-beta.72) (2025-01-24)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.70...v3.10.0-beta.71) (2025-01-23)


### Features

* **customization:** new customization service api ([#4688](https://github.com/OHIF/Viewers/issues/4688)) ([55ad8ef](https://github.com/OHIF/Viewers/commit/55ad8efbabc3fabd8031fc08927b2f92ae5aec69))





# [3.10.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.69...v3.10.0-beta.70) (2025-01-23)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.68...v3.10.0-beta.69) (2025-01-22)


### Bug Fixes

* **seg:** sphere scissor on stack and cpu rendering reset properties was broken ([#4721](https://github.com/OHIF/Viewers/issues/4721)) ([f00d182](https://github.com/OHIF/Viewers/commit/f00d18292f02e8910215d913edfc994850a68d88))





# [3.10.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.67...v3.10.0-beta.68) (2025-01-21)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.66...v3.10.0-beta.67) (2025-01-21)


### Bug Fixes

* **ui:** Update dependencies and add missing icons ([#4699](https://github.com/OHIF/Viewers/issues/4699)) ([cf97fa9](https://github.com/OHIF/Viewers/commit/cf97fa9b7b9687a9b73c1cf6926bc9fbc39b6512))





# [3.10.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.65...v3.10.0-beta.66) (2025-01-21)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.64...v3.10.0-beta.65) (2025-01-20)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.63...v3.10.0-beta.64) (2025-01-20)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.62...v3.10.0-beta.63) (2025-01-17)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.61...v3.10.0-beta.62) (2025-01-16)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.60...v3.10.0-beta.61) (2025-01-16)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.59...v3.10.0-beta.60) (2025-01-15)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.58...v3.10.0-beta.59) (2025-01-14)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.57...v3.10.0-beta.58) (2025-01-13)


### Features

* **multimonitor:** Add simple multi-monitor support to open another study([#4178](https://github.com/OHIF/Viewers/issues/4178)) ([07c628e](https://github.com/OHIF/Viewers/commit/07c628e689b28f831317a7c28d712509b69c6b13))





# [3.10.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.56...v3.10.0-beta.57) (2025-01-13)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.55...v3.10.0-beta.56) (2025-01-13)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.54...v3.10.0-beta.55) (2025-01-10)


### Features

* **dev:** move to rsbuild for dev - faster ([#4674](https://github.com/OHIF/Viewers/issues/4674)) ([d4a4267](https://github.com/OHIF/Viewers/commit/d4a4267429c02916dd51f6aefb290d96dd1c3b04))





# [3.10.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.53...v3.10.0-beta.54) (2025-01-10)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.52...v3.10.0-beta.53) (2025-01-10)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.51...v3.10.0-beta.52) (2025-01-10)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.50...v3.10.0-beta.51) (2025-01-10)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.49...v3.10.0-beta.50) (2025-01-10)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.48...v3.10.0-beta.49) (2025-01-09)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.47...v3.10.0-beta.48) (2025-01-09)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.46...v3.10.0-beta.47) (2025-01-09)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.45...v3.10.0-beta.46) (2025-01-08)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.44...v3.10.0-beta.45) (2025-01-08)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.43...v3.10.0-beta.44) (2025-01-08)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.42...v3.10.0-beta.43) (2025-01-08)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.41...v3.10.0-beta.42) (2025-01-08)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.40...v3.10.0-beta.41) (2025-01-08)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.39...v3.10.0-beta.40) (2025-01-08)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.38...v3.10.0-beta.39) (2025-01-08)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.37...v3.10.0-beta.38) (2025-01-07)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.36...v3.10.0-beta.37) (2025-01-06)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.35...v3.10.0-beta.36) (2025-01-03)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.34...v3.10.0-beta.35) (2025-01-03)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.33...v3.10.0-beta.34) (2025-01-02)


### Bug Fixes

* Docker build time was very slow on a tiny change ([#4559](https://github.com/OHIF/Viewers/issues/4559)) ([7e43b2f](https://github.com/OHIF/Viewers/commit/7e43b2f768cfc3e08ecde9dfdae275194daece2b))





# [3.10.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.32...v3.10.0-beta.33) (2024-12-20)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.31...v3.10.0-beta.32) (2024-12-20)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.30...v3.10.0-beta.31) (2024-12-20)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.29...v3.10.0-beta.30) (2024-12-18)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.28...v3.10.0-beta.29) (2024-12-18)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.27...v3.10.0-beta.28) (2024-12-18)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.26...v3.10.0-beta.27) (2024-12-18)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.25...v3.10.0-beta.26) (2024-12-18)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.24...v3.10.0-beta.25) (2024-12-17)


### Bug Fixes

* Documentation and default enabled for bulkdata load ([#4607](https://github.com/OHIF/Viewers/issues/4607)) ([d0ccdbd](https://github.com/OHIF/Viewers/commit/d0ccdbd68db1dcb190b5a288dd455f573eddc280))





# [3.10.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.23...v3.10.0-beta.24) (2024-12-17)


### Features

* migrate icons to ui-next  ([#4606](https://github.com/OHIF/Viewers/issues/4606)) ([4e2ae32](https://github.com/OHIF/Viewers/commit/4e2ae328744ed95589c2cdf7a531454a25bf88b5))





# [3.10.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.22...v3.10.0-beta.23) (2024-12-17)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.21...v3.10.0-beta.22) (2024-12-13)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.20...v3.10.0-beta.21) (2024-12-11)


### Features

* **node:** move to node 20 ([#4594](https://github.com/OHIF/Viewers/issues/4594)) ([1f04d6c](https://github.com/OHIF/Viewers/commit/1f04d6c1be729a26fe7bcda923770a1cd461053c))





# [3.10.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.19...v3.10.0-beta.20) (2024-12-11)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.18...v3.10.0-beta.19) (2024-12-11)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.17...v3.10.0-beta.18) (2024-12-06)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.16...v3.10.0-beta.17) (2024-12-06)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.15...v3.10.0-beta.16) (2024-12-05)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.14...v3.10.0-beta.15) (2024-12-05)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.14](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.13...v3.10.0-beta.14) (2024-12-03)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.13](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.12...v3.10.0-beta.13) (2024-12-02)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.12](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.11...v3.10.0-beta.12) (2024-11-29)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.11](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.10...v3.10.0-beta.11) (2024-11-28)


### Bug Fixes

* **multiframe:** metadata handling of NM studies and loading order  ([#4554](https://github.com/OHIF/Viewers/issues/4554)) ([7624ccb](https://github.com/OHIF/Viewers/commit/7624ccb5e495c0a151227a458d8d5bfb8babb22c))





# [3.10.0-beta.10](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.9...v3.10.0-beta.10) (2024-11-28)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.9](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.8...v3.10.0-beta.9) (2024-11-22)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.8](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.7...v3.10.0-beta.8) (2024-11-22)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.7](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.6...v3.10.0-beta.7) (2024-11-22)


### Bug Fixes

* Make the commands ordering the registration order of hte mode ([#4492](https://github.com/OHIF/Viewers/issues/4492)) ([edfaf72](https://github.com/OHIF/Viewers/commit/edfaf7248d217707e90d24642361a40c6f1a03ff))





# [3.10.0-beta.6](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.5...v3.10.0-beta.6) (2024-11-22)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.5](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.4...v3.10.0-beta.5) (2024-11-15)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.4](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.3...v3.10.0-beta.4) (2024-11-15)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.3](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.2...v3.10.0-beta.3) (2024-11-14)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.2](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.1...v3.10.0-beta.2) (2024-11-13)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.1](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.0...v3.10.0-beta.1) (2024-11-12)

**Note:** Version bump only for package ohif-docs





# [3.10.0-beta.0](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.111...v3.10.0-beta.0) (2024-11-12)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.110...v3.9.0-beta.111) (2024-11-12)


### Bug Fixes

* Have an addIcon that adds to both ui and ui-next ([#4490](https://github.com/OHIF/Viewers/issues/4490)) ([4a12523](https://github.com/OHIF/Viewers/commit/4a125236ddbf8a4a95fb9c5820f511d0224e663f))
* Measurement Tracking: Various UI and functionality improvements ([#4481](https://github.com/OHIF/Viewers/issues/4481)) ([62b2748](https://github.com/OHIF/Viewers/commit/62b27488471c9d5979142e2d15872a85778b90ed))





# [3.9.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.109...v3.9.0-beta.110) (2024-11-11)


### Bug Fixes

* **bugs:** Update dependencies and enhance UI components ([#4478](https://github.com/OHIF/Viewers/issues/4478)) ([05d41c5](https://github.com/OHIF/Viewers/commit/05d41c52068a3b7ba249f15ecdf71838c352fd30))





# [3.9.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.108...v3.9.0-beta.109) (2024-11-08)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.107...v3.9.0-beta.108) (2024-11-07)


### Bug Fixes

* **tmtv:** fix toggle one up weird behaviours ([#4473](https://github.com/OHIF/Viewers/issues/4473)) ([aa2b649](https://github.com/OHIF/Viewers/commit/aa2b649444eb4fe5422e72ea7830a709c4d24a90))





# [3.9.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.106...v3.9.0-beta.107) (2024-11-06)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.105...v3.9.0-beta.106) (2024-11-06)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.104...v3.9.0-beta.105) (2024-11-05)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.103...v3.9.0-beta.104) (2024-10-30)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.102...v3.9.0-beta.103) (2024-10-29)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.101...v3.9.0-beta.102) (2024-10-29)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.100...v3.9.0-beta.101) (2024-10-18)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.99...v3.9.0-beta.100) (2024-10-17)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.98...v3.9.0-beta.99) (2024-10-17)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.97...v3.9.0-beta.98) (2024-10-15)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.96...v3.9.0-beta.97) (2024-10-11)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.95...v3.9.0-beta.96) (2024-10-10)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.94...v3.9.0-beta.95) (2024-10-08)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.93...v3.9.0-beta.94) (2024-10-04)


### Features

* **tours:** freeze versions and add licensings doc ([#4407](https://github.com/OHIF/Viewers/issues/4407)) ([60a8d51](https://github.com/OHIF/Viewers/commit/60a8d5154a5d6d2b121bd93aeacf12d97ef9f8cb))





# [3.9.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.92...v3.9.0-beta.93) (2024-10-04)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.91...v3.9.0-beta.92) (2024-10-01)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.90...v3.9.0-beta.91) (2024-10-01)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.89...v3.9.0-beta.90) (2024-09-30)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.88...v3.9.0-beta.89) (2024-09-27)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.87...v3.9.0-beta.88) (2024-09-24)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.86...v3.9.0-beta.87) (2024-09-19)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.85...v3.9.0-beta.86) (2024-09-19)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.84...v3.9.0-beta.85) (2024-09-17)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.83...v3.9.0-beta.84) (2024-09-12)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.82...v3.9.0-beta.83) (2024-09-11)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.81...v3.9.0-beta.82) (2024-09-05)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.80...v3.9.0-beta.81) (2024-08-27)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.79...v3.9.0-beta.80) (2024-08-16)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.78...v3.9.0-beta.79) (2024-08-16)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.77...v3.9.0-beta.78) (2024-08-15)


### Features

* Add CS3D WSI and Video Viewports and add annotation navigation for MPR ([#4182](https://github.com/OHIF/Viewers/issues/4182)) ([7599ec9](https://github.com/OHIF/Viewers/commit/7599ec9421129dcade94e6fa6ec7908424ab3134))





# [3.9.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.76...v3.9.0-beta.77) (2024-08-15)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.75...v3.9.0-beta.76) (2024-08-08)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.74...v3.9.0-beta.75) (2024-08-07)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.73...v3.9.0-beta.74) (2024-08-06)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.72...v3.9.0-beta.73) (2024-08-02)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.71...v3.9.0-beta.72) (2024-07-31)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.70...v3.9.0-beta.71) (2024-07-30)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.69...v3.9.0-beta.70) (2024-07-30)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.68...v3.9.0-beta.69) (2024-07-27)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.67...v3.9.0-beta.68) (2024-07-26)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.66...v3.9.0-beta.67) (2024-07-26)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.65...v3.9.0-beta.66) (2024-07-24)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.64...v3.9.0-beta.65) (2024-07-23)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.63...v3.9.0-beta.64) (2024-07-19)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.62...v3.9.0-beta.63) (2024-07-10)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.61...v3.9.0-beta.62) (2024-07-09)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.60...v3.9.0-beta.61) (2024-07-09)


### Features

* **auth:** Add Authorization Code Flow and new Keycloak recipes with new video tutorials ([#4234](https://github.com/OHIF/Viewers/issues/4234)) ([aefa6d9](https://github.com/OHIF/Viewers/commit/aefa6d94dff82d34fa8358933fb1d5dec3f8246d))





# [3.9.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.59...v3.9.0-beta.60) (2024-07-09)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.58...v3.9.0-beta.59) (2024-07-05)


### Bug Fixes

* webpack import bugs showing warnings on import ([#4265](https://github.com/OHIF/Viewers/issues/4265)) ([24c511f](https://github.com/OHIF/Viewers/commit/24c511f4bc04c4143bbd3d0d48029f41f7f36014))


### Features

* Add interleaved HTJ2K and volume progressive loading ([#4276](https://github.com/OHIF/Viewers/issues/4276)) ([a2084f3](https://github.com/OHIF/Viewers/commit/a2084f319b731d98b59485799fb80357094f8c38))





# [3.9.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.57...v3.9.0-beta.58) (2024-07-04)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.56...v3.9.0-beta.57) (2024-07-02)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.55...v3.9.0-beta.56) (2024-07-02)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.54...v3.9.0-beta.55) (2024-06-28)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.53...v3.9.0-beta.54) (2024-06-28)


### Features

* **studyPrefetcher:** Study Prefetcher ([#4206](https://github.com/OHIF/Viewers/issues/4206)) ([2048b19](https://github.com/OHIF/Viewers/commit/2048b19484c0b1fae73f993cfaa814f861bbd230))





# [3.9.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.52...v3.9.0-beta.53) (2024-06-28)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.51...v3.9.0-beta.52) (2024-06-27)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.50...v3.9.0-beta.51) (2024-06-27)


### Bug Fixes

* **cli:** Fix the cli utilities which require full paths ([d09f8b5](https://github.com/OHIF/Viewers/commit/d09f8b5ba2dcc0c02beb405b8cfa79fbae5bdde8)), closes [#4267](https://github.com/OHIF/Viewers/issues/4267)





# [3.9.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.49...v3.9.0-beta.50) (2024-06-26)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.48...v3.9.0-beta.49) (2024-06-26)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.47...v3.9.0-beta.48) (2024-06-25)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.46...v3.9.0-beta.47) (2024-06-21)


### Bug Fixes

* Allow the mode setup/creation to be async, and provide a few more values to extension/app config/mode setup. ([#4016](https://github.com/OHIF/Viewers/issues/4016)) ([88575c6](https://github.com/OHIF/Viewers/commit/88575c6c09fd778a31b2f91524163ce65d1639dd))
* **CustomViewportOverlay:** pass accurate data to Custom Viewport Functions ([#4224](https://github.com/OHIF/Viewers/issues/4224)) ([aef00e9](https://github.com/OHIF/Viewers/commit/aef00e91d63e9bc2de289cc6f35975e36547fb20))


### Features

* customization service append and customize functionality should run once ([#4238](https://github.com/OHIF/Viewers/issues/4238)) ([e462fd3](https://github.com/OHIF/Viewers/commit/e462fd31f7944acfee34f08cfbc28cfd9de16169))
* **sort:** custom series sort in study panel ([#4214](https://github.com/OHIF/Viewers/issues/4214)) ([a433d40](https://github.com/OHIF/Viewers/commit/a433d406e2cac13f644203996c682260b54e8865))





# [3.9.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.45...v3.9.0-beta.46) (2024-06-18)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.44...v3.9.0-beta.45) (2024-06-18)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.43...v3.9.0-beta.44) (2024-06-17)


### Bug Fixes

* **cli:** version txt had a new line which it should not ([#4233](https://github.com/OHIF/Viewers/issues/4233)) ([097ef76](https://github.com/OHIF/Viewers/commit/097ef7665559a672d73e1babfc42afccc3cdd41d))





# [3.9.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.42...v3.9.0-beta.43) (2024-06-12)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.41...v3.9.0-beta.42) (2024-06-12)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.40...v3.9.0-beta.41) (2024-06-12)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.39...v3.9.0-beta.40) (2024-06-12)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.38...v3.9.0-beta.39) (2024-06-08)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.37...v3.9.0-beta.38) (2024-06-07)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.36...v3.9.0-beta.37) (2024-06-05)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.35...v3.9.0-beta.36) (2024-06-05)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.34...v3.9.0-beta.35) (2024-06-05)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.33...v3.9.0-beta.34) (2024-06-05)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.32...v3.9.0-beta.33) (2024-06-05)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.31...v3.9.0-beta.32) (2024-05-31)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.30...v3.9.0-beta.31) (2024-05-30)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.29...v3.9.0-beta.30) (2024-05-30)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.28...v3.9.0-beta.29) (2024-05-30)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.27...v3.9.0-beta.28) (2024-05-30)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.26...v3.9.0-beta.27) (2024-05-29)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.25...v3.9.0-beta.26) (2024-05-29)


### Features

* **hp:** Add displayArea option for Hanging protocols and example with Mamo([#3808](https://github.com/OHIF/Viewers/issues/3808)) ([18ac08e](https://github.com/OHIF/Viewers/commit/18ac08ed860d119721c52e4ffc270332259100b6))





# [3.9.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.24...v3.9.0-beta.25) (2024-05-29)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.23...v3.9.0-beta.24) (2024-05-29)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.22...v3.9.0-beta.23) (2024-05-28)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.21...v3.9.0-beta.22) (2024-05-27)


### Features

* **ui:** move to React 18 and base for using shadcn/ui ([#4174](https://github.com/OHIF/Viewers/issues/4174)) ([70f2c79](https://github.com/OHIF/Viewers/commit/70f2c797f42af603d7ea0eb8d23b4103aba66f77))





# [3.9.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.20...v3.9.0-beta.21) (2024-05-24)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.19...v3.9.0-beta.20) (2024-05-24)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.18...v3.9.0-beta.19) (2024-05-24)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.17...v3.9.0-beta.18) (2024-05-24)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.16...v3.9.0-beta.17) (2024-05-23)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.15...v3.9.0-beta.16) (2024-05-23)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.14...v3.9.0-beta.15) (2024-05-22)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.14](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.13...v3.9.0-beta.14) (2024-05-21)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.13](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.12...v3.9.0-beta.13) (2024-05-21)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.12](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.11...v3.9.0-beta.12) (2024-05-21)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.11](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.10...v3.9.0-beta.11) (2024-05-21)


### Features

* **test:** Playwright testing integration ([#4146](https://github.com/OHIF/Viewers/issues/4146)) ([fe1a706](https://github.com/OHIF/Viewers/commit/fe1a706446cc33670bf5fab8451e8281b487fcd6))





# [3.9.0-beta.10](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.9...v3.9.0-beta.10) (2024-05-21)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.9](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.8...v3.9.0-beta.9) (2024-05-17)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.8](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.7...v3.9.0-beta.8) (2024-05-16)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.7](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.6...v3.9.0-beta.7) (2024-05-15)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.6](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.5...v3.9.0-beta.6) (2024-05-15)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.5](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.4...v3.9.0-beta.5) (2024-05-14)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.4](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.3...v3.9.0-beta.4) (2024-05-14)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.3](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.2...v3.9.0-beta.3) (2024-05-08)


### Features

* **typings:** Enhance typing support with withAppTypes and custom services throughout OHIF ([#4090](https://github.com/OHIF/Viewers/issues/4090)) ([374065b](https://github.com/OHIF/Viewers/commit/374065bc3bad9d212f9817a8d41546cc64cfabfb))





# [3.9.0-beta.2](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.1...v3.9.0-beta.2) (2024-05-06)


### Bug Fixes

* **bugs:** enhancements and bugs in several areas ([#4086](https://github.com/OHIF/Viewers/issues/4086)) ([730f434](https://github.com/OHIF/Viewers/commit/730f4349100f21b4489a21707dbb2dca9dbfbba2))





# [3.9.0-beta.1](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.0...v3.9.0-beta.1) (2024-05-06)

**Note:** Version bump only for package ohif-docs





# [3.9.0-beta.0](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.94...v3.9.0-beta.0) (2024-04-29)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.93...v3.8.0-beta.94) (2024-04-29)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.92...v3.8.0-beta.93) (2024-04-29)


### Bug Fixes

* **toolbox:** Preserve user-specified tool state and streamline command execution ([#4063](https://github.com/OHIF/Viewers/issues/4063)) ([f1a736d](https://github.com/OHIF/Viewers/commit/f1a736d1934733a434cb87b2c284907a3122403f))





# [3.8.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.91...v3.8.0-beta.92) (2024-04-28)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.90...v3.8.0-beta.91) (2024-04-25)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.89...v3.8.0-beta.90) (2024-04-22)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.88...v3.8.0-beta.89) (2024-04-22)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.87...v3.8.0-beta.88) (2024-04-22)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.86...v3.8.0-beta.87) (2024-04-19)


### Features

* **tmtv-mode:** Add Brush tools and move SUV peak calculation to web worker ([#4053](https://github.com/OHIF/Viewers/issues/4053)) ([8192e34](https://github.com/OHIF/Viewers/commit/8192e348eca993fec331d4963efe88f9a730eceb))





# [3.8.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.85...v3.8.0-beta.86) (2024-04-19)


### Bug Fixes

* **layouts:** and fix thumbnail in touch and update migration guide for 3.8 release ([#4052](https://github.com/OHIF/Viewers/issues/4052)) ([d250d04](https://github.com/OHIF/Viewers/commit/d250d04580883446fcb8d748b2a97c5c198922af))





# [3.8.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.84...v3.8.0-beta.85) (2024-04-18)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.83...v3.8.0-beta.84) (2024-04-18)


### Bug Fixes

* **bugs:** and replace seriesInstanceUID and seriesInstanceUIDs URL with seriesInstanceUIDs ([#4049](https://github.com/OHIF/Viewers/issues/4049)) ([da7c1a5](https://github.com/OHIF/Viewers/commit/da7c1a5d8c54bfa1d3f97bbc500386bf76e7fd9d))





# [3.8.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.82...v3.8.0-beta.83) (2024-04-18)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.81...v3.8.0-beta.82) (2024-04-17)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.80...v3.8.0-beta.81) (2024-04-16)


### Bug Fixes

* **viewport:** Reset viewport state and fix CINE looping, thumbnail resolution, and dynamic tool settings ([#4037](https://github.com/OHIF/Viewers/issues/4037)) ([f99a0bf](https://github.com/OHIF/Viewers/commit/f99a0bfb31434aa137bbb3ed1f9eef1dfcc09025))





# [3.8.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.79...v3.8.0-beta.80) (2024-04-16)


### Bug Fixes

* **bugs:** enhancements and bug fixes ([#4036](https://github.com/OHIF/Viewers/issues/4036)) ([e80fc6f](https://github.com/OHIF/Viewers/commit/e80fc6f47708e1d6b1a1e1de438196a4b74ec637))





# [3.8.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.78...v3.8.0-beta.79) (2024-04-10)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.77...v3.8.0-beta.78) (2024-04-10)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.76...v3.8.0-beta.77) (2024-04-10)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.75...v3.8.0-beta.76) (2024-04-10)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.74...v3.8.0-beta.75) (2024-04-10)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.73...v3.8.0-beta.74) (2024-04-10)


### Features

* **4D:** Add 4D dynamic volume rendering and new pre-clinical 4d pt/ct mode ([#3664](https://github.com/OHIF/Viewers/issues/3664)) ([d57e8bc](https://github.com/OHIF/Viewers/commit/d57e8bc1571c6da4effaa492ee2d162c552365a2))





# [3.8.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.72...v3.8.0-beta.73) (2024-04-08)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.71...v3.8.0-beta.72) (2024-04-05)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.70...v3.8.0-beta.71) (2024-04-05)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.69...v3.8.0-beta.70) (2024-04-05)


### Features

* **measurement:** Add support measurement label autocompletion ([#3855](https://github.com/OHIF/Viewers/issues/3855)) ([56b1eae](https://github.com/OHIF/Viewers/commit/56b1eae6356a6534960df1196bdd1e95b0a9a470))





# [3.8.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.68...v3.8.0-beta.69) (2024-04-03)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.67...v3.8.0-beta.68) (2024-04-03)


### Features

* **segmentation:** Enhanced segmentation panel design for TMTV ([#3988](https://github.com/OHIF/Viewers/issues/3988)) ([9f3235f](https://github.com/OHIF/Viewers/commit/9f3235ff096636aafa88d8a42859e8dc85d9036d))





# [3.8.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.66...v3.8.0-beta.67) (2024-04-02)


### Features

* **ViewportActionMenu:** window level per viewport / new patient info / colorbars/ 3D presets and 3D volume rendering ([#3963](https://github.com/OHIF/Viewers/issues/3963)) ([b7f90e3](https://github.com/OHIF/Viewers/commit/b7f90e3951845396f99b69f0a74fc56b2ffeada1))





# [3.8.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.65...v3.8.0-beta.66) (2024-03-28)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.64...v3.8.0-beta.65) (2024-03-28)


### Features

* **layout:** new layout selector with 3D volume rendering ([#3923](https://github.com/OHIF/Viewers/issues/3923)) ([617043f](https://github.com/OHIF/Viewers/commit/617043fe0da5de91fbea4ac33a27f1df16ae1ca6))





# [3.8.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.63...v3.8.0-beta.64) (2024-03-27)


### Features

* **toolbar:** new Toolbar to enable reactive state synchronization ([#3983](https://github.com/OHIF/Viewers/issues/3983)) ([566b25a](https://github.com/OHIF/Viewers/commit/566b25a54425399096864bd263193646556011a5))





# [3.8.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.62...v3.8.0-beta.63) (2024-03-25)


### Features

* **worklist:** new investigational use text ([#3999](https://github.com/OHIF/Viewers/issues/3999)) ([45b68e8](https://github.com/OHIF/Viewers/commit/45b68e841dcb9e28a2ea991c37ee7ac4a8c5b71e))





# [3.8.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.61...v3.8.0-beta.62) (2024-03-19)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.60...v3.8.0-beta.61) (2024-03-18)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.59...v3.8.0-beta.60) (2024-03-15)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.58...v3.8.0-beta.59) (2024-03-08)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.57...v3.8.0-beta.58) (2024-03-05)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.56...v3.8.0-beta.57) (2024-02-28)


### Bug Fixes

* **docs:** Minor typos in hpModule.md ([#3962](https://github.com/OHIF/Viewers/issues/3962)) ([4cdfdae](https://github.com/OHIF/Viewers/commit/4cdfdae8149166cf9dc91a55c0d7f2a224e55d8f))





# [3.8.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.55...v3.8.0-beta.56) (2024-02-22)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.54...v3.8.0-beta.55) (2024-02-21)


### Features

* **resize:** Optimize resizing process and maintain zoom level ([#3889](https://github.com/OHIF/Viewers/issues/3889)) ([b3a0faf](https://github.com/OHIF/Viewers/commit/b3a0faf5f5f0a1993b2b017eb4cc1216164ea2c6))





# [3.8.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.53...v3.8.0-beta.54) (2024-02-14)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.52...v3.8.0-beta.53) (2024-02-05)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.51...v3.8.0-beta.52) (2024-01-22)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.50...v3.8.0-beta.51) (2024-01-22)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.49...v3.8.0-beta.50) (2024-01-22)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.48...v3.8.0-beta.49) (2024-01-19)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.47...v3.8.0-beta.48) (2024-01-17)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.46...v3.8.0-beta.47) (2024-01-12)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.45...v3.8.0-beta.46) (2024-01-12)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.44...v3.8.0-beta.45) (2024-01-09)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.43...v3.8.0-beta.44) (2024-01-09)


### Features

* **transferSyntax:** prefer server transcoded transfer syntax for all images ([#3883](https://github.com/OHIF/Viewers/issues/3883)) ([1456a49](https://github.com/OHIF/Viewers/commit/1456a493d66c90c787b022256c9f2846afb115fc))





# [3.8.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.42...v3.8.0-beta.43) (2024-01-09)


### Bug Fixes

* **segmentation:** upgrade cs3d to fix various segmentation bugs ([#3885](https://github.com/OHIF/Viewers/issues/3885)) ([b1efe40](https://github.com/OHIF/Viewers/commit/b1efe40aa146e4052cc47b3f774cabbb47a8d1a6))





# [3.8.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.41...v3.8.0-beta.42) (2024-01-08)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.40...v3.8.0-beta.41) (2024-01-08)


### Features

* Add on mode init hook ([#3882](https://github.com/OHIF/Viewers/issues/3882)) ([f58725c](https://github.com/OHIF/Viewers/commit/f58725ce40685f7297181ef98d81bc28420c8291))





# [3.8.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.39...v3.8.0-beta.40) (2024-01-08)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.38...v3.8.0-beta.39) (2024-01-08)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.37...v3.8.0-beta.38) (2024-01-08)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.36...v3.8.0-beta.37) (2024-01-08)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.35...v3.8.0-beta.36) (2023-12-15)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.34...v3.8.0-beta.35) (2023-12-14)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.33...v3.8.0-beta.34) (2023-12-13)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.32...v3.8.0-beta.33) (2023-12-13)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.31...v3.8.0-beta.32) (2023-12-13)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.30...v3.8.0-beta.31) (2023-12-13)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.29...v3.8.0-beta.30) (2023-12-13)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.28...v3.8.0-beta.29) (2023-12-13)


### Features

* **config:** Add activateViewportBeforeInteraction parameter for viewport interaction customization ([#3847](https://github.com/OHIF/Viewers/issues/3847)) ([f707b4e](https://github.com/OHIF/Viewers/commit/f707b4ebc996f379cd30337badc06b07e6e35ac5))





# [3.8.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.27...v3.8.0-beta.28) (2023-12-08)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.26...v3.8.0-beta.27) (2023-12-06)


### Bug Fixes

* **auth:** fix the issue with oauth at a non root path ([#3840](https://github.com/OHIF/Viewers/issues/3840)) ([6651008](https://github.com/OHIF/Viewers/commit/6651008fbb35dabd5991c7f61128e6ef324012df))





# [3.8.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.25...v3.8.0-beta.26) (2023-11-28)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.24...v3.8.0-beta.25) (2023-11-27)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.23...v3.8.0-beta.24) (2023-11-24)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.22...v3.8.0-beta.23) (2023-11-24)


### Features

* Merge Data Source ([#3788](https://github.com/OHIF/Viewers/issues/3788)) ([c4ff2c2](https://github.com/OHIF/Viewers/commit/c4ff2c2f09546ce8b72eab9c5e7beed611e3cab0))





# [3.8.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.21...v3.8.0-beta.22) (2023-11-21)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.20...v3.8.0-beta.21) (2023-11-21)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.19...v3.8.0-beta.20) (2023-11-21)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.18...v3.8.0-beta.19) (2023-11-18)


### Features

* **docs:** Added various training videos to support the OHIF CLI tools ([#3794](https://github.com/OHIF/Viewers/issues/3794)) ([d83beb7](https://github.com/OHIF/Viewers/commit/d83beb7c62c1d5be19c54e08d23883f112147fe1))





# [3.8.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.17...v3.8.0-beta.18) (2023-11-15)


### Features

* **url:** Add SeriesInstanceUIDs wado query param ([#3746](https://github.com/OHIF/Viewers/issues/3746)) ([b694228](https://github.com/OHIF/Viewers/commit/b694228dd535e4b97cb86a1dc085b6e8716bdaf3))





# [3.8.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.16...v3.8.0-beta.17) (2023-11-13)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.15...v3.8.0-beta.16) (2023-11-13)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.14...v3.8.0-beta.15) (2023-11-10)


### Features

* **dicomJSON:** Add Loading Other Display Sets and JSON Metadata Generation script ([#3777](https://github.com/OHIF/Viewers/issues/3777)) ([43b1c17](https://github.com/OHIF/Viewers/commit/43b1c17209502e4876ad59bae09ed9442eda8024))





# [3.8.0-beta.14](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.13...v3.8.0-beta.14) (2023-11-10)


### Bug Fixes

* **path:** upgrade docusaurus for security ([#3780](https://github.com/OHIF/Viewers/issues/3780)) ([8bbcd0e](https://github.com/OHIF/Viewers/commit/8bbcd0e692e25917c1b6dd94a39fac834c812fca))





# [3.8.0-beta.13](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.12...v3.8.0-beta.13) (2023-11-09)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.12](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.11...v3.8.0-beta.12) (2023-11-08)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.11](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.10...v3.8.0-beta.11) (2023-11-08)


### Features

* **hp callback:** Add viewport ready callback ([#3772](https://github.com/OHIF/Viewers/issues/3772)) ([bf252bc](https://github.com/OHIF/Viewers/commit/bf252bcec2aae3a00479fdcb732110b344bcf2c0))





# [3.8.0-beta.10](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.9...v3.8.0-beta.10) (2023-11-03)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.9](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.8...v3.8.0-beta.9) (2023-11-02)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.8](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.7...v3.8.0-beta.8) (2023-10-31)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.7](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.6...v3.8.0-beta.7) (2023-10-30)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.6](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.5...v3.8.0-beta.6) (2023-10-25)


### Bug Fixes

* **toolbar:** allow customizable toolbar for active viewport and allow active tool to be deactivated via a click ([#3608](https://github.com/OHIF/Viewers/issues/3608)) ([dd6d976](https://github.com/OHIF/Viewers/commit/dd6d9768bbca1d3cc472e8c1e6d85822500b96ef))





# [3.8.0-beta.5](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.4...v3.8.0-beta.5) (2023-10-24)


### Bug Fixes

* **sr:** dcm4chee requires the patient name for an SR to match what is in the original study ([#3739](https://github.com/OHIF/Viewers/issues/3739)) ([d98439f](https://github.com/OHIF/Viewers/commit/d98439fe7f3825076dbc87b664a1d1480ff414d3))





# [3.8.0-beta.4](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.3...v3.8.0-beta.4) (2023-10-23)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.3](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.2...v3.8.0-beta.3) (2023-10-23)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.2](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.1...v3.8.0-beta.2) (2023-10-19)


### Bug Fixes

* **cine:** Use the frame rate specified in DICOM and optionally auto play cine ([#3735](https://github.com/OHIF/Viewers/issues/3735)) ([d9258ec](https://github.com/OHIF/Viewers/commit/d9258eca70587cf4dc18be4e56c79b16bae73d6d))





# [3.8.0-beta.1](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.0...v3.8.0-beta.1) (2023-10-19)

**Note:** Version bump only for package ohif-docs





# [3.8.0-beta.0](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.110...v3.8.0-beta.0) (2023-10-12)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.109...v3.7.0-beta.110) (2023-10-11)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.108...v3.7.0-beta.109) (2023-10-11)


### Bug Fixes

* **export:** wrong export for the tmtv RT function ([#3715](https://github.com/OHIF/Viewers/issues/3715)) ([a3f2a1a](https://github.com/OHIF/Viewers/commit/a3f2a1a7b0d16bfcc0ecddc2ab731e54c5e377c8))





# [3.7.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.107...v3.7.0-beta.108) (2023-10-10)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.106...v3.7.0-beta.107) (2023-10-10)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.105...v3.7.0-beta.106) (2023-10-10)


### Bug Fixes

* **segmentation:**  Various fixes for segmentation mode and other ([#3709](https://github.com/OHIF/Viewers/issues/3709)) ([a9a6ad5](https://github.com/OHIF/Viewers/commit/a9a6ad50eae67b43b8b34efc07182d788cacdcfe))





# [3.7.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.104...v3.7.0-beta.105) (2023-10-10)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.103...v3.7.0-beta.104) (2023-10-09)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.102...v3.7.0-beta.103) (2023-10-09)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.101...v3.7.0-beta.102) (2023-10-06)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.100...v3.7.0-beta.101) (2023-10-06)


### Bug Fixes

* **bugs:** fixing lots of bugs regarding release candidate ([#3700](https://github.com/OHIF/Viewers/issues/3700)) ([8bc12a3](https://github.com/OHIF/Viewers/commit/8bc12a37d0353160ae5ea4624dc0b244b7d59c07))





# [3.7.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.99...v3.7.0-beta.100) (2023-10-06)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.98...v3.7.0-beta.99) (2023-10-04)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.97...v3.7.0-beta.98) (2023-10-04)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.96...v3.7.0-beta.97) (2023-10-04)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.95...v3.7.0-beta.96) (2023-10-04)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.94...v3.7.0-beta.95) (2023-10-04)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.93...v3.7.0-beta.94) (2023-10-03)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.92...v3.7.0-beta.93) (2023-10-03)


### Features

* **displayArea:** add display area to hanging protocol ([#3691](https://github.com/OHIF/Viewers/issues/3691)) ([5e7fe91](https://github.com/OHIF/Viewers/commit/5e7fe91617d7399f85702d82e7bfa028b8010a89))





# [3.7.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.91...v3.7.0-beta.92) (2023-10-03)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.90...v3.7.0-beta.91) (2023-10-03)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.89...v3.7.0-beta.90) (2023-10-03)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.88...v3.7.0-beta.89) (2023-10-03)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.87...v3.7.0-beta.88) (2023-10-03)


### Bug Fixes

* **config:** support more values for the useSharedArrayBuffer ([#3688](https://github.com/OHIF/Viewers/issues/3688)) ([1129c15](https://github.com/OHIF/Viewers/commit/1129c155d2c7d46c98a5df7c09879aa3d459fa7e))





# [3.7.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.86...v3.7.0-beta.87) (2023-09-29)


### Bug Fixes

* **no sab:** should work when shared array buffer is not required ([#3686](https://github.com/OHIF/Viewers/issues/3686)) ([a67d72d](https://github.com/OHIF/Viewers/commit/a67d72de85238b369a18c010bf6d147daefc6df5))





# [3.7.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.85...v3.7.0-beta.86) (2023-09-29)


### Bug Fixes

* **cli:** various fixes for adding custom modes and extensions ([#3683](https://github.com/OHIF/Viewers/issues/3683)) ([dc73b18](https://github.com/OHIF/Viewers/commit/dc73b187484da029a2664bb1302f30137c973b8c))





# [3.7.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.84...v3.7.0-beta.85) (2023-09-26)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.83...v3.7.0-beta.84) (2023-09-26)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.82...v3.7.0-beta.83) (2023-09-26)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.81...v3.7.0-beta.82) (2023-09-26)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.80...v3.7.0-beta.81) (2023-09-26)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.79...v3.7.0-beta.80) (2023-09-22)


### Features

* **segmentation mode:** Add create, and export SEG with Brushes ([#3632](https://github.com/OHIF/Viewers/issues/3632)) ([48bbd62](https://github.com/OHIF/Viewers/commit/48bbd6281a497ea68670239f5426a10ee6c56dc1))





# [3.7.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.78...v3.7.0-beta.79) (2023-09-22)


### Performance Improvements

* **memory:** add 16 bit texture via configuration - reduces memory by half ([#3662](https://github.com/OHIF/Viewers/issues/3662)) ([2bd3b26](https://github.com/OHIF/Viewers/commit/2bd3b26a6aa54b211ef988f3ad64ef1fe5648bab))





# [3.7.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.77...v3.7.0-beta.78) (2023-09-21)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.76...v3.7.0-beta.77) (2023-09-21)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.75...v3.7.0-beta.76) (2023-09-19)


### Bug Fixes

* **keyCloak:** fix openresty keycloak deployment recipe ([#3655](https://github.com/OHIF/Viewers/issues/3655)) ([2d7721c](https://github.com/OHIF/Viewers/commit/2d7721cb581f55dc49e3baeca2411b18dd78ad74))





# [3.7.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.74...v3.7.0-beta.75) (2023-09-18)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.73...v3.7.0-beta.74) (2023-09-15)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.72...v3.7.0-beta.73) (2023-09-12)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.71...v3.7.0-beta.72) (2023-09-12)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.70...v3.7.0-beta.71) (2023-09-12)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.69...v3.7.0-beta.70) (2023-09-12)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.68...v3.7.0-beta.69) (2023-09-11)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.67...v3.7.0-beta.68) (2023-09-11)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.66...v3.7.0-beta.67) (2023-09-06)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.65...v3.7.0-beta.66) (2023-09-06)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.64...v3.7.0-beta.65) (2023-09-06)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.63...v3.7.0-beta.64) (2023-09-05)


### Bug Fixes

* **nginx archive recipe:** Fixes to various configuration files. ([#3624](https://github.com/OHIF/Viewers/issues/3624)) ([3ce7225](https://github.com/OHIF/Viewers/commit/3ce72254b390f32c9aa207a0589e688805e2659d))





# [3.7.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.62...v3.7.0-beta.63) (2023-09-01)


### Features

* **grid:** remove viewportIndex and only rely on viewportId ([#3591](https://github.com/OHIF/Viewers/issues/3591)) ([4c6ff87](https://github.com/OHIF/Viewers/commit/4c6ff873e887cc30ffc09223f5cb99e5f94c9cdd))





# [3.7.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.61...v3.7.0-beta.62) (2023-08-30)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.60...v3.7.0-beta.61) (2023-08-29)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.59...v3.7.0-beta.60) (2023-08-29)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.58...v3.7.0-beta.59) (2023-08-29)

**Note:** Version bump only for package ohif-docs





# [3.7.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.57...v3.7.0-beta.58) (2023-08-25)


### Features

* **cloud data source config:** GUI and API for configuring a cloud data source with Google cloud healthcare implementation ([#3589](https://github.com/OHIF/Viewers/issues/3589)) ([a336992](https://github.com/OHIF/Viewers/commit/a336992971c07552c9dbb6e1de43169d37762ef1))





# [3.7.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.56...v3.7.0-beta.57) (2023-08-23)

**Note:** Version bump only for package ohif-docs

---

### Platform Docs Docs Conformance (`platform/docs/docs/conformance.md`)

---
sidebar_position: 12
sidebar_label: DICOM Conformance Statement
title: DICOM Conformance Statement
summary: Access information about the OHIF Viewer's compliance with DICOM standards through an open-sourced document provided by Radical Imaging, which details the application's implementation of DICOM protocols and services.
---

You can find a version that has been open sourced by Radical Imaging [in this link](https://docs.google.com/document/d/1hbDlUApX4svX33gAUGxGfD7fXXZNaBsX0hSePbc-hNA/edit?usp=sharing)

---

### Platform Docs Docs Release Notes (`platform/docs/docs/release-notes.md`)

---
sidebar_position: 2
sidebar_label: Release Notes
title: OHIF Viewer Release Notes
summary: Information about OHIF Viewer version releases, including new features, improvements, and bug fixes, which can be found in detail on the official OHIF website.
---

# Release Notes



You can find the detailed release notes on the OHIF website. Please visit [https://ohif.org/release-notes](https://ohif.org/release-notes)

---

### Platform Docs Docs Resources (`platform/docs/docs/resources.md`)

---
sidebar_position: 13
sidebar_label: Resources
title: OHIF Viewer Educational Resources
summary: A comprehensive collection of presentations, slides, posters, and videos from conferences, hackathons, and community meetings where the OHIF team has shared knowledge about the viewer's development, features, and capabilities, organized chronologically from 2016 to present.
---

# Resources

Throughout the development of the OHIF Viewer, we have participated in various
conferences and "hackathons". In this page, we will provide the presentations
and other resources that we have provided to the community in the past:

## 2025

### Machine Learning in Medical Imaging Consortium (MaLMIC) | January 2025

We presented two talks at the Machine Learning in Medical Imaging Consortium (MaLMIC) 2025 conference.

- Advanced Medical Imaging Visualization [Slides](https://docs.google.com/presentation/d/1HZDL-72nNe4BPawDxR3XnSFLB3oLo72RjExc-KHDZfo/edit?usp=sharing)
- Introducing Advanced Segmentation Tools in the OHIF Viewer and Cornerstone3D [Slides](https://docs.google.com/presentation/d/146oJ24PPsFZaDPHeFudRF1dmbL42K9yHzQdXXAXdWxk/edit?usp=sharing)


## 2024

### ITCR Sustainment Session 2024

Dr. Gordon Harris presented at ITCR sustainment session about the future of OHIF.

- OHIF Sustainability [Slides](https://docs.google.com/presentation/d/15380mjCzBKBj9PuysCW1Q9ODnyoypJrCDpj3atTtK6I/edit?usp=sharing)

### ITCR Sustainment Panel 2024

- Advanced Medical Imaging Visualization [Slides](https://docs.google.com/presentation/d/1alUp9uJpoJs3aAUE0KqrufGo6e6HHvXYmOAdJp-Rlkc/edit?usp=sharing)


### IMNO 2024 - March 19-20, 2024

We participated in the Imaging Network Ontario (ImNO) 2024 symposium, presenting three posters. One of our presentations received the best talk award during the session.


- Advancing Medical Imaging on the Web: Implementation of Hanging Protocols for Automated Image Display Configuration in OHIF V3 [Poster](https://www.dropbox.com/scl/fi/z4h86bmsxi0c62e1n6h9l/P7-9-Alireza-Sedghi-Final.pdf?rlkey=v5pm0p5ygkbq41x9bz3hr5yi8&dl=0)
- Advancing Medical Imaging on the Web: Optimizing the Dicomweb Server Architecture with Static Dicomweb [Poster](https://www.dropbox.com/scl/fi/ep0lxjp90kbxhjoffe4kh/P7-10-Bill-Wallace-Final.pdf?rlkey=xl2u6tdnh9j9hgvkajxv3b02o&dl=0)
- (**🏆🏆 BEST PRESENTATION AWARD in the Session 7 Pitches: Devices, HW, SW Development 🏆🏆**) Advancing Medical Imaging on the Web: Integrating High Throughput JPEG 2000 (HTJ2K) in Cornerstone3D for Streamlined Progressive Loading and Visualization [Poster](https://www.dropbox.com/scl/fi/srs2rxgtv2r69ver9ub1j/P7-8-Bill-Wallace-Final.pdf?rlkey=k9mmraw76r9q2s3b9w9s0793w&dl=0)

## 2023

### ITCR 2023 Conference | September 11-13, 2023

Dr. Gordon Harris presented an update on OHIF in [NCI Informatics Technology for Cancer Research Annual Meeting](https://www.itcr2023.org/). You can find the slides and poster here:
[[Slides]](https://docs.google.com/presentation/d/1R38s95db_yZj0WoYdlUbaWGZsWVb3H-3u_hXBZXiTaE/edit?usp=sharing)[[Poster]](https://ohif-assets.s3.us-east-2.amazonaws.com/presentations/OHIF-ITCR-2023-FINAL-PRINT.pdf)




### SIIM 2023 Tech Tools Webinar |  April 12th, 2023

Free, Open Source Tools for Research: MONAI and OHIF Viewer
[[Slides](https://docs.google.com/presentation/d/1afJ5Y9Tzukgn7eAbaO1oiCtN7XvIimFdmZP-HcOUofA/edit?usp=sharing)][[Video](https://www.youtube.com/watch?v=lo8J5w5jUJI)]


### NA-MIC Project Week 38th 2023 - Remote

We participated in the 38th Project Week with three projects around OHIF. [[Website](https://projectweek.na-mic.org/PW38_2023_GranCanaria/)]

- PolySeg representations for OHIF Viewer ([link](https://projectweek.na-mic.org/PW38_2023_GranCanaria/Projects/OHIF_PolySeg/))
- Cross study synchronizer for OHIF Crosshair ([link](https://projectweek.na-mic.org/PW38_2023_GranCanaria/Projects/OHIF_SyncCrosshair/))
- DATSCAN Viewer implementation in OHIF ([link](https://projectweek.na-mic.org/PW38_2023_GranCanaria/Projects/OHIF_DATSCAN/))



## 2022

### OHIF Demo to Interns
[[Slides]](https://docs.google.com/presentation/d/1a2PkUnqkVMaXaBsuFn7-PPlBJULU3dBwzI_44gKFeYI/edit?usp=sharing)

### SIIM 2022 - Updates from the Imaging Informatics Community
We participated in the SIIM 2022 conference to give update for the imaging
informatics community.
[[Slides]](https://docs.google.com/presentation/d/1EUGaUzQtGhZbZWpGLe6ONqChpVMw9Qr9l3KHODevMow/edit?usp=sharing)
[[Video]](https://vimeo.com/734463662/dbd5a88371)

### The Imaging Network Ontario - Remote

The Imaging Network Ontario (ImNO) is an annual symposium that brings together
medical imaging researchers and scientists from across Canada to share
knowledge, ideas, and experiences.
[[Slides]](https://docs.google.com/presentation/d/18XZDon4-Sitc2a70V5sFyhyUVZI_mIgfXHGtdxhZMjE/edit?usp=sharing)
[[Video]](https://vimeo.com/843234581/ad7d308a44)


### [NA-MIC Project Week 36th 2022 - Remote](https://github.com/NA-MIC/ProjectWeek/blob/master/PW36_2022_Virtual/README.md)

The Project Week is a week-long hackathon of hands-on activity in which medical
image computing researchers. OHIF team participated and gave a talk on OHIF and
Cornerstone in the 36th Project Week:
[[Slides]](https://docs.google.com/presentation/d/1-GtOKmr2cQi-r3OFyseSmgLeurtB3KXUkGMx2pVLh1I/edit?usp=sharing)
[[Video]](https://vimeo.com/668339696/63a2c48de8)

## 2021

### [NA-MIC Project Week 35th 2021 - Remote](https://github.com/NA-MIC/ProjectWeek/tree/master/PW35_2021_Virtual)

The Project Week is a week-long hackathon of hands-on activity in which medical
image computing researchers. OHIF team participated in the 35th Project Week
in 2021.
[[Slides]](https://docs.google.com/presentation/d/1KYNjuiI8lT1foQ4P9TGNV0lBhM6H-5KBs0wkYj4JJbk/edit?usp=sharing)

### Chan Zuckerberg Initiative (CZI)

Project presentations and demonstrations of Essential Open Source Software for
Science (EOSS) grantees
[[Slides]](https://docs.google.com/presentation/d/1_CLtG2hsL3ZxOtV2olVnzBOzq-TMLrHLomOy3FiU4NE/edit?usp=sharing)
[[Video]](https://youtu.be/0FjKkTJO0Rc?t=3737)

### Google Cloud Tech

Healthcare Imaging with Cloud Healthcare API
[[Video]](https://www.youtube.com/watch?v=2MiX9ScHFhY)

## 2020

### OHIF ITCR Pitch

OHIF pitch for Informatics Technology for Cancer Research (ITCR)
[[Slides]](https://docs.google.com/presentation/d/1MZXnZrVAnjmhVIWqC-aRSvJOoMMRLhLddACdCa1TybM/edit?usp=sharing)
[[Video]](https://vimeo.com/843234613/625bdb8793)

## 2019

### OHIF and VTK.js Training Course

OHIF and Kitware collaboration to create a training course for OHIF and VTK.js
developers. Funding for this work was provided by Kitware (NIH NINDS
R44NS081792, NIH NINDS R42NS086295, NIH NIBIB and NIGMS R01EB021396, NIH NIBIB
R01EB014955), Isomics (NIH P41 EB015902), and Massachusetts General Hospital
(NIH U24 CA199460).

1. Introduction to VTK.js and OHIF
   [[Slides]](https://docs.google.com/presentation/d/1NCJxpfx_qUGJI_2DhbECzaOg0k-Z6b65QlUptCofN-A/edit#slide=id.p)
   [[Video]](https://vimeo.com/375520781)
2. Developing with VTK.js
   [[Slides]](https://docs.google.com/presentation/d/17TCS6EhFi6SWFIrcAJ-DFdFzFFL-WD9BBTv-owmMdDU/edit#slide=id.p)
   [[Video]](https://vimeo.com/375521036)
3. VTK.js Architecture and Tooling
   [[Slides]](https://docs.google.com/presentation/d/1Sr1OGxMSw0oCt46koKQbmwSIE11Kqq8MGtyW3W0ASpk/edit?usp=gmail_thread)
   [[Video]](https://vimeo.com/375521810)
4. OHIF + VTK.js Integration
   [[Slides]](https://docs.google.com/presentation/d/1Iwg-u01HGVf1CgC6NbcBD3gm3uHN9WhjU59FSz55TN8/edit?ts=5d9c9ce4#slide=id.g59aa99cda4_0_131)
   [[Video]](https://vimeo.com/375521206)

## 2017

### Lesion Tracker

LesionTracker: Extensible Open-Source Zero-Footprint Web Viewer for Cancer
Imaging Research and Clinical Trials. This project was supported in part by
grant U24 CA199460 from the National Cancer Institute (NCI) Informatics
Technology for Cancer Research (ITCR) Program.
[[Video]](https://www.youtube.com/watch?v=gUIPtoSBL-Q)

### OHIF Community Meeting - June

[[Slides]](https://docs.google.com/presentation/d/1K9Y6eP5DYTXoDlfwCZE6GkCUp83AK4_40YQS0dlzVBo/edit?usp=sharing)

## 2016

### Imaging Community Call

Open Source Oncology Web Viewer; Presentation by Gordon J. Harris
[[Slides]](https://www.slideshare.net/imgcommcall/lesiontracker)

### OHIF Community Meeting - June

[[Slides]](https://docs.google.com/presentation/d/1Ai25mBG0ZWUPhaadp3VnbCVmkYs9K51sQ8osMixrvJ0/edit?usp=sharing)

### OHIF Community Meeting - September

[[Slides]](https://docs.google.com/presentation/d/1iYZoU7v7KHSLHiKwH1_9_wweAkG7RGnyxrWeeHva4zQ/edit?usp=sharing)

---

### Platform Docs Docs Test Coverage (`platform/docs/docs/test-coverage.md`)

---
sidebar_position: 14
sidebar_label: Test Coverage
title: OHIF Viewer Test Coverage
summary: Information about the automated testing infrastructure for the OHIF Viewer, with a focus on Playwright tests and access to the latest test coverage reports, which help ensure reliability and quality of the codebase.
---

# Test Coverage

## Playwright


Here's the test coverage report for our Playwright tests. Keep in mind that this doesn't include our Cypress tests, so our actual test coverage is likely higher than what's shown. We're focusing on Playwright for future OHIF testing, and we're really pushing to improve that coverage number.


You can view our latest test coverage report here:
- [OHIF Playwright Test Coverage Report](https://docs.ohif.org/coverage)

---

### Platform Docs Docs Behaviours Report Dialog Save Destinations (`platform/docs/docs/behaviours/report-dialog-save-destinations.md`)

# Report dialog: where a save goes, and what the series is called

Status: **Implemented — current behaviour**

The report dialog stores a segmentation, a contour set, or a measurement report.
The dialog asks the user two things: which series the object goes into, and what
that series is called.

Implemented across:

- `extensions/default/src/customizations/reportDialogCustomization.tsx` — the
  dialog, and the `ohif.createReportDialog` customization.
- `extensions/default/src/Panels/createReportDialogPrompt.tsx` — the prompt that
  shows the dialog, and the input and the output of the prompt.
- `extensions/default/src/utils/seriesDescriptionHistory.ts` — the descriptions
  that the viewer remembers.
- `extensions/cornerstone-dicom-seg/src/commandsModule.ts` — `storeSegmentation`,
  the SEG caller and the RTSTRUCT caller.
- `extensions/default/src/utils/promptSaveReport.tsx` — the measurement report
  caller.
- `libs/@cornerstonejs/packages/adapters/src/utilities/referencedMetadataProvider.ts`
  — the `PredecessorSequence` provider, which reads the predecessor instance.

## One save stores one object

Each destination stores all of the current data as one object, and the dialog
merges nothing. A save into a series that already holds data does not read that
data, and the save leaves no part of the current data out. The destination
decides which series holds the new object, and therefore which instance the new
object supersedes. The earlier instances stay in the series, and the new
instance becomes the one that the viewer loads by default.

## The three destinations

| Destination | Where the object goes | When the dialog offers the destination |
| --- | --- | --- |
| `Save to current` | The series that the viewer loaded the data from | The `predecessorImageId` of the data names a loaded series |
| `Save as new` | A new series, with an editable number and description | Always |
| `Replace existing` | Another loaded series of this modality, which the user selects | The viewer holds at least one other such series |

`Save to current` is the default choice when the dialog offers it, and
`Save as new` is the default choice otherwise. `Save to current` and
`Replace existing` keep the number and the description of the target series, so
the dialog does not let the user edit either one.

## Which series the dialog offers

The dialog offers a loaded series as a destination only when both of these hold:

1. The series holds the same type of object, which is the modality of the save.
2. The series has a `predecessorImageId` value.

The `predecessorImageId` value names the immediate prior object that someone
saved into the series. The save supersedes that one instance. The adapter reads
the series and the instance number through the value, from the
`PredecessorSequence` provider.

The dialog does **not** fall back to the `SeriesInstanceUID` value of the display
set. A UID names a series and not an instance, so a UID names no prior object,
and a UID is not an image id. The provider finds no instance for a UID, and the
save then starts a new series rather than extending the chosen one.

A local id, such as `dicomfile:3`, is a valid value. The viewer registers an
uploaded instance under a local id, and the provider resolves a local id, so a
user can save against an uploaded instance more than once.

A display set that the viewer downloaded and never stored has no
`predecessorImageId` value, and the dialog does not offer that display set. The
number of a new series still counts such a series, because the number comes from
every loaded series of the modality and not from the offered ones alone.

## What the new series is called

`Save as new` offers four names, and the field starts from the first name that is
not blank:

1. `itemName`, the name that the user chose for the item. A rename before the
   save therefore reaches the field. `storeSegmentation` passes
   `segmentation.label`, but only when the user chose that label: the service
   invents a name such as `Segmentation 3` for a new segmentation, and marks the
   segmentation with `labelIsGenerated`. A label that is still marked this way
   goes to `defaultSeriesDescription` instead, so a generated name does not
   outrank the remembered descriptions. A rename clears the mark, and the save
   compares no two strings, so a user who types the invented name still gets the
   name in `itemName`.
2. The description of the series that the viewer loaded the data from, which is
   the name of the last save of this data.
3. The descriptions that the user used before for this type of item, most recent
   first. See [remembered descriptions](#remembered-descriptions).
4. `defaultSeriesDescription`, the name for an item that has no other name. The
   in-tree callers pass `Segmentation`, `Contours` and `Measurements`.

The pull-down holds the four names in that order. A blank name, and a name of
spaces, drops out of the list, so such a name cannot hide a later name. The
dialog compares the names without case, and the list holds each name once. An
emptied field falls back to the first name of the list.

A caller with no editable name passes no `itemName`: the measurement report has
no such name, and the report therefore starts from the description of the loaded
series, or from the last used name.

### Remembered descriptions

The viewer remembers a description when the user creates a new series with the
description, and a download counts as a save. A save into a series that already
exists remembers nothing, because that series keeps its own description.

The history holds a name that the user chose. A save that uses
`defaultSeriesDescription` remembers nothing, because the caller supplies that
name at every save, and the dialog offers the name in any case. A generated
segmentation label reaches `defaultSeriesDescription`, so `Segmentation 1` stays
out of the history and the dialog cannot offer `Segmentation 1` as the name of a
later, unrelated segmentation.

- `itemType` is the key that the viewer remembers the descriptions under, and
  `itemType` defaults to the modality.
- `rememberedDescriptionCount` is how many descriptions the viewer remembers, and
  the count defaults to 5.
- A count of 0 turns the history off. The list then holds one name, and the
  dialog does not render the pull-down.

The user reaches the list in three ways: the pull-down button shows every name;
typing narrows the list to the names that the typing can complete; **Tab**
completes to the first of those names, and the arrow keys plus **Enter** select
one.

## The series number of a new series

The dialog offers one past the highest series number of the loaded series of this
modality, and at least `minSeriesNumber`. The user can edit the number. An empty
number, and a number that is not valid, falls back to the offered number.

`createReportDialogPrompt` returns `seriesNumber`, and also
`priorSeriesNumber`, which is one less. A caller that computes the number as
`1 + priorSeriesNumber` gets the number that the dialog shows.

---

### Platform Docs Docs Behaviours Segmentation Multiframe Part10 Prefetch (`platform/docs/docs/behaviours/segmentation-multiframe-part10-prefetch.md`)

# Full-instance prefetch for segmentation (and multiframe) loading

Status: **Implemented — enabled and awaited to completion by default;
per-frame loading is the explicit opt-out**

The boolean `loadMultiframeAsPart10` resolves, in order: the data source
`configuration`, the global customization
`cornerstone.segmentation.loadMultiframeAsPart10`, then the built-in default of
`true` — i.e. by default the SEG load **waits for the whole-instance
fetch+parse to complete or fail** (deliberately no timeout) and serves every
frame from the registry. Set `loadMultiframeAsPart10: false` explicitly to
force per-frame loading — the exception, for back ends that need to fetch the
individual images instead (e.g. servers that cannot serve a whole-instance
retrieve, or deployments where holding the full Part 10 object in memory is
undesirable). A failed or unsupported instance fetch resolves quickly and
falls back to per-frame regardless of the setting, so it never wedges the load.

Note the per-frame endpoint itself is not inefficient — each frame request is
cheap — but SEG frames are so small and numerous that one bulk Part 10 fetch
beats hundreds of tiny requests (see Problem below). This holds even for very
large SEG objects (hundreds of MB): any finite race cap would simply expire on
those and storm per-frame anyway while abandoning the bulk fetch's benefit,
which is why there is no timeout.

Implemented across:

- `@cornerstonejs/dicom-image-loader`
  - `imageLoader/prefetchPart10Instance.ts` — registers a Part 10 instance into
    the frame registry (thin wrapper over `addDicomPart10Instance`).
  - `imageLoader/wadors/loadImageFromRegistry.ts` +
    `wadors/loadImage.ts` — WADO-RS loads now consult the registry first.
- `@ohif/extension-default` `DicomWebDataSource` — `retrieve.prefetchInstanceFrames`.
- `@ohif/extension-cornerstone-dicom-seg` `getSopClassHandlerModule.ts` — call
  site (resolves the config and awaits the prefetch).

Related: `@cornerstonejs/adapters` `labelmapImagesFromBuffer.ts`
(`decodeSegPixelDataFromFrameIds`, bounded by `concurrency`, default 16).

## Problem

The SEG load path now fetches/decodes frames through the cornerstone image
loader, one loadable `imageId` per frame, parallelized up to `N=16`
(`concurrency`). For a SEG (or any multiframe instance) with **800+ small
frames**, this means 800+ independent HTTP requests, each with its own
request/response overhead. Even at 16-wide concurrency the *per-request* latency
floor dominates: each frame is < 1 KB of payload but pays a full round trip.

Streaming **one large object** (the entire Part 10 / multiframe instance) is far
cheaper than streaming hundreds of tiny ones — a single connection, a single set
of headers, no per-frame TTFB. The whole instance for an 800-frame binary SEG is
typically a few hundred KB to a few MB.

## Goal

Add a **generic data-source capability** that, _just before_ the segmentation
loader runs, optionally fetches the **entire original instance** in one request
and **registers it into the Cornerstone3D frame registry** (the
`@cornerstonejs/metadata` NATURALIZED + `COMPRESSED_FRAME_DATA` framework, parsed
by the dcmjs async reader) — so the existing per-frame `imageId` fetch path
transparently hits local data instead of the network, while the **cornerstone
decode path stays byte-for-byte identical** (same decompressor, same workers).

Crucially this is **best-effort**:

- By default (`loadMultiframeAsPart10` unset → `true`) the load **waits for the
  full-instance fetch+parse to complete or fail** — no timeout — then every
  frame is served from the registry.
- If `loadMultiframeAsPart10` resolves to `false` (explicitly configured), the
  capability is **disabled** — no full-instance fetch is attempted. Per-frame
  loading is the exception, opted into per deployment.
- If the full-instance fetch or parse **fails for any reason**, it must **never**
  fail the segmentation decode. We log and fall back to per-frame fetches.

## Why this is safe / transparent

There is **one uniform frame registry: the Cornerstone3D `@cornerstonejs/metadata`
NATURALIZED framework**, populated by `addDicomPart10Instance` (which parses the
Part 10 with the dcmjs `AsyncDicomReader`) and read per-frame via the
`COMPRESSED_FRAME_DATA` typed provider. Frame imageIds are normalized to the base
instance by `baseImageIdQueryFilter` (strips `/frames/N`, `?frame=N`, `&frame=N`),
so one registration under the instance serves every frame.

This is the **same registry the WADO-URI / `dicomweb` loader already uses**:
`wadouri/loadImage.ts`'s `loadImageFromNaturalizedMetadata` resolves each frame
from `COMPRESSED_FRAME_DATA` and decodes it with `createImage`. The gap was that
**WADO-RS** (`wadors/loadImage.ts`) always issued a per-frame `/frames/N` request
and never consulted the registry. The adapter closes that gap:

- `wadors/loadImageFromRegistry.ts` — `loadImageFromCompressedFrameRegistry(imageId)`
  looks up `COMPRESSED_FRAME_DATA` for the frame; if present it decodes via the
  **same `createImage`** path and returns the image; if absent it returns
  `undefined`.
- `wadors/loadImage.ts` calls it first and short-circuits when the registry has
  the frame, otherwise falls through to the existing network path.

So once `prefetchPart10Instance` has registered the instance, **both WADO-URI and
WADO-RS** serve every frame from the single registry, with the **same decode
pipeline** (`createImage` → worker decoder). From cornerstone's perspective
nothing changed except the compressed bytes came from the registry instead of the
wire.

> Rejected alternatives: (1) a bespoke `Map<imageId, frame>` registry plus
> `getPixelData` shims — duplicates a registry that already exists; (2) seeding
> the core image cache (`cache.putImageLoadObject`) per frame — works, but the
> per-frame compressed data already lives in the NATURALIZED registry, so basing
> the design on that registry (and teaching WADO-RS to read it) keeps a single
> source of truth instead of copying frames into a second cache.

## API (as implemented)

A generic capability on the data source's `retrieve` namespace (so it works for
any multiframe instance, not just SEG, and alternate data sources can override
it), plus the SEG handler call site that awaits it.

`IWebApiDataSource.create` passes `retrieve` through verbatim, so the capability
is added there (no `@ohif/core` change):

```ts
// On the data source (DicomWebDataSource):
dataSource.retrieve.prefetchInstanceFrames({
  instance,                          // study/series/sop UIDs for retrieveInstance
  imageId,                           // SEG instance imageId (frame qualifiers normalized away)
}): {
  done: Promise<boolean>;            // resolves true if fetched+registered, false if skipped/failed
  cancel: () => void;
};
```

The implementation fetches the instance with `wadoDicomWebClient.retrieveInstance`
(which returns the Part 10 as an `ArrayBuffer`, unwrapping `multipart/related`
transparently) and passes a **lazy resolver** to
`dicomImageLoader.prefetchPart10Instance(imageId, resolver)`. All work is wrapped
so any failure resolves `done` to `false` — it never throws into the loader.

### Call site (just before the loader)

In `getSopClassHandlerModule.ts`, immediately before
`createFromDicomSegImageId(...)` (abridged from the actual code):

```ts
const loadMultiframeAsPart10 =
  (dataSource?.getConfig?.()?.loadMultiframeAsPart10 as boolean | undefined) ??
  (customizationService?.getCustomization?.(
    'cornerstone.segmentation.loadMultiframeAsPart10'
  ) as boolean | undefined) ??
  true;

let prefetch;
if (loadMultiframeAsPart10) {
  prefetch = dataSource.retrieve?.prefetchInstanceFrames?.({
    instance,
    imageId: segImageIdForMetadata,
  });
  if (prefetch?.done) {
    // Wait for the bulk fetch to complete or fail — no timeout.
    await prefetch.done;
  }
}

try {
  results = await adaptersSEG.Cornerstone3D.Segmentation.createFromDicomSegImageId(
    imageIds,
    segImageIdForMetadata,
    { metadataProvider: metaData, tolerance, parserType, frameImageIds,
      concurrency: SEG_FRAME_DECODE_CONCURRENCY }
  );
} finally {
  eventTarget.removeEventListener(Enums.Events.SEGMENTATION_LOAD_PROGRESS, onProgress);
  prefetch?.cancel?.();
}
```

The SEG loader and adapter are **unchanged** — the loader still asks the image
loader for each frame. Registered frames resolve from the registry; the rest
fetch normally.

## Mechanism (the 4 requested points)

### 1. Async DICOM reader (dcmjs) to parse the instance

Parsing is done by `@cornerstonejs/metadata`'s `addDicomPart10Instance`, which
uses the dcmjs **`AsyncDicomReader`** (`naturalizePart10Buffer` in
`naturalizedHandlers.ts`) and understands encapsulated PixelData fragmentation,
so the NATURALIZED instance exposes pixel data as an array of per-frame
ArrayBuffer fragments. `COMPRESSED_FRAME_DATA` then slices out the requested
frame. We did not re-implement any parsing — the prefetch just feeds the fetched
Part 10 buffer to this existing reader.

**Implemented as full-buffer v1**: the whole instance is fetched, then parsed.
`addDicomPart10Instance` accepts a lazy resolver, so the fetch is what the race
waits on. Progressive/streaming registration (registering frames as bytes arrive)
is a future optimization — see rollout step 4.

#### Response envelope: `multipart/related` vs raw DICOM

The full-instance fetch can come back in **two shapes**, and the parser must
handle both before any DICOM parsing happens:

- **`multipart/related`** — a WADO-RS instance retrieve
  (`GET …/instances/{sop}` with `Accept: multipart/related; type="application/dicom"`)
  wraps the Part 10 object(s) in a MIME multipart envelope: leading part headers,
  a `--boundary` marker, the DICOM bytes, then a terminal `--boundary--`. The
  inner DICOM byte offsets are **shifted** by the MIME header length, so dcmjs
  must be fed the *unwrapped* inner part, never the raw response.
- **raw DICOM** — WADO-URI, a direct file/object URL, or a `bulkDataURI` that
  returns a single `application/dicom` body: the response **is** the Part 10
  bytes, no envelope.

**As implemented**, the full-buffer path delegates this to **`dicomweb-client`'s
`retrieveInstance`**, which performs the WADO-RS instance retrieve and returns the
Part 10 as an `ArrayBuffer` with the `multipart/related` envelope already
unwrapped (and returns the single-part body as-is). `prefetchInstanceFrames`
additionally tolerates an `[ArrayBuffer]` or `ArrayBufferView` shape defensively.
So the implemented path is:

```
retrieveInstance() → ArrayBuffer (multipart unwrapped by dicomweb-client)
                   → prefetchPart10Instance → addDicomPart10Instance → dcmjs AsyncDicomReader
```

Detection by `Content-Type` and manual unwrapping (the approach `wadors/extractMultipart.ts`
uses: `contentType.indexOf('multipart') === -1` → bytes as-is; else strip the
boundary/part headers) becomes relevant only for the **future streaming path**
(rollout step 4), where these wrinkles must be handled directly:

- The multipart preamble/boundary stripped at the **start** of the stream and the
  terminal boundary detected at the **end**; a boundary token can **straddle chunk
  boundaries**, so the unwrapper must buffer across chunks (the existing
  `findIndexOfString` + `tokenIndex` carry-over in `extractMultipart` is built for
  incremental calls).
- `multipart/related` may contain **multiple parts**; a single-instance retrieve
  yields one — guard for >1.
- A truncated/partial body (no terminal boundary yet) must not be mis-parsed.

### 2. Register the compressed data into the frame registry

The fetched Part 10 buffer is registered **once per instance** via the
`prefetchPart10Instance` adapter (a thin wrapper over `addDicomPart10Instance`):

```ts
// @cornerstonejs/dicom-image-loader: imageLoader/prefetchPart10Instance.ts
import { utilities } from '@cornerstonejs/metadata';
const { addDicomPart10Instance } = utilities;

export function prefetchPart10Instance(baseImageId, part10 /* buffer | resolver */) {
  return addDicomPart10Instance(baseImageId, part10);
}
```

That populates NATURALIZED for the instance; `COMPRESSED_FRAME_DATA` then yields
each frame's compressed bytes + transfer syntax on demand. Frame imageIds
normalize to the instance key automatically (`baseImageIdQueryFilter`), so there
is no per-frame registration loop and no second cache to keep coherent — the
registry **is** the existing NATURALIZED framework.

The "few new adapters" the task calls for:

1. `prefetchPart10Instance(baseImageId, part10)` — entry point to register a
   fetched instance into the registry (exported from
   `@cornerstonejs/dicom-image-loader`).
2. `loadImageFromCompressedFrameRegistry(imageId, options)` in
   `wadors/loadImageFromRegistry.ts` — teaches the **WADO-RS** loader to read the
   registry. It looks up `COMPRESSED_FRAME_DATA` for the frame and, if present,
   decodes via the same `createImage` the network path uses; `wadors/loadImage.ts`
   calls it first and short-circuits on a hit. (WADO-URI already reads the
   registry via `loadImageFromNaturalizedMetadata`.)

Metadata the decoder needs (`imagePixelModule`, transfer syntax) comes from the
same NATURALIZED instance, plus the SEG handler's existing
`_ensureSegInstanceMetadataAvailable` per frame imageId.

### 3. Cornerstone uses its existing decompressor — identical downstream

Both the WADO-URI path and the new WADO-RS registry path decode via
`createImage` (→ the same web-worker decoder used for every network frame), so
encapsulated transfer syntaxes are decompressed exactly as if fetched per-frame
and native/uncompressed frames pass through unchanged. No new decode path, no
codec changes, no divergence in pixel output — the only difference is that the
compressed bytes came from the registry instead of the wire.

### 4. Failure is non-fatal — fall back to per-frame fetches

`prefetchInstanceFrames` wraps the fetch + parse so that **any** failure (network
error, cancel, parse error, unexpected `retrieveInstance` shape) resolves
`done` to `false` and logs a warning — it never throws into the SEG load. When
the registry has no data for a frame, `loadImageFromCompressedFrameRegistry`
returns `undefined` and the WADO-RS loader falls through to its normal
`/frames/N` request. So if the prefetch is slow, disabled, or fails, loading is
exactly today's per-frame behaviour.

Edge cases that degrade gracefully:

- `cancel()` (viewport closed / segmentation removed mid-load) → the resolver
  throws on its cancelled flag; `done` resolves `false`; any already-registered
  data stays usable.
- A misbehaving metadata provider → the registry lookup is wrapped in try/catch
  and returns `undefined`, so per-frame loading is never broken.

## Semantics (the `loadMultiframeAsPart10` knob)

- Unset (default) or `true` → start the full-instance fetch+parse and **await
  it to completion or failure** (`await prefetch.done`) — deliberately no
  timeout; every frame is then served from the registry. Fetch failure resolves
  `done` quickly, so unsupported servers fall straight through to per-frame.
- `false` (explicitly configured) → **disabled**; per-frame loading is the
  exception, opted into per deployment.

> `addDicomPart10Instance` registers the instance atomically (one parse), so
> registration is all-or-nothing rather than progressive. Progressive
> registration (rollout step 4) would let frames be served as they arrive.

There is no timeout because a bounded wait loses on exactly the objects where
the prefetch matters most: a large SEG (hundreds of MB) cannot finish inside
any small cap, so a capped race expires and storms per-frame anyway while
abandoning the bulk fetch's benefit. The only failure mode a timeout would
bound — a fetch that never settles — is already covered by the browser's
network-level failure surfacing through `done`.

## Where the generic capability lives

- The **registry is the existing `@cornerstonejs/metadata` NATURALIZED framework**
  — no new cache. New code in `@cornerstonejs/dicom-image-loader` is the thin
  adapter `prefetchPart10Instance()` plus the WADO-RS read path
  (`wadors/loadImageFromRegistry.ts`, wired into `wadors/loadImage.ts`).
- The **fetch + register orchestration** lives in the **data source**
  (`extensions/default/.../DicomWebDataSource` → `retrieve.prefetchInstanceFrames`),
  because it knows how to retrieve a full instance (auth headers, `wadoRoot`,
  WADO-RS instance retrieve via `dicomweb-client`, CORS), and so alternate data
  sources can implement/override it.
- The SEG handler only **reads the configuration and awaits the prefetch**.

This keeps the layering clean: data source = "how to get bytes", image loader =
"how to register/decode bytes", SEG handler = "when to ask".

## Open questions / risks

1. **NATURALIZED registry key alignment.** Both registration
   (`addDicomPart10Instance`) and the WADO-RS read normalize frame imageIds to the
   base instance via `baseImageIdQueryFilter`, so they agree. Worth a sanity check
   per data source that the SEG `imageId` passed to `prefetchInstanceFrames` and
   the frame imageIds the SEG loader requests share the same instance base.
2. **Memory.** Holding the full instance plus the still-compressed frames in the
   registry raises memory for that instance until it is evicted. Compressed frames
   are small and decode is on-demand. Registry/cache eviction lifecycle for
   prefetched instances should be verified (especially repeated SEG loads).
3. **Streaming availability.** v1 uses a single full-buffer `retrieveInstance`. A
   future streaming path (step 4) would register frames as bytes arrive.
4. **Auth / headers.** Handled — the resolver sets
   `wadoDicomWebClient.headers = getAuthorizationHeader()` before retrieve, reusing
   the data source's existing decoration.
5. **Per-frame overhead.** Every WADO-RS load now does one cheap
   `COMPRESSED_FRAME_DATA` lookup (a Map get after base normalization) before
   falling through. Negligible, and only short-circuits when an instance was
   actually prefetched.

## Incremental rollout

1. ✅ `prefetchPart10Instance` adapter + WADO-RS registry read
   (`wadors/loadImageFromRegistry.ts`) in dicom-image-loader. No behaviour change
   until something registers an instance.
2. ✅ `retrieve.prefetchInstanceFrames` in DicomWebDataSource (full-buffer v1 via
   `retrieveInstance`); whether to call it is the caller's policy.
3. ✅ SEG handler call site. Now **enabled and awaited to completion by
   default** (no timeout); per-frame loading requires an explicit
   `loadMultiframeAsPart10: false`.
4. ⏳ Progressive (streaming) parse to register frames as they arrive (handle the
   `multipart/related` unwrap + boundary-straddle directly).
5. ⏳ Extend to other multiframe loaders (the registry path is generic).

---

### Platform Docs Docs Configuration ConfigurationFiles (`platform/docs/docs/configuration/configurationFiles.md`)

---
sidebar_position: 1
sidebar_label: Configuration Files
title: Configuration Files
summary: Comprehensive guide to configuring OHIF Viewer, including data sources, environment variables, advanced options like study prefetching, and detailed explanations of configuration parameters for performance optimization and feature customization.
---

# Config files

After following the steps outlined in
[Getting Started](./../development/getting-started.md), you'll notice that the
OHIF Viewer has data for several studies and their images. You didn't add this
data, so where is it coming from?

By default, the viewer is configured to connect to a Amazon S3 bucket that is hosting
a Static WADO server (see [Static WADO DICOMWeb](https://github.com/RadicalImaging/static-dicomweb)).
By default we use `default.js` for the configuration file. You can change this by setting the `APP_CONFIG` environment variable
and select other options such as `config/local_orthanc.js` or `config/google.js`.


## Configuration Files

The configuration for our viewer is in the `<root>platform/app/public/config`
directory. Our build process knows which configuration file to use based on the
`APP_CONFIG` environment variable. By default, its value is
[`config/default.js`][default-config]. The majority of the viewer's features,
and registered extension's features, are configured using this file.

The simplest way is to update the existing default config:

```js title="platform/app/public/config/default.js"
window.config = {
  routerBasename: null,
  extensions: [],
  modes: [],
  showStudyList: true,
  dataSources: [
    {
      namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
      sourceName: 'dicomweb',
      configuration: {
        friendlyName: 'dcmjs DICOMWeb Server',
        name: 'DCM4CHEE',
        wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
        qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
        wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
        qidoSupportsIncludeField: true,
        supportsReject: true,
        imageRendering: 'wadors',
        thumbnailRendering: 'wadors',
        enableStudyLazyLoad: true,
        supportsFuzzyMatching: true,
        supportsWildcard: true,
        omitQuotationForMultipartRequest: true,
      },
    },
  ],
  defaultDataSourceName: 'dicomweb',
};
```

> As you can see a new change in `OHIF-v3` is the addition of `dataSources`. You
> can build your own datasource and map it to the internal data structure of
> OHIF’s > metadata and enjoy using other peoples developed mode on your own
> data!
>
> You can read more about data sources at
> [Data Source section in Modes](../platform/modes/index.md)

The configuration can also be written as a JS Function in case you need to
inject dependencies like external services:

```js
window.config = ({ servicesManager } = {}) => {
  const { UIDialogService } = servicesManager.services;
  return {
    cornerstoneExtensionConfig: {
      tools: {
        ArrowAnnotate: {
          configuration: {
            getTextCallback: (callback, eventDetails) => UIDialogService.create({...
          }
        }
      },
    },
    routerBasename: null,
    dataSources: [
    {
      namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
      sourceName: 'dicomweb',
      configuration: {
        friendlyName: 'dcmjs DICOMWeb Server',
        name: 'DCM4CHEE',
        wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
        qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
        wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
        qidoSupportsIncludeField: true,
        supportsReject: true,
        imageRendering: 'wadors',
        thumbnailRendering: 'wadors',
        enableStudyLazyLoad: true,
        supportsFuzzyMatching: true,
        supportsWildcard: true,
        omitQuotationForMultipartRequest: true,
      },
    },
  ],
  defaultDataSourceName: 'dicomweb',
  };
};
```





## Configuration Options


Here are a list of some options available:
- `customizationService`: An array of customization module references and inline overrides applied at the global scope. This is how deployers enable optional features like the [Appearance & Theming](./ui.md) system and configure UI components without modifying core code. See [Customization Service](../platform/services/customization-service/customizationService.md) for the full syntax reference.
- `disableEditing`:  If true, it disables editing in OHIF, hiding edit buttons in segmentation
  panel and locking already stored measurements.
- `maxNumberOfWebWorkers`: The maximum number of web workers to use for
  decoding. Defaults to minimum of `navigator.hardwareConcurrency` and
  what is specified by `maxNumberOfWebWorkers`. Some windows machines require smaller values.
- `acceptHeader` : accept header to request specific dicom transfer syntax ex : [ 'multipart/related; type=image/jls; q=1', 'multipart/related; type=application/octet-stream; q=0.1' ]
- `investigationalUseDialog`: This should contain an object with `option` value, it can be either `always` which always shows the dialog once per session, `never` which never shows the dialog, or `configure` which shows the dialog once and won't show it again until a set number of days defined by the user, if it's set to configure, you are required to add an additional property `days` which is the number of days to wait before showing the dialog again.
- `groupEnabledModesFirst`: boolean, if set to true, all valid modes for the study get grouped together first, then the rest of the modes. If false, all modes are shown in the order they are defined in the configuration.
- `experimentalStudyBrowserSort`: boolean, if set to true, you will get the experimental StudyBrowserSort component in the UI, which displays a list of sort functions that the displaySets can be sorted by, the sort reflects in all part of the app including the thumbnail/study panel. These sort functions are defined in the customizationModule and can be expanded by users.
- `disableConfirmationPrompts`: boolean, if set to true, it skips confirmation prompts for segmentation related prompts.
- `showPatientInfo`: string, if set to 'visible', the patient info header will be shown and its initial state is expanded. If set to 'visibleCollapsed', the patient info header will be shown but it's initial state is collapsed. If set to 'disabled', the patient info header will never be shown, and if set to 'visibleReadOnly', the patient info header will be shown and always expanded.
- `requestTransferSyntaxUID` : Request a specific Transfer syntax from dicom web server ex: 1.2.840.10008.1.2.4.80  (applied only if acceptHeader is not set)
- `omitQuotationForMultipartRequest`: Some servers (e.g., .NET) require the `multipart/related` request to be sent without quotation marks. Defaults to `false`. If your server doesn't require this, then setting this flag to `true` might improve performance (by removing the need for preflight requests). Also note that
if auth headers are used, a preflight request is required.
- `maxNumRequests`: The maximum number of requests to allow in parallel. It is an object with keys of `interaction`, `thumbnail`, and `prefetch`. You can specify a specific number for each type. For `thumbnail`, a small pool (around `5`) is recommended: the study list preview panel fetches a thumbnail per series in parallel, and a larger pool yields little throughput benefit while risking server overload and contention with `interaction`/`prefetch` requests.
- `modesConfiguration`: Allows overriding modes configuration.
  - Example config:
  ```js
    modesConfiguration: {
      '@ohif/mode-longitudinal': {
        displayName: 'Custom Name',
        routeName: 'customRouteName',
          routes: [
            {
              path: 'customPath',
              layoutTemplate: () => {
                /** Custom Layout */
                return {
                  id: ohif.layout,
                  props: {
                    leftPanels: [tracked.thumbnailList],
                    rightPanels: [dicomSeg.panel, tracked.measurements],
                    rightPanelClosed: true,
                    viewports: [
                      {
                        namespace: tracked.viewport,
                        displaySetsToDisplay: [ohif.sopClassHandler],
                      },
                    ],
                  },
                };
              },
            },
          ],
      }
    },
  ```
  Note: Although the mode configuration is passed to the mode factory function, it is up to the particular mode itself if its going to use it to allow overwriting its original configuration e.g.
  ```js
    function modeFactory({ modeConfiguration }) {
    return {
      id,
      routeName: 'viewer',
      displayName: 'Basic Viewer',
      ...
      onModeEnter: ({ servicesManager, extensionManager, commandsManager }) => {
        ...
      },
      /**
       * This mode allows its configuration to be overwritten by
       * destructuring the modeConfiguration value from the mode fatory function
       * at the end of the mode configuration definition.
       */
      ...modeConfiguration,
    };
  }
  ```
- `showLoadingIndicator`: (default to true), if set to false, the loading indicator will not be shown when navigating between studies.
- `showStudyList`: (default to false), if set to false, the OHIF search (or work list) page will not be shown nor will there be a back button (chevron) in the viewer to navigate to it
- `useNorm16Texture`: (default to false), if set to true, it will use 16 bit data type for the image data wherever possible which has
  significant impact on reducing the memory usage. However, the 16Bit textures require EXT_texture_norm16 extension in webGL 2.0 (you can check if you have it here https://webglreport.com/?v=2). In addition to the extension, there are reported problems for Intel Macs that might cause the viewer to crash. In summary, it is great a configuration if you have support for it.
- `useSharedArrayBuffer` (default to 'TRUE', options: 'AUTO', 'FALSE', 'TRUE', note that these are strings), for volume loading we use sharedArrayBuffer to be able to
  load the volume progressively as the data arrives (each webworker has the shared buffer and can write to it). However, there might be certain environments that do not support sharedArrayBuffer. In that case, you can set this flag to false and the viewer will use the regular arrayBuffer which might be slower for large volume loading.
- `supportsWildcard`: (default to false), if set to true, the datasource will support wildcard matching for patient name and patient id.
- `allowMultiSelectExport`: (default to false), if set to true, the user will be able to select the datasource to export the report to.
- `activateViewportBeforeInteraction`: (default to true), if set to false, tools can be used directly without the need to click and activate the viewport.
- `autoPlayCine`: (default to false), if set to true, data sets with the DICOM frame time tag (i.e. (0018,1063)) will auto play when displayed
- `addWindowLevelActionMenu`: (default to true), if set to false, the window level action menu item is NOT added to the viewport action corners
- `showErrorDetails`: determines which runtime environments can display exception and error details caught at the `ErrorBoundary`; acceptable values include: `always`, `dev`, and `production`
- `dangerouslyUseDynamicConfig`: Dynamic config allows user to pass `configUrl` query string. This allows to load config without recompiling application. If the `configUrl` query string is passed, the worklist and modes will load from the referenced json rather than the default .env config. If there is no `configUrl` path provided, the default behaviour is used and there should not be any deviation from current user experience.<br/>
Points to consider while using `dangerouslyUseDynamicConfig`:<br/>
  - User have to enable this feature by setting `dangerouslyUseDynamicConfig.enabled:true`. By default it is `false`.
  - Regex helps to avoid easy exploit. Default is `/.*/`. Setup your own regex to choose a specific source of configuration only.
  - System administrators can return `cross-origin: same-origin` with OHIF files to disallow any loading from other origin. It will block read access to resources loaded from a different origin to avoid potential attack vector.
  - Example config:
    ```js
    dangerouslyUseDynamicConfig: {
      enabled: false,
      regex: /.*/
    }
    ```
  > Example 1, to allow numbers and letters in an absolute or sub-path only.<br/>
`regex: /(0-9A-Za-z.]+)(\/[0-9A-Za-z.]+)*/`<br/>
Example 2, to restricts to either hosptial.com or othersite.com.<br/>
`regex: /(https:\/\/hospital.com(\/[0-9A-Za-z.]+)*)|(https:\/\/othersite.com(\/[0-9A-Za-z.]+)*)/` <br/>
Example usage:<br/>
`http://localhost:3000/?configUrl=http://localhost:3000/config/example.json`<br/>
- `onConfiguration`: Currently only available for DicomWebDataSource, this option allows the interception of the data source configuration for dynamic values e.g. values coming from url params or query params. Here is an example of building the dicomweb datasource configuration object with values that are based on the route url params:
   ```
   {
     namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
     sourceName: 'gcpdicomweb',
     configuration: {
       friendlyName: 'GCP DICOMWeb Server',
       name: 'gcpdicomweb',
       qidoSupportsIncludeField: false,
       imageRendering: 'wadors',
       thumbnailRendering: 'wadors',
       enableStudyLazyLoad: true,
       supportsFuzzyMatching: false,
       supportsWildcard: false,
       singlepart: 'bulkdata,video,pdf',
       onConfiguration: (dicomWebConfig, options) => {
         const { params } = options;
         const { project, location, dataset, dicomStore } = params;
         const pathUrl = `https://healthcare.googleapis.com/v1/projects/${project}/locations/${location}/datasets/${dataset}/dicomStores/${dicomStore}/dicomWeb`;
         return {
           ...dicomWebConfig,
           wadoRoot: pathUrl,
           qidoRoot: pathUrl,
           wadoUri: pathUrl,
           wadoUriRoot: pathUrl,
         };
       },
     },
   },
  ```
This configuration would allow the user to build a dicomweb configuration from a GCP healthcare api path e.g. http://localhost:3000/projects/your-gcp-project/locations/us-central1/datasets/your-dataset/dicomStores/your-dicom-store/study/1.3.6.1.4.1.1234.5.2.1.1234.1234.123123123123123123123123123123


:::note
You can stack multiple panel components on top of each other by providing an array of panel components in the `rightPanels` or `leftPanels` properties.

For instance we can use

```
rightPanels: [[dicomSeg.panel, tracked.measurements], [dicomSeg.panel, tracked.measurements]]
```

This will result in two panels, one with `dicomSeg.panel` and `tracked.measurements` and the other with `dicomSeg.panel` and `tracked.measurements` stacked on top of each other.

:::

### Study Prefetcher

You can enable the study prefetcher so that OHIF loads the next/previous series/display sets
based on the proximity to the current series/display set. This can be useful to improve the user experience


```js
  studyPrefetcher: {
    /* Enable/disable study prefetching service (default: false) */
    enabled: true,
    /* Number of displaysets to be prefetched  (default: 2)*/
    displaySetsCount: 2,
    /**
     * Max number of concurrent prefetch requests (default: 10)
     * High numbers may impact on the time to load a new dropped series because
     * the browser will be busy with all prefetching requests. As soon as the
     * prefetch requests get fulfilled the new ones from the new dropped series
     * are sent to the server.
     *
     * TODO: abort all prefetch requests when a new series is loaded on a viewport.
     * (need to add support for `AbortController` on Cornerstone)
     * */
    maxNumPrefetchRequests: 10,
    /* Display sets loading order (closest (deafult), downward or upward) */
    order: 'closest',
  },

```

### More on Accept Header Configuration
In the previous section we showed that you can modify the `acceptHeader`
configuration to request specific dicom transfer syntax. By default
we use `acceptHeader: ['multipart/related; type=application/octet-stream; transfer-syntax=*']` for the following
reasons:

- **Ensures Optimal Transfer Syntax**: By allowing the server to select the transfer syntax,
  the client is more likely to receive the image in a syntax that's well-suited for fast transmission
  and rendering. This might be the original syntax the image was stored in or another syntax that the server deems efficient.

- **Avoids Transcoding**: Transcoding (converting from one transfer syntax to another) can be a resource-intensive process.
 Since the OHIF Viewer supports all transfer syntaxes, it is fine to accept any transfer syntax (transfer-syntax=*).
 This allows the server to send the images in their stored syntax, avoiding the need for costly on-the-fly conversions.
 This approach not only saves server resources but also reduces response times by leveraging the viewer's capability to handle various syntaxes directly.

- **Faster Data Transfer**: Compressed transfer syntaxes generally result in smaller file sizes compared
  to uncompressed ones. Smaller files transmit faster over the network, leading to quicker load
  times for the end-user. By accepting any syntax, the client can take advantage of compression when available.

However, if you would like to get compressed data in a specific transfer syntax, you can modify the `acceptHeader` configuration or
`requestTransferSyntaxUID` configuration.

### Data Source: stackRetrieveOptions
At the data source configuration level, you can set `stackRetrieveOptions` to customize Cornerstone stack image retrieval. Merged with defaults; only specify overrides. For example, set `streaming: false` when the data source returns uncompressed DICOM (e.g. `application/octet-stream` only) to avoid black image on load:

```js
configuration: {
  acceptHeader: ['application/octet-stream'],
  stackRetrieveOptions: {
    retrieveOptions: { single: { streaming: false } },
  },
}
```

## Environment Variables

We use environment variables at build and dev time to change the Viewer's
behavior. We can update the `HTML_TEMPLATE` to easily change which extensions
are registered, and specify a different `APP_CONFIG` to connect to an
alternative data source (or even specify different default hotkeys).

| Environment Variable | Description                                                                                        | Default             |
| -------------------- | -------------------------------------------------------------------------------------------------- | ------------------- |
| `HTML_TEMPLATE`      | Which [HTML template][html-templates] to use as our web app's entry point. Specific to PWA builds. | `index.html`        |
| `PUBLIC_URL`         | The route relative to the host that the app will be served from. Specific to PWA builds.           | `/`                 |
| `APP_CONFIG`         | Which [configuration file][config-file] to copy to output as `app-config.js`                       | `config/default.js` |
| `PROXY_TARGET`       | When developing, proxy requests that match this pattern to `PROXY_DOMAIN`                          | `undefined`         |
| `PROXY_DOMAIN`       | When developing, proxy requests from `PROXY_TARGET` to `PROXY_DOMAIN`                              | `undefined`         |
| `OHIF_PORT`          | The port to run the webpack server on for PWA builds.                                              | `3000`              |

You can also create a new config file and specify its path relative to the build
output's root by setting the `APP_CONFIG` environment variable. You can set the
value of this environment variable a few different ways:

- ~[Add a temporary environment variable in your shell](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-temporary-environment-variables-in-your-shell)~
  - Previous `react-scripts` functionality that we need to duplicate with
    `dotenv-webpack`
- ~[Add environment specific variables in `.env` file(s)](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env)~
  - Previous `react-scripts` functionality that we need to duplicate with
    `dotenv-webpack`
- Using the `cross-env` package in a npm script:
  - `"build": "cross-env APP_CONFIG=config/my-config.js react-scripts build"`

After updating the configuration, `yarn run build` to generate updated build
output.




[dcmjs-org]: https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
[storescu]: https://support.dcmtk.org/docs/storescu.html
[webpack-proxy]: https://webpack.js.org/configuration/dev-server/#devserverproxy
[orthanc-docker-compose]: https://github.com/OHIF/Viewers/tree/master/platform/app/.recipes/Nginx-Orthanc

[dcm4chee]: https://github.com/dcm4che/dcm4chee-arc-light
[dcm4chee-docker]: https://github.com/dcm4che/dcm4chee-arc-light/wiki/Running-on-Docker
[orthanc]: https://www.orthanc-server.com/
[orthanc-docker]: https://book.orthanc-server.com/users/docker.html
[dicomcloud]: https://github.com/DICOMcloud/DICOMcloud
[dicomcloud-install]: https://github.com/DICOMcloud/DICOMcloud#running-the-code
[osirix]: https://www.osirix-viewer.com/
[horos]: https://www.horosproject.org/
[default-config]: https://github.com/OHIF/Viewers/blob/master/platform/app/public/config/default.js
[html-templates]: https://github.com/OHIF/Viewers/tree/master/platform/app/public/html-templates
[config-files]: https://github.com/OHIF/Viewers/tree/master/platform/app/public/config

---

### Platform Docs Docs Configuration Tours (`platform/docs/docs/configuration/tours.md`)

---
sidebar_position: 3
sidebar_label: Tours
title: Configuring Tours in OHIF
summary: Guide to implementing interactive guided tours in OHIF using Shepherd.js, including detailed configuration options, step definitions, customization parameters, and examples for creating effective user onboarding experiences.
---

# Configuring Tours in OHIF with Shepherd.js

In OHIF, you can configure guided tours for users by leveraging [Shepherd.js](https://shepherdjs.dev/), a JavaScript library for building feature tours. This page explains how you can define and customize these tours within your app configuration file.

## Overview

Tours allow you to provide step-by-step guidance to users, explaining different features of your mode/extension or the viewer. Each tour is associated with a route and consists of several steps, each guiding the user through specific interactions in the viewer.

### Adding a Tour to your Configuration

Here's how you can add a tour to your configuration file:

```javascript
window.config = {
  customizationService: {
    'ohif.tours': {
      $set: [
        {
          id: 'basicViewerTour',
          route: '/viewer',
          steps: [
            {
              id: 'zoom',
              title: 'Zooming In and Out',
              text: 'You can zoom the images using the right click.',
              attachTo: {
                element: '.viewport-element',
                on: 'left',
              },
              advanceOn: {
                selector: '.cornerstone-viewport-element',
                event: 'CORNERSTONE_TOOLS_MOUSE_UP',
              },
            },
          ],
        },
      ],
    },
  },
};
```


## Explanation of Parameters

### `tours` Array

Each item in the `tours` array defines a specific tour for a particular route. The object contains the following properties:

- **`id`**: A unique identifier for the tour. This helps in tracking whether the tour has been shown.
- **`route`**: The route in the application where the tour is applicable. When the user navigates to this route, the tour can automatically trigger if it hasn't been shown before.
- **`steps`**: An array of steps that define the individual guide elements in the tour. Each step corresponds to a UI element and guides the user through interactions.
- **`tourOptions`**: An object that allows you to configure the overall behavior of the tour, such as using a modal overlay or defining default step options.

### `steps` Array

Each step defines a part of the tour. Here's a breakdown of the properties you can define:

- **`id`**: A unique identifier for the step within the tour.
- **`title`**: The title of the step, which appears at the top of the tooltip for the step.
- **`text`**: The content or description of the step, explaining what the user needs to do or understand.
- **`attachTo`**: Specifies where the step should be attached in the DOM. It includes:
  - `element`: A string selector or a DOM element that the step should attach to.
  - `on`: Specifies the position of the tooltip relative to the element (e.g., 'top', 'left', 'bottom', 'right').
- **`advanceOn`**: Defines an event that will automatically advance the tour to the next step. This is useful for actions like clicking a button or scrolling.
  - `selector`: The CSS selector for the element that triggers the advance.
  - `event`: The event name that advances the step, this can be a OHIF service event, or a cornerstone event, or any native JS event (e.g., 'click', 'CORNERSTONE_TOOLS_MOUSE_WHEEL').
- **`beforeShowPromise`**: A function that returns a promise. When the promise resolves, the rest of the show logic for the step will execute. You can use this to ensure that the target element is ready before the step shows.

### `tourOptions`

The `tourOptions` object allows you to configure the overall behavior of the tour. Here's a breakdown of the available properties:

- **`useModalOverlay`**: A boolean that, if set to `true`, places the tour steps above a darkened modal overlay. The overlay creates an opening around the target element so it can remain interactive.
- **`defaultStepOptions`**: Default options that apply to all steps in the tour. You can override these in individual steps. The following are some options available:
  - `buttons`: An array of button objects that appear in the footer of each step. Each button can trigger actions like advancing the tour or skipping it. For example:
    - **`text`**: The label text on the button.
    - **`action`**: A function to execute when the button is clicked. You can advance the tour using `this.next()`, or complete it using `this.complete()`.
    - **`secondary`**: A boolean that, when set to `true`, styles the button as secondary (often for actions like skipping).

### `floatingUIOptions`

You can define positioning options for the steps using **Floating UI** middleware. This helps control how the steps are positioned, especially near the browser edges.

For example, you can ensure that the steps maintain a margin of 24px from the viewport edges by configuring `preventOverflow` middleware:

```javascript
floatingUIOptions: {
  middleware: [
    preventOverflow({ padding: 24 }),
    flip(), // Allows the step to flip if it is overflowing
  ]
}
```

### Shepherd.js Lifecycle Events

Each step and tour can have lifecycle events like `show`, `hide`, `complete`, or `cancel`. These events allow you to hook into the tour’s lifecycle to perform actions when certain events are triggered.

For example:

```javascript
when: {
  show() {
    console.log('Step shown!');
  },
  hide() {
    console.log('Step hidden.');
  }
}
```

## Customizing Your Tour

Once you have a basic tour in place, you can extend it with more advanced features like custom scrolling behavior, dynamic elements, and event-based step advancement. For more details, check out the [Shepherd.js documentation](https://shepherdjs.dev/).

## Licensing
All versions below 14.0 for Shepherd.JS is under the MIT license, if you wish to use any version above 14.0, you can visit the ShepherdJS website to learn about their pricing and plans [Shepherd.js](https://www.shepherdjs.dev/)

[LICENSE](https://github.com/shipshapecode/shepherd?tab=License-1-ov-file#readme)

## Demo



## Conclusion

By leveraging **Shepherd.js**, you can provide users with interactive and informative guided tours of the viewer. This can greatly improve the user experience and help users understand how to use key features.

---

### Platform Docs Docs Configuration Ui (`platform/docs/docs/configuration/ui.md`)

---
sidebar_position: 5
sidebar_label: UI & Appearance
title: UI & Appearance
summary: Overview of OHIF's UI system — the component library, theming and appearance customization, iconography, and the services that drive modals, dialogs, notifications, and viewport layout.
---

# UI & Appearance

OHIF's user interface is built on **ui-next**, a component library purpose-built
for medical imaging workflows. It provides a consistent set of React components,
a token-based theming system, a curated icon set, and a collection of UI services
that manage runtime behavior like modals, notifications, and viewport layout.

This page gives a high-level map of how these pieces fit together and where to
find detailed documentation for each.

## Component Library

The [component library](/components) is the foundation of every panel, toolbar, dialog, and
control in the viewer. Components are organized into three tiers:

- **Simple components** — atomic building blocks like Button, Checkbox, Input,
  Label, Slider, and Switch. These are styled with the design system's tokens and
  are the smallest interactive units.

- **Compound components** — composed from simple components to handle more
  complex interactions: Select, Dialog, DropdownMenu, Tabs, Table, Popover,
  Tooltip, Toast, and others. These manage their own state (open/close, selection,
  focus) via headless patterns.

- **OHIF-specific components** — built for medical imaging workflows and not
  found in general-purpose libraries: AllInOneMenu, CinePlayer, DataRow,
  DataTable, Numeric, PanelSection, SmartScrollbar, ToolButton, and
  ToolButtonList. These integrate directly with OHIF's services and extension
  system.

Every component renders live in the interactive
[Components](/components) section of this documentation site, where you
can see props, variants, and copy usage examples.

## Appearance Dialog

The Appearance dialog is an optional UI that lets end users switch presets,
apply custom CSS overrides, and share themes via URL. It is not enabled by
default, but deployers can
[opt in via configuration](../platform/services/customization-service/appearance-theming.md#enabling-the-theme-module).
See [Appearance & Theming](../platform/services/customization-service/appearance-theming.md)
for the full setup and developer guide.

## Colors & Theming

OHIF uses a **token-based color system** built on CSS custom properties with HSL
values. The base theme (dark mode) is defined in `:root` via Tailwind CSS, and
theme presets override specific tokens by applying a CSS class to `document.body`.

The theming system covers:

- **[Design tokens](/colors-and-theming#color-tokens-and-roles)** — a set of semantic color variables (`--background`,
  `--primary`, `--card`, `--border`, etc.) that every component references. Tokens
  are defined as HSL triplets and consumed via Tailwind's `hsl(var(...))` pattern.

- **Theme presets** — six built-in themes (three tonal, three neutral) that shift
  the entire interface's color palette. Presets are defined as JSON files and
  applied via CSS classes. Also see:
  [Creating Themes](/colors-and-theming#creating-themes) and
  [Adding a Theme Preset](../platform/services/customization-service/appearance-theming.md#adding-a-theme-preset).

- **Accessibility** — foreground tokens are paired with every surface token to
  maintain contrast ratios across themes. When adding custom themes,
  [test colors to match accessibility standards](/colors-and-theming#accessibility).

Explore the live token swatches and theme picker in the interactive
[Colors & Theming](/colors-and-theming) page, and see
[Appearance & Theming](../platform/services/customization-service/appearance-theming.md)
for the full configuration and developer guide.

## Iconography

OHIF ships a curated set of icons designed specifically for medical imaging interfaces.
Icons are SVG-based, registered via `addIcon()`, and rendered through the `Icons`
component. They follow the same token system as the rest of the UI, so icon colors
respond to the active theme.

Browse the full set with search and click-to-copy in the
[Iconography](/components/icons) page.

## White Labeling

OHIF supports replacing the header logo with custom branding via the
`whiteLabeling` configuration key. This lets you rebrand the viewer without
modifying source code.

Add a `whiteLabeling` entry to your configuration file with a
`createLogoComponentFn` that returns a React element:

```js
window.config = {
  /** .. **/
  whiteLabeling: {
    createLogoComponentFn: function(React) {
      return React.createElement(
        'a',
        {
          target: '_self',
          rel: 'noopener noreferrer',
          className: 'text-purple-600 line-through',
          href: '/',
        },
        React.createElement('img', {
          src: './customLogo.svg',
        })
      );
    },
  },
  /** .. **/
};
```



You can use Tailwind CSS utility classes in the `className` property to style
your custom logo component.

## UI Services

While the component library handles what gets rendered, **UI services** handle
the runtime behavior: opening modals, showing notifications, managing viewport
layout, and coordinating dialogs. These services use a pub/sub architecture and
are accessed through the `servicesManager`:

| Service | What it manages |
|---------|----------------|
| [Modal Service](../platform/services/ui/ui-modal-service.md) | Full-screen and contained modals (including the Appearance dialog) |
| [Dialog Service](../platform/services/ui/ui-dialog-service.md) | Lightweight dialogs with form inputs and confirmations |
| [Notification Service](../platform/services/ui/ui-notification-service.md) | Toast notifications (success, warning, error, info) |
| [Viewport Grid Service](../platform/services/ui/viewport-grid-service.md) | Viewport layout, grid arrangement, and active viewport tracking |
| [Viewport Dialog Service](../platform/services/ui/ui-viewport-dialog-service.md) | Dialogs anchored to specific viewports |
| [Viewport Action Menu](../platform/services/ui/viewport-action-menu.md) | Context menus and action buttons on viewport corners |
| [Cine Service](../platform/services/ui/cine-service.md) | Cine playback controls and frame rate |

UI services are documented in the [Services > UI](../platform/services/ui/index.md)
section.

## Customization Service

The [Customization Service](../platform/services/customization-service/customizationService.md)
is the mechanism that ties everything together. It allows deployers and
extension authors to override, extend, or replace UI components and behaviors
without modifying core code. Customizations can be scoped to a specific mode, set
globally via configuration, or provided as defaults by extensions.

The Appearance dialog itself is delivered as a customization module. Deployers
enable it by adding a single reference to their config's `customizationService`
array. This pattern means that any part of the UI that supports customization
can be configured the same way.

See the full customization guide at
[Customization Service](../platform/services/customization-service/customizationService.md),
including the syntax reference for `$set`, `$push`, `$merge`, `$filter`, and
other operations.

---

### Platform Docs Docs Configuration Url (`platform/docs/docs/configuration/url.md`)

---
sidebar_position: 4
sidebar_label: URL
title: URL Parameters
summary: Reference for OHIF Viewer URL parameters that control WorkList filtering, study/series loading, and viewer behavior, including parameters for filtering by patient name, modality, data sources, specifying initial series/instances, and selecting hanging protocols.
---

# URL

You can modify the URL at any state of the app to get the desired result. Here
are different part of the APP that you can modify:


## WorkList

The WorkList can be modified by adding the following query parameters:

### PatientName

The patient name can be modified by adding the `PatientName` query parameter.

```js
/?patientName=myQuery
```

### MRN

The MRN can be modified by adding the `MRN` query parameter.

```js
/?mrn=myQuery
```

### Description

The description can be modified by adding the `Description` query parameter.

```js
/?description=myQuery
```

### Modality

The modality can be modified by adding the `modalities` query parameter.

```js
/?modalities=MG
```

### Accession Number

The accession number can be modified by adding the `accession` query parameter.

```js
/?accession=myQuery
```

### DataSources

If you happen to have multiple data sources configured, you can filter the
WorkList by adding the `dataSources` query parameter.

```js
/?dataSources=orthanc
```

Note1: You should pass the `sourceName` of the data source in the configuration file (not the friendly name nor the name)
Note2: Make sure that the configuration file you are using actually includes that data source. You cannot use a data source from another configuration file.


:::tip

You can add `sortBy` and `sortDirection` query parameters to sort the WorkList

```js
/?patientName=myquery&sortBy=studyDate&sortDirection=ascending
```

:::


## Viewer

The Viewer can be modified by adding the following query parameters:


### Mode

As you have seen before, the Viewer can be configured to be in different modes.
Each mode registers their `id` in the URL.

For instance

```js
/viewer?StudyInstanceUIDs=1.3.6.1.4.1.14519.5.2.1.7009.2403.871108593056125491804754960339
```

will open the viewer in the basic (longitudinal) mode with the StudyInstanceUID
1.3.6.1.4.1.14519.5.2.1.7009.2403.871108593056125491804754960339.

And if configured, the same study can be opened in the `tmtv` mode

```js
/tmtv?StudyInstanceUIDs=1.3.6.1.4.1.14519.5.2.1.7009.2403.871108593056125491804754960339
```

### StudyInstanceUIDs

You can open more than one study in the Viewer by adding the `StudyInstanceUIDs`


```js
/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095722.1&StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095258.1
```

:::tip

You can use this feature to open a current and prior study in the Viewer.
Read more in the [Hanging Protocol Module](../platform/extensions/modules/hpModule.md#matching-on-prior-study-with-uid) section.  You can also use commas to separate
values.

:::


### SeriesInstanceUIDs

Sometimes you need to only retrieve a specific series in a study, you can do
that by providing series level QIDO query parameters in the URL such as
SeriesInstanceUIDs.  This does NOT work with instance or study
level parameters.  For example:

```js
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8
```

This will only open the viewer with one series (one displaySet) loaded, and no
queries made for any other series.

Sometimes you need to only retrieve a subset of series in a study, you can do
that by providing more than one series, separated by commas.  For example:

```js
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8,1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10
```

This will only open the viewer with two series (two displaySets) loaded, and no
queries made for any other series.

### initialSeriesInstanceUID

Alternatively, sometimes you want to just open the study on a specified series, but allowing other
series to be present too.  This is the same behavior can be
achieved by using the `initialSeriesInstanceUID` parameter.  For example:

```js
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8
```

This will open all the series in the study, but the viewer will start with the
series specified by the `initialSeriesInstanceUID` parameter.


Note that you can combine these, if you want to load a specific set of series
plus show an initial one as the first one selected, for example:

```js
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8,1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10
```

### initialSopInstanceUID

You can also specify the initial SOP Instance to be displayed by using the
`initialSopInstanceUID` parameter.  For example:

```js
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095501.9
```

This will open the study with the filtered series, and navigate to the slice 101
which happens to be the SOP Instance specified by the `initialSopInstanceUID`

Note: again you can mix and match

```js
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8,1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095510.8
```

You can even load the whole study and only specify the initial SOP Instance to be displayed. Although
it will take more time to match, but it works as expected.

```js
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095510.8
```

### hangingProtocolId

You can select the initial hanging protocol to apply by using the
hangingProtocolId parameter.  The selected parameter must be available in a
hangingProtocolModule registration, but does not have to be active.

For instance for loading a specific study in mpr mode from start you can use:

```js
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&hangingProtocolId=@ohif/mnGrid
```

### token

Although not recommended, you can use the token param in the URL which will inject
the token into the Authorization header of the request.

---

### Platform Docs Docs Deployment Authorization (`platform/docs/docs/deployment/authorization.md`)

---
sidebar_position: 6
sidebar_label: Auth
title: Authorization and Authentication
summary: Guide to configuring OpenID-Connect authentication in OHIF Viewer, including setup of authorization flows, token handling, and implementation details for securing access to medical imaging data.
---

# Authorization and Authentication
The OHIF Viewer can be configured to work with authorization servers that support one or more of the OpenID-Connect authorization flows. The Viewer finds it's OpenID-Connect settings on the oidc configuration key. You can set these values in your configuration files. For instance you can take a look at our
`google.js` configuration file.


```js
oidc: [
  {
    // ~ REQUIRED
    authority: 'https://accounts.google.com',
    client_id: '723928408739-k9k9r3i44j32rhu69vlnibipmmk9i57p.apps.googleusercontent.com',
    redirect_uri: '/callback',
    response_type: 'id_token token',
    scope: 'email profile openid https://www.googleapis.com/auth/cloudplatformprojects.readonly https://www.googleapis.com/auth/cloud-healthcare', // email profile openid
    // ~ OPTIONAL
    post_logout_redirect_uri: '/logout-redirect.html',
    revoke_uri: 'https://accounts.google.com/o/oauth2/revoke?token=',
    automaticSilentRenew: true,
    revokeAccessTokenOnSignout: true,
  },
],
```

You need to provide the following information:
- authority: The URL of the authorization server.
- client_id: The client id of your application (provided by the authorization server).
- redirect_uri: The callback URL of your application.
- response_type: The response type of the authorization flow (e.g. id_token token, [learn more about different flows](https://darutk.medium.com/diagrams-of-all-the-openid-connect-flows-6968e3990660)).
- scope: The scopes that your application needs to access
- post_logout_redirect_uri: The URL that the user will be redirected to after logout.
- revoke_uri: The URL that the user will be redirected to after logout.
- automaticSilentRenew: If true, the user will be automatically logged in after the token expires.
- revokeAccessTokenOnSignout: If true, the access token will be revoked on logout.



## How it works
The Viewer uses the `userAuthenticationService` to set the OpenID-Connect settings. The `userAuthenticationService` is a singleton service that is responsible for authentication and authorization. It is initialized by the app and you can grab it
from the `servicesManager`

```js
const userAuthenticationService = servicesManager.services.userAuthenticationService;
```

Then the userAuthenticationService will inject the token as Authorization header in the requests that are sent to the server (both metadata
and pixelData).

## Token based authentication in URL
Sometimes (although not recommended), some servers like to send the token
in the query string. In this case, the viewer will automatically grab the token from the query string
and add it to the userAuthenticationService and remove it from the query string (to prevent it from being logged in the console
in future requests).

and example would be

```js
http://localhost:3000/viewer?StudyInstanceUIDs=1.2.3.4.5.6.6.7&token=e123125jsdfahsdf
```



## Securing dynamic datasource URLs
When using `dicomwebproxy` or `dicomjson` data sources with a runtime `?url=...` query parameter,
configure explicit trust boundaries to prevent credential exfiltration.

Use these datasource configuration options:

- `dangerouslyAllowedOriginsForAuthenticatedEnvironments`: Origin allowlist used only when the viewer is running in an authenticated environment. Entries may use `http://` or `https://` and can include localhost origins.

Allowed entry format for `dangerouslyAllowedOriginsForAuthenticatedEnvironments`:

- Must be a bare origin only: `scheme://host[:port]`
- `http://` and `https://` are both allowed
- Localhost is allowed when explicitly listed (for example, `http://localhost:5000`)
- Must not include username/password, path, query string, or hash
- Invalid entries are ignored and logged as misconfigured

Policy summary:

- In unauthenticated environments, any HTTP(S) `?url=` origin is allowed.
- In authenticated environments, same-origin `?url=` values are allowed by default.
- In authenticated environments, cross-origin `?url=` values must be present in `dangerouslyAllowedOriginsForAuthenticatedEnvironments`, otherwise loading fails closed.
- In unauthenticated environments, cross-origin config URLs are fetched with:
  - `method: 'GET'`
  - `mode: 'cors'`
  - `credentials: 'omit'`
  - `redirect: 'error'`
  - `referrerPolicy: 'no-referrer'`
- In unauthenticated environments, same-origin config URLs use a plain `fetch()` call (browser default `credentials: 'same-origin'`).
- Same-origin config URLs are fetched using simple fetch behavior (so same-origin session/cookie auth is preserved).
- In authenticated environments, allowlisted cross-origin config URLs are fetched using simple fetch behavior.
- Returned datasource configuration payloads are consumed as-is (no additional URL/config scrubbing).

Example:

```js
dataSources: [
  {
    namespace: '@ohif/extension-default.dataSourcesModule.dicomwebproxy',
    sourceName: 'dicomwebproxy',
    configuration: {
      name: 'dicomwebproxy',
      dangerouslyAllowedOriginsForAuthenticatedEnvironments: [
        'https://config.example.com',
        'http://localhost:5000',
      ],
    },
  },
]
```

## Implicit Flow vs Authorization Code Flow

The Viewer supports both the Implicit Flow and the Authorization Code Flow. The Implicit Flow is the default currently, as it is easier to set up and use. However, you can opt for better security by using the Authorization Code Flow. To do so, add `useAuthorizationCodeFlow` to the configuration and change the `response_type` from `id_token token` to `code`.

Read more about Implicit Flow vs Authorization Code Flow [here](https://documentation.openiddict.com/guides/choosing-the-right-flow.html#:~:text=The%20implicit%20flow%20is%20similar,when%20using%20response_mode%3Dform_post%20) and [here](https://medium.com/@alysachan830/the-basics-of-oauth-2-0-authorization-code-implicit-flow-state-and-pkce-ed95d3478e1c)

```js
oidc: [
  {
    authority: 'https://accounts.google.com',
    client_id: '723928408739-k9k9r3i44j32rhu69vlnibipmmk9i57p.apps.googleusercontent.com',
    redirect_uri: '/callback',
    scope: 'email profile openid',
    post_logout_redirect_uri: '/logout-redirect.html',
    revoke_uri: 'https://accounts.google.com/o/oauth2/revoke?token=',
    revokeAccessTokenOnSignout: true,
    automaticSilentRenew: true,
    // CHANGE THESE *****************************
    response_type: 'code',
    useAuthorizationCodeFlow: true,
  },
],
```

In fact, since browsers are blocking third-party cookies, the Implicit Flow will cease functioning in the future (not specific to OHIF). Read more [here](https://support.okta.com/help/s/article/FAQ-How-Blocking-Third-Party-Cookies-Can-Potentially-Impact-Your-Okta-Environment?language=en_US). It is recommended to use the Authorization Code Flow and begin migrating to it.

:::note
For the Authorization Code Flow, when authenticating against Google, you must add the `client_secret` to the configuration as well. Unfortunately, this seems to occur only with Google.
:::

---

### Platform Docs Docs Deployment Azure (`platform/docs/docs/deployment/azure.md`)

---
sidebar_position: 12
title: Microsoft Azure Integration
summary: Comprehensive guide for configuring OHIF with Microsoft Azure Healthcare APIs, including step-by-step instructions for Azure AD registration, DICOM service setup, CORS configuration, and OAuth authentication implementation.
---

# Microsoft Azure

This guide explains how to configure a DICOM datasource in OHIF using Azure Healthcare APIs. It focuses on the configuration details and parameters necessary for integration.

---

## Configuring Azure Healthcare APIs as a DICOMweb Data Source

Follow these steps to set up Azure as a DICOM datasource for the OHIF Viewer.

---

### Azure AD Registration:

1. Navigate to the Azure Portal.
2. Select **"Azure Active Directory"** > **"App registrations"** > **"New registration"**.
3. Name your application.
4. Under **"Supported account types"**, select **"Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)"**.
5. Enter the following values in your redirect URI tab:

   

---

### API Permissions:

1. Under your registered application, go to **"API permissions"**.
2. Click **"Add a permission"**.
3. Choose the Azure API for DICOM (**Dicom.ReadWrite**). If you can't find it, refer to the "Configure Azure DICOMWEB Service" section and then return to this step.

   

---

### Authentication:

1. Under **"Authentication"**, check the **"ID tokens"** box since we are using OpenID Connect.

---

### App Client ID and Tenant ID:

1. Copy your app client ID and tenant ID to prepare for use in configuring an OHIF datasource.

---

### Consent:

1. The first time a user logs in, they will be prompted to consent to the permissions your application has requested.
2. Once they grant consent, your application can use the obtained access token to call the specific Microsoft API on behalf of the user.

   

---

### Configure Azure DICOMWEB Service:

1. **Create a Health Data Services workspace**:

   

2. Visit the newly created workspace and press **"Deploy DICOM Service"**:

   

3. After the DICOM service is deployed, visit the **"CORS headers"** section:

   

4. Set the headers and origins to `*` and specify the HTTP methods you'd like to use:

   

5. Save the changes.

6. Add the Microsoft emails of the users you'd like to grant access to your DICOM service in the **"Access control"** section and assign them the **"DICOM Data Owner"** role (or other roles depending on your requirements):

   

7. Copy your DICOM service URL to prepare it for usage in OHIF as a datasource:

   

8. Upload your DICOM files to your service.

---

## 1. Configure OIDC Authentication

Azure uses OpenID Connect (OIDC) for authentication. Update the OIDC section in your configuration file with the following parameters:

```json
"oidc": [
  {
    "redirect_uri": "/callback",
    "response_type": "id_token token",
    "scope": "openid https://dicom.healthcareapis.azure.com/Dicom.ReadWrite",
    "post_logout_redirect_uri": "/logout-redirect.html",
    "automaticSilentRenew": false,
    "revokeAccessTokenOnSignout": true,
    "loadUserInfo": false,
    "authority": "https://login.microsoftonline.com/{tenant-id}/v2.0/",
    "client_id": "{client-id}"
  }
]
```

#### Parameters:
- **redirect_uri**: The URL where users are redirected after successful authentication.
- **response_type**: Specifies the authentication response type (id_token and token).
- **scope**: Defines the level of access. Use `Dicom.ReadWrite` to allow read and write access to DICOM data.
- **post_logout_redirect_uri**: The URL users are redirected to after logout.
- **automaticSilentRenew**: Automatically renews tokens without user interaction. Set to `false` for manual renewal.
- **revokeAccessTokenOnSignout**: Revokes access tokens upon logout for added security.
- **loadUserInfo**: Disables loading additional user information; set to `false` for Azure as it is not supported.
- **authority**: The Azure AD tenant URL for OIDC authorization.
- **client_id**: The application’s client ID from Azure AD.

---

## 2. Add the Data Source Configuration

Update the data source configuration file with your Azure Healthcare APIs details:

```json
{
  "namespace": "@ohif/extension-default.dataSourcesModule.dicomweb",
  "sourceName": "ohif_azure",
  "friendlyName": "ohif_azure",
  "configuration": {
    "singlepart": "bulkdata,pdf,video",
    "imageRendering": "wadors",
    "thumbnailRendering": "wadors",
    "supportsWildcard": true,
    "enableStudyLazyLoad": true,
    "supportsFuzzyMatching": false,
    "supportsStow": true,
    "qidoRoot": "https://{your-dicom-instance}.dicom.azurehealthcareapis.com/v2",
    "wadoUriRoot": "https://{your-dicom-instance}.dicom.azurehealthcareapis.com/v2",
    "wadoRoot": "https://{your-dicom-instance}.dicom.azurehealthcareapis.com/v2"
  }
}
```

#### Parameters:
- **qidoRoot**: Base URL for QIDO-RS queries.
- **wadoUriRoot**: Base URL for WADO-URI requests.
- **wadoRoot**: Base URL for WADO-RS requests.

---

## 3. Running the Viewer with Azure Configuration

1. Save the above configurations in your OHIF Viewer configuration file.
2. Run the viewer:

   ```bash
   cd OHIFViewer
   yarn install --frozen-lockfile
   APP_CONFIG=config/azure.js yarn run dev
   ```

   Replace `config/azure.js` with the path to your configuration file.

---

### Additional Notes
- Ensure that the Azure Healthcare API is enabled for your subscription and that the necessary permissions (e.g., `Dicom.ReadWrite`) are assigned to the OIDC client.
- The `qidoRoot`, `wadoUriRoot`, and `wadoRoot` should point to your Azure DICOM service URL. Replace `{your-dicom-instance}` with your actual instance name.

This setup allows OHIF to interact seamlessly with Azure's Healthcare APIs, enabling robust DICOM management and visualization.

---

### Platform Docs Docs Deployment Build For Production (`platform/docs/docs/deployment/build-for-production.md`)

---
sidebar_position: 2
title: Build for Production
summary: Step-by-step guide to building a production-ready version of the OHIF Viewer, including environment setup, code acquisition, dependency restoration, production build creation, and configuration options for deployment.
---

# Build for Production

### Build Machine Requirements

- [Node.js & NPM](https://nodejs.org/en/download/)
- [Yarn](https://yarnpkg.com/lang/en/docs/install/)
- [Git](https://www.atlassian.com/git/tutorials/install-git)

### Getting the Code

_With Git:_

```bash
# Clone the remote repository to your local machine
git clone https://github.com/OHIF/Viewers.git
```

More on: _[`git clone`](https://git-scm.com/docs/git-clone),
[`git checkout`](https://git-scm.com/docs/git-checkout)_

_From .zip:_

[OHIF/Viewers: master.zip](https://github.com/OHIF/Viewers/archive/master.zip)

### Restore Dependencies & Build

Open your terminal, and navigate to the directory containing the source files.
Next run these commands:

```bash
# If you haven't already, enable yarn workspaces
yarn config set workspaces-experimental true

# Restore dependencies
yarn install --frozen-lockfile

# Build source code for production
yarn run build
```

If everything worked as expected, you should have a new `dist/` directory in the
`platform/app/dist` folder. It should roughly resemble the following:

```bash title="<root>platform/app/dist/"
├── app-config.js
├── app.bundle.js
├── app.css
├── index.html
├── manifest.json
├── service-worker.js
└── ...
```

By default, the build output will connect to OHIF's publicly accessible PACS. If
this is your first time setting up the OHIF Viewer, it is recommended that you
test with these default settings. After testing, you can find instructions on
how to configure the project for your own imaging archive below.

### Configuration

The configuration for our viewer is in the `<root>platform/app/public/config`
directory. Our build process knows which configuration file to use based on the
`APP_CONFIG` environment variable. By default, its value is
[`config/default.js`][default-config]. The majority of the viewer's features,
and registered extension's features, are configured using this file.

The easiest way to apply your own configuration is to modify the `default.js`
file. For more advanced configuration options, check out our
[configuration essentials guide](../configuration/configurationFiles.md).

## Next Steps

### Deploying Build Output

_Drag-n-drop_

- [Netlify: Drop](./static-assets#netlify-drop)

_Easy_

- [Surge.sh](./static-assets#surgesh)
- [GitHub Pages](./static-assets#github-pages)

_Advanced_

- [AWS S3 + Cloudfront](./static-assets#aws-s3--cloudfront)
- [GCP + Cloudflare](./static-assets#gcp--cloudflare)
- [Azure](./static-assets#azure)

### Testing Build Output Locally

A quick way to test your build output locally is to spin up a small webserver.
You can do this by running the following commands in the `dist/` output
directory:

```bash
# Install http-server as a globally available package
yarn global add http-server

# Change the directory to the platform/app
cd platform/app

# Serve the files in our current directory
npx serve ./dist -c ../public/serve.json
```



### Automating Builds and Deployments

If you found setting up your environment and running all of these steps to be a
bit tedious, then you are in good company. Thankfully, there are a large number
of tools available to assist with automating tasks like building and deploying
web application. For a starting point, check out this repository's own use of:

- [CircleCI][circleci]: [config.yaml][circleci-config]
- [Netlify][netlify]: [netlify.toml][netlify.toml] |
  [build-deploy-preview.sh][build-deploy-preview.sh]


[circleci]: https://circleci.com/gh/OHIF/Viewers
[circleci-config]: https://github.com/OHIF/Viewers/blob/master/.circleci/config.yml
[netlify]: https://app.netlify.com/sites/ohif/deploys
[netlify.toml]: https://github.com/OHIF/Viewers/blob/master/platform/app/netlify.toml
[build-deploy-preview.sh]: https://github.com/OHIF/Viewers/blob/master/.netlify/build-deploy-preview.sh

---

### Platform Docs Docs Deployment Cors (`platform/docs/docs/deployment/cors.md`)

---
sidebar_position: 8
title: Cross-Origin Resource Sharing
summary: Detailed explanation of cross-origin security configurations for OHIF Viewer, covering CORS requirements for data source access, iframe embedding, secure contexts, and troubleshooting techniques for proper implementation.
---

# Cross-Origin Information for OHIF

This document describes various security configurations, settings and environments/contexts needed to fully leverage OHIF’s capabilities. One may need some configurations while others might need ALL of them - it all depends on the environment OHIF is expected to run in.

In particular, three of OHIF’s features depend on these configurations:
- [Embedding OHIF in an iframe](#embedding-ohif-in-an-iframe)
- [XMLHttpRequests to fetch data from data sources](#cors-in-ohif)


## Embedding OHIF in an iframe

As described [here](./iframe.md), there are cases where OHIF will be embedded in an iframe. The following links provide more information for setting up and configuring OHIF to work in an iframe:

- [OHIF iframe documentation](./iframe.md#static-build)
- [OHIF as a Cross-origin Resource in an iframe](#ohif-as-a-cross-origin-resource-in-an-iframe)

## Secure Context

MDN defines a secure context as [“a Window or Worker for which certain minimum standards of authentication and confidentiality are met.“](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts)

Any local URL is considered secure. The following are some examples of local URLs that are considered secure…
- http://localhost
- http://127.0.0.1:3000

URLs that are NOT local must be delivered over `https://` or `wss://` (i.e. TLS) to be considered secure. See [When is a context considered secure](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure) in MDN for more information.

### iframes

A page embedded in an iframe is considered secure if it itself and every one of its embedding ancestors are delivered securely. Otherwise it is deemed insecure.


### Configuring/setting up a secure context

[Local URLs are considered secure](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure), and as such whenever OHIF is accessed via a local URL (e.g. http://localhost:3000) it is running in a secure context. For example, in a development environment using the default webpack setup, OHIF can be deployed and accessed in a secure context at http://localhost:3000.

The best alternative is to host OHIF over HTTPS.

:::tip
OHIF can be served over HTTPS in a variety of ways (these are just some examples).
- Website hosting services that offer HTTPS deployment (e.g,. Netlify) or offer HTTPS load balancers (AWS, Google Cloud etc.)
- Setting up a reverse proxy (e.g. `nginx`) with a self-signed certificate that forwards requests to the OHIF server
    - [An OHIF Docker image can be set up this way](./docker/docker.md#ssl).
:::

## Origin Definition

According to [MDN](https://developer.mozilla.org/en-US/docs/Glossary/Origin), a Web content’s origin is defined by the scheme (protocol), hostname (domain), and port of the URL used to access it. Two objects have the same origin only when the scheme, hostname, and port all match.

## CORS - Cross-Origin Resource Sharing

A cross-origin resource is a resource (e.g. image, JSON, etc) that is served by one origin and used/referenced by a different origin.

CORS is the protocol utilized by web servers and browsers whereby a server of one origin identifies and/or restricts which of its resources that other origins (i.e. other than its own) a browser should allow access to. By default a browser does not permit cross-origin resource sharing.

The CORS mechanism relies on the HTTP response headers from the server to indicate if a resource can be shared with a different origin.

See the [MDN CORS article](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) for more information.

### CORS HTTP Headers

The header that mostly concerns OHIF is listed below and should be configured accordingly on the DICOMweb server or any data source that OHIF would make XMLHttpRequests to for its data.

```http
Access-Control-Allow-Origin: `<origin>` | *
```

:::tip
The `Access-Control-Allow-Origin` header specifies which origins can access the served resource embedded in the response.

Either a single, specific origin (i.e. `<origin>`) can be specified or ALL origins (i.e. *)

See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#access-control-allow-origin) for more information.
:::

### CORS in OHIF

OHIF fetches and displays data and images from data sources. It invokes XMLHttpRequests to some data sources such as DICOMweb data sources to fetch the information to render. Typically, a DICOMweb server is hosted on a completely different origin than the one serving OHIF. As such, those XMLHttpRequests use CORS.

### Troubleshooting CORS in OHIF

The following is an example screenshot of the browser console when one of OHIF’s DICOMweb data source servers is not configured for CORS.



And the following is what is in the accompanying network tab.



:::info
Setting the appropriate CORS header varies per server or service that is hosting the data source. What follows below is just one example to remedy the problem.
:::

:::tip
If Orthanc is the data source running in a Docker container composed with/behind nginx. And OHIF is being served at localhost:3000. The issue can be remedied by adding either of the following to Orthanc’s Docker container nginx.conf file.

```nginx
add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always;
```

Or

```nginx
add_header 'Access-Control-Allow-Origin' '*' always;
```
:::




### Header Values (see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy#usage) for more information)

|Value|Description|
|-----|-----------|
|same-site|Only requests from the same site can read the resource.|
|same-origin|Only requests from the same origin can read the resource.|
|cross-origin|Requests from any origin can read the resource. The value is useful and [exists](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy#relationship_to_cross-origin_embedder_policy_coep) primarily for letting documents with the [COEP require-corp value](#header-values-pertinent-to-ohif-see-mdn-for-more-information-1) know that the resource is ok to be embedded|

### OHIF and CORP


#### PDF from a Cross Origin DICOMweb Data Source

There are some DICOMweb data sources (e.g. dcm4chee) whereby OHIF uses the data source’s `/rendered` endpoint to embed a DICOM PDF document in the OHIF DOM using an `<object>` tag.

As specified for the [COEP require-corp value](#header-values-pertinent-to-ohif-see-mdn-for-more-information-1), a page like OHIF with COEP header `require-corp` can embed cross-origin resources in DOM elements that have the [`crossorigin` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin) OR the resource is delivered with an appropriate CORP header. The `<object>` tag does NOT support the `crossorigin` attribute. As such, the PDF must be delivered with a CORP header.

:::tip
Setting the CORP header varies per server or service that is hosting the data source. The following is just one example.

For a dcm4chee DICOMweb data source composed in Docker behind nginx, the CORP header can be configured in the nginx.conf file as such:

```nginx
add_header 'Cross-Origin-Resource-Policy' 'cross-origin' always;
```

If the dcm4chee server and the OHIF server are hosted on the same site, then the following would also work:
```nginx
add_header 'Cross-Origin-Resource-Policy' 'same-site' always;
```
:::

---

### Platform Docs Docs Deployment Custom Url Access (`platform/docs/docs/deployment/custom-url-access.md`)

---
sidebar_position: 4
title: Custom URL Access/Build
summary: "Instructions for hosting the OHIF Viewer on custom URL paths, with two deployment approaches: simple setup for serving the viewer from a subpath with assets at the root, and advanced setup for custom asset paths with detailed configuration steps."
---


# Hosting the Web Viewer on a Custom URL Path

You can host the viewer on a subpath like `/abc` instead of the root `/`. There are **two levels** of customization depending on how you want to serve your static assets.


## Simple Setup (Recommended for Most Use Cases)

If you want to make the viewer accessible from a custom path (e.g. `/abc`) and **don’t care where the assets are loaded from** (they’ll be fetched from the root `/`), this setup is for you.

### What You Get

- Viewer available at `https://yourdomain.com/abc`
- All assets (JS, WASM, etc.) still loaded from the root (`/app.js`, `/viewer.wasm`, etc.)

### How To Set It Up

1. Set `routerBasename` in your config file (e.g., `config/myConfig.js`) to `/abc`
2. Build the viewer with:

```bash
APP_CONFIG=config/myConfig.js yarn build
```

### Local Development

```bash
APP_CONFIG=config/myConfig.js yarn dev
```

---

##  Advanced Setup (Custom Asset Path)

If you want to host the viewer at `/abc` **and** serve static assets from a different location (e.g. `/my-private-assets`), this is a more advanced scenario.

### What You Get

- Viewer accessible from `https://yourdomain.com/abc`
- All assets loaded from `https://yourdomain.com/my-private-assets/`

### Why This is Tricky

Some libraries (especially ones using WASM) load assets using **relative paths**, which can break if not handled carefully. To solve this:

- Set `routerBasename` to `/abc`
- Set `PUBLIC_URL` to `/my-private-assets/`
- Webpack will load assets from the specified public URL.

### Local Development Notes

In development, use proxy rewrites to handle relative asset paths. Example for `dicom-microscopy-viewer`:

```js
proxy: {
  '/dicom-microscopy-viewer': {
    target: 'http://localhost:3000',
    pathRewrite: {
      '^/dicom-microscopy-viewer': `/${PUBLIC_URL}/dicom-microscopy-viewer`,
    },
  },
}
```

This ensures local development can find assets even when libraries expect them at certain paths.


### Building and Serving in Production

To build the viewer for production:

```bash
PUBLIC_URL=/my-private-assets/ APP_CONFIG=config/myConfig.js yarn build
```

If you're using `npx serve`, make sure to update `serve.json`:

```json
{
  "rewrites": [{ "source": "*", "destination": "/abc/index.html" }]
}
```

Serve the viewer like this:

```bash
cd platform/app
mv dist abc  # Rename dist folder to match your viewer route
npx serve -c ./public/serve.json
```

---

### 🐳 Using Docker? You're Covered

If you’re using our Dockerfile, you’re all set — it already handles copying specific asset folders (like `dicom-microscopy-viewer`) to the root:

```Dockerfile
COPY --from=builder /usr/src/app/platform/app/dist/dicom-microscopy-viewer /usr/share/nginx/html/dicom-microscopy-viewer
```

Keep an eye on the browser network tab for any assets that might fail to load — if any other libraries require similar treatment, you’ll need to handle those as well.

---

## Summary

| Goal                              | routerBasename | PUBLIC_URL           | Assets Load From        |
|-----------------------------------|----------------|-----------------------|--------------------------|
| Viewer at `/abc`, assets from `/` | `/abc`         | default                   | Root `/`                 |
| Viewer at `/abc`, assets from `/my-private-assets` | `/abc`         | `/my-private-assets/`  | `/my-private-assets/`    |

---

### Platform Docs Docs Deployment Google Cloud Healthcare (`platform/docs/docs/deployment/google-cloud-healthcare.md`)

---
sidebar_position: 9
title: Google Cloud Healthcare Integration
summary: Guide to setting up Google Cloud Healthcare API as a DICOM data source for OHIF, including project creation, API configuration, OAuth authentication setup, and implementation details for connecting the viewer to Google-hosted medical imaging data.
---

# Google Cloud Healthcare

> The [Google Cloud Healthcare API](https://cloud.google.com/healthcare/) is a
> powerful option for storing medical imaging data in the cloud.

An alternative to deploying your own PACS is to use a software-as-a-service
provider such as Google Cloud. The Cloud Healthcare API promises to be a
scalable, secure, cost effective image storage solution for those willing to
store their data in the cloud. It offers an
[almost-entirely complete DICOMWeb API](https://cloud.google.com/healthcare/docs/dicom)
which requires tokens generated via the
[OAuth 2.0 Sign In flow](https://developers.google.com/identity/protocols/oauth2).
Images can even be transcoded on the fly if this is desired.

## Setup a Google Cloud Healthcare Project

1. Create a Google Cloud account
2. Create a project in Google Cloud

    A project in Google Cloud can be created by clicking the projects drop down box.

    

    And then clicking the `NEW PROJECT` button in the top-right corner of the
    dialogue that is displayed.

3. Enable the [Cloud Healthcare API](https://cloud.google.com/healthcare/) for your project

   :::tip
   An API can be enabled through the `APIs & Services > Enabled APIs & Services`
   console and clicking the `+ ENABLE APIS AND SERVICES` button.

   
   :::

   :::tip
   The principal (i.e. account) that is enabling the Cloud Healthcare API will require
   the following roles that can be set in the `IAM & Admin > IAM` console for the
   desired project.
    - Service Usage Viewer
    - Service Usage Admin
   :::

   :::tip
   Roles can be added to a principal in the `IAM & Admin > IAM` console by clicking
   the `Edit principal` (i.e. pencil) icon to the right of a principal or by clicking the
   `GRANT ACCESS` button at the top of the list of principals. The `GRANT ACCESS`
   button is particularly useful if the `Edit principal` icon is disabled.
   :::

4. (Optional): Create a Dataset and DICOM Data Store for storing your DICOM data

    :::tip
    To both list existing datasets as well as create a new dataset for your project,
    the principal (i.e. account) must have the following roles enabled
    in the `IAM & Admin > IAM` console.

    - Editor

    :::

5. Enable the [Cloud Resource Manager API](https://cloud.google.com/resource-manager/) for your project.

   _Note:_ If you are having trouble finding the APIs, use the search box at
    the top of the Cloud console.

6. Go to APIs & Services > OAuth Consent Screen to create an OAuth Consent screen and fill in your application details.

   - Run through the three step process of adding an OAuth Consent Screen, clicking `SAVE AND CONTINUE` at the end of each step.

      
   - For the Scopes step, for Google APIs, click the `ADD OR REMOVE SCOPES` button.
   - In the `Update selected scopes` dialogue that flies in from the right, add the
   following scopes to the `Manually add scopes` text box.
     - `https://www.googleapis.com/auth/cloudplatformprojects.readonly`
     - `https://www.googleapis.com/auth/cloud-healthcare`

      

   - Click `ADD TO TABLE` and then click `UPDATE`


7. Go to APIs & Services > Credentials to create a new set of credentials:

    - Click `+ CREATE CREDENTIALS` and from the drop down select `OAuth Client ID`.
    See [OAuth 2.0 Client ID](https://developers.google.com/identity/protocols/oauth2/) for more information.

      

    - Choose the "Web Application" type
    - Add your domain (e.g. `http://localhost:3000`) to the Authorized JavaScript
    origins.
    - Add your domain, plus `callback` (e.g. `http://localhost:3000/callback`) to the Authorized Redirect URIs.
    - Save your Client ID for later.

8. (Optional): Create a bucket containing DICOM files and import it into a Data Store

    - When importing a bucket into a Data Store, the following warning might be
      displayed indicating that the Cloud Healthcare Service Agent service account associated with the
      project does not have the `Storage Object Viewer` role.

      

    - The Cloud Healthcare Service Agent service account can be displayed in the
    `IAM & Admin > IAM` console by checking the `Include Google-provided role grants` checkbox.
    The `Storage Object Viewer` role can then be granted to the Cloud Healthcare Service Agent service account.

      

    - More information regarding the Cloud Healthcare Service Agent service account can
    be found at https://cloud.google.com/healthcare-api/docs/permissions-healthcare-api-gcp-products

9. (Optional): Enable Public Datasets that are being hosted by Google:
  https://cloud.google.com/healthcare/docs/resources/public-datasets/

## Run the viewer with your OAuth Client ID

1. Open the `config/google.js` file and change `YOURCLIENTID` to your Client ID
   value.
1. Run the OHIF Viewer using the config/google.js configuration file

```bash
cd OHIFViewer
yarn install --frozen-lockfile
APP_CONFIG=config/google.js yarn run dev
```

## Configuring Google Cloud Healthcare as a datasource in OHIF

A Google Cloud Healthcare DICOM store can be configured as a DICOMweb datasource
in OHIF. A full or partial path is permitted in the configuration file. For
partial paths, the [data source configuration UI](../configuration/dataSources/configuration-ui.md)
will assist in filling in the missing pieces. For example, a configuration with
empty `wadoUriRoot`, `qidoRoot` and `wadoRoot` will prompt for the entire path
step-by-step starting with the project.

---

### Platform Docs Docs Deployment Iframe (`platform/docs/docs/deployment/iframe.md`)

---
sidebar_position: 7
sidebar_label: iframe
title: Embedding OHIF in an iframe
summary: Guidelines for embedding OHIF Viewer within other applications using iframe integration, explaining configuration requirements for path settings, static builds, and proper setup to ensure WebWorkers, WASM, and WebGL features function correctly.
---

# iframe

With the transition to more advanced visualization, loading, and rendering techniques using WebWorkers, WASM, and WebGL, the script tag usage of the OHIF viewer v3 has been deprecated.
An alternative option for script tag usage is to employ an iframe. You can utilize the iframe element to load the OHIF viewer and establish communication with it using the postMessage API if needed.

We recommend utilizing modern development practices and incorporating OHIF viewer within your application using a more modular and integrated approach, such as leveraging bundlers, other UI
components, and frameworks.

## Static Build

You can use the iframe element to load the OHIF viewer as a child element of your application if you need the
viewer to be embedded within your application. The iframe element can be used as follows (use your own custom styles)

```html
<iframe src="./path-to-ohif-build" style="width: 100%; height: 500px; border: none"/>
```

The important thing to note here is that the iframe element is loading the OHIF viewer from the `./path-to-ohif-build`. This path can be
named anything you want, but it should be the path to the OHIF viewer build directory. The build directory is the directory that
contains the `index.html` file (See [build for production](./build-for-production.md) for more information).

It is also required that the PUBLIC_URL environment variable is set to the same path. For example, if the iframe is
`<iframe src="./ohif" />` (which means there is a `ohif` folder containing the build in your main app), then you need to:

1. use a config (e.g. config/myConfig.js) file that is using the `routerBasename` of `/ohif` (note the one / - it is not /ohif/).
2. build the viewer with `PUBLIC_URL=/ohif/ APP_CONFIG=config/myConfig.js yarn build` (note the two / - it is not /ohif).

:::tip
Check to make sure the `app-config.js` in the build is reflecting the correct routerBasename.
:::

:::tip
The PUBLIC_URL tells the application where to find the static assets and the routerBasename will tell the application how to handle the rouets
:::

### Try it locally

Download the index.html and the build (against the /ohif/ path) from [here](https://ohif-assets-new.s3.us-east-1.amazonaws.com/iframe-basic/Archive.zip)

Then run the

```bash
npx http-server unzipped-folder

# you can use npx serve ./dist -c ../public/serve.json as an alternative to http-server
```

You should be able to see

---

### Platform Docs Docs Deployment Nginx  Image Archive (`platform/docs/docs/deployment/nginx--image-archive.md`)

---
sidebar_position: 10
title: Nginx + Image Archive Setup
summary: Tutorial for setting up OHIF Viewer with Nginx and PACS (Orthanc or DCM4CHEE), using Docker for a production-ready system with reverse proxy configuration to securely handle medical imaging data, including installation steps and troubleshooting tips.
---

# Nginx + Image Archive


At a certain point, you may want others to have access to your instance of the
OHIF Viewer and its medical imaging data. This post covers one of many potential
setups that accomplish that. Please note, noticeably absent is user account
control.

Do not use this recipe to host sensitive medical data on the open web. Depending
on your company's policies, this may be an appropriate setup on an internal
network when protected with a server's basic authentication.



### Handling Web Requests

We mitigate our first issue by allowing [Nginx][nginx] to handle incoming web
requests. Nginx is open source software for web serving, reverse proxying,
caching, and more. It's designed for maximum performance and stability --
allowing us to more reliably serve content.

More specifically, we accomplish this by using a
[`reverse proxy`](https://en.wikipedia.org/wiki/Reverse_proxy) to retrieve
resources from our image archive (Orthanc), and when accessing its web admin.

> A reverse proxy is a type of proxy server that retrieves resources on behalf
> of a client from one or more servers. These resources are then returned to the
> client, appearing as if they originated from the proxy server itself.



This setup allows us to create a setup similar to the one pictured below:




- All web requests are routed through `nginx` image
- `/pacs/dicom-web` is a reverse proxy for `orthanc`'s `DICOM Web` endpoints, which handles DICOM requests
- `/pacs` is a reverse proxy for `orthanc`'s Web Admin, which is the UI for managing studies
- All static resources for OHIF Viewer are served up by `nginx` when a matching
  route for that resource is requested

## Getting Started

### Requirements

- Docker
  - [Docker for Mac](https://docs.docker.com/docker-for-mac/)
  - [Docker for Windows](https://docs.docker.com/docker-for-windows/)

_Not sure if you have `docker` installed already? Try running `docker --version`
in command prompt or terminal_

### Setup

- `cd platform/app/.recipes/Nginx-Orthanc`
- run: `docker-compose up --build`
- Navigate to `127.0.0.1` for the viewer (at first there is no study)
- Navigate to `127.0.0.1/pacs` for uploading studies via the UI, or send studies via DIMSE C-STORE to `ORTHANC@127.0.0.1:4242` (hint: you can use utilizes like dcm4che's `storescu` to send studies in bulk via the command line)

:::note
For subsequent runs, use `docker-compose up -d` to start the services without rebuilding the images. However, ensure you rebuild the images if you make changes to the Dockerfile. If you modify the configurations in the `nginx.conf` or `orthanc.json` files, you can restart the services by running `docker-compose up`, as these files are mounted as volumes.

```
Inside docker compose file you see the following volumes mounted:

volumes:
  # Nginx config
  - ./config/nginx.conf:/etc/nginx/nginx.conf
  # Logs
  - ./logs/nginx:/var/logs/nginx
```
:::


You can see the overview of the mentioned steps:


:::info
The following video demonstrates an outdated capture using the deprecated `OpenResty-Orthanc` recipe. However, it still provides insight into the steps for running the viewer with Orthanc. Use the new `Nginx-Orthanc` recipe for the most up-to-date instructions.
:::




<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/843233827?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479"  frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>


### Troubleshooting

_Exit code 137_

This means Docker ran out of memory. Open Docker Desktop, go to the `advanced`
tab, and increase the amount of Memory available.

_Cannot create container for service X_

Use this one with caution: `docker system prune`

_X is already running_

Stop running all containers:

- Win: `docker ps -a -q | ForEach { docker stop $_ }`
- Linux: `docker stop $(docker ps -a -q)`


_Traceback (most recent call last):_
  _File "urllib3/connectionpool.py", line 670, in urlopen_
  _...._

Are you sure your docker is running? see explanation [here](https://github.com/docker/compose/issues/7896)


### Configuration

After verifying that everything runs with default configuration values, you will
likely want to update:

- The domain: `http://127.0.0.1`

#### OHIF Viewer

The OHIF Viewer's configuration is imported from a static `.js` file. The
configuration we use is set to a specific file when we build the viewer, and
determined by the env variable: `APP_CONFIG`. You can see where we set its value
in the `dockerfile` for this solution:

`ENV APP_CONFIG=config/docker-nginx-orthanc.js`

You can find the configuration we're using here:
`/public/config/docker-nginx-orthanc.js`

To rebuild the `webapp` image created by our `dockerfile` after updating the
Viewer's configuration, you can run:

- `docker-compose build` OR
- `docker-compose up --build`

#### Other

All other files are found in: `/docker/Nginx-Orthanc/`

| Service           | Configuration                     | Docs                                        |
| ----------------- | --------------------------------- | ------------------------------------------- |
| OHIF Viewer       | [dockerfile][dockerfile]          | You're reading them now!                    |
| Nginx | [`/nginx.conf`][config-nginx]     |  |
| Orthanc           | [`/orthanc.json`][config-orthanc] | [Here][orthanc-docs]                        |

## Next Steps

### OHIF + Dcm4chee

You can follow the similar steps above to run OHIF Viewer with Dcm4chee PACS.

The recipe for this setup can be found at `platform/app/.recipes/Nginx-Dcm4chee`.


The routes are as follows:
- `127.0.0.1` for the OHIF viewer
- `127.0.0.1/pacs` for the Dcm4chee UI

:::info
For uploading studies, you can see the following gif for the steps:



:::

### Deploying to Production

While you can deploy this solution to production, there is one main caveat: every user can access the app and the patient portal without any authentication. In the next step, we will add authentication with Keycloak to secure the app.




### Improving This Guide

Here are some improvements this guide would benefit from, and that we would be
more than happy to accept Pull Requests for:

- Add Docker caching for faster builds



### Referenced Articles

For more documentation on the software we've chosen to use, you may find the
following resources helpful:

- [Orthanc for Docker](http://book.orthanc-server.com/users/docker.html)

For a different take on this setup, check out the repositories our community
members put together:

- [mjstealey/ohif-orthanc-dimse-docker](https://github.com/mjstealey/ohif-orthanc-dimse-docker)
- [trypag/ohif-orthanc-postgres-docker](https://github.com/trypag/ohif-orthanc-postgres-docker)





[nginx]: https://www.nginx.com/resources/glossary/nginx/
[understanding-cors]: https://medium.com/@baphemot/understanding-cors-18ad6b478e2b
[orthanc-docs]: http://book.orthanc-server.com/users/configuration.html#configuration
[lua-resty-openidc-docs]: https://github.com/zmartzone/lua-resty-openidc

[dockerfile]: https://github.com/OHIF/Viewers/blob/master/platform/app/.recipes/OpenResty-Orthanc/dockerfile
[config-nginx]: https://github.com/OHIF/Viewers/blob/master/platform/app/.recipes/OpenResty-Orthanc/config/nginx.conf
[config-orthanc]: https://github.com/OHIF/Viewers/blob/master/platform/app/.recipes/OpenResty-Orthanc/config/orthanc.json

---

### Platform Docs Docs Deployment Static Assets (`platform/docs/docs/deployment/static-assets.md`)

---
sidebar_position: 3
title: Deploy Static Assets
summary: Guide to deploying OHIF Viewer static assets using various hosting options, from simple drag-and-drop methods like Netlify to more advanced cloud platforms like AWS, GCP, and Azure, with step-by-step instructions for each deployment approach.
---

# Deploy Static Assets

> WARNING! All of these solutions stand-up a publicly accessible web viewer. Do
> not hook your hosted viewer up to a sensitive source of data without
> implementing authentication.

There are a lot of options for deploying static assets. Some services, like
`netlify` and `surge.sh`, specialize in static websites. You'll notice that
deploying with them requires much less time and effort, but comes at the cost of
less product offerings.

While not required, it can simplify things to host your Web Viewer alongside
your image archive. Services with more robust product offerings, like
`Google Cloud`, `Microsoft's Azure`, and `Amazon Web Services (AWS)`, are able
to accommodate this setup.

_Drag-n-drop_

- [Netlify: Drop](#netlify-drop)

_Easy_

- [Surge.sh](#surgesh)
- [GitHub Pages](#github-pages)

_Advanced_

- [Deploy Static Assets](#deploy-static-assets)
  - [Drag-n-drop](#drag-n-drop)
    - [Netlify Drop](#netlify-drop)
  - [Easy](#easy)
    - [Surge.sh](#surgesh)
    - [GitHub Pages](#github-pages)
  - [Advanced](#advanced)
    - [AWS S3 + Cloudfront](#aws-s3--cloudfront)
    - [GCP + Cloudflare](#gcp--cloudflare)
    - [Azure](#azure)

## Drag-n-drop

### Netlify Drop


<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/843233793?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479"  frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>


_GIF demonstrating deployment with Netlify Drop_

1. https://app.netlify.com/drop
2. Drag your `build/` folder on to the drop target
3. ...
4. _annnd you're done_

**Features:**

- Custom domains & HTTPS
- Instant Git integration
- Continuous deployment
- Deploy previews
- Access to add-ons

(Non-free tiers include identity, FaaS, Forms, etc.)

Learn more about [Netlify on their website](https://www.netlify.com/)

## Easy

### Surge.sh

> Static web publishing for Front-End Developers. Simple, single-command web
> publishing. Publish HTML, CSS, and JS for free, without leaving the command
> line.



_GIF demonstrating deployment with surge_

```shell
# Add surge command
yarn global add surge

# In the build directory
surge
```

**Features:**

- Free custom domain support
- Free SSL for surge.sh subdomains
- pushState support for single page apps
- Custom 404.html pages
- Barrier-free deployment through the CLI
- Easy integration into your Grunt toolchain
- Cross-origin resource support
- And more…

Learn more about [surge.sh on their website](https://surge.sh/)

### GitHub Pages

> WARNING! While great for project sites and light use, it is not advised to use
> GitHub Pages for production workloads. Please consider using a different
> service for mission critical applications.

> Websites for you and your projects. Hosted directly from your GitHub
> repository. Just edit, push, and your changes are live.

This deployment strategy makes more sense if you intend to maintain your project in
a GitHub repository. It allows you to specify a `branch` or `folder` as the
target for a GitHub Page's website. As you push code changes, the hosted content
updates to reflect those changes.

1. Head over to GitHub.com and create a new repository, or go to an existing
   one. Click on the Settings tab.
2. Scroll down to the GitHub Pages section. Choose the `branch` or `folder` you
   would like as the "root" of your website.
3. Fire up a browser and go to `http://username.github.io/repository`

Configuring Your Site:

- [Setting up a custom domain](https://help.github.com/en/articles/using-a-custom-domain-with-github-pages)
- [Setting up SSL](https://help.github.com/en/articles/securing-your-github-pages-site-with-https)

Learn more about [GitHub Pages on its website](https://pages.github.com/)

## Advanced

All of these options, while using providers with more service offerings,
demonstrate how to host the viewer with their respective file storage and CDN
offerings. While you can serve your static assets this way, if you're going
through the trouble of using AWS/GCP/Azure, it's more likely you're doing so to
avoid using a proxy or to simplify authentication.

If that is the case, check out some of our more advanced `docker` deployments
that target these providers from the left-hand sidepanel.

These guides can be a bit longer and an update more frequently. To provide
accurate documentation, we will link to each provider's own recommended steps:

### AWS S3 + Cloudfront

- [Host a Static Website](https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html)
- [Speed Up Your Website with Cloudfront](https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-cloudfront-walkthrough.html)

### GCP + Cloudflare

- [Things to Know Before Getting Started](https://code.luasoftware.com/tutorials/google-cloud-storage/things-to-know-before-hosting-static-website-on-google-cloud-storage/)
- [Hosting a Static Website on GCP](https://cloud.google.com/storage/docs/hosting-static-website)

### Azure

 - Deploying viewer to Azure blob storage as a static website:
    Refer to [Host a static website](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-static-website)
    High level steps :
        1.	Go to Azure portal and create a storage account.
        2.   Under Overview->Capabilities, select Static website.
        3.	Enable Static website. Set the index document as ‘index.html’.
        4.	Copy the primary endpoint. This will serve as the root URL for the viewer.
        5.	Save. A new container named ‘$web’ will be created.
        6.	Copy OHIF viewer’s build output from ‘platform\app\dist’ folder to the ‘$web’ container.
        7.	Open browser and navigate to the viewer root URL copied in the step above. It should display OHIF viewer with data from default data source.

       
    Special consideration while accessing DicomJson data source :
      • Due to the way routing is handled in react, it may error out in production when trying to display data through dicomJson data source. E.g. https://[Static Website endpoint]/viewer/dicomjson?url= https://ohif-dicom-json-example.s3.amazonaws.com/LIDC-IDRI-0001.json
      •	Resolution to this is to set error page to ‘index.html’ at the website level. This will ensure that all errors are redirected to root and requests are further served from root path.
       

- [Add SSL Support](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-https-custom-domain-cdn)
- [Configure a Custom Domain](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-custom-domain-name)

## Content-Security-Policy

The hosted viewer ships a `Content-Security-Policy-Report-Only` header (see
`netlify.toml`; the nginx recipes under `platform/app/.recipes` carry the same
policy as commented `add_header` examples). Report-Only means the browser
evaluates the policy and logs violations to the console, but blocks nothing.

What the policy covers:

- `default-src 'self'` with `frame-ancestors 'none'` (mirrors the existing
  `X-Frame-Options: DENY`), `base-uri 'self'`, and `form-action 'self'`.
- `script-src` allows `'unsafe-inline'`/`'unsafe-eval'` (required by the
  current bundles and the cornerstone/vtk WASM and worker paths) plus
  `https://cdnjs.cloudflare.com` for the Rollbar snippet used by demo builds.
- `worker-src`, `object-src`, `frame-src`, and `img-src` allow `blob:` because
  web workers, DICOM PDF rendering, and image data all use blob URLs.
- `connect-src` allows any `https:` origin because deployments point the
  viewer at arbitrary DICOMweb servers; narrow this to your archive's origin
  in your own deployment if you can.

Reading violations: open the browser devtools console and filter for
`Content-Security-Policy`. Report-only violations are logged as warnings and
do not affect behavior; each one is either telemetry for tightening the policy
or a directive that must stay relaxed.

Criteria for promoting Report-Only to an enforcing `Content-Security-Policy`
header: zero unexplained violations across the e2e suite and a manual session
that exercises study load, MPR, SEG display, PDF display, and video display.
Until then, keep the header name `Content-Security-Policy-Report-Only`.

---

### Platform Docs Docs Deployment User Account Control (`platform/docs/docs/deployment/user-account-control.md`)

---
sidebar_position: 11
title: User Account Control
summary: Comprehensive guide for implementing user authentication in OHIF using Keycloak, covering setup with both Orthanc and DCM4CHEE, configuration with OAuth2 proxy, SSL implementation, and detailed steps for local and production deployment scenarios.
---
# User Account Control


:::danger
DISCLAIMER: We make no claims or guarantees regarding the security of this approach. If you have any doubts, please consult an expert and conduct thorough audits.
:::

Making a viewer and its medical imaging data accessible on the open web can
provide a lot of benefits, but requires additional security to make sure
sensitive information can only be viewed by authorized individuals. Most image
archives are equipped with basic security measures, but they are not
robust/secure enough for the open web.

This guide covers one of many potential production setups that secure our
sensitive data.

## Overview

This guide builds on top of our
[Nginx + Image Archive guide](./nginx--image-archive.md),
wherein we used a [`reverse proxy`](https://en.wikipedia.org/wiki/Reverse_proxy)
to retrieve resources from our image archive (Orthanc).

To add support for "User Account Control" we introduce
[Keycloak](https://www.keycloak.org/about.html). Keycloak is an open source
Identity and Access Management solution that makes it easy to secure
applications and services with little to no code. We improve upon our
`reverse proxy` setup by integrating Keycloak and Nginx to create an
`authenticating reverse proxy`.

> An authenticating reverse proxy is a reverse proxy that only retrieves the
> resources on behalf of a client if the client has been authenticated. If a
> client is not authenticated they can be redirected to a login page.

This setup allows us to create a setup similar to the one pictured below:





**Nginx:**

- Acts as a reverse proxy server that handles incoming requests to the domain (mydomain.com:80) and forwards them to the appropriate backend services.
- It also ensures that all requests go through the OAuth2 Proxy for authentication.


**OAuth2 Proxy:**

- Serves as an intermediary that authenticates users via OAuth2.
- Works in conjunction with Keycloak to manage user sessions and authentication tokens.
- Once the user is authenticated, it allows access to specific routes (/ohif-viewer, /pacs, /pacs-admin).

**Keycloak:**

- An open-source identity and access management solution.
- Manages user identities, including authentication and authorization.
- Communicates with the OAuth2 Proxy to validate user credentials and provide tokens for authenticated sessions.

**OHIF Viewer:**

- Hosted under the route /ohif-viewer, which serves the static assets of the OHIF Viewer.

**Orthanc/DCM4chee:**

- PACS (Picture Archiving and Communication System) for managing medical imaging data.
Exposes two routes:
- /pacs: Accesses the DICOM web services.
- /pacs-admin: Provides administrative and explorer interfaces.



## Getting Started - Orthanc


### Requirements

- Docker
  - [Docker for Mac](https://docs.docker.com/docker-for-mac/)
  - [Docker for Windows](https://docs.docker.com/docker-for-windows/)

_Not sure if you have `docker` installed already? Try running `docker --version`
in command prompt or terminal_

### Setup 1 - Trying Locally

Navigate to the Orthanc Keycloak configuration directory:

`cd platform\app\.recipes\Nginx-Orthanc-Keycloak`

Due to the increased complexity of this setup, we've introduced a magic word `YOUR_DOMAIN`. Replace this word with your project IP address to follow along more easily.

Since we are running this locally, we will use `127.0.0.1` as our IP address.

In the `docker-compose.yml` file, replace `YOUR_DOMAIN` with `127.0.0.1`.

In the Keycloak service:


Before:

```
KC_HOSTNAME_ADMIN_URL: http://YOUR_DOMAIN/keycloak/
KC_HOSTNAME_URL: http://YOUR_DOMAIN/keycloak/
```


After

```
KC_HOSTNAME_ADMIN_URL: http://127.0.0.1/keycloak/
KC_HOSTNAME_URL: http://127.0.0.1/keycloak/
```

In the Keycloak healthcheck, replace `YOUR_DOMAIN` with `localhost`.

In the Nginx config, change:

```
server_name YOUR_DOMAIN;
```

to:

```
server_name 127.0.0.1;
```

Since we're not using SSL, remove the following lines from the Nginx config file and create one server instead of two:

Before (two servers one for http and one for https):

```
server {
    listen 80;
    server_name YOUR_DOMAIN;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name YOUR_DOMAIN;

    ssl_certificate /etc/letsencrypt/live/ohifviewer.duckdns.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ohifviewer.duckdns.org/privkey.pem;

    root /var/www/html;
```

After (merging both servers into one only http server):

```
server {
  listen 80;
  server_name 127.0.0.1;

  location /.well-known/acme-challenge/ {
      root /var/www/certbot;
  }

  root /var/www/html;
```

In OAuth2-proxy configuration at `oauth2-proxy.cfg`

Before:

```
redirect_url="http://YOUR_DOMAIN/oauth2/callback"
oidc_issuer_url="http://YOUR_DOMAIN/keycloak/realms/ohif"
```

After:

```
redirect_url="http://127.0.0.1/oauth2/callback"
oidc_issuer_url="http://127.0.0.1/keycloak/realms/ohif"
```

Finally, in the docker-nginx-orthanc-keycloak config file that lives in `platform/app/public/config/docker-nginx-orthanc-keycloak.js`, replace `YOUR_DOMAIN` with

Before:

```
wadoUriRoot: 'http://YOUR_DOMAIN/pacs',
qidoRoot: 'http://YOUR_DOMAIN/pacs',
wadoRoot: 'http://YOUR_DOMAIN/pacs',
```

After:

```
wadoUriRoot: 'http://127.0.0.1/pacs',
qidoRoot: 'http://127.0.0.1/pacs',
wadoRoot: 'http://127.0.0.1/pacs',
```

:::note
This is the config that is used inside the dockerfile to build the viewer, look at dockerfile

`ENV APP_CONFIG=config/docker-nginx-orthanc-keycloak.js`
:::

Run the following command to start the services:

```
docker-compose up --build
```


You can watch the following video, which will guide you through the process of setting up Orthanc with keycloak and OHIF locally.

We have set up two predefined users in Keycloak:

- `user: admin password: admin` - Has access to keycloak portal for managing users and clients
- `user: viewer password: viewer` - Has access to the OHIF Viewer but not the pacs-admin
- `user: pacsadmin password: pacsadmin` - Has access to both the pacs-admin for uploading and the OHIF Viewer

You can navigate to:

- `http://127.0.0.1` - This will redirect you to `http://127.0.0.1/ohif-viewer`, prompting you to log in with Keycloak using either user
- `http://127.0.0.1/pacs-admin` - Only the `pacsadmin` user can access this route, while the `viewer` user cannot
-

<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/981362196?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479"  frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>


### Step 2 - Trying via a Server

Now that you have successfully set up Orthanc with Keycloak and OHIF locally, you can deploy it to a server. While you can rent a server from any provider, this tutorial will demonstrate the process using Linode as an example.

You can watch the following video, which will guide you through the process.

Some notes:

- Since this is a remote machine we need to clone the repo
- Typically a Linux machine, you need to download and install Docker on it
- Use the Visual Studio Code Remote SSH extension to connect to the server
- Use docker extension in Visual Studio Code to manage the containers
- The public IP address of the server now becomes the YOUR_DOMAIN and is used in the configuration files.

Still we have not set up SSL, so we will use HTTP instead of HTTPS.

We should use the same one server configuration as we did locally for Nginx (but with the new server IP address)

:::info
Don't forget to change the `docker-ngix-orthanc-keycloak.js` file to use the new server IP address.
:::

After you run `docker compose up --build` you can navigate to the server IP address and see the viewer will not work...

We have encountered some strange  issues with the Keycloak service not allowing non-HTTPS connections (around 10:00). To resolve this, we need to modify the Keycloak configuration to permit HTTPS. This requires accessing the container and making the necessary changes.

After accessing the container shell

```
cd /opt/keycloak/bin

./kcadm.sh config credentials --server http://localhost:8080 --realm master --user admin
./kcadm.sh update realms/master -s sslRequired=NONE
```

After we need to change some configurations in the Keycloak UI to enable the connection in the server

Navigate to

```
http://IP_ADDRESS/keycloak
```

which will redirect you to the Keycloak login page

0. login with the admin user `admin` and password `admin`
1. From the top left drop down menu, select `ohif` realm
2. Go to `Clients` and select `ohif_viewer`
3. In the `Access Settings` change all instances of `http://127.0.0.1` to `http://IP_ADDRESS`
   1. Root URL:  `http://IP_ADDRESS`
   2. Home URL:  `http://IP_ADDRESS`
   3. Valid Redirect URIs: `http://IP_ADDRESS/oauth2/callback`
   4. Valid post logout URIs: `*`
   5. Web Origins: `http://IP_ADDRESS`
   6. Admin URL: `http://IP_ADDRESS`

Now if you navigate to the IP address it should work !!


<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/981362334?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479"  frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>

### Step 3 - Adding SSL and Deploying to Production

Now we'll add an SSL certificate to our server to enable HTTPS. We'll use Let's Encrypt to generate the SSL certificate.

Let's Encrypt requires a domain name, so we'll use a free domain name service like DuckDNS (duckdns.org). Follow these steps:

1. Visit https://www.duckdns.org/ and create an account.
2. Create a free domain name and point it to your server's IP address.

You can watch a video guide for this process if needed.

Replace `YOUR_DOMAIN` with your new domain name in the `docker-compose.yml` file and all other config files, as we did previously.

Next, we'll add HTTPS support. Add the following lines to the Nginx config file:

(Note: We'll have both HTTP and HTTPS servers, and the server IP will use HTTPS)
```
server {
    listen 80;
    server_name https://IP_ADDRESS;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name https://IP_ADDRESS;

    ssl_certificate /etc/letsencrypt/live/ohifviewer.duckdns.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ohifviewer.duckdns.org/privkey.pem;

    root /var/www/html;
```

Don't forget to replace `YOUR_DOMAIN` with the new domain name in the `docker-nginx-orthanc-keycloak.js` file.

:::info
Remember to include `https://` when adding the domain name to the configurations.
:::

Now, we need to add a certificate. Let's assume we have the domain name `hospital.duckdns.org` and the email we registered with DuckDNS is `your_email@example.com`.

```
 docker run -it --rm --name certbot \
  -v ./config/letsencrypt:/etc/letsencrypt \
  -v ./config/certbot:/var/www/certbot \
  -p 80:80 \
  certbot/certbot certonly \
  --standalone \
  --preferred-challenges http \
  --email your_email@example.com \
  --agree-tos \
  --no-eff-email \
  -d hospital.duckdns.org
```

:::note
Replace "hospital.duckdns.org" with your domain name and update the email address accordingly.
:::

:::warning
DuckDNS is suitable for testing and demonstration purposes only. For production environments, use a proper domain name and SSL certificate to ensure security.
:::

If you follow these steps, you'll encounter the error `invalid parameter: redirect_uri` when attempting to log in to Keycloak. This occurs because the redirect URL isn't set up correctly in the Keycloak client configuration. To resolve this, we need to log in and adjust these settings.

Navigate to:

```
http://IP_ADDRESS/keycloak
```

Log in using the admin credentials:
- Username: `admin`
- Password: `admin`

Replace all IP addresses with the new domain name, using HTTPS.

<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/981362676?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479"  frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>






## Getting Started - DCM4CHEE




You can follow the same steps as above to set up DCM4CHEE. The only difference is that you need to navigate to the correct directory. `platform\app\.recipes\Nginx-Dcm4chee-Keycloak`

You can watch the following video, which will guide you through the process of setting up DCM4CHEE.


<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/981362509?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479"  frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>



## Troubleshooting


_invalid parameter: redirect_uri_

This means the redirect URL isn't set up correctly in the Keycloak client configuration. To resolve this, log in to Keycloak and adjust the settings in the correct client (ohif_viewer) and correct realm (ohif).

_Exit code 137_

This means Docker ran out of memory. Open Docker Desktop, go to the `advanced`
tab, and increase the amount of Memory available.

_Cannot create container for service X_

Use this one with caution: `docker system prune`

_X is already running_

Stop running all containers:

- Win: `docker ps -a -q | ForEach { docker stop $_ }`
- Linux: `docker stop $(docker ps -a -q)`


#### OHIF Viewer

The OHIF Viewer's configuration is imported from a static `.js` file. The
configuration we use is set to a specific file when we build the viewer, and
determined by the env variable: `APP_CONFIG`. You can see where we set its value
in the `dockerfile` for this solution:

`ENV APP_CONFIG=config/docker-nginx-orthanc-keycloak.js`

You can find the configuration we're using here:
`/public/config/docker-nginx-orthanc-keycloak.js`

To rebuild the `webapp` image created by our `dockerfile` after updating the
Viewer's configuration, you can run:

- `docker-compose build` OR
- `docker-compose up --build`



## Next Steps

### Keycloak Theming

The `Login` screen for the `ohif-viewer` client is using a Custom Keycloak
theme. You can find the source files for it in
`platform/app/.recipes/deprecated-recipes/OpenResty-Orthanc-Keycloak/volumes/keycloak-themes`. You can see how
we add it to Keycloak in the `docker-compose` file, and you can read up on how
to leverage custom themes in
[Keycloak's own docs](https://www.keycloak.org/docs/latest/server_development/index.html#_themes).

| Default Theme                                                          | OHIF Theme                                                       |
| ---------------------------------------------------------------------- | ---------------------------------------------------------------- |
|  |  |





## Resources

### Referenced Articles

The inspiration for our setup was driven largely by these articles:

- [Securing Nginx with Keycloak](https://edhull.co.uk/blog/2018-06-06/keycloak-nginx)
- [Authenticating Reverse Proxy with Keycloak](https://eclipsesource.com/blogs/2018/01/11/authenticating-reverse-proxy-with-keycloak/)
- [Securing APIs with Kong and Keycloak](https://www.jerney.io/secure-apis-kong-keycloak-1/)

For more documentation on the software we've chosen to use, you may find the
following resources helpful:

- [Orthanc for Docker](http://book.orthanc-server.com/users/docker.html)
- [OpenResty Guide](http://www.staticshin.com/programming/definitely-an-open-resty-guide/)
- [Lua Ngx API](https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/)
- [Auth0: Picking a Grant Type](https://auth0.com/docs/api-auth/which-oauth-flow-to-use)

We chose to use a generic OpenID Connect library on the client, but it's worth
noting that Keycloak comes packaged with its own:

- [oidc-client-js](https://github.com/IdentityModel/oidc-client-js/wiki)
- [Keycloak JavaScript Adapter](https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter)

If you're not already drowning in links, here are some good security resources
for OAuth:

- [Diagrams of OpenID Connect Flows](https://medium.com/@darutk/diagrams-of-all-the-openid-connect-flows-6968e3990660)
- [KeyCloak: OpenID Connect Flows](https://www.keycloak.org/docs/latest/securing_apps/index.html#authorization-code)

For a different take on this setup, check out the repositories our community
members put together:

- [mjstealey/ohif-orthanc-dimse-docker](https://github.com/mjstealey/ohif-orthanc-dimse-docker)
- [trypag/ohif-orthanc-postgres-docker](https://github.com/trypag/ohif-orthanc-postgres-docker)





[orthanc-docs]: http://book.orthanc-server.com/users/configuration.html#configuration
[lua-resty-openidc-docs]: https://github.com/zmartzone/lua-resty-openidc

[config]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/src/config.js
[dockerfile]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/.recipes/OpenResty-Orthanc-Keycloak/dockerfile
[config-nginx]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/.recipes/OpenResty-Orthanc-Keycloak/config/nginx.conf
[config-orthanc]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/.recipes/OpenResty-Orthanc-Keycloak/config/orthanc.json
[config-keycloak]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/.recipes/OpenResty-Orthanc-Keycloak/config/ohif-keycloak-realm.json

---

### Platform Docs Docs Development Android Ios Debugging (`platform/docs/docs/development/android-ios-debugging.md`)

---
sidebar_position: 12
sidebar_label: Android & iOS Debugging
title: Android & iOS Debugging
summary: Comprehensive guide for debugging OHIF Viewer on mobile devices, covering setup of Android and iOS emulators, step-by-step instructions for connecting Chrome DevTools and Safari Web Inspector, and video tutorials demonstrating the debugging workflow.
---

# Android & iOS Debugging for OHIF using Emulators

This guide covers how to debug the OHIF viewer on Android and iOS emulators using Chrome DevTools and Safari Web Inspector, respectively. You can use these tools to inspect elements, debug JavaScript, and view console logs for the web content running on the emulators.

## Android Emulator Setup with Android Studio

### Prerequisites:
- Install [Android Studio](https://developer.android.com/studio)
- Ensure you have a recent Android SDK and Emulator installed via Android Studio
- Google Chrome installed on your machine

### Steps to Run Android Emulator:

1. **Launch Android Studio:**
   - Open Android Studio and create a new project if you don't already have one.
   - Once your IDE opens up, click on the **Device Manager** icon in the right-side toolbar.

2. **Create a Virtual Device (if necessary):**
   - If you don’t have an existing virtual device, click **Create Virtual Device**.
   - Choose a device model (e.g., Pixel series) and click **Next**.
   - Select a system image with the required Android API version and click **Next**.
   - Finish the setup by clicking **Finish**.

3. **Start the Android Emulator:**
   - Once the device is created, click the **Play** button next to the virtual device to start the emulator.

4. **Open a Browser on the Emulator:**
   - Once the emulator is running, open the **Chrome** app on the virtual device.
   - Navigate to the OHIF Viewer URL to view the application. The URL will be 10.0.2.2:3000, you can read more about it [here](https://developer.android.com/studio/run/emulator-networking).

5. **Debug Using Chrome DevTools:**
   - On your development machine, open Google Chrome.
   - Type `chrome://inspect` in the Chrome address bar and hit **Enter**.
   - You will see your Android device listed under **Remote Target**.
   - Click **Inspect** to open DevTools for the browser on the Android emulator.

6. **Happy Debugging!:**
   - You can now use Chrome DevTools to inspect elements, debug JavaScript, and view console logs directly from the emulator’s browser.

### Video Tutorial

<iframe width="560" height="315" src="https://www.youtube.com/embed/wYa10-djAfI" title="OHIF Debugging Guide for Android" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

---

## iOS Emulator Setup with Xcode

### Prerequisites:
- Install [Xcode](https://developer.apple.com/xcode/) from the Mac App Store.
- Ensure you have the latest iOS SDK.

### Steps to Run iOS Emulator:

1. **Launch Xcode:**
   - Open Xcode and navigate to **Xcode > Settings**.
   - Go to the **Platform** tab and ensure you have an iOS simulator installed for the version of iOS you need. If not you can do so using the + button.

2. **Start the iOS Simulator:**
   - Open Xcode and navigate to **Xcode > Open Developer Tools > Simulator**.
   - Select your device from the list of available simulators and click on it.

3. **Open a Browser on the Simulator:**
   - Run the **Safari** browser

4. **Connect Safari DevTools to the iOS Simulator:**
   - On your development machine, open **Safari** on your Mac.
   - Click **Develop** in the menu bar and select your simulator under **Devices**.
   - You will see the web pages open on the iOS simulator. Select the page to open the inspector.

5. **Happy Debugging!:**
   - You can now use the Safari Web Inspector to inspect elements, debug JavaScript, and view logs for the OHIF Viewer on the iOS simulator.

### Video Tutorial

<iframe width="560" height="315" src="https://www.youtube.com/embed/_M5e6RFl36E" title="OHIF Debugging Guide for iOS" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

---

### Platform Docs Docs Development Architecture (`platform/docs/docs/development/architecture.md`)

---
sidebar_position: 2
sidebar_label: Architecture
title: OHIF Architecture
summary: Detailed explanation of OHIF Viewer's architecture, covering the platform's core components, extensions system, modes concept, and the relationships between these elements that enable building flexible and extensible medical imaging applications.
---

# Architecture

In order to achieve a platform that can support various workflows and be
extensible for the foreseeable future we went through extensive planning of
possible use cases and decided to significantly change and improve the
architecture.

Below, we aim to demystify that complexity by providing insight into how
`OHIF Platform` is architected, and the role each of its dependent libraries
plays.

## Overview

The [OHIF Medical Image Viewing Platform][viewers-project] is maintained as a
[`monorepo`][monorepo]. This means that this repository, instead of containing a
single project, contains many projects. If you explore our project structure,
you'll see the following:

```bash
│
├── extensions
│   ├── default               # default functionalities
│   ├── cornerstone           # 2D/3D images w/ Cornerstonejs
│   ├── cornerstone-dicom-sr  # Structured reports
│   ├── measurement-tracking  # measurement tracking
│   └── dicom-pdf             # View DICOM wrapped PDFs in viewport
|   # and many more ...
│
├── modes
│   └── longitudinal         # longitudinal measurement tracking mode
|   └── basic-dev-mode       # basic viewer with Cornerstone (a developer focused mode)
|   # and many more
│
├── platform
│   ├── core                 # Business Logic
│   ├── i18n                 # Internationalization Support
│   ├── ui                   # React component library
│   └── app               # Connects platform and extension projects
│
├── ...                      # misc. shared configuration
├── lerna.json               # MonoRepo (Lerna) settings
├── package.json             # Shared devDependencies and commands
└── README.md
```

OHIF v3 is composed of the following components, described in detail in further
sections:

- `@ohif/app`: The core framework that controls extension registration, mode
  composition and routing.
- `@ohif/core`: A library of useful and reusable medical imaging functionality
  for the web.
- `@ohif/ui`: A library of reusable components to build OHIF-styled applications
  with.
- `Extensions`: A set of building blocks for building applications. The OHIF org
  maintains a few core libraries.
- `Modes`: Configuration objects that tell @ohif/app how to compose
  extensions to build applications on different routes of the platform.

## Extensions

The `extensions` directory contains many packages that provide essential
functionalities such as rendering, study/series browsers, measurement tracking
that modes can consume to enable a certain workflow. Extensions have had their
behavior changed in `OHIF-v3` and their api is expanded. In summary:

> In `OHIF-v3`, extensions no longer automatically hook themselves to the app.
> Now, registering an extension makes its component available to `modes` that
> wish to use them. Basically, extensions in `OHIF-v3` are **building blocks**
> for building applications.

OHIF team maintains several high value and commonly used functionalities in its
own extensions. For a list of extensions maintained by OHIF,
[check out this helpful table](../platform/extensions/index.md#maintained-extensions).
As an example `default` extension provides a default viewer layout, a
study/series browser and a datasource that maps to a DICOMWeb compliant backend.

[Click here to read more about extensions!](../platform/extensions/index.md)

## Modes

The `modes` directory contains workflows that can be registered with OHIF within
certain `routes`. The mode will get used once the user opens the viewer on the
registered route.

OHIF extensions were designed to provide certain core functionalities for
building your viewer. However, often in medical imaging we face a specific use
case in which we are using some core functionalities, adding our specific UI,
and use it in our workflows. Previously, to achieve this you had to create an
extension to add have such feature. `OHIF-v3` introduces `Modes` to enable
building such workflows by re-using the core functionalities from the
extensions.

Some common workflows may include:

- Measurement tracking for lesions
- Segmentation of brain abnormalities
- AI probe mode for detecting prostate cancer

In the mentioned modes above, they will share the same core rendering module
that the `default` extension provides. However, segmentation mode will require
segmentation tools which is not needed for the other two. As you can see, modes
are a layer on top of extensions, that you can configure in order to achieve
certain workflows.

To summarize the difference between extensions and modes in `OHIF-v3` and
extensions in `OHIF-v2`

> - `Modes` are configuration objects that tell _@ohif/app_ how to compose
>   extensions to build applications on different routes of the platform.
> - In v2 extensions are “plugins” that add functionality to a core viewer.
> - In v3 extensions are building blocks that a mode uses to build an entire
>   viewer layout.

[Click here to read more about modes!](../platform/modes/index.md)

## Platform

### `@ohif/app`

This library is the core library which consumes modes and extensions and builds
an application. Extensions can be passed in as app configuration and will be
consumed and initialized at the appropriate time by the application. Upon
initialization the viewer will consume extensions and modes and build up the
route desired, these can then be accessed via the study list, or directly via
url parameters.

Upon release modes will also be plugged into the app via configuration, but this
is still an area which is under development/discussion, and they are currently
pulled from the window in beta.

Future ideas for this framework involve only adding modes and fetching the
required extension versions at either runtime or build time, but this decision
is still up for discussion.

### `@ohif/core`

OHIF core is a carefully maintained and tested set of web-based medical imaging
functions and classes. This library includes managers and services used from
within the viewer app.

OHIF core is largely similar to the @ohif/core library in v2, however a lot of
logic has been moved to extensions: however all logic about DICOMWeb and other
data fetching mechanisms have been pulled out, as these now live in extensions,
described later.

### `@ohif/ui`

Firstly, a large time-consumer/barrier for entry we discovered was building new
UI in a timely manner that fit OHIF’s theme. For this reason we have built a new
UI component library which contains all the components one needs to build their
own viewer.

These components are presentational only, so you can reuse them with whatever
logic you desire. As the components are presentational, you may swap out
@ohif/ui for a custom UI library with conforming API if you wish to white label
the viewer. The UI library is here to make development easier and quicker, but
it is not mandatory for extension components to use.

[Check out our component library!](https://ui.ohif.org/)

## Overview of the architecture

OHIF-v3 architecture can be seen in the following figure. We will explore each
piece in more detail.



## Common Questions

> Can I create my own Viewer using Vue.js or Angular.js?

You can, but you will not be able to leverage as much of the existing code and
components. `@ohif/core` could still be used for business logic, and to provide
a model for extensions. `@ohif/ui` would then become a guide for the components
you would need to recreate.

> When I want to implement a functionality, should it be in the mode or in an
> extension?

This is a great question. Modes are designed to consume extensions, so you
should implement your functionality in one of the modules of your new extension,
and let the mode consume it. This way, in the future, if you needed another mode
that utilizes the same functionality, you can easily hook the extension to the
new mode as well.




[monorepo]: https://github.com/OHIF/Viewers/issues/768
[viewers-project]: https://github.com/OHIF/Viewers
[viewer-npm]: https://www.npmjs.com/package/@ohif/app
[pwa]: https://developers.google.com/web/progressive-web-apps/
[configuration]: ../configuration/configurationFiles.md
[extensions]: ../platform/extensions/index.md
[core-github]: https://github.com/OHIF/viewers/platform/core
[ui-github]: https://github.com/OHIF/Viewers/tree/master/platform/ui

---

### Platform Docs Docs Development Continuous Integration (`platform/docs/docs/development/continuous-integration.md`)

---
sidebar_position: 8
sidebar_label: Continuous Integration
title: Continuous Integration
summary: Overview of OHIF's CI/CD setup using CircleCI and Netlify, detailing workflows for pull request checks, optional Docker image publishing, deployment to development/staging/production environments, and the release process for npm packages and documentation.
---

# Continuous Integration (CI)

This repository uses `CircleCI` and `Netlify` for Continuous integration.

## Deploy Previews

[Netlify Deploy previews][deploy-previews] are generated for every pull request.
They allow pull request authors and reviewers to "Preview" the OHIF Viewer as if
the changes had been merged.

Deploy previews can be configured by modifying the `netlify.toml` file in the
root of the repository. Some additional scripts/assets for netlify are included
in the root `.netlify` directory.

## Workflows

[CircleCI Workflows][circleci-workflows] are a set of rules for defining a
collection of jobs and their run order. They are self-documenting and their
configuration can be found in our CircleCI configuration file:
`.circleci/config.yml`.

### Workflow: PR_CHECKS

The PR_CHECKS workflow (Pull Request Checks) runs our automated unit and
end-to-end tests for every code check-in. These tests must all pass before code
can be merged to our `master` branch.



### Workflow: PR_OPTIONAL_DOCKER_PUBLISH

The PR_OPTIONAL_DOCKER_PUBLISH workflow allows for "manual approval" to publish
the pull request as a tagged docker image. This is helpful when changes need to
be tested with the Google Adapter before merging to `master`.



> NOTE: This workflow will fail unless it's for a branch on our `upstream`
> repository. If you need this functionality, but the branch is from a fork,
> merge the changes to a short-lived `feature/` branch on `upstream`

### Workflow: DEPLOY

The DEPLOY workflow deploys the OHIF Viewer when changes are merged to master.
It uses the Netlify CLI to deploy assets created as part of the repository's PWA
Build process (`yarn run build`). The workflow allows for "Manual Approval" to
promote the build to `STAGING` and `PRODUCTION` environments.



| Environment | Description                                                                        | URL                                           |
| ----------- | ---------------------------------------------------------------------------------- | --------------------------------------------- |
| Development | Always reflects latest changes on `master` branch.                                 | [Netlify][netlify-dev] / [OHIF][ohif-dev]     |
| Staging     | For manual testing before promotion to prod. Keeps development workflow unblocked. | [Netlify][netlify-stage] / [OHIF][ohif-stage] |
| Production  | Stable, tested, updated less frequently.                                           | [Netlify][netlify-prod] / [OHIF][ohif-prod]   |

### Workflow: RELEASE

The RELEASE workflow publishes our `npm` packages, updated documentation, and
`docker` image when changes are merged to master. `Lerna` and "Semantic Commit
Syntax" are used to independently version and publish the many packages in our
monorepository. If a new version is cut/released, a Docker image is created.
Documentation is generated with `gitbook` and pushed to our `gh-pages` branch.
GitHub hosts the `gh-pages` branch with GitHub Pages.

- Platform Packages: https://github.com/ohif/viewers/#platform
- Extension Packages: https://github.com/ohif/viewers/#extensions
- Documentation: https://docs.ohif.org/






[deploy-previews]: https://www.netlify.com/blog/2016/07/20/introducing-deploy-previews-in-netlify/
[circleci-workflows]: https://circleci.com/docs/2.0/workflows/
[netlify-dev]: https://ohif-dev.netlify.com
[netlify-stage]: https://ohif-stage.netlify.com
[netlify-prod]: https://ohif-prod.netlify.com
[ohif-dev]: https://viewer-dev.ohif.org
[ohif-stage]: https://viewer-stage.ohif.org
[ohif-prod]: https://viewer-prod.ohif.org

---

### Platform Docs Docs Development Contributing (`platform/docs/docs/development/contributing.md`)

---
sidebar_position: 5
sidebar_label: Contributing
title: Contributing to OHIF
summary: Guidelines for contributing to the OHIF project, including best practices for submitting pull requests, working with multiple repositories, and advice on creating changes that are more likely to be accepted by the core team.
---

# Contributing

## How can I help?

Fork the repository, make your change and submit a pull request. If you would
like to discuss the changes you intend to make to clarify where or how they
should be implemented, please don't hesitate to create a new issue. At a
minimum, you may want to read the following documentation:

- [Getting Started](/development/getting-started.md)
- [Architecture](./architecture.md)

Pull requests that are:

- Small
- [Well tested](./testing.md)
- Decoupled

Are much more likely to get reviewed and merged in a timely manner.

## When changes impact multiple repositories

While this can be tricky, we've tried to reduce how often this situation crops
up this with our [recent switch to a monorepo][monorepo]. Our maintained
extensions, ui components, internationalization library, and business logic can
all be developed by simply running `yarn run dev` from the repository root.

Testing the viewer with locally developed, unpublished package changes from a
package outside of the monorepo is most common with extension development. Let's
demonstrate how to accomplish this with two commonly forked extension
dependencies:

#### Other linkage notes

We're still working out some of the kinks with local package development as
there are a lot of factors that can influence the behavior of our development
server and bundler. If you encounter issues not addressed here, please don't
hesitate to reach out on GitHub.

Sometimes you might encounter a situation where the linking doesn't work as
expected. This might happen when there are multiple linked packages with the
same name. You can [remove][unlink] the linked packages inside yarn and try
again.

## Any guidance on submitting changes?

While we do appreciate code contributions, triaging and integrating contributed
code changes can be very time consuming. Please consider the following tips when
working on your pull requests:

- Functionality is appropriate for the repository. Consider creating a GitHub
  issue to discuss your suggested changes.
- The scope of the pull request is not too large. Please consider separate pull
  requests for each feature as big pull requests are very time consuming to
  understand.

We will provide feedback on your pull requests as soon as possible. Following
the tips above will help ensure your changes are reviewed.






[example-url]: https://deploy-preview-237--ohif.netlify.com/viewer/?url=https://s3.eu-central-1.amazonaws.com/ohif-viewer/sampleDICOM.json
[pr-237]: https://github.com/OHIF/Viewers/pull/237
[monorepo]: https://github.com/OHIF/Viewers/issues/768
[unlink]: https://stackoverflow.com/questions/58459698/is-there-a-command-to-unlink-all-yarn-packages-yarn-unlink-all

---

### Platform Docs Docs Development Cs3d Integration (`platform/docs/docs/development/cs3d-integration.md`)

---
sidebar_position: 10
sidebar_label: CS3D Integration Testing
title: Cornerstone3D Integration Testing
summary: How to test OHIF against specific Cornerstone3D branches or versions, both locally and in CI.
---

# Cornerstone3D Integration Testing

OHIF can be tested against a specific Cornerstone3D (CS3D) branch or published version.
This is useful for:

- Validating OHIF changes against unreleased CS3D features
- Upgrading CS3D versions with automated testing
- Debugging issues that span both repositories

## CI Workflow

The **Playwright Tests** workflow in GitHub Actions has built-in CS3D integration support.

### Triggering from a pull request

Open a PR targeting `master` or `release/*`, then add a `CS3D_REF` line anywhere in the PR
description body:

```
CS3D_REF: main
```

or

```
CS3D_REF: 5.10.6
```

The line itself is the request. There is no label, and there is no default: a PR with no
`CS3D_REF` line runs the ordinary Playwright suite against the CS3D version this repo
already pins.

The line must sit at the top level of the body. The workflow ignores a `CS3D_REF` line in
any of three places, because a reader takes each of them as an example and not as an
instruction:

- inside a fenced code block, which is how a PR documents this syntax without triggering it;
- inside an indented code block, which means four spaces or more;
- inside an HTML comment. The OHIF pull request template is almost entirely HTML comments,
  so write the line outside them.

The workflow prints a warning when it ignores a `CS3D_REF` line for one of these reasons.
It fails the gate when the code block or the comment that hides the line is never closed,
because an unclosed block hides every line below it, and a request written there would
otherwise disappear without a word.

The workflow reads the PR body live on every run, so you can change the line and re-run
without pushing a commit.

:::caution
The branch must live in the `cornerstonejs/cornerstone3D` repository. The old
`<owner>:<branch>` form is rejected — it let a PR point the clone at any GitHub account
and run that account's install scripts on the shared self-hosted runner.
:::

### Triggering via workflow_dispatch

Use **Actions > Playwright Tests > Run workflow** and set the `cs3d_ref` input. The input
accepts the same forms as the PR body line, and it also has no default — leave it empty to
run the ordinary suite.

| Input | Behavior |
|-------|----------|
| *(empty)* | Run the ordinary suite against the pinned CS3D version |
| `5.10.6` | Install exact version 5.10.6 |
| `5.11.0-beta.1` | Install exact prerelease |
| `5.10.x` | Install latest 5.10.x release |
| `5.x` | Install latest published 5.x release |
| `4.19+` | Install the latest 4.19.0 or later release within major version 4 |
| `main` | Clone and build the `cornerstonejs/cornerstone3D` `main` branch from source |

The version forms are exactly these five: `5.10.6`, `5.11.0-beta.1`, `5.10.x`, `5.x` and
`4.19+`. A value that is written only from digits, dots, `x` and `+`, and that is not one of
the five, is rejected by the gate with a message that names the accepted forms. A two-part
number such as `5.10` is the common mistake: write `5.10.x` for the latest 5.10 release, or
name the exact release. A branch whose name merely starts with a digit, such as
`5.x-backport`, is still treated as a branch.

### Branch vs Version Behavior

**Version path** (e.g., `5.x`, `5.10.6`):
- Installs OHIF dependencies normally
- Updates all `@cornerstonejs/*` versions in workspace package.json files
- Re-installs to fetch the specified versions from npm
- Runs all tests
- Builds and deploys a Netlify preview
- The tested version is read back from `node_modules` and logged in workflow annotations

**Branch path** (e.g., `main`, `feat/foo`):
- Clones CS3D into `libs/@cornerstonejs`
- Builds CS3D from source (`pnpm run build:esm`)
- Links built packages into OHIF's `node_modules`
- Runs all tests
- Builds and deploys a Netlify preview
- The **CS3D Branch Merge Guard** job reports a red result, because merging would leave
  `master` depending on unreleased CS3D code. The guard is advisory — it reports, it does
  not block the merge button.

### Retiring a branch ref

Once the CS3D change is released, change the line rather than deleting it:

```
CS3D_REF: feat/my-feature now 5.10.6
```

The version after `now` is a **record, not a request**. On every run the workflow compares
it against the version this repo pins and keeps whichever is newer, so the line can never
drag the pin backwards. A line still saying `now 5.10.6` in a repo that has moved on to
5.11.0 tests 5.11.0.

That is what lets the line stay in place as history: the branch name remains visible as the
reason the pinned version moved, and once the repo pins that version or something newer the
line stops changing the run — no rewrite, no reinstall, and no preview deploy. The merge
guard also passes, because what the PR depends on is a published release.

The version after `now` must be one concrete release, such as `5.10.6` or `5.11.0-beta.1`.
A range is rejected, because it would resolve to a different version on a later run and the
record would stop meaning what it said.

:::note
A PR from a fork still requests approval on the `cs3d-integration` environment while the
line is present, even after the line is spent. The gate that makes that decision has no
checkout by design, so it cannot tell which version the repo pins. Delete the line to stop
the prompt.
:::

### Approval and deferral for fork PRs

Two rules apply to a PR from a fork, and to no other PR:

- **An integration run waits for approval.** A `CS3D_REF` line asks the shared self-hosted
  runner to build and execute CS3D code, so the run pauses on the `cs3d-integration`
  environment until one of the named reviewers approves that specific run.
- **A PR that changes a CI-defining file does not run Playwright until it is merged.** The
  paths are `.github/`, `.scripts/`, `pnpm-workspace.yaml`, `preinstall.js`, any root
  pnpmfile, and every `.npmrc` in the workspace. `package.json` and `pnpm-lock.yaml` are
  not on the list, so a fork PR that adds a dependency or moves a module between workspace
  packages runs Playwright as usual; changes to the root `package.json` and
  `pnpm-lock.yaml` still need a code owner's review before merge.

A PR from a branch in the OHIF repository is unaffected by both rules: the branch lives in
this repo, so someone with write access pushed it.

### Version Commit on Merge

The CS3D version update is **not committed** during the PR workflow. The tested version is
recorded in workflow annotations (`::notice::` messages). To apply the version update:

1. After the PR is approved and the version test passes, note the tested version from the logs
2. Run `node .scripts/cs3d-set-version.mjs <version>` locally or as part of the merge process
3. Commit the updated package.json files

## Local Development

### Setting Up a CS3D Worktree

For local development, use the CS3D repo's `link:cs3d` script to create a git worktree.
This shares a single git repository across multiple OHIF checkouts:

```bash
# From your cornerstone3D repo:
bun run link:cs3d /path/to/ohif main
# or with a specific branch:
bun run link:cs3d /path/to/ohif origin:feat/my-feature
```

This creates `libs/@cornerstonejs` as a worktree and generates `link-cs3d.js` / `unlink-cs3d.js`
helper scripts. See the [Local Linking](./link.md) docs for more on the linking workflow.

### Package Scripts

Once `libs/@cornerstonejs` exists (via worktree or clone):

```bash
# Switch branches in the existing worktree
yarn cs3d:checkout <branch-name>

# Install dependencies and build ESM
yarn cs3d:build

# Symlink CS3D packages into node_modules/@cornerstonejs
yarn cs3d:link

# Remove symlinks and restore packages from npm registry
yarn cs3d:unlink
```

:::note
`cs3d:checkout` requires `libs/@cornerstonejs` to already exist. It runs
`git fetch && git checkout` inside that directory.
:::

### Wildcard Versions

The `cs3d-resolve-version.mjs` script resolves patterns like `5.x` or `5.10.x`:

```bash
node .scripts/cs3d-resolve-version.mjs 5.x
# prints: 5.10.6  (or whatever the latest 5.x release is)
```

### Updating All CS3D Versions

```bash
node .scripts/cs3d-set-version.mjs 5.10.6
# Updates all @cornerstonejs/* dependencies across the workspace

node .scripts/cs3d-set-version.mjs 5.10.6 --only-if-newer
# Same, but refuses to move the pin backwards
```

The workflow uses `--only-if-newer` for the version recorded after `now` in a retiring
`CS3D_REF` line, which is how a spent line stops changing the run. Without the flag the
requested version is applied as given, downgrades included.

This updates the packages that the cornerstone3D monorepo releases together (adapters, ai,
core, dicom-image-loader, labelmap-interpolation, metadata, nifti-volume-loader,
polymorphic-segmentation, tools, utils). It does not touch the codec packages or
`calculate-suv`, which carry their own version lines.

The script stops with an error when it finds an `@cornerstonejs/*` dependency that is in
neither group. A package it does not recognise is a question it cannot answer: it would
either leave that package behind at the old version, or ask npm for a release that does not
exist. Add the new package to `CS3D_PACKAGES` or to `INDEPENDENT_PACKAGES` in
`.scripts/cs3d-set-version.mjs`.

---

### Platform Docs Docs Development Link (`platform/docs/docs/development/link.md`)

---
sidebar_position: 9
sidebar_label: Local Linking
title: Local Library Linking
summary: Brief introduction to the concept of local linking for library development in OHIF, explaining how to test libraries in application context before publishing, with reference to Cornerstonejs linking documentation.
---

# Introduction

Local linking allows you to develop and test a library in the context of an application before it's published or when you encounter
a bug that you suspect is related to a library. With Yarn, this can be achieved through the yarn link command.

You can take a look at the Cornerstonejs tutorial for linking https://www.cornerstonejs.org/docs/contribute/linking

## Linking with `bun`

The [instructions](#introduction) above describe how to use `yarn` for local linking. Some use `bun` for day-to-day
code linking and execution. The method to link locally using `bun` differs slightly.

:::tip

Linking locally with `bun` provides for running the [playwright tests](./playwright-testing.md) locally so as to include (and test) local changes from Cornerstone3D and other libraries like dicom-microscopy-viewer.

:::

### Linking Cornerstone3D

In the local Cornerstone3D, simply replace `yarn` with `bun` for each of the commands. For example, in `cornerstone/packages/core` the following would be done.

```
# In cornerstone/packages/core
bun unlink
bun link
bun dev
```

In OHIF, edit the root `package.json` file to include the cornerstone3D packages to link and add them to the `resolutions`.

For example here is a snippet of the `package.json` file linking cornerstone core and tools locally. Add whichever
cornerstone packages to link locally in the `resolutions`.

```
  ...
  "resolutions": {
    "commander": "8.3.0",
    "path-to-regexp": "0.1.12",
    "@cornerstonejs/core": "link:@cornerstonejs/core",
    "@cornerstonejs/tools": "link:@cornerstonejs/tools",
    ...
  },
  ...
```

In OHIF, run `bun install -f --config=.\bunfig.update-lockfile.toml` and then run OHIF using either `bun dev` or `bun dev:fast`.

### Linking dicom-microscopy-viewer

The process for linking other libraries such as the dicom-microscopy-viewer is similar to that of linking Cornerstone3D.

```
# In the local dicom-microscopy-viewer directory
bun unlink
bun link
bun webpack:dynamic-import:watch
```
In OHIF, edit the root `package.json` file to include the dicom-microscopy-viewer package in the `resolutions`. The following is an example of this...

```
  ...
  "resolutions": {
    "commander": "8.3.0",
    "path-to-regexp": "0.1.12",
    "dicom-microscopy-viewer": "link:dicom-microscopy-viewer",
    ...
  },
  ...
```

In OHIF, run `bun install -f --config=.\bunfig.update-lockfile.toml` and then run OHIF using either `bun dev` or `bun dev:fast`.

---

### Platform Docs Docs Development Notes Requirements (`platform/docs/docs/development/notes-requirements.md`)

---
sidebar_position: 14
sidebar_label: Notes and Requirements
title: Notes and Requirements for general OHIF behaviour
summary: Specifies some of the expected behavior of OHIF generally
---

# Notes and Requirements

This document just lists general notes and requirements for how OHIF behaves.
The plan is to break this document down into a new sub-category once there
are sufficient notes/requirements.


## Series and Display Set Sorting `sortStudy.ts`

Often a user will want to see a sorted list of series, or more generally
a sorted list of display sets.  Series are the original data and can be split
up into several display sets, although they are the same general sort of concept

For example, an MR series might contain both T1 and T2 echos, and the T2 echo
should occur after the T1.  Or, a single series might contain 4 mammography views:
`LCC`, `RCC`, `LMLO`, `RMLO` with all the `CC` views shown first, and within
that all the left views first for a given sub-type of CC view.

To allow controlling that, the `sortStudy` can register sort functions
that user used when two display sets come from the same series.  Between
those display sets, the registration also registers a default ordering
for that compare function.  Thus, the registration might look like:

```javascript
   addSameSeriesCompare('mammographyCompare', mammographyCompare, 5)
   addSameSeriesCompare('mrT1T2Compare', mrT1T2Compare, 7);
```

Then, the display set for mr and mammography need to set the field `compareSameSeries`
to the value `mammographyCompare`.

```javascript
   makeDisplaySet
     ...
     displaySet = {
      ...,
      compareSameSeries: 'mammographyCompare',
```

### Specifying Sort Order from Series Split

The series split rules (`getSopClassHandlerModule`) can specify a custom order
of display sets for the same series by adding a `sortVector`
to the display set created.  Display sets which match on series instance uid
are then compared using the sort vector.  The first element is the general sort
order for this type of value among all other sort types, and must be numeric.
The remainder of the values in the vector should be consistent for all
sort vectors whose first value is the same value.

For example, the mammography sort vector might have a primary value of '25',
and then use the next three values for `view type`, `sub type` and `side`.
It might also be true that "both" side views sort before everything and would be assigned
a value less than `25` here.

```
   // LCC view
   [25, 'CC', 'L', 'XO']
   // BCC view
   [24, 'CC', 'B']
```

### Display Set Date and Time `getLatestInstanceDateTime`

Derived series - reports, segmentations, structure sets - are listed after the
images in reverse date/time order, so the most recently created one is the one
nearest the images.  Ordering them that way needs a single date/time saying when
each display set was created.

A display set is created from one instance of its series, which it carries as
`instance`, and the date/time it is ordered by is the creation date/time of that
instance.  This matters because every instance of a series carries that series'
`SeriesDate`/`SeriesTime`: a second report saved into an existing SR series has
the date and time of the series as it was first created, and only its
instance level date/time say when the report itself was made.

- **Instances** are sorted by instance number, increasing, as the default.  Only
  when the instance numbers do not decide - they tie, or neither instance has
  one - does the sort fall back to the creation date/time below, and then to the
  sop instance uid.  The last instance of a series is taken to be the most
  recently created one, so an instance number that fails to say which that is
  has to be replaced by something that does.
- **Display sets** are ordered by their own `SeriesDate`/`SeriesTime`, which
  hold the date/time *of the display set* and not always the date/time of the
  series the instances belong to.  The SOP class handler writes both, with
  `getLatestInstanceDateTime` of the instance the display set shows.  A handler whose
  `addInstances` advances that instance - the SR and the chart one, which append
  to their display set rather than making a new one - has to write both again,
  or the date shown for the display set stays that of the report it replaced and
  disagrees with the place the series list has just sorted it into.
- **Series** carry the same two attributes and are ordered by them in the same
  way, so sorting a list of series rather than display sets is the plain series
  date/time sort it always was.

The sort reads the display set and never `displaySet.instance`, because
`getLatestInstanceDateTime(instance)` differs between the display sets of one split
series.  A key that varies inside a series hides the `addSameSeriesCompare`
comparison, which runs only when the key ties, and it makes the comparator
inconsistent: with one key inside a series and another between series, a series
A whose two display sets straddle a display set B of another series gives
A1 < B, B < A2 and A2 < A1, and `Array.prototype.sort` then returns a different
list for each input order.

Two consequences follow, and both are intended:

- An image display set takes the instance's `SeriesDate`/`SeriesTime`, which
  every instance of a series carries identically.  Every display set of one
  mammography, CR, DX, ECG or multi-frame series therefore holds the same value,
  ties on the key, and the display sets stay together in the series list.
- Two display sets of one series that hold *different* values order by those
  values, and a display set of another series can come between them.  That is
  what a second segmentation saved into an existing SEG series needs:
  `DisplaySetService` gives it its own display set, because the SEG, RTSTRUCT
  and PMAP handlers have no `addInstances`, and that display set has to take the
  position of the save.  A split that needs its display sets kept together gives
  all of them one value - the value of the series - and registers a comparison
  with `addSameSeriesCompare` to order them among themselves.

DICOM records "when this was created" in several different attribute pairs, and
which of them are present depends on the modality and on whoever wrote the
object, so `getLatestInstanceDateTime` chooses one pair from all of them:
`InstanceCreationDate`/`Time`, `ContentDate`/`Time`, `AcquisitionDate`/`Time`
(or the combined `AcquisitionDateTime`), `StructureSetDate`/`Time`,
`PresentationCreationDate`/`Time` and `SeriesDate`/`Time`.  The rules are:

- The date is the latest date found in any of those attributes.
- The time is the latest time found in an attribute carrying that exact same
  date.  A time is never combined with a date it did not arrive with, so the
  result is always a date/time that really occurred.
- When nothing carries a time for the winning date, the time is empty and the
  ordering is only accurate to the day, which is as good as the data allows.
- `StudyDate`/`StudyTime` are not included.  Every series in the study shares
  them, so they cannot tell one series from another.
- A value that is not a DICOM DA counts as no date at all.  Some series level
  metadata carries a date already formatted for display, and `19-Jan-2026` would
  otherwise read as `192026` and order by day of month.
- A combined `AcquisitionDateTime` that ends with the `&ZZXX` UTC offset is
  moved to the offset of the viewer, by `expandDicomDateTime`, and the date/time
  read from it is the local wall clock reading of that same instant.  A DT that
  declares no offset is read exactly as it is, like every bare DA and TM here.
  A DT holding a date alone names the start of that day, which is the reading
  the move needs, and it comes back with the time of that instant here.  It gets
  that time even when it declares the viewer's own offset, so that two DT values
  naming one instant always give one answer.

For any of this to work on newly stored objects, `updateNewInstanceMetadata`
stamps every report, segmentation and structure set OHIF saves with the current
date/time, and with an instance number one higher than every instance already in
the series - the most recently created instance of a series is not necessarily
the one with the highest instance number, so deriving the instance number from a
single predecessor instance can collide with an instance that already exists.

The stamp writes `InstanceCreationDate`/`Time`, which the SOP Common module
gives to every IOD, and the creation date/time pair the modality's own IOD
defines: `StructureSetDate`/`Time` for an RTSTRUCT, `PresentationCreationDate`/
`Time` for a PR, and `ContentDate`/`Time` for everything else - a SEG gets that
pair from the Multi-frame Functional Groups module, an SR from the SR Document
General module, and an image series from the General Image module.  The RTSTRUCT
and PR IODs define no content date/time at all, so writing one on them adds an
attribute a strict validator or archive can reject the instance for.

That stamp covers the instance level attributes, which are the ones that move
when an object is added to an existing series.  The date/time of the series
being *created* is generated with the object instead, from
`getCurrentDicomDateTime`, because dcmjs and the adapters stamp `SeriesDate`/
`Time` and `StructureSetDate`/`Time` in UTC - the wrong wall clock reading
anywhere else, and around midnight the wrong day.  The store commands pass those
in, so an object OHIF saves reads as one wall clock instant throughout.

A comparator registered with `addSameSeriesCompare` orders two display sets of
the same series, and decides before the instance compare that
`compareSameSeriesDisplaySet` otherwise falls through to.

The date/time stamped on a saved object, and the ordering rules above, changed in
3.14 - see
[display set date/time ordering](../migration-guide/3p13-to-3p14/display-set-ordering.md)
for what moves and what to do about it.

---

### Platform Docs Docs Development Ohif Cli (`platform/docs/docs/development/ohif-cli.md`)

---
sidebar_position: 3
sidebar_label: OHIF CLI
title: OHIF Command Line Interface
summary: Comprehensive guide to the OHIF CLI tool for managing extensions and modes, including commands for creating, linking, adding, removing, and publishing components, with detailed examples and explanations of the underlying configuration system.
---

# OHIF Command Line Interface

:::danger Deprecated
`ohif-cli` is deprecated as of 3.14 and will be removed in the following
release.

**To create a new extension or mode**, point an AI coding agent at an existing
one in `extensions/` or `modes/` and have it generate the new package. The
in-repo packages are always current; the templates bundled with the CLI are a
snapshot and drift out of date between releases.

**`link-extension` and `link-mode` no longer affect the default build.** They
write a `resolve.modules` entry into `platform/app/.webpack/webpack.pwa.js`,
which is read only by the legacy rspack pipeline — `pnpm run dev`, its
`dev:orthanc` / `dev:dcm4chee` / `dev:static` variants, `pnpm run build:legacy`,
and the Playwright e2e server. As of 3.14 the default `pnpm run build` and
`pnpm run dev:fast` go through `rsbuild.config.ts`, which does not read that
file. If your linked package resolves dependencies from its own
`node_modules`, use `pnpm run build:legacy` until the CLI is removed.

To add an extension or mode without the CLI, edit
[`pluginConfig.json`](../platform/extensions/pluginConfig.md) directly.
:::

OHIF-v3 architecture has been re-designed to enable building applications that
are easily extensible to various use cases (Modes) that behind the scene would
utilize desired functionalities (Extensions) to reach the goal of the use case.
Now, the question is _how to create/remove/install/uninstall an extension and/or
mode?_

You can use the `cli` script that comes with the OHIF monorepo to achieve these
goals.


## CLI Installation

You don't need to install the `cli` currently. You can use `yarn` to invoke its
commands.

## Commands

:::note Important
All commands should run from the root of the monorepo.
:::


There are various commands that can be used to interact with the OHIF-v3 CLI. If
you run the following command, you will see a list of available commands.

```
yarn run cli --help
```

which will output

```
OHIF CLI

Options:
  -V, --version                          output the version number
  -h, --help                             display help for command

Commands:
  create-extension                       Create a new template extension
  create-mode                            Create a new template Mode
  add-extension <packageName> [version]  Adds an ohif extension
  remove-extension <packageName>         removes an ohif extension
  add-mode <packageName> [version]       Removes an ohif mode
  remove-mode <packageName>              Removes an ohif mode
  link-extension <packageDir>            Links a local OHIF extension to the Viewer to be used for development
  unlink-extension <extensionName>       Unlinks a local OHIF extension from the Viewer
  link-mode <packageDir>                 Links a local OHIF mode to the Viewer to be used for development
  unlink-mode <extensionName>            Unlinks a local OHIF mode from the Viewer
  list                                   List Added Extensions and Modes
  search [options]                       Search NPM for the list of Modes and Extensions
  help [command]                         display help for command
```

As seen there are commands for you such as: `create-extension`, `create-mode`,
`add-extension`, `remove-extension`, `add-mode`, `remove-mode`,
`link-extension`, `unlink-extension`, `link-mode`, `unlink-mode`, `list`,
`search`, and `help`. Here we will go through each of the commands and describe
them.

### create-mode

If you need to create a new mode, you can use the `create-mode` command. This
command will create a new mode template in the directory that you specify.
The command will ask you couple of information/questions in order
to properly create the mode metadata in the `package.json` file.

```bash
yarn run cli create-mode
```

<div style={{textAlign: 'center',}}>




</div>

Note 1: Some questions have a default answer, which is indicated inside the
parenthesis. If you don't want to answer the question, just hit enter. It will
use the default answer.

Note 2: As you see in the questions, you can initiate a git repository for the
new mode right away by answering `Y` (default) to the question.

Note 3: Finally, as indicated by the green lines at the end, `create-mode` command only
create the mode template. You will need to link the mode to the Viewer in order
to use it. See the [`link-mode`](#link-mode) command.

If we take a look at the directory that we created, we will see the following
files:

<div style={{maxWidth:"500px"}}>



</div>


### create-extension

Similar to the `create-mode` command, you can use the `create-extension`
command to create a new extension template. This command will create a new
extension template in the directory that you specify the path.

```bash
yarn run cli create-extension
```


Note: again similar to the `create-extension` command, you need to manually link
the extension to the Viewer in order to use it. See the
[`link-mode`](#link-mode) command.


### link-extension

`link-extension` command will link a local OHIF extension to the Viewer. This
command will utilize `yarn link` to achieve so.

```bash
yarn run cli link-extension <extensionDir>
```

### unlink-extension

There might be situations where you want to unlink an extension from the Viewer
after some developments. `unlink-extension` command will do so.

```bash
ohif-cli unlink-extension <extensionName>
```



### link-mode

Similar to the `link-extension` command, `link-mode` command will link a local
OHIF mode to the Viewer.

```bash
yarn run cli link-mode <modeDir>
```

### unlink-mode

Similar to the `unlink-extension` command, `unlink-mode` command will unlink a
local OHIF mode from the Viewer.

```bash
ohif-cli unlink-mode <modeName>
```

### add-mode

OHIF is a modular viewer. This means that you can install (add) different modes
to the viewer if they are published online . `add-mode` command will add a new mode to
the viewer. It will look for the mode in the NPM registry and installs it. This
command will also add the extension dependencies that the mode relies on to the
Viewer (if specified in the peerDependencies section of the package.json).

:::note Important
`cli` will validate the npm package before adding it to the Viewer. An OHIF mode
should have `ohif-mode` as one of its keywords.
:::

Note: If you don't specify the version, the latest version will be used.

```bash
yarn run cli add-mode <packageName> [version]
```

For instance `@ohif-test/mode-clock` is an example OHIF mode that we have
published to NPM. This mode basically has a panel that shows the clock :)

We can add this mode to the Viewer by running the following command:

```bash
yarn run cli add-mode @ohif-test/mode-clock
```

After installation, the Viewer has a new mode!





Note: If the mode has an extension peerDependency (in this case @ohif-test/extension-clock),
`cli` will automatically add the extension to the Viewer too.

The result




### add-extension

This command will add an OHIF extension to the Viewer. It will look for the
extension in the NPM registry and install it.

```bash
yarn run cli add-extension <packageName> [version]
```


### remove-mode

This command will remove the mode from the Viewer and also remove the extension
dependencies that the mode relies on from the Viewer.

```bash
yarn run cli remove-mode <packageName>
```


### remove-extension

Similar to the `remove-mode` command, this command will remove the extension
from the Viewer.

```bash
yarn run cli remove-extension <packageName>
```

### list

`list` command will list all the installed extensions and modes in
the Viewer. It uses the `PluginConfig.json` file to list the installed
extensions and modes.

```bash
yarn run cli list
```

an output would look like this:

<div style={{maxWidth:"500px"}}>



</div>

### search

Using `search` command, you can search for OHIF extensions and modes
in the NPM registry. This tool can accept a `--verbose` flag to show more
information about the results.

```bash
yarn run cli search [--verbose]
```

<div style={{maxWidth:"600px"}}>



</div>

with the verbose flag `ohif-cli search --verbose` you will achieve the following
output:

<div style={{maxWidth:"600px"}}>



</div>


## PluginConfig.json

To make all the above commands work, we have created a new file called `PluginConfig.json` which contains the
information needed to run the commands. You **don't need to (and should not)**
edit/update/modify this file as it is automatically generated by the CLI. You
can take a look at what this file contains by going to
`platform/app/PluginConfig.json` in your project's root directory. In short,
this file tracks and stores all the extensions/modes and the their version that
are currently being used by the viewer.

## Private NPM Repos

For the `yarn cli` to view private NPM repos, create a read-only token with the
following steps and export it as an environmental variable. You may also export
an existing npm token.
```
npm login
npm token create --read-only
export NPM_TOKEN=<your readonly token>
```

## External dependencies
The ohif-cli will add the path to the external dependencies to the webpack config,
so that you can install them in your project and use them in your custom
extensions and modes. To achieve this ohif-cli will update the webpack.pwa.js
file in the platform/app directory.

## Video tutorials
See the [Video Tutorials](./video-tutorials.md) for videos of some the above
commands in action.

---

### Platform Docs Docs Development Our Process (`platform/docs/docs/development/our-process.md`)

---
sidebar_position: 6
sidebar_label: Issue & PR Triage Process
title: OHIF Development Process
summary: Detailed explanation of OHIF's issue triage, backlog management, contribution evaluation, and release processes, including categorization of issues, pull request workflow, quality assurance procedures, and continuous integration practices.
---

# Our Process

Our process is a living, breathing thing. We strive to have regular
[retrospectives][retrospective] that help us shape and adapt our process to our
team's current needs. This document attempts to capture the broad strokes of
that process in an effort to:

- Strengthen community member involvement and understanding
- Welcome feedback and helpful suggestions

## Issue Triage

[GitHub issues][gh-issues] are the best way to provide feedback, ask questions,
and suggest changes to the OHIF Viewer's core team. Community issues generally
fall into one of three categories, and are marked with a `triage` label when
created.

| Issue Template Name    | Description                                                                              |
| ---------------------- | ---------------------------------------------------------------------------------------- |
| Community: Report 🐛   | Describe a new issue; Provide steps to reproduce; Expected versus actual result?         |
| Community: Request ✋  | Describe a proposed new feature. Why should it be implemented? What is the impact/value? |
| Community: Question ❓ | Seek clarification or assistance relevant to the repository.                             |

_table 1. issue template names and descriptions_

Issues that require `triage` are akin to support tickets. As this is often our
first contact with would-be adopters and contributors, it's important that we
strive for timely responses and satisfactory resolutions. We attempt to
accomplish this by:

1. Responding to issue requiring `triage` at least once a week
2. Create new "official issues" from "community issues"
3. Provide clear guidance and next steps (when applicable)
4. Regularly clean up old (stale) issues

> 🖋 Less obviously, patterns in the issues being reported can highlight areas
> that need improvement. For example, users often have difficulty navigating
> CORS issues when deploying the OHIF Viewer -- how do we best reduce our ticket
> volume for this issue?

### Backlogged Issues

Community issues serve as vehicles of discussion that lead us to "backlogged
issues". Backlogged issues are the distilled and actionable information
extracted from community issues. They contain the scope and requirements
necessary for hand-off to a core-team (or community) contributor ^\_^

| Category | Description                                                                              | Labels                                                                                                                               |
| -------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Bugs     | An issue with steps that produce a bug (an unexpected result).                           | [Bug: Verified 🐛][label-bug]                                                                                                        |
| Stories  | A feature/enhancement with a clear benefit, boundaries, and requirements.                | [Story 🙌][label-story]                                                                                                              |
| Tasks    | Changes that improve [UX], [DX], or test coverage; but don't impact application behavior | [Task: CI/Tooling 🤖][label-tooling], [Task: Docs 📖][label-docs], [Task: Refactor 🛠][label-refactor], [Task: Tests 🔬][label-tests] |

_table 2. backlogged issue types ([full list of labels][gh-labels])_

## Issue Curation (["backlog grooming"][groom-backlog])

If a [GitHub issue][gh-issues] has a `bug`, `story`, or `task` label; it's on
our backlog. If an issue is on our backlog, it means we are, at the very least,
committed to reviewing any community drafted Pull Requests to complete the
issue. If you're interested in seeing an issue completed but don't know where to
start, please don't hesitate to leave a comment!

While we don't yet have a long-term or quarterly road map, we do regularly add
items to our ["Active Development" GitHub Project Board][gh-board]. Items on
this project board are either in active development by Core Team members, or
queued up for development as in-progress items are completed.

> 🖋 Want to contribute but not sure where to start? Check out [Up for
> grabs][label-grabs] issues and our [Contributing
> documentation][contributing-docs]

## Contributions (Pull Requests)

Incoming Pull Requests (PRs) are triaged using the following labels. Code review
is performed on all PRs where the bug fix or added functionality is deemed
appropriate:

| Labels                                         | Description                                                                                                 |
| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| **Classification**                             |                                                                                                             |
| [PR: Bug Fix][label-bug]                       | Filed to address a Bug.                                                                                     |
| [PR: Draft][draft]                             | Filed to gather early feedback from the core team, but which is not intended for merging in the short term. |
| **Review Workflow**                            |                                                                                                             |
| [PR: Awaiting Response 💬][awaiting-response]  | The core team is waiting for additional information from the author.                                        |
| [PR: Awaiting Review 👀][awaiting-review]      | The core team has not yet performed a code review.                                                          |
| [PR: Awaiting Revisions 🖊][awaiting-revisions] | Following code review, this label is applied until the author has made sufficient changes.                  |
| **QA**                                         |                                                                                                             |
| [PR: Awaiting User Cases 💃][awaiting-stories] | The PR code changes need common language descriptions of impact to end users before the review can start    |
| [PR: No UX Impact 🙃][no-ux-impact]            | The PR code changes do not impact the user's experience                                                     |

We rely on GitHub Checks and integrations with third party services to evaluate
changes in code quality and test coverage. Tests must pass and User cases must
be present (when applicable) before a PR can be merged to master, and code
quality and test coverage must not be changed by a significant margin. For some
repositories, visual screenshot-based tests are also included, and video
recordings of end-to-end tests are stored for later review.

[You can read more about our continuous integration efforts here](/development/continuous-integration.md)

## Releases

Releases are made automatically based on the type of commits which have been
merged (major.minor.patch). Releases are automatically pushed to NPM. Release
notes are automatically generated. Users can subscribe to GitHub and NPM
releases.

We host development, staging, and production environments for the Progressive
Web Application version of the OHIF Viewer. [Development][ohif-dev] always
reflects the latest changes on our master branch. [Staging][ohif-stage] is used
to regression test a release before a bi-weekly deploy to our [Production
environment][ohif-prod].

Important announcements are made on GitHub, tagged as Announcement, and pinned
so that they remain at the top of the Issue page.

The Core team occasionally performs full manual testing to begin the process of
releasing a Stable version. Once testing is complete, the known issues are
addressed and a Stable version is released.




[groom-backlog]: https://www.agilealliance.org/glossary/backlog-grooming
[retrospective]: https://www.atlassian.com/team-playbook/plays/retrospective
[gh-issues]: https://github.com/OHIF/Viewers/issues/new/choose
[gh-labels]: https://github.com/OHIF/Viewers/labels

[label-story]: https://github.com/OHIF/Viewers/labels/Story%20%3Araised_hands%3A
[label-tooling]: https://github.com/OHIF/Viewers/labels/Task%3A%20CI%2FTooling%20%3Arobot%3A
[label-docs]: https://github.com/OHIF/Viewers/labels/Task%3A%20Docs%20%3Abook%3A
[label-refactor]: https://github.com/OHIF/Viewers/labels/Task%3A%20Refactor%20%3Ahammer_and_wrench%3A
[label-tests]: https://github.com/OHIF/Viewers/labels/Task%3A%20Tests%20%3Amicroscope%3A
[label-bug]: https://github.com/OHIF/Viewers/labels/Bug%3A%20Verified%20%3Abug%3A

[draft]: https://github.com/OHIF/Viewers/labels/PR%3A%20Draft
[awaiting-response]: https://github.com/OHIF/Viewers/labels/PR%3A%20Awaiting%20Response%20%3Aspeech_balloon%3A
[awaiting-review]: https://github.com/OHIF/Viewers/labels/PR%3A%20Awaiting%20Review%20%3Aeyes%3A
[awaiting-stories]: https://github.com/OHIF/Viewers/labels/PR%3A%20Awaiting%20UX%20Stories%20%3Adancer%3A
[awaiting-revisions]: https://github.com/OHIF/Viewers/labels/PR%3A%20Awaiting%20Revisions%20%3Apen%3A
[no-ux-impact]: https://github.com/OHIF/Viewers/labels/PR%3A%20No%20UX%20Impact%20%3Aupside_down_face%3A

[ohif-dev]: https://viewer-dev.ohif.org
[ohif-stage]: https://viewer-stage.ohif.org
[ohif-prod]: https://viewer.ohif.org
[gh-board]: https://github.com/OHIF/Viewers/projects/4
[label-grabs]: https://github.com/OHIF/Viewers/issues?q=is%3Aissue+is%3Aopen+label%3A%22Up+For+Grabs+%3Araising_hand_woman%3A%22
[contributing-docs]: ./contributing.md

---

### Platform Docs Docs Development Playwright Testing (`platform/docs/docs/development/playwright-testing.md`)

---
sidebar_position: 11
sidebar_label: Playwright Testing
title: End-to-End Testing with Playwright
summary: How to run, write, and submit Playwright end-to-end tests for the OHIF Viewer, covering setup, serving the viewer, fixtures, page objects, normalized viewport coordinates, render waits, assertions, screenshot baseline rules, naming, and PR submission.
---

This guide covers running, writing, and submitting Playwright end-to-end
tests. The idea behind it is to open the testing effort to the
whole community. Every contributed test broadens coverage and raises the
overall quality of the OHIF Viewer. Following these conventions keeps the
suite fast, stable, and reviewable, and makes it much more likely your PR
merges quickly. That is how we get to the larger goal: a viewer whose quality
we can guarantee.

The suite lives in the `tests/` directory at the repository root:

```text
playwright.config.ts     → Chromium-only, port 3335, `data-cy` as the test id attribute
tests/
├── *.spec.ts            → One spec per feature/behavior
├── pages/               → Page objects (ViewportPageObject, MainToolbarPageObject, …)
├── utils/               → Shared utilities (visitStudy, checkForViewportScreenshot, …)
│   └── fixture.ts       → Extends the Playwright test runner and injects page objects
└── screenshots/         → Visual regression baselines
```

## Getting started

You might need to run `pnpm exec playwright install` for the first time if you have not.

```bash
# one-time setup
pnpm install
pnpm run test:data                     # pull the DICOM test data submodule
pnpm exec playwright install chromium  # install the browser

# run the whole suite (starts the viewer on port 3335 automatically)
pnpm run test:e2e:ci

# iterate on a single spec
TEST_ENV=true pnpm exec playwright test tests/YourNew.spec.ts

# other useful modes
pnpm run test:e2e:ui                              # Playwright UI mode
pnpm run test:e2e:headed                          # headed browser
pnpm exec playwright show-report tests/playwright-report
```

To pass Playwright flags such as `--update-snapshots`, `--reporter`, or `-g`,
call `TEST_ENV=true pnpm exec playwright test <flags>` directly. Appending
them to a script (`pnpm run test:e2e -- <flags>`) forwards a literal `--`, and
Playwright then treats the flags as test-file filters instead of options.

### Serving the viewer yourself

By default each run builds and serves the viewer on port 3335 before the tests
start, which is slow when you iterate. Outside CI, Playwright reuses a server
that is already listening on that port, so you can start one yourself and
keep it running between runs. It must use the e2e app config, port 3335, and
`TEST_ENV=true` (the viewer reads it at build time, so setting it only on the
test command has no effect on a server you started yourself):

```bash
TEST_ENV=true APP_CONFIG=config/e2e.js OHIF_PORT=3335 OHIF_OPEN=false pnpm start
```

A viewer on the default port 3000 is not picked up; Playwright would start
its own on 3335.

## Start from a seed spec

This is the single most important habit. The suite follows consistent idioms
that are easier to mimic than to reinvent. Before writing a new test, find an
existing spec that covers the same area (measurements, segmentation, MPR/3D,
hydration, panels, …), read it end to end, and adapt it. When a spec or this
guide disagrees with the current source under `tests/pages/` or
`tests/utils/`, the source wins.

## The rules at a glance

1. Import `test`, `expect`, and utilities from `./utils`, never from
   `@playwright/test`.
2. Destructure fixture-injected page objects from the test arguments; never
   `new` them.
3. Reach every application control through a page object, with no raw
   `page.getByTestId(...)` or `getByRole(...)` calls in specs.
4. Prefer normalized coordinates (0 to 1) for viewport clicks and drags, so
   the test doesn't depend on viewport size.
5. Load studies with `visitStudy` using a real StudyInstanceUID and the
   correct mode, and handle hydration and tracking prompts.
6. Use web-first, auto-retrying assertions with exact expected values; never
   grab a value and then assert it.
7. After an action that re-renders the viewport, await the render signal
   (`waitForViewportRenderCycle`) instead of sleeping.
8. Assert the actual effect (the image zoomed, the segment is gone), not a
   proxy attribute like `data-active` or a bare count.
9. Screenshots only for canvas-only output: viewport- or grid-scoped,
   text-free baselines, named via `screenShotPaths`.
10. `await` every locator action and every assertion.

The sections below explain each rule briefly.

## Test anatomy

Tests are not vanilla Playwright. `tests/utils/fixture.ts` extends the test
runner and injects page objects bound to the right `page`:

```ts
// ✅ Correct: fixtures and utilities come from the barrel
import { test, expect, visitStudy, checkForViewportScreenshot, screenShotPaths } from './utils';

// ❌ Wrong: compiles, but page-object fixtures are never injected
import { test, expect } from '@playwright/test';

test('renames a segment', async ({
  viewportPageObject,
  mainToolbarPageObject,
  leftPanelPageObject,
  rightPanelPageObject,
  DOMOverlayPageObject, // note the capital D; fixture keys are exact
}) => {
  // ...
});
```

## Loading a study

Every test starts with `visitStudy` in a `beforeEach`. The UID must exist on
the e2e data server, so do not invent UIDs:

```ts
test.beforeEach(async ({ page }) => {
  const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
  const mode = 'viewer';
  await visitStudy(page, studyInstanceUID, mode, 2000); // 2s settle delay is the convention
});
```

Commonly used studies:

| StudyInstanceUID | Mode | Used for |
| --- | --- | --- |
| `1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5` | `viewer` | Measurements, annotations, context menu |
| `1.3.6.1.4.1.14519.5.2.1.1706.8374.643249677828306008300337414785` | `viewer` | 3D, MPR, crosshairs |
| `1.3.6.1.4.1.14519.5.2.1.256467663913010332776401703474716742458` | `viewer` / `segmentation` | Labelmap SEG |
| `1.2.840.113619.2.290.3.3767434740.226.1600859119.501` | `viewer` / `segmentation` / `tmtv` | RTSTRUCT/contour, TMTV (use a `10000` delay in `tmtv`) |
| `1.3.6.1.4.1.14519.5.2.1.7695.4007.324475281161490036195179843543` | `viewer` | SR hydration |

Test in the mode that provides the feature. Segmentation tools, for example,
are not available in `viewer` mode.

Some workflows show prompts that must be handled before anything else works:
loading SEG/RTSTRUCT/SR data asks whether to hydrate, and the first
measurement asks whether to start tracking. Answer them through
`DOMOverlayPageObject` (see an existing hydration spec for the exact
sequence).

## Interacting with the viewport

The viewport is a WebGL canvas, so you cannot select rendered pixels with
CSS. Prefer normalized coordinates (0 to 1, origin top-left) so tests are
independent of viewport size. Reach for absolute pixels only when the target
is genuinely pixel-anchored, and say why in a comment:

```ts
const activeViewport = await viewportPageObject.active;

await activeViewport.normalizedClickAt([{ x: 0.5, y: 0.5 }]);
await activeViewport.normalizedDragAt({ start: { x: 0.3, y: 0.3 }, end: { x: 0.7, y: 0.7 } });
```

## Wait for renders, don't sleep

`page.waitForTimeout(...)` after a viewport-changing action is a flake
source. Too short and the test fails; too long and the suite crawls. The
viewports report when they are done. Wait on that signal, and start the
watcher before the action so you don't miss the cycle:

```ts
// ❌ Sleep-and-pray
await segmentRow.delete();
await page.waitForTimeout(5000);

// ✅ Wait on the actual render signal
const renderCycle = waitForViewportRenderCycle(page);
await segmentRow.delete();
await renderCycle;
```

Capture the promise immediately before the step that triggers the render.
Captured ahead of a multi-step sequence, it resolves on an intermediate
render and the final await becomes a no-op. Use
`waitForViewportsRendered(page)` when the render is already in flight (layout
switch, series load, `sliceNavigation.toSlice(...)`). For DOM-side state
(panel rows, dialogs), rely on
auto-retrying assertions instead; they wait for you.

Every remaining `waitForTimeout`, `hover`, or non-obvious interaction in your
spec must be justified, ideally with a code comment, or removed. Expect a
reviewer to ask "why is this needed?" for each one.

## Assertions

Use Playwright's web-first assertions, which auto-retry until they pass or
time out. Never read a value into a variable and assert the variable; that
races the UI:

```ts
// ❌ Grab-then-assert: no retry, flaky
const count = await panel.rows.count();
expect(count).toBe(3);

// ✅ Web-first: retries until the UI settles
await expect(panel.rows).toHaveCount(3);
await expect(segmentRow.title).toHaveText('Segment 5');
```

- Assert exact expected values: `toHaveText`, exact `toHaveCount`,
  `toHaveAttribute`. Avoid `toBeTruthy`, `toContainText`, and `>=`-style
  loose counts.
- `expect(locator).not.toBeNull()` is always a no-op, because a locator is
  never null. Use `toBeVisible()`.
- When a value can only come through a method, use
  `await expect.poll(() => ...)`.
- Reserve capture-then-compare (e.g. saving an SVG `d` to diff before/after)
  for whole-SVG show/hide checks; anything updated incrementally should use
  the retrying `toHaveAttribute`. When you do capture, first assert the
  captured value is not null (`null === null` passes vacuously), and capture
  only after the render settles. A too-early capture snapshots a transient
  preview path that never matches the persisted one.
- Verify the outcome, not a proxy. After deleting a segment, assert the
  deleted name is gone from the list, not merely that the count dropped.
  After activating a tool, drag on the viewport and confirm the image
  responded. Asserting that the toolbar button looks active proves only that
  the button changed, not that the tool does anything to the canvas.
  Assert the side-panel state too (e.g. the clicked segment is highlighted,
  not only that the viewport navigated).
- For a measurement, assert its panel row, its SVG text, and its cached stats
  in one call with `expectAnnotationStatsText`, building the expected lines
  with `measurementTextFormatters` (see `Length.spec.ts`).
- A drawn annotation must be visible, not merely present. `toHaveCount(n)`
  plus a non-null `d` still passes when a regression hides the path, so add
  `toBeVisible()` after drawing and after navigating back.
- Cover the granular case, not only the bulk one (toggle a single segment,
  not just "toggle all"), and interact out of listed order where order
  shouldn't matter.
- Assert preconditions before relying on hardcoded indices (e.g. expect the
  initial count before addressing "row 4").
- `await` every locator action and assertion. A floating `.click()` or
  un-awaited `toHaveText` lets a broken test pass silently. Custom failure
  messages must describe the check they guard.

## Page objects

Specs must read as intent, not as a pile of selectors. If the control you need
isn't exposed by a page object, extend one (or add a new one) rather than
inlining `page.*` calls:

| What you need | Where it belongs |
| --- | --- |
| A toolbar button or tool | `MainToolbarPageObject` |
| A menu, prompt, or small dialog | `DOMOverlayPageObject` |
| A substantial dialog with its own fields | Its own page object, reached through `DOMOverlayPageObject` (see `DicomTagBrowserPageObject` for an example) |
| A side-panel control | `LeftPanelPageObject` / `RightPanelPageObject` |
| Anything inside a viewport | `ViewportPageObject` |

Conventions that come up in every review:

- Page-object methods return Locators, not extracted values, so specs can
  use web-first assertions. Absence checks go through the page object too
  (e.g. filter a titles locator and expect count 0).
- Put actions on the object that owns the element. A row click belongs on
  the row object, and it should target a safe spot (the title, not wherever a
  visibility toggle might sit).
- Scope child locators to their parent locator, not to `page`. This also
  avoids needing globally unique `data-cy` values.
- Expose one locator per control, anchored on the element that receives
  clicks and carries the interactive state.
- If a control has no `data-cy`, add one to the source component (the config
  maps `getByTestId` to `data-cy`) and call it out in your PR. Follow existing
  `data-cy` naming patterns, include the segmentation representation type
  where relevant, and spell-check the value; a typo passes CI and pollutes
  production code. Don't add new props or attributes to production components
  when an existing hook works.
- When you replace one raw `page.*` call, sweep the spec for every similar
  call and replace them all.
- Remove the `page` fixture from the test signature once nothing uses it.

## Utilities

- Logic repeated across specs belongs in `tests/utils/`. Before adding a
  utility, check whether one already covers it. Don't add wrappers that
  contribute nothing; a function whose only body is a wait shouldn't exist.
- New utilities take a single object parameter with defaults, not positional
  arguments. Some existing helpers (e.g. `visitStudy`) predate this — check
  each utility's signature before calling it.
- Import utilities through the `./utils` barrel. A few helpers are
  intentionally not re-exported; only then import from the deeper path.
- Hoist literals repeated within a spec (e.g. a click-coordinate array) into
  a file-level constant.
- Shared expectations belong in `tests/utils/assertions.ts`.
- Specs never call `page.evaluate` directly. The app exposes `services`,
  `commandsManager`, `extensionManager`, `config`, and the cornerstone
  libraries on `window` (typed as `AppTypes.Test`); read them through a
  utility such as `getSUV` or `clearAllAnnotations`. Use this for setup and
  for values the UI does not show, never as a stand-in for a render
  assertion (see Screenshots below).

  ```ts
  // tests/utils/getSUV.ts
  const getSUV = async page =>
    page.evaluate(
      ({ services }: AppTypes.Test) =>
        services.measurementService.getMeasurements()[0].displayText[2],
      await page.evaluateHandle('window')
    );
  ```

## Screenshots (visual regression)

Reach for the cheapest faithful signal, in this order:

1. If the result has a DOM or SVG signal, assert on it. Panel counts, dialog
   and overlay text, enabled state, and SVG annotation paths are all DOM; no
   screenshot needed.
2. If the result exists only as pixels on the WebGL canvas, a
   viewport-scoped screenshot is the correct tool.
3. Never substitute a `window.services` state read for a render assertion.
   It passes even when rendering is broken.

Rules for new screenshot assertions:

- Capture a viewport with `checkForViewportScreenshot({ page, viewport, screenshotPath })`
  and the grid with `checkForGridScreenshot({ page, viewportPageObject, screenshotPath })`;
  both hide viewport text before the shot (the grid helper on every pane).
  Keep text out of baselines; dates, series descriptions, and W/L values
  drift and make them fragile.
- The helpers also hide hydration and tracking prompts and the unhydrated
  `SEG`/`RTSTRUCT`/`SR` badge, so assert those through `DOMOverlayPageObject`
  instead. Close menus (e.g. the data overlay menu) before a capture and
  assert their contents through the DOM.
- Never screenshot the full app. Use `checkForScreenshot` (object form,
  with a locator) only for non-viewport locators such as panels and dialogs.
- Name baselines with `screenShotPaths.<category>.<name>` from
  `tests/utils/screenShotPaths.ts`, not hand-typed strings.
- Pair the screenshot with the DOM assertions that exist for the same outcome
  (e.g. the exact SVG path count). The count verifies topology; the pixels
  verify appearance.
- Don't add `normalizedClip` unless you're targeting a sub-region of a
  locator, and never tune `maxDiffPixelRatio` or `threshold` to make a test
  pass. If a baseline mismatches, fix the flake or regenerate the baseline
  with `--update-snapshots` and review the diff by eye before committing.
- A missing baseline is written on the spot by Playwright. Because
  `checkForScreenshot` retries, the first run then compares against the file it
  just wrote and usually **passes** — an unreviewed baseline can slip in
  silently. It is also the very first capture, so it can catch a mid-load
  frame. Always open the new PNG under `tests/screenshots/chromium/<spec>/`
  and confirm it shows what you expect before committing it.

## Naming

- Spec file names must be unambiguous. Does `ContourSegRename` rename a
  segment or a segmentation? Say which.
- Test titles are precise and non-repetitive; method and parameter names are
  self-explanatory (`newName`, not `text`). Check for an existing naming
  precedent before inventing one, add a doc comment when a method's purpose
  isn't clear from its name, and fix typos before pushing; automated
  reviewers flag every one.
- Remember there are two segmentation representations, contour and labelmap.
  Don't give a helper a generic name if it only handles one, and encode the
  representation type in signatures and `data-cy` values where it matters.
  Conversely, a helper that works for both representations shouldn't name
  one, and a feature that isn't segmentation-specific shouldn't carry
  segmentation in its name.

## Submitting your PR

- Keep the scope small: one feature or behavior per PR. Small, decoupled PRs
  get reviewed much faster (see the general
  [contributing guidelines](./contributing.md)).
- Title the PR in [Conventional Commits](https://www.conventionalcommits.org/)
  form — `<type>(<scope>): <subject>`, e.g.
  `test(contour): add segment rename interactions` — not the auto-filled branch
  name. The repo's release tooling parses these to derive the semantic version,
  so the type matters. See this
  [quick reference](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716).

## Agentic development

- The in-repo agent skill at
  [`.agents/skills/ohif-test-agent/`](https://github.com/OHIF/Viewers/tree/master/.agents/skills/ohif-test-agent)
  mirrors these
  conventions and adds per-feature seed-spec pointers
  (`references/patterns-by-feature.md`) and a failure-triage guide
  (`references/failure-triage.md`). It's useful reading for humans too, and
  an AI coding agent working in this repo follows the same rules.

---

### Platform Docs Docs Development Testing (`platform/docs/docs/development/testing.md`)

---
sidebar_position: 7
sidebar_label: Testing
title: Testing OHIF
summary: Comprehensive guide to OHIF's testing approach, covering unit tests and end-to-end tests with detailed instructions for running them, explanation of test data management, and an overview of the project's testing philosophy and best practices.
---

# Running Tests for OHIF

We introduce here various test types that is available for OHIF, and how to run
each test in order to make sure your contribution hasn't broken any existing
functionalities. Idea and philosophy of each testing category is discussed in
the second part of this page.

## Unit test

To run the unit test:

```bash
yarn run test:unit:ci
```

Note: You should have already installed all the packages with `yarn install --frozen-lockfile`.

Running unit test will generate a report at the end showing the successful and
unsuccessful tests with detailed explanations.

## End-to-end test
For running the OHIF e2e test you need to run the following steps:

- Open a new terminal, and from the root of the OHIF mono repo, run the following command:

  ```bash
  yarn test:data
  ```

  This will download the required data to run the e2e tests (it might take a while).
  The `test:data` only needs to be run once and checks the data out. Read more about
  test data [below](#test-data).

- Run the viewer with e2e config

  ```bash
  APP_CONFIG=config/e2e.js yarn start
  ```

  You should be able to see test studies in the study list

  

- Open a new terminal inside the OHIF project, and run the e2e cypress test

  ```bash
  yarn test:e2e
  ```

  You should be able to see the cypress window open

  

  Run the tests by clicking on the `Run #number integration tests` .

  A new window will open, and you will see e2e tests being executed one after
  each other.

  

  ## Test Data
  The testing data is stored in two OHIF repositories.  The first contains the
  binary DICOM data, at [viewer-testdata](https://github.com/OHIF/viewer-testdata.git)
  while the second module contains data in the DICOMweb format, installed as a submodule
  into OHIF in the `testdata` directory.  This is retrieved via the command
  ```bash
  yarn test:data
  ```
  or the equivalent command `git submodule update --init`
  When adding new data, run:
  ```
  npm install dicomp10-to-dicomweb
  mkdicomweb -d dicomweb dcm
  ```
  to update the local dicomweb submodule in viewer-testdata.  Then, commit
  that data and update the submodules used in OHIF and in the viewer-testdata
  parent modules.

  All data MUST be fully anonymized and allowed to be used for open access.
  Any attributions should be included in the DCM directory.

## Testing Philosophy

> Testing is an opinionated topic. Here is a rough overview of our testing
> philosophy. See something you want to discuss or think should be changed? Open
> a PR and let's discuss.

You're an engineer. You know how to write code, and writing tests isn't all that
different. But do you know why we write tests? Do you know when to write one, or
what kind of test to write? How do you know if a test is a _"good"_ test? This
document's goal is to give you the tools you need to make those determinations.

Okay. So why do we write tests? To increase our... **CONFIDENCE**

- If I do a large refactor, does everything still work?
- If I changed some critical piece of code, is it safe to push to production?

Gaining the confidence we need to answer these questions after every change is
costly. Good tests allow us to answer them without manual regression testing.
What and how we choose to test to increase that confidence is nuanced.

## Further Reading: Kinds of Tests

Test's buy us confidence, but not all tests are created equal. Each kind of test
has a different cost to write and maintain. An expensive test is worth it if it
gives us confidence that a payment is processed, but it may not be the best
choice for asserting an element's border color.

| Test Type   | Example                                                                  | Speed            | Cost                                                                     |
| ----------- | ------------------------------------------------------------------------ | ---------------- | ------------------------------------------------------------------------ |
| Static      | `addNums(1, '2')` called with `string`, expected `int`.                  | :rocket: Instant | :money_with_wings:                                                       |
| Unit        | `addNums(1, 2)` returns expected result `3`                              | :airplane: Fast  | :money_with_wings::money_with_wings:                                     |
| Integration | Clicking "Sign In", navigates to the dashboard (mocked network requests) | :running: Okay   | :money_with_wings::money_with_wings::money_with_wings:                   |
| End-to-end  | Clicking "Sign In", navigates to the dashboard (no mocks)                | :turtle: Slow    | :money_with_wings::money_with_wings::money_with_wings::money_with_wings: |

- :rocket: Speed: How quickly tests run
- :money_with_wings: Cost: Time to write, and to debug when broken (more points
  of failure)

### Static Code Analysis

Modern tooling gives us this "for free". It can catch invalid regular
expressions, unused variables, and guarantee we're calling methods/functions
with the expected parameter types.

Example Tooling:

- [ESLint][eslint-rules]
- [TypeScript][typescript-docs] or [Flow][flow-org]

### Unit Tests

The building blocks of our libraries and applications. For these, you'll often
be testing a single function or method. Conceptually, this equates to:

_Pure Function Test:_

- If I call `sum(2, 2)`, I expect the output to be `4`

_Side Effect Test:_

- If I call `resetViewport(viewport)`, I expect `cornerstone.reset` to be called
  with `viewport`

#### When to use

Anything that is exposed as public API should have unit tests.

#### When to avoid

You're actually testing implementation details. You're testing implementation
details if:

- Your test does something that the consumer of your code would never do.
  - IE. Using a private function
- A refactor can break your tests

### Integration Tests

We write integration tests to gain confidence that several units work together.
Generally, we want to mock as little as possible for these tests. In practice,
this means only mocking network requests.

### End-to-End Tests

These are the most expensive tests to write and maintain. Largely because, when
they fail, they have the largest number of potential points of failure. So why
do we write them? Because they also buy us the most confidence.

#### When to use

Mission critical features and functionality, or to cover a large breadth of
functionality until unit tests catch up. Unsure if we should have a test for
feature `X` or scenario `Y`? Open an issue and let's discuss.

### General

- [Assert(js) Conf 2018 Talks][assert-js-talks]
  - [Write tests. Not too many. Mostly integration.][kent-talk] - Kent C. Dodds
  - [I see your point, but…][gleb-talk] - Gleb Bahmutov
- [Static vs Unit vs Integration vs E2E Testing][kent-blog] - Kent C. Dodds
  (Blog)

### End-to-end Testing w/ Cypress

- [Getting Started](https://docs.cypress.io/guides/overview/why-cypress.html)
  - Be sure to check out `Getting Started` and `Core Concepts`
- [Best Practices](https://docs.cypress.io/guides/references/best-practices.html)
- [Example Recipes](https://docs.cypress.io/examples/examples/recipes.html)




[eslint-rules]: https://eslint.org/docs/rules/
[mini-pacs]: https://github.com/OHIF/viewer-testdata
[typescript-docs]: https://www.typescriptlang.org/docs/home.html
[flow-org]: https://flow.org/

[assert-js-talks]: https://www.youtube.com/playlist?list=PLZ66c9_z3umNSrKSb5cmpxdXZcIPNvKGw
[kent-talk]: https://www.youtube.com/watch?v=Fha2bVoC8SE
[gleb-talk]: https://www.youtube.com/watch?v=5FnalKRjpZk
[kent-blog]: https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests

[testing-trophy]: https://twitter.com/kentcdodds/status/960723172591992832?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E960723172591992832&ref_url=https%3A%2F%2Fkentcdodds.com%2Fblog%2Fwrite-tests
[aaron-square]: https://twitter.com/Carofine247/status/966727489274961920
[gleb-pyramid]: https://twitter.com/Carofine247/status/966764532046684160/photo/3
[testing-pyramid]: https://dojo.ministryoftesting.com/dojo/lessons/the-mobile-test-pyramid
[testing-dorito]: https://twitter.com/denvercoder/status/960752578198843392
[testing-dorito-img]: https://pbs.twimg.com/media/DVVHXycUMAAcN-F?format=jpg&name=4096x4096

---

### Platform Docs Docs Development Types (`platform/docs/docs/development/types.md`)

---
sidebar_position: 10
sidebar_label: Global Types
title: Global Types and Service Extensions
summary: Guide to using and extending TypeScript types in OHIF applications, focusing on the withAppTypes utility for component typing, adding custom properties, and properly integrating new services into the global namespace for type safety and code completion.
---

# Extending App Types and Services in Your Application

This documentation provides an overview and examples on how to use and extend `withAppTypes`, integrate custom properties, and add services in the global namespace of the application. This helps in enhancing the application's modularity and extensibility.

## Overview of `withAppTypes`

The `withAppTypes` function is a TypeScript utility that extends the base properties of components or modules with the application's core service and manager types. It allows for a more flexible and type-safe way to pass around core functionality and custom properties.

### Using `withAppTypes`

`withAppTypes` can be enhanced using generics to include custom properties. This is particularly useful for passing additional data or configurations specific to your component or service.

### Extending with Custom Properties

You can extend `withAppTypes` to include custom properties by defining an interface for the props you need. For example:

```typescript
interface ColorbarProps {
  viewportId: string;
  displaySets: Array<any>;
  colorbarProperties: ColorbarProperties;
}

export function Colorbar({
  viewportId,
  displaySets,
  commandsManager, // injected type
  servicesManager, // injected type
  colorbarProperties,
}: withAppTypes<ColorbarProps>): ReactElement {
  // Component logic here
}
```

In this example, `ColorbarProps` is a custom interface that extends the application types through `withAppTypes`.

## Typing the custom extensions's new services

Extensions can define additional services that integrate seamlessly into the application's global service architecture, and will be available on the ServicesManager for use across the application.

### Adding the extension's services Types

Declare your service in the global namespace and use it across your application as demonstrated below:

`extensions/my-extension/src/types/whatever.ts`

```typescript
declare global {
  namespace AppTypes {
    // only add if you need direct access to the service ex. AppTypes.MicroscopyService
    export type MicroscopyService = MicroscopyServiceType;
    // add to the global Services interface, and to withAppTypes
    export interface Services {
      microscopyService?: MicroscopyServiceType;
    }
  }
}
```

Doing the above adds the `microscopyService` to the global Services interface, which ServicesManager uses by default `public services: AppTypes.Services = {};` to type services, and is also used by withAppTypes to inject services into components.
You will also get access to the seperate services via `AppTypes.YourServiceName` in your application.


```typescript
export function CustomComponent({
  servicesManager,
}: withAppTypes<CustomComponentProps>): ReactElement {
  const { microscopyService } = servicesManager.services;
  microscopyService.someMethod(); // auto completation available

}
```

```typescript
export function CustomComponent2(
  microscopyService: AppTypes.MicroscopyService,
): ReactElement {
  microscopyService.someMethod(); // auto completation available
}
```

---

### Platform Docs Docs Development Video Tutorials (`platform/docs/docs/development/video-tutorials.md`)

---
sidebar_position: 4
sidebar_label: Video Tutorials
title: OHIF Development Video Tutorials
summary: Collection of instructional videos demonstrating key OHIF development workflows, including creating, linking, and publishing modes and extensions, with step-by-step demonstrations of the OHIF CLI and NPM publishing process.
---

# Video Tutorials

## Creating, Linking and Publishing OHIF Modes and Extensions

The [OHIF CLI](./ohif-cli.md) facilitates the creation, linkage and publication
of OHIF modes and extensions. The videos below walk through how to use the CLI for
- creating modes and extensions
- linking local modes and extensions
- publishing modes and extensions to NPM
- adding published modes and extensions to OHIF
- submitting a mode to OHIF

The videos build on top of one another whereby the mode and extension created
in each of the first two videos are published to NPM and then the published
entities are added to OHIF.

### Creating and Linking a Mode

The first video demonstrates the creation and linkage of a mode.
<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/884891676?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="Create and link a mode"></iframe>
</div>

### Creating and Linking an Extension

The second video creates and links an extension. The mode from the first
video is modified to reference the extension.
<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/884891718?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="Create and link an extension"></iframe>
</div>

### Publishing an Extension to NPM

The third video shows how the extension created in the second video can
be published to NPM.
<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/884891701?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="Publish an extension to NPM"></iframe>
</div>

### Publishing a Mode to NPM

The fourth video shows how the mode created in the first video can be
published to NPM.
<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/884893445?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="Publish a mode to NPM"></iframe>
</div>

### Adding a Mode from NPM

The fifth video adds the mode and extension published in NPM to OHIF. Note
that since the mode references the extension both are added with one CLI
command.
<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/884893388?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="Add a mode from NPM"></iframe>
</div>

### Submitting a Mode to OHIF

The sixth video demonstrates how a mode can be submitted to OHIF to have it
appear in OHIF's mode gallery.
<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/884893372?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="Submit a mode to OHIF"></iframe>
</div>

---

### Platform Docs Docs Development WebWorkers (`platform/docs/docs/development/webWorkers.md`)

---
sidebar_position: 13
sidebar_label: Web Workers
title: Web Workers Implementation Guide
summary: Step-by-step guide for implementing web workers in OHIF to handle computationally intensive tasks in background threads, including worker creation, registration, task execution, progress tracking, and best practices for code organization.
---
# Web Worker Implementation Guide

## Overview
Web Workers enable running computationally intensive tasks in background threads without blocking the UI. This guide explains how to implement them step by step.

## Basic Setup

### 1. Create Your Worker File
First, create a worker file with your background tasks:

```javascript
// myWorker.js
import { expose } from 'comlink';

const obj = {
  // Simple task
  basicCalculation({ data }) {
    // Your computation here
    return result;
  },

  // Task with progress updates
  longRunningTask({ data }, progressCallback) {
    const total = data.length;

    for (let i = 0; i < total; i++) {
      // Your processing logic

      if (progressCallback) {
        const progress = Math.round((i / total) * 100);
        progressCallback(progress);
      }
    }

    return result;
  }
};

expose(obj);
```

### 2. Register the Worker

In the main thread, can be your service, commands module, etc.

```javascript
import { getWebWorkerManager } from '@cornerstonejs/core';

const workerManager = getWebWorkerManager();

// Define worker creation function
const workerFn = () => {
  return new Worker(
    new URL('./myWorker.js', import.meta.url),
    { name: 'my-worker' }
  );
};

// Registration options
const options = {
  maxWorkerInstances: 1, // Number of concurrent workers
  autoTerminateOnIdle: {
    enabled: true,
    idleTimeThreshold: 3000, // Terminate after 3s idle
  },
};

// Register the worker
workerManager.registerWorker('my-worker', workerFn, options);
```

:::info
It is recommended to register the worker in top of the commands module. So that it
gets registered before any commands that need to use the worker.
:::

### 3. Execute Tasks

```javascript
// Basic execution
try {
  const result = await workerManager.executeTask(
    'my-worker',
    'basicCalculation',
    { data: myData }
  );
} catch (error) {
  console.error('Task failed:', error);
}

// Execution with progress callback
try {
  const result = await workerManager.executeTask(
    'my-worker',
    'longRunningTask',
    { data: myData },
    {
      callbacks: [
        (progress) => {
          console.log(`Progress: ${progress}%`);
        }
      ]
    }
  );
} catch (error) {
  console.error('Task failed:', error);
}
```

## Progress Events (Optional)

If you want to show progress in your UI as a loading spinner, you can implement a progress event system:

### 1. Publish Progress Events

```javascript
// Helper to trigger progress events
const publishProgress = (eventTarget, progress, taskId) => {
  triggerEvent(eventTarget, 'WEB_WORKER_PROGRESS', {
    progress,    // number 0-100
    type: 'YOUR_TASK_TYPE', // can be any string identifier
    id: taskId,  // unique task identifier
  });
};

// Usage in your application
async function runTaskWithProgress(data) {
  // Start progress
  publishProgress(eventTarget, 0, data.id);

  try {
    const result = await workerManager.executeTask(
      'my-worker',
      'longRunningTask',
      { data },
      {
        callbacks: [
          (progress) => {
            publishProgress(eventTarget, progress, data.id);
          }
        ]
      }
    );

    // Complete progress
    publishProgress(eventTarget, 100, data.id);

    return result;
  } catch (error) {
    console.error('Task failed:', error);
    throw error;
  }
}
```

Note: Publishing the `WEB_WORKER_PROGRESS` event on Cornerstone's `eventTarget` will automatically trigger the built-in loading spinner. This gives users visual feedback while your worker runs in the background.


## Multiple Methods in One Worker

You can define multiple related methods in a single worker file:

```javascript
// complexWorker.js
import { expose } from 'comlink';

const obj = {
  processingMethod1({ data }, progressCallback) {
    // Implementation
  },

  processingMethod2({ data }, progressCallback) {
    // Implementation
  },

  processingMethod3({ data }, progressCallback) {
    // Implementation
  },

  // Shared helper methods
  _internalHelper() {
    // Helper logic
  }
};

expose(obj);
```

---

### Platform Docs Docs Faq Add Viewport Icon (`platform/docs/docs/faq/add-viewport-icon.md`)

---
id: add-viewport-icon
title: How to add a custom icon to the viewport corners
summary: Learn how to add a custom icon or dropdown to one of the viewport corners in OHIF.
---

# How to add a custom icon to the viewport corners

## Question
How can I add a custom icon or dropdown to one of the viewport corners in OHIF?

## Answer
OHIF provides a customizable viewport action menu system that allows you to add icons, buttons, or dropdowns to any of the four corners of a viewport (topLeft, topRight, bottomLeft, bottomRight). This is done through the `customizationService` and the viewport action corners API.

Here's a complete example that shows how to add a mode switch dropdown to the top-left corner of the viewport:

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Key Concepts

1. **Location-based customization**: The viewport is divided into four corners identified by:
   - `viewportActionMenu.topLeft`
   - `viewportActionMenu.topRight`
   - `viewportActionMenu.bottomLeft`
   - `viewportActionMenu.bottomRight`

2. **Component structure**:
   - `id` - A unique identifier for your component
   - `enabled` - Boolean to control if the component should be displayed
   - `component` - A function that returns a React component to render

3. **Component positioning**: The component's position within a corner is determined by its order in the array. Components are rendered in the order they appear.

4. **Dropdown positioning**: Use the `viewportActionCornersService.getAlignAndSide()` method to get the correct alignment for your dropdown menu based on its location.

## Adding Multiple Components

If you want to add multiple components to the same corner or different corners, you can do it in a single customization:

```js
customizationService.setCustomizations({
  'viewportActionMenu.topLeft': {
    $push: [
      {
        id: 'modeSwitch',
        enabled: true,
        component: getModeSwitchMenu,
      },
    ],
  },
  'viewportActionMenu.topRight': {
    $push: [
      {
        id: 'anotherComponent',
        enabled: true,
        component: getAnotherComponent,
      },
    ],
  },
});
```

## Replacing Existing Components

If you want to replace all components in a corner instead of adding to them, use `$set` instead of `$push`:

```js
customizationService.setCustomizations({
  'viewportActionMenu.topLeft': {
    $set: [
      {
        id: 'modeSwitch',
        enabled: true,
        component: getModeSwitchMenu,
      },
      // This will be the only components in the top-left corner
    ],
  },
});
```

Remember that this customization will affect all viewports in the active mode. If you need different behavior for different viewports, you should check the `viewportId` parameter in your component's logic.

---

### Platform Docs Docs Faq General (`platform/docs/docs/faq/general.md`)

---
id: general
title: General FAQ
summary: Answers to common questions about OHIF Viewer, including how to report bugs, request features, contact for support or academic collaborations, regulatory compliance status (FDA/CE/HIPAA), and obtaining sample studies.
---



# General FAQ


## How do I report a bug?

Navigate to our [GitHub Repository][new-issue], and submit a new bug report.
Follow the steps outlined in the [Bug Report Template][bug-report-template].

## How can I request a new feature?

At the moment we are in the process of defining our roadmap and will do our best
to communicate this to the community. If your requested feature is on the
roadmap, then it will most likely be built at some point. If it is not, you are
welcome to build it yourself and [contribute it](../development/contributing.md).
If you have resources and would like to fund the development of a feature,
please [contact us](https://ohif.org/get-support).


## Who should I contact about Academic Collaborations?

[Gordon J. Harris](https://www.dfhcc.harvard.edu/insider/member-detail/member/gordon-j-harris-phd/)
at Massachusetts General Hospital is the primary contact for any academic
collaborators. We are always happy to hear about new groups interested in using
the OHIF framework, and may be able to provide development support if the
proposed collaboration has an impact on cancer research.

## Does OHIF offer support?

yes, you can contact us for more information [here](https://ohif.org/get-support)


## Does The OHIF Viewer have [510(k) Clearance][501k-clearance] from the U.S. F.D.A or [CE Marking][ce-marking] from the European Commission?

**NO.** The OHIF Viewer is **NOT** F.D.A. cleared or CE Marked. It is the users'
responsibility to ensure compliance with applicable rules and regulations. The
[License](https://github.com/OHIF/Viewers/blob/master/LICENSE) for the OHIF
Platform does not prevent your company or group from seeking F.D.A. clearance
for a product built using the platform.

If you have gone this route (or are going there), please let us know because we
would be interested to hear about your experience.

## Is there a DICOM Conformance Statement for the OHIF Viewer?

Yes, check it here [DICOM Conformance Statement](https://docs.google.com/document/d/1hbDlUApX4svX33gAUGxGfD7fXXZNaBsX0hSePbc-hNA/edit?usp=sharing)

## Is The OHIF Viewer [HIPAA][hipaa-def] Compliant?

**NO.** The OHIF Viewer **DOES NOT** fulfill all of the criteria to become HIPAA
Compliant. It is the users' responsibility to ensure compliance with applicable
rules and regulations.

## Could you provide me with a particular study from the OHIF Viewer Demo?

You can check out the studies that we have put in this [Dropbox link](https://www.dropbox.com/scl/fo/66xidsx13pn0zf3b9cbfq/ADaCgn7aT29WMlnTdT_WRXM?rlkey=rratvx6g4kfxnswjdbupewjye&dl=0)






[general]: general
[technical]: technical
[report-bug]: how-do-i-report-a-bug
[new-feature]: how-can-i-request-a-new-feature
[commercial-support]: does-ohif-offer-commercial-support
[academic]: who-should-i-contact-about-academic-collaborations
[fda-clearance]: does-the-ohif-viewer-have-510k-clearance-from-the-us-fda-or-ce-marking-from-the-european-commission
[hipaa]: is-the-ohif-viewer-hipaa-compliant
[501k-clearance]: https://www.fda.gov/MedicalDevices/DeviceRegulationandGuidance/HowtoMarketYourDevice/PremarketSubmissions/PremarketNotification510k/
[ce-marking]: https://ec.europa.eu/growth/single-market/ce-marking_en
[hipaa-def]: https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act
[new-issue]: https://github.com/OHIF/Viewers/issues/new/choose
[bug-report-template]: https://github.com/OHIF/Viewers/issues/new?assignees=&labels=Bug+Report+%3Abug%3A&template=---bug-report.md&title=

---

### Platform Docs Docs Faq Technical (`platform/docs/docs/faq/technical.md`)

---
id: technical
title: Technical FAQ
summary: Technical explanations and solutions for OHIF Viewer implementation challenges, including required metadata fields, handling large volumes for MPR/rendering, dynamically loading measurements, customizing series sorting, and addressing common rendering issues.
---

# Technical FAQ

* [How to add a custom icon to the viewport corners](./add-viewport-icon.md)


## Viewer opens but does not show any thumbnails

Thumbnails may not appear in your DICOMWeb application for various reasons. This guide focuses on one primary scenario, which is you are using
the `supportsWildcard: true` in your configuration file while your sever does not support it.
One

For instance for the following filtering in the worklist tab we send this request



`https://d33do7qe4w26qo.cloudfront.net/dicomweb/studies?PatientName=*Head*&limit=101&offset=0&fuzzymatching=false&includefield=00081030%2C00080060`

Which our server can respond properly. If your server does not support this type of filtering, you can disable it by setting `supportsWildcard: false` in your configuration file,
or edit your server code to support it for instance something like

```js
Pseudocode:
For each filter in filters:
    if filter.value contains "*":
        Convert "*" to SQL LIKE wildcard ("%")
        Add "metadataField LIKE ?" to query
    else:
        Add "metadataField = ?" to query
```



## What are the list of required metadata for the OHIF Viewer to work?


### Mandatory

**All Modalities**

- `StudyInstanceUID`, `SeriesInstanceUID`, `SOPInstanceUID`: Unique identifiers for the study, series, and object.
- `PhotometricInterpretation`: Describes the color space of the image.
- `Rows`, `Columns`: Image dimensions.
- `PixelRepresentation`: Indicates how pixel data should be interpreted.
- `Modality`: Type of modality (e.g., CT, MR, etc.).
- `PixelSpacing`: Spacing between pixels.
- `BitsAllocated`: Number of bits allocated for each pixel sample.
- `SOPClassUID`: Specifies the DICOM service class of the object (though you might be able to render without it for most regular images datasets, but it is pretty normal to have it)

**Rendering**

You need to have the following tags for the viewer to render the image properly, otherwise you should
use the windowing tools to adjust the image to your liking:

- `RescaleIntercept`, `RescaleSlope`: Values used for rescaling pixel values for visualization.
- `WindowCenter`, `WindowWidth`: Windowing parameters for display.

**Some Datasets**

- `InstanceNumber`: Useful for sorting instances (without it the instances might be out of order)

**For MPR (Multi-Planar Reformatting) rendering and tools**

- `ImagePositionPatient`, `ImageOrientationPatient`: Position and orientation of the image in the patient.

**SEG (Segmentation)**

- `FrameOfReferenceUID` for handling segmentation layers.
- sequences
  - `ReferencedSeriesSequence`
  - `SharedFunctionalGroupsSequence`
  - `PerFrameFunctionalGroupsSequence`

**RTSTRUCT (Radiotherapy Structure)**

- `FrameOfReferenceUID` for handling segmentation layers.
- sequences
  - `ROIContourSequence`
  - `StructureSetROISequence`
  - `ReferencedFrameOfReferenceSequence`

**US (Ultrasound)**

- `NumberOfFrames`: Number of frames in a multi-frame image.
- `SequenceOfUltrasoundRegions`: For measurements.
- `FrameTime`: Time between frames if specified.

**SR (Structured Reporting)**

- Various sequences for encoding the report content and template.
  - `ConceptNameCodeSequence`
  - `ContentSequence`
  - `ContentTemplateSequence`
  - `CurrentRequestedProcedureEvidenceSequence`
  - `ContentTemplateSequence`
  - `CodingSchemeIdentificationSequence`

**PT with SUV Correction (Positron Tomography Standardized Uptake Value)**

- Sequences and tags related to radiopharmaceuticals, units, corrections, and timing.
  - `RadiopharmaceuticalInformationSequence`
  - `SeriesDate`
  - `SeriesTime`
  - `CorrectedImage`
  - `Units`
  - `DecayCorrection`
  - `AcquisitionDate`
  - `AcquisitionTime`
  - `PatientWeight`

**PDF**

- `EncapsulatedDocument`: Contains the PDF document.

**Video**

- `NumberOfFrames`: Video frame count .


### Optional
There are various other optional tags that will add to the viewer experience, but are not required for basic functionality. These include:
Patient Information, Study Information, Series Information, Instance Information, and Frame Information.


## How do I handle large volumes for MPR and Volume Rendering

Currently there are two ways to handle large volumes for MPR and Volume Rendering if that does not
fit in the memory of the client machine.

### `useNorm16Texture`

WebGL officially supports only 8-bit and 32-bit data types. For most images, 8 bits are not enough, and 32 bits are too much. However, we have to use the 32-bit data type for volume rendering and MPR, which results in suboptimal memory consumption for the application.

Through [EXT_texture_norm16](https://registry.khronos.org/webgl/extensions/EXT_texture_norm16/) , WebGL can support 16 bit data type which is ideal
for most images. You can look into the [webgl report](https://webglreport.com/?v=2) to check if you have that extension enabled.




This is a flag that you can set in your [configuration file](../configuration/configurationFiles.md) to force usage of 16 bit data type for the volume rendering and MPR. This will reduce the memory usage by half.


For instance for a large pt/ct study



Before (without the flag) the app shows 399 MB of memory usage




After (with flag, running locally) the app shows 249 MB of memory usage




:::note
Using the 16 bit texture (if supported) will not have any effect in the rendering what so ever, and pixelData
would be exactly shown as it is. For datasets that cannot be represented with 16 bit data type, the flag will be ignored
and the 32 bit data type will be used.


Read more about these discussions in our PRs
- https://github.com/Kitware/vtk-js/pull/2058
:::


:::warning
Although the support for 16 bit data type is available in WebGL, in some settings (e.g., Intel-based Macos) there seems
to be still some issues with it. You can read and track bugs below.

- https://bugs.chromium.org/p/chromium/issues/detail?id=1246379
- https://bugs.chromium.org/p/chromium/issues/detail?id=1408247
:::

### `preferSizeOverAccuracy`

This is another flag that you can set in your [configuration file](../configuration/configurationFiles.md) to force the usage of the `half_float` data type for volume rendering and MPR. The main reason to choose this option over `useNorm16Texture` is its broader support across hardware and browsers. However, it is less accurate than the 16-bit data type and may lead to some rendering artifacts.

```js
Integers between 0 and 2048 can be exactly represented (and also between −2048 and 0)
Integers between 2048 and 4096 round to a multiple of 2 (even number)
Integers between 4096 and 8192 round to a multiple of 4
Integers between 8192 and 16384 round to a multiple of 8
Integers between 16384 and 32768 round to a multiple of 16
Integers between 32768 and 65519 round to a multiple of 32
```

As you see in the ranges above 2048 there will be inaccuracies in the rendering.

Memory snapshot after enabling `preferSizeOverAccuracy` for the same study as above




## How to dynamically load a measurement

You can dynamically load a measurement by using a combination of `MeasurementService` and `CornerstoneTools` Annotation API. Here, we will demonstrate this with an example of loading a `Rectangle` measurement.



So if we look at the terminal and get the measurement service we can see there is one measurement



However, this is the `mapped` cornerstone measurement inside OHIF, and it has additional information such as `geReport` and `source`, which are internal details of OHIF Viewers that you don't need to worry about.

we can call the `cornerstoneTools` api to grab the raw annotation data with the `uid`

`cornerstoneTools.annotation.state.getAnnotation("ea45a45c-0731-47d4-9438-d2a53ffea4ff")`






:::note
Note: There is a `pointsInShape` attribute inside the data that stores the points within the annotation for some tools like `Rectangle` and `EllipticalRoi`. However, you can remove that attribute as well.
:::

For the sake of this example, I have extracted those keys and uploaded them to our server for fetching.

`
https://ohif-assets.s3.us-east-2.amazonaws.com/ohif-faq/rectangle-roi.json
`

Now, let's discuss how to load this measurement dynamically and programmatically.

There are numerous places in OHIF where you can add annotations, but we always recommend having your own extensions and modes to maintain full control over your custom API.

For this example, I will add the logic in the `longitudinal` mode. However, as mentioned, you can create your own extension and mode, and either use `onModeEnter` or other lifecycle hooks to add annotations. Learn more about lifecycle hooks [here](../platform/extensions/lifecycle.md).


Of course, you need to load the appropriate measurement for each study. However, for simplicity's sake, I will hardcode the URL in this example.

```js
import * as cs3dTools from '@cornerstonejs/tools';

onModeEnter: function ({ servicesManager, extensionManager, commandsManager }: withAppTypes) {
  // rest of logic

  const annotationResponse = await fetch(
    'https://ohif-assets.s3.us-east-2.amazonaws.com/ohif-faq/rectangle-roi.json'
  );

  const annotationData = await annotationResponse.json();

  cs3dTools.annotation.state.addAnnotation(annotationData);
},
```

As you can see, we use the CornerstoneTools API to add the annotation. Since OHIF has mappers set up for CornerstoneTools (`extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.ts`), it will automatically map the annotation to the OHIF measurement service.

If you refresh the viewer, you'll see the measurement loaded on the image.



But if you notice it does not appear on the right panel, the reason is that the right panel is the tracking measurement panel. You can switch to a non-tracking measurement by changing

`rightPanels: [dicomSeg.panel, tracked.measurements],`

to

`rightPanels: [dicomSeg.panel, '@ohif/extension-default.panelModule.measure'],`

which then it will look like




:::info
There is also dedicated example for this in the [cornerstone3D examples](https://www.cornerstonejs.org/live-examples/dynamicallyaddannotations).
:::


## How do I sort the series in the study panel by a specific value

You need to enable the experimental StudyBrowserSort component by setting the `experimentalStudyBrowserSort` to true in your config file. This will add a dropdown in the study panel to sort the series by a specific value. This component is experimental
since we are re-deigning the study panel and it might change in the future, but the functionality will remain the same.

```js
{
  experimentalStudyBrowserSort: true,
}
```
The component will appear in the study panel and will allow you to sort the series by a specific value. It comes with 3 default sorting functions, Series Number, Series Image Count, and Series Date.

You can sort the series in the study panel by a specific value by adding a custom sorting function in the customizationModule, you can use the existing customizationModule in `extensions/default/src/getCustomizationModule.tsx` or create your own in your extension.

The value to be used for the entry is `studyBrowser.sortFunctions` and should be under the `default` key.

### Example

```js
export default function getCustomizationModule({ servicesManager, extensionManager }) {
  return [
    {
      name: 'default',
      value: [

        {
          id: 'studyBrowser.sortFunctions',
          values: [
            {
              label: 'Series Number',
              sortFunction: (a, b) => {
                return a?.SeriesNumber - b?.SeriesNumber;
              },
            },
            // Add more sort functions as needed
          ],
        },
      ],
    },
  ];
}
```

### Explanation
This function will be retrieved by the StudyBrowserSort component and will be used to sort all displaySets, it will reflect in all parts of the app since it works at the displaySetService level, which means the thumbnails in the study panel will also be sorted by the desired value.
You can define multiple functions and pick which sort to use via the dropdown in the StudyBrowserSort component that appears in the study panel.


## How can i change the sorting of the thumbnail / study panel / study browser
We are currently redesigning the study panel and the study browser. During this process, you can enable our undesigned component via the `experimentalStudyBrowserSort` flag. This will look like:



You can also add your own sorting functions by utilizing the `customizationService` and adding the `studyBrowser.sortFunctions` key, as shown below:

```
customizationService.addModeCustomizations([
  {
    id: 'studyBrowser.sortFunctions',
    values: [{
      label: 'Series Images',
      sortFunction: (a, b) => {
        return a?.numImageFrames - b?.numImageFrames;
      },
    }],
  },
]);
```

:::note
Notice the arrays and objects, the values are arrays
:::


## How do I change the cine auto mount behavior

You can change the cine auto mount behavior by adding the `autoCineModalities` mode customization, the value is an array of modalities that should be mounted with cine.

By default the viewer will mount with cine enabled for `OT` and `US` modalities.

```js
customizationService.addModeCustomizations([
  {
    id: 'autoCineModalities',
    modalities: ['OT', 'US'],
  },
]);
```

---

### Platform Docs Docs Migration Guide From 3p7 To 3p8 (`platform/docs/docs/migration-guide/from-3p7-to-3p8.md`)

---
sidebar_position: 2
sidebar_label: 3.7 -> 3.8
title: Migration Guide from 3.7 to 3.8
summary: Migration guide for upgrading from OHIF 3.7 to 3.8, covering changes to toolbar button definitions, active tool handling, button evaluators, tool listeners, leftPanel/rightPanel naming, URL parameters, UI components, and refactoring of enums.
---

# Migration Guide

There are two main things that need to be taken care of.


## New Toolbar Button definitions

### Update Active Tool Handling
The concept of `activeTool` and its associated getter and setter has been removed. The active tool should now be derived from the toolGroup and the viewport.


**Action Needed**

Remove any code that sets the default tool using `toolbarService.setDefaultTool()` and activates the tool using
`toolbarService.recordInteraction()`. For example, the following code should be removed:

```javascript
let unsubscribe;
toolbarService.setDefaultTool({
  groupId: "WindowLevel",
  itemId: "WindowLevel",
  interactionType: "tool",
  commands: [
    {
      commandName: "setToolActive",
      commandOptions: {
        toolName: "WindowLevel",
      },
      context: "CORNERSTONE",
    },
  ],
});

const activateTool = () => {
  toolbarService.recordInteraction(toolbarService.getDefaultTool());

  unsubscribe();
};

({ unsubscribe } = toolGroupService.subscribe(
  toolGroupService.EVENTS.VIEWPORT_ADDED,
  activateTool
));
```



Instead, focus on defining the buttons and their placement in the toolbar using `toolbarService.addButtons()` and `toolbarService.createButtonSection()`. For example:

```javascript
toolbarService.addButtons([...toolbarButtons, ...moreTools]);
toolbarService.createButtonSection("primary", [
  "MeasurementTools",
  "Zoom",
  "WindowLevel",
  "Pan",
  "Capture",
  "Layout",
  "MPR",
  "Crosshairs",
  "MoreTools",
]);
```


### Update Button Definitions
The concept of button types (toggle, action, tool) has been removed. Buttons are now defined using a simplified object-based definition.

**Action Needed**

Update your button definitions to use the new object-based format and remove the `type` property. Use the `uiType` property for the top-level UI type definition. For example:

```javascript
// Old Implementation
{
  id: 'Capture',
  type: 'ohif.action',
  props: {
    icon: 'tool-capture',
    label: 'Capture',
    type: 'action',
    commands: [
      {
        commandName: 'showDownloadViewportModal',
        commandOptions: {},
        context: 'CORNERSTONE',
      },
    ],
  },
},
```

is now

```javascript
// New Implementation
{
  id: 'Capture',
  uiType: 'ohif.radioGroup',
  props: {
    icon: 'tool-capture',
    label: 'Capture',
    commands: [
      {
        commandName: 'showDownloadViewportModal',
        context: 'CORNERSTONE',
      },
    ],
    evaluate: 'evaluate.action',
  },
},
```

### Add Evaluators to Button Definitions
Introduce the ﻿evaluate property in your button definitions to determine the state of the button based on the app context.

**Action Needed**

Add the appropriate `evaluate` property to each button definition. For example:
   - Use `evaluate.cornerstoneTool` if the button should be highlighted only when it is the active primary tool (left mouse).
	- Use `evaluate.cornerstoneTool.toggle` if the tool is a toggle tool (like reference lines or image overlay).

Refer to the `modes/longitudinal/src/toolbarButtons.ts` file for examples of using the `evaluate` property.

Additional Resources

  - For more information on the new toolbar module and its usage, refer to the [Toolbar documentation](../platform/extensions/modules/toolbar.md).
  - Consult the updated button definitions in `modes/longitudinal/src/toolbarButtons.ts` for examples of the new object-based button definition format and the usage of evaluators.

### Tool listeners

Some tools can be configured to listen to events to trigger, for example

```ts
createButton({
  id: 'ReferenceLines',
  icon: 'tool-referenceLines',
  label: 'Reference Lines',
  tooltip: 'Show Reference Lines',
  commands: 'toggleEnabledDisabledToolbar',
  listeners: {
      [ViewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED]:
          ReferenceLinesListeners,
      [ViewportGridService.EVENTS.VIEWPORTS_READY]:
          ReferenceLinesListeners,
  },
  evaluate: 'evaluate.cornerstoneTool.toggle',
  }),
```

If you have a custom viewport component, and you are overriding the ```onElementEnabled``` handler, than ensure to call ```viewportGridService.setViewportIsReady(viewportId, true)``` in your own handler so that eventually the ```VIEWPORTS_READY``` event fires as expected, if you are not modifying the handler, then an existing handler that is automatically passed down via the props will call that for you, it is passed down from ```ViewportGrid.tsx```

```ts
<ViewportComponent
   displaySets={displaySets}
   viewportLabel={viewports.size > 1 ? viewportLabel : ''}
   viewportId={viewportId}
   dataSource={dataSource}
   viewportOptions={viewportOptions}
   displaySetOptions={displaySetOptions}
   needsRerendering={displaySetsNeedsRerendering}
   isHangingProtocolLayout={isHangingProtocolLayout}
   onElementEnabled={() => {
          viewportGridService.setViewportIsReady(viewportId, true);
   }}
/>

```

## Toolbar Service

toolbarService.init is not a function.

**Action Needed**
remove the call to toolbarService.init() from your codebase.



## leftPanelDefaultClosed and rightPanelDefaultClosed

Now they are renamed to `leftPanelClosed` and `rightPanelClosed` respectively.


## StudyInstanceUID in the URL param

Previously there were two params that you could choose: seriesInstanceUID and seriesInstanceUIDs, they have been replaced with seriesInstanceUIDs so even if you would like to filter one series use ``seriesInstanceUIDs`


## UI

### Header
Header in @ohif/ui now needs servicesManager and appConfig as input.


### Panels
Left and right panel lists are no longer injected into the LayoutTemplate, and have been moved to a PanelService where you have to fetch them from.

If you're using the main layout, you're fine. However, if you have a custom layout, you'll need to update it. To get the panels, see the

`extensions/default/src/ViewerLayout/index.tsx`




## Refactoring

- TimingEnum (and I guess all enums exported from OHIF core have now moved from Types to Enums export).

---

### Platform Docs Docs Migration Guide From V2 (`platform/docs/docs/migration-guide/from-v2.md`)

---
sidebar_position: 3
sidebar_label: 2.x -> 3.5
title: Migration Guide from 2.x to 3.5
summary: Comprehensive migration guide for upgrading from OHIF 2.x to 3.5, covering architectural changes, UI improvements, extensions, modes, cornerstone3D integration, configuration changes, and build process updates.
---

# Migration Guide

On this page, we will provide a guide to migrating from OHIF v2 to v3. Please note
that this document is a work in progress and will be updated as we move forward.
This document is not meant to be used as a migration recipe but as a migration overview.


# Introduction

## Importance of Migration

- Enhanced UX: the new design and UI of OHIF v3 provides a more intuitive and user-friendly experience.
  OHIF v3 adds an improved side panels and toolbar, and a new layout system that lets you customize
  the layout of your application.
- Improved Performance: OHIF v3 leverages the new Cornerstone3D rendering and tooling libraries, which
  significantly improve performance and provide a more robust and stable foundation for your application
  for rendering and interacting with medical images. Some of the new advanced features in Cornerstone3D
  include: OffScreen Rendering and GPU Acceleration for all viewports, streaming of the volume data, 3D annotations and measurements,
  sharing tool states between viewports and more.
- Improved Customizability: With addition of Modes and Extensions, OHIF v3 provides a more modular
  and customizable framework for building medical imaging applications, this will let you
  focus on your use case and not worry about the underlying infrastructure and also have less worry
  to keep up to date with the latest changes.
- Community driven Modes: OHIF v3 provides a gallery of modes that you can use as a starting point
  for your application. These
- Future-Proofing: By migrating to v3, you align your application with the latest advancements in the OHIF framework, ensuring ongoing support, updates, and access to new features.
- Community Support: OHIF v3 benefits from an active community of developers and contributors who provide valuable support, bug fixes, and continuous improvements.

## Migration Timeframe

The duration of the migration process can vary depending on factors such as the complexity of custom changes made in v2, familiarity with v3's architecture, and the size of the codebase.
If you don't have any custom changes in v2, the migration process should be relatively straightforward. If you have custom changes, you will need to update them to work with the new architecture and new
rendering and tooling engines.


## Complexity and Pain Points

Certain scenarios can make the migration process more complex and potentially introduce pain points:

- Extensive Customizations: If your v2 implementation includes extensive custom changes and overrides, adapting those customizations to the new structure and APIs of v3 may require additional effort and careful refactoring.
- UI Customizations: Since in OHIF v3 we moved our component library to Tailwind CSS
  if you have any custom UI components, you will need to migrate them to Tailwind CSS too, and this might be a bit time consuming.
- Hardware requirements: Since Cornerstone3D uses WebGL for rendering volumeViewport (although it has
  a CPU rendering fallback), you need to make sure that your target hardware supports WebGL. You can check
  if your hardware supports WebGL [here](https://get.webgl.org/). Also regarding the GPU requirements, you can check the tier of your GPU [here](https://pmndrs.github.io/detect-gpu/), if it is tier 1 and above, you
  should be good to go.

## Summary of Changes

OHIF v3 is a major re-architecture of the OHIF v2 to make it more modular and
easier to maintain. The main differences are:

- platform/viewer (@ohif/viewer) has been renamed to platform/app (@ohif/app) (explanation below)
- Extensions are available to be used by modes on request, but are still injected as module components.
- To use the modules provided by the extensions, you need to write a [Mode](../platform/modes/index.md). Modes
are configuration objects that will be used by the viewer to load the modules. This lets users to be able to use common extensions with different configurations, and enhances the customizability of the viewer.
- App configuration structure is different, mainly the `servers` is renamed to `dataSources`.
- Apps can be customized significantly more than previously by providing configuration code int he customizationModule section.
- The viewer UI is completely re-written in Tailwind CSS for better maintainability, although it is a WIP but
  already provides a better user experience.
- cornerstone-core and cornerstone-tools are removed and OHIF v3 is using the new Cornerstone3D rendering library and tools. Moving to Cornerstone3D has enabled us to provide a more robust and stable foundation
  for 3D rendering and 3D annotations and measurements. In addition, Cornerstone3D provides APIs to load
  and stream data into a volume which has huge performance benefits.
- A new CLI tool to help you create extensions and modes (more [here](../development/ohif-cli.md))
- redux store has been removed and replaced with a simpler state management system via React Context API.

New significant additions that might be useful for you that weren't available in OHIF v2:
- [OHIF CLI](../development/ohif-cli.md)
- [New Rendering Engine and Toolings](https://www.cornerstonejs.org/)
- [Modes](../platform/modes/index.md)
- [Mode Gallery](https://ohif.org/modes)
- [Layouts](../platform/extensions/modules/layout-template.md)
- [Data Sources](../platform/extensions/modules/data-source.md)
- [Hanging Protocols](../platform/services/data/HangingProtocolService.md)
- [URL Params](../configuration/url.md)

## Platform/viewer (@ohif/viewer) -> platform/app (@ohif/app)


To ensure proper versioning of OHIF v3, we have made a decision to rename the platform/viewer to platform/app. Previously, the platform/viewer package followed software engineering versioning (currently at v4.12.51). However, going forward, we aim to align the versioning of platform/app with the product version (e.g., v3.4.0, v3.5.0, etc.).

Since the platform/viewer (@ohif/viewer) is already at v4.12.51, we opted to rename it as platform/app to enable versioning in accordance with the product versioning approach. If you were utilizing any exports from @ohif/viewer, please update them to use @ohif/app instead.


## Configuration

:::tip
There are various configurations available to customize the viewer. Each configuration is represented by a custom-tailored object that should be used with the viewer to work effectively with a specific server. Here are some examples of configuration files found in the platform/app/public/config directory. Some server-specific configurations that you should be aware are: `supportsWildcard`, `bulkDataURI`, `omitQuotationForMultipartRequest`, `staticWado` (Read more about them [here](../configuration/configurationFiles.md)).

- default.js: This is our default configuration designed for our main server, which uses a Static WADO datasource hosted on Amazon S3.
- local_orthanc.js: Use this configuration when working with our local Orthanc server.
- local_dcm4chee.js: This configuration is intended for our local dcm4chee server.
- netlify.js: This configuration is the same as default.js and is used for deployment on Netlify.
- google.js: Use this configuration to run the viewer against the Google Health API.
:::

OHIF v3 has a new configuration structure. The main difference is that the `servers` is renamed to `dataSources` and the configuration is now asynchronous. Datasources are more abstract and
far more capable than servers. Read more about dataSources [here](../platform/extensions/modules/data-source.md).

- `StudyPrefetcher` is only available in OHIF v3.9 beta and will be available in the next stable 3.9 release.
- The `servers` object has been replaced with a `dataSources` array containing objects representing different data sources.
- The cornerstoneExtensionConfig property has been removed, you should use `customizationService` instead (you can read more [here](../platform/services/customization-service/customizationService.md))
- The maxConcurrentMetadataRequests property has been removed in favor of `maxNumRequests`
- The hotkeys array has been updated with different command names and options, and some keys have been removed.
- New properties have been added, including `maxNumberOfWebWorkers`, `omitQuotationForMultipartRequest`, `showWarningMessageForCrossOrigin`, `showCPUFallbackMessage`, `showLoadingIndicator`, `strictZSpacingForVolumeViewport`.
- you should see if `supportsWildcard` is supported in your server, some servers don't support it and you need to make it false.

## Modes

As mentioned briefly above, modes are configuration objects that will be used by the viewer to load extensions.
This lets users to be able to use common extensions with different configurations. So as OHIF developers can focus on creating extensions while
you as the user can focus on creating modes having your own use case and configuration/initialization logic in mind.

Separating the configuration from the extensions also makes it so that you can
have multiple modes in a single application each focusing on certain tasks. For example, you can have a mode for segmentation which uses specific panels and tools which you don't need
for a mode that will be used for reading (read more about modes [here](../platform/modes/index.md))

:::info
Previously, the viewer was designed around registered extensions. If you had a specific use case, you had to duplicate the viewer code and incorporate your customizations through extensions. However, with the introduction of a new layer of abstraction called Modes, you no longer need to fork the viewer.

Modes provide a flexible approach where you can create your own mode and utilize the necessary extensions within that mode. This eliminates the need for duplicating the viewer codebase.

Furthermore, Modes offer the advantage of having multiple applications within a single viewer. For instance, you can have a mode dedicated to segmentation tasks and another mode focused on reading. Each mode can have its own unique configuration, initialization logic, layout, tools, and hanging protocols. This ensures a cleaner user interface in the viewer and an improved user experience overall.
:::

Upon entering a mode, the Viewer will register its declared extensions and load them. And you
can specify which modules you need from each extension in the mode configuration. For instance

```js

const ohif = {
  layout: '@ohif/extension-default.layoutTemplateModule.viewerLayout',
  sopClassHandler: '@ohif/extension-default.sopClassHandlerModule.stack',
  measurements: '@ohif/extension-default.panelModule.measure',
  thumbnailList: '@ohif/extension-default.panelModule.seriesList',
};

const cs3d = {
  viewport: '@ohif/extension-cornerstone.viewportModule.cornerstone',
};

const tmtv = {
  hangingProtocol: '@ohif/extension-tmtv.hangingProtocolModule.ptCT',
  petSUV: '@ohif/extension-tmtv.panelModule.petSUV',
  ROIThresholdPanel: '@ohif/extension-tmtv.panelModule.ROIThresholdSeg',
};

function modeFactory({ modeConfiguration }) {
  routes: [
    {
      path: 'tmtv',
      layoutTemplate: ({ location, servicesManager }) => {
        return {
          id: ohif.layout,
          props: {
            // leftPanels: [ohif.thumbnailList],
            rightPanels: [tmtv.ROIThresholdPanel, tmtv.petSUV],
            viewports: [
              {
                namespace: cs3d.viewport,
                displaySetsToDisplay: [ohif.sopClassHandler],
              },
            ],
          },
        };
      },
    },
  ],
}
```

In the example above, we are using the `tmtv` mode which is a mode for reading PET/CT scans
and as you can see we are specifying the layout, the panels and the viewports that we need
for this mode. The `tmtv` mode is using the `cs3d` extension for rendering and the `ohif` extension. As you see you can reference the modules from the extensions using the `namespace` via strings. So for instance, if you need to use the `viewportModule` from the `@ohif/extension-cornerstone` you can use `@ohif/extension-cornerstone.viewportModule.cornerstone` as the namespace.

:::tip
`ExtensionManager` will register and load the modules from the extensions and make them available to the viewer by their namespaces.
:::

Below you can see a screen shot from the demo showcasing 3 modes for the opened study.



:::tip
How do I decide certain thing should go inside a mode or extension, Here are some considerations to help you make the decision:

- **Functionality Scope**: If the functionality is specific to a particular use case or task within your viewer, it is often best suited to be included within a mode. Modes allow you to create customized configurations, layouts, panels, tools, and other components specific to a particular task or workflow. This includes which tool to be active by default, which panels to be displayed, and which layout to be used.

- **Reusability**: If the functionality can be used across multiple modes, it is better to implement it as an extension. Extensions provide a modular approach where you can encapsulate and share functionality across different modes. For instance, if you have a custom panel that you want to use in multiple modes, you can implement it as an extension and include it in
  the mode configuration.

- **Complexity**: If the functionality requires significant customizations, complex logic, or extensive modifications to the viewer's core behavior, it might be better suited as an extension.

- **New Service**: If you are writing a new service, it is preferable to implement it as an extension. Services are used to provide a common interface for interacting with external systems and data sources.
There is a new way to register new services which are extendible by other extensions.

Remember that there is no strict rule for deciding between modes and extensions. It's a matter of understanding the specific requirements of your application.

:::


## Routes

In OHIF v2 a study was loaded and mounted on `/viewer/:studyInstanceUID` route. In OHIF v3
we have reworked the route registration to enable more sophisticated routing. Now, Modes are tied to specific routes in the viewer, and multiple modes/routes can be present within a single application, making "routes" configuration the most important part of mode configuration.

- Routes with a dataSourceName: `{mode.id}/{dataSourceName}`
- Routes without a dataSourceName: `{mode.id}` which uses the default dataSourceName

This makes a mode flexible enough to be able to connect to multiple datasources
without rebuild of the app for use cases such as reading from one PACS and
writing to another.

<details>
<summary>
Can I register a custom route to OHIF v3?
</summary>

Yes, you can take advantage of the customizationService and register your own routes.
see [custom routes](../platform/services/customization-service/customRoutes.md)


</details>


## DICOM Endpoints

In OHIF v3 there is a new end point that your DICOM server should be able to respond to
`WADO-RS GET studies/{studyInstanceUid}/series`

This is used in the viewer for fetching the series list for a study to use for the hanging protocol.

## LifeCycle Hooks

OHIF v2 had `preRegistration` hook for extensions for initialization. In OHIF v3 you have
even more control using `onModeEnter` and `onModeExit` hooks on the extensions and on the modes.

- `preRegistration`: is called before the extension is registered to the viewer. So very early in the lifecycle of the viewer.
- `onModeEnter` is called when the mode is entered (component on the route is mounted, e.g., when you click on the mode to enter it)
- `onModeExit` is called when the mode is exited (component on the route is unmounted, e.g., when you navigate back to the worklist)

## Extensions

Since extensions in OHIF v2 were the main way of customizing the viewer, we will spend some time
below to explain how you can migrate your extensions to OHIF v3.

### Default Extension

Lots of common functionalities in the platform/core has been moved inside
the `@ohif/extension-default` extension. This extension is loaded by default
in the viewer and it provides the following functionalities:

- common datasources such as DICOMWeb, DICOMLocal, and DICOMJSON datasource.
- default measurement panel and panel study browser
- common toolbar button layouts
- common hanging protocol configurations

<details>
<summary>
how can I integrate to my google health api? is there support for that?
</summary>

You can right now, take a look into our google configuration that we use for our QA located at
`config/google.js`. Also we have some exciting UI changes coming up for the next release
that will make it easier to integrate with google health api.
</details>

<details>
<summary>
Is there any recommendation for PACS integration
</summary>

You can take a look at open source PACS such as dcm4chee or orthanc. We have support for them. Also
we have a new static wado datasource that you can use to take benefit of new deduplicated metadata
and caching features.

</details>

### Cornerstone Extension

In OHIF v2, the Cornerstone extension provided modules like Cornerstone ViewportModule, ToolbarModule, and CommandsModule for controlling viewport actions.
It relied on `react-cornerstone-viewport` for rendering viewports, `cornerstone-tools` for tools, and `cornerstone-core` for core functionalities.

However, in OHIF v3, there have been significant changes. The rendering and tooling logic has been migrated to a new library called [`Cornerstone3D`](https://github.com/cornerstonejs/cornerstone3D-beta/). This means that all viewport rendering and tool functionalities are now handled by Cornerstone3D.

Additionally, in OHIF v3, the native support for 3D functionalities previously provided by the `vtk` extension has been integrated into Cornerstone3D. As a result, any vtkjs logic is encapsulated on CS3D. Things now are much more cleaner and simpler.

To migrate from OHIF v2 to OHIF v3:

#### Loading

Previously we used `cornerstone-wado-image-loader` for loading images. However, we have fully switched the a new
library called `@cornerstonejs/dicom-image-loader` which is a fork of `cornerstone-wado-image-loader` with typescript support and bug fixes.
We have deprecated `cornerstone-wado-image-loader` and you should also switch to `@cornerstonejs/dicom-image-loader` as well.
The process is very simple, you can follow this [PR](https://github.com/OHIF/Viewers/pull/3339) to see how we have migrated.

There is also a new loader and package `@cornerstonejs/streaming-image-volume-loader`, which provides streaming of the image data
into a volume using web workers and web assembly. You can look into the cornerstone documentation and read more about the
volumeViewport and volumeLoader.


#### Rendering

The significant difference between cornerstone-core and cornerstone3D is that cornerstone3D fully utilizes
[vtk.js](https://kitware.github.io/vtk-js/) for rendering, however in cornerstone-core we used a mix of webGL and vtk
for rendering. While you don't need to do a migration for this, you should be aware that the rendering is now fully performed in the
world coordinate system and the image is placed in the world coordinate system using the `imagePositionPatient` and `imageOrientationPatient`
attributes of the image. This means that you can now share the tool states between multiple viewports and you can also
use the same tool states for 2D and 3D viewports.

:::tip

In OHIF v3, we have removed the OHIF's vtk extension and migrated all the 3D functionalities to Cornerstone3D.

Also you need to remove any dependencies on `react-cornerstone-viewport`, `cornerstone-tools`, and `cornerstone-core`.
:::

#### Tools

If you don't have any custom tools, you most likely won't need to make any changes as have tried
to migrate all the tools from `cornerstone-tools` to Cornerstone3D (except `ROIWindowLevel` which is work in progress right now).

Cornerstone3D has moved the coordinate system of tools to the world coordinate system enabling sharing
tool states between multiple viewports, and as a result the toolData is now stored in the world coordinate system as well.
So to migrate your tools, you will need to update your toolData to be stored in the world coordinate system. You can look
into the simplest tool for instance LengthTool in both `cornerstone-tools` and `cornerstone3D` to see the difference.



By following these steps, you can leverage the improved rendering and tooling capabilities of Cornerstone3D and eliminate the need for the old ohif's vtk extension in OHIF v3.


<details>
<summary>
Is there any name standard for modes and extensions?
</summary>

No naming standard, you can have your organization name as a prefix for your modes and extensions as we
do for ohif (`@ohif/extension-*` and `@ohif/mode-*`).

</details>


<details>
<summary>
What happens if I have create a mode with same name as existing one
</summary>

You shouldn't. Modes are configuration objects that you can simply. There is no real use case
for creating a mode with same name as existing one. If you do so, the last one will override the previous one


</details>


<details>
<summary>
How to remove an "core" extension/mode?
</summary>

You can use the OHIF cli tool to add/remove/link and unlink extensions and modes. You can find more information
about the cli tool [here](../development/ohif-cli.md)

</details>

<details>
<summary>
If I have vtkjs implementation how can I port it? Should I create a specific extension for that?
</summary>

Cornerstone3D has support for some vtk.js actor and mappers including imageData, polyData and volume. If you have another
implementation of vtk.js actor or mapper, you might be able to use `viewport.addActor` to include it in the rendering
pipeline, but depending on the implementation and how much it interfere with the cornerstone3D rendering pipeline, you might
not get the expected result.

</details>



### DICOM Segmentation & DICOM RT

In OHIF v3, the equivalent extensions for RT and SEG exists with similar logic, but with various improvements such as
enhanced ui/ux for segmentation panel, faster loading and interaction, and better support for multiple viewports,
animations for jump to segment, volumetric rendering, and more. Additionally, OHIF v3 introduces new functionalities with the SEG Viewport and RT Viewport.

:::tip

In OHIF v3, Segmentation objects
are loading using the frame of reference by default which means that if there are two viewports that are using the same frame of reference,
if you load a segmentation (labelmap or RT) which lives in the same frame of reference, it will be loaded in both viewports.
:::

When loading a series that contains SEG (Segmentation) or RT (RT Structure Set) data, the viewport will automatically
switch to the corresponding SEG or RT viewport. The user will then be prompted to decide whether to load the segmentation
or RT structure set into the viewer. This new feature addresses a common use case in which there are multiple segmentation
series in a study, and the user only wants to load specific ones. In OHIF v3, the Segmentations are all loaded
as 3D volumes and as a result a volume viewport is used to display them. (Stack Segmentation in Cornerstone3D is still a
work in progress.)

In OHIF v2, the user had to load all the segmentation series and then manually delete the ones they didn't want to see.
However, in OHIF v3, the user has more control. The temporary SEG or RT viewport does not immediately load (hydrate)
the segmentation or RT structure set. Instead, the user can decide which ones to load, reducing unnecessary
loading and providing a more efficient workflow.

This enhancement in OHIF v3 allows users to selectively load specific segmentations or RT structure sets,
improving the usability and efficiency of the viewer when working with multiple SEG or RT series.




<details>
<summary>
Can I load one seg in one viewport and another in another viewport?
</summary>

If there is another viewport in the grid that is using the same frame of reference, the segmentation will be loaded in that viewport as well.

However, since we split the concept of `load` (`hydration`) and `preview`, you can use the preview (not load), which
makes sure the SEG is contained within the viewport, but it is not hydrated so you cannot edit it.

In future however, we will add more controls over, hiding the segmentation in other viewports via UI, however, you can
right now do it via code.



</details>

<details>
<summary>
Does it support nifti?
</summary>

Nifit support for both image and segmentation is coming soon. We are working on it.


</details>

### DICOM SR

In OHIF v2, DICOM SR functionality was integrated into the Cornerstone extension. However, in OHIF v3, DICOM SR is now a separate extension. The DICOM SR extension in OHIF v3 retains the same loading and hydrating logic using dcmjs adapters. Additionally, it introduces a new type of viewport called the SR Viewport, which is used to display SR data.

Similar to the temporary SEG and RT viewports, when a SR display set is selected in OHIF v3, the user is prompted to decide whether to load the SR data into the viewer and initiate the tracking. The SR viewport allows the user to switch between different measurements within the SR instance by utilizing the arrow buttons located at the top of the viewport.

:::tip
This separation of DICOM SR into its own extension in OHIF v3 provides a dedicated viewport type for SR data and offers enhanced functionality for interacting with SR measurements within the viewer.
:::


### DICOM Tag Browser

In OHIF v2, the DICOM Tag Browser was a separate extension that provided a dedicated user interface for exploring DICOM tags. However, in OHIF v3, we have integrated the DICOM Tag Browser functionality into the `default` extension.

The DICOM Tag Browser is a powerful tool for debugging and inspecting DICOM metadata, and we wanted to make it easily accessible to users. As a result, it is now available as a toolbar icon within the `default` extension. This allows users to conveniently access the DICOM Tag Browser directly from the toolbar, eliminating the need for a separate extension.


<details>
<summary>
Now that dicom tag is integrated back to default extension, how can I port my code that was implemented in the old extension? Should I create an extension or change directly into default?
</summary>

If you have a custom tag browser, you have two options, either modify the default tag browser (if you think the features
you added is useful for everyone, feel free to open a PR!), or create your own extension with your custom tag browser
which then you can add to the toolbar.



</details>


### DICOM HTML

Since we have added graphical overlay of DICOM SR in OHIF v3, we have temporarily downgraded the priority of displaying DICOM HTML within the viewer. While DICOM HTML support is not available in the current version of OHIF v3, we acknowledge its importance and plan to reintroduce this functionality in future updates.



<details>
<summary>
is there any easy way for supporting my own dicom html viewer? Should I use extension?
</summary>

Yes, you can write your own sopClassHandler and custom viewport in your custom extensions.
After, you need to associate that with the viewport that you
will use in the mode configuration, this way when that sopClassUID is requested it will use your custom viewport.



</details>



### DICOM Microscopy

In OHIF v2, the DICOM microscopy engine was based on an older version of the [DICOM microscopy viewer](https://github.com/ImagingDataCommons/dicom-microscopy-viewer) maintained by our friends at IDC (Imaging Data Commons). However, in OHIF v3, we have upgraded to the latest version of the DICOM microscopy viewer. This new version offers significant improvements in terms of robustness and performance, providing users with an enhanced microscopy viewing experience.

One notable addition in the latest DICOM microscopy viewer is the support for annotations within the whole slide images (SM images). This feature allows users to annotate and mark specific regions of interest directly within the microscopy images.

:::tip
Looking ahead, our future plans include adding DICOM SR (Structured Reporting) support for export of annotations in microscopy images. While we will enhance our support for SM images (color profiles etc.), we recommend utilizing the [SLIM Viewer](https://github.com/ImagingDataCommons/slim) developed by IDC for more sophisticated microscopy use cases.
:::



## Extension Modules


v3 Extension is likely the same as in v2. Extensions can (like before) have
modules exported via `get{ModuleName}Module` (e.g., `getViewportModule`).

:::info
There are new
types of modules that can be exported from extensions (such as `HangingProtocolModule`, `LayoutModule`, read more about
modules in v3 [here](../platform/extensions/index.md)).
:::

The main difference between v3 and v2 is that exported modules were represented as a single object, whereas in OHIF v3, they are
represented as an array of objects, each having a name property. This change was implemented to
enable extensions to export multiple named submodules, providing more flexibility and modularity.

To access these modules in OHIF v3, you can use the namespace provided by the `ExtensionManager`. For example, consider the following code snippet


```js
getUtilityModule({ servicesManager }) {
  return [
    {
      name: 'common',
      exports: {
        getCornerstoneLibraries: () => {
          return { cornerstone, cornerstoneTools };
        },
        getEnabledElement,
        dicomLoaderService,
        registerColormap,
      },
    },
    {
      name: 'core',
      exports: {
        Enums: cs3DEnums,
      },
    },
    {
      name: 'tools',
      exports: {
        toolNames,
        Enums: cs3DToolsEnums,
      },
    },
  ];
},
```


In this example, the extension is exporting multiple submodules named 'common',
'core', and 'tools'. To access the 'common' submodule provided by the @ohif/extension-cornerstone extension,
you can use the following code:

```js
extensionManager.getModuleEntry(
  '@ohif/extension-cornerstone.utilityModule.common'
);
```

This allows you to access the specific submodule provided by the extension and utilize its functionalities within your application.


<details>
<summary>
How can I have a lazy-loaded component and import it from another extension?
</summary>

If an extension is exporting a component, you can import it from another extension. For example, if you have an extension that exports a component called `MyComponent`, you can import it from another extension like this:

```js
import { MyComponent } from '@ohif/extension-my-extension';
```


</details>


### ToolbarModule

In OHIF v2, the toolbarModule was used to add buttons to the toolbar. For example, the following code snippet demonstrates adding a zoom tool button to the toolbar:

In OHIF v2

```js
{
  id: 'Zoom',
  label: 'Zoom',
  icon: 'search-plus',
  //
  type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
  commandName: 'setToolActive',
  commandOptions: { toolName: 'Zoom' },
},
```

However, in OHIF v3, the toolbarModule has been repurposed to define different button types. For instance, OHIF v3 introduces the ohif.radioGroup and ohif.splitButton button types, which provide more flexibility in defining toolbar buttons for each mode.



```js
{
  name: 'ohif.radioGroup',
  defaultComponent: ToolbarButton,
  clickHandler: () => {},
},
{
  name: 'ohif.splitButton',
  defaultComponent: ToolbarSplitButton,
  clickHandler: () => {},
},
```

To use these button types within your modes, you can define the buttons in your mode's configuration. In the onModeEnter hook, you can add the defined buttons to the toolbar using the toolbarService. Here's an example of how to add buttons to the toolbar:



```js
// toolbar button
{
  id: 'Zoom',
  type: 'ohif.radioGroup',
  props: {
    type: 'tool',
    icon: 'tool-zoom',
    label: 'Zoom',
    commands: _createSetToolActiveCommands('Zoom'),
  },
},
```

and in `onModeEnter`

```js
onModeEnter: ({ servicesManager, extensionManager, commandsManager }) => {
  const {
    toolbarService,
    toolGroupService,
  } = servicesManager.services;

  // Init tool groups (see cornerstone3D for more details)
  initToolGroups(extensionManager, toolGroupService, commandsManager);

  toolbarService.addButtons(toolbarButtons);
  toolbarService.createButtonSection('primary', [
    'MeasurementTools',
    'Zoom',
    'WindowLevel',
    'Pan',
    'Capture',
    'Layout',
    'Crosshairs',
    'MoreTools',
  ]);
},
```

By using the updated toolbarModule in OHIF v3, you can define and add toolbar buttons specific to each mode, providing greater flexibility and customization options for the toolbar configuration.

An example of split button icon in v3 is shown below



<details>
<summary>
Is the tool state shared between two different modes?
</summary>
No, the tool state is not shared between different modes in OHIF v3. Each mode operates independently and maintains its own tool state.

</details>

<details>
<summary>
I have a custom icon. How can I add it to the toolbar?
</summary>

You need to first register it via `addIcon` in the src/components/Icon, and then you can
referenced it by name in the toolbar configuration for mode
</details>


<details>
<summary>
Can I change the toolbar's location? Can I add a secondary toolbar?
</summary>
Not in our default layout, but you can write your own layout in your custom extension
and use it instead of the default one.

</details>

<details>
<summary>
Can I have different tool sets for each viewport?
</summary>

We don't have fully support for this yet, but we have plans for it. Basically, the plan
is to use the viewport action bar in the top of the viewport to provide viewport-specific
tool sets.
</details>

<details>
<summary>
Are all tools from v2 support in v3?
</summary>

Almost all with the exception of ROIWindow, but we have plans to add it in the future. However, there are
much more tools in v3 that are not available in v2 such as referenceLines, Stack Image Sync, and
Calibration tool.
</details>

### CommandsModule

The structure of the commands module is the same as before. The only difference is that
we use Cornerstone3D for rendering and tools. So, if you have a custom command that you were
using in the v2, you need to migrate it to the new Cornerstone3D API.

You can visit the migration guide for cornerstone  [here](https://www.cornerstonejs.org/docs/migrationGuides).

### PanelModule

Previously in OHIF v2 you had

```js
return {
  menuOptions: [
    {
      icon: 'list',
      label: 'Segmentations',
      target: 'segmentation-panel',
      stateEvent: SegmentationPanelTabUpdatedEvent,
    },
  ],
  components: [
    {
      id: 'segmentation-panel',
      component: ExtendedSegmentationPanel,
    },
  ],
  defaultContext: ['VIEWER'],
};
```

but in OHIF v3 you have

```js
return [
  {
    name: 'panelSegmentation',
    iconName: 'tab-segmentation',
    iconLabel: 'Segmentation',
    label: 'Segmentation',
    component: wrappedPanelSegmentation,
  },
];
```

<details>
<summary>
How can I add my own custom panel?
</summary>
To add your own custom panel in OHIF v3, you can follow these steps:

- Create a new React component that represents your custom panel.
- Provide it in the getPanelModule of your extension.
- Inside your mode, add the panel namespace to the mode's configuration for the layout module.

</details>

<details>
<summary>
How to enhance an existing panel?
</summary>
To enhance an existing panel in OHIF v3, you can create a new React component that extends or wraps the existing panel component. In your enhanced component, you can add additional functionality, modify the appearance, or incorporate new features specific to your use case. You can also look into the customizationService to see
how you can use the registered points to customize the panel.

</details>

<details>
<summary>
How to change the order of appearance of panels?
</summary>
To change the order of appearance of panels in OHIF v3, you can modify the panel layout configuration in the mode configuration. The panel layout configuration specifies the order and arrangement of panels within the viewer interface.

</details>

<details>
<summary>
Is there a way to change the viewer layout to present right panels on the left and the toolbar on the right?
</summary>
Not with our default layout which the default extension provides. However, you can write a new layout and provide it
in the `getLayoutModule` which you can reference in the `layout` property of the mode configuration.
</details>

### SopClassHandlerModule

The least changed module is the SopClassHandlerModule, although this now returns
an array instead of a single instance. The purpose of this module is to create
a list of displaySets based on the metadata.  OHIF App uses this module to
create one or more displaySets for each series.
The displaySet is then used to then get assigned
on each viewport and the viewport renders the image.

The `DisplaySet` created by the handler can have a member function `addInstances`
which will update the display set with new SOP instance data, allowing the
preservation of the display set UID when required.

Multiple display sets will be returned when different parts of the series are
to be shown separately, for example, to split scout images from volume images.


### ViewportModule

In OHIF v3, viewports are tied to series of SOP Class UIDs (sopClassUIDs). Each extension provides its own viewport for specific SOP Class UIDs, and you can choose which viewports and SOP Class UIDs your mode can handle in the mode configuration.

For example, in the longitudinal mode configuration, there are multiple viewports specified along with their associated SOP Class Handler Modules:


```js
viewports: [
  {
    namespace: '@ohif/extension-measurement-tracking.viewportModule.cornerstone-tracked',
    displaySetsToDisplay: [ '@ohif/extension-default.sopClassHandlerModule.stack'],
  },
  {
    namespace: '@ohif/extension-cornerstone-dicom-sr.viewportModule.dicom-sr',
    displaySetsToDisplay: [ '@ohif/extension-cornerstone-dicom-sr.sopClassHandlerModule.dicom-sr'],
  },
  // additional viewports
],
```

In this example, there are six viewports specified, each identified by a unique namespace. Each viewport is associated with a specific SOP Class Handler Module through the displaySetsToDisplay property.

To add a new viewport, you would need to create a new SOP Class Handler Module and a new Viewport Module. The SOP Class Handler Module handles the logic for loading and handling specific SOP Class UIDs, while the Viewport Module defines the rendering and behavior of the viewport.

In addition to the viewports, the mode configuration should include and register each SOP Class Handler Module that your mode can handle:


```js
sopClassHandlers: [
  '@ohif/extension-default.sopClassHandlerModule.stack',
  '@ohif/extension-cornerstone-dicom-sr.sopClassHandlerModule.dicom-sr',
  '@ohif/extension-dicom-video.sopClassHandlerModule.dicom-video',
  '@ohif/extension-dicom-pdf.sopClassHandlerModule.dicom-pdf',
  '@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg',
  '@ohif/extension-cornerstone-dicom-rt.sopClassHandlerModule.dicom-rt',
]
```

Here, each SOP Class Handler Module is specified with its namespace.

By configuring the viewports and SOP Class Handler Modules in your mode, you can define how your mode interacts with different types of DICOM data and specify the appropriate rendering and behavior for each SOP Class UID.

## Metadata Store and Provider

In OHIF v2, we utilized the `platform/core/classes/metadata` module, which included the classes StudyeMetadata, SeriesMetadata, and InstanceMetadata for storing metadata. However, in OHIF v3, we have replaced these classes with a more versatile metadata store called `DICOMMetadataStore`. This new metadata store is used by each datasource to store the metadata associated with studies, series, and instances. The DICOMMetadataStore API allows you to add study/series/instance metadata to the store and retrieve metadata from it.

Although we have transitioned to using DICOMMetadataStore as the primary metadata storage mechanism, you still have access to OHIF's MetadataProvider. The MetadataProvider can be found in the same `platform/core/classes` location. The MetadataProvider is internally used to retrieve instance-based metadata based on UIDs, perform queries, and includes some legacy support for older versions of the loading logic.


## Build

We have recently transitioned from bundling all the extensions and the viewer into a single bundle to a more modular approach. In this new approach, the required extensions are dynamically loaded inside a mode as needed. This change brings several advantages, including:

- Faster build time: Bundling only the necessary extensions reduces the build time, as you no longer need to bundle all extensions upfront.
- Smaller bundle size: By loading extensions on-demand, the initial bundle size is reduced, resulting in faster page load times for users.
- Faster reload for development: During development, the incremental build process allows for faster reloads, improving developer productivity.

This new approach does not impact the deployment process of the viewer. You can continue to follow our deployment guides, such as the [Build for Production](../deployment/build-for-production.md) guide, to deploy the viewer effectively.


### Script tag usage of the OHIF viewer

With the transition to more advanced visualization, loading, and rendering techniques using WebWorkers, WASM, and WebGL, the script tag usage of the OHIF viewer has been deprecated. However, if you still prefer to use the script tag usage, it is theoretically possible to bundle all the required dependencies and utilize the script tag approach.

An alternative option for script tag usage is to employ an `iframe`. You can utilize the iframe element to load the OHIF viewer and establish communication with it using the postMessage API. This allows you to exchange messages and data between the parent window and the iframe, enabling interaction and coordination with the OHIF viewer embedded within the iframe.

Please note that while these alternatives exist, we recommend utilizing modern development practices and incorporating OHIF viewer within your application using a more modular and integrated approach, such as leveraging bundlers, and import statements to ensure better maintainability, extensibility, and compatibility with the OHIF ecosystem.


<details>
<summary>
I use OHIF v2 in an iframe. Is there any impediment for v3?
</summary>
No, there is no impediment for using OHIF v3 in an iframe. OHIF v3 is designed to be compatible with iframe usage, allowing you to embed the viewer within other applications or web pages seamlessly. You can still communicate with the OHIF v3 viewer using the postMessage API to exchange information and trigger actions between the parent window and the embedded iframe.

</details>


<details>
<summary>
Does the build support dynamic imports? How can I use it?
</summary>
Yes, the build configuration in OHIF v3 supports dynamic imports. Dynamic imports allow you to asynchronously load modules or components on demand, improving performance and reducing the initial bundle size. In fact we are using this method for our viewport components. In general you can:

```
import('path/to/module').then((module) => {
  // Use the imported module here
}).catch((error) => {
  // Handle any error that occurs during dynamic import
});
```

By using dynamic imports, you can selectively load modules or components at runtime when they are needed, enhancing the efficiency and responsiveness of your application.  However, note
that these components must be available at BUILD time, and cannot be updated after
build.

</details>

<details>

<summary>
How can I enhance the existing build to consume my own webpack script?
</summary>
You can't enhance the existing build to consume your own webpack script as of now. However, you can
modify the webpack.base.js and webpakc.pwa.js files to add your own webpack script/modules if needed.

</details>

## UI Components

Migrating to Tailwind CSS, OHIF v3 is now able to have a component-oriented styling approach, speeding up development, ensuring consistent styling, making responsive design easier, and enabling extensibility

We have gone through extensive re-design of each part of the UI, and we have also added new components to the OHIF viewer.

<details>
<summary>
I have a huge complex styles using native CSS, how can I reuse them?
</summary>
You can leverage the power of Tailwind CSS (https://TailwindCSS.com/) in OHIF v3 to reuse your existing styles. Tailwind CSS is a utility-first approach, allowing you to create reusable CSS classes by composing utility classes together. You can migrate your existing styles to Tailwind CSS by breaking them down into utility classes and utilizing the extensive set of predefined utilities provided by Tailwind CSS.

</details>

<details>
<summary>
How can I change the page color from being purplish to blueish?
</summary>
In OHIF v3, you can easily modify the page color by customizing the Tailwind CSS configuration. You can locate the tailwind.config.js file in your project and update the theme section, specifically the colors property, to define your desired color palette. By adjusting the values for the colors, you can change the page color to any shade of blue or other colors according to your preference.

</details>

<details>
<summary>
Can I have my own React UI component working in the application? Is there a way to use the current build for it as well?
</summary>
Yes, you can integrate your own React UI components seamlessly into the OHIF v3 application. You can even have external
UI dependencies and by creating your own component inside your extensions and importing it into the application, you can
use it as if it was part of the OHIF v3 application.

</details>

<details>
<summary>
How can I replace the existing component ui/tooltip?
</summary>
You need to write your own component, and inside your mode layout you can replace the existing component with your own.
As of now, for the tooltip component, you need to use the customizationService to customize it; however, the customizationService
requires a registration of the to-be-customized property before you can customize it. Read more about customizationService.

</details>

<details>
<summary>
How can I add/consume logos/images/icons?
</summary>

For logos you can use the whiteLabelling inside the configuration. However, if you need a more complex UI for your toolbar
you need to create you own layout. See `getLayoutModule`.

</details>

## Redux store

In OHIF v3, we made the decision to move away from the Redux store and adopt a new approach utilizing React context providers and services with a pub/sub pattern. This shift was driven by the need for a more flexible and scalable architecture that better aligns with the plugin and extension system of OHIF. This offers

- Modularity and Scalability: Context providers and services enable a modular architecture for easy addition and removal of plugins and extensions.
- Reduced Boilerplate: eliminate Redux boilerplate for simpler development.
- Flexible Pub/Sub Pattern: Services provide a pub/sub pattern for inter-component communication.

<details>

<summary>
Now that redux store is gone, how can I access the user information?
</summary>

You can use the `authenticationService` for that purpose.

</details>

---

### Platform Docs Docs Platform Browser Support (`platform/docs/docs/platform/browser-support.md`)

---
sidebar_position: 2
title: Browser Support
summary: Documentation of OHIF's browser compatibility standards, including supported browsers (IE11, Firefox, Chrome, Safari, Edge), transpilation and polyfill strategies, and development priorities focused on modern evergreen browsers.
---
# Browser Support

The browsers that we support are specified in the `.browserlistrc` file located
in the `platform/app` project. While we leverage the latest language features
when writing code, we rely on `babel` to _transpile_ our code so that it can run
in the browsers that we support.

## In Practice

The OHIF Viewer is capable of _running_ on:

- IE 11
- FireFox
- Chrome
- Safari
- Edge

However, we do not have the resources to adequately test and maintain bug free
functionality across all of these. In order to push web based medical imaging
forward, we focus our development efforts on recent version of modern evergreen
browsers.

Our support of older browsers equates to our willingness to review PRs for bug
fixes, and target their minimum JS support whenever possible.

### Polyfills

> A polyfill, or polyfiller, is a piece of code (or plugin) that provides the
> technology that you, the developer, expect the browser to provide natively.

An example of a polyfill is that you expect `Array.prototype.filter` to exist,
but for some reason, the browser that's being used has not implemented that
language feature yet. Our earlier transpilation will rectify _syntax_
discrepancies, but unimplemented features require a "temporary" implementation.
That's where polyfills step in.

We previously used polyfill io, but due to a security vulnerability in the library, it's necessary to switch to alternative services.




[core-js]: https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md

---

### Platform Docs Docs Platform Environment Variables (`platform/docs/docs/platform/environment-variables.md`)

---
sidebar_position: 3
sidebar_label: Environment Variables
title: Environment Variables
summary: Documentation of the environment variables used in OHIF during build time to configure application behavior, including application settings, internationalization options, and methods for setting these variables.
---
# Environment Variables

There are a number of environment variables we use at build time to influence the output application's behavior.

```bash
# Application
NODE_ENV=< production | development >
DEBUG=< true | false >
APP_CONFIG=< relative path to application configuration file >
PUBLIC_URL=< relative path to application root - default / >
ROUTER_BASENAME=< relative path to application root - default PUBLIC_URL >
VERSION_NUMBER=<Set by CircleCI>
BUILD_NUM=<Set by CircleCI>
# i18n
USE_LOCIZE=<false>
LOCIZE_PROJECTID=<ProjectID to pull translations for>
LOCIZE_API_KEY=<To enable Locize live editing of translations>
```

## Setting Environment Variables

- `npx cross-env`
- `.env` files
- env variables on build machine, or for terminal session

---

### Platform Docs Docs Platform Internationalization (`platform/docs/docs/platform/internationalization.md`)

---
sidebar_position: 4
sidebar_label: Internationalization
title: Internationalization
summary: Documentation of OHIF's internationalization (i18n) implementation, including how to change languages, extend existing languages, add new languages, and contribute translations, using the @ohif/i18n package powered by i18next.
---

# Viewer: Internationalization

OHIF supports internationalization using [i18next](https://www.i18next.com/)
through the npm package [@ohif/i18n](https://www.npmjs.com/package/@ohif/i18n),
where is the main instance of i18n containing several languages and tools.

<div className="text--center">
    <p>Our translation management is powered by
    <a href="https://locize.com/" target="_blank" rel="noopener noreferrer"> Locize </a>
    through their generous support of open source.</p>
     <a href="https://locize.com/" target="_blank" rel="noopener noreferrer" style={{padding: '20px'}}>
      <img style={{width:'70px'}} src="https://pbs.twimg.com/profile_images/909709940910120961/oyB0mX2L.jpg" alt="Locize Translation Management Logo"/>
    </a>
</div>

## How to change language for the viewer?

You can take a look into user manuals to see how to change the viewer's
language. In summary, you can change the language:

- In the preference modals
- Using the language query in the URL: `lng=Test-LNG`

## Installing

```bash
yarn add @ohif/i18n

# OR

npm install --save @ohif/i18n
```

## How it works

After installing `@ohif/i18n` npm package, the translation function
[t](https://www.i18next.com/overview/api#t) can be used [with](#with-react) or
[without](#without-react) React.

A translation will occur every time a text match happens in a
[t](https://www.i18next.com/overview/api#t) function.

The [t](https://www.i18next.com/overview/api#t) function is responsible for
getting translations using all the power of i18next.

E.g.

Before:

```html
<div>my translated text</div>
```

After:

```html
<div>{t('my translated text')}</div>
```

If the translation.json file contains a key that matches the HTML content e.g.
`my translated text`, it will be replaced automatically by the
[t](https://www.i18next.com/overview/api#t) function.

---

### With React

This section will introduce you to [react-i18next](https://react.i18next.com/)
basics and show how to implement the [t](https://www.i18next.com/overview/api#t)
function easily.

#### Using Hooks

You can use `useTranslation` hooks that is provided by `react-i18next`

You can read more about this
[here](https://react.i18next.com/latest/usetranslation-hook).

```js
import React from 'react';
import { useTranslation } from 'react-i18next';

function MyComponent() {
  const { t } = useTranslation();

  return <p>{t('my translated text')}</p>;
}
```

### Using outside of OHIF viewer

OHIF Viewer already sets a main
[I18nextProvider](https://react.i18next.com/latest/i18nextprovider) connected to
the shared i18n instance from `@ohif/i18n`, all extensions inside OHIF Viewer
will share this same provider at the end, you don't need to set new providers at
all.

But, if you need to use it completely outside of OHIF viewer, you can set the
I18nextProvider this way:

```jsx
import i18n from '@ohif/i18n';
import { I18nextProvider } from 'react-i18next';
import App from './App';

<I18nextProvider i18n={i18n}>
  <App />
</I18nextProvider>;
```

After setting `I18nextProvider` in your React App, all translations from
`@ohif/i18n` should be available following the basic [With React](#with-react)
usage.

---

### Without React

When needed, you can also use available translations _without React_.

E.g.

```js
import { T } from '@ohif/i18n';
console.log(T('my translated text'));
console.log(T('$t(Common:Play) my translated text'));
```

---

## Main Concepts While Translating

## Namespaces

Namespaces are being used to organize translations in smaller portions, combined
semantically or by use. Each `.json` file inside `@ohif/i18n` npm package
becomes a new namespace automatically.

- Buttons: All buttons translations
- CineDialog: Translations for the tool tips inside the Cine Player Dialog
- Common: all common jargons that can be reused like `t('$t(common:image)')`
- Header: translations related to OHIF's Header Top Bar
- MeasurementTable - Translations for the `@ohif/ui` Measurement Table
- UserPreferencesModal - Translations for the `@ohif/ui` Preferences Modal
- Modals - Translations available for other modals
- PatientInfo - Translations for patients info hover
- SidePanel - Translations for side panels
- ToolTip - Translations for tool tips

### How to use another NameSpace inside the current NameSpace?

i18next provides a parsing feature able to get translations strings from any
NameSpace, like this following example getting data from `Common` NameSpace:

```
$t('Common:Reset')
```

## Extending Languages in @ohif/i18n

Sometimes, even using the same language, some nouns or jargons can change
according to the country, states or even from Hospital to Hospital.

In this cases, you don't need to set an entire language again, you can extend
languages creating a new folder inside a pre existent language folder and
@ohif/i18n will do the hard work.

This new folder must to be called with a double character name, like the `UK` in
the following file tree:

```bash
 |-- src
    |-- locales
    index.js
        |-- en
            |-- Buttons.json
            index.js
            | UK
               |-- Buttons.js
               index.js
            | US
               |-- Buttons.js
               index.js
  ...
```

All properties inside a Namespace will be merged in the new sub language, e.g
`en-US` and `en-UK` will merge the props with `en`, using i18next's fallback
languages tool.

You will need to export all Json files in your `index.js` file, mounting an
object like this:

```js
   {
     en: {
       NameSpace: {
         keyWord1: 'keyWord1Translation',
         keyWord2: 'keyWord2Translation',
         keyWord3: 'keyWord3Translation',
       }
     },
     'en-UK': {
       NameSpace: {
         keyWord1: 'keyWord1DifferentTranslation',
       }
     }
   }
```

Please check the `index.js` files inside locales folder for an example of this
exporting structure.

### Extending languages dynamically

You have access to the i18next instance, so you can use the
[addResourceBundle](https://www.i18next.com/how-to/add-or-load-translations#add-after-init)
method to add and change language resources as needed.

E.g.

```js
import { i18n } from '@ohif/i18n';
i18next.addResourceBundle('pt-BR', 'Buttons', {
  Angle: 'Ângulo',
});
```

---

### How to set a whole new language

To set a brand new language you can do it in two different ways:

- Opening a pull request for `@ohif/i18n` and sharing the translation with the
  community. 😍 Please see [Contributing](#contributing-with-new-languages)
  section for further information.

- Setting it only in your project or extension:

You'll need a final object like the following, what is setting French as
language, and send it to `addLocales` method.

```js
const newLanguage =
   {
     fr: {
       Commons: {
          "Reset": "Réinitialiser",
          "Previous": "Précédent",
       },
       Buttons: {
         "Rectangle": "Rectangle",
         "Circle": "Cercle",
       }
     }
```

To make it easier to translate, you can copy the .json files in the /locales
folder and theirs index.js exporters, keeping same keys and NameSpaces.
Importing the main index.js file, will provide you an Object as expected by the
method `addlocales`;

E.g. of `addLocales` usage

```js
import { addLocales } from '@ohif/i18n';
import locales from './locales/index.js';
addLocales(locales);
```

You can also set them manually, one by one, using this
[method](#extending-languages-dynamically).

---

## Test Language

We have created a test language that its translations can be seen in the locales
folder. You can copy paste the folder and its `.json` namespaces and add your
custom language translations.

> If you apply the test-LNG you can see all the elements get appended with 'Test
> {}'. For instance `Study list` becomes `Test Study list`.

## Language Detections

@ohif/i18n uses
[i18next-browser-languageDetector](https://github.com/i18next/i18next-browser-languageDetector)
to manage detections, also exports a method called initI18n that accepts a new
detector config as parameter.

### Changing the language

OHIF Viewer accepts a query param called `lng` in the url to change the
language.

E.g.

```
https://docs.ohif.org/demo/?lng=es-MX
```

### Language Persistence

The user's language preference is kept automatically by the detector and stored
at a cookie called 'i18next', and in a localstorage key called 'i18nextLng'.
These names can be changed with a new
[Detector Config](https://github.com/i18next/i18next-browser-languageDetector).

## Debugging translations

There is an environment variable responsible for debugging the translations,
called `REACT_APP_I18N_DEBUG`.

Run the project as following to get full debug information:

```bash
REACT_APP_I18N_DEBUG=true yarn run dev
```

## Contributing with new languages

We have integrated `i18next` into the OHIF Viewer and hooked it up with Locize
for translation management. Now we need your help to get the app translated into
as many languages as possible, and ensure that we haven't missed pieces of the
app that need translation. Locize has graciously offered to provide us with free
usage of their product.

Once each crowd-sourcing project is completed, we can approve it and merge the
changes into the main project. At that point, the language will be immediately
available on https://viewer.ohif.org/ for testing, and can be used in any OHIF
project. We will support usage through both the Locize CDN and by copying the
language directly into the `@ohif/i18n` package, so that end users can serve the
content from their own domains.

Here are a couple examples:

Spanish:
https://viewer.ohif.org/viewer/1.2.840.113619.2.5.1762583153.215519.978957063.78?lng=es

Chinese:
https://viewer.ohif.org/viewer/1.2.840.113619.2.5.1762583153.215519.978957063.78?lng=zh

Portuguese:
https://viewer.ohif.org/viewer/1.2.840.113619.2.5.1762583153.215519.978957063.78?lng=pt-BR

Here are some links you can use to sign up to help translate. All you have to do
is sign up, translate the strings, and click Save. On our side, we have a
dashboard to see how many strings are translated and by whom.

This is a pretty random set of languages, so please post below if you'd like a
new language link to be added:

Languages:

[French](https://www.locize.io/register?invitation=Nj8jRPaFKYwtIfNZ6Y5GVOJOpeiXNAdVuSiOg9ceaiveP6uF6y1wVXM9lgfKoYZX)

[German](https://www.locize.io/register?invitation=gChNiVi66YINTPpbKESVAVYPapwg3DkpvMSSomLTvVqBJTXrdmPvxi0WZYHER11q)

[Dutch](https://www.locize.io/register?invitation=2PGe7I184aN0cazM4GXMhzeLtGTf9Zen5uyOEFhHQ8vYkfKHkgR0mJ8dwbNlIeCG)

[Turkish](https://www.locize.io/register?invitation=NOMIXsfneqPbFDqjce5wI7Z6p2swXSjc0rHOH4KLcM6qXSNA4LGyJaLxS7nqWAe3)

[Chinese](https://www.locize.io/register?invitation=lrcUbt7DvV4aJmQeEA4SMAj5xNWr3rltOcaZW1cFc6eod0nvzSPFU4V383tDHGGn)

[Japanese](https://www.locize.io/register?invitation=AaRq2S22o5FsxArwgVuw1gZcQjoe2ffyxarqlAXOpN7JnR2sf2mfamc5qV6LG1Mn)

[Arabic](https://www.locize.io/register?invitation=BiqI6fOm1sC84N3YJLbImXmaOCk8Hc3TMGpXg7NH2R0b0OKuPCp9wlCHLoqMRpfQ)

[Hindi](https://www.locize.io/register?invitation=ph7JmOGTV95DF3EFaI1kvK5Hx98dV9w2wj9h9UhUCWnkBNAwWEdWMcyjnF94zkWb)

[Malay](https://www.locize.io/register?invitation=HsV9F5mKZyeUZYrC3XFRzNI2l0EsIh6hK0MUIKP8IYZA3GxuzfgkvWBLCFwCpDik)

[Russian](https://www.locize.io/register?invitation=da4V9Q8DVO3M1FIlvfT50ZiS8NDNgvC0dE5hHUEAp47FXy6pLXmf1cp2lgLBfLmb)

[Swedish](https://www.locize.io/register?invitation=uR4kzBZC1vhJe6jyMwYXgGPj84QDMulQRlt2s6rONU6ljUh5dgwuUyhJEtZ4REA3)

[Italian](https://www.locize.io/register?invitation=viAS1NC5q342OxtuIv3JFX9DJ3KoR4SmGoElkBlRMphsDKt4hy9bW8JfBjHlfnd7)

[Spanish](https://www.locize.io/register?invitation=ZikXW3KI4w4eo5Cf6L1aQMWaR69XAQ0a9Va3NGorH7mAPvEPXp8w8NLkPNLs5nG8)

[Ukrainian](https://www.locize.io/register?invitation=TY0s6onqH3Asl05Bh1qB44SNSABL2pTYoturwxAmcNKRnzBZFK7bGfn7kVi23Vpg)

[Vietnamese](https://www.locize.io/register?invitation=eqfHDm0vaqxGfQ5TGt6SeV0dx9b2dCp1RrMRdIRavqzOCOAfD3IElzUsyIT689cK)

[Portugese-Brazil](https://www.locize.io/register?invitation=Qc5Dq449xbblQqLTpWeMfsyFiu3gACcgpj0EIucQjjs9Ph9pzPLpq3MnZupF9t6N)

Don't see your language in the above list? Add a request
[here](https://github.com/OHIF/Viewers/issues/618) so that we can create the
language for your translation contribution.

---

### Platform Docs Docs Platform Pwa Vs Packaged (`platform/docs/docs/platform/pwa-vs-packaged.md`)

---
sidebar_position: 3
title: PWA vs Packaged Application
summary: Explanation of OHIF's primary build process for Progressive Web Applications (PWAs), detailing how the application is built as a set of static assets with service worker support for enhanced performance across devices and network conditions.
---

# PWA vs Packaged

It's important to know that the OHIF Viewer project provides two different build
processes:

```bash
# Static Asset output: For deploying PWAs
yarn run build
```

## Progressive Web Application (PWA)

> [Progressive Web Apps][pwa] are a new breed of web applications that meet the
> [following requirements][pwa-checklist]. Notably, targeting a PWA allows us
> provide a reliable, fast, and engaging experience across different devices and
> network conditions.

The OHIF Viewer is maintained as a [monorepo][monorepo]. We use WebPack to build
the many small static assets that comprise our application. Also generated is an
`index.html` that will serve as an entry point for loading configuration and the
application, as well as a `service-worker` that can intelligently cache files so
that subsequent requests are from the local file system instead of over the
network.

You can read more about this particular strategy in our
[Build for Production Deployment Guide](./../deployment/build-for-production.md)

## Commonjs Bundle (Packaged Script)

We are not supporting `Commonjs` bundling inside `OHIF-v3`.

---

### Platform Docs Docs Platform Scope Of Project (`platform/docs/docs/platform/scope-of-project.md`)

---
sidebar_position: 1
title: Scope of Project
summary: Overview of the OHIF Viewer's scope as a web-based medical imaging viewer that functions as a "dumb client," explaining its capabilities as a Progressive Web Application (PWA), the separation of data from the viewer, and clarification about offline capabilities.
---
# Scope of Project

The OHIF Viewer is a web based medical imaging viewer. This allows it to be used
on almost any device, anywhere. The OHIF Viewer is what is commonly referred to
as a ["Dumb Client"][simplicable]

> A dumb client is software that fully depends on a connection to a server or
> cloud service for its functionality. Without a network connection, the
> software offers nothing useful. - [simplicable.com][simplicable]

While the Viewer persists some data, it's scope is limited to caching things
like user preferences and previous query parameters. Because of this, the Viewer
has been built to be highly configurable to work with almost any web accessible
data source.



To be more specific, the OHIF Viewer is a collection of HTML, JS, and CSS files.
These can be delivered to your end users however you would like:

- From the local network
- From a remote web server
- From a CDN (content delivery network)
- From a service-worker's cache
- etc.

These "static asset" files are referred to collectively as a "Progressive Web
Application" (PWA), and have the same capabilities and limitations that all PWAs
have.

All studies, series, images, imageframes, metadata, and the images themselves
must come from an external source. There are many, many ways to provide this
information, the OHIF Viewer's scope **DOES NOT** encompass providing _any_
data; only the configuration necessary to interface with one or more of these
many data sources. The OHIF Viewer's scope **DOES** include configuration and
support for services that are protected with OpenID-Connect.

In an effort to aid our users and contributors, we attempt to provide several
[deployment and hosting recipes](../deployment/index.md) as potential starting
points. These are not meant to be rock solid, production ready, solutions; like
most recipes, they should be augmented to best fit you and your organization's
taste, preferences, etc.

## FAQ

_Am I able to cache studies for offline viewing?_

Not currently. A web page's offline cache capabilities are limited and somewhat
volatile (mostly imposed at the browser vendor level). For more robust offline
caching, you may want to consider a server on the local network, or packaging
the OHIF Viewer as a desktop application.

_Does the OHIF Viewer work with the local filesystem?_

It is possible to accomplish this through extensions; however, for a user
experience that accommodates a large number of studies, you would likely need to
package the OHIF Viewer as an [Electron app][electron].




[simplicable]: https://simplicable.com/new/dumb-client
[electron]: https://electronjs.org/

---

### Platform Docs Src Pages Help (`platform/docs/src/pages/help.md`)

# Help

We all need a little help sometimes. Don't let a few roadblocks stand in the way
of you building something awesome.

## Get Support

If you're a developer looking to contribute code, documentation, or discussion;
we are more than happy to help provide clarification and answer questions via
[GitHub issues][gh-issues] or our [community forum][google-group]. Regular
contributors may also be invited to join our Slack Group to streamline
discussion.

For bug reports and feature requests (including incomplete or confusing
documentation), [GitHub issues][gh-issues] continue to be your best avenue of
communication.

Complex issues specific to your organization/situation are still okay to post,
but they're less likely to receive a response. Unfortunately, we have limited
resources and must be judicious with how we allocate them. If you find yourself
in this situation and in need of assistance, it may be in your best interest to
pursue paid support.

If you need additional help, please [reach out to us](https://ohif.org/get-support) to get more information on
how we can help you.


[gh-issues]: https://github.com/OHIF/Viewers/issues/
[google-group]: https://groups.google.com/forum/#!forum/cornerstone-platform

---

### Platform Docs Versioned Docs Version 3.11 Conformance (`platform/docs/versioned_docs/version-3.11/conformance.md`)

---
sidebar_position: 12
sidebar_label: DICOM Conformance Statement
title: DICOM Conformance Statement
summary: Access information about the OHIF Viewer's compliance with DICOM standards through an open-sourced document provided by Radical Imaging, which details the application's implementation of DICOM protocols and services.
---

You can find a version that has been open sourced by Radical Imaging [in this link](https://docs.google.com/document/d/1hbDlUApX4svX33gAUGxGfD7fXXZNaBsX0hSePbc-hNA/edit?usp=sharing)

---

### Platform Docs Versioned Docs Version 3.11 Release Notes (`platform/docs/versioned_docs/version-3.11/release-notes.md`)

---
sidebar_position: 2
sidebar_label: Release Notes
title: OHIF Viewer Release Notes
summary: Information about OHIF Viewer version releases, including new features, improvements, and bug fixes, which can be found in detail on the official OHIF website.
---

# Release Notes



You can find the detailed release notes on the OHIF website. Please visit [https://ohif.org/release-notes](https://ohif.org/release-notes)

---

### Platform Docs Versioned Docs Version 3.11 Resources (`platform/docs/versioned_docs/version-3.11/resources.md`)

---
sidebar_position: 13
sidebar_label: Resources
title: OHIF Viewer Educational Resources
summary: A comprehensive collection of presentations, slides, posters, and videos from conferences, hackathons, and community meetings where the OHIF team has shared knowledge about the viewer's development, features, and capabilities, organized chronologically from 2016 to present.
---

# Resources

Throughout the development of the OHIF Viewer, we have participated in various
conferences and "hackathons". In this page, we will provide the presentations
and other resources that we have provided to the community in the past:

## 2025

### Machine Learning in Medical Imaging Consortium (MaLMIC) | January 2025

We presented two talks at the Machine Learning in Medical Imaging Consortium (MaLMIC) 2025 conference.

- Advanced Medical Imaging Visualization [Slides](https://docs.google.com/presentation/d/1HZDL-72nNe4BPawDxR3XnSFLB3oLo72RjExc-KHDZfo/edit?usp=sharing)
- Introducing Advanced Segmentation Tools in the OHIF Viewer and Cornerstone3D [Slides](https://docs.google.com/presentation/d/146oJ24PPsFZaDPHeFudRF1dmbL42K9yHzQdXXAXdWxk/edit?usp=sharing)


## 2024

### ITCR Sustainment Session 2024

Dr. Gordon Harris presented at ITCR sustainment session about the future of OHIF.

- OHIF Sustainability [Slides](https://docs.google.com/presentation/d/15380mjCzBKBj9PuysCW1Q9ODnyoypJrCDpj3atTtK6I/edit?usp=sharing)

### ITCR Sustainment Panel 2024

- Advanced Medical Imaging Visualization [Slides](https://docs.google.com/presentation/d/1alUp9uJpoJs3aAUE0KqrufGo6e6HHvXYmOAdJp-Rlkc/edit?usp=sharing)


### IMNO 2024 - March 19-20, 2024

We participated in the Imaging Network Ontario (ImNO) 2024 symposium, presenting three posters. One of our presentations received the best talk award during the session.


- Advancing Medical Imaging on the Web: Implementation of Hanging Protocols for Automated Image Display Configuration in OHIF V3 [Poster](https://www.dropbox.com/scl/fi/z4h86bmsxi0c62e1n6h9l/P7-9-Alireza-Sedghi-Final.pdf?rlkey=v5pm0p5ygkbq41x9bz3hr5yi8&dl=0)
- Advancing Medical Imaging on the Web: Optimizing the Dicomweb Server Architecture with Static Dicomweb [Poster](https://www.dropbox.com/scl/fi/ep0lxjp90kbxhjoffe4kh/P7-10-Bill-Wallace-Final.pdf?rlkey=xl2u6tdnh9j9hgvkajxv3b02o&dl=0)
- (**🏆🏆 BEST PRESENTATION AWARD in the Session 7 Pitches: Devices, HW, SW Development 🏆🏆**) Advancing Medical Imaging on the Web: Integrating High Throughput JPEG 2000 (HTJ2K) in Cornerstone3D for Streamlined Progressive Loading and Visualization [Poster](https://www.dropbox.com/scl/fi/srs2rxgtv2r69ver9ub1j/P7-8-Bill-Wallace-Final.pdf?rlkey=k9mmraw76r9q2s3b9w9s0793w&dl=0)

## 2023

### ITCR 2023 Conference | September 11-13, 2023

Dr. Gordon Harris presented an update on OHIF in [NCI Informatics Technology for Cancer Research Annual Meeting](https://www.itcr2023.org/). You can find the slides and poster here:
[[Slides]](https://docs.google.com/presentation/d/1R38s95db_yZj0WoYdlUbaWGZsWVb3H-3u_hXBZXiTaE/edit?usp=sharing)[[Poster]](https://ohif-assets.s3.us-east-2.amazonaws.com/presentations/OHIF-ITCR-2023-FINAL-PRINT.pdf)




### SIIM 2023 Tech Tools Webinar |  April 12th, 2023

Free, Open Source Tools for Research: MONAI and OHIF Viewer
[[Slides](https://docs.google.com/presentation/d/1afJ5Y9Tzukgn7eAbaO1oiCtN7XvIimFdmZP-HcOUofA/edit?usp=sharing)][[Video](https://www.youtube.com/watch?v=lo8J5w5jUJI)]


### NA-MIC Project Week 38th 2023 - Remote

We participated in the 38th Project Week with three projects around OHIF. [[Website](https://projectweek.na-mic.org/PW38_2023_GranCanaria/)]

- PolySeg representations for OHIF Viewer ([link](https://projectweek.na-mic.org/PW38_2023_GranCanaria/Projects/OHIF_PolySeg/))
- Cross study synchronizer for OHIF Crosshair ([link](https://projectweek.na-mic.org/PW38_2023_GranCanaria/Projects/OHIF_SyncCrosshair/))
- DATSCAN Viewer implementation in OHIF ([link](https://projectweek.na-mic.org/PW38_2023_GranCanaria/Projects/OHIF_DATSCAN/))



## 2022

### OHIF Demo to Interns
[[Slides]](https://docs.google.com/presentation/d/1a2PkUnqkVMaXaBsuFn7-PPlBJULU3dBwzI_44gKFeYI/edit?usp=sharing)

### SIIM 2022 - Updates from the Imaging Informatics Community
We participated in the SIIM 2022 conference to give update for the imaging
informatics community.
[[Slides]](https://docs.google.com/presentation/d/1EUGaUzQtGhZbZWpGLe6ONqChpVMw9Qr9l3KHODevMow/edit?usp=sharing)
[[Video]](https://vimeo.com/734463662/dbd5a88371)

### The Imaging Network Ontario - Remote

The Imaging Network Ontario (ImNO) is an annual symposium that brings together
medical imaging researchers and scientists from across Canada to share
knowledge, ideas, and experiences.
[[Slides]](https://docs.google.com/presentation/d/18XZDon4-Sitc2a70V5sFyhyUVZI_mIgfXHGtdxhZMjE/edit?usp=sharing)
[[Video]](https://vimeo.com/843234581/ad7d308a44)


### [NA-MIC Project Week 36th 2022 - Remote](https://github.com/NA-MIC/ProjectWeek/blob/master/PW36_2022_Virtual/README.md)

The Project Week is a week-long hackathon of hands-on activity in which medical
image computing researchers. OHIF team participated and gave a talk on OHIF and
Cornerstone in the 36th Project Week:
[[Slides]](https://docs.google.com/presentation/d/1-GtOKmr2cQi-r3OFyseSmgLeurtB3KXUkGMx2pVLh1I/edit?usp=sharing)
[[Video]](https://vimeo.com/668339696/63a2c48de8)

## 2021

### [NA-MIC Project Week 35th 2021 - Remote](https://github.com/NA-MIC/ProjectWeek/tree/master/PW35_2021_Virtual)

The Project Week is a week-long hackathon of hands-on activity in which medical
image computing researchers. OHIF team participated in the 35th Project Week
in 2021.
[[Slides]](https://docs.google.com/presentation/d/1KYNjuiI8lT1foQ4P9TGNV0lBhM6H-5KBs0wkYj4JJbk/edit?usp=sharing)

### Chan Zuckerberg Initiative (CZI)

Project presentations and demonstrations of Essential Open Source Software for
Science (EOSS) grantees
[[Slides]](https://docs.google.com/presentation/d/1_CLtG2hsL3ZxOtV2olVnzBOzq-TMLrHLomOy3FiU4NE/edit?usp=sharing)
[[Video]](https://youtu.be/0FjKkTJO0Rc?t=3737)

### Google Cloud Tech

Healthcare Imaging with Cloud Healthcare API
[[Video]](https://www.youtube.com/watch?v=2MiX9ScHFhY)

## 2020

### OHIF ITCR Pitch

OHIF pitch for Informatics Technology for Cancer Research (ITCR)
[[Slides]](https://docs.google.com/presentation/d/1MZXnZrVAnjmhVIWqC-aRSvJOoMMRLhLddACdCa1TybM/edit?usp=sharing)
[[Video]](https://vimeo.com/843234613/625bdb8793)

## 2019

### OHIF and VTK.js Training Course

OHIF and Kitware collaboration to create a training course for OHIF and VTK.js
developers. Funding for this work was provided by Kitware (NIH NINDS
R44NS081792, NIH NINDS R42NS086295, NIH NIBIB and NIGMS R01EB021396, NIH NIBIB
R01EB014955), Isomics (NIH P41 EB015902), and Massachusetts General Hospital
(NIH U24 CA199460).

1. Introduction to VTK.js and OHIF
   [[Slides]](https://docs.google.com/presentation/d/1NCJxpfx_qUGJI_2DhbECzaOg0k-Z6b65QlUptCofN-A/edit#slide=id.p)
   [[Video]](https://vimeo.com/375520781)
2. Developing with VTK.js
   [[Slides]](https://docs.google.com/presentation/d/17TCS6EhFi6SWFIrcAJ-DFdFzFFL-WD9BBTv-owmMdDU/edit#slide=id.p)
   [[Video]](https://vimeo.com/375521036)
3. VTK.js Architecture and Tooling
   [[Slides]](https://docs.google.com/presentation/d/1Sr1OGxMSw0oCt46koKQbmwSIE11Kqq8MGtyW3W0ASpk/edit?usp=gmail_thread)
   [[Video]](https://vimeo.com/375521810)
4. OHIF + VTK.js Integration
   [[Slides]](https://docs.google.com/presentation/d/1Iwg-u01HGVf1CgC6NbcBD3gm3uHN9WhjU59FSz55TN8/edit?ts=5d9c9ce4#slide=id.g59aa99cda4_0_131)
   [[Video]](https://vimeo.com/375521206)

## 2017

### Lesion Tracker

LesionTracker: Extensible Open-Source Zero-Footprint Web Viewer for Cancer
Imaging Research and Clinical Trials. This project was supported in part by
grant U24 CA199460 from the National Cancer Institute (NCI) Informatics
Technology for Cancer Research (ITCR) Program.
[[Video]](https://www.youtube.com/watch?v=gUIPtoSBL-Q)

### OHIF Community Meeting - June

[[Slides]](https://docs.google.com/presentation/d/1K9Y6eP5DYTXoDlfwCZE6GkCUp83AK4_40YQS0dlzVBo/edit?usp=sharing)

## 2016

### Imaging Community Call

Open Source Oncology Web Viewer; Presentation by Gordon J. Harris
[[Slides]](https://www.slideshare.net/imgcommcall/lesiontracker)

### OHIF Community Meeting - June

[[Slides]](https://docs.google.com/presentation/d/1Ai25mBG0ZWUPhaadp3VnbCVmkYs9K51sQ8osMixrvJ0/edit?usp=sharing)

### OHIF Community Meeting - September

[[Slides]](https://docs.google.com/presentation/d/1iYZoU7v7KHSLHiKwH1_9_wweAkG7RGnyxrWeeHva4zQ/edit?usp=sharing)

---

### Platform Docs Versioned Docs Version 3.11 Test Coverage (`platform/docs/versioned_docs/version-3.11/test-coverage.md`)

---
sidebar_position: 14
sidebar_label: Test Coverage
title: OHIF Viewer Test Coverage
summary: Information about the automated testing infrastructure for the OHIF Viewer, with a focus on Playwright tests and access to the latest test coverage reports, which help ensure reliability and quality of the codebase.
---

# Test Coverage

## Playwright


Here's the test coverage report for our Playwright tests. Keep in mind that this doesn't include our Cypress tests, so our actual test coverage is likely higher than what's shown. We're focusing on Playwright for future OHIF testing, and we're really pushing to improve that coverage number.


You can view our latest test coverage report here:
- [OHIF Playwright Test Coverage Report](https://docs.ohif.org/coverage)

---

### Platform Docs Docs Configuration DataSources Configuration Ui (`platform/docs/docs/configuration/dataSources/configuration-ui.md`)

---
sidebar_position: 6
sidebar_label: Configuration UI
title: Configuration UI
summary: Describes interfaces for implementing configurable data sources in OHIF, with details on BaseDataSourceConfigurationAPI and BaseDataSourceConfigurationAPIItem to enable generic UIs for hierarchical data source configuration.
---

# Configuration UI

OHIF provides for a generic mechanism for configuring a data source. This is
most useful for those organizations with several data sources
that share common (path) hierarchies. For example, an organization may have several DICOM stores
in the Google Cloud Healthcare realm where each is organized into various projects,
location, data sets and DICOM stores.

By implementing the `BaseDataSourceConfigurationAPI` and
`BaseDataSourceConfigurationAPIItem` in an [OHIF extension](../../platform/extensions/index.md), a data source can
be made configurable via the generic UI as is depicted below for a
Google Cloud Healthcare data source.



:::tip
A datasource root URI can be [fully or partially specified](../../deployment/google-cloud-healthcare.md#configuring-google-cloud-healthcare-as-a-datasource-in-ohif)
in the OHIF configuration file.
:::

## `BaseDataSourceConfigurationAPIItem` interface

Each (path) item of a data source is represented by an instance of this interface.
At the very least each of these items must expose two properties:

|Property |Description|
|---------|-----------|
|id|a string that uniquely identifies the item|
|name|a human readable name for the item|

Note that information such as where in the path hierarchy the item exists
has been omitted, but can be added in any concrete class that might implement this
interface. For example, the the Google Cloud Healthcare implementation of this
interface (`GoogleCloudDataSourceConfigurationAPIItem`) adds an `itemType`
(i.e. projects, locations, datasets, or dicomStores) and `url`.

## `BaseDataSourceConfigurationAPI` interface

The implementation of this interface is at the heart of the configuration process.
It possesses several methods for building up a data source path based on various
`BaseDataSourceConfigurationAPIItem` objects that are set via calls to the `setCurrentItem`
method.

The constructor for the concrete class implementation should accept whatever
parameters are necessary for configuring the data source. One argument
to the constructor must be the string identifying the name of the data source
to be configured. Furthermore, considering that the `ExtensionManager` possesses
API to configure and update data sources, it too will likely be an argument to
the constructor. See [Creation via Customization Module](#creation-via-customization-module)
for more information on how the constructor is invoked via a factory method.

For an example implementation of this interface see `GoogleCloudDataSourceConfigurationAPI`.

### Interface Methods

Each of the following subsections lists a method of the interface with a description
detailing what the method should do.

#### `getItemLabels`

Gets the i18n labels (i.e. the i18n lookup keys) for each of the configurable items
of the data source configuration API.  For example, for the Google Cloud Healthcare
API, this would be `['Project', 'Location', 'Data set', 'DICOM store']`.

Besides the configurable item labels themselves, several other string look ups
are used base on EACH of the labels returned by this method.
For instance, for the label `{itemLabel}`, the following strings are fetched for
translation...
1. No `{itemLabel}` available
   - used to indicate no such items are available
   - for example, for Google, No Project available would be 'No projects available'
2. Select `{itemLabel}`
   - used to direct selection of the item
   - for example, for Google, Select Project would be 'Select a project'
3. Error fetching `{itemLabel}` list
   - used to indicate an error occurred fetching the list of items
   - usually accompanied by the error itself
   - for example, for Google, Error fetching Project list would be 'Error fetching projects'
4. Search `{itemLabel}` list
   - used as the placeholder text for filtering a list of items
   - for example, for Google, Search Project list would be 'Search projects'

#### `initialize`

Initializes the cloud server API and returns the top-level sub-items
that can be chosen to begin the process of configuring a data source.
For example, for the Google Cloud Healthcare API, this would perform the initial request
to fetch the top level projects for the logged in user account.

#### `setCurrentItem`

Sets the current path item that is passed as an argument to the method and
returns the sub-items of that item
that can be further chosen to configure a data source.
When setting the last configurable item of the data source (path), this method
returns an empty list AND configures the active data source with the selected
items path.

For example, for the Google Cloud Healthcare API, this would take the current item
(say a data set) and queries and returns its sub-items (i.e. all of the DICOM stores
contained in that data set). Furthermore, whenever the item to set is a DICOM store,
the Google Cloud Healthcare API implementation would update the OHIF data source
associated with this instance to point to that DICOM store.

#### `getConfiguredItems`

Gets the list of items currently configured for the data source associated with
this API instance. The resultant array must be the same length as the result of
`getItemLabels`. Furthermore the items returned should correspond (index-wise)
with the labels returned from `getItemLabels`.

## Creation via Customization Module

The generic UI (i.e. `DataSourceConfigurationComponent`) uses the
[OHIF UI customization service](../../platform/services/customization-service/customizationService.md) to
instantiate the `BaseDataSourceConfigurationAPI` instance to configure a data source.

A UI configurable data source should have a `configurationAPI` field as part of
its `configuration` in the OHIF config file. The `configurationAPI` value is the
customization id of the customization module that provides the factory method
to instantiate the `BaseDataSourceConfigurationAPI` instance.

For example, the following is a snippet of a Google Cloud Healthcare data source configuration.

```js
  dataSources: [
    {
      namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
      sourceName: 'google-dicomweb',
      configuration: {
        name: 'GCP',
        wadoUriRoot: 'https://healthcare.googleapis.com/v1/projects/ohif-cloud-healthcare/locations/us-east4/...',
        ...
        configurationAPI: 'ohif.dataSourceConfigurationAPI.google',
        ...
      },
    },
  ]
```

This suggests that the factory method is provided by the `'ohif.dataSourceConfigurationAPI.google'`
customization module. That customization module is provided by the `default` extension's
`getCustomizationModule` and looks something like the following snippet of code. Notice that
the factory method's name MUST be `factory` and accept one argument - the data source name.
Furthermore note how the constructor is invoked with anything required by the concrete configuration
API class.

```js
export default function getCustomizationModule({
  servicesManager,
  extensionManager,
}) {
  return [
    {
      name: 'default',
      value: [
        {
          // The factory for creating an instance of a BaseDataSourceConfigurationAPI for Google Cloud Healthcare
          id: 'ohif.dataSourceConfigurationAPI.google',
          factory: (dataSourceName: string) =>
            new GoogleCloudDataSourceConfigurationAPI(
              dataSourceName,
              servicesManager,
              extensionManager
            ),
        },
      ],
    },
  ];
}

```

---

### Platform Docs Docs Configuration DataSources Dicom Json (`platform/docs/docs/configuration/dataSources/dicom-json.md`)

---
sidebar_position: 3
sidebar_label: DICOM JSON
title: DICOM JSON
summary: Explains how to configure and use the DICOM JSON data source format in OHIF, including structure of the JSON file with study/series/instance metadata, implementation examples, and local deployment instructions.
---

# DICOM JSON

You can launch the OHIF Viewer with a JSON file which points to a DICOMWeb
server as well as a list of study and series instance UIDs along with metadata.

An example would look like

`https://viewer.ohif.org/viewer/dicomjson?url=https://ohif-dicom-json-example.s3.amazonaws.com/LIDC-IDRI-0001.json`

As you can see the url to the location of the JSON file is passed in the query
after the `dicomjson` string, which is
`https://ohif-dicom-json-example.s3.amazonaws.com/LIDC-IDRI-0001.json` (this
json file has been generated by OHIF team and stored in an amazon s3 bucket for
the purpose of the guide).

## DICOM JSON sample

Here we are using the LIDC-IDRI-0001 case which is a sample of the LIDC-IDRI
dataset. Let's have a look at the JSON file:

### Metadata

JSON file stores the metadata for the study level, series level and instance
level. A JSON launch file should follow the same structure as the one below.

:::tip
You can use our script to generate the JSON file from a hosted endpoint. See
`.scripts/dicom-json-generator.js`

You could run it like this:

```bash
node .scripts/dicom-json-generator.js '/path/to/study/folder' 'url/to/dicom/server/folder' 'json/output/file.json'
```

Some modalities require additional metadata to be added to the JSON file. You can read more about the minimum amount of metadata required for the viewer to work [here](../../faq/technical#what-are-the-list-of-required-metadata-for-the-ohif-viewer-to-work). We will handle this in the script. For example, the script will add the CodeSequences for SR in order to display the measurements in the viewer.
:::


Note that at the instance level metadata we are storing both the `metadata` and
also the `url` for the dicom file on the dicom server. In this case we are
referring to
`dicomweb:https://ohif-dicom-json-example.s3.amazonaws.com/LIDC-IDRI-0001/01-01-2000-30178/3000566.000000-03192/1-001.dcm`
which is stored in another directory in our s3. (You can actually try
downloading the dicom file by opening the url in your browser).

The URL to the script in the given example is `https://ohif-dicom-json-example.s3.amazonaws.com/LIDC-IDRI-0001/01-01-2000-30178`. This URL serves as the parent directory that contains all the series within their respective folders.

```
/* Detailed source-code truncated for AI context efficiency. */
```



### Local Demo

You can run OHIF with a JSON data source against you local datasets (given that
their JSON metadata is extracted).

First you need to put the JSON file and the folder containing the dicom files
inside your `public` folder. Since files are served from your local server the
`url` for the JSON file will be `http://localhost:3000/LIDC-IDRI-0001.json` and
the dicom files will be
`dicomweb:http://localhost:3000/LIDC-IDRI-0001/01-01-2000-30178/3000566.000000-03192/1-001.dcm`.

After `yarn install --frozen-lockfile` and running `yarn dev` and opening the browser at
`http://localhost:3000/viewer/dicomjson?url=http://localhost:3000/LIDC-IDRI-0001.json`
will display the viewer.

Download JSON file from
[here](https://www.dropbox.com/sh/zvkv6mrhpdze67x/AADLGK46WuforD2LopP99gFXa?dl=0)

Sample DICOM files can be downloaded from
[TCIA](https://wiki.cancerimagingarchive.net/display/Public/LIDC-IDRI) or
directly from
[here](https://www.dropbox.com/sh/zvkv6mrhpdze67x/AADLGK46WuforD2LopP99gFXa?dl=0)

Your public folder should look like this:



:::tip
It is important to URL encode the `url` query parameter especially if the `url`
parameter itself also contains query parameters. So for example,

`http://localhost:3000/viewer/dicomjson?url=http://localhost:3000/LIDC-IDRI-0001.json?key0=val0&key1=val1`

should be...

`http://localhost:3000/viewer/dicomjson?url=http://localhost:3000/LIDC-IDRI-0001.json?key0=val0%26key1=val1`

Notice the ampersand (`&`) is encoded as `%26`.
:::

:::note
When hosting the DICOM JSON files, it is important to be aware that certain providers
do not automatically handle the 404 error and fallback to index.html. For example, Netlify
handles this, but Azure does not. Consequently, when you attempt to access a link with a
specific URL, a 404 error will be displayed.

This issue also occurs locally, where the http-server does not handle it. However,
if you utilize the `serve` package (npx serve ./dist -c ../public/serve.json), it effectively addresses this problem.
:::

---

### Platform Docs Docs Configuration DataSources Dicom Web Proxy (`platform/docs/docs/configuration/dataSources/dicom-web-proxy.md`)

---
sidebar_position: 4
sidebar_label: DICOMweb Proxy
title: DICOMweb Proxy
summary: Documents the DICOMweb Proxy data source which constructs a dynamic DICOMweb datasource from a configuration JSON file, allowing OHIF to delegate subsequent requests for metadata and images to the configured server.
---

# DICOMweb Proxy

You can launch the OHIF Viewer with a url that returns a JSON file which
contains a DICOMWeb configuration. The DICOMweb Proxy constructs a DICOMweb
datasource and delegates subsequent requests for metadata and images to that.

Usage is similar to that of the [DICOM JSON](./dicom-json.md) datasource and
might look like

`https://viewer.ohif.org/viewer/dicomwebproxy?url=https://ohif-dicom-json-example.s3.amazonaws.com/dicomweb.json`

The url to the location of the JSON file is passed in the query
after the `dicomwebproxy` string, which is
`https://ohif-dicom-json-example.s3.amazonaws.com/dicomweb.json` (this json file
does not exist at the moment of this writing).

## DICOMweb JSON configuration sample

The json returned by the url in this example contains a dicomweb configuration
(see [DICOMweb](dicom-web.md)), in a "servers" object, which is then used to
construct a dynamic DICOMweb datasource to delegate requests to. Here is an
example configuration that might be returned using the url parameter.

```json
{
  "servers": {
    "dicomWeb": [
      {
        "name": "DCM4CHEE",
        "wadoUriRoot": "https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado",
        "qidoRoot": "https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs",
        "wadoRoot": "https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs",
        "qidoSupportsIncludeField": true,
        "supportsReject": true,
        "imageRendering": "wadors",
        "thumbnailRendering": "wadors",
        "enableStudyLazyLoad": true,
        "supportsFuzzyMatching": true,
        "supportsWildcard": true
      }
    ]
  }
}
```

The DICOMweb Proxy expects the json returned by the url parameter it is invoked
with to include a servers object which contains a "dicomWeb" configuration array
as above. It will only consider the first array item in the dicomWeb
configuration.

---

### Platform Docs Docs Configuration DataSources Dicom Web (`platform/docs/docs/configuration/dataSources/dicom-web.md`)

---
sidebar_position: 2
sidebar_label: DICOMweb
title: DICOMweb
summary: Comprehensive guide to configuring DICOMweb data sources in OHIF, including setting up local DICOM servers (Orthanc, DCM4CHEE), configurations for PDF, video, and bulkdata handling, and detailed instructions for development environments.
---

# DICOMweb

## Set up a local DICOM server

ATTENTION! Already have a remote or local server? Skip to the
[configuration section](#configuration-learn-more) below.

While the OHIF Viewer can work with any data source, the easiest to configure
are the ones that follow the [DICOMWeb][dicom-web] spec.

1. Choose and install an Image Archive
2. Upload data to your archive (e.g. with DCMTK's [storescu][storescu] or your
   archive's web interface)
3. Keep the server running

For our purposes, we will be using `Orthanc`, but you can see a list of
[other Open Source options](#open-source-dicom-image-archives) below.

### Requirements

- Docker
  - [Docker for Mac](https://docs.docker.com/docker-for-mac/)
  - [Docker for Windows (recommended)](https://docs.docker.com/docker-for-windows/)
  - [Docker Toolbox for Windows](https://docs.docker.com/toolbox/toolbox_install_windows/)

_Not sure if you have `docker` installed already? Try running `docker --version`
in command prompt or terminal_

> If you are using `Docker Toolbox` you need to change the _PROXY_DOMAIN_
> parameter in _platform/app/package.json_ to http://192.168.99.100:8042 or
> the ip docker-machine ip throws. This is the value [`WebPack`][webpack-proxy]
> uses to proxy requests

## Open Source DICOM Image Archives

There are a lot of options available to you to use as a local DICOM server. Here
are some of the more popular ones:

| Archive                                       | Installation                       |
| --------------------------------------------- | ---------------------------------- |
| [DCM4CHEE Archive 5.x][dcm4chee]              | [W/ Docker][dcm4chee-docker]       |
| [Orthanc][orthanc]                            | [W/ Docker][orthanc-docker]        |
| [DICOMcloud][dicomcloud] (**DICOM Web only**) | [Installation][dicomcloud-install] |
| [OsiriX][osirix] (**Mac OSX only**)           | Desktop Client                     |
| [Horos][horos] (**Mac OSX only**)             | Desktop Client                     |

_Feel free to make a Pull Request if you want to add to this list._

Below, we will focus on `DCM4CHEE` and `Orthanc` usage:

### Running Orthanc

_Start Orthanc:_

```bash
# Runs orthanc so long as window remains open
yarn run orthanc:up
```

_Upload your first Study:_

1. Navigate to
   [Orthanc's web interface](http://localhost:8042/ui/app/index.html#/) at
   `http://localhost:8042/ui/app/index.html#/` in a web browser.
2. In the left you can see the upload button where you can drag and drop your DICOM files

#### Orthanc: Learn More

You can see the `docker-compose.yml` file this command runs at
[`<project-root>/platform/app/.recipes/Nginx-Orthanc`][orthanc-docker-compose], and more on
Orthanc for Docker in [Orthanc's documentation][orthanc-docker].

#### Connecting to Orthanc

Now that we have a local Orthanc instance up and running, we need to configure
our web application to connect to it. Open a new terminal window, navigate to
this repository's root directory, and run:

```bash
# If you haven't already, enable yarn workspaces
yarn config set workspaces-experimental true

# Restore dependencies
yarn install --frozen-lockfile

# Run our dev command, but with the local orthanc config
yarn run dev:orthanc
```

#### Configuration: Learn More

> For more configuration fun, check out the
> [Essentials Configuration](../configurationFiles.md) guide.

Let's take a look at what's going on under the hood here. `yarn run dev:orthanc`
is running the `dev:orthanc` script in our project's `package.json` (inside
`platform/app`). That script is:

```js
cross-env NODE_ENV=development PROXY_TARGET=/dicom-web PROXY_DOMAIN=http://localhost:8042 APP_CONFIG=config/docker-nginx-orthanc.js webpack-dev-server --config .webpack/webpack.pwa.js -w
```

- `cross-env` sets three environment variables
  - PROXY_TARGET: `/dicom-web`
  - PROXY_DOMAIN: `http://localhost:8042`
  - APP_CONFIG: `config/docker-nginx-orthanc.js`
- `webpack-dev-server` runs using the `.webpack/webpack.pwa.js` configuration
  file. It will watch for changes and update as we develop.

`PROXY_TARGET` and `PROXY_DOMAIN` tell our development server to proxy requests
to `Orthanc`. This allows us to bypass CORS issues that normally occur when
requesting resources that live at a different domain.

The `APP_CONFIG` value tells our app which file to load on to `window.config`.
By default, our app uses the file at
`<project-root>/platform/app/public/config/default.js`. Here is what that
configuration looks like:

```js
window.config = {
  routerBasename: null,
  extensions: [],
  modes: [],
  showStudyList: true,
  dataSources: [
    {
      namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
      sourceName: 'dicomweb',
      configuration: {
        friendlyName: 'dcmjs DICOMWeb Server',
        name: 'DCM4CHEE',
        wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
        qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
        wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
        qidoSupportsIncludeField: true,
        supportsReject: true,
        imageRendering: 'wadors',
        thumbnailRendering: 'wadors',
        enableStudyLazyLoad: true,
        supportsFuzzyMatching: true,
        supportsWildcard: true,
      },
    },
  ],
  defaultDataSourceName: 'dicomweb',
};
```

### Data Source Configuration Options

The following properties can be added to the `configuration` property of each data source.

##### `dicomUploadEnabled`
A boolean indicating if the DICOM upload to the data source is permitted/accepted or not. A value of true provides a link on the OHIF work list page that allows for DICOM files from the local file system to be uploaded to the data source

:::tip
The [OHIF plugin for Orthanc](https://book.orthanc-server.com/plugins/ohif.html) by default utilizes the DICOM JSON data
source and it has been discovered that only those studies uploaded to Orthanc AFTER the plugin has been installed are
available as DICOM JSON. As such, if the OHIF plugin for Orthanc is desired for studies uploaded prior to installing the plugin,
then consider switching to using [DICOMweb instead](https://book.orthanc-server.com/plugins/ohif.html#using-dicomweb).
:::



Don't forget to add the customization to the config as well

```js
customizationService: {
  dicomUploadComponent:
    '@ohif/extension-cornerstone.customizationModule.cornerstoneDicomUploadComponent',
},
```


#### `stowRoot`
The base URL for STOW-RS requests, for deployments that expose storage on a
different endpoint than retrieval. Optional — when omitted, STOW requests use
`wadoRoot`.

Note that `qidoRoot`, `wadoRoot` and `stowRoot` are independent absolute URLs and
need not share a host or path prefix. Each service is routed to its own root.

#### `singlepart`
A comma delimited string specifying which payloads the data source responds with as single part. Those not listed are considered multipart. Values that can be included here are `pdf`, `video`, `bulkdata`, `thumbnail` and `image`.

For DICOM video and PDF it has been found that Orthanc delivers multipart, while DCM4CHEE delivers single part. Consult the DICOM conformance statement for your particular data source to determine which payload types it delivers.

To learn more about how you can configure the OHIF Viewer, check out our
[Configuration Guide](../configurationFiles.md).

#### `thumbnailRendering`

Optional. Controls how thumbnail images are requested.

| Value | Behavior |
| ----- | -------- |
| `wadors` (default) | Uses WADO-RS retrieval for thumbnail image content |
| `thumbnailDirect` | Uses the thumbnail URL directly as the image source. Use this only when the archive serves that URL without auth headers |
| `thumbnail` | Uses the WADO-RS `.../thumbnail` endpoint |
| `rendered` | Uses the WADO-RS `.../rendered` endpoint |

Use `thumbnail` or `rendered` when the archive supports dedicated thumbnail/rendered responses. If either is selected, `thumbnailRequestStrategy` controls how the image data is fetched.

#### `thumbnailRequestStrategy`

Optional. Controls how the app retrieves the data for various thumbnails (e.g. side study panel study browser and study list preview panel) when
`thumbnailRendering` is `thumbnail` or `rendered`. It does not apply to `wadors` or `thumbnailDirect`.

| Value | Behavior |
| ----- | -------- |
| `bulkDataRetrieve` (default) | Uses the DICOMweb client's bulk data retrieve API, consistent with other bulk data reads |
| `fetch` | Performs an authenticated HTTP `GET` to the WADO-RS `.../thumbnail` or `.../rendered` URL and builds a blob URL from the JPEG response. Prefer this when the archive serves a plain image body and bulk data retrieve is incompatible or unreliable. |

Example (Orthanc-style plain fetch for thumbnails):

```js
thumbnailRendering: 'rendered',
thumbnailRequestStrategy: 'fetch',
```

#### `queryLimit`

Optional. The maximum number of studies requested from the server for the study list, passed as the `limit` query parameter to data sources that honor it. Paging is handled in the OHIF client, so this value caps how many studies a single search returns. When not specified, it defaults to `101`.

```js
queryLimit: 101,
```

### DICOM PDF
See the [`singlepart`](#singlepart) data source configuration option.

### DICOM Video
See the [`singlepart`](#singlepart) data source configuration option.

### BulkDataURI

The `bulkDataURI` configuration option alters how the datasource uses the
bulkdata end points for retrieving metadata if the data was originally not included in the
response from the server. This is useful for the metadata information that
are big and can/should be retrieved in a separate request. In case the bulkData URI
is relative (instead of absolute) the `relativeResolution` option can be used to
specify the resolution of the relative URI. The possible values are `studies`, `series`.

The default value is shown below (this will be added if not included in the config).

```js
bulkDataURI: {
  enabled: true,
  relativeResolution: 'series',
},
```

The other options allowed are:

* transform - to take the string and return an updated string
* startsWith and prefixWith - to remove a standard prefix and add an optional prefix
  * Used primarily for a reverse proxy or change in URL naming
* relativeResolution - used to set bulkdata paths to studies resolution for incorrect bulkdata paths

### Running DCM4CHEE

dcm4che is a collection of open source applications for healthcare enterprise
written in Java programming language which implements DICOM standard. dcm4chee
(extra 'e' at the end) is dcm4che project for an Image Manager/Image Archive
which provides storage, retrieval and other functionalities. You can read more
about dcm4chee in their website [here](https://www.dcm4che.org/)

DCM4chee installation is out of scope for these tutorials and can be found
[here](https://github.com/dcm4che/dcm4chee-arc-light/wiki/Run-minimum-set-of-archive-services-on-a-single-host)

An overview of steps for running OHIF Viewer using a local DCM4CHEE is shown
below:

<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
    <iframe src="https://player.vimeo.com/video/843233881?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>

[dcm4chee]: https://github.com/dcm4che/dcm4chee-arc-light
[dcm4chee-docker]:
  https://github.com/dcm4che/dcm4chee-arc-light/wiki/Running-on-Docker
[orthanc]: https://www.orthanc-server.com/
[orthanc-docker]: http://book.orthanc-server.com/users/docker.html
[dicomcloud]: https://github.com/DICOMcloud/DICOMcloud
[dicomcloud-install]: https://github.com/DICOMcloud/DICOMcloud#running-the-code
[osirix]: http://www.osirix-viewer.com/
[horos]: https://www.horosproject.org/
[default-config]:
  https://github.com/OHIF/Viewers/blob/master/platform/app/public/config/default.js
[html-templates]:
  https://github.com/OHIF/Viewers/tree/master/platform/app/public/html-templates
[config-files]:
  https://github.com/OHIF/Viewers/tree/master/platform/app/public/config
[storescu]: http://support.dcmtk.org/docs/storescu.html
[webpack-proxy]: https://webpack.js.org/configuration/dev-server/#devserverproxy

---

### Platform Docs Docs Configuration DataSources Introduction (`platform/docs/docs/configuration/dataSources/introduction.md`)

---
sidebar_position: 1
sidebar_label: Introduction
title: Data Source Introduction
summary: Introduces OHIF's data structure based on naturalized DICOM JSON format, providing an overview of common data sources available in OHIF and how custom data sources can be implemented.
---

# Data Source

The internal data structure of OHIF’s metadata follows naturalized DICOM JSON, a
format pioneered by `dcmjs`. In short DICOM metadata headers with DICOM Keywords
instead of tags and sequences as arrays, for easy development and clear code.

Here in this section we will discuss couple of data sources that are commonly used
and OHIF has provided the implementation for them.

## Custom Data Source
Do you have a custom data source? or a custom data that you want to use in OHIF?
You can easily write a data source to map your data to OHIF’s native format.

You can read more in the [Data Source Module](../../platform/extensions/modules/data-source.md)

---

--- METRICS ---
- Files Extracted: 101
- Estimated Token Budget: ~192085 tokens
- Canonical Reference: https://codewiki.google/github.com/OHIF/Viewers
