From d3614b2963638d616ef61c07cf46c3f3542ad4bf Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Fri, 13 Dec 2024 00:22:18 -0500 Subject: [PATCH 1/6] 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 2/6] 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 3/6] 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 4/6] 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 5/6] 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 6/6] 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.