diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 07b530e8d..a580e1895 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -10,7 +10,7 @@ jobs: name: E2E Testing on ${{ matrix.os }} runs-on: ${{ matrix.os }} env: - DOWNLOAD_TIMEOUT: 220000 + DOWNLOAD_TIMEOUT: 60000 VITE_SHOW_SAMPLE_DATA: true steps: - uses: actions/checkout@v4 diff --git a/docs/loading_data.md b/docs/loading_data.md index c9a0c0a04..b67ed18d3 100644 --- a/docs/loading_data.md +++ b/docs/loading_data.md @@ -67,3 +67,7 @@ To layer images: 1. Under the Rendering tab, an opacity slider changes the transparency of the upper layer. ![Add Layer](./assets/add-layer.jpg) + +## State Files + +Load preconfigured scenes with annotations, segment groups, and view settings via [state files](./state_files.md). State files can embed data (`*.volview.zip`) or reference remote data via URIs (`*.volview.json`). diff --git a/docs/state_files.md b/docs/state_files.md index 396fe37cb..0f7f9972a 100644 --- a/docs/state_files.md +++ b/docs/state_files.md @@ -1,11 +1,69 @@ # State Files -VolView state files are a great way to save your scene and data to either be used later, or for distributing to collaborators and other users. These files store all of the information you need to restore the state of VolView: your data, annotations, camera positions, background colors, colormaps, multi-view layouts, and more. +VolView state files save your scene configuration: annotations, camera positions, colormaps, layouts, and more. There are two formats: -State files can be saved by clicking on "Disk" icon in the top of the toolbar. This button will generate a `*.volview.zip` file that can then be re-opened in VolView at any time. +## Zip State Files (`*.volview.zip`) -When saving VolView state, your data is saved along with the application state. This way, when you send a state file to a collaborator, they too can open the state file and load the previously saved data. However, this means that your state file will be as large as your dataset(s) and may contain patient identifying information. Please follow your institutes HIPAA, IRB and other regulatory and confidentiality requirements. +Save by clicking the "Disk" icon in the toolbar. This embeds your image data that was loaded from local files alongside the application state. Useful for sharing annotations with collaborators. -State files are loaded by clicking on the "Folder" icon immediately below the save-state Disk icon. This will bring up a file browser for you to select and load your state file. +## Sparse Manifest Files (`*.volview.json`) -TIP: State files are a great way for developers to transfer data into / out of VolView for integration with other systems. For example, they can be used to integrate VolView with access control systems, to streamline workflows, or to ingest results from AI systems. +JSON files that reference remote data via URIs instead of embedding it. Useful for: + +- Linking to data hosted on servers +- Sharing annotations without duplicating large datasets +- Integrating with external systems (AI pipelines, access control, etc.) + +Example manifest: + +```json +{ + "version": "6.2.0", + "dataSources": [ + { "id": 0, "type": "uri", "uri": "https://example.com/scan.zip" }, + { "id": 1, "type": "uri", "uri": "https://example.com/segmentation.nii.gz" } + ], + "segmentGroups": [ + { + "id": "seg-1", + "dataSourceId": 1, + "metadata": { + "name": "Tumor Segmentation", + "parentImage": "0", + "segments": { + "order": [1], + "byValue": { + "1": { "value": 1, "name": "Tumor", "color": [255, 0, 0, 255] } + } + } + } + } + ], + "tools": { + "rectangles": { + "tools": [ + { + "imageID": "0", + "frameOfReference": { + "planeNormal": [0, 0, 1], + "planeOrigin": [0, 0, 50] + }, + "slice": 50, + "firstPoint": [-20, -20, 50], + "secondPoint": [20, 20, 50], + "label": "lesion" + } + ], + "labels": { + "lesion": { "color": "red" } + } + } + } +} +``` + +## Loading State Files + +- **Drag and drop** onto VolView +- **File browser** via the "Folder" icon below the save button +- **URL parameter**: `?urls=[https://example.com/session.volview.json]` diff --git a/package-lock.json b/package-lock.json index 1073f59f4..f94312dd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14132,19 +14132,20 @@ } }, "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dev": true, "license": "MIT", "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.0", + "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", + "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", diff --git a/src/components/EditableChipList.vue b/src/components/EditableChipList.vue index 9c3cc045f..fb48041c8 100644 --- a/src/components/EditableChipList.vue +++ b/src/components/EditableChipList.vue @@ -39,7 +39,11 @@ const itemsToRender = computed(() => mandatory > - + - + mdi-plus {{ createLabelText }} diff --git a/src/components/ModulePanel.vue b/src/components/ModulePanel.vue index cbc8172d2..a5fe429d3 100644 --- a/src/components/ModulePanel.vue +++ b/src/components/ModulePanel.vue @@ -149,6 +149,7 @@ export default defineComponent({ position: relative; flex: 2; overflow: auto; + scrollbar-gutter: stable; } .module-text { diff --git a/src/components/SaveSession.vue b/src/components/SaveSession.vue index 33c1973d6..291933cc9 100644 --- a/src/components/SaveSession.vue +++ b/src/components/SaveSession.vue @@ -35,7 +35,7 @@ import { defineComponent, onMounted, ref } from 'vue'; import { saveAs } from 'file-saver'; import { onKeyDown } from '@vueuse/core'; -import { serialize } from '../io/state-file'; +import { serialize } from '../io/state-file/serialize'; const DEFAULT_FILENAME = 'session.volview.zip'; diff --git a/src/components/tools/ScalarProbe.vue b/src/components/tools/ScalarProbe.vue index 32c9d585a..fcffe6a6c 100644 --- a/src/components/tools/ScalarProbe.vue +++ b/src/components/tools/ScalarProbe.vue @@ -1,7 +1,9 @@