From 0007fb4e50e0ca98f525a5aad835fc0e4048c7a5 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Mon, 22 Jul 2024 03:18:51 -0400 Subject: [PATCH 01/30] Add initial code. --- .../log-viewer-webui/client/package-lock.json | 56 ++++++++++++++++++- .../log-viewer-webui/client/package.json | 3 +- .../log-viewer-webui/client/src/App.jsx | 40 +++++++++++++ .../log-viewer-webui/client/webpack.config.js | 8 +++ .../SearchResultsTable.scss | 4 ++ .../SearchResultsTable/index.jsx | 47 ++++++++++------ components/webui/settings.json | 1 + 7 files changed, 138 insertions(+), 21 deletions(-) diff --git a/components/log-viewer-webui/client/package-lock.json b/components/log-viewer-webui/client/package-lock.json index bf75b0710..ec64f42bd 100644 --- a/components/log-viewer-webui/client/package-lock.json +++ b/components/log-viewer-webui/client/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "license": "Apache-2.0", "dependencies": { + "axios": "^1.7.2", "react": "^18.3.1", "react-dom": "^18.3.1" }, @@ -3298,6 +3299,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -3314,6 +3320,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/babel-loader": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", @@ -3724,6 +3740,17 @@ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -4154,6 +4181,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -5487,7 +5522,6 @@ "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true, "funding": [ { "type": "individual", @@ -5541,6 +5575,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -7230,7 +7277,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -7239,7 +7285,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -8145,6 +8190,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/components/log-viewer-webui/client/package.json b/components/log-viewer-webui/client/package.json index 47b2a7af3..ec6d01387 100644 --- a/components/log-viewer-webui/client/package.json +++ b/components/log-viewer-webui/client/package.json @@ -35,6 +35,7 @@ }, "dependencies": { "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "axios": "^1.7.2" } } diff --git a/components/log-viewer-webui/client/src/App.jsx b/components/log-viewer-webui/client/src/App.jsx index 3a6f57fff..38732f67d 100644 --- a/components/log-viewer-webui/client/src/App.jsx +++ b/components/log-viewer-webui/client/src/App.jsx @@ -1,9 +1,49 @@ +import { + useEffect, + useRef, +} from "react"; + +import axios from "axios"; + + +/** + * Submits a job to extract an IR + * + * @param {number|string} origFileId The ID of the original file to extract IR from + * @param {number} logEventIx The index of the log event + */ +const submitExtractIrJob = async (origFileId, logEventIx) => { + const {data} = await axios.post("/query/extract-ir", { + msg_ix: logEventIx, + orig_file_id: origFileId, + }); + + window.location = `/log-viewer/index.html?filePath=http://${window.location.host}/ir/${data.path}`; +}; + /** * Renders the main application. * * @return {JSX.Element} */ const App = () => { + const isFirstRun = useRef(true); + + useEffect(() => { + if (false === isFirstRun.current) { + return; + } + isFirstRun.current = false; + + const searchParams = new URLSearchParams(window.location.search); + const origFileId = searchParams.get("origFileId"); + const logEventIx = searchParams.get("logEventIx"); + if (null === origFileId || null === logEventIx) { + console.error("Either origFileId or logEventIx is missing from the URL parameters"); + } + submitExtractIrJob(origFileId, logEventIx).then(); + }, []); + return (

Hello world!

); diff --git a/components/log-viewer-webui/client/webpack.config.js b/components/log-viewer-webui/client/webpack.config.js index 2829b3c10..61ec64bb6 100644 --- a/components/log-viewer-webui/client/webpack.config.js +++ b/components/log-viewer-webui/client/webpack.config.js @@ -22,6 +22,14 @@ const plugins = [ ]; const config = { + devServer: { + proxy: [ + { + context: ["/"], + target: "http://localhost:3000", + }, + ], + }, devtool: isProduction ? "source-map" : "eval-source-map", diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss index 6c24ec2da..6b6d2d656 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss @@ -29,6 +29,10 @@ .search-results-content { font-size: 0.875rem; line-height: var(--search-results-message-line-height); + + &-clickable { + cursor: pointer; + } } .search-results-timestamp { diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index 77d6af8a8..ab805c360 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -1,3 +1,4 @@ +import {Meteor} from "meteor/meteor"; import {useEffect} from "react"; import Table from "react-bootstrap/Table"; @@ -35,7 +36,7 @@ const SEARCH_RESULT_MESSAGE_LINE_HEIGHT = 1.5; * @param {boolean} props.hasMoreResultsInTotal * @param {number} props.maxLinesPerResult * @param {Function} props.onLoadMoreResults - * @param {object} props.searchResults + * @param {object[]} props.searchResults * @param {Function} props.setFieldToSortBy * @return {React.ReactElement} */ @@ -77,6 +78,12 @@ const SearchResultsTable = ({ } }; + const handleSearchResultClick = (ev) => { + const {orig_file_id: origFileId, log_event_ix:logEventIx} = ev.currentTarget.dataset; + window.open(Meteor.settings.public.LogViewerWebuiClientUrl + + `?origFileId=${origFileId}&logEventIx=${logEventIx}`); + }; + useEffect(() => { document.documentElement.style.setProperty( "--search-results-message-line-height", @@ -91,24 +98,30 @@ const SearchResultsTable = ({ ); }, [maxLinesPerResult]); - const rows = []; - for (let i = 0; i < searchResults.length; ++i) { - const searchResult = searchResults[i]; - rows.push( - + const rows = searchResults.map((result)=> { + return ( + - {searchResult.timestamp ? - dayjs.utc(searchResult.timestamp).format(DATETIME_FORMAT_TEMPLATE) : + {result.timestamp ? + dayjs.utc(result.timestamp).format(DATETIME_FORMAT_TEMPLATE) : "N/A"} -
-                        {searchResult.message}
-                    
+ +
+                            {result.message}
+                        
+
); - } + }); return (
@@ -119,11 +132,11 @@ const SearchResultsTable = ({ striped={true} > - - +
diff --git a/components/webui/settings.json b/components/webui/settings.json index 335ae0b51..d5c929147 100644 --- a/components/webui/settings.json +++ b/components/webui/settings.json @@ -13,6 +13,7 @@ "AggregationResultsCollectionName": "aggregation-results", "ClpStorageEngine": "clp", "CompressionJobsCollectionName": "compression-jobs", + "LogViewerWebuiClientUrl": "http://localhost:8080", "SearchResultsCollectionName": "search-results", "SearchResultsMetadataCollectionName": "results-metadata", "StatsCollectionName": "stats", From c6d89d9678afc0178e9e2f7a0320005488a366db Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Mon, 22 Jul 2024 03:37:23 -0400 Subject: [PATCH 02/30] Reformat code. --- .../SearchResultsTable/index.jsx | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index ab805c360..7f0326822 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -79,9 +79,9 @@ const SearchResultsTable = ({ }; const handleSearchResultClick = (ev) => { - const {orig_file_id: origFileId, log_event_ix:logEventIx} = ev.currentTarget.dataset; - window.open(Meteor.settings.public.LogViewerWebuiClientUrl + - `?origFileId=${origFileId}&logEventIx=${logEventIx}`); + const {orig_file_id: origFileId, log_event_ix: logEventIx} = ev.currentTarget.dataset; + window.open(`${Meteor.settings.public.LogViewerWebuiClientUrl + }?origFileId=${origFileId}&logEventIx=${logEventIx}`); }; useEffect(() => { @@ -98,7 +98,7 @@ const SearchResultsTable = ({ ); }, [maxLinesPerResult]); - const rows = searchResults.map((result)=> { + const rows = searchResults.map((result) => { return ( @@ -108,13 +108,15 @@ const SearchResultsTable = ({ + data-orig_file_id={result.orig_file_id} + title={"Go to the log context"} + onClick={handleSearchResultClick} + >
+                            className={"search-results-content search-results-message"}
+                        >
                             {result.message}
                         
@@ -132,11 +134,11 @@ const SearchResultsTable = ({ striped={true} > - - +
From 44c15ebba99bab11c0b083fabacf6b19ca0f8d1e Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Mon, 22 Jul 2024 03:40:00 -0400 Subject: [PATCH 03/30] Reformat code. --- .../SearchResultsTable/index.jsx | 52 +++++++++---------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index 7f0326822..3ef3aabb4 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -98,33 +98,6 @@ const SearchResultsTable = ({ ); }, [maxLinesPerResult]); - const rows = searchResults.map((result) => { - return ( - - - {result.timestamp ? - dayjs.utc(result.timestamp).format(DATETIME_FORMAT_TEMPLATE) : - "N/A"} - - - -
-                            {result.message}
-                        
-
- - - ); - }); - return (
- {rows} + {searchResults.map((result) => ( + + + + + ))}
+ {result.timestamp ? + dayjs.utc(result.timestamp).format(DATETIME_FORMAT_TEMPLATE) : + "N/A"} + + +
+                                        {result.message}
+                                    
+
+
Date: Tue, 23 Jul 2024 02:33:44 -0400 Subject: [PATCH 04/30] Add loading state UI to log-viewer-webui-client. --- .../log-viewer-webui/client/package-lock.json | 612 ++++++++++++++++-- .../log-viewer-webui/client/package.json | 8 +- .../log-viewer-webui/client/public/index.html | 4 + .../log-viewer-webui/client/src/App.jsx | 43 +- .../log-viewer-webui/client/src/api/query.js | 42 ++ .../client/src/ui/Loading.jsx | 148 +++++ .../client/src/ui/QueryState.jsx | 51 ++ 7 files changed, 801 insertions(+), 107 deletions(-) create mode 100644 components/log-viewer-webui/client/src/api/query.js create mode 100644 components/log-viewer-webui/client/src/ui/Loading.jsx create mode 100644 components/log-viewer-webui/client/src/ui/QueryState.jsx diff --git a/components/log-viewer-webui/client/package-lock.json b/components/log-viewer-webui/client/package-lock.json index ec64f42bd..4141c89aa 100644 --- a/components/log-viewer-webui/client/package-lock.json +++ b/components/log-viewer-webui/client/package-lock.json @@ -9,6 +9,10 @@ "version": "0.1.0", "license": "Apache-2.0", "dependencies": { + "@emotion/react": "^11.13.0", + "@emotion/styled": "^11.13.0", + "@mui/joy": "^5.0.0-beta.48", + "@types/react": "^18.3.3", "axios": "^1.7.2", "react": "^18.3.1", "react-dom": "^18.3.1" @@ -47,7 +51,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, "dependencies": { "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" @@ -99,7 +102,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7", "@jridgewell/gen-mapping": "^0.3.5", @@ -211,7 +213,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -223,7 +224,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, "dependencies": { "@babel/template": "^7.24.7", "@babel/types": "^7.24.7" @@ -236,7 +236,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -261,7 +260,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -374,7 +372,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -386,7 +383,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -395,7 +391,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -441,7 +436,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", @@ -456,7 +450,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", - "dev": true, "bin": { "parser": "bin/babel-parser.js" }, @@ -1765,7 +1758,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", - "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1777,7 +1769,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/parser": "^7.24.7", @@ -1791,7 +1782,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/generator": "^7.24.7", @@ -1812,7 +1802,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.24.7", "@babel/helper-validator-identifier": "^7.24.7", @@ -1831,6 +1820,152 @@ "node": ">=10.0.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.2.0", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.0.tgz", + "integrity": "sha512-hPV345J/tH0Cwk2wnU/3PBzORQ9HeX+kQSbwI+jslzpRCHE6fSGTohswksA/Ensr8znPzwfzKZCmAM9Lmlhp7g==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz", + "integrity": "sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, + "node_modules/@emotion/react": { + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.0.tgz", + "integrity": "sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz", + "integrity": "sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.9.0", + "@emotion/utils": "^1.4.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" + }, + "node_modules/@emotion/styled": { + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", + "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz", + "integrity": "sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", + "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" + }, "node_modules/@es-joy/jsdoccomment": { "version": "0.43.1", "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.43.1.tgz", @@ -1963,6 +2098,40 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.5.tgz", + "integrity": "sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA==", + "dependencies": { + "@floating-ui/utils": "^0.2.5" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.8.tgz", + "integrity": "sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.5" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.5.tgz", + "integrity": "sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -2073,7 +2242,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -2087,7 +2255,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -2096,7 +2263,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -2114,14 +2280,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2187,6 +2351,228 @@ "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", "dev": true }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", + "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@floating-ui/react-dom": "^2.0.8", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "@popperjs/core": "^2.11.8", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.4.tgz", + "integrity": "sha512-rNdHXhclwjEZnK+//3SR43YRx0VtjdHnUFhMSGYmAMJve+KiwEja/41EYh8V3pZKqF2geKyfcFUenTfDTYUR4w==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/joy": { + "version": "5.0.0-beta.48", + "resolved": "https://registry.npmjs.org/@mui/joy/-/joy-5.0.0-beta.48.tgz", + "integrity": "sha512-OhTvjuGl9I5IvpBr0BQyDehIW/xb2yteW6YglHJMdOb/279nItn76X1NBtPV9ImldNlBjReGwvpOXmBTTGER9w==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.40", + "@mui/core-downloads-tracker": "^5.16.1", + "@mui/system": "^5.16.1", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.1", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.4.tgz", + "integrity": "sha512-ZsAm8cq31SJ37SVWLRlu02v9SRthxnfQofaiv14L5Bht51B0dz6yQEoVU/V8UduZDCCIrWkBHuReVfKhE/UuXA==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.16.4", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.4.tgz", + "integrity": "sha512-0+mnkf+UiAmTVB8PZFqOhqf729Yh0Cxq29/5cA3VAyDVTRIUUQ8FXQhiAhUIbijFmM72rY80ahFPXIm4WDbzcA==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.4.tgz", + "integrity": "sha512-ET1Ujl2/8hbsD611/mqUuNArMCGv/fIWO/f8B3ZqF5iyPHM2aS74vhTNyjytncc4i6dYwGxNk+tLa7GwjNS0/w==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.16.4", + "@mui/styled-engine": "^5.16.4", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.4", + "clsx": "^2.1.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz", + "integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.4.tgz", + "integrity": "sha512-nlppYwq10TBIFqp7qxY0SvbACOXeOjeVL3pOcDsK0FT8XjrEXh9/+lkg8AEIzD16z7YfiJDQjaJG2OLkE7BxNg==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.3.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2305,6 +2691,15 @@ "node": ">= 8" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@stylistic/eslint-plugin-js": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.8.1.tgz", @@ -2504,6 +2899,16 @@ "@types/node": "*" } }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + }, "node_modules/@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", @@ -2516,6 +2921,15 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/retry": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", @@ -3062,7 +3476,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -3347,6 +3760,20 @@ "webpack": ">=5" } }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.11", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", @@ -3589,8 +4016,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "peer": true, "engines": { "node": ">=6" } @@ -3629,7 +4054,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -3643,7 +4067,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -3719,11 +4142,18 @@ "node": ">=6" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -3731,8 +4161,7 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/colorette": { "version": "2.0.20", @@ -3915,6 +4344,21 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -4016,6 +4460,11 @@ "node": ">=4" } }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -4074,7 +4523,6 @@ "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -4402,6 +4850,14 @@ "node": ">=4" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/error-stack-parser": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", @@ -4600,8 +5056,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "peer": true, "engines": { "node": ">=10" }, @@ -5470,6 +5924,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -5631,7 +6090,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5792,7 +6250,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } @@ -5880,7 +6337,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -5941,7 +6397,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -5958,6 +6413,14 @@ "he": "bin/he" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", @@ -6216,8 +6679,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "peer": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -6390,6 +6851,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, "node_modules/is-async-function": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", @@ -6465,7 +6931,6 @@ "version": "2.14.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", - "dev": true, "dependencies": { "hasown": "^2.0.2" }, @@ -6985,7 +7450,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -7003,8 +7467,7 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-traverse": { "version": "0.4.1", @@ -7090,6 +7553,11 @@ "node": ">= 0.8.0" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -7365,8 +7833,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -7483,8 +7950,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -7781,8 +8246,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "peer": true, "dependencies": { "callsites": "^3.0.0" }, @@ -7804,6 +8267,23 @@ "node": ">= 18" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -7854,8 +8334,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.11.1", @@ -7892,8 +8371,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "peer": true, "engines": { "node": ">=8" } @@ -7901,8 +8378,7 @@ "node_modules/picocolors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "node_modules/picomatch": { "version": "4.0.2", @@ -8160,8 +8636,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "peer": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -8308,9 +8782,7 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, - "peer": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-refresh": { "version": "0.14.2", @@ -8414,8 +8886,7 @@ "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/regenerator-transform": { "version": "0.15.2", @@ -8524,7 +8995,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -8562,8 +9032,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -9397,11 +9865,15 @@ "webpack": "^5.27.0" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -9413,7 +9885,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -9552,7 +10023,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, "engines": { "node": ">=4" } @@ -10546,6 +11016,14 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/components/log-viewer-webui/client/package.json b/components/log-viewer-webui/client/package.json index ec6d01387..8978b8aee 100644 --- a/components/log-viewer-webui/client/package.json +++ b/components/log-viewer-webui/client/package.json @@ -34,8 +34,12 @@ ] }, "dependencies": { + "@emotion/react": "^11.13.0", + "@emotion/styled": "^11.13.0", + "@mui/joy": "^5.0.0-beta.48", + "@types/react": "^18.3.3", + "axios": "^1.7.2", "react": "^18.3.1", - "react-dom": "^18.3.1", - "axios": "^1.7.2" + "react-dom": "^18.3.1" } } diff --git a/components/log-viewer-webui/client/public/index.html b/components/log-viewer-webui/client/public/index.html index e0646892c..971424b95 100644 --- a/components/log-viewer-webui/client/public/index.html +++ b/components/log-viewer-webui/client/public/index.html @@ -5,6 +5,10 @@ + + +
diff --git a/components/log-viewer-webui/client/src/App.jsx b/components/log-viewer-webui/client/src/App.jsx index 38732f67d..5b8ad6a67 100644 --- a/components/log-viewer-webui/client/src/App.jsx +++ b/components/log-viewer-webui/client/src/App.jsx @@ -1,51 +1,18 @@ -import { - useEffect, - useRef, -} from "react"; +import {CssVarsProvider} from "@mui/joy/styles/CssVarsProvider"; -import axios from "axios"; +import Query from "./ui/QueryState.jsx"; -/** - * Submits a job to extract an IR - * - * @param {number|string} origFileId The ID of the original file to extract IR from - * @param {number} logEventIx The index of the log event - */ -const submitExtractIrJob = async (origFileId, logEventIx) => { - const {data} = await axios.post("/query/extract-ir", { - msg_ix: logEventIx, - orig_file_id: origFileId, - }); - - window.location = `/log-viewer/index.html?filePath=http://${window.location.host}/ir/${data.path}`; -}; - /** * Renders the main application. * * @return {JSX.Element} */ const App = () => { - const isFirstRun = useRef(true); - - useEffect(() => { - if (false === isFirstRun.current) { - return; - } - isFirstRun.current = false; - - const searchParams = new URLSearchParams(window.location.search); - const origFileId = searchParams.get("origFileId"); - const logEventIx = searchParams.get("logEventIx"); - if (null === origFileId || null === logEventIx) { - console.error("Either origFileId or logEventIx is missing from the URL parameters"); - } - submitExtractIrJob(origFileId, logEventIx).then(); - }, []); - return ( -

Hello world!

+ + + ); }; diff --git a/components/log-viewer-webui/client/src/api/query.js b/components/log-viewer-webui/client/src/api/query.js new file mode 100644 index 000000000..8cb96151a --- /dev/null +++ b/components/log-viewer-webui/client/src/api/query.js @@ -0,0 +1,42 @@ +import axios from "axios"; + + +/** + * @typedef {number} QueryLoadState + */ +let enumQueryLoadState; +/** + * Enum of query loading state. + * + * @enum {QueryLoadState} + */ +const QUERY_LOAD_STATE = Object.freeze({ + SUBMITTING: (enumQueryLoadState = 0), + WAITING: ++enumQueryLoadState, + LOADING: ++enumQueryLoadState, +}); + +/** + * Submits a job to extract a segment of the original file, which contains a given log event index, + * into CLP's IR format for viewing in the Log Viewer. + * + * @param {number|string} origFileId The ID of the original file to extract IR from + * @param {number} logEventIx The index of the log event + * @param {Function} onQueryStateChange Callback to set query state. + * @param {Function} onErrorMsg Callback to set error message. + */ +const submitExtractIrJob = async (origFileId, logEventIx, onQueryStateChange, onErrorMsg) => { + const {data} = await axios.post("/query/extract-ir", { + msg_ix: logEventIx, + orig_file_id: origFileId, + }); + + onQueryStateChange(QUERY_LOAD_STATE.LOADING); + + window.location = `/log-viewer/index.html?filePath=/ir/${data.path}`; +}; + +export { + QUERY_LOAD_STATE, + submitExtractIrJob, +}; diff --git a/components/log-viewer-webui/client/src/ui/Loading.jsx b/components/log-viewer-webui/client/src/ui/Loading.jsx new file mode 100644 index 000000000..44478b2cc --- /dev/null +++ b/components/log-viewer-webui/client/src/ui/Loading.jsx @@ -0,0 +1,148 @@ +import { + Box, + LinearProgress, + Sheet, + Step, + StepIndicator, + Stepper, + Typography, +} from "@mui/joy"; + + +/** + * Descriptions for query states. + */ +const QUERY_STATE_DESCRIPTIONS = Object.freeze([ + { + label: "Submitting query Job", + description: "Parsing arguments and submitting job to the server.", + }, + { + label: "Waiting for job To finish", + description: "The job is running. Waiting for the job to finish.", + }, + { + label: "Loading up Log Viewer", + description: "The query has been completed and the results are being loaded.", + }, +]); + + +/** + * Renders a step with a label and a description text. + * + * @param {object} props + * @param {string} props.description + * @param {boolean} props.isActive + * @param {boolean} props.isError whether an error message should be shown instead of a step. + * @param {string} props.label + * @param {number} props.stepNumber + * @return {React.ReactElement} + */ +const LoadingStep = ({ + description, + isActive, + isError, + label, + stepNumber, +}) => { + let color = "danger"; + if (false === isError) { + color = isActive ? + "primary" : + "neutral"; + } + + return ( + + {stepNumber} + + } + > + + {label} + + + {description} + + + ); +}; + +/** + * Displays status of a pending query job. + * + * @param {object} props + * @param {QueryLoadState} props.currentState + * @param {string} props.errorMsg + * @return {React.ReactElement} + */ +const Loading = ({currentState, errorMsg}) => { + const steps = []; + QUERY_STATE_DESCRIPTIONS.forEach((state, index) => { + const isActive = (currentState === index); + steps.push( + + ); + if (isActive && null !== errorMsg) { + steps.push( + + ); + } + }); + + return ( + <> + + + + + + + {steps} + + + + + ); +}; + +export default Loading; diff --git a/components/log-viewer-webui/client/src/ui/QueryState.jsx b/components/log-viewer-webui/client/src/ui/QueryState.jsx new file mode 100644 index 000000000..a8bb28b31 --- /dev/null +++ b/components/log-viewer-webui/client/src/ui/QueryState.jsx @@ -0,0 +1,51 @@ +import { + useEffect, + useRef, + useState, +} from "react"; + +import { + QUERY_LOAD_STATE, + submitExtractIrJob, +} from "../api/query.js"; +import Loading from "./Loading.jsx"; + + +/** + * Submits queries and renders the query states. + * + * @return {React.ReactElement} + */ +const Query = () => { + const [queryState, setQueryState] = useState(QUERY_LOAD_STATE.SUBMITTING); + const [errorMsg, setErrorMsg] = useState(null); + const isFirstRun = useRef(true); + + useEffect(() => { + if (false === isFirstRun.current) { + return; + } + isFirstRun.current = false; + + const searchParams = new URLSearchParams(window.location.search); + const origFileId = searchParams.get("origFileId"); + const logEventIx = searchParams.get("logEventIx"); + if (null === origFileId || null === logEventIx) { + const error = "Non-IR-Extraction queries are not supported at the moment. " + + "Either origFileId or logEventIx is missing from the URL parameters."; + + console.error(error); + setErrorMsg(error); + } + + submitExtractIrJob(origFileId, Number(logEventIx), setQueryState, setErrorMsg).then(); + }, []); + + return ( + + ); +}; + +export default Query; From 420126aace3a900854422850aa2cbd2234cc721e Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Tue, 23 Jul 2024 03:03:58 -0400 Subject: [PATCH 05/30] Display Axios error when any. --- .../log-viewer-webui/client/src/api/query.js | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/components/log-viewer-webui/client/src/api/query.js b/components/log-viewer-webui/client/src/api/query.js index 8cb96151a..56ca0baa1 100644 --- a/components/log-viewer-webui/client/src/api/query.js +++ b/components/log-viewer-webui/client/src/api/query.js @@ -1,4 +1,4 @@ -import axios from "axios"; +import axios, {AxiosError} from "axios"; /** @@ -26,14 +26,25 @@ const QUERY_LOAD_STATE = Object.freeze({ * @param {Function} onErrorMsg Callback to set error message. */ const submitExtractIrJob = async (origFileId, logEventIx, onQueryStateChange, onErrorMsg) => { - const {data} = await axios.post("/query/extract-ir", { - msg_ix: logEventIx, - orig_file_id: origFileId, - }); + try { + const {data} = await axios.post("/query/extract-ir", { + msg_ix: logEventIx, + orig_file_id: origFileId, + }); - onQueryStateChange(QUERY_LOAD_STATE.LOADING); + onQueryStateChange(QUERY_LOAD_STATE.LOADING); - window.location = `/log-viewer/index.html?filePath=/ir/${data.path}`; + window.location = `/log-viewer/index.html?filePath=/ir/${data.path}`; + } catch (e) { + let errorMsg = "Unknown error."; + if (e instanceof AxiosError) { + errorMsg = e.message; + if ("undefined" !== typeof e.response) { + errorMsg = e.response.data.message ?? e.response.statusText; + } + } + onErrorMsg(errorMsg); + } }; export { From a6bf9d264633ba948153387bcc0477cd35558d48 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Tue, 23 Jul 2024 03:07:21 -0400 Subject: [PATCH 06/30] Set logEventIdx cursor position. --- components/log-viewer-webui/client/src/api/query.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/log-viewer-webui/client/src/api/query.js b/components/log-viewer-webui/client/src/api/query.js index 56ca0baa1..a435db714 100644 --- a/components/log-viewer-webui/client/src/api/query.js +++ b/components/log-viewer-webui/client/src/api/query.js @@ -34,7 +34,9 @@ const submitExtractIrJob = async (origFileId, logEventIx, onQueryStateChange, on onQueryStateChange(QUERY_LOAD_STATE.LOADING); - window.location = `/log-viewer/index.html?filePath=/ir/${data.path}`; + const innerLogEventIx = logEventIx - data.begin_msg_ix + 1; + window.location = `/log-viewer/index.html?filePath=/ir/${data.path}` + + `#logEventIdx=${innerLogEventIx}`; } catch (e) { let errorMsg = "Unknown error."; if (e instanceof AxiosError) { From c1f6e19e5dcdc9249e8083913fcc4e5970b7703b Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Tue, 23 Jul 2024 03:14:57 -0400 Subject: [PATCH 07/30] Add LogViewerWebuiClientUrl setting override in `start-clp.py`. --- .../clp-package-utils/clp_package_utils/scripts/start_clp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 655c1dae1..d4504b2dd 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -738,6 +738,7 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts }, "public": { "ClpStorageEngine": clp_config.package.storage_engine, + "LogViewerWebuiClientUrl": f"http://{clp_config.log_viewer_webui.host}:{clp_config.log_viewer_webui.port}" }, } meteor_settings = read_and_update_settings_json(settings_json_path, meteor_settings_updates) From 18b9411c98d6d1f0bf599e559d6581497f843b9d Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Tue, 23 Jul 2024 03:18:49 -0400 Subject: [PATCH 08/30] Reformat code. --- .../clp-package-utils/clp_package_utils/scripts/start_clp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index d4504b2dd..569cb9e95 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -738,7 +738,7 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts }, "public": { "ClpStorageEngine": clp_config.package.storage_engine, - "LogViewerWebuiClientUrl": f"http://{clp_config.log_viewer_webui.host}:{clp_config.log_viewer_webui.port}" + "LogViewerWebuiClientUrl": f"http://{clp_config.log_viewer_webui.host}:{clp_config.log_viewer_webui.port}", }, } meteor_settings = read_and_update_settings_json(settings_json_path, meteor_settings_updates) From f684c091a52b79c5a9c69aa9c811185f38ccbe6e Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Tue, 23 Jul 2024 18:42:07 -0400 Subject: [PATCH 09/30] Avoid CSS-in-JS by moving styles to a separate stylesheet. --- .../client/src/ui/Loading.css | 24 +++++++++++++++++++ .../client/src/ui/Loading.jsx | 18 +++++--------- 2 files changed, 30 insertions(+), 12 deletions(-) create mode 100644 components/log-viewer-webui/client/src/ui/Loading.css diff --git a/components/log-viewer-webui/client/src/ui/Loading.css b/components/log-viewer-webui/client/src/ui/Loading.css new file mode 100644 index 000000000..c897fc42f --- /dev/null +++ b/components/log-viewer-webui/client/src/ui/Loading.css @@ -0,0 +1,24 @@ +.loading-sheet { + height: 100%; + + display: flex; + flex-direction: column; + + align-items: center; + justify-content: center; +} + +.loading-progress-container { + width: 100%; +} + +.loading-stepper-container { + display: flex; + flex-grow: 1; + + align-items: center; +} + +.loading-stepper { + --Stepper-verticalGap: 2rem!important; +} diff --git a/components/log-viewer-webui/client/src/ui/Loading.jsx b/components/log-viewer-webui/client/src/ui/Loading.jsx index 44478b2cc..e7f9882f9 100644 --- a/components/log-viewer-webui/client/src/ui/Loading.jsx +++ b/components/log-viewer-webui/client/src/ui/Loading.jsx @@ -8,6 +8,8 @@ import { Typography, } from "@mui/joy"; +import "./Loading.css"; + /** * Descriptions for query states. @@ -115,27 +117,19 @@ const Loading = ({currentState, errorMsg}) => { return ( <> - - + + - + {steps} From ba61aa6d0dfdc29e8f7a36042fdbae65f111562b Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Thu, 25 Jul 2024 14:26:50 -0400 Subject: [PATCH 10/30] Rename `LogViewerWebuiClientUrl` -> `LogViewerWebuiUrl`. --- .../clp-package-utils/clp_package_utils/scripts/start_clp.py | 2 +- .../ui/SearchView/SearchResults/SearchResultsTable/index.jsx | 2 +- components/webui/settings.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 2050a2b1b..0b024e814 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -786,7 +786,7 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts }, "public": { "ClpStorageEngine": clp_config.package.storage_engine, - "LogViewerWebuiClientUrl": f"http://{clp_config.log_viewer_webui.host}:{clp_config.log_viewer_webui.port}", + "LogViewerWebuiUrl": f"http://{clp_config.log_viewer_webui.host}:{clp_config.log_viewer_webui.port}", }, } meteor_settings = read_and_update_settings_json(settings_json_path, meteor_settings_updates) diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index 3ef3aabb4..b670681de 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -80,7 +80,7 @@ const SearchResultsTable = ({ const handleSearchResultClick = (ev) => { const {orig_file_id: origFileId, log_event_ix: logEventIx} = ev.currentTarget.dataset; - window.open(`${Meteor.settings.public.LogViewerWebuiClientUrl + window.open(`${Meteor.settings.public.LogViewerWebuiUrl }?origFileId=${origFileId}&logEventIx=${logEventIx}`); }; diff --git a/components/webui/settings.json b/components/webui/settings.json index d5c929147..f959dac8e 100644 --- a/components/webui/settings.json +++ b/components/webui/settings.json @@ -13,7 +13,7 @@ "AggregationResultsCollectionName": "aggregation-results", "ClpStorageEngine": "clp", "CompressionJobsCollectionName": "compression-jobs", - "LogViewerWebuiClientUrl": "http://localhost:8080", + "LogViewerWebuiUrl": "http://localhost:8080", "SearchResultsCollectionName": "search-results", "SearchResultsMetadataCollectionName": "results-metadata", "StatsCollectionName": "stats", From 302ac3a46708ac228b8776e73855ca31815da2cf Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Thu, 25 Jul 2024 14:30:28 -0400 Subject: [PATCH 11/30] Break HTML tag into two lines. Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/log-viewer-webui/client/public/index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/log-viewer-webui/client/public/index.html b/components/log-viewer-webui/client/public/index.html index 971424b95..c2e5d6b78 100644 --- a/components/log-viewer-webui/client/public/index.html +++ b/components/log-viewer-webui/client/public/index.html @@ -8,7 +8,8 @@ + href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" + />
From 7eed866ab9167a6b40bc210ad554048278407239 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Thu, 25 Jul 2024 14:37:33 -0400 Subject: [PATCH 12/30] Refactor theme key to use constants. --- components/log-viewer-webui/client/src/App.jsx | 3 ++- .../client/src/typings/LOCAL_STORAGE_KEY.js | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 components/log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js diff --git a/components/log-viewer-webui/client/src/App.jsx b/components/log-viewer-webui/client/src/App.jsx index 5b8ad6a67..d774af601 100644 --- a/components/log-viewer-webui/client/src/App.jsx +++ b/components/log-viewer-webui/client/src/App.jsx @@ -1,5 +1,6 @@ import {CssVarsProvider} from "@mui/joy/styles/CssVarsProvider"; +import LOCAL_STORAGE_KEY from "./typings/LOCAL_STORAGE_KEY.js"; import Query from "./ui/QueryState.jsx"; @@ -10,7 +11,7 @@ import Query from "./ui/QueryState.jsx"; */ const App = () => { return ( - + ); diff --git a/components/log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js b/components/log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js new file mode 100644 index 000000000..c1dc19979 --- /dev/null +++ b/components/log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js @@ -0,0 +1,8 @@ +/** + * Enum of `window.localStorage` keys. + */ +const LOCAL_STORAGE_KEY = Object.freeze({ + UI_THEME: "uiTheme", +}); + +export default LOCAL_STORAGE_KEY; From d8c6b423bc07e3ee945f50698dc15eb2dbed2a06 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Thu, 25 Jul 2024 15:19:08 -0400 Subject: [PATCH 13/30] Apply docs / prompts suggestions from code review. Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/log-viewer-webui/client/src/api/query.js | 6 +++--- components/log-viewer-webui/client/src/ui/Loading.jsx | 10 +++++----- .../log-viewer-webui/client/src/ui/QueryState.jsx | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/components/log-viewer-webui/client/src/api/query.js b/components/log-viewer-webui/client/src/api/query.js index a435db714..bc0347f01 100644 --- a/components/log-viewer-webui/client/src/api/query.js +++ b/components/log-viewer-webui/client/src/api/query.js @@ -17,10 +17,10 @@ const QUERY_LOAD_STATE = Object.freeze({ }); /** - * Submits a job to extract a segment of the original file, which contains a given log event index, - * into CLP's IR format for viewing in the Log Viewer. + * Submits a job to extract the split of an original file that contains a given log event. The file +* is extracted as a CLP IR file. * - * @param {number|string} origFileId The ID of the original file to extract IR from + * @param {number|string} origFileId The ID of the original file * @param {number} logEventIx The index of the log event * @param {Function} onQueryStateChange Callback to set query state. * @param {Function} onErrorMsg Callback to set error message. diff --git a/components/log-viewer-webui/client/src/ui/Loading.jsx b/components/log-viewer-webui/client/src/ui/Loading.jsx index e7f9882f9..ea97a25c2 100644 --- a/components/log-viewer-webui/client/src/ui/Loading.jsx +++ b/components/log-viewer-webui/client/src/ui/Loading.jsx @@ -20,25 +20,25 @@ const QUERY_STATE_DESCRIPTIONS = Object.freeze([ description: "Parsing arguments and submitting job to the server.", }, { - label: "Waiting for job To finish", + label: "Waiting for job to finish", description: "The job is running. Waiting for the job to finish.", }, { - label: "Loading up Log Viewer", + label: "Loading Log Viewer", description: "The query has been completed and the results are being loaded.", }, ]); /** - * Renders a step with a label and a description text. + * Renders a step with a label and description. * * @param {object} props * @param {string} props.description * @param {boolean} props.isActive - * @param {boolean} props.isError whether an error message should be shown instead of a step. + * @param {boolean} props.isError * @param {string} props.label - * @param {number} props.stepNumber + * @param {number | string} props.stepNumber * @return {React.ReactElement} */ const LoadingStep = ({ diff --git a/components/log-viewer-webui/client/src/ui/QueryState.jsx b/components/log-viewer-webui/client/src/ui/QueryState.jsx index a8bb28b31..eb637d91f 100644 --- a/components/log-viewer-webui/client/src/ui/QueryState.jsx +++ b/components/log-viewer-webui/client/src/ui/QueryState.jsx @@ -31,8 +31,8 @@ const Query = () => { const origFileId = searchParams.get("origFileId"); const logEventIx = searchParams.get("logEventIx"); if (null === origFileId || null === logEventIx) { - const error = "Non-IR-Extraction queries are not supported at the moment. " + - "Either origFileId or logEventIx is missing from the URL parameters."; + const error = "Either `origFileId` or `logEventIx` are missing from the URL " + + "parameters. Note that non-IR-extraction queries are not supported at the moment."; console.error(error); setErrorMsg(error); From 8c860e5e23ecd22885e58aed04d1268cd9609012 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Thu, 25 Jul 2024 15:22:20 -0400 Subject: [PATCH 14/30] Rename `stepNumber` -> `stepIndicatorText`. --- components/log-viewer-webui/client/src/ui/Loading.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/log-viewer-webui/client/src/ui/Loading.jsx b/components/log-viewer-webui/client/src/ui/Loading.jsx index ea97a25c2..6f2f3cee4 100644 --- a/components/log-viewer-webui/client/src/ui/Loading.jsx +++ b/components/log-viewer-webui/client/src/ui/Loading.jsx @@ -38,7 +38,7 @@ const QUERY_STATE_DESCRIPTIONS = Object.freeze([ * @param {boolean} props.isActive * @param {boolean} props.isError * @param {string} props.label - * @param {number | string} props.stepNumber + * @param {number | string} props.stepIndicatorText * @return {React.ReactElement} */ const LoadingStep = ({ @@ -46,7 +46,7 @@ const LoadingStep = ({ isActive, isError, label, - stepNumber, + stepIndicatorText, }) => { let color = "danger"; if (false === isError) { @@ -64,7 +64,7 @@ const LoadingStep = ({ "solid" : "outlined"} > - {stepNumber} + {stepIndicatorText} } > @@ -100,7 +100,7 @@ const Loading = ({currentState, errorMsg}) => { isError={false} key={index} label={state.label} - stepNumber={index + 1}/> + stepIndicatorText={index + 1}/> ); if (isActive && null !== errorMsg) { steps.push( @@ -110,7 +110,7 @@ const Loading = ({currentState, errorMsg}) => { isError={true} key={`${index}-error`} label={"Error"} - stepNumber={"X"}/> + stepIndicatorText={"X"}/> ); } }); From c81aef83c3df75b94d0e8b3fc4349cde0cb5eed9 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Thu, 25 Jul 2024 15:53:01 -0400 Subject: [PATCH 15/30] Rename `ix` -> `idx`; `msg_ix` -> `log_event_idx`; use camelCase wherever applicable. --- .../log-viewer-webui/client/src/api/query.js | 16 +++++------- .../client/src/ui/QueryState.jsx | 8 +++--- .../log-viewer-webui/server/src/DbManager.js | 10 +++---- .../server/src/routes/query.js | 26 ++++++++++++------- .../SearchResultsTable/index.jsx | 6 ++--- 5 files changed, 34 insertions(+), 32 deletions(-) diff --git a/components/log-viewer-webui/client/src/api/query.js b/components/log-viewer-webui/client/src/api/query.js index bc0347f01..b330a90f6 100644 --- a/components/log-viewer-webui/client/src/api/query.js +++ b/components/log-viewer-webui/client/src/api/query.js @@ -18,25 +18,21 @@ const QUERY_LOAD_STATE = Object.freeze({ /** * Submits a job to extract the split of an original file that contains a given log event. The file -* is extracted as a CLP IR file. + * is extracted as a CLP IR file. * * @param {number|string} origFileId The ID of the original file - * @param {number} logEventIx The index of the log event + * @param {number} logEventIdx The index of the log event * @param {Function} onQueryStateChange Callback to set query state. * @param {Function} onErrorMsg Callback to set error message. */ -const submitExtractIrJob = async (origFileId, logEventIx, onQueryStateChange, onErrorMsg) => { +const submitExtractIrJob = async (origFileId, logEventIdx, onQueryStateChange, onErrorMsg) => { try { - const {data} = await axios.post("/query/extract-ir", { - msg_ix: logEventIx, - orig_file_id: origFileId, - }); - + const {data} = await axios.post("/query/extract-ir", {logEventIdx, origFileId}); onQueryStateChange(QUERY_LOAD_STATE.LOADING); - const innerLogEventIx = logEventIx - data.begin_msg_ix + 1; + const innerLogEventNum = logEventIdx - data.begin_msg_ix + 1; window.location = `/log-viewer/index.html?filePath=/ir/${data.path}` + - `#logEventIdx=${innerLogEventIx}`; + `#logEventIdx=${innerLogEventNum}`; } catch (e) { let errorMsg = "Unknown error."; if (e instanceof AxiosError) { diff --git a/components/log-viewer-webui/client/src/ui/QueryState.jsx b/components/log-viewer-webui/client/src/ui/QueryState.jsx index eb637d91f..232a2f509 100644 --- a/components/log-viewer-webui/client/src/ui/QueryState.jsx +++ b/components/log-viewer-webui/client/src/ui/QueryState.jsx @@ -29,16 +29,16 @@ const Query = () => { const searchParams = new URLSearchParams(window.location.search); const origFileId = searchParams.get("origFileId"); - const logEventIx = searchParams.get("logEventIx"); - if (null === origFileId || null === logEventIx) { - const error = "Either `origFileId` or `logEventIx` are missing from the URL " + + const logEventIdx = searchParams.get("logEventIdx"); + if (null === origFileId || null === logEventIdx) { + const error = "Either `origFileId` or `logEventIdx` are missing from the URL " + "parameters. Note that non-IR-extraction queries are not supported at the moment."; console.error(error); setErrorMsg(error); } - submitExtractIrJob(origFileId, Number(logEventIx), setQueryState, setErrorMsg).then(); + submitExtractIrJob(origFileId, Number(logEventIdx), setQueryState, setErrorMsg).then(); }, []); return ( diff --git a/components/log-viewer-webui/server/src/DbManager.js b/components/log-viewer-webui/server/src/DbManager.js index ad71518a5..2cb7ef3e0 100644 --- a/components/log-viewer-webui/server/src/DbManager.js +++ b/components/log-viewer-webui/server/src/DbManager.js @@ -131,17 +131,17 @@ class DbManager { /** * Gets the metadata for an IR file extracted from part of an original file, where the original - * file has the given ID and the extracted part contains the given message index. + * file has the given ID and the extracted part contains the given log event index. * * @param {string} origFileId - * @param {number} msgIdx + * @param {number} logEventIdx * @return {Promise} A promise that resolves to the extracted IR file's metadata. */ - async getExtractedIrFileMetadata (origFileId, msgIdx) { + async getExtractedIrFileMetadata (origFileId, logEventIdx) { return await this.#irFilesCollection.findOne({ orig_file_id: origFileId, - begin_msg_ix: {$lte: msgIdx}, - end_msg_ix: {$gt: msgIdx}, + begin_msg_ix: {$lte: logEventIdx}, + end_msg_ix: {$gt: logEventIdx}, }); } diff --git a/components/log-viewer-webui/server/src/routes/query.js b/components/log-viewer-webui/server/src/routes/query.js index 2f790ebc3..628bcd053 100644 --- a/components/log-viewer-webui/server/src/routes/query.js +++ b/components/log-viewer-webui/server/src/routes/query.js @@ -1,3 +1,6 @@ +// eslint-disable-next-line no-magic-numbers +const EXTRACT_IR_TARGET_UNCOMPRESSED_SIZE = 128 * 1024 * 1024; + /** * Creates query routes. * @@ -7,30 +10,33 @@ */ const routes = async (fastify, options) => { fastify.post("/query/extract-ir", async (req, resp) => { - const {orig_file_id: origFileId, msg_ix: msgIdx} = req.body; - const sanitizedMsgIdx = Number(msgIdx); + const {origFileId, logEventIdx} = req.body; + const sanitizedLogEventIdx = Number(logEventIdx); - let irMetadata = - await fastify.dbManager.getExtractedIrFileMetadata(origFileId, sanitizedMsgIdx); + let irMetadata = await fastify.dbManager.getExtractedIrFileMetadata( + origFileId, + sanitizedLogEventIdx + ); if (null === irMetadata) { const extractResult = await fastify.dbManager.submitAndWaitForExtractIrJob({ file_split_id: null, - msg_ix: sanitizedMsgIdx, + msg_ix: sanitizedLogEventIdx, orig_file_id: origFileId, - // eslint-disable-next-line no-magic-numbers - target_uncompressed_size: 128 * 1024 * 1024, + target_uncompressed_size: EXTRACT_IR_TARGET_UNCOMPRESSED_SIZE, }); if (null === extractResult) { const err = new Error("Unable to extract IR for file with " + - `orig_file_id=${origFileId} at msg_ix=${sanitizedMsgIdx}`); + `origFileId=${origFileId} at logEventIdx=${sanitizedLogEventIdx}`); err.statusCode = 400; throw err; } - irMetadata = - await fastify.dbManager.getExtractedIrFileMetadata(origFileId, sanitizedMsgIdx); + irMetadata = await fastify.dbManager.getExtractedIrFileMetadata( + origFileId, + sanitizedLogEventIdx + ); } return irMetadata; diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index b670681de..4bba7898c 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -79,9 +79,9 @@ const SearchResultsTable = ({ }; const handleSearchResultClick = (ev) => { - const {orig_file_id: origFileId, log_event_ix: logEventIx} = ev.currentTarget.dataset; + const {orig_file_id: origFileId, log_event_idx: logEventIdx} = ev.currentTarget.dataset; window.open(`${Meteor.settings.public.LogViewerWebuiUrl - }?origFileId=${origFileId}&logEventIx=${logEventIx}`); + }?origFileId=${origFileId}&logEventIdx=${logEventIdx}`); }; useEffect(() => { @@ -141,7 +141,7 @@ const SearchResultsTable = ({ Date: Thu, 25 Jul 2024 16:11:33 -0400 Subject: [PATCH 16/30] Refactor Axios error reporting code for clearness. --- components/log-viewer-webui/client/src/api/query.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/log-viewer-webui/client/src/api/query.js b/components/log-viewer-webui/client/src/api/query.js index b330a90f6..7b17508f4 100644 --- a/components/log-viewer-webui/client/src/api/query.js +++ b/components/log-viewer-webui/client/src/api/query.js @@ -38,7 +38,11 @@ const submitExtractIrJob = async (origFileId, logEventIdx, onQueryStateChange, o if (e instanceof AxiosError) { errorMsg = e.message; if ("undefined" !== typeof e.response) { - errorMsg = e.response.data.message ?? e.response.statusText; + if ("undefined" !== typeof e.response.data.message) { + errorMsg = e.response.data.message; + } else { + errorMsg = e.response.statusText; + } } } onErrorMsg(errorMsg); From fb6c7b62b7af0418c6a6092037dbc84d530cc670 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Thu, 25 Jul 2024 16:12:50 -0400 Subject: [PATCH 17/30] Log axios error object together with the error message. --- components/log-viewer-webui/client/src/api/query.js | 1 + 1 file changed, 1 insertion(+) diff --git a/components/log-viewer-webui/client/src/api/query.js b/components/log-viewer-webui/client/src/api/query.js index 7b17508f4..730099240 100644 --- a/components/log-viewer-webui/client/src/api/query.js +++ b/components/log-viewer-webui/client/src/api/query.js @@ -45,6 +45,7 @@ const submitExtractIrJob = async (origFileId, logEventIdx, onQueryStateChange, o } } } + console.error(errorMsg, e); onErrorMsg(errorMsg); } }; From ae526ebe92f270c04de6859f7b6e6409a5f89af6 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Thu, 25 Jul 2024 18:30:45 -0400 Subject: [PATCH 18/30] Move `QUERY_STATE_DESCRIPTIONS` into api/query.js and use enum `QUERY_LOAD_STATE` as indices. --- .../log-viewer-webui/client/src/api/query.js | 19 +++++++++ .../client/src/ui/Loading.jsx | 39 +++++++------------ 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/components/log-viewer-webui/client/src/api/query.js b/components/log-viewer-webui/client/src/api/query.js index 730099240..34ac44a1b 100644 --- a/components/log-viewer-webui/client/src/api/query.js +++ b/components/log-viewer-webui/client/src/api/query.js @@ -16,6 +16,24 @@ const QUERY_LOAD_STATE = Object.freeze({ LOADING: ++enumQueryLoadState, }); +/** + * Descriptions for query states. + */ +const QUERY_STATE_DESCRIPTIONS = Object.freeze({ + [QUERY_LOAD_STATE.SUBMITTING]: { + label: "Submitting query Job", + description: "Parsing arguments and submitting job to the server.", + }, + [QUERY_LOAD_STATE.WAITING]: { + label: "Waiting for job to finish", + description: "The job is running. Waiting for the job to finish.", + }, + [QUERY_LOAD_STATE.LOADING]: { + label: "Loading Log Viewer", + description: "The query has been completed and the results are being loaded.", + }, +}); + /** * Submits a job to extract the split of an original file that contains a given log event. The file * is extracted as a CLP IR file. @@ -52,5 +70,6 @@ const submitExtractIrJob = async (origFileId, logEventIdx, onQueryStateChange, o export { QUERY_LOAD_STATE, + QUERY_STATE_DESCRIPTIONS, submitExtractIrJob, }; diff --git a/components/log-viewer-webui/client/src/ui/Loading.jsx b/components/log-viewer-webui/client/src/ui/Loading.jsx index 6f2f3cee4..956957eee 100644 --- a/components/log-viewer-webui/client/src/ui/Loading.jsx +++ b/components/log-viewer-webui/client/src/ui/Loading.jsx @@ -8,26 +8,12 @@ import { Typography, } from "@mui/joy"; -import "./Loading.css"; - +import { + QUERY_LOAD_STATE, + QUERY_STATE_DESCRIPTIONS, +} from "../api/query.js"; -/** - * Descriptions for query states. - */ -const QUERY_STATE_DESCRIPTIONS = Object.freeze([ - { - label: "Submitting query Job", - description: "Parsing arguments and submitting job to the server.", - }, - { - label: "Waiting for job to finish", - description: "The job is running. Waiting for the job to finish.", - }, - { - label: "Loading Log Viewer", - description: "The query has been completed and the results are being loaded.", - }, -]); +import "./Loading.css"; /** @@ -91,16 +77,17 @@ const LoadingStep = ({ */ const Loading = ({currentState, errorMsg}) => { const steps = []; - QUERY_STATE_DESCRIPTIONS.forEach((state, index) => { - const isActive = (currentState === index); + Object.values(QUERY_LOAD_STATE).forEach((state) => { + const isActive = (currentState === state); + const stateDescription = QUERY_STATE_DESCRIPTIONS[state]; steps.push( + key={state} + label={stateDescription.label} + stepIndicatorText={state + 1}/> ); if (isActive && null !== errorMsg) { steps.push( @@ -108,7 +95,7 @@ const Loading = ({currentState, errorMsg}) => { description={errorMsg} isActive={isActive} isError={true} - key={`${index}-error`} + key={`${state}-error`} label={"Error"} stepIndicatorText={"X"}/> ); From 6568b5ad6fae8a5bb56c5397ec466310e84e0d9a Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Thu, 25 Jul 2024 18:31:19 -0400 Subject: [PATCH 19/30] Update components/log-viewer-webui/client/src/ui/Loading.jsx Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/log-viewer-webui/client/src/ui/Loading.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/log-viewer-webui/client/src/ui/Loading.jsx b/components/log-viewer-webui/client/src/ui/Loading.jsx index 956957eee..9b6a1d010 100644 --- a/components/log-viewer-webui/client/src/ui/Loading.jsx +++ b/components/log-viewer-webui/client/src/ui/Loading.jsx @@ -34,11 +34,11 @@ const LoadingStep = ({ label, stepIndicatorText, }) => { - let color = "danger"; - if (false === isError) { - color = isActive ? - "primary" : - "neutral"; + let color = isActive ? + "primary" : + "neutral"; + if (isError) { + color = "danger"; } return ( From 3f6d40fc3e74a0d431adbf1e4017f6a2efcd7823 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Thu, 25 Jul 2024 18:34:50 -0400 Subject: [PATCH 20/30] Rename `Query`/`QueryState` -> `QueryStatus`. --- components/log-viewer-webui/client/src/App.jsx | 4 ++-- .../client/src/ui/{QueryState.jsx => QueryStatus.jsx} | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename components/log-viewer-webui/client/src/ui/{QueryState.jsx => QueryStatus.jsx} (95%) diff --git a/components/log-viewer-webui/client/src/App.jsx b/components/log-viewer-webui/client/src/App.jsx index d774af601..6d7a65e45 100644 --- a/components/log-viewer-webui/client/src/App.jsx +++ b/components/log-viewer-webui/client/src/App.jsx @@ -1,7 +1,7 @@ import {CssVarsProvider} from "@mui/joy/styles/CssVarsProvider"; import LOCAL_STORAGE_KEY from "./typings/LOCAL_STORAGE_KEY.js"; -import Query from "./ui/QueryState.jsx"; +import QueryStatus from "./ui/QueryStatus.jsx"; /** @@ -12,7 +12,7 @@ import Query from "./ui/QueryState.jsx"; const App = () => { return ( - + ); }; diff --git a/components/log-viewer-webui/client/src/ui/QueryState.jsx b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx similarity index 95% rename from components/log-viewer-webui/client/src/ui/QueryState.jsx rename to components/log-viewer-webui/client/src/ui/QueryStatus.jsx index 232a2f509..13bf2068c 100644 --- a/components/log-viewer-webui/client/src/ui/QueryState.jsx +++ b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx @@ -16,7 +16,7 @@ import Loading from "./Loading.jsx"; * * @return {React.ReactElement} */ -const Query = () => { +const QueryStatus = () => { const [queryState, setQueryState] = useState(QUERY_LOAD_STATE.SUBMITTING); const [errorMsg, setErrorMsg] = useState(null); const isFirstRun = useRef(true); @@ -48,4 +48,4 @@ const Query = () => { ); }; -export default Query; +export default QueryStatus; From 50b9f704b1cc305cfdcd8681bce66918de56946c Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Thu, 25 Jul 2024 19:02:40 -0400 Subject: [PATCH 21/30] Add extra button for opening up Log Viewer, instead of the previous hyperlinked log message text approach. --- .../SearchResultsTable/index.jsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index 4bba7898c..9da6fbd6d 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -8,6 +8,7 @@ import { faSort, faSortDown, faSortUp, + faSquareUpRight, } from "@fortawesome/free-solid-svg-icons"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; @@ -111,7 +112,6 @@ const SearchResultsTable = ({
@@ -122,12 +122,14 @@ const SearchResultsTable = ({
Log message
+ +
 
+ @@ -138,6 +140,13 @@ const SearchResultsTable = ({ dayjs.utc(result.timestamp).format(DATETIME_FORMAT_TEMPLATE) : "N/A"} + +
+                                    {result.message}
+                                
+
-
-                                        {result.message}
-                                    
+
From 46d8a7afba7fe80eb07cccc8da4d08d9080ffab5 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Fri, 26 Jul 2024 00:36:28 -0400 Subject: [PATCH 22/30] Add href to and remove onclick handler. --- .../SearchResultsTable/SearchResultsTable.scss | 4 ---- .../SearchResults/SearchResultsTable/index.jsx | 15 +++++---------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss index 6b6d2d656..6c24ec2da 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss @@ -29,10 +29,6 @@ .search-results-content { font-size: 0.875rem; line-height: var(--search-results-message-line-height); - - &-clickable { - cursor: pointer; - } } .search-results-timestamp { diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index 9da6fbd6d..d9cd3c134 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -79,12 +79,6 @@ const SearchResultsTable = ({ } }; - const handleSearchResultClick = (ev) => { - const {orig_file_id: origFileId, log_event_idx: logEventIdx} = ev.currentTarget.dataset; - window.open(`${Meteor.settings.public.LogViewerWebuiUrl - }?origFileId=${origFileId}&logEventIdx=${logEventIdx}`); - }; - useEffect(() => { document.documentElement.style.setProperty( "--search-results-message-line-height", @@ -149,11 +143,12 @@ const SearchResultsTable = ({ From db770f772c9342803f8b1c8917eb6edcc69ace2c Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Fri, 26 Jul 2024 00:37:31 -0400 Subject: [PATCH 23/30] Move React state setter usages from api submission functions back into React components. --- .../log-viewer-webui/client/src/api/query.js | 79 +++++-------------- .../client/src/typings/query.js | 37 +++++++++ .../client/src/ui/Loading.jsx | 3 +- .../client/src/ui/QueryStatus.jsx | 38 +++++++-- 4 files changed, 90 insertions(+), 67 deletions(-) create mode 100644 components/log-viewer-webui/client/src/typings/query.js diff --git a/components/log-viewer-webui/client/src/api/query.js b/components/log-viewer-webui/client/src/api/query.js index 34ac44a1b..be17d0fc8 100644 --- a/components/log-viewer-webui/client/src/api/query.js +++ b/components/log-viewer-webui/client/src/api/query.js @@ -1,38 +1,16 @@ -import axios, {AxiosError} from "axios"; +import axios from "axios"; /** - * @typedef {number} QueryLoadState + * @typedef {object} ExtractIrResp + * @property {number} begin_msg_ix + * @property {number} end_msg_ix + * @property {string} file_split_id + * @property {boolean} is_last_ir_chunk + * @property {string} orig_file_id + * @property {string} path + * @property {string} _id */ -let enumQueryLoadState; -/** - * Enum of query loading state. - * - * @enum {QueryLoadState} - */ -const QUERY_LOAD_STATE = Object.freeze({ - SUBMITTING: (enumQueryLoadState = 0), - WAITING: ++enumQueryLoadState, - LOADING: ++enumQueryLoadState, -}); - -/** - * Descriptions for query states. - */ -const QUERY_STATE_DESCRIPTIONS = Object.freeze({ - [QUERY_LOAD_STATE.SUBMITTING]: { - label: "Submitting query Job", - description: "Parsing arguments and submitting job to the server.", - }, - [QUERY_LOAD_STATE.WAITING]: { - label: "Waiting for job to finish", - description: "The job is running. Waiting for the job to finish.", - }, - [QUERY_LOAD_STATE.LOADING]: { - label: "Loading Log Viewer", - description: "The query has been completed and the results are being loaded.", - }, -}); /** * Submits a job to extract the split of an original file that contains a given log event. The file @@ -40,36 +18,15 @@ const QUERY_STATE_DESCRIPTIONS = Object.freeze({ * * @param {number|string} origFileId The ID of the original file * @param {number} logEventIdx The index of the log event - * @param {Function} onQueryStateChange Callback to set query state. - * @param {Function} onErrorMsg Callback to set error message. + * @param {Function} onUploadProgress Callback to handle upload progress events. + * @return {Promise>} */ -const submitExtractIrJob = async (origFileId, logEventIdx, onQueryStateChange, onErrorMsg) => { - try { - const {data} = await axios.post("/query/extract-ir", {logEventIdx, origFileId}); - onQueryStateChange(QUERY_LOAD_STATE.LOADING); - - const innerLogEventNum = logEventIdx - data.begin_msg_ix + 1; - window.location = `/log-viewer/index.html?filePath=/ir/${data.path}` + - `#logEventIdx=${innerLogEventNum}`; - } catch (e) { - let errorMsg = "Unknown error."; - if (e instanceof AxiosError) { - errorMsg = e.message; - if ("undefined" !== typeof e.response) { - if ("undefined" !== typeof e.response.data.message) { - errorMsg = e.response.data.message; - } else { - errorMsg = e.response.statusText; - } - } - } - console.error(errorMsg, e); - onErrorMsg(errorMsg); - } +const submitExtractIrJob = async (origFileId, logEventIdx, onUploadProgress) => { + return await axios.post( + "/query/extract-ir", + {logEventIdx, origFileId}, + {onUploadProgress} + ); }; -export { - QUERY_LOAD_STATE, - QUERY_STATE_DESCRIPTIONS, - submitExtractIrJob, -}; +export {submitExtractIrJob}; diff --git a/components/log-viewer-webui/client/src/typings/query.js b/components/log-viewer-webui/client/src/typings/query.js new file mode 100644 index 000000000..fb5de24f0 --- /dev/null +++ b/components/log-viewer-webui/client/src/typings/query.js @@ -0,0 +1,37 @@ +/** + * @typedef {number} QueryLoadState + */ +let enumQueryLoadState; +/** + * Enum of query loading state. + * + * @enum {QueryLoadState} + */ +const QUERY_LOAD_STATE = Object.freeze({ + SUBMITTING: (enumQueryLoadState = 0), + WAITING: ++enumQueryLoadState, + LOADING: ++enumQueryLoadState, +}); + +/** + * Descriptions for query states. + */ +const QUERY_STATE_DESCRIPTIONS = Object.freeze({ + [QUERY_LOAD_STATE.SUBMITTING]: { + label: "Submitting query Job", + description: "Parsing arguments and submitting job to the server.", + }, + [QUERY_LOAD_STATE.WAITING]: { + label: "Waiting for job to finish", + description: "The job is running. Waiting for the job to finish.", + }, + [QUERY_LOAD_STATE.LOADING]: { + label: "Loading Log Viewer", + description: "The query has been completed and the results are being loaded.", + }, +}); + +export { + QUERY_LOAD_STATE, + QUERY_STATE_DESCRIPTIONS, +}; diff --git a/components/log-viewer-webui/client/src/ui/Loading.jsx b/components/log-viewer-webui/client/src/ui/Loading.jsx index 9b6a1d010..edb681dc9 100644 --- a/components/log-viewer-webui/client/src/ui/Loading.jsx +++ b/components/log-viewer-webui/client/src/ui/Loading.jsx @@ -11,7 +11,7 @@ import { import { QUERY_LOAD_STATE, QUERY_STATE_DESCRIPTIONS, -} from "../api/query.js"; +} from "../typings/query.js"; import "./Loading.css"; @@ -37,6 +37,7 @@ const LoadingStep = ({ let color = isActive ? "primary" : "neutral"; + if (isError) { color = "danger"; } diff --git a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx index 13bf2068c..d43f8e439 100644 --- a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx +++ b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx @@ -4,10 +4,10 @@ import { useState, } from "react"; -import { - QUERY_LOAD_STATE, - submitExtractIrJob, -} from "../api/query.js"; +import {AxiosError} from "axios"; + +import {submitExtractIrJob} from "../api/query.js"; +import {QUERY_LOAD_STATE} from "../typings/query.js"; import Loading from "./Loading.jsx"; @@ -38,7 +38,35 @@ const QueryStatus = () => { setErrorMsg(error); } - submitExtractIrJob(origFileId, Number(logEventIdx), setQueryState, setErrorMsg).then(); + submitExtractIrJob( + origFileId, + Number(logEventIdx), + () => { + setQueryState(QUERY_LOAD_STATE.WAITING); + } + ) + .then(({data}) => { + setQueryState(QUERY_LOAD_STATE.LOADING); + + const innerLogEventNum = logEventIdx - data.begin_msg_ix + 1; + window.location = `/log-viewer/index.html?filePath=/ir/${data.path}` + + `#logEventIdx=${innerLogEventNum}`; + }) + .catch((e) => { + let msg = "Unknown error."; + if (e instanceof AxiosError) { + msg = e.message; + if ("undefined" !== typeof e.response) { + if ("undefined" !== typeof e.response.data.message) { + msg = e.response.data.message; + } else { + msg = e.response.statusText; + } + } + } + console.error(msg, e); + setErrorMsg(msg); + }); }, []); return ( From ec84389f742f1fce59edc6fde690fc458fc42413 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Fri, 26 Jul 2024 00:47:15 -0400 Subject: [PATCH 24/30] Add space before `!important`. --- components/log-viewer-webui/client/src/ui/Loading.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/log-viewer-webui/client/src/ui/Loading.css b/components/log-viewer-webui/client/src/ui/Loading.css index c897fc42f..d8bec1842 100644 --- a/components/log-viewer-webui/client/src/ui/Loading.css +++ b/components/log-viewer-webui/client/src/ui/Loading.css @@ -20,5 +20,5 @@ } .loading-stepper { - --Stepper-verticalGap: 2rem!important; + --Stepper-verticalGap: 2rem !important; } From af597974f6c3696a94b247f9483ea4edd6cd81b9 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Fri, 26 Jul 2024 10:31:34 -0400 Subject: [PATCH 25/30] Hide horizontal scrollbar in search result content if it does not overflow in x-direction. --- .../SearchResults/SearchResultsTable/SearchResultsTable.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss index 6c24ec2da..db2f38117 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss @@ -27,6 +27,8 @@ } .search-results-content { + overflow: auto; + font-size: 0.875rem; line-height: var(--search-results-message-line-height); } From 8bb0e84e021987274b2dd5695f178cb69a072e14 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Fri, 26 Jul 2024 11:22:18 -0400 Subject: [PATCH 26/30] Hide "Go to the log context" button for clp-s where "Extract IR" is not yet supported. --- .../SearchResultsTable/index.jsx | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index d9cd3c134..4b1329372 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -93,6 +93,10 @@ const SearchResultsTable = ({ ); }, [maxLinesPerResult]); + // eslint-disable-next-line no-warning-comments + // TODO: remove this flag once "Extract IR" support is added for ClpStorageEngine "clp-s" + const isExtractIrSupported = ("clp" === Meteor.settings.public.ClpStorageEngine); + return (
- + {isExtractIrSupported && + } @@ -135,24 +140,23 @@ const SearchResultsTable = ({ "N/A"} - + > + + + } ))} From 2b52fd5288ae2567c097da9a93a24a1f8ad3c06b Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Sat, 27 Jul 2024 13:19:47 -0400 Subject: [PATCH 27/30] Reformat code - apply suggestions from code review. Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- .../clp-package-utils/clp_package_utils/scripts/start_clp.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 0b024e814..4d0d461ba 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -786,7 +786,9 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts }, "public": { "ClpStorageEngine": clp_config.package.storage_engine, - "LogViewerWebuiUrl": f"http://{clp_config.log_viewer_webui.host}:{clp_config.log_viewer_webui.port}", + "LogViewerWebuiUrl": ( + f"http://{clp_config.log_viewer_webui.host}:{clp_config.log_viewer_webui.port}", + ), }, } meteor_settings = read_and_update_settings_json(settings_json_path, meteor_settings_updates) From a48588f127de4a6790bf40808a26e899ba791c8a Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Sat, 27 Jul 2024 13:20:32 -0400 Subject: [PATCH 28/30] Add early return statement in erroneous URL parameter case - Apply suggestions from code review Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/log-viewer-webui/client/src/ui/QueryStatus.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx index d43f8e439..4c852fc13 100644 --- a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx +++ b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx @@ -36,6 +36,7 @@ const QueryStatus = () => { console.error(error); setErrorMsg(error); + return; } submitExtractIrJob( From 4cf54ad90011788b6ddeecac57e248a88835eb82 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Sat, 27 Jul 2024 13:21:06 -0400 Subject: [PATCH 29/30] Docs / Prompts improvement - Apply suggestions from code review Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/log-viewer-webui/client/src/typings/query.js | 2 +- .../ui/SearchView/SearchResults/SearchResultsTable/index.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/log-viewer-webui/client/src/typings/query.js b/components/log-viewer-webui/client/src/typings/query.js index fb5de24f0..27e7d85c7 100644 --- a/components/log-viewer-webui/client/src/typings/query.js +++ b/components/log-viewer-webui/client/src/typings/query.js @@ -14,7 +14,7 @@ const QUERY_LOAD_STATE = Object.freeze({ }); /** - * Descriptions for query states. + * Descriptions for query loading states. */ const QUERY_STATE_DESCRIPTIONS = Object.freeze({ [QUERY_LOAD_STATE.SUBMITTING]: { diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index 4b1329372..28a331bb8 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -149,7 +149,7 @@ const SearchResultsTable = ({ Date: Sat, 27 Jul 2024 13:47:32 -0400 Subject: [PATCH 30/30] Rename QUERY_LOAD_STATE -> QUERY_LOADING_STATES. --- .../client/src/typings/query.js | 26 +++++++++---------- .../client/src/ui/Loading.jsx | 8 +++--- .../client/src/ui/QueryStatus.jsx | 8 +++--- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/components/log-viewer-webui/client/src/typings/query.js b/components/log-viewer-webui/client/src/typings/query.js index 27e7d85c7..b91a814f1 100644 --- a/components/log-viewer-webui/client/src/typings/query.js +++ b/components/log-viewer-webui/client/src/typings/query.js @@ -1,37 +1,37 @@ /** - * @typedef {number} QueryLoadState + * @typedef {number} QueryLoadingState */ -let enumQueryLoadState; +let enumQueryLoadingState; /** * Enum of query loading state. * - * @enum {QueryLoadState} + * @enum {QueryLoadingState} */ -const QUERY_LOAD_STATE = Object.freeze({ - SUBMITTING: (enumQueryLoadState = 0), - WAITING: ++enumQueryLoadState, - LOADING: ++enumQueryLoadState, +const QUERY_LOADING_STATES = Object.freeze({ + SUBMITTING: (enumQueryLoadingState = 0), + WAITING: ++enumQueryLoadingState, + LOADING: ++enumQueryLoadingState, }); /** * Descriptions for query loading states. */ -const QUERY_STATE_DESCRIPTIONS = Object.freeze({ - [QUERY_LOAD_STATE.SUBMITTING]: { +const QUERY_LOADING_STATE_DESCRIPTIONS = Object.freeze({ + [QUERY_LOADING_STATES.SUBMITTING]: { label: "Submitting query Job", description: "Parsing arguments and submitting job to the server.", }, - [QUERY_LOAD_STATE.WAITING]: { + [QUERY_LOADING_STATES.WAITING]: { label: "Waiting for job to finish", description: "The job is running. Waiting for the job to finish.", }, - [QUERY_LOAD_STATE.LOADING]: { + [QUERY_LOADING_STATES.LOADING]: { label: "Loading Log Viewer", description: "The query has been completed and the results are being loaded.", }, }); export { - QUERY_LOAD_STATE, - QUERY_STATE_DESCRIPTIONS, + QUERY_LOADING_STATE_DESCRIPTIONS, + QUERY_LOADING_STATES, }; diff --git a/components/log-viewer-webui/client/src/ui/Loading.jsx b/components/log-viewer-webui/client/src/ui/Loading.jsx index edb681dc9..e157d1224 100644 --- a/components/log-viewer-webui/client/src/ui/Loading.jsx +++ b/components/log-viewer-webui/client/src/ui/Loading.jsx @@ -9,8 +9,8 @@ import { } from "@mui/joy"; import { - QUERY_LOAD_STATE, - QUERY_STATE_DESCRIPTIONS, + QUERY_LOADING_STATE_DESCRIPTIONS, + QUERY_LOADING_STATES, } from "../typings/query.js"; import "./Loading.css"; @@ -78,9 +78,9 @@ const LoadingStep = ({ */ const Loading = ({currentState, errorMsg}) => { const steps = []; - Object.values(QUERY_LOAD_STATE).forEach((state) => { + Object.values(QUERY_LOADING_STATES).forEach((state) => { const isActive = (currentState === state); - const stateDescription = QUERY_STATE_DESCRIPTIONS[state]; + const stateDescription = QUERY_LOADING_STATE_DESCRIPTIONS[state]; steps.push( { - const [queryState, setQueryState] = useState(QUERY_LOAD_STATE.SUBMITTING); + const [queryState, setQueryState] = useState(QUERY_LOADING_STATES.SUBMITTING); const [errorMsg, setErrorMsg] = useState(null); const isFirstRun = useRef(true); @@ -43,11 +43,11 @@ const QueryStatus = () => { origFileId, Number(logEventIdx), () => { - setQueryState(QUERY_LOAD_STATE.WAITING); + setQueryState(QUERY_LOADING_STATES.WAITING); } ) .then(({data}) => { - setQueryState(QUERY_LOAD_STATE.LOADING); + setQueryState(QUERY_LOADING_STATES.LOADING); const innerLogEventNum = logEventIdx - data.begin_msg_ix + 1; window.location = `/log-viewer/index.html?filePath=/ir/${data.path}` +
-
 
-
+
 
+
-
+                                
                                     {result.message}
                                 
- + - - -