diff --git a/components/log-viewer-webui/client/package-lock.json b/components/log-viewer-webui/client/package-lock.json index fc1a071310..d80e7f03b1 100644 --- a/components/log-viewer-webui/client/package-lock.json +++ b/components/log-viewer-webui/client/package-lock.json @@ -15,16 +15,19 @@ "@sinclair/typebox": "^0.34.25", "antd": "^5.24.5", "axios": "^1.7.9", + "highlight.js": "^11.11.1", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router": "^7.4.1", + "react-syntax-highlighter": "^15.6.1", "zustand": "^5.0.3" }, "devDependencies": { "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", + "@types/react-syntax-highlighter": "^15.5.13", "@vitejs/plugin-react": "^4.3.4", - "eslint-config-yscope": "*", + "eslint-config-yscope": "latest", "typescript": "~5.6.2", "vite": "^6.2.6" } @@ -2241,6 +2244,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -2289,6 +2301,22 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/react-syntax-highlighter": { + "version": "15.5.13", + "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz", + "integrity": "sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.19.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.0.tgz", @@ -3366,6 +3394,36 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", @@ -3415,6 +3473,16 @@ "node": ">= 0.8" } }, + "node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/comment-parser": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", @@ -4587,6 +4655,19 @@ "reusify": "^1.0.4" } }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/fdir": { "version": "6.4.3", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", @@ -4730,6 +4811,14 @@ "node": ">= 6" } }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -5036,6 +5125,48 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/highlightjs-vue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", + "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==", + "license": "CC0-1.0" + }, "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", @@ -5105,6 +5236,30 @@ "node": ">= 0.4" } }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -5263,6 +5418,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -5325,6 +5490,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -5738,6 +5913,29 @@ "loose-envify": "cli.js" } }, + "node_modules/lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "license": "MIT", + "dependencies": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lowlight/node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -6098,6 +6296,24 @@ "node": ">=6" } }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "license": "MIT", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/parse-imports": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.2.1.tgz", @@ -6239,6 +6455,15 @@ "node": ">= 0.8.0" } }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -6256,6 +6481,19 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -6968,6 +7206,32 @@ } } }, + "node_modules/react-syntax-highlighter": { + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.1.tgz", + "integrity": "sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "highlight.js": "^10.4.1", + "highlightjs-vue": "^1.0.0", + "lowlight": "^1.17.0", + "prismjs": "^1.27.0", + "refractor": "^3.6.0" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, + "node_modules/react-syntax-highlighter/node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -6992,6 +7256,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "license": "MIT", + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/prismjs": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", @@ -7419,6 +7707,16 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", @@ -8261,6 +8559,15 @@ "node": ">=0.10.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/components/log-viewer-webui/client/package.json b/components/log-viewer-webui/client/package.json index 6397be684f..ea62e92066 100644 --- a/components/log-viewer-webui/client/package.json +++ b/components/log-viewer-webui/client/package.json @@ -20,14 +20,17 @@ "@sinclair/typebox": "^0.34.25", "antd": "^5.24.5", "axios": "^1.7.9", + "highlight.js": "^11.11.1", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router": "^7.4.1", + "react-syntax-highlighter": "^15.6.1", "zustand": "^5.0.3" }, "devDependencies": { "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", + "@types/react-syntax-highlighter": "^15.5.13", "@vitejs/plugin-react": "^4.3.4", "eslint-config-yscope": "latest", "typescript": "~5.6.2", diff --git a/components/log-viewer-webui/client/src/pages/SearchPage/SearchControls/index.module.css b/components/log-viewer-webui/client/src/pages/SearchPage/SearchControls/index.module.css index 3b53313c8f..8119ea54bc 100644 --- a/components/log-viewer-webui/client/src/pages/SearchPage/SearchControls/index.module.css +++ b/components/log-viewer-webui/client/src/pages/SearchPage/SearchControls/index.module.css @@ -1,6 +1,4 @@ .searchControlsContainer { - margin-top: 20px; - padding: 0 20px; display: flex; gap: 10px; } diff --git a/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Message/LogViewerLink.tsx b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Message/LogViewerLink.tsx new file mode 100644 index 0000000000..765bab8129 --- /dev/null +++ b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Message/LogViewerLink.tsx @@ -0,0 +1,41 @@ +import {LinkOutlined} from "@ant-design/icons"; +import { + Tooltip, + Typography, +} from "antd"; + +import styles from "./index.module.css"; + + +const {Link} = Typography; + +// eslint-disable-next-line no-warning-comments +// TODO: Fix link to connect to package log viewer when log viewer setup finished. Also pass +// proper args to package log viewer. +const LOG_VIEWER_URL = "https://y-scope.github.io/yscope-log-viewer/"; + +interface LogViewerLinkProps { + filePath: string; +} + +/** + * Render a link to the log viewer with open file. + * + * @param props + * @param props.filePath + * @return + */ +const LogViewerLink = ({filePath}: LogViewerLinkProps) => ( + + + + {filePath} + + +); + +export default LogViewerLink; diff --git a/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Message/index.module.css b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Message/index.module.css new file mode 100644 index 0000000000..e6140d720b --- /dev/null +++ b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Message/index.module.css @@ -0,0 +1,3 @@ +.linkIcon { + margin-right: 4px; +} diff --git a/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Message/index.tsx b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Message/index.tsx new file mode 100644 index 0000000000..f9456f4bab --- /dev/null +++ b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Message/index.tsx @@ -0,0 +1,44 @@ +import SyntaxHighlighter from "react-syntax-highlighter"; + +import {Typography} from "antd"; + +import LogViewerLink from "./LogViewerLink"; +import {highlighterCustomStyles} from "./utils"; + +import "highlight.js/styles/intellij-light.css"; + + +const {Text} = Typography; + +interface MessageProps { + message: string; + filePath: string; +} + +/** + * Renders a message with syntax highlighting and a file path link. + * + * @param props + * @param props.message + * @param props.filePath + * @return + */ +const Message = ({message, filePath}: MessageProps) => { + return ( + <> + {/* Parent `Text` component allows syntax highlighter to inherit AntD fonts. */} + + + {message} + + + + + ); +}; + +export default Message; diff --git a/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Message/utils.ts b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Message/utils.ts new file mode 100644 index 0000000000..f04be5abfb --- /dev/null +++ b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Message/utils.ts @@ -0,0 +1,11 @@ +/** + * Style overrides for the syntax highlighter. "react-syntax-highlighter" lib will not accept + * styles directly from CSS modules. + */ +export const highlighterCustomStyles: React.CSSProperties = { + background: "none", + border: "none", + fontFamily: "inherit", + margin: "0", + padding: "0", +}; diff --git a/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/index.tsx b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/index.tsx new file mode 100644 index 0000000000..77e6b441de --- /dev/null +++ b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/index.tsx @@ -0,0 +1,54 @@ +import {Table} from "antd"; + +import { + SearchResult, + searchResultsTableColumns, +} from "./typings"; + + +// eslint-disable-next-line no-warning-comments +// TODO: Replace with values from database once api implemented. +const DUMMY_RESULTS: SearchResult[] = [ + { + id: 1, + timestamp: "2023-01-01 12:00:00", + message: "INFO: User login successful for user 'john.doe'.", + filePath: "/var/logs/auth.log", + }, + { + id: 2, + timestamp: "2023-01-01 12:01:00", + message: "ERROR: Failed to connect to database 'logs_db'.", + filePath: "/var/logs/db.log", + }, + { + id: 3, + timestamp: "2023-01-01 12:02:00", + message: "WARN: Disk space running low on volume '/var/logs'.", + filePath: "/var/logs/system.log", + }, + { + id: 4, + timestamp: "2023-01-01 12:03:00", + message: "DEBUG: Processing request ID 12345.", + filePath: "/var/logs/app.log", + }, +]; + +/** + * Renders search results in a table. + * + * @return + */ +const SearchResultsTable = () => { + return ( + + columns={searchResultsTableColumns} + dataSource={DUMMY_RESULTS} + pagination={false} + rowKey={(record) => record.id.toString()} + virtual={true}/> + ); +}; + +export default SearchResultsTable; diff --git a/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/typings.tsx b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/typings.tsx new file mode 100644 index 0000000000..af10344d45 --- /dev/null +++ b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/typings.tsx @@ -0,0 +1,41 @@ +import {TableProps} from "antd"; + +import Message from "./Message"; + + +/** + * Structure of search results data displayed in the table. + */ +interface SearchResult { + id: number; + timestamp: string; + message: string; + filePath: string; +} + +/** + * Columns configuration for the seach results table. + */ +const searchResultsTableColumns: NonNullable["columns"]> = [ + { + dataIndex: "timestamp", + key: "timestamp", + sorter: true, + title: "Timestamp", + width: 15, + }, + { + dataIndex: "message", + key: "message", + render: (_, record) => ( + + ), + title: "Message", + width: 85, + }, +]; + +export type {SearchResult}; +export {searchResultsTableColumns}; diff --git a/components/log-viewer-webui/client/src/pages/SearchPage/index.module.css b/components/log-viewer-webui/client/src/pages/SearchPage/index.module.css new file mode 100644 index 0000000000..b62e697498 --- /dev/null +++ b/components/log-viewer-webui/client/src/pages/SearchPage/index.module.css @@ -0,0 +1,6 @@ +.searchPageContainer { + display: flex; + flex-direction: column; + gap: 16px; + padding: 24px 16px 16px; +} diff --git a/components/log-viewer-webui/client/src/pages/SearchPage/index.tsx b/components/log-viewer-webui/client/src/pages/SearchPage/index.tsx index 429dcd3f98..d14124b4bf 100644 --- a/components/log-viewer-webui/client/src/pages/SearchPage/index.tsx +++ b/components/log-viewer-webui/client/src/pages/SearchPage/index.tsx @@ -1,4 +1,6 @@ +import styles from "./index.module.css"; import SearchControls from "./SearchControls"; +import SearchResultsTable from "./SearchResults/SearchResultsTable"; /** @@ -8,7 +10,10 @@ import SearchControls from "./SearchControls"; */ const SearchPage = () => { return ( - +
+ + +
); };