diff --git a/components/log-viewer-webui/client/eslint.config.mjs b/components/log-viewer-webui/client/eslint.config.mjs index 575bdab3fa..c775381295 100644 --- a/components/log-viewer-webui/client/eslint.config.mjs +++ b/components/log-viewer-webui/client/eslint.config.mjs @@ -44,6 +44,18 @@ const EslintConfig = [ ], }, }, + { + // eslint-disable-next-line no-warning-comments + // TODO: Remove dot notation rule once part of eslint-config-yscope + files: [ + "**/*.ts", + "**/*.tsx", + ], + rules: { + "dot-notation": "off", + "@typescript-eslint/dot-notation": "error", + }, + }, ]; diff --git a/components/log-viewer-webui/client/package-lock.json b/components/log-viewer-webui/client/package-lock.json index 75e55b0d49..428424d371 100644 --- a/components/log-viewer-webui/client/package-lock.json +++ b/components/log-viewer-webui/client/package-lock.json @@ -16,7 +16,8 @@ "antd": "^5.24.5", "axios": "^1.7.9", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-router": "^7.4.1" }, "devDependencies": { "@types/react": "^19.0.10", @@ -2226,6 +2227,12 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -3438,6 +3445,15 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "license": "MIT" }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/copy-to-clipboard": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", @@ -6927,6 +6943,30 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.4.1.tgz", + "integrity": "sha512-Vmizn9ZNzxfh3cumddqv3kLOKvc7AskUT0dC1prTabhiEi0U4A33LmkDOJ79tXaeSqCqMBXBU/ySX88W85+EUg==", + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -7188,6 +7228,12 @@ "node": ">=10" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -7700,6 +7746,12 @@ "license": "0BSD", "peer": true }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/components/log-viewer-webui/client/package.json b/components/log-viewer-webui/client/package.json index 403ce6c7a4..80e8038fd1 100644 --- a/components/log-viewer-webui/client/package.json +++ b/components/log-viewer-webui/client/package.json @@ -21,7 +21,8 @@ "antd": "^5.24.5", "axios": "^1.7.9", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-router": "^7.4.1" }, "devDependencies": { "@types/react": "^19.0.10", diff --git a/components/log-viewer-webui/client/src/AntdApp.tsx b/components/log-viewer-webui/client/src/AntdApp.tsx index ca2ee68d4d..2021013da1 100644 --- a/components/log-viewer-webui/client/src/AntdApp.tsx +++ b/components/log-viewer-webui/client/src/AntdApp.tsx @@ -1,4 +1,6 @@ -import MainLayout from "./ui/MainLayout"; +import {RouterProvider} from "react-router"; + +import router from "./router"; /** @@ -7,9 +9,7 @@ import MainLayout from "./ui/MainLayout"; * @return */ const AntApp = () => { - return ( - - ); + return ; }; export default AntApp; diff --git a/components/log-viewer-webui/client/src/ui/MainLayout.css b/components/log-viewer-webui/client/src/components/Layout/MainLayout.module.css similarity index 75% rename from components/log-viewer-webui/client/src/ui/MainLayout.css rename to components/log-viewer-webui/client/src/components/Layout/MainLayout.module.css index 4ef577453a..784310750a 100644 --- a/components/log-viewer-webui/client/src/ui/MainLayout.css +++ b/components/log-viewer-webui/client/src/components/Layout/MainLayout.module.css @@ -1,15 +1,15 @@ -.main-layout { +.mainLayout { min-height: 100vh; } -.sider-logo-container { +.siderLogoContainer { display: flex; justify-content: center; align-items: center; height: 64px; } -.sider-logo { +.siderLogo { max-width: 100%; max-height: 100%; height: 32px; diff --git a/components/log-viewer-webui/client/src/ui/MainLayout.tsx b/components/log-viewer-webui/client/src/components/Layout/MainLayout.tsx similarity index 60% rename from components/log-viewer-webui/client/src/ui/MainLayout.tsx rename to components/log-viewer-webui/client/src/components/Layout/MainLayout.tsx index 258e9c74cb..b3ef4f89c5 100644 --- a/components/log-viewer-webui/client/src/ui/MainLayout.tsx +++ b/components/log-viewer-webui/client/src/components/Layout/MainLayout.tsx @@ -1,4 +1,8 @@ import {useState} from "react"; +import { + Link, + Outlet, +} from "react-router"; import { SearchOutlined, @@ -10,16 +14,16 @@ import { MenuProps, } from "antd"; -import "./MainLayout.css"; +import styles from "./MainLayout.module.css"; const {Sider} = Layout; type MenuItem = Required["items"][number]; -const items: MenuItem[] = [ - {label: "Ingest", key: "/ingest", icon: }, - {label: "Search", key: "/search", icon: }, +const SIDEBAR_MENU_ITEMS: MenuItem[] = [ + {label: Ingest, key: "/ingest", icon: }, + {label: Search, key: "/search", icon: }, ]; /** @@ -31,7 +35,7 @@ const MainLayout = () => { const [collapsed, setCollapsed] = useState(false); return ( - + { setCollapsed(value); }} > -
+
{"CLP
+ + + ); }; + export default MainLayout; diff --git a/components/log-viewer-webui/client/src/pages/IngestPage.tsx b/components/log-viewer-webui/client/src/pages/IngestPage.tsx new file mode 100644 index 0000000000..5cfed3feef --- /dev/null +++ b/components/log-viewer-webui/client/src/pages/IngestPage.tsx @@ -0,0 +1,16 @@ +/** + * Presents compression statistics. + * + * @return + */ +const IngestPage = () => { + return ( +
+

Ingest Page

+

This is the Ingest Page.

+
+ ); +}; + + +export default IngestPage; diff --git a/components/log-viewer-webui/client/src/pages/SearchPage.tsx b/components/log-viewer-webui/client/src/pages/SearchPage.tsx new file mode 100644 index 0000000000..1e419d0661 --- /dev/null +++ b/components/log-viewer-webui/client/src/pages/SearchPage.tsx @@ -0,0 +1,16 @@ +/** + * Provides a search interface that allows users to query archives and visualize search results. + * + * @return + */ +const SearchPage = () => { + return ( +
+

Search Page

+

This is the Search Page.

+
+ ); +}; + + +export default SearchPage; diff --git a/components/log-viewer-webui/client/src/router.tsx b/components/log-viewer-webui/client/src/router.tsx new file mode 100644 index 0000000000..45e498bbd1 --- /dev/null +++ b/components/log-viewer-webui/client/src/router.tsx @@ -0,0 +1,20 @@ +import {createBrowserRouter} from "react-router"; + +import MainLayout from "./components/Layout/MainLayout"; +import IngestPage from "./pages/IngestPage"; +import SearchPage from "./pages/SearchPage"; + + +const router = createBrowserRouter([ + { + path: "/", + Component: MainLayout, + children: [ + {path: "ingest", Component: IngestPage}, + {path: "search", Component: SearchPage}, + ], + }, +]); + + +export default router;