Skip to content

Commit 405f786

Browse files
Support for multi bucket study loading and sheet integration in segmentation mode.
1 parent f275d0d commit 405f786

File tree

5 files changed

+83
-29
lines changed

5 files changed

+83
-29
lines changed

extensions/ohif-gradienthealth-extension/src/DicomJSONDataSource/index.js

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -179,15 +179,15 @@ const getBigQueryRows = async (studyuids, seriesuid, access_token) => {
179179

180180
const filesFromStudyInstanceUID = async ({bucketName, prefix, studyuids, headers})=>{
181181
const studyMetadata = studyuids.map(async (studyuid) => {
182-
const folderPath = `${prefix}/${studyuid}/`;
182+
const folderPath = `${prefix}/studies/${studyuid}/series/`;
183183
const delimiter = '/'
184184
const apiUrl = `https://storage.googleapis.com/storage/v1/b/${bucketName}/o?prefix=${folderPath}&delimiter=${delimiter}`;
185185
const response = await fetch(apiUrl, { headers });
186186
const res = await response.json()
187187
const files = res.items || [];
188188
const folders = res.prefixes || [];
189189
const series = folders.map(async (folderPath)=>{
190-
const objectName = `${folderPath}metadata.json.gz`;
190+
const objectName = `${folderPath}metadata`;
191191
const apiUrl = `https://storage.googleapis.com/storage/v1/b/${bucketName}/o/${encodeURIComponent(objectName)}?alt=media`;
192192
const response = await fetch(apiUrl, { headers });
193193
return response.json()
@@ -241,7 +241,9 @@ const storeDicomSeg = async (naturalizedReport, headers) => {
241241
} = naturalizedReport;
242242

243243
const params = new URLSearchParams(window.location.search);
244-
const bucket = params.get('bucket') || 'gradient-health-search-viewer-links';
244+
const buckets = params.getAll('bucket');
245+
const bucket =
246+
buckets[1] || buckets[0] || 'gradient-health-search-viewer-links';
245247
const prefix = params.get('bucket-prefix') || 'dicomweb';
246248
const segBucket = params.get('seg-bucket') || bucket
247249
const segPrefix = params.get('seg-prefix') || prefix
@@ -275,7 +277,7 @@ const storeDicomSeg = async (naturalizedReport, headers) => {
275277
const compressedFile = pako.gzip(JSON.stringify(segSeries));
276278

277279
return fetch(
278-
`https://storage.googleapis.com/upload/storage/v1/b/${segBucket}/o?uploadType=media&name=${segPrefix}/${StudyInstanceUID}/${SeriesInstanceUID}/metadata.json.gz&contentEncoding=gzip`,
280+
`https://storage.googleapis.com/upload/storage/v1/b/${segBucket}/o?uploadType=media&name=${segPrefix}/studies/${StudyInstanceUID}/series/${SeriesInstanceUID}/metadata&contentEncoding=gzip`,
279281
{
280282
method: 'POST',
281283
headers: {
@@ -320,6 +322,10 @@ function createDicomJSONApi(dicomJsonConfig, servicesManager) {
320322
},
321323
initialize: async ({ params, query, url }) => {
322324
if (!url) url = query.get('url');
325+
if (!url) {
326+
url = query.toString();
327+
query.set('url', url);
328+
}
323329
let metaData = getMetaDataByURL(url);
324330

325331
// if we have already cached the data from this specific url
@@ -331,19 +337,29 @@ function createDicomJSONApi(dicomJsonConfig, servicesManager) {
331337
});
332338
}
333339

340+
const buckets = query.getAll('bucket');
341+
if (buckets.length === 0)
342+
buckets.push('gradient-health-search-viewer-links');
343+
334344
const { UserAuthenticationService } = servicesManager.services;
335-
const studyMetadata = await filesFromStudyInstanceUID({
336-
bucketName: query.get('bucket') || 'gradient-health-search-viewer-links',
337-
prefix: query.get('bucket-prefix') || 'dicomweb',
338-
studyuids: query.getAll('StudyInstanceUID'),
339-
headers: UserAuthenticationService.getAuthorizationHeader()
340-
});
345+
346+
const studyMetadata = [];
347+
for (let i = 0; i < buckets.length; i++) {
348+
const metadataPerBucket = await filesFromStudyInstanceUID({
349+
bucketName: buckets[i],
350+
prefix: query.get('bucket-prefix') || 'dicomweb',
351+
studyuids: query.getAll('StudyInstanceUIDs'),
352+
headers: UserAuthenticationService.getAuthorizationHeader(),
353+
});
354+
355+
studyMetadata.push(...metadataPerBucket);
356+
}
341357

342358
const data = getMetadataFromRows(
343-
_.flatten(studyMetadata),
344-
query.get('prefix'),
359+
_.flatten(studyMetadata),
360+
query.get('prefix'),
345361
query.getAll('SeriesInstanceUID')
346-
);
362+
);
347363

348364
let StudyInstanceUID;
349365
let SeriesInstanceUID;
@@ -422,8 +438,9 @@ function createDicomJSONApi(dicomJsonConfig, servicesManager) {
422438
console.debug('Not implemented', params)
423439
},
424440
series: {
425-
metadata: ({
441+
metadata: async ({
426442
StudyInstanceUID,
443+
buckets,
427444
madeInClient = false,
428445
customSort,
429446
} = {}) => {
@@ -433,7 +450,20 @@ function createDicomJSONApi(dicomJsonConfig, servicesManager) {
433450
);
434451
}
435452

436-
const study = findStudies('StudyInstanceUID', StudyInstanceUID)[0];
453+
let study = findStudies('StudyInstanceUID', StudyInstanceUID)[0];
454+
455+
if (!study && buckets) {
456+
const params = new URLSearchParams(window.location.search);
457+
params.set('StudyInstanceUIDs', StudyInstanceUID);
458+
params.delete('bucket');
459+
buckets.forEach((bucket) => {
460+
params.append('bucket', bucket);
461+
});
462+
await implementation.initialize({ query: params });
463+
464+
study = findStudies('StudyInstanceUID', StudyInstanceUID)[0];
465+
}
466+
437467
let series;
438468

439469
if (customSort) {

extensions/ohif-gradienthealth-extension/src/_shared/FormGeneratorComponent/fields/DisplayValue.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export default function DisplayValue({formIndex, name, value, defaultValue, opti
88
<Typography sx={{ fontSize: 14, marginRight: 1 }} color="text.secondary" gutterBottom>
99
{ name }:
1010
</Typography>
11-
<Typography variant="body2">
11+
<Typography variant="body2" className="overflow-auto invisible-scrollbar">
1212
{ value !== null ? value.toString() : defaultValue !== null ? defaultValue.toString() : '' }
1313
</Typography>
1414
</Paper>

extensions/ohif-gradienthealth-extension/src/_shared/FormGeneratorComponent/fields/Textarea.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1-
import * as React from 'react';
2-
import { useMemo } from 'react';
1+
import React, { useState, useMemo, useEffect } from 'react';
32
import Paper from '@mui/material/Paper';
43
import TextField from '@mui/material/TextField';
54
import debounce from 'lodash.debounce';
65

76
export default function Textarea({formIndex, name, value, defaultValue, options, onChange}) {
8-
const [val, setVal] = React.useState(value !== null ? value : (defaultValue !== null ? defaultValue : ''));
7+
const [val, setVal] = useState(value ?? defaultValue ?? '');
98
const { rows } = options
109
const debouncedOnChange = useMemo(
1110
() => debounce((formIndex, value) => {
12-
onChange({formIndex, value})
13-
}, 600), [onChange]
11+
onChange({formIndex, value})
12+
}, 600), [onChange]
1413
);
1514

15+
useEffect(() => {
16+
setVal(value ?? defaultValue ?? '');
17+
}, [value, defaultValue]);
18+
1619
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
1720
setVal(event.target.value);
1821
debouncedOnChange(formIndex, event.target.value)

extensions/ohif-gradienthealth-extension/src/services/CacheAPIService/CacheAPIService.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,23 @@ export default class CacheAPIService {
119119
});
120120
}
121121

122-
public async cacheStudy(StudyInstanceUID) {
123-
await this.dataSource.retrieve.series.metadata({ StudyInstanceUID });
122+
public async cacheStudy(StudyInstanceUID, buckets = undefined) {
123+
const { sopClassUids: segSOPClassUIDs } =
124+
this.extensionManager.getModuleEntry(
125+
'@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg'
126+
);
127+
await this.dataSource.retrieve.series.metadata({
128+
StudyInstanceUID,
129+
buckets,
130+
});
124131
const study = DicomMetadataStore.getStudy(StudyInstanceUID);
125-
const imageIds = study.series.flatMap((serie) =>
126-
serie.instances.flatMap((instance) => instance.imageId)
127-
);
132+
const imageIds = study.series
133+
.filter(
134+
(serie) => !segSOPClassUIDs.includes(serie.instances[0].SOPClassUID)
135+
)
136+
.flatMap((serie) =>
137+
serie.instances.flatMap((instance) => instance.imageId)
138+
);
128139
this.cacheImageIds(imageIds);
129140
}
130141

extensions/ohif-gradienthealth-extension/src/services/GoogleSheetsService/GoogleSheetsService.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export default class GoogleSheetsService {
5757
const url = row[urlIndex];
5858
const params = new URLSearchParams('?' + url.split('?')[1]);
5959
const StudyInstanceUID = params.get('StudyInstanceUIDs');
60-
CacheAPIService.cacheStudy(StudyInstanceUID);
60+
CacheAPIService.cacheStudy(StudyInstanceUID, params.getAll('bucket'));
6161
});
6262
}
6363

@@ -254,12 +254,16 @@ export default class GoogleSheetsService {
254254
const url = rowValues[index];
255255
const params = new URLSearchParams('?' + url.split('?')[1]);
256256
const StudyInstanceUID = params.get('StudyInstanceUIDs');
257+
const buckets = params.getAll('bucket');
257258
if (!StudyInstanceUID) {
258259
window.location.href = `https://docs.google.com/spreadsheets/d/${this.sheetId}`;
259260
}
260261
const dataSource = this.extensionManager.getActiveDataSource()[0];
261-
await dataSource.retrieve.series.metadata({ StudyInstanceUID });
262+
await dataSource.retrieve.series.metadata({ StudyInstanceUID, buckets });
262263
const studies = [DicomMetadataStore.getStudy(StudyInstanceUID)];
264+
const activeProtocolId =
265+
HangingProtocolService.getActiveProtocol().protocol.id;
266+
HangingProtocolService.reset()
263267
HangingProtocolService.run(
264268
{
265269
studies,
@@ -270,11 +274,17 @@ export default class GoogleSheetsService {
270274
}
271275
),
272276
},
273-
'breast'
277+
activeProtocolId
274278
);
275279

276280
const nextParams = new URLSearchParams(window.location.search);
277281
nextParams.set('StudyInstanceUIDs', StudyInstanceUID);
282+
if (buckets.length) {
283+
nextParams.delete('bucket');
284+
buckets.forEach((bucket) => {
285+
nextParams.append('bucket', bucket);
286+
});
287+
}
278288
const nextURL =
279289
window.location.href.split('?')[0] + '?' + nextParams.toString();
280290
window.history.replaceState({}, null, nextURL);

0 commit comments

Comments
 (0)