From fb53555bfb1183b659834d08a1ffa8303e2defcf Mon Sep 17 00:00:00 2001 From: Mary McGrath Date: Mon, 18 Nov 2024 12:54:04 -0500 Subject: [PATCH 01/13] fix: lab value display --- .../src/app/services/formatService.tsx | 39 +++++++++++++++---- .../src/app/services/labsService.tsx | 28 +++++++------ .../ecr-viewer/src/app/tests/utils.test.tsx | 8 ++++ .../app/view-data/components/DataDisplay.tsx | 2 +- 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/containers/ecr-viewer/src/app/services/formatService.tsx b/containers/ecr-viewer/src/app/services/formatService.tsx index 2a2edcb32f..ac81a1a090 100644 --- a/containers/ecr-viewer/src/app/services/formatService.tsx +++ b/containers/ecr-viewer/src/app/services/formatService.tsx @@ -2,6 +2,7 @@ import React from "react"; import { ToolTipElement } from "@/app/view-data/components/ToolTipElement"; import { ContactPoint } from "fhir/r4"; import { sanitizeAndMap } from "../view-data/utils/utils"; +import parse from "html-react-parser"; interface Metadata { [key: string]: string; @@ -26,6 +27,8 @@ export interface TableJson { tables?: TableRow[][]; } +export type TableValue = string | React.JSX.Element | React.JSX.Element[]; + /** * Formats a person's name using given name(s), family name, optional prefix(es), and optional suffix(es). * @param given - Optional array of given name(s). @@ -359,9 +362,7 @@ export function formatTablesToJSON(htmlString: string): TableJson[] { const tables: any[] = []; const resultId = getDataId(li); const firstChildNode = getFirstNonCommentChild(li); - const resultName = firstChildNode - ? getElementContent(firstChildNode) - : ""; + const resultName = firstChildNode ? getElementText(firstChildNode) : ""; li.querySelectorAll("table").forEach((table) => { tables.push(processTable(table)); }); @@ -375,7 +376,7 @@ export function formatTablesToJSON(htmlString: string): TableJson[] { const tableWithCaptionArray = doc.querySelectorAll("table:has(caption)"); if (tableWithCaptionArray.length > 0) { doc.querySelectorAll("table").forEach((table) => { - const resultName = getElementContent(table.caption as Node); + const resultName = getElementText(table.caption as Element); const resultId = getDataId(table) ?? undefined; jsonArray.push({ resultId, resultName, tables: [processTable(table)] }); }); @@ -387,7 +388,7 @@ export function formatTablesToJSON(htmlString: string): TableJson[] { const contentArray = doc.querySelectorAll("content"); if (contentArray.length > 0) { contentArray.forEach((content) => { - const resultName = getElementContent(content); + const resultName = getElementText(content); const tables: any[] = []; let sibling = content.nextElementSibling; @@ -457,7 +458,7 @@ function processTable(table: Element): TableRow[] { if (headers.length > 0) { hasHeaders = true; headers.forEach((header) => { - keys.push(getElementContent(header)); + keys.push(getElementText(header)); }); } @@ -489,8 +490,30 @@ function processTable(table: Element): TableRow[] { return jsonArray; } -function getElementContent(el: Node): string { - return sanitizeAndMap(el.textContent?.trim() ?? ""); +/** + * Extracts the html content from an element and sanitizes and maps it so it is safe to render. + * @param el - An HTML element or node. + * @returns A sanitized and parsed snippet of JSX. + * @example @param el - Values here + * @example @returns -

Values here

+ */ +function getElementContent(el: Element | Node): TableValue { + const rawValue = (el as Element)?.innerHTML ?? el.textContent; + const value = rawValue?.trim() ?? ""; + if (value === "") return value; + const res = parse(sanitizeAndMap(value)); + return res; +} + +/** + * Extracts the text content from an element and concatenates it. + * @param el - An HTML element or node. + * @returns A string with the text data. + * @example @param el - Values here + * @example @returns - 'Values here' + */ +function getElementText(el: Element | Node): string { + return el.textContent?.trim() ?? ""; } /** diff --git a/containers/ecr-viewer/src/app/services/labsService.tsx b/containers/ecr-viewer/src/app/services/labsService.tsx index 60c69a8851..eb4abd1809 100644 --- a/containers/ecr-viewer/src/app/services/labsService.tsx +++ b/containers/ecr-viewer/src/app/services/labsService.tsx @@ -15,6 +15,7 @@ import { formatAddress, formatPhoneNumber, TableJson, + TableValue, } from "@/app/services/formatService"; import { Coding, ObservationComponent } from "fhir/r4b"; import EvaluateTable, { @@ -119,15 +120,18 @@ export const checkAbnormalTag = (labReportJson: TableJson): boolean => { * @example result - JSON object that contains the tables for all lab reports * @example searchKey - Ex. "Analysis Time" or the field that we are searching data for. */ -export function searchResultRecord(result: any[], searchKey: string) { - let resultsArray: any[] = []; +export function searchResultRecord( + result: any[], + searchKey: string, +): TableValue[] { + let resultsArray: TableValue[] = []; // Loop through each table for (const table of result) { // For each table, recursively search through all nodes if (Array.isArray(table)) { - const nestedResult: string = searchResultRecord(table, searchKey); - if (nestedResult) { + const nestedResult = searchResultRecord(table, searchKey); + if (nestedResult.length > 0) { return nestedResult; } } else { @@ -145,7 +149,7 @@ export function searchResultRecord(result: any[], searchKey: string) { } } } - return [...new Set(resultsArray)].join(", "); + return [...new Set(resultsArray)]; } /** @@ -229,7 +233,7 @@ const returnReceivedTime = ( export const returnFieldValueFromLabHtmlString = ( labReportJson: TableJson, fieldName: string, -): React.ReactNode => { +): React.ReactNode | TableValue[] => { if (!labReportJson) { return noData; } @@ -259,11 +263,13 @@ const returnAnalysisTime = ( return noData; } - const analysisTimeArray = - typeof fieldVals === "string" ? fieldVals.split(", ") : []; - const analysisTimeArrayFormatted = analysisTimeArray.map((dateTime) => { - return formatDateTime(dateTime); - }); + const analysisTimeArrayFormatted = (fieldVals as TableValue[]).map( + (dateTime) => { + const dateTimeNode = parse(`

${dateTime}

`); + console.log({ dateTime, typeofdate: typeof dateTimeNode, dateTimeNode }); + return formatDateTime(dateTime); + }, + ); return [...new Set(analysisTimeArrayFormatted)].join(", "); }; diff --git a/containers/ecr-viewer/src/app/tests/utils.test.tsx b/containers/ecr-viewer/src/app/tests/utils.test.tsx index 6432306001..b38b9dc643 100644 --- a/containers/ecr-viewer/src/app/tests/utils.test.tsx +++ b/containers/ecr-viewer/src/app/tests/utils.test.tsx @@ -565,5 +565,13 @@ describe("Utils", () => { `

hi there

I'm content`, ); }); + + it("should remove comments", () => { + const html = `hi thereI'm contentonetwo`; + const actual = sanitizeAndMap(html); + expect(actual).toBe( + `

hi there

I'm content`, + ); + }); }); }); diff --git a/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx b/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx index 565a7a7aae..36d6b94493 100644 --- a/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx +++ b/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx @@ -41,7 +41,7 @@ export const DataDisplay: React.FC<{
Date: Mon, 18 Nov 2024 18:29:24 -0500 Subject: [PATCH 02/13] fix: fold in parsing with sanitizing, add keys, remove arrs --- .../src/app/services/formatService.tsx | 7 ++- .../src/app/services/labsService.tsx | 19 ++++--- .../app/tests/services/labsService.test.tsx | 29 ++++++----- .../ecr-viewer/src/app/tests/utils.test.tsx | 48 ++++++++++++------ .../app/view-data/components/DataDisplay.tsx | 1 + .../src/app/view-data/components/common.tsx | 11 ++-- .../src/app/view-data/utils/utils.tsx | 50 +++++++++++++++---- 7 files changed, 110 insertions(+), 55 deletions(-) diff --git a/containers/ecr-viewer/src/app/services/formatService.tsx b/containers/ecr-viewer/src/app/services/formatService.tsx index ac81a1a090..a827457ec5 100644 --- a/containers/ecr-viewer/src/app/services/formatService.tsx +++ b/containers/ecr-viewer/src/app/services/formatService.tsx @@ -1,8 +1,7 @@ import React from "react"; import { ToolTipElement } from "@/app/view-data/components/ToolTipElement"; import { ContactPoint } from "fhir/r4"; -import { sanitizeAndMap } from "../view-data/utils/utils"; -import parse from "html-react-parser"; +import { parseSanitizeAndMap } from "../view-data/utils/utils"; interface Metadata { [key: string]: string; @@ -27,7 +26,7 @@ export interface TableJson { tables?: TableRow[][]; } -export type TableValue = string | React.JSX.Element | React.JSX.Element[]; +export type TableValue = string | React.JSX.Element; /** * Formats a person's name using given name(s), family name, optional prefix(es), and optional suffix(es). @@ -501,7 +500,7 @@ function getElementContent(el: Element | Node): TableValue { const rawValue = (el as Element)?.innerHTML ?? el.textContent; const value = rawValue?.trim() ?? ""; if (value === "") return value; - const res = parse(sanitizeAndMap(value)); + let res = parseSanitizeAndMap(value); return res; } diff --git a/containers/ecr-viewer/src/app/services/labsService.tsx b/containers/ecr-viewer/src/app/services/labsService.tsx index eb4abd1809..1fa0da84b6 100644 --- a/containers/ecr-viewer/src/app/services/labsService.tsx +++ b/containers/ecr-viewer/src/app/services/labsService.tsx @@ -3,10 +3,9 @@ import { Bundle, Device, Observation, Organization, Reference } from "fhir/r4"; import { PathMappings, noData, - sanitizeAndMap, + parseSanitizeAndMap, } from "@/app/view-data/utils/utils"; import { evaluate } from "@/app/view-data/utils/evaluate"; -import parse from "html-react-parser"; import { AccordionLabResults } from "@/app/view-data/components/AccordionLabResults"; import { formatDateTime, @@ -264,9 +263,15 @@ const returnAnalysisTime = ( } const analysisTimeArrayFormatted = (fieldVals as TableValue[]).map( - (dateTime) => { - const dateTimeNode = parse(`

${dateTime}

`); - console.log({ dateTime, typeofdate: typeof dateTimeNode, dateTimeNode }); + (rawDateTime) => { + let dateTime; + if (typeof rawDateTime === "string") { + dateTime = rawDateTime; + } else if (typeof rawDateTime.props.children === "string") { + dateTime = rawDateTime.props.children; + } else { + return ""; + } return formatDateTime(dateTime); }, ); @@ -347,7 +352,7 @@ export const evaluateDiagnosticReportData = ( infoPath: "observationDeviceReference", applyToValue: (ref) => { const device = evaluateReference(fhirBundle, mappings, ref) as Device; - return parse(sanitizeAndMap(device.deviceName?.[0]?.name ?? "")); + return parseSanitizeAndMap(device.deviceName?.[0]?.name ?? ""); }, className: "minw-10 width-20", }, @@ -355,7 +360,7 @@ export const evaluateDiagnosticReportData = ( columnName: "Lab Comment", infoPath: "observationNote", hiddenBaseText: "comment", - applyToValue: (v) => parse(sanitizeAndMap(v)), + applyToValue: (v) => parseSanitizeAndMap(v), className: "minw-10 width-20", }, ]; diff --git a/containers/ecr-viewer/src/app/tests/services/labsService.test.tsx b/containers/ecr-viewer/src/app/tests/services/labsService.test.tsx index ea05560b05..3e29014ae7 100644 --- a/containers/ecr-viewer/src/app/tests/services/labsService.test.tsx +++ b/containers/ecr-viewer/src/app/tests/services/labsService.test.tsx @@ -43,7 +43,7 @@ const labReportNormalJsonObject = { Value: { value: "Not Detected", metadata: {} }, "Ref Range": { value: "Not Detected", metadata: {} }, "Test Method": { - value: "LAB DEVICE: BIOFIRE® FILMARRAY® 2.0 SYSTEM", + value:

LAB DEVICE: BIOFIRE® FILMARRAY® 2.0 SYSTEM

, metadata: {}, }, "Analysis Time": { @@ -74,7 +74,7 @@ const labReportNormalJsonObject = { Value: { value: "Not Detected", metadata: {} }, "Ref Range": { value: "Not Detected", metadata: {} }, "Test Method": { - value: "LAB DEVICE: BIOFIRE® FILMARRAY® 2.0 SYSTEM", + value:

LAB DEVICE: BIOFIRE® FILMARRAY® 2.0 SYSTEM

, metadata: {}, }, "Analysis Time": { @@ -131,19 +131,22 @@ const labReportNormalJsonObject = { [ { "Performing Organization": { - value: - "PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675)", + value: ( +

+ PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675) +

+ ), metadata: { "data-id": "Result.1.2.840.114350.1.13.297.3.7.2.798268.1670845.PerformingLab", }, }, - Address: { value: "501 S. Buena Vista Street", metadata: {} }, + Address: { value:

501 S. Buena Vista Street

, metadata: {} }, "City/State/ZIP Code": { - value: "Burbank, CA 91505", + value:

Burbank, CA 91505

, metadata: {}, }, - "Phone Number": { value: "818-847-6000", metadata: {} }, + "Phone Number": { value:

818-847-6000

, metadata: {} }, }, ], ], @@ -240,34 +243,34 @@ describe("Labs Utils", () => { it("extracts string of all results of a search for specified lab report", () => { const searchKey = "Collection Time"; - const expectedResult = "09/28/2022 1:51 PM PDT"; + const expectedResult = ["09/28/2022 1:51 PM PDT"]; const result = searchResultRecord(labHTMLJson, searchKey); - expect(result).toBe(expectedResult); + expect(result).toStrictEqual(expectedResult); }); it("returns an empty string of results if none are found for search key", () => { const invalidSearchKey = "foobar"; - const expectedResult = ""; + const expectedResult = []; const result = searchResultRecord(labHTMLJson, invalidSearchKey); - expect(result).toBe(expectedResult); + expect(result).toStrictEqual(expectedResult); }); }); describe("returnFieldValueFromLabHtmlString", () => { it("extracts correct field value from within a lab report", () => { const fieldName = "Analysis Time"; - const expectedResult = "09/28/2022 1:59 PM PDT"; + const expectedResult = ["09/28/2022 1:59 PM PDT"]; const result = returnFieldValueFromLabHtmlString( labReportNormalJsonObject, fieldName, ); - expect(result).toBe(expectedResult); + expect(result).toStrictEqual(expectedResult); }); it("returns NoData if none are found for field name", () => { diff --git a/containers/ecr-viewer/src/app/tests/utils.test.tsx b/containers/ecr-viewer/src/app/tests/utils.test.tsx index b38b9dc643..cd420f2da7 100644 --- a/containers/ecr-viewer/src/app/tests/utils.test.tsx +++ b/containers/ecr-viewer/src/app/tests/utils.test.tsx @@ -1,4 +1,7 @@ -import { isDataAvailable, sanitizeAndMap } from "@/app/view-data/utils/utils"; +import { + isDataAvailable, + parseSanitizeAndMap, +} from "@/app/view-data/utils/utils"; import { loadYamlConfig } from "@/app/api/utils"; import { Bundle } from "fhir/r4"; import BundleWithTravelHistory from "./assets/BundleTravelHistory.json"; @@ -10,7 +13,7 @@ import BundleWithPendingResultsOnly from "./assets/BundlePendingResultsOnly.json import BundleWithScheduledOrdersOnly from "./assets/BundleScheduledOrdersOnly.json"; import BundleNoActiveProblems from "./assets/BundleNoActiveProblems.json"; import BundleCareTeam from "./assets/BundleCareTeam.json"; -import React from "react"; +import React, { Fragment } from "react"; import { render, screen } from "@testing-library/react"; import { CarePlanActivity } from "fhir/r4b"; import { evaluate } from "@/app/view-data/utils/evaluate"; @@ -551,27 +554,44 @@ describe("Utils", () => { }); }); - describe("sanitizeAndMap", () => { + describe("parseSanitizeAndMap", () => { it("should leave alone nice safe HTML", () => { - const html = "

hi there

"; - const actual = sanitizeAndMap(html); - expect(actual).toBe(html); + const str = "

hi there

"; + const jsx =

hi there

; + const actual = parseSanitizeAndMap(str); + expect(actual).toStrictEqual(jsx); }); it("should map xml-y HTML", () => { - const html = `hi thereI'm contentonetwo`; - const actual = sanitizeAndMap(html); - expect(actual).toBe( - `

hi there

I'm content`, + const str = `hi thereI'm contentonetwo`; + const jsx = ( + <> +

hi there

+ I'm content + + ); + const actual = parseSanitizeAndMap(str); + expect(actual).toStrictEqual(jsx); }); it("should remove comments", () => { - const html = `hi thereI'm contentonetwo`; - const actual = sanitizeAndMap(html); - expect(actual).toBe( - `

hi there

I'm content`, + const str = `hi thereI'm contentonetwo`; + const jsx = ( + <> +

hi there

+ I'm content + + ); + const actual = parseSanitizeAndMap(str); + expect(actual).toEqual(jsx); }); }); }); diff --git a/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx b/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx index 36d6b94493..a07e326178 100644 --- a/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx +++ b/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx @@ -33,6 +33,7 @@ export const DataDisplay: React.FC<{ item.dividerLine == null || item.dividerLine == undefined ? true : item.dividerLine; + console.log(item.value); return (
diff --git a/containers/ecr-viewer/src/app/view-data/components/common.tsx b/containers/ecr-viewer/src/app/view-data/components/common.tsx index ccaf6dd1a1..20dd837fcf 100644 --- a/containers/ecr-viewer/src/app/view-data/components/common.tsx +++ b/containers/ecr-viewer/src/app/view-data/components/common.tsx @@ -22,7 +22,7 @@ import { PathMappings, evaluateData, noData, - sanitizeAndMap, + parseSanitizeAndMap, } from "@/app/view-data/utils/utils"; import { Bundle, @@ -40,7 +40,6 @@ import { Procedure, } from "fhir/r4"; import { evaluate } from "@/app/view-data/utils/evaluate"; -import parse from "html-react-parser"; import { DisplayDataProps } from "@/app/view-data/components/DataDisplay"; import { AdministeredMedication, @@ -212,7 +211,7 @@ export const returnProblemsTable = ( { columnName: "Comments", infoPath: "activeProblemsComments", - applyToValue: (v) => parse(sanitizeAndMap(v)), + applyToValue: (v) => parseSanitizeAndMap(v), hiddenBaseText: "comment", }, ]; @@ -499,10 +498,8 @@ export const evaluateClinicalData = ( const clinicalNotes: DisplayDataProps[] = [ { title: "Miscellaneous Notes", - value: parse( - sanitizeAndMap( - evaluateValue(fhirBundle, mappings["historyOfPresentIllness"]), - ) || "", + value: parseSanitizeAndMap( + evaluateValue(fhirBundle, mappings["historyOfPresentIllness"]) ?? "", ), }, ]; diff --git a/containers/ecr-viewer/src/app/view-data/utils/utils.tsx b/containers/ecr-viewer/src/app/view-data/utils/utils.tsx index ffa27bb18b..27fd0687d4 100644 --- a/containers/ecr-viewer/src/app/view-data/utils/utils.tsx +++ b/containers/ecr-viewer/src/app/view-data/utils/utils.tsx @@ -1,7 +1,8 @@ -import React from "react"; +import React, { Fragment } from "react"; import { removeHtmlElements } from "@/app/services/formatService"; import { DisplayDataProps } from "@/app/view-data/components/DataDisplay"; import sanitizeHtml from "sanitize-html"; +import parse from "html-react-parser"; export interface PathMappings { [key: string]: string; @@ -64,13 +65,42 @@ export const isDataAvailable = (item: DisplayDataProps): Boolean => { * @param val - The string of content to sanitize and map. * @returns - Returns sanitized and mapped content. */ -export const sanitizeAndMap = (val: string): string => { - return sanitizeHtml(val, { - transformTags: { - paragraph: "p", - list: "ul", - item: "li", - content: "span", - }, - }); +export const parseSanitizeAndMap = ( + val: string, +): string | React.JSX.Element => { + const parsed = parse( + sanitizeHtml(val, { + transformTags: { + paragraph: "p", + list: "ul", + item: "li", + content: "span", + }, + }), + ); + + if (Array.isArray(parsed)) { + if (parsed.length === 0) { + return ""; + } else if (parsed.length === 1) { + return parsed[0]; + } + + const res = ( + <> + {parsed.map((item, ind) => { + // Make sure items always have a key + const key = `el-${ind}`; + return typeof item === "string" ? ( + {item} + ) : ( + { ...item, key } + ); + })} + + ); + return res; + } + + return parsed; }; From 7c1025a2670119ce8f523fb91254f92693da97d2 Mon Sep 17 00:00:00 2001 From: Mary McGrath Date: Tue, 19 Nov 2024 09:26:32 -0500 Subject: [PATCH 03/13] refactor: always deal witha single elements --- .../src/app/services/formatService.tsx | 4 +- .../src/app/services/labsService.tsx | 68 +++++++++---------- .../tests/__snapshots__/utils.test.tsx.snap | 37 ++++++++++ .../__snapshots__/LabInfo.test.tsx.snap | 12 +++- .../app/tests/services/labsService.test.tsx | 6 +- .../ecr-viewer/src/app/tests/utils.test.tsx | 51 ++++++-------- .../app/view-data/components/DataDisplay.tsx | 1 - .../src/app/view-data/components/common.tsx | 6 +- .../src/app/view-data/utils/utils.tsx | 59 +++++++++------- 9 files changed, 140 insertions(+), 104 deletions(-) create mode 100644 containers/ecr-viewer/src/app/tests/__snapshots__/utils.test.tsx.snap diff --git a/containers/ecr-viewer/src/app/services/formatService.tsx b/containers/ecr-viewer/src/app/services/formatService.tsx index a827457ec5..15a7457a42 100644 --- a/containers/ecr-viewer/src/app/services/formatService.tsx +++ b/containers/ecr-viewer/src/app/services/formatService.tsx @@ -1,7 +1,7 @@ import React from "react"; import { ToolTipElement } from "@/app/view-data/components/ToolTipElement"; import { ContactPoint } from "fhir/r4"; -import { parseSanitizeAndMap } from "../view-data/utils/utils"; +import { safeParse } from "../view-data/utils/utils"; interface Metadata { [key: string]: string; @@ -500,7 +500,7 @@ function getElementContent(el: Element | Node): TableValue { const rawValue = (el as Element)?.innerHTML ?? el.textContent; const value = rawValue?.trim() ?? ""; if (value === "") return value; - let res = parseSanitizeAndMap(value); + let res = safeParse(value); return res; } diff --git a/containers/ecr-viewer/src/app/services/labsService.tsx b/containers/ecr-viewer/src/app/services/labsService.tsx index 1fa0da84b6..ae129252bc 100644 --- a/containers/ecr-viewer/src/app/services/labsService.tsx +++ b/containers/ecr-viewer/src/app/services/labsService.tsx @@ -2,8 +2,9 @@ import React from "react"; import { Bundle, Device, Observation, Organization, Reference } from "fhir/r4"; import { PathMappings, + arrayToElement, noData, - parseSanitizeAndMap, + safeParse, } from "@/app/view-data/utils/utils"; import { evaluate } from "@/app/view-data/utils/evaluate"; import { AccordionLabResults } from "@/app/view-data/components/AccordionLabResults"; @@ -122,7 +123,7 @@ export const checkAbnormalTag = (labReportJson: TableJson): boolean => { export function searchResultRecord( result: any[], searchKey: string, -): TableValue[] { +): TableValue { let resultsArray: TableValue[] = []; // Loop through each table @@ -130,25 +131,20 @@ export function searchResultRecord( // For each table, recursively search through all nodes if (Array.isArray(table)) { const nestedResult = searchResultRecord(table, searchKey); - if (nestedResult.length > 0) { + if (nestedResult) { return nestedResult; } - } else { - const keys = Object.keys(table); - let searchKeyValue: string = ""; - keys.forEach((key) => { - // Search for search key value - if (key === searchKey && table[key].hasOwnProperty("value")) { - searchKeyValue = table[key]["value"]; - } - }); - - if (searchKeyValue !== "") { - resultsArray.push(searchKeyValue); - } + } else if ( + table.hasOwnProperty(searchKey) && + table[searchKey].hasOwnProperty("value") + ) { + resultsArray.push(table[searchKey]["value"]); } } - return [...new Set(resultsArray)]; + + // Remove empties and duplicates + const res = [...new Set(resultsArray.filter(Boolean))]; + return arrayToElement(res); } /** @@ -256,27 +252,29 @@ const returnAnalysisTime = ( labReportJson: TableJson, fieldName: string, ): React.ReactNode => { - const fieldVals = returnFieldValueFromLabHtmlString(labReportJson, fieldName); + const fieldVal = returnFieldValueFromLabHtmlString(labReportJson, fieldName); - if (fieldVals === noData) { + if (fieldVal === noData) { return noData; } - const analysisTimeArrayFormatted = (fieldVals as TableValue[]).map( - (rawDateTime) => { - let dateTime; - if (typeof rawDateTime === "string") { - dateTime = rawDateTime; - } else if (typeof rawDateTime.props.children === "string") { - dateTime = rawDateTime.props.children; - } else { - return ""; - } - return formatDateTime(dateTime); - }, - ); + if (typeof fieldVal === "string") return formatDateTime(fieldVal); + + let analysisTimeArrayFormatted = ( + fieldVal as React.JSX.Element + ).props.children.map((el: TableValue) => { + let dateTime; + if (typeof el === "string") { + dateTime = el; + } else if (typeof el.props.children === "string") { + dateTime = el.props.children; + } else { + return ""; + } + return formatDateTime(dateTime); + }); - return [...new Set(analysisTimeArrayFormatted)].join(", "); + return [...new Set(analysisTimeArrayFormatted.filter(Boolean))].join(", "); }; /** @@ -352,7 +350,7 @@ export const evaluateDiagnosticReportData = ( infoPath: "observationDeviceReference", applyToValue: (ref) => { const device = evaluateReference(fhirBundle, mappings, ref) as Device; - return parseSanitizeAndMap(device.deviceName?.[0]?.name ?? ""); + return safeParse(device.deviceName?.[0]?.name ?? ""); }, className: "minw-10 width-20", }, @@ -360,7 +358,7 @@ export const evaluateDiagnosticReportData = ( columnName: "Lab Comment", infoPath: "observationNote", hiddenBaseText: "comment", - applyToValue: (v) => parseSanitizeAndMap(v), + applyToValue: (v) => safeParse(v), className: "minw-10 width-20", }, ]; diff --git a/containers/ecr-viewer/src/app/tests/__snapshots__/utils.test.tsx.snap b/containers/ecr-viewer/src/app/tests/__snapshots__/utils.test.tsx.snap new file mode 100644 index 0000000000..8296061dd7 --- /dev/null +++ b/containers/ecr-viewer/src/app/tests/__snapshots__/utils.test.tsx.snap @@ -0,0 +1,37 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Utils safeParse should map xml-y HTML 1`] = ` + +

+ hi there +

+ + I'm content + +
    +
  • + one +
  • +
  • + two +
  • +
+
+`; + +exports[`Utils safeParse should remove comments 1`] = ` + +

+ hi there +

+ I'm content +
    +
  • + one +
  • +
  • + two +
  • +
+
+`; diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap index fa066d5aee..61e935372a 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap @@ -1230,7 +1230,9 @@ NASHVILLE, TN
- testing comment +

+ testing comment +

- VUMC CERNER LAB - 04/18/2022 2:57 PM CDT MICROARRAY REPORT NARRATIVE +

+ VUMC CERNER LAB - 04/18/2022 2:57 PM CDT +

+ +

+ MICROARRAY REPORT NARRATIVE +

{ it("extracts string of all results of a search for specified lab report", () => { const searchKey = "Collection Time"; - const expectedResult = ["09/28/2022 1:51 PM PDT"]; + const expectedResult = "09/28/2022 1:51 PM PDT"; const result = searchResultRecord(labHTMLJson, searchKey); @@ -252,7 +252,7 @@ describe("Labs Utils", () => { it("returns an empty string of results if none are found for search key", () => { const invalidSearchKey = "foobar"; - const expectedResult = []; + const expectedResult = ""; const result = searchResultRecord(labHTMLJson, invalidSearchKey); @@ -263,7 +263,7 @@ describe("Labs Utils", () => { describe("returnFieldValueFromLabHtmlString", () => { it("extracts correct field value from within a lab report", () => { const fieldName = "Analysis Time"; - const expectedResult = ["09/28/2022 1:59 PM PDT"]; + const expectedResult = "09/28/2022 1:59 PM PDT"; const result = returnFieldValueFromLabHtmlString( labReportNormalJsonObject, diff --git a/containers/ecr-viewer/src/app/tests/utils.test.tsx b/containers/ecr-viewer/src/app/tests/utils.test.tsx index cd420f2da7..4aaa2e137f 100644 --- a/containers/ecr-viewer/src/app/tests/utils.test.tsx +++ b/containers/ecr-viewer/src/app/tests/utils.test.tsx @@ -1,7 +1,4 @@ -import { - isDataAvailable, - parseSanitizeAndMap, -} from "@/app/view-data/utils/utils"; +import { isDataAvailable, safeParse } from "@/app/view-data/utils/utils"; import { loadYamlConfig } from "@/app/api/utils"; import { Bundle } from "fhir/r4"; import BundleWithTravelHistory from "./assets/BundleTravelHistory.json"; @@ -13,8 +10,8 @@ import BundleWithPendingResultsOnly from "./assets/BundlePendingResultsOnly.json import BundleWithScheduledOrdersOnly from "./assets/BundleScheduledOrdersOnly.json"; import BundleNoActiveProblems from "./assets/BundleNoActiveProblems.json"; import BundleCareTeam from "./assets/BundleCareTeam.json"; -import React, { Fragment } from "react"; -import { render, screen } from "@testing-library/react"; +import React from "react"; +import { render, screen, cleanup } from "@testing-library/react"; import { CarePlanActivity } from "fhir/r4b"; import { evaluate } from "@/app/view-data/utils/evaluate"; import userEvent from "@testing-library/user-event"; @@ -554,44 +551,34 @@ describe("Utils", () => { }); }); - describe("parseSanitizeAndMap", () => { + describe("safeParse", () => { + it("should leave a string safe HTML", () => { + const str = "hi there"; + const actual = safeParse(str); + expect(actual).toBe(str); + }); + it("should leave alone nice safe HTML", () => { const str = "

hi there

"; const jsx =

hi there

; - const actual = parseSanitizeAndMap(str); + const actual = safeParse(str); expect(actual).toStrictEqual(jsx); }); it("should map xml-y HTML", () => { const str = `hi thereI'm contentonetwo`; - const jsx = ( - <> -

hi there

- I'm content -
    -
  • one
  • -
  • two
  • -
- - ); - const actual = parseSanitizeAndMap(str); - expect(actual).toStrictEqual(jsx); + const parsed = safeParse(str); + const { asFragment } = render(parsed); + expect(asFragment()).toMatchSnapshot(); + cleanup(); }); it("should remove comments", () => { const str = `hi thereI'm contentonetwo`; - const jsx = ( - <> -

hi there

- I'm content -
    -
  • one
  • -
  • two
  • -
- - ); - const actual = parseSanitizeAndMap(str); - expect(actual).toEqual(jsx); + const parsed = safeParse(str); + const { asFragment } = render(parsed); + expect(asFragment()).toMatchSnapshot(); + cleanup(); }); }); }); diff --git a/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx b/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx index a07e326178..36d6b94493 100644 --- a/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx +++ b/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx @@ -33,7 +33,6 @@ export const DataDisplay: React.FC<{ item.dividerLine == null || item.dividerLine == undefined ? true : item.dividerLine; - console.log(item.value); return (
diff --git a/containers/ecr-viewer/src/app/view-data/components/common.tsx b/containers/ecr-viewer/src/app/view-data/components/common.tsx index 20dd837fcf..788df9a6c9 100644 --- a/containers/ecr-viewer/src/app/view-data/components/common.tsx +++ b/containers/ecr-viewer/src/app/view-data/components/common.tsx @@ -22,7 +22,7 @@ import { PathMappings, evaluateData, noData, - parseSanitizeAndMap, + safeParse, } from "@/app/view-data/utils/utils"; import { Bundle, @@ -211,7 +211,7 @@ export const returnProblemsTable = ( { columnName: "Comments", infoPath: "activeProblemsComments", - applyToValue: (v) => parseSanitizeAndMap(v), + applyToValue: (v) => safeParse(v), hiddenBaseText: "comment", }, ]; @@ -498,7 +498,7 @@ export const evaluateClinicalData = ( const clinicalNotes: DisplayDataProps[] = [ { title: "Miscellaneous Notes", - value: parseSanitizeAndMap( + value: safeParse( evaluateValue(fhirBundle, mappings["historyOfPresentIllness"]) ?? "", ), }, diff --git a/containers/ecr-viewer/src/app/view-data/utils/utils.tsx b/containers/ecr-viewer/src/app/view-data/utils/utils.tsx index 27fd0687d4..1761819895 100644 --- a/containers/ecr-viewer/src/app/view-data/utils/utils.tsx +++ b/containers/ecr-viewer/src/app/view-data/utils/utils.tsx @@ -61,13 +61,11 @@ export const isDataAvailable = (item: DisplayDataProps): Boolean => { }; /** - * Sanitizes the html while also mapping common hl7v3 tags to html. - * @param val - The string of content to sanitize and map. + * Parses and sanitizes the html while also mapping common hl7v3 tags to html. + * @param val - The string of content to parse. * @returns - Returns sanitized and mapped content. */ -export const parseSanitizeAndMap = ( - val: string, -): string | React.JSX.Element => { +export const safeParse = (val: string): string | React.JSX.Element => { const parsed = parse( sanitizeHtml(val, { transformTags: { @@ -79,28 +77,37 @@ export const parseSanitizeAndMap = ( }), ); - if (Array.isArray(parsed)) { - if (parsed.length === 0) { - return ""; - } else if (parsed.length === 1) { - return parsed[0]; - } + return Array.isArray(parsed) ? arrayToElement(parsed) : parsed; +}; - const res = ( - <> - {parsed.map((item, ind) => { - // Make sure items always have a key - const key = `el-${ind}`; - return typeof item === "string" ? ( - {item} - ) : ( - { ...item, key } - ); - })} - - ); - return res; +/** + * Collapses an array of values into one element. + * @param vals - An array of strings and elments. + * @returns - One string or element. + */ +export const arrayToElement = (vals: any[]) => { + // An empty array is returned for an empty input + if (vals.length === 0) { + return ""; + } else if (vals.length === 1) { + return vals[0]; } - return parsed; + // Wrap the items in a fragment and make sure they all have keys. + // It reduces the cases to handle elsewhere in the logic and avoids + // dupblicate key warnings. + const res = ( + <> + {vals.map((item, ind) => { + // Make sure items always have a key + const key = `el-${ind}`; + return typeof item === "string" ? ( + {item} + ) : ( + { ...item, key } + ); + })} + + ); + return res; }; From 4af8415ba294820c4c9c196731a5a3fd640babcb Mon Sep 17 00:00:00 2001 From: Mary McGrath Date: Tue, 19 Nov 2024 10:51:23 -0500 Subject: [PATCH 04/13] fix: linting --- containers/ecr-viewer/src/app/services/labsService.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/ecr-viewer/src/app/services/labsService.tsx b/containers/ecr-viewer/src/app/services/labsService.tsx index ae129252bc..bb5bc8dbb1 100644 --- a/containers/ecr-viewer/src/app/services/labsService.tsx +++ b/containers/ecr-viewer/src/app/services/labsService.tsx @@ -235,7 +235,7 @@ export const returnFieldValueFromLabHtmlString = ( const labTables = labReportJson.tables; const fieldValue = searchResultRecord(labTables ?? [], fieldName); - if (!fieldValue || fieldValue.length === 0) { + if (!fieldValue) { return noData; } From 85a30ab720a2bc920631106113a8a236ee24378f Mon Sep 17 00:00:00 2001 From: Mary McGrath Date: Tue, 19 Nov 2024 17:27:44 -0500 Subject: [PATCH 05/13] refactor: TableValue => RenderableNode --- .../src/app/components/AccordionContainer.tsx | 3 ++- .../src/app/services/formatService.tsx | 6 ++---- .../src/app/services/labsService.tsx | 20 +++++++++---------- .../app/view-data/components/DataDisplay.tsx | 2 +- .../src/app/view-data/utils/utils.tsx | 8 +++++--- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/containers/ecr-viewer/src/app/components/AccordionContainer.tsx b/containers/ecr-viewer/src/app/components/AccordionContainer.tsx index d6bd33ed85..fb2735128b 100644 --- a/containers/ecr-viewer/src/app/components/AccordionContainer.tsx +++ b/containers/ecr-viewer/src/app/components/AccordionContainer.tsx @@ -1,9 +1,10 @@ import React from "react"; import { Accordion, HeadingLevel } from "@trussworks/react-uswds"; import { formatString } from "@/app/services/formatService"; +import { RenderableNode } from "../view-data/utils/utils"; export interface AccordionItemProps { - title: React.ReactNode | string; + title: RenderableNode; content: React.ReactNode; expanded: boolean; id: string; diff --git a/containers/ecr-viewer/src/app/services/formatService.tsx b/containers/ecr-viewer/src/app/services/formatService.tsx index 15a7457a42..1163ee28e9 100644 --- a/containers/ecr-viewer/src/app/services/formatService.tsx +++ b/containers/ecr-viewer/src/app/services/formatService.tsx @@ -1,7 +1,7 @@ import React from "react"; import { ToolTipElement } from "@/app/view-data/components/ToolTipElement"; import { ContactPoint } from "fhir/r4"; -import { safeParse } from "../view-data/utils/utils"; +import { RenderableNode, safeParse } from "../view-data/utils/utils"; interface Metadata { [key: string]: string; @@ -26,8 +26,6 @@ export interface TableJson { tables?: TableRow[][]; } -export type TableValue = string | React.JSX.Element; - /** * Formats a person's name using given name(s), family name, optional prefix(es), and optional suffix(es). * @param given - Optional array of given name(s). @@ -496,7 +494,7 @@ function processTable(table: Element): TableRow[] { * @example @param el - Values here * @example @returns -

Values here

*/ -function getElementContent(el: Element | Node): TableValue { +function getElementContent(el: Element | Node): RenderableNode { const rawValue = (el as Element)?.innerHTML ?? el.textContent; const value = rawValue?.trim() ?? ""; if (value === "") return value; diff --git a/containers/ecr-viewer/src/app/services/labsService.tsx b/containers/ecr-viewer/src/app/services/labsService.tsx index bb5bc8dbb1..d0f493a04f 100644 --- a/containers/ecr-viewer/src/app/services/labsService.tsx +++ b/containers/ecr-viewer/src/app/services/labsService.tsx @@ -2,6 +2,7 @@ import React from "react"; import { Bundle, Device, Observation, Organization, Reference } from "fhir/r4"; import { PathMappings, + RenderableNode, arrayToElement, noData, safeParse, @@ -15,7 +16,6 @@ import { formatAddress, formatPhoneNumber, TableJson, - TableValue, } from "@/app/services/formatService"; import { Coding, ObservationComponent } from "fhir/r4b"; import EvaluateTable, { @@ -123,8 +123,8 @@ export const checkAbnormalTag = (labReportJson: TableJson): boolean => { export function searchResultRecord( result: any[], searchKey: string, -): TableValue { - let resultsArray: TableValue[] = []; +): RenderableNode { + let resultsArray: RenderableNode = []; // Loop through each table for (const table of result) { @@ -158,7 +158,7 @@ const returnSpecimenSource = ( report: LabReport, fhirBundle: Bundle, mappings: PathMappings, -): React.ReactNode => { +): RenderableNode => { const observations = getObservations(report, fhirBundle, mappings); const specimenSource = observations.flatMap((observation) => { return evaluate(observation, mappings["specimenSource"]); @@ -180,7 +180,7 @@ const returnCollectionTime = ( report: LabReport, fhirBundle: Bundle, mappings: PathMappings, -): React.ReactNode => { +): RenderableNode => { const observations = getObservations(report, fhirBundle, mappings); const collectionTime = observations.flatMap((observation) => { const rawTime = evaluate(observation, mappings["specimenCollectionTime"]); @@ -205,7 +205,7 @@ const returnReceivedTime = ( report: LabReport, fhirBundle: Bundle, mappings: PathMappings, -): React.ReactNode => { +): RenderableNode => { const observations = getObservations(report, fhirBundle, mappings); const receivedTime = observations.flatMap((observation) => { const rawTime = evaluate(observation, mappings["specimenReceivedTime"]); @@ -228,7 +228,7 @@ const returnReceivedTime = ( export const returnFieldValueFromLabHtmlString = ( labReportJson: TableJson, fieldName: string, -): React.ReactNode | TableValue[] => { +): RenderableNode => { if (!labReportJson) { return noData; } @@ -251,7 +251,7 @@ export const returnFieldValueFromLabHtmlString = ( const returnAnalysisTime = ( labReportJson: TableJson, fieldName: string, -): React.ReactNode => { +): RenderableNode => { const fieldVal = returnFieldValueFromLabHtmlString(labReportJson, fieldName); if (fieldVal === noData) { @@ -262,11 +262,11 @@ const returnAnalysisTime = ( let analysisTimeArrayFormatted = ( fieldVal as React.JSX.Element - ).props.children.map((el: TableValue) => { + ).props.children.map((el: RenderableNode) => { let dateTime; if (typeof el === "string") { dateTime = el; - } else if (typeof el.props.children === "string") { + } else if (typeof el?.props?.children === "string") { dateTime = el.props.children; } else { return ""; diff --git a/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx b/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx index 36d6b94493..afa10a3e50 100644 --- a/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx +++ b/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx @@ -7,7 +7,7 @@ export interface DisplayDataProps { title?: string; className?: string; toolTip?: string; - value?: string | React.JSX.Element | React.JSX.Element[] | React.ReactNode; + value?: React.ReactNode; dividerLine?: boolean; table?: boolean; } diff --git a/containers/ecr-viewer/src/app/view-data/utils/utils.tsx b/containers/ecr-viewer/src/app/view-data/utils/utils.tsx index 1761819895..9c5e63e0f4 100644 --- a/containers/ecr-viewer/src/app/view-data/utils/utils.tsx +++ b/containers/ecr-viewer/src/app/view-data/utils/utils.tsx @@ -13,6 +13,8 @@ export interface CompleteData { unavailableData: DisplayDataProps[]; } +export type RenderableNode = string | React.JSX.Element; + export const noData = ( No data ); @@ -65,7 +67,7 @@ export const isDataAvailable = (item: DisplayDataProps): Boolean => { * @param val - The string of content to parse. * @returns - Returns sanitized and mapped content. */ -export const safeParse = (val: string): string | React.JSX.Element => { +export const safeParse = (val: string): RenderableNode => { const parsed = parse( sanitizeHtml(val, { transformTags: { @@ -85,7 +87,7 @@ export const safeParse = (val: string): string | React.JSX.Element => { * @param vals - An array of strings and elments. * @returns - One string or element. */ -export const arrayToElement = (vals: any[]) => { +export const arrayToElement = (vals: RenderableNode[]) => { // An empty array is returned for an empty input if (vals.length === 0) { return ""; @@ -101,7 +103,7 @@ export const arrayToElement = (vals: any[]) => { {vals.map((item, ind) => { // Make sure items always have a key const key = `el-${ind}`; - return typeof item === "string" ? ( + return typeof item !== "object" ? ( {item} ) : ( { ...item, key } From c7a42bd6edbe295a88fc2fd3ddd84d7d76adc858 Mon Sep 17 00:00:00 2001 From: Mary McGrath Date: Tue, 19 Nov 2024 17:31:27 -0500 Subject: [PATCH 06/13] fix: add p-list class --- .../AccordionContent.test.tsx.snap | 134 +++++++++--------- .../__snapshots__/Clinical.test.tsx.snap | 2 +- .../__snapshots__/Demographics.test.tsx.snap | 28 ++-- .../__snapshots__/EcrMetadata.test.tsx.snap | 30 ++-- .../__snapshots__/EcrSummary.test.tsx.snap | 20 +-- .../__snapshots__/Encounter.test.tsx.snap | 18 +-- .../__snapshots__/LabInfo.test.tsx.snap | 72 +++++----- .../__snapshots__/SocialHistory.test.tsx.snap | 10 +- .../__snapshots__/Unavailable.test.tsx.snap | 50 +++---- .../app/view-data/components/DataDisplay.tsx | 2 +- 10 files changed, 183 insertions(+), 183 deletions(-) diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/AccordionContent.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/AccordionContent.test.tsx.snap index 097a6b1618..519e9367ec 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/AccordionContent.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/AccordionContent.test.tsx.snap @@ -53,7 +53,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Vital Status
Deceased
@@ -72,7 +72,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Contact
@@ -237,7 +237,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Patient Name
No data
@@ -256,7 +256,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp DOB
No data
@@ -275,7 +275,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Current Age
No data
@@ -294,7 +294,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Age at Death
No data
@@ -313,7 +313,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Date of Death
No data
@@ -332,7 +332,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Sex
No data
@@ -351,7 +351,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Race
No data
@@ -370,7 +370,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Ethnicity
No data
@@ -389,7 +389,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Tribal Affiliation
No data
@@ -408,7 +408,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Preferred Language
No data
@@ -427,7 +427,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Patient Address
No data
@@ -446,7 +446,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp County
No data
@@ -465,7 +465,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Emergency Contact
No data
@@ -505,7 +505,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp
No data
@@ -537,7 +537,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Occupation
No data
@@ -556,7 +556,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Tobacco Use
No data
@@ -575,7 +575,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Travel History
No data
@@ -594,7 +594,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Homeless Status
No data
@@ -613,7 +613,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Pregnancy Status
No data
@@ -632,7 +632,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Alcohol Use
No data
@@ -651,7 +651,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Sexual Orientation
No data
@@ -670,7 +670,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Gender Identity
No data
@@ -689,7 +689,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Occupation
No data
@@ -721,7 +721,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Encounter Date/Time
No data
@@ -740,7 +740,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Encounter Type
No data
@@ -759,7 +759,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Encounter ID
No data
@@ -778,7 +778,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Encounter Diagnosis
No data
@@ -810,7 +810,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Facility Name
No data
@@ -829,7 +829,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Facility Address
No data
@@ -848,7 +848,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Facility Contact Address
No data
@@ -867,7 +867,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Facility Contact
No data
@@ -886,7 +886,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Facility Type
No data
@@ -905,7 +905,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Facility ID
No data
@@ -937,7 +937,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Miscellaneous Notes
No data
@@ -969,7 +969,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Provider Name
No data
@@ -988,7 +988,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Provider Address
No data
@@ -1007,7 +1007,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Provider Contact
No data
@@ -1026,7 +1026,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Provider Facility Name
No data
@@ -1045,7 +1045,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Provider Facility Address
No data
@@ -1064,7 +1064,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Provider ID
No data
@@ -1096,7 +1096,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Reason for Visit
No data
@@ -1115,7 +1115,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Problems List
No data
@@ -1147,7 +1147,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Vital Signs
No data
@@ -1179,7 +1179,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Immunization History
No data
@@ -1211,7 +1211,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Procedures
No data
@@ -1230,7 +1230,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Planned Procedures
No data
@@ -1249,7 +1249,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Plan of Treatment
No data
@@ -1268,7 +1268,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Administered Medications
No data
@@ -1287,7 +1287,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Care Team
No data
@@ -1340,7 +1340,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp
No data
@@ -1359,7 +1359,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Date/Time eCR Created
No data
@@ -1378,7 +1378,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp eICR Release Version
No data
@@ -1397,7 +1397,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp EHR Manufacturer Model Name
No data
@@ -1437,7 +1437,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp
No data
@@ -1456,7 +1456,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp eRSD Warnings
No data
@@ -1475,7 +1475,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Custodian ID
No data
@@ -1494,7 +1494,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Custodian Name
No data
@@ -1513,7 +1513,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Custodian Address
No data
@@ -1532,7 +1532,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Custodian Contact
No data
@@ -1564,7 +1564,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Author Name
No data
@@ -1583,7 +1583,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Author Address
No data
@@ -1602,7 +1602,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Author Contact
No data
@@ -1621,7 +1621,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Author Facility Name
No data
@@ -1640,7 +1640,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Author Facility Address
No data
@@ -1659,7 +1659,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp Author Facility Contact
No data
diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/Clinical.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/Clinical.test.tsx.snap index 23967b45d4..be12346de6 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/Clinical.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/Clinical.test.tsx.snap @@ -30,7 +30,7 @@ exports[`Snapshot test for Clinical Notes should match snapshot for non table no Miscellaneous Notes

This patient was only recently discharged for a recurrent GI bleed as described diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/Demographics.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/Demographics.test.tsx.snap index c9d907662c..12cab5a28f 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/Demographics.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/Demographics.test.tsx.snap @@ -30,7 +30,7 @@ exports[`Demographics should match snapshot 1`] = ` Patient Name

Test patient
@@ -49,7 +49,7 @@ exports[`Demographics should match snapshot 1`] = ` DOB
06/01/1996
@@ -68,7 +68,7 @@ exports[`Demographics should match snapshot 1`] = ` Current Age
27
@@ -87,7 +87,7 @@ exports[`Demographics should match snapshot 1`] = ` Vital Status
Alive
@@ -106,7 +106,7 @@ exports[`Demographics should match snapshot 1`] = ` Sex
female
@@ -125,7 +125,7 @@ exports[`Demographics should match snapshot 1`] = ` Race
Asian/Pacific Islander
@@ -144,7 +144,7 @@ exports[`Demographics should match snapshot 1`] = ` Ethnicity
Not Hispanic or Latino
@@ -163,7 +163,7 @@ exports[`Demographics should match snapshot 1`] = ` Tribal
test
@@ -182,7 +182,7 @@ exports[`Demographics should match snapshot 1`] = ` Preferred Language
test
@@ -201,7 +201,7 @@ exports[`Demographics should match snapshot 1`] = ` Patient Address
test address
@@ -220,7 +220,7 @@ exports[`Demographics should match snapshot 1`] = ` County
test
@@ -239,7 +239,7 @@ exports[`Demographics should match snapshot 1`] = ` Contact
test contact
@@ -258,7 +258,7 @@ exports[`Demographics should match snapshot 1`] = ` Emergency Contact
N/A
@@ -277,7 +277,7 @@ exports[`Demographics should match snapshot 1`] = ` Patient IDs
123-4567-890
diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/EcrMetadata.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/EcrMetadata.test.tsx.snap index 3695f9ff83..1adae7ac61 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/EcrMetadata.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/EcrMetadata.test.tsx.snap @@ -231,7 +231,7 @@ exports[`ECR Metadata should match snapshot 1`] = ` eICR Identifier
1dd10047-2207-4eac-a993-0f706c88be5d
@@ -250,7 +250,7 @@ exports[`ECR Metadata should match snapshot 1`] = ` Date/Time eCR Created
2022-05-14T12:56:38Z
@@ -269,7 +269,7 @@ exports[`ECR Metadata should match snapshot 1`] = ` eICR Release Version
R1.1 (2016-12-01)
@@ -288,7 +288,7 @@ exports[`ECR Metadata should match snapshot 1`] = ` EHR Software Name
Epic - Version 10.1
@@ -307,7 +307,7 @@ exports[`ECR Metadata should match snapshot 1`] = ` EHR Manufacturer Model Name
Epic - Version 10.1
@@ -335,7 +335,7 @@ exports[`ECR Metadata should match snapshot 1`] = ` Author Name
Dr. Stella Zinman
@@ -354,7 +354,7 @@ exports[`ECR Metadata should match snapshot 1`] = ` Author Address
1 Main st
@@ -373,7 +373,7 @@ exports[`ECR Metadata should match snapshot 1`] = ` Author Contact
(661)382-5000
@@ -392,7 +392,7 @@ exports[`ECR Metadata should match snapshot 1`] = ` Author Facility Name
PRM- Palmdale Regional Medical Center
@@ -411,7 +411,7 @@ exports[`ECR Metadata should match snapshot 1`] = ` Author Facility Address
38600 Medical Center Drive Palmdale, CA @@ -432,7 +432,7 @@ Palmdale, CA Author Facility Contact
(661)382-5000
@@ -460,7 +460,7 @@ Palmdale, CA Custodian ID
1104202761
@@ -479,7 +479,7 @@ Palmdale, CA Custodian Name
Vanderbilt University Medical Center
@@ -498,7 +498,7 @@ Palmdale, CA Custodian Address
3401 West End Ave Nashville, TN @@ -519,7 +519,7 @@ Nashville, TN Custodian Contact
Work 1-615-322-5000
diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/EcrSummary.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/EcrSummary.test.tsx.snap index 97d66a9c9c..4085cdafc4 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/EcrSummary.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/EcrSummary.test.tsx.snap @@ -28,7 +28,7 @@ exports[`EcrSummary should match snapshot 1`] = ` Patient Name
ABEL CASTILLO
@@ -47,7 +47,7 @@ exports[`EcrSummary should match snapshot 1`] = ` DOB
04/15/2015
@@ -66,7 +66,7 @@ exports[`EcrSummary should match snapshot 1`] = ` Sex
male
@@ -85,7 +85,7 @@ exports[`EcrSummary should match snapshot 1`] = ` Patient Address
1050 CARPENTER ST EDWARDS, CA @@ -106,7 +106,7 @@ EDWARDS, CA Patient Contact
Home (818)419-5968 MELLY.C.A.16@GMAIL.COM @@ -140,7 +140,7 @@ MELLY.C.A.16@GMAIL.COM Facility Name
PRM- Palmdale Regional Medical Center
@@ -159,7 +159,7 @@ MELLY.C.A.16@GMAIL.COM Facility Contact
(661)382-5000
@@ -178,7 +178,7 @@ MELLY.C.A.16@GMAIL.COM Encounter Date/Time
Start: 05/13/2022 7:25 AM UTC End: 05/13/2022 9:57 AM UTC @@ -198,7 +198,7 @@ End: 05/13/2022 9:57 AM UTC Encounter Type
Emergency
@@ -263,7 +263,7 @@ End: 05/13/2022 9:57 AM UTC RCKMS Rule Summary
covid summary
diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/Encounter.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/Encounter.test.tsx.snap index a480d39d7b..9924d340f6 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/Encounter.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/Encounter.test.tsx.snap @@ -31,7 +31,7 @@ exports[`Encounter should match snapshot 1`] = ` Encounter Type
Ambulatory
@@ -50,7 +50,7 @@ exports[`Encounter should match snapshot 1`] = ` Encounter ID
123456789
@@ -81,7 +81,7 @@ exports[`Encounter should match snapshot 1`] = ` Facility Name
PRM- Palmdale Regional Medical Center
@@ -100,7 +100,7 @@ exports[`Encounter should match snapshot 1`] = ` Facility Address
5001 North Mount Washington Circle Drive North Canton, MA 02740 @@ -120,7 +120,7 @@ North Canton, MA 02740 Facility Contact Address
5001 North Mount Washington Circle Drive North Canton, MA 02740 @@ -140,7 +140,7 @@ North Canton, MA 02740 Facility Type
Healthcare Provider
@@ -159,7 +159,7 @@ North Canton, MA 02740 Facility ID
2.16.840.1.113883.4.6
@@ -192,7 +192,7 @@ North Canton, MA 02740 Provider Name
test provider name
@@ -211,7 +211,7 @@ North Canton, MA 02740 Provider Contact
test provider contact
diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap index 61e935372a..73855acf88 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap @@ -31,7 +31,7 @@ exports[`LabInfo should match snapshot test 1`] = ` Lab Performing Name
PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675)
@@ -50,7 +50,7 @@ exports[`LabInfo should match snapshot test 1`] = ` Lab Address
501 S. Buena Vista Street Burbank, CA @@ -71,7 +71,7 @@ Burbank, CA Number of Results
2
@@ -250,7 +250,7 @@ Burbank, CA Analysis Time
09/28/2022 2:00 PM PDT
@@ -269,7 +269,7 @@ Burbank, CA Collection Time
09/28/2022 8:51 PM UTC
@@ -288,7 +288,7 @@ Burbank, CA Received Time
09/28/2022 8:51 PM UTC
@@ -307,7 +307,7 @@ Burbank, CA Specimen (Source)
Stool
@@ -326,7 +326,7 @@ Burbank, CA Anatomical Location/Laterality
STOOL SPECIMEN / Unknown
@@ -345,7 +345,7 @@ Burbank, CA Collection Method/Volume
Ambhp1 Test MD
@@ -410,7 +410,7 @@ Burbank, CA Result Type
MICROBIOLOGY - GENERAL ORDERABLES
@@ -429,7 +429,7 @@ Burbank, CA Narrative
09/28/2022 1:59 PM PDT
@@ -599,7 +599,7 @@ Burbank, CA Collection Time
09/28/2022 8:51 PM UTC
@@ -618,7 +618,7 @@ Burbank, CA Received Time
09/28/2022 8:51 PM UTC
@@ -637,7 +637,7 @@ Burbank, CA Specimen (Source)
Stool
@@ -656,7 +656,7 @@ Burbank, CA Anatomical Location/Laterality
STOOL SPECIMEN / Unknown
@@ -675,7 +675,7 @@ Burbank, CA Collection Method/Volume
Ambhp1 Test MD
@@ -740,7 +740,7 @@ Burbank, CA Result Type
MICROBIOLOGY - GENERAL ORDERABLES
@@ -759,7 +759,7 @@ Burbank, CA Narrative
VUMC CERNER LAB
@@ -815,7 +815,7 @@ Burbank, CA Lab Address
4605 TVC VUMC 1301 Medical Center Drive @@ -837,7 +837,7 @@ NASHVILLE, TN Number of Results
1
@@ -1106,7 +1106,7 @@ NASHVILLE, TN Analysis Time
04/04/2022 4:55 PM UTC
@@ -1148,7 +1148,7 @@ NASHVILLE, TN Received Time
04/18/2022 7:46 PM UTC
@@ -1167,7 +1167,7 @@ NASHVILLE, TN Specimen (Source)
Blood
@@ -1186,7 +1186,7 @@ NASHVILLE, TN Anatomical Location/Laterality
Collection / Unknown
@@ -1228,7 +1228,7 @@ NASHVILLE, TN Resulting Agency Comment

testing comment @@ -1249,7 +1249,7 @@ NASHVILLE, TN Authorizing Provider

Carda Testprovqa MD
@@ -1268,7 +1268,7 @@ NASHVILLE, TN Result Type
LAB GENETIC TESTING
@@ -1287,7 +1287,7 @@ NASHVILLE, TN Narrative

VUMC CERNER LAB - 04/18/2022 2:57 PM CDT diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/SocialHistory.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/SocialHistory.test.tsx.snap index 0b6e927712..d58425719d 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/SocialHistory.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/SocialHistory.test.tsx.snap @@ -30,7 +30,7 @@ exports[`SocialHistory should match snapshot 1`] = ` Occupation

Nursing, psychiatric, and home health aides
@@ -49,7 +49,7 @@ exports[`SocialHistory should match snapshot 1`] = ` Tobacco Use
Tobacco smoking consumption unknown
@@ -68,7 +68,7 @@ exports[`SocialHistory should match snapshot 1`] = ` Homeless Status
unsatisfactory living conditions (finding)
@@ -87,7 +87,7 @@ exports[`SocialHistory should match snapshot 1`] = ` Occupation
Nursing, psychiatric, and home health aides
@@ -106,7 +106,7 @@ exports[`SocialHistory should match snapshot 1`] = ` Sexual Orientation
Do not know
diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/Unavailable.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/Unavailable.test.tsx.snap index 9ec70b10e9..f32aa83ba8 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/Unavailable.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/Unavailable.test.tsx.snap @@ -32,7 +32,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Tribal Affiliation
No data
@@ -51,7 +51,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Preffered Language
No data
@@ -83,7 +83,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Travel History
No data
@@ -102,7 +102,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Pregnancy Status
No data
@@ -121,7 +121,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Alcohol Use
No data
@@ -140,7 +140,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Sexual Orientation
No data
@@ -159,7 +159,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Gender Identity
No data
@@ -191,7 +191,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Encounter Date/Time
No data
@@ -210,7 +210,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Encounter Type
No data
@@ -229,7 +229,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Encounter ID
No data
@@ -261,7 +261,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Facility Name
No data
@@ -280,7 +280,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Facility Address
No data
@@ -299,7 +299,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Facility Contact Address
No data
@@ -318,7 +318,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Facility Type
No data
@@ -337,7 +337,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Facility ID
No data
@@ -369,7 +369,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Miscellaneous Notes
No data
@@ -401,7 +401,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Provider Facility Name
No data
@@ -420,7 +420,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Provider Facility Address
No data
@@ -452,7 +452,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Reason for Visit
No data
@@ -471,7 +471,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Problems List
No data
@@ -503,7 +503,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Vitals
No data
@@ -535,7 +535,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Immunization History
No data
@@ -567,7 +567,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Procedures
No data
@@ -599,7 +599,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` EHR Software Name
No data
@@ -618,7 +618,7 @@ exports[`UnavailableInfo should match snapshot 1`] = ` Custodian Contact
No data
diff --git a/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx b/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx index afa10a3e50..5b808cf59f 100644 --- a/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx +++ b/containers/ecr-viewer/src/app/view-data/components/DataDisplay.tsx @@ -41,7 +41,7 @@ export const DataDisplay: React.FC<{
Date: Tue, 19 Nov 2024 17:36:36 -0500 Subject: [PATCH 07/13] fix: missing [] --- containers/ecr-viewer/src/app/services/labsService.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/ecr-viewer/src/app/services/labsService.tsx b/containers/ecr-viewer/src/app/services/labsService.tsx index d0f493a04f..4934127c7e 100644 --- a/containers/ecr-viewer/src/app/services/labsService.tsx +++ b/containers/ecr-viewer/src/app/services/labsService.tsx @@ -124,7 +124,7 @@ export function searchResultRecord( result: any[], searchKey: string, ): RenderableNode { - let resultsArray: RenderableNode = []; + let resultsArray: RenderableNode[] = []; // Loop through each table for (const table of result) { From a008ac46a6caeef13bcaf8ccc224909be9b7a7b3 Mon Sep 17 00:00:00 2001 From: Mary McGrath Date: Thu, 21 Nov 2024 17:24:35 -0500 Subject: [PATCH 08/13] Update containers/ecr-viewer/src/app/view-data/utils/utils.tsx Co-authored-by: Boban --- containers/ecr-viewer/src/app/view-data/utils/utils.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/containers/ecr-viewer/src/app/view-data/utils/utils.tsx b/containers/ecr-viewer/src/app/view-data/utils/utils.tsx index 9c5e63e0f4..d031de4040 100644 --- a/containers/ecr-viewer/src/app/view-data/utils/utils.tsx +++ b/containers/ecr-viewer/src/app/view-data/utils/utils.tsx @@ -98,7 +98,7 @@ export const arrayToElement = (vals: RenderableNode[]) => { // Wrap the items in a fragment and make sure they all have keys. // It reduces the cases to handle elsewhere in the logic and avoids // dupblicate key warnings. - const res = ( + return ( <> {vals.map((item, ind) => { // Make sure items always have a key @@ -111,5 +111,4 @@ export const arrayToElement = (vals: RenderableNode[]) => { })} ); - return res; }; From 40ce77ff05f69e5a6c4e4b2b024bdf9877ffd9f3 Mon Sep 17 00:00:00 2001 From: Mary McGrath Date: Thu, 21 Nov 2024 17:24:41 -0500 Subject: [PATCH 09/13] Update containers/ecr-viewer/src/app/view-data/utils/utils.tsx Co-authored-by: Boban --- containers/ecr-viewer/src/app/view-data/utils/utils.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/ecr-viewer/src/app/view-data/utils/utils.tsx b/containers/ecr-viewer/src/app/view-data/utils/utils.tsx index d031de4040..de5aa73694 100644 --- a/containers/ecr-viewer/src/app/view-data/utils/utils.tsx +++ b/containers/ecr-viewer/src/app/view-data/utils/utils.tsx @@ -97,7 +97,7 @@ export const arrayToElement = (vals: RenderableNode[]) => { // Wrap the items in a fragment and make sure they all have keys. // It reduces the cases to handle elsewhere in the logic and avoids - // dupblicate key warnings. + // duplicate key warnings. return ( <> {vals.map((item, ind) => { From 86473b0c62c766155a79ee2a26299b5f351d5faf Mon Sep 17 00:00:00 2001 From: Mary McGrath Date: Thu, 21 Nov 2024 18:07:55 -0500 Subject: [PATCH 10/13] fix: handle empty nodes --- .../seed-scripts/create-seed-data.py | 2 +- .../tests/__snapshots__/utils.test.tsx.snap | 9 +++++++ .../__snapshots__/LabInfo.test.tsx.snap | 1 - .../ecr-viewer/src/app/tests/utils.test.tsx | 8 ++++++ .../src/app/view-data/utils/utils.tsx | 27 ++++++++++++++++--- 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/containers/ecr-viewer/seed-scripts/create-seed-data.py b/containers/ecr-viewer/seed-scripts/create-seed-data.py index b391edffdd..f01720ce50 100644 --- a/containers/ecr-viewer/seed-scripts/create-seed-data.py +++ b/containers/ecr-viewer/seed-scripts/create-seed-data.py @@ -30,7 +30,7 @@ def _process_files(args): :return: A list of fhir bundles """ print("Converting files...") - subfolders = ["LA"] + subfolders = ["ME"] # Holds all of the rquests we are going to make requests = [] diff --git a/containers/ecr-viewer/src/app/tests/__snapshots__/utils.test.tsx.snap b/containers/ecr-viewer/src/app/tests/__snapshots__/utils.test.tsx.snap index 8296061dd7..9bea07aaf3 100644 --- a/containers/ecr-viewer/src/app/tests/__snapshots__/utils.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/__snapshots__/utils.test.tsx.snap @@ -35,3 +35,12 @@ exports[`Utils safeParse should remove comments 1`] = ` `; + +exports[`Utils safeParse should remove empty nodes 1`] = ` + +
+ + hiya + +
+`; diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap index 35d536ef97..63590e8983 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap @@ -1327,7 +1327,6 @@ NASHVILLE, TN

VUMC CERNER LAB - 04/18/2022 2:57 PM CDT

-

MICROARRAY REPORT NARRATIVE

diff --git a/containers/ecr-viewer/src/app/tests/utils.test.tsx b/containers/ecr-viewer/src/app/tests/utils.test.tsx index 4aaa2e137f..635a49cda1 100644 --- a/containers/ecr-viewer/src/app/tests/utils.test.tsx +++ b/containers/ecr-viewer/src/app/tests/utils.test.tsx @@ -565,6 +565,14 @@ describe("Utils", () => { expect(actual).toStrictEqual(jsx); }); + it("should remove empty nodes", () => { + const str = `


hiya`; + const parsed = safeParse(str); + const { asFragment } = render(parsed); + expect(asFragment()).toMatchSnapshot(); + cleanup(); + }); + it("should map xml-y HTML", () => { const str = `hi thereI'm contentonetwo`; const parsed = safeParse(str); diff --git a/containers/ecr-viewer/src/app/view-data/utils/utils.tsx b/containers/ecr-viewer/src/app/view-data/utils/utils.tsx index de5aa73694..ab409e71e5 100644 --- a/containers/ecr-viewer/src/app/view-data/utils/utils.tsx +++ b/containers/ecr-viewer/src/app/view-data/utils/utils.tsx @@ -88,10 +88,13 @@ export const safeParse = (val: string): RenderableNode => { * @returns - One string or element. */ export const arrayToElement = (vals: RenderableNode[]) => { + // Filter out empty nodes. + const trimmed = vals.map(trimEmptyElements).filter(Boolean); + // An empty array is returned for an empty input - if (vals.length === 0) { + if (trimmed.length === 0) { return ""; - } else if (vals.length === 1) { + } else if (trimmed.length === 1) { return vals[0]; } @@ -100,7 +103,7 @@ export const arrayToElement = (vals: RenderableNode[]) => { // duplicate key warnings. return ( <> - {vals.map((item, ind) => { + {trimmed.map((item, ind) => { // Make sure items always have a key const key = `el-${ind}`; return typeof item !== "object" ? ( @@ -112,3 +115,21 @@ export const arrayToElement = (vals: RenderableNode[]) => { ); }; + +/** + * Return "" if an element is empty, otherwise return the element. + *
are returned as is as it shouldn't have content in it. + * @param val - A RenderableNode. + * @returns - A string or element. + */ +const trimEmptyElements = (val: RenderableNode) => { + if (typeof val === "string") { + return val.trim(); + } + + // allowed to be empty - self-closing + if (val.type == "br") return val; + + // got children? go ahead + return val.props.children ? val : ""; +}; From 76e1f8a729d3a43768653ee0810553e5acef7f6f Mon Sep 17 00:00:00 2001 From: Mary McGrath Date: Fri, 22 Nov 2024 08:37:25 -0500 Subject: [PATCH 11/13] Update containers/ecr-viewer/seed-scripts/create-seed-data.py Co-authored-by: Boban --- containers/ecr-viewer/seed-scripts/create-seed-data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/ecr-viewer/seed-scripts/create-seed-data.py b/containers/ecr-viewer/seed-scripts/create-seed-data.py index f01720ce50..b391edffdd 100644 --- a/containers/ecr-viewer/seed-scripts/create-seed-data.py +++ b/containers/ecr-viewer/seed-scripts/create-seed-data.py @@ -30,7 +30,7 @@ def _process_files(args): :return: A list of fhir bundles """ print("Converting files...") - subfolders = ["ME"] + subfolders = ["LA"] # Holds all of the rquests we are going to make requests = [] From d37b06ad525f5caa0239c994f652c8040ce2b049 Mon Sep 17 00:00:00 2001 From: Mary McGrath Date: Fri, 22 Nov 2024 08:59:32 -0500 Subject: [PATCH 12/13] test: update tests post-merge --- .../__snapshots__/LabInfo.test.tsx.snap | 24 ++++++++++++++----- .../app/tests/services/labsService.test.tsx | 12 +++++----- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap index 83ded71e60..5332dabf23 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap @@ -80,24 +80,36 @@ exports[`LabInfo when labResults is DisplayDataProps[] should match snapshot tes - SARS-CoV-2, NAA CL + + SARS-CoV-2, NAA CL + - POS + + POS + - 2022-04-21T21:02:00.000Z + + 2022-04-21T21:02:00.000Z + - Symptomatic as defined by CDC? + + Symptomatic as defined by CDC? + - YES + + YES + - 2022-04-21T21:02:00.000Z + + 2022-04-21T21:02:00.000Z + diff --git a/containers/ecr-viewer/src/app/tests/services/labsService.test.tsx b/containers/ecr-viewer/src/app/tests/services/labsService.test.tsx index 14228bbf16..1e2963e184 100644 --- a/containers/ecr-viewer/src/app/tests/services/labsService.test.tsx +++ b/containers/ecr-viewer/src/app/tests/services/labsService.test.tsx @@ -240,29 +240,29 @@ describe("Labs Utils", () => { { "Lab Test Name": { metadata: {}, - value: "SARS-CoV-2, NAA CL", + value: SARS-CoV-2, NAA CL, }, "Lab Test Result Date": { metadata: {}, - value: "2022-04-21T21:02:00.000Z", + value: 2022-04-21T21:02:00.000Z, }, "Lab Test Result Value": { metadata: {}, - value: "POS", + value: POS, }, }, { "Lab Test Name": { metadata: {}, - value: "Symptomatic as defined by CDC?", + value: Symptomatic as defined by CDC?, }, "Lab Test Result Date": { metadata: {}, - value: "2022-04-21T21:02:00.000Z", + value: 2022-04-21T21:02:00.000Z, }, "Lab Test Result Value": { metadata: {}, - value: "YES", + value: YES, }, }, ], From 46dc51653b0aa614e149f315889bea55a52e4cba Mon Sep 17 00:00:00 2001 From: Mary McGrath Date: Fri, 22 Nov 2024 09:36:19 -0500 Subject: [PATCH 13/13] fix: handling of nested time values --- .../ecr-viewer/src/app/services/labsService.tsx | 7 +++++-- .../ecr-viewer/src/app/tests/assets/BundleLab.json | 2 +- .../components/__snapshots__/LabInfo.test.tsx.snap | 4 +--- .../__snapshots__/labsService.test.tsx.snap | 14 ++++++++++++++ .../src/app/tests/services/labsService.test.tsx | 11 +++++++---- 5 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 containers/ecr-viewer/src/app/tests/services/__snapshots__/labsService.test.tsx.snap diff --git a/containers/ecr-viewer/src/app/services/labsService.tsx b/containers/ecr-viewer/src/app/services/labsService.tsx index fa66c85d88..b9e07dd284 100644 --- a/containers/ecr-viewer/src/app/services/labsService.tsx +++ b/containers/ecr-viewer/src/app/services/labsService.tsx @@ -296,8 +296,11 @@ const returnAnalysisTime = ( let dateTime; if (typeof el === "string") { dateTime = el; - } else if (typeof el?.props?.children === "string") { - dateTime = el.props.children; + } else if ( + el?.props?.children?.length === 1 && + typeof el?.props?.children[0] === "string" + ) { + dateTime = el.props.children[0]; } else { return ""; } diff --git a/containers/ecr-viewer/src/app/tests/assets/BundleLab.json b/containers/ecr-viewer/src/app/tests/assets/BundleLab.json index 84f73037d2..e77a11106d 100644 --- a/containers/ecr-viewer/src/app/tests/assets/BundleLab.json +++ b/containers/ecr-viewer/src/app/tests/assets/BundleLab.json @@ -47,7 +47,7 @@ "title": "Results", "text": { "status": "generated", - "div": "
  • Stool Pathogens, NAAT, 12 to 25 Targets (09/28/2022 1:51 PM PDT)
    Component Value Ref Range Test Method Analysis Time Performed At Pathologist Signature
    Campylobacter, NAAT Not Detected Not Detected LAB DEVICE: BIOFIRE\u00ae FILMARRAY\u00ae 2.0 SYSTEM 09/28/2022 1:59 PM PDT PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675)
    Plesiomonas shigelloides, NAAT Not Detected Not Detected LAB DEVICE: BIOFIRE\u00ae FILMARRAY\u00ae 2.0 SYSTEM 09/28/2022 1:59 PM PDT PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675)
    Specimen (Source) Anatomical Location / Laterality Collection Method / Volume Collection Time Received Time
    Stool STOOL SPECIMEN / Unknown 09/28/2022 1:51 PM PDT 09/28/2022 1:51 PM PDT
    Authorizing Provider Result Type
    Ambhp1 Test MD MICROBIOLOGY - GENERAL ORDERABLES
    Performing Organization Address City/State/ZIP Code Phone Number
    PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675) 501 S. Buena Vista Street Burbank, CA 91505 818-847-6000
  • (ABNORMAL) Stool Pathogens, NAAT, 12 to 25 Targets (09/28/2022 1:51 PM PDT)
    Component Value Ref Range Test Method Analysis Time Performed At Pathologist Signature
    Campylobacter, NAAT Not Detected Not Detected LAB DEVICE: BIOFIRE\u00ae FILMARRAY\u00ae 2.0 SYSTEM 09/28/2022 2:00 PM PDT PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675)
    Plesiomonas shigelloides, NAAT Not Detected Not Detected LAB DEVICE: BIOFIRE\u00ae FILMARRAY\u00ae 2.0 SYSTEM 09/28/2022 2:00 PM PDT PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675)
    Specimen (Source) Anatomical Location / Laterality Collection Method / Volume Collection Time Received Time
    Stool STOOL SPECIMEN / Unknown 09/28/2022 1:51 PM PDT 09/28/2022 1:51 PM PDT
    Authorizing Provider Result Type
    Ambhp1 Test MD MICROBIOLOGY - GENERAL ORDERABLES
    Performing Organization Address City/State/ZIP Code Phone Number
    PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675) 501 S. Buena Vista Street Burbank, CA 91505 818-847-6000
  • Cytogenomic SNP microarray (04/04/2022 11:55 AM CDT)
    Component Value Ref Range Test Method Analysis Time Performed At Pathologist Signature
    Organism ID Acinetobacter baumannii VUMC CERNER LAB
    Sodium 139 138 - 145 mmol/L VUMC CERNER LAB
    Comment:
    Lab comment
    Organism Antibiotic Method Susceptibility
    Acinetobacter baumannii Amikacin MIC 0.25: Susceptible
    Acinetobacter baumannii Avycaz (Ceftazidime/Avibactam) MIC 0.05: Intermediate
    Acinetobacter baumannii Levofloxacin MIC 0.75: Resistant
    Specimen (Source) Anatomical Location / Laterality Collection Method / Volume Collection Time Received Time
    Blood Collection / Unknown 04/04/2022 11:55 AM CDT 04/18/2022 2:46 PM CDT
    Narrative
    VUMC CERNER LAB - 04/18/2022 2:57 PM CDT MICROARRAY REPORT NARRATIVE
    Resulting Agency Comment
    testing comment
    Authorizing Provider Result Type
    Carda Testprovqa MD LAB GENETIC TESTING
    Performing Organization Address City/State/ZIP Code Phone Number
    VUMC CERNER LAB 4605 TVC VUMC 1301 Medical Center Drive NASHVILLE, TN 37232-5310 615-875-5227
documented in this encounter" + "div": "
  • Stool Pathogens, NAAT, 12 to 25 Targets (09/28/2022 1:51 PM PDT)
    Component Value Ref Range Test Method Analysis Time Performed At Pathologist Signature
    Campylobacter, NAAT Not Detected Not Detected LAB DEVICE: BIOFIRE\u00ae FILMARRAY\u00ae 2.0 SYSTEM

    09/28/2022 1:59:00 PM PDT

    PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675)
    Plesiomonas shigelloides, NAAT Not Detected Not Detected LAB DEVICE: BIOFIRE\u00ae FILMARRAY\u00ae 2.0 SYSTEM

    09/28/2022 1:59:00 PM PDT

    PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675)
    Specimen (Source) Anatomical Location / Laterality Collection Method / Volume Collection Time Received Time
    Stool STOOL SPECIMEN / Unknown 09/28/2022 1:51 PM PDT 09/28/2022 1:51 PM PDT
    Authorizing Provider Result Type
    Ambhp1 Test MD MICROBIOLOGY - GENERAL ORDERABLES
    Performing Organization Address City/State/ZIP Code Phone Number
    PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675) 501 S. Buena Vista Street Burbank, CA 91505 818-847-6000
  • (ABNORMAL) Stool Pathogens, NAAT, 12 to 25 Targets (09/28/2022 1:51 PM PDT)
    Component Value Ref Range Test Method Analysis Time Performed At Pathologist Signature
    Campylobacter, NAAT Not Detected Not Detected LAB DEVICE: BIOFIRE\u00ae FILMARRAY\u00ae 2.0 SYSTEM 09/28/2022 2:00 PM PDT PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675)
    Plesiomonas shigelloides, NAAT Not Detected Not Detected LAB DEVICE: BIOFIRE\u00ae FILMARRAY\u00ae 2.0 SYSTEM 09/28/2022 2:00 PM PDT PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675)
    Specimen (Source) Anatomical Location / Laterality Collection Method / Volume Collection Time Received Time
    Stool STOOL SPECIMEN / Unknown 09/28/2022 1:51 PM PDT 09/28/2022 1:51 PM PDT
    Authorizing Provider Result Type
    Ambhp1 Test MD MICROBIOLOGY - GENERAL ORDERABLES
    Performing Organization Address City/State/ZIP Code Phone Number
    PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675) 501 S. Buena Vista Street Burbank, CA 91505 818-847-6000
  • Cytogenomic SNP microarray (04/04/2022 11:55 AM CDT)
    Component Value Ref Range Test Method Analysis Time Performed At Pathologist Signature
    Organism ID Acinetobacter baumannii VUMC CERNER LAB
    Sodium 139 138 - 145 mmol/L VUMC CERNER LAB
    Comment:
    Lab comment
    Organism Antibiotic Method Susceptibility
    Acinetobacter baumannii Amikacin MIC 0.25: Susceptible
    Acinetobacter baumannii Avycaz (Ceftazidime/Avibactam) MIC 0.05: Intermediate
    Acinetobacter baumannii Levofloxacin MIC 0.75: Resistant
    Specimen (Source) Anatomical Location / Laterality Collection Method / Volume Collection Time Received Time
    Blood Collection / Unknown 04/04/2022 11:55 AM CDT 04/18/2022 2:46 PM CDT
    Narrative
    VUMC CERNER LAB - 04/18/2022 2:57 PM CDT MICROARRAY REPORT NARRATIVE
    Resulting Agency Comment
    testing comment
    Authorizing Provider Result Type
    Carda Testprovqa MD LAB GENETIC TESTING
    Performing Organization Address City/State/ZIP Code Phone Number
    VUMC CERNER LAB 4605 TVC VUMC 1301 Medical Center Drive NASHVILLE, TN 37232-5310 615-875-5227
documented in this encounter" }, "code": { "coding": [ diff --git a/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap b/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap index 5332dabf23..78645cf1e7 100644 --- a/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap +++ b/containers/ecr-viewer/src/app/tests/components/__snapshots__/LabInfo.test.tsx.snap @@ -689,9 +689,7 @@ Burbank, CA
- 09/28/2022 1:59 PM PDT -
+ />
+

+ + 09/28/2022 1:59:00 PM PDT + +

+

+ 09/28/2022 1:59:00 PM PDT +

+ +`; diff --git a/containers/ecr-viewer/src/app/tests/services/labsService.test.tsx b/containers/ecr-viewer/src/app/tests/services/labsService.test.tsx index 1e2963e184..5692957058 100644 --- a/containers/ecr-viewer/src/app/tests/services/labsService.test.tsx +++ b/containers/ecr-viewer/src/app/tests/services/labsService.test.tsx @@ -51,7 +51,11 @@ const labReportNormalJsonObject = { metadata: {}, }, "Analysis Time": { - value: "09/28/2022 1:59 PM PDT", + value: ( +

+ 09/28/2022 1:59:00 PM PDT +

+ ), metadata: {}, }, "Performed At": { @@ -82,7 +86,7 @@ const labReportNormalJsonObject = { metadata: {}, }, "Analysis Time": { - value: "09/28/2022 1:59 PM PDT", + value:

09/28/2022 1:59:00 PM PDT

, metadata: {}, }, "Performed At": { @@ -330,14 +334,13 @@ describe("Labs Utils", () => { describe("returnFieldValueFromLabHtmlString", () => { it("extracts correct field value from within a lab report", () => { const fieldName = "Analysis Time"; - const expectedResult = "09/28/2022 1:59 PM PDT"; const result = returnFieldValueFromLabHtmlString( labReportNormalJsonObject, fieldName, ); - expect(result).toStrictEqual(expectedResult); + expect(result).toMatchSnapshot(); }); it("returns NoData if none are found for field name", () => {