From 2076a306a6a504afcfe99556b5dfa7e822807cbf Mon Sep 17 00:00:00 2001 From: Trevor McMaster Date: Fri, 27 Jan 2023 14:35:12 -0700 Subject: [PATCH] Updated Chart.js dependency --- guide/results-viewer-react/package-lock.json | 50 +++++++++++++------ guide/results-viewer-react/package.json | 4 +- .../src/chartjs-adapter-date-fns.d.ts | 2 + .../src/components/TestResults/charts.ts | 19 +++---- .../src/components/TestResults/index.tsx | 29 ++++++++--- .../src/components/TestResults/model.ts | 6 +-- .../src/components/YamlWriterForm/index.tsx | 3 +- 7 files changed, 73 insertions(+), 40 deletions(-) create mode 100644 guide/results-viewer-react/src/chartjs-adapter-date-fns.d.ts diff --git a/guide/results-viewer-react/package-lock.json b/guide/results-viewer-react/package-lock.json index 39dcba16..b21df770 100644 --- a/guide/results-viewer-react/package-lock.json +++ b/guide/results-viewer-react/package-lock.json @@ -10,8 +10,8 @@ "license": "ISC", "dependencies": { "@fs/hdr-histogram-wasm": "file:./lib/hdr-histogram-wasm", - "chart.js": "^3.9.1", - "chartjs-adapter-date-fns": "^2.0.1", + "chart.js": "~4.2.0", + "chartjs-adapter-date-fns": "^3.0.0", "date-fns": "^2.29.3", "file-saver": "^2.0.5", "immutability-helper": "^3.1.1", @@ -2523,6 +2523,11 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", @@ -11571,16 +11576,23 @@ } }, "node_modules/chart.js": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz", - "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.2.0.tgz", + "integrity": "sha512-wbtcV+QKeH0F7gQZaCJEIpsNriFheacouJQTVIjITi3eQA8bTlIBoknz0+dgV79aeKLNMAX+nDslIVE/nJ3rzA==", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": "^7.0.0" + } }, "node_modules/chartjs-adapter-date-fns": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-2.0.1.tgz", - "integrity": "sha512-v3WV9rdnQ05ce3A0ZCjzUekJCAbfm6+3HqSoeY2BIkdMYZoYr/4T+ril1tZyDl869lz6xdNVMXejUFT9YKpw4A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz", + "integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==", "peerDependencies": { - "chart.js": ">=2.8.0" + "chart.js": ">=2.8.0", + "date-fns": ">=2.0.0" } }, "node_modules/chokidar": { @@ -26754,6 +26766,11 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + }, "@leichtgewicht/ip-codec": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", @@ -33849,14 +33866,17 @@ "dev": true }, "chart.js": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz", - "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.2.0.tgz", + "integrity": "sha512-wbtcV+QKeH0F7gQZaCJEIpsNriFheacouJQTVIjITi3eQA8bTlIBoknz0+dgV79aeKLNMAX+nDslIVE/nJ3rzA==", + "requires": { + "@kurkle/color": "^0.3.0" + } }, "chartjs-adapter-date-fns": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-2.0.1.tgz", - "integrity": "sha512-v3WV9rdnQ05ce3A0ZCjzUekJCAbfm6+3HqSoeY2BIkdMYZoYr/4T+ril1tZyDl869lz6xdNVMXejUFT9YKpw4A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz", + "integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==", "requires": {} }, "chokidar": { diff --git a/guide/results-viewer-react/package.json b/guide/results-viewer-react/package.json index cda7dc8d..ead4ff48 100644 --- a/guide/results-viewer-react/package.json +++ b/guide/results-viewer-react/package.json @@ -29,8 +29,8 @@ "homepage": "https://github.com/FamilySearch/pewpew/tree/master/lib/config-wasm#readme", "dependencies": { "@fs/hdr-histogram-wasm": "file:./lib/hdr-histogram-wasm", - "chart.js": "^3.9.1", - "chartjs-adapter-date-fns": "^2.0.1", + "chart.js": "~4.2.0", + "chartjs-adapter-date-fns": "^3.0.0", "date-fns": "^2.29.3", "file-saver": "^2.0.5", "immutability-helper": "^3.1.1", diff --git a/guide/results-viewer-react/src/chartjs-adapter-date-fns.d.ts b/guide/results-viewer-react/src/chartjs-adapter-date-fns.d.ts new file mode 100644 index 00000000..f3382cf2 --- /dev/null +++ b/guide/results-viewer-react/src/chartjs-adapter-date-fns.d.ts @@ -0,0 +1,2 @@ +// https://stackoverflow.com/questions/72374653/typescript-types-for-chartjs-adapter-date-fns +declare module "chartjs-adapter-date-fns"; diff --git a/guide/results-viewer-react/src/components/TestResults/charts.ts b/guide/results-viewer-react/src/components/TestResults/charts.ts index ad3ef908..0a378948 100644 --- a/guide/results-viewer-react/src/components/TestResults/charts.ts +++ b/guide/results-viewer-react/src/components/TestResults/charts.ts @@ -1,4 +1,3 @@ -import "chartjs-adapter-date-fns"; import { Chart, ChartDataset, @@ -12,6 +11,7 @@ import { LinearScale, LogarithmicScale, PointElement, + ScatterDataPoint, TimeScale, Title, Tooltip @@ -69,9 +69,9 @@ export function RTT (el: HTMLCanvasElement, dataPoints: DataPoint[]): Chart { const borderColor = colors[i % colors.length]; const backgroundColor = borderColor + "46"; let label: string; - let data: Chart.ChartPoint[]; - // eslint-disable-next-line eqeqeq - if (type == "avg") { + // It's a ScatterDataPoint but thanks to chartjs-adapter-date-fns it will date Dates as well as numbers + let data: (Omit & { x: Date | number })[]; + if (type === "avg") { label = "Avg"; data = dataPoints.map((dp) => ({ x: dp.time, @@ -79,8 +79,7 @@ export function RTT (el: HTMLCanvasElement, dataPoints: DataPoint[]): Chart { ? Math.round(dp.rttHistogram.getMean()) / MICROS_TO_MS : NaN })); - // eslint-disable-next-line eqeqeq - } else if (type == "min") { + } else if (type === "min") { label = "Min"; data = dataPoints.map((dp) => ({ x: dp.time, @@ -88,8 +87,7 @@ export function RTT (el: HTMLCanvasElement, dataPoints: DataPoint[]): Chart { ? Number(dp.rttHistogram.getMinNonZeroValue()) / MICROS_TO_MS : NaN })); - // eslint-disable-next-line eqeqeq - } else if (type == "max") { + } else if (type === "max") { label = "Max"; data = dataPoints.map((dp) => ({ x: dp.time, @@ -97,8 +95,7 @@ export function RTT (el: HTMLCanvasElement, dataPoints: DataPoint[]): Chart { ? Number(dp.rttHistogram.getMaxValue()) / MICROS_TO_MS : NaN })); - // eslint-disable-next-line eqeqeq - } else if (type == "std") { + } else if (type === "std") { label = "Std Dev"; data = dataPoints.map((dp) => ({ x: dp.time, @@ -106,7 +103,7 @@ export function RTT (el: HTMLCanvasElement, dataPoints: DataPoint[]): Chart { ? Math.round(dp.rttHistogram.getStdDeviation()) / MICROS_TO_MS : NaN })); - } else if (typeof type == "number") { + } else if (typeof type === "number") { label = type + "th PCTL"; data = dataPoints.map((dp) => ({ x: dp.time, diff --git a/guide/results-viewer-react/src/components/TestResults/index.tsx b/guide/results-viewer-react/src/components/TestResults/index.tsx index 4efbf5bd..509ae56f 100644 --- a/guide/results-viewer-react/src/components/TestResults/index.tsx +++ b/guide/results-viewer-react/src/components/TestResults/index.tsx @@ -84,6 +84,7 @@ export interface TestResultProps { } export interface TestResultState { + defaultMessage: string; /** Filters the results Data by a tag equalling this value. I.e. 'method', 'url', '_id' */ summaryTagFilter: string; /** Filters the results Data by a summaryTagFilter's value containing this value */ @@ -155,8 +156,7 @@ const minMaxTime = (testResults: any) => { const startTime3: Date = new Date(startTime2); const endTime3: Date = new Date(endTime2); - // eslint-disable-next-line eqeqeq - const includeDateWithStart = startTime3.toLocaleDateString() == endTime3.toLocaleDateString(); + const includeDateWithStart = startTime3.toLocaleDateString() === endTime3.toLocaleDateString(); testTimes.startTime = dateToString(startTime3, includeDateWithStart); testTimes.endTime = dateToString(endTime3, false); @@ -189,8 +189,12 @@ const freeHistograms = (resultsData: ParsedFileEntry[] | undefined, summaryData: for (const [bucketId, dataPoints] of oldData) { let counter = 0; for (const dataPoint of dataPoints) { - log(`Freeing histogram ${JSON.stringify(bucketId)}: ${counter++}`, LogLevel.DEBUG); - dataPoint.rttHistogram.free(); + try { + log(`Freeing histogram ${JSON.stringify(bucketId)}: ${counter++}`, LogLevel.DEBUG); + dataPoint.rttHistogram.free(); + } catch (error) { + log(`Freeing histogram ${JSON.stringify(bucketId)} failed: ${counter}`, LogLevel.WARN, error); + } } } }; @@ -280,7 +284,9 @@ const getSummaryData = ({ }; export const TestResults = ({ resultsText }: TestResultProps) => { + const defaultMessage = "Select Results File"; const defaultState: TestResultState = { + defaultMessage, summaryTagFilter: "", summaryTagValueFilter: "", resultsData: undefined, @@ -296,6 +302,9 @@ export const TestResults = ({ resultsText }: TestResultProps) => { setState((oldState: TestResultState) => ({ ...oldState, ...newState })); const updateResultsData = async (resultsText: string): Promise => { + updateState({ + defaultMessage: "Results Loading..." + }); try { // if there are multiple jsons (new format), split them up and parse them separately const results = resultsText.replace(/}{/g, "}\n{") @@ -324,6 +333,7 @@ export const TestResults = ({ resultsText }: TestResultProps) => { log("updateResultsData", LogLevel.DEBUG, { filteredData: filteredData?.length, resultsData: resultsData?.length, summaryData }); updateState({ + defaultMessage, resultsData, filteredData, summaryData, @@ -333,6 +343,7 @@ export const TestResults = ({ resultsText }: TestResultProps) => { } catch (error) { log("Error parsing Data", LogLevel.ERROR, error); updateState({ + defaultMessage, error: formatError(error) }); } @@ -376,6 +387,11 @@ export const TestResults = ({ resultsText }: TestResultProps) => { }); }; + useEffect(() => { + import("chartjs-adapter-date-fns") + .catch((error) => log("Could not load chartjs-adapter-date-fns import", LogLevel.ERROR, error)); + }, []); + useEffect(() => { updateResultsData(resultsText); }, [resultsText]); @@ -422,7 +438,7 @@ export const TestResults = ({ resultsText }: TestResultProps) => { })} ) : ( -

No Results Found

+

{state.defaultMessage}

)} ); @@ -562,8 +578,7 @@ const Endpoint = ({ bucketId, dataPoints }: EndpointProps) => {
    {Object.entries(bucketId).map(([key, value], idx) => { - // eslint-disable-next-line eqeqeq - if (key != "method" && key != "url") { + if (key !== "method" && key !== "url") { return (
  • {key} - {value} diff --git a/guide/results-viewer-react/src/components/TestResults/model.ts b/guide/results-viewer-react/src/components/TestResults/model.ts index 3acc2779..b0ce3cbc 100644 --- a/guide/results-viewer-react/src/components/TestResults/model.ts +++ b/guide/results-viewer-react/src/components/TestResults/model.ts @@ -4,7 +4,7 @@ type Check = [string, CheckType]; // eslint-disable-next-line @typescript-eslint/ban-types function isObject (o: unknown): o is object { - return typeof o == "object" && !!o; + return typeof o === "object" && !!o; } /** @@ -172,7 +172,7 @@ function isStatusCounts (sc: unknown): sc is StatusCounts { // check that the keys can be parsed as a number and the values are numbers return Object.entries(sc).every( ([k, v]: [string, unknown]) => - Number.parseInt(k, 10) > 0 && typeof v == "number" + Number.parseInt(k, 10) > 0 && typeof v === "number" ); } @@ -181,7 +181,7 @@ function isTestErrors (sc: unknown): sc is TestErrors { return false; } // check that the values are all numbers - return Object.values(sc).every((v: unknown) => typeof v == "number"); + return Object.values(sc).every((v: unknown) => typeof v === "number"); } export interface DataPointPreProcessed { diff --git a/guide/results-viewer-react/src/components/YamlWriterForm/index.tsx b/guide/results-viewer-react/src/components/YamlWriterForm/index.tsx index 7902010c..2517d1c4 100644 --- a/guide/results-viewer-react/src/components/YamlWriterForm/index.tsx +++ b/guide/results-viewer-react/src/components/YamlWriterForm/index.tsx @@ -80,8 +80,7 @@ export interface YamlWriterFormState { } const nameReg = new RegExp("^[A-Za-z_-].*$"); -// eslint-disable-next-line no-useless-escape -const valueReg = new RegExp("^[A-Za-z0-9_-\{\}\$].*$"); +const valueReg = new RegExp("^[A-Za-z0-9_-{}$].*$"); const defaults = "default"; type YamlWriterBooleanState = "default" | "filterHeaders" | "authenticated";