From d3614b2963638d616ef61c07cf46c3f3542ad4bf Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Fri, 13 Dec 2024 00:22:18 -0500 Subject: [PATCH 01/14] case sensitive field for filtering --- .../default/src/DicomWebDataSource/index.js | 3 +++ .../utils/StaticWadoClient.ts | 25 ++++++++++++++----- platform/app/public/config/default.js | 1 + 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js index 206df45a51a..3410d772b93 100644 --- a/extensions/default/src/DicomWebDataSource/index.js +++ b/extensions/default/src/DicomWebDataSource/index.js @@ -54,6 +54,7 @@ const metadataProvider = classes.MetadataProvider; * @param {boolean} dicomWebConfig.bulkDataURI - Whether to enable bulkDataURI * @param {function} dicomWebConfig.onConfiguration - Function that is called after the configuration is initialized * @param {boolean} dicomWebConfig.staticWado - Whether to use the static WADO client + * @param {boolean} dicomWebConfig.caseSensitive - Whether to use case sensitive filtering on results (default: true) * @param {object} userAuthenticationService - User authentication service * @param {object} userAuthenticationService.getAuthorizationHeader - Function that returns the authorization header * @returns {object} - DICOM Web API object @@ -107,6 +108,7 @@ function createDicomWebApi(dicomWebConfig, servicesManager) { url: dicomWebConfig.qidoRoot, staticWado: dicomWebConfig.staticWado, singlepart: dicomWebConfig.singlepart, + caseSensitive: dicomWebConfig.caseSensitive, headers: userAuthenticationService.getAuthorizationHeader(), errorInterceptor: errorHandler.getHTTPErrorHandler(), }; @@ -115,6 +117,7 @@ function createDicomWebApi(dicomWebConfig, servicesManager) { url: dicomWebConfig.wadoRoot, staticWado: dicomWebConfig.staticWado, singlepart: dicomWebConfig.singlepart, + caseSensitive: dicomWebConfig.caseSensitive, headers: userAuthenticationService.getAuthorizationHeader(), errorInterceptor: errorHandler.getHTTPErrorHandler(), }; diff --git a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts index 519e8109c03..c59c410b2b7 100644 --- a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts +++ b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts @@ -111,9 +111,12 @@ export default class StaticWadoClient extends api.DICOMwebClient { } const lowerParams = this.toLowerParams(queryParams); + const caseSensitive = this.config.caseSensitive; const filtered = searchResult.filter(study => { for (const key of Object.keys(StaticWadoClient.studyFilterKeys)) { - if (!this.filterItem(key, lowerParams, study, StaticWadoClient.studyFilterKeys)) { + if ( + !this.filterItem(key, lowerParams, study, StaticWadoClient.studyFilterKeys, caseSensitive) + ) { return false; } } @@ -156,19 +159,28 @@ export default class StaticWadoClient extends api.DICOMwebClient { * * @param {*} desired * @param {*} actual + * @param {boolean} caseSensitive * @returns true if the values match */ - compareValues(desired, actual) { + compareValues(desired, actual, caseSensitive = true) { if (Array.isArray(desired)) { - return desired.find(item => this.compareValues(item, actual)); + return desired.find(item => this.compareValues(item, actual, caseSensitive)); } if (Array.isArray(actual)) { - return actual.find(actualItem => this.compareValues(desired, actualItem)); + return actual.find(actualItem => this.compareValues(desired, actualItem, caseSensitive)); } if (actual?.Alphabetic) { actual = actual.Alphabetic; } if (typeof actual == 'string') { + if (!caseSensitive) { + if (typeof desired === 'string') { + desired = desired.toLowerCase(); + } + if (typeof actual === 'string') { + actual = actual.toLowerCase(); + } + } if (actual.length === 0) { return true; } @@ -208,9 +220,10 @@ export default class StaticWadoClient extends api.DICOMwebClient { * @param queryParams - * @param {*} study * @param {*} sourceFilterMap + * @param {boolean} caseSensitive * @returns */ - filterItem(key: string, queryParams, study, sourceFilterMap) { + filterItem(key: string, queryParams, study, sourceFilterMap, caseSensitive = true) { const altKey = sourceFilterMap[key] || key; if (!queryParams) { return true; @@ -227,7 +240,7 @@ export default class StaticWadoClient extends api.DICOMwebClient { return this.compareDateRange(testValue, valueElem.Value[0]); } const value = valueElem.Value; - return this.compareValues(testValue, value); + return this.compareValues(testValue, value, caseSensitive); } /** Converts the query parameters to lower case query parameters */ diff --git a/platform/app/public/config/default.js b/platform/app/public/config/default.js index 0e5443099fa..8761ed3c1e6 100644 --- a/platform/app/public/config/default.js +++ b/platform/app/public/config/default.js @@ -52,6 +52,7 @@ window.config = { supportsFuzzyMatching: false, supportsWildcard: true, staticWado: true, + caseSensitive: false, singlepart: 'bulkdata,video', // whether the data source should use retrieveBulkData to grab metadata, // and in case of relative path, what would it be relative to, options From f5d206c7a0d4b762c5864bf1736c7e12dfebcfdd Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Fri, 13 Dec 2024 11:18:21 -0500 Subject: [PATCH 02/14] readme --- platform/docs/docs/configuration/configurationFiles.md | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/docs/docs/configuration/configurationFiles.md b/platform/docs/docs/configuration/configurationFiles.md index db24e8da95f..8f35c93d392 100644 --- a/platform/docs/docs/configuration/configurationFiles.md +++ b/platform/docs/docs/configuration/configurationFiles.md @@ -193,6 +193,7 @@ if auth headers are used, a preflight request is required. - `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 +- `caseSensitive`: (default to true), if set to false, it will allow static wado servers to have case in-sensitive matching for queries. please set this as the dataSources configuration, not in the main configuration. - `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.
Points to consider while using `dangerouslyUseDynamicConfig`:
- User have to enable this feature by setting `dangerouslyUseDynamicConfig.enabled:true`. By default it is `false`. From 52378b6124fabca5b7119ee8e7e1d2d272a857d0 Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Fri, 13 Dec 2024 11:59:12 -0500 Subject: [PATCH 03/14] update --- extensions/default/src/DicomWebDataSource/index.js | 6 +++--- .../src/DicomWebDataSource/utils/StaticWadoClient.ts | 9 +++++++-- platform/app/public/config/default.js | 4 +++- platform/docs/docs/configuration/configurationFiles.md | 7 ++++++- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js index 3410d772b93..eeff59d6987 100644 --- a/extensions/default/src/DicomWebDataSource/index.js +++ b/extensions/default/src/DicomWebDataSource/index.js @@ -54,7 +54,7 @@ const metadataProvider = classes.MetadataProvider; * @param {boolean} dicomWebConfig.bulkDataURI - Whether to enable bulkDataURI * @param {function} dicomWebConfig.onConfiguration - Function that is called after the configuration is initialized * @param {boolean} dicomWebConfig.staticWado - Whether to use the static WADO client - * @param {boolean} dicomWebConfig.caseSensitive - Whether to use case sensitive filtering on results (default: true) + * @param {object} dicomWebConfig.caseSensitive - Whether to use case sensitive filtering on results * @param {object} userAuthenticationService - User authentication service * @param {object} userAuthenticationService.getAuthorizationHeader - Function that returns the authorization header * @returns {object} - DICOM Web API object @@ -108,7 +108,7 @@ function createDicomWebApi(dicomWebConfig, servicesManager) { url: dicomWebConfig.qidoRoot, staticWado: dicomWebConfig.staticWado, singlepart: dicomWebConfig.singlepart, - caseSensitive: dicomWebConfig.caseSensitive, + caseSensitive: dicomWebConfig.caseSensitive || {}, headers: userAuthenticationService.getAuthorizationHeader(), errorInterceptor: errorHandler.getHTTPErrorHandler(), }; @@ -117,7 +117,7 @@ function createDicomWebApi(dicomWebConfig, servicesManager) { url: dicomWebConfig.wadoRoot, staticWado: dicomWebConfig.staticWado, singlepart: dicomWebConfig.singlepart, - caseSensitive: dicomWebConfig.caseSensitive, + caseSensitive: dicomWebConfig.caseSensitive || {}, headers: userAuthenticationService.getAuthorizationHeader(), errorInterceptor: errorHandler.getHTTPErrorHandler(), }; diff --git a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts index c59c410b2b7..0fc1cb3d77f 100644 --- a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts +++ b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts @@ -111,11 +111,16 @@ export default class StaticWadoClient extends api.DICOMwebClient { } const lowerParams = this.toLowerParams(queryParams); - const caseSensitive = this.config.caseSensitive; const filtered = searchResult.filter(study => { for (const key of Object.keys(StaticWadoClient.studyFilterKeys)) { if ( - !this.filterItem(key, lowerParams, study, StaticWadoClient.studyFilterKeys, caseSensitive) + !this.filterItem( + key, + lowerParams, + study, + StaticWadoClient.studyFilterKeys, + this.config.caseSensitive[key] + ) ) { return false; } diff --git a/platform/app/public/config/default.js b/platform/app/public/config/default.js index 8761ed3c1e6..7149f7337e3 100644 --- a/platform/app/public/config/default.js +++ b/platform/app/public/config/default.js @@ -52,7 +52,9 @@ window.config = { supportsFuzzyMatching: false, supportsWildcard: true, staticWado: true, - caseSensitive: false, + caseSensitive: { + patientname: false, + }, singlepart: 'bulkdata,video', // whether the data source should use retrieveBulkData to grab metadata, // and in case of relative path, what would it be relative to, options diff --git a/platform/docs/docs/configuration/configurationFiles.md b/platform/docs/docs/configuration/configurationFiles.md index 8f35c93d392..f7bdc85eeb7 100644 --- a/platform/docs/docs/configuration/configurationFiles.md +++ b/platform/docs/docs/configuration/configurationFiles.md @@ -193,7 +193,12 @@ if auth headers are used, a preflight request is required. - `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 -- `caseSensitive`: (default to true), if set to false, it will allow static wado servers to have case in-sensitive matching for queries. please set this as the dataSources configuration, not in the main configuration. +- `caseSensitive`: an object with filter keys that should be case sensitive. By default, all filters are case sensitive. If you want to set a filter to be case insensitive, you can set it to false. Example: + ```js + caseSensitive: { + patientname: false, + } + ``` - `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.
Points to consider while using `dangerouslyUseDynamicConfig`:
- User have to enable this feature by setting `dangerouslyUseDynamicConfig.enabled:true`. By default it is `false`. From f44124fbbfad1a495676ce80fc6b234a16c79a97 Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Fri, 20 Dec 2024 09:56:33 -0500 Subject: [PATCH 04/14] fix --- extensions/default/src/DicomWebDataSource/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extensions/default/src/DicomWebDataSource/index.ts b/extensions/default/src/DicomWebDataSource/index.ts index 6a915c0c351..b41335c0557 100644 --- a/extensions/default/src/DicomWebDataSource/index.ts +++ b/extensions/default/src/DicomWebDataSource/index.ts @@ -67,6 +67,8 @@ export type DicomWebConfig = { staticWado?: boolean; /** User authentication service */ userAuthenticationService: Record; + /** Case sensitivity configuration */ + caseSensitive?: Record; }; export type BulkDataURIConfig = { @@ -147,6 +149,7 @@ function createDicomWebApi(dicomWebConfig: DicomWebConfig, servicesManager) { qidoConfig = { url: dicomWebConfig.qidoRoot, + caseSensitive: dicomWebConfig.caseSensitive || {}, staticWado: dicomWebConfig.staticWado, singlepart: dicomWebConfig.singlepart, headers: userAuthenticationService.getAuthorizationHeader(), @@ -155,6 +158,7 @@ function createDicomWebApi(dicomWebConfig: DicomWebConfig, servicesManager) { wadoConfig = { url: dicomWebConfig.wadoRoot, + caseSensitive: dicomWebConfig.caseSensitive || {}, staticWado: dicomWebConfig.staticWado, singlepart: dicomWebConfig.singlepart, headers: userAuthenticationService.getAuthorizationHeader(), From 3965935856491f2f954ea69dcf2c67382fa639da Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Sat, 21 Dec 2024 15:30:06 -0500 Subject: [PATCH 05/14] updates --- .../utils/StaticWadoClient.ts | 27 +++++++------------ platform/app/public/config/default.js | 3 +++ platform/app/public/config/e2e.js | 12 +++++++++ .../docs/configuration/configurationFiles.md | 2 +- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts index 0fc1cb3d77f..1c9baf87766 100644 --- a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts +++ b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts @@ -113,15 +113,7 @@ export default class StaticWadoClient extends api.DICOMwebClient { const lowerParams = this.toLowerParams(queryParams); const filtered = searchResult.filter(study => { for (const key of Object.keys(StaticWadoClient.studyFilterKeys)) { - if ( - !this.filterItem( - key, - lowerParams, - study, - StaticWadoClient.studyFilterKeys, - this.config.caseSensitive[key] - ) - ) { + if (!this.filterItem(key, lowerParams, study, StaticWadoClient.studyFilterKeys)) { return false; } } @@ -177,15 +169,15 @@ export default class StaticWadoClient extends api.DICOMwebClient { if (actual?.Alphabetic) { actual = actual.Alphabetic; } + if (typeof actual == 'string') { if (!caseSensitive) { - if (typeof desired === 'string') { - desired = desired.toLowerCase(); - } - if (typeof actual === 'string') { - actual = actual.toLowerCase(); - } + desired = desired.toLowerCase(); + actual = actual.toLowerCase(); } + } + + if (typeof actual == 'string') { if (actual.length === 0) { return true; } @@ -225,10 +217,9 @@ export default class StaticWadoClient extends api.DICOMwebClient { * @param queryParams - * @param {*} study * @param {*} sourceFilterMap - * @param {boolean} caseSensitive * @returns */ - filterItem(key: string, queryParams, study, sourceFilterMap, caseSensitive = true) { + filterItem(key: string, queryParams, study, sourceFilterMap) { const altKey = sourceFilterMap[key] || key; if (!queryParams) { return true; @@ -245,6 +236,8 @@ export default class StaticWadoClient extends api.DICOMwebClient { return this.compareDateRange(testValue, valueElem.Value[0]); } const value = valueElem.Value; + const caseSensitive = this.config.caseSensitive[key]; + return this.compareValues(testValue, value, caseSensitive); } diff --git a/platform/app/public/config/default.js b/platform/app/public/config/default.js index 7149f7337e3..c4cb16b344c 100644 --- a/platform/app/public/config/default.js +++ b/platform/app/public/config/default.js @@ -54,6 +54,9 @@ window.config = { staticWado: true, caseSensitive: { patientname: false, + studydescription: false, + accessionnumber: false, + '00100020': false, }, singlepart: 'bulkdata,video', // whether the data source should use retrieveBulkData to grab metadata, diff --git a/platform/app/public/config/e2e.js b/platform/app/public/config/e2e.js index 25fab2917aa..d3937fd098b 100644 --- a/platform/app/public/config/e2e.js +++ b/platform/app/public/config/e2e.js @@ -46,6 +46,12 @@ window.config = { relativeResolution: 'studies', transform: url => url.replace('/pixeldata.mp4', '/index.mp4'), }, + caseSensitive: { + patientname: false, + studydescription: false, + accessionnumber: false, + '00100020': false, + }, }, }, { @@ -118,6 +124,12 @@ window.config = { relativeResolution: 'studies', transform: url => url.replace('/pixeldata.mp4', '/rendered'), }, + caseSensitive: { + patientname: false, + studydescription: false, + accessionnumber: false, + '00100020': false, + }, }, }, diff --git a/platform/docs/docs/configuration/configurationFiles.md b/platform/docs/docs/configuration/configurationFiles.md index f7bdc85eeb7..a2126183633 100644 --- a/platform/docs/docs/configuration/configurationFiles.md +++ b/platform/docs/docs/configuration/configurationFiles.md @@ -193,7 +193,7 @@ if auth headers are used, a preflight request is required. - `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 -- `caseSensitive`: an object with filter keys that should be case sensitive. By default, all filters are case sensitive. If you want to set a filter to be case insensitive, you can set it to false. Example: +- `caseSensitive`: an object with filter keys that should be case sensitive, only works on STATIC-WADO backends. By default, all filters are case sensitive. If you want to set a filter to be case insensitive, you can set it to false. Example: ```js caseSensitive: { patientname: false, From 6039fbb544716f3d303667f173eda679aa58cf96 Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Sat, 21 Dec 2024 15:31:34 -0500 Subject: [PATCH 06/14] doc --- platform/docs/docs/configuration/configurationFiles.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/docs/docs/configuration/configurationFiles.md b/platform/docs/docs/configuration/configurationFiles.md index a2126183633..f7865332d36 100644 --- a/platform/docs/docs/configuration/configurationFiles.md +++ b/platform/docs/docs/configuration/configurationFiles.md @@ -197,6 +197,9 @@ if auth headers are used, a preflight request is required. ```js caseSensitive: { patientname: false, + studydescription: false, + accessionnumber: false, + '00100020': false, } ``` - `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.
From 1871db4cf61c7c5ec44bfafecebb529df36945d5 Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Sun, 26 Jan 2025 20:34:54 -0500 Subject: [PATCH 07/14] remove --- extensions/default/src/DicomWebDataSource/index.ts | 4 ---- .../DicomWebDataSource/utils/StaticWadoClient.ts | 14 +++++--------- .../docs/docs/configuration/configurationFiles.md | 9 --------- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/extensions/default/src/DicomWebDataSource/index.ts b/extensions/default/src/DicomWebDataSource/index.ts index 676b54bbb6c..6bf6c4e12d3 100644 --- a/extensions/default/src/DicomWebDataSource/index.ts +++ b/extensions/default/src/DicomWebDataSource/index.ts @@ -67,8 +67,6 @@ export type DicomWebConfig = { staticWado?: boolean; /** User authentication service */ userAuthenticationService: Record; - /** Case sensitivity configuration */ - caseSensitive?: Record; }; export type BulkDataURIConfig = { @@ -149,7 +147,6 @@ function createDicomWebApi(dicomWebConfig: DicomWebConfig, servicesManager) { qidoConfig = { url: dicomWebConfig.qidoRoot, - caseSensitive: dicomWebConfig.caseSensitive || {}, staticWado: dicomWebConfig.staticWado, singlepart: dicomWebConfig.singlepart, headers: userAuthenticationService.getAuthorizationHeader(), @@ -158,7 +155,6 @@ function createDicomWebApi(dicomWebConfig: DicomWebConfig, servicesManager) { wadoConfig = { url: dicomWebConfig.wadoRoot, - caseSensitive: dicomWebConfig.caseSensitive || {}, staticWado: dicomWebConfig.staticWado, singlepart: dicomWebConfig.singlepart, headers: userAuthenticationService.getAuthorizationHeader(), diff --git a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts index 1c9baf87766..c8a1c834bbf 100644 --- a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts +++ b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts @@ -156,25 +156,22 @@ export default class StaticWadoClient extends api.DICOMwebClient { * * @param {*} desired * @param {*} actual - * @param {boolean} caseSensitive * @returns true if the values match */ compareValues(desired, actual, caseSensitive = true) { if (Array.isArray(desired)) { - return desired.find(item => this.compareValues(item, actual, caseSensitive)); + return desired.find(item => this.compareValues(item, actual)); } if (Array.isArray(actual)) { - return actual.find(actualItem => this.compareValues(desired, actualItem, caseSensitive)); + return actual.find(actualItem => this.compareValues(desired, actualItem)); } if (actual?.Alphabetic) { actual = actual.Alphabetic; } if (typeof actual == 'string') { - if (!caseSensitive) { - desired = desired.toLowerCase(); - actual = actual.toLowerCase(); - } + desired = desired.toLowerCase(); + actual = actual.toLowerCase(); } if (typeof actual == 'string') { @@ -236,9 +233,8 @@ export default class StaticWadoClient extends api.DICOMwebClient { return this.compareDateRange(testValue, valueElem.Value[0]); } const value = valueElem.Value; - const caseSensitive = this.config.caseSensitive[key]; - return this.compareValues(testValue, value, caseSensitive); + return this.compareValues(testValue, value); } /** Converts the query parameters to lower case query parameters */ diff --git a/platform/docs/docs/configuration/configurationFiles.md b/platform/docs/docs/configuration/configurationFiles.md index f7865332d36..db24e8da95f 100644 --- a/platform/docs/docs/configuration/configurationFiles.md +++ b/platform/docs/docs/configuration/configurationFiles.md @@ -193,15 +193,6 @@ if auth headers are used, a preflight request is required. - `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 -- `caseSensitive`: an object with filter keys that should be case sensitive, only works on STATIC-WADO backends. By default, all filters are case sensitive. If you want to set a filter to be case insensitive, you can set it to false. Example: - ```js - caseSensitive: { - patientname: false, - studydescription: false, - accessionnumber: false, - '00100020': false, - } - ``` - `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.
Points to consider while using `dangerouslyUseDynamicConfig`:
- User have to enable this feature by setting `dangerouslyUseDynamicConfig.enabled:true`. By default it is `false`. From e64042c1f96be0eed1de550aa07d030c851f8059 Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Sun, 26 Jan 2025 20:35:55 -0500 Subject: [PATCH 08/14] updates --- .../src/DicomWebDataSource/utils/StaticWadoClient.ts | 5 ----- platform/app/public/config/default.js | 8 +------- platform/app/public/config/e2e.js | 12 ------------ 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts index c8a1c834bbf..ebc2d0892c8 100644 --- a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts +++ b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts @@ -169,11 +169,6 @@ export default class StaticWadoClient extends api.DICOMwebClient { actual = actual.Alphabetic; } - if (typeof actual == 'string') { - desired = desired.toLowerCase(); - actual = actual.toLowerCase(); - } - if (typeof actual == 'string') { if (actual.length === 0) { return true; diff --git a/platform/app/public/config/default.js b/platform/app/public/config/default.js index ba63736e836..ce88ee277ab 100644 --- a/platform/app/public/config/default.js +++ b/platform/app/public/config/default.js @@ -50,15 +50,9 @@ window.config = { imageRendering: 'wadors', thumbnailRendering: 'wadors', enableStudyLazyLoad: true, - supportsFuzzyMatching: false, + supportsFuzzyMatching: true, supportsWildcard: true, staticWado: true, - caseSensitive: { - patientname: false, - studydescription: false, - accessionnumber: false, - '00100020': false, - }, singlepart: 'bulkdata,video', // whether the data source should use retrieveBulkData to grab metadata, // and in case of relative path, what would it be relative to, options diff --git a/platform/app/public/config/e2e.js b/platform/app/public/config/e2e.js index d3937fd098b..25fab2917aa 100644 --- a/platform/app/public/config/e2e.js +++ b/platform/app/public/config/e2e.js @@ -46,12 +46,6 @@ window.config = { relativeResolution: 'studies', transform: url => url.replace('/pixeldata.mp4', '/index.mp4'), }, - caseSensitive: { - patientname: false, - studydescription: false, - accessionnumber: false, - '00100020': false, - }, }, }, { @@ -124,12 +118,6 @@ window.config = { relativeResolution: 'studies', transform: url => url.replace('/pixeldata.mp4', '/rendered'), }, - caseSensitive: { - patientname: false, - studydescription: false, - accessionnumber: false, - '00100020': false, - }, }, }, From bcdebdd5cc264dae1e04efdb1e86ff227deb60b9 Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Sun, 26 Jan 2025 21:01:00 -0500 Subject: [PATCH 09/14] updates --- .../default/src/DicomWebDataSource/index.ts | 2 ++ .../utils/StaticWadoClient.ts | 28 ++++++++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/extensions/default/src/DicomWebDataSource/index.ts b/extensions/default/src/DicomWebDataSource/index.ts index 6bf6c4e12d3..735a4028ea5 100644 --- a/extensions/default/src/DicomWebDataSource/index.ts +++ b/extensions/default/src/DicomWebDataSource/index.ts @@ -151,6 +151,7 @@ function createDicomWebApi(dicomWebConfig: DicomWebConfig, servicesManager) { singlepart: dicomWebConfig.singlepart, headers: userAuthenticationService.getAuthorizationHeader(), errorInterceptor: errorHandler.getHTTPErrorHandler(), + supportsFuzzyMatching: dicomWebConfig.supportsFuzzyMatching, }; wadoConfig = { @@ -159,6 +160,7 @@ function createDicomWebApi(dicomWebConfig: DicomWebConfig, servicesManager) { singlepart: dicomWebConfig.singlepart, headers: userAuthenticationService.getAuthorizationHeader(), errorInterceptor: errorHandler.getHTTPErrorHandler(), + supportsFuzzyMatching: dicomWebConfig.supportsFuzzyMatching, }; // TODO -> Two clients sucks, but its better than 1000. diff --git a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts index ebc2d0892c8..4bb37b15119 100644 --- a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts +++ b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts @@ -156,19 +156,36 @@ export default class StaticWadoClient extends api.DICOMwebClient { * * @param {*} desired * @param {*} actual + * @param {*} fuzzyMatching - if true, then do a sub-string match on the values * @returns true if the values match */ - compareValues(desired, actual, caseSensitive = true) { + compareValues(desired, actual, fuzzyMatching) { if (Array.isArray(desired)) { - return desired.find(item => this.compareValues(item, actual)); + return desired.find(item => this.compareValues(item, actual, fuzzyMatching)); } if (Array.isArray(actual)) { - return actual.find(actualItem => this.compareValues(desired, actualItem)); + return actual.find(actualItem => this.compareValues(desired, actualItem, fuzzyMatching)); } if (actual?.Alphabetic) { actual = actual.Alphabetic; } + if (fuzzyMatching && typeof actual === 'string' && typeof desired === 'string') { + const normalizeValue = str => str.replace(/^\*+|\*+$/g, '').toLowerCase(); + + const normalizedDesired = normalizeValue(desired); + const normalizedActual = normalizeValue(actual); + + const tokenizeAndNormalize = str => str.replace(/\^/g, ' ').split(/\s+/).filter(Boolean); + + const desiredTokens = tokenizeAndNormalize(normalizedDesired); + const actualTokens = tokenizeAndNormalize(normalizedActual); + + return desiredTokens.some(desiredToken => + actualTokens.some(actualToken => actualToken.startsWith(desiredToken)) + ); + } + if (typeof actual == 'string') { if (actual.length === 0) { return true; @@ -212,6 +229,9 @@ export default class StaticWadoClient extends api.DICOMwebClient { * @returns */ filterItem(key: string, queryParams, study, sourceFilterMap) { + const { supportsFuzzyMatching = false } = this.config; + const isPatientName = key === 'patientname'; + const altKey = sourceFilterMap[key] || key; if (!queryParams) { return true; @@ -229,7 +249,7 @@ export default class StaticWadoClient extends api.DICOMwebClient { } const value = valueElem.Value; - return this.compareValues(testValue, value); + return this.compareValues(testValue, value, supportsFuzzyMatching && isPatientName); } /** Converts the query parameters to lower case query parameters */ From 9bdf4d5b567a39b4fe43951e7e8df5b54fa454e4 Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Mon, 27 Jan 2025 09:36:58 -0500 Subject: [PATCH 10/14] fix --- .../src/DicomWebDataSource/utils/StaticWadoClient.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts index 4bb37b15119..e557b536343 100644 --- a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts +++ b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts @@ -171,7 +171,15 @@ export default class StaticWadoClient extends api.DICOMwebClient { } if (fuzzyMatching && typeof actual === 'string' && typeof desired === 'string') { - const normalizeValue = str => str.replace(/^\*+|\*+$/g, '').toLowerCase(); + const normalizeValue = str => { + if (str.startsWith('*')) { + str = str.slice(1); + } + if (str.endsWith('*')) { + str = str.slice(0, -1); + } + return str.toLowerCase(); + }; const normalizedDesired = normalizeValue(desired); const normalizedActual = normalizeValue(actual); From e5b297dc5740494225d876e7bef91c1bceefdfc0 Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Mon, 27 Jan 2025 10:08:50 -0500 Subject: [PATCH 11/14] fixes --- .../src/DicomWebDataSource/utils/StaticWadoClient.ts | 10 ++-------- platform/app/public/config/default.js | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts index e557b536343..5372cb6688f 100644 --- a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts +++ b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts @@ -172,24 +172,18 @@ export default class StaticWadoClient extends api.DICOMwebClient { if (fuzzyMatching && typeof actual === 'string' && typeof desired === 'string') { const normalizeValue = str => { - if (str.startsWith('*')) { - str = str.slice(1); - } - if (str.endsWith('*')) { - str = str.slice(0, -1); - } return str.toLowerCase(); }; const normalizedDesired = normalizeValue(desired); const normalizedActual = normalizeValue(actual); - const tokenizeAndNormalize = str => str.replace(/\^/g, ' ').split(/\s+/).filter(Boolean); + const tokenizeAndNormalize = str => str.split(/[\s^]+/).filter(Boolean); const desiredTokens = tokenizeAndNormalize(normalizedDesired); const actualTokens = tokenizeAndNormalize(normalizedActual); - return desiredTokens.some(desiredToken => + return desiredTokens.every(desiredToken => actualTokens.some(actualToken => actualToken.startsWith(desiredToken)) ); } diff --git a/platform/app/public/config/default.js b/platform/app/public/config/default.js index ce88ee277ab..c3a6c1ba775 100644 --- a/platform/app/public/config/default.js +++ b/platform/app/public/config/default.js @@ -51,7 +51,7 @@ window.config = { thumbnailRendering: 'wadors', enableStudyLazyLoad: true, supportsFuzzyMatching: true, - supportsWildcard: true, + supportsWildcard: false, staticWado: true, singlepart: 'bulkdata,video', // whether the data source should use retrieveBulkData to grab metadata, From 2c2683c8dd1fe87dd7c8a02c5a31f30d476a038f Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Mon, 27 Jan 2025 10:14:50 -0500 Subject: [PATCH 12/14] update --- platform/docs/docs/user-guide/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/docs/docs/user-guide/index.md b/platform/docs/docs/user-guide/index.md index 52f44bad8cb..f40ef30df23 100644 --- a/platform/docs/docs/user-guide/index.md +++ b/platform/docs/docs/user-guide/index.md @@ -44,6 +44,8 @@ Below the study list are pagination options for 25, 50, or 100 studies per page. ![user-study-next](../assets/img/user-study-next.png) +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. From 4cdea43867a285a18dd54ced0bce5bf6f9b6b0ed Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Mon, 27 Jan 2025 10:23:47 -0500 Subject: [PATCH 13/14] indexOf name --- .../default/src/DicomWebDataSource/utils/StaticWadoClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts index 5372cb6688f..fa0e548c148 100644 --- a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts +++ b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts @@ -232,7 +232,7 @@ export default class StaticWadoClient extends api.DICOMwebClient { */ filterItem(key: string, queryParams, study, sourceFilterMap) { const { supportsFuzzyMatching = false } = this.config; - const isPatientName = key === 'patientname'; + const isPatientName = key.indexOf('name') !== -1; const altKey = sourceFilterMap[key] || key; if (!queryParams) { From 31c006b0918ecb0eaafe0f124d80e13219382cdf Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Mon, 27 Jan 2025 10:31:48 -0500 Subject: [PATCH 14/14] fixes --- .../utils/StaticWadoClient.ts | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts index fa0e548c148..a34cc9d9a94 100644 --- a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts +++ b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts @@ -156,15 +156,17 @@ export default class StaticWadoClient extends api.DICOMwebClient { * * @param {*} desired * @param {*} actual - * @param {*} fuzzyMatching - if true, then do a sub-string match on the values + * @param {*} options - fuzzyMatching: if true, then do a sub-string match * @returns true if the values match */ - compareValues(desired, actual, fuzzyMatching) { + compareValues(desired, actual, options) { + const { fuzzyMatching } = options; + if (Array.isArray(desired)) { - return desired.find(item => this.compareValues(item, actual, fuzzyMatching)); + return desired.find(item => this.compareValues(item, actual, options)); } if (Array.isArray(actual)) { - return actual.find(actualItem => this.compareValues(desired, actualItem, fuzzyMatching)); + return actual.find(actualItem => this.compareValues(desired, actualItem, options)); } if (actual?.Alphabetic) { actual = actual.Alphabetic; @@ -214,7 +216,7 @@ export default class StaticWadoClient extends api.DICOMwebClient { } const dash = range.indexOf('-'); if (dash === -1) { - return this.compareValues(range, value); + return this.compareValues(range, value, {}); } const start = range.substring(0, dash); const end = range.substring(dash + 1); @@ -231,8 +233,13 @@ export default class StaticWadoClient extends api.DICOMwebClient { * @returns */ filterItem(key: string, queryParams, study, sourceFilterMap) { + const isName = (key: string) => key.indexOf('name') !== -1; + const { supportsFuzzyMatching = false } = this.config; - const isPatientName = key.indexOf('name') !== -1; + + const options = { + fuzzyMatching: isName(key) && supportsFuzzyMatching, + }; const altKey = sourceFilterMap[key] || key; if (!queryParams) { @@ -251,7 +258,7 @@ export default class StaticWadoClient extends api.DICOMwebClient { } const value = valueElem.Value; - return this.compareValues(testValue, value, supportsFuzzyMatching && isPatientName); + return this.compareValues(testValue, value, options); } /** Converts the query parameters to lower case query parameters */