diff --git a/extensions/default/src/DicomWebDataSource/index.ts b/extensions/default/src/DicomWebDataSource/index.ts index 8bc63603a..d9ee04320 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 519e8109c..a34cc9d9a 100644 --- a/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts +++ b/extensions/default/src/DicomWebDataSource/utils/StaticWadoClient.ts @@ -156,18 +156,40 @@ export default class StaticWadoClient extends api.DICOMwebClient { * * @param {*} desired * @param {*} actual + * @param {*} options - fuzzyMatching: if true, then do a sub-string match * @returns true if the values match */ - compareValues(desired, actual) { + compareValues(desired, actual, options) { + const { fuzzyMatching } = options; + if (Array.isArray(desired)) { - return desired.find(item => this.compareValues(item, actual)); + return desired.find(item => this.compareValues(item, actual, options)); } if (Array.isArray(actual)) { - return actual.find(actualItem => this.compareValues(desired, actualItem)); + return actual.find(actualItem => this.compareValues(desired, actualItem, options)); } if (actual?.Alphabetic) { actual = actual.Alphabetic; } + + if (fuzzyMatching && typeof actual === 'string' && typeof desired === 'string') { + const normalizeValue = str => { + return str.toLowerCase(); + }; + + const normalizedDesired = normalizeValue(desired); + const normalizedActual = normalizeValue(actual); + + const tokenizeAndNormalize = str => str.split(/[\s^]+/).filter(Boolean); + + const desiredTokens = tokenizeAndNormalize(normalizedDesired); + const actualTokens = tokenizeAndNormalize(normalizedActual); + + return desiredTokens.every(desiredToken => + actualTokens.some(actualToken => actualToken.startsWith(desiredToken)) + ); + } + if (typeof actual == 'string') { if (actual.length === 0) { return true; @@ -194,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); @@ -211,6 +233,14 @@ 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 options = { + fuzzyMatching: isName(key) && supportsFuzzyMatching, + }; + const altKey = sourceFilterMap[key] || key; if (!queryParams) { return true; @@ -227,7 +257,8 @@ 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, options); } /** 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 4b998b16d..901f8ea30 100644 --- a/platform/app/public/config/default.js +++ b/platform/app/public/config/default.js @@ -111,8 +111,8 @@ window.config = { imageRendering: 'wadors', thumbnailRendering: 'wadors', enableStudyLazyLoad: true, - supportsFuzzyMatching: false, - supportsWildcard: true, + supportsFuzzyMatching: true, + supportsWildcard: false, staticWado: true, singlepart: 'bulkdata,video', // whether the data source should use retrieveBulkData to grab metadata, diff --git a/platform/docs/docs/user-guide/index.md b/platform/docs/docs/user-guide/index.md index 52f44bad8..f40ef30df 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.