aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeandro Alves <leandroalves@yahooinc.com>2022-06-22 12:47:27 +0200
committerLeandro Alves <leandroalves@yahooinc.com>2022-06-22 12:47:27 +0200
commit9be2d3ba0d7e7a68d99bad06f514dfe8cff03ed5 (patch)
treedde812c664f68b33a1a8bdd28e710cd184498407
parent587d2b646501a434ed79d8c520487141b93fda8b (diff)
Add basic app router structure
-rw-r--r--client/js/app/package.json1
-rw-r--r--client/js/app/src/app/components/index.js2
-rw-r--r--client/js/app/src/app/components/layout/app.jsx (renamed from client/js/app/src/app/components/App.jsx)4
-rw-r--r--client/js/app/src/app/components/layout/error.jsx25
-rw-r--r--client/js/app/src/app/libs/app-router.jsx42
-rw-r--r--client/js/app/src/app/pages/main.jsx9
-rw-r--r--client/js/app/src/app/pages/query-builder/index.js1
-rw-r--r--client/js/app/src/app/pages/query-builder/query-builder.jsx5
-rw-r--r--client/js/app/yarn.lock43
9 files changed, 123 insertions, 9 deletions
diff --git a/client/js/app/package.json b/client/js/app/package.json
index 74a0347da1c..5459608197c 100644
--- a/client/js/app/package.json
+++ b/client/js/app/package.json
@@ -16,6 +16,7 @@
"devDependencies": {
"@mantine/core": "^4",
"@mantine/hooks": "^4",
+ "@reach/router": "^1",
"@types/react": "^18",
"@types/react-dom": "^18",
"@vitejs/plugin-react": "^1",
diff --git a/client/js/app/src/app/components/index.js b/client/js/app/src/app/components/index.js
new file mode 100644
index 00000000000..e7c597c3971
--- /dev/null
+++ b/client/js/app/src/app/components/index.js
@@ -0,0 +1,2 @@
+export { App } from 'app/components/layout/app';
+export { Error } from 'app/components/layout/error';
diff --git a/client/js/app/src/app/components/App.jsx b/client/js/app/src/app/components/layout/app.jsx
index 074309854b0..ba8047ba04c 100644
--- a/client/js/app/src/app/components/App.jsx
+++ b/client/js/app/src/app/components/layout/app.jsx
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import logo from 'app/assets/logo.svg';
import 'app/styles/App.css';
-function App() {
+export function App() {
const [count, setCount] = useState(0);
return (
@@ -41,5 +41,3 @@ function App() {
</div>
);
}
-
-export default App;
diff --git a/client/js/app/src/app/components/layout/error.jsx b/client/js/app/src/app/components/layout/error.jsx
new file mode 100644
index 00000000000..95bc78df413
--- /dev/null
+++ b/client/js/app/src/app/components/layout/error.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { Center } from '@mantine/core';
+
+// TODO: make a better page
+
+function getMessage(code, location) {
+ const statusCode =
+ parseInt(code || new URLSearchParams(location?.search).get('code')) || 404;
+
+ switch (statusCode) {
+ case 403:
+ return 'Sorry, you are not authorized to view this page.';
+ case 404:
+ return 'Sorry, the page you were looking for does not exist.';
+ case 500:
+ return 'Oops... something went wrong.';
+ default:
+ return 'Unknown error - really, I have no idea what is going on here.';
+ }
+}
+
+export function Error({ code, location }) {
+ const message = getMessage(code, location);
+ return <Center sx={{ minHeight: '89px' }}>{message}</Center>;
+}
diff --git a/client/js/app/src/app/libs/app-router.jsx b/client/js/app/src/app/libs/app-router.jsx
new file mode 100644
index 00000000000..c90355b6375
--- /dev/null
+++ b/client/js/app/src/app/libs/app-router.jsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { Redirect, Router } from '@reach/router';
+import { Error } from 'app/components';
+
+const mainTitle = 'Vespa Console';
+
+function AppRoute({ element, title, default: isDefault, ...props }) {
+ const clone = React.cloneElement(element, props, props.children);
+ if (title != null) {
+ const titleStr = typeof title === 'function' ? title(props) : title;
+ document.title = titleStr.endsWith(mainTitle)
+ ? titleStr
+ : `${titleStr} - ${mainTitle}`;
+ } else if (isDefault) {
+ // Reset the title if title is not set and this is a default router
+ document.title = mainTitle;
+ }
+ return clone;
+}
+
+export function AppRouter({ children, props: inParentProps }) {
+ const newProps = Object.assign(
+ { primary: false, component: React.Fragment },
+ inParentProps
+ );
+
+ // If there is only one route then this comes as an object.
+ if (!Array.isArray(children)) children = [children];
+ const hasDefault = children.some((child) => child.props.default);
+
+ return (
+ <Router {...newProps}>
+ {children
+ .filter(({ props }) => props.enabled ?? true)
+ .map((e, i) => {
+ if (e.type === Redirect) return e;
+ return <AppRoute key={i} element={e} {...e.props} />;
+ })}
+ {!hasDefault && <Error code={404} default />}
+ </Router>
+ );
+}
diff --git a/client/js/app/src/app/pages/main.jsx b/client/js/app/src/app/pages/main.jsx
index e385b05b2a4..b183b4cf9d1 100644
--- a/client/js/app/src/app/pages/main.jsx
+++ b/client/js/app/src/app/pages/main.jsx
@@ -1,10 +1,15 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
-import App from 'app/components/App';
+import { App } from 'app/components';
import 'app/styles/index.css';
+import { AppRouter } from 'app/libs/app-router';
+import { QueryBuilder } from 'app/pages/query-builder';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
- <App />
+ <AppRouter>
+ <App path="/" />
+ <QueryBuilder path="query-builder" />
+ </AppRouter>
</React.StrictMode>
);
diff --git a/client/js/app/src/app/pages/query-builder/index.js b/client/js/app/src/app/pages/query-builder/index.js
new file mode 100644
index 00000000000..429a8dd8478
--- /dev/null
+++ b/client/js/app/src/app/pages/query-builder/index.js
@@ -0,0 +1 @@
+export { QueryBuilder } from 'app/pages/query-builder/query-builder';
diff --git a/client/js/app/src/app/pages/query-builder/query-builder.jsx b/client/js/app/src/app/pages/query-builder/query-builder.jsx
new file mode 100644
index 00000000000..7e8f133f9ec
--- /dev/null
+++ b/client/js/app/src/app/pages/query-builder/query-builder.jsx
@@ -0,0 +1,5 @@
+import React from 'react';
+
+export function QueryBuilder() {
+ return <>query builder</>;
+}
diff --git a/client/js/app/yarn.lock b/client/js/app/yarn.lock
index 709d0d356fb..ede5ded6f7a 100644
--- a/client/js/app/yarn.lock
+++ b/client/js/app/yarn.lock
@@ -402,7 +402,7 @@
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
-"@mantine/core@^4.2.10":
+"@mantine/core@^4":
version "4.2.10"
resolved "https://registry.yarnpkg.com/@mantine/core/-/core-4.2.10.tgz#6b4973bc5c79cd077341ab2bbe327749ca3ed8c4"
integrity sha512-UCPhDcumygfBvik64VkMnBvqy0ZN9q+1AQ0fPdK8aAUvjRBWSyH0dJPL55vsK1ODboKktSEsyjHtb09DroL7fA==
@@ -413,7 +413,7 @@
react-popper "^2.2.5"
react-textarea-autosize "^8.3.2"
-"@mantine/hooks@^4.2.10":
+"@mantine/hooks@^4":
version "4.2.10"
resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-4.2.10.tgz#ad55d5ad3c5814eab924dfb6fd04f9ffd44e3d30"
integrity sha512-gVYWeE4Ieu6FBwh9h/3FjcrrNzKx1k6Yw07/LSngJP0uT3fLt1gvY2p4PtPpOh7z2/RpTXBR1x+dOgEUKomYUQ==
@@ -525,6 +525,16 @@
dependencies:
"@babel/runtime" "^7.13.10"
+"@reach/router@^1.3.4":
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.3.4.tgz#d2574b19370a70c80480ed91f3da840136d10f8c"
+ integrity sha512-+mtn9wjlB9NN2CNnnC/BRYtwdKBfSyyasPYraNAyvaV1occr/5NnB4CVzjEZipNHwYebQwcndGUmpFzxAUoqSA==
+ dependencies:
+ create-react-context "0.3.0"
+ invariant "^2.2.3"
+ prop-types "^15.6.1"
+ react-lifecycles-compat "^3.0.4"
+
"@rollup/pluginutils@^4.2.1":
version "4.2.1"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
@@ -790,6 +800,14 @@ convert-source-map@^1.7.0:
dependencies:
safe-buffer "~5.1.1"
+create-react-context@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c"
+ integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==
+ dependencies:
+ gud "^1.0.0"
+ warning "^4.0.3"
+
cross-spawn@^7.0.0, cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -1408,6 +1426,11 @@ globals@^13.15.0:
dependencies:
type-fest "^0.20.2"
+gud@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
+ integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==
+
has-bigints@^1.0.1, has-bigints@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
@@ -1506,6 +1529,13 @@ internal-slot@^1.0.3:
has "^1.0.3"
side-channel "^1.0.4"
+invariant@^2.2.3:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+ integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+ dependencies:
+ loose-envify "^1.0.0"
+
is-bigint@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
@@ -1971,7 +2001,7 @@ pretty-quick@^3:
mri "^1.1.5"
multimatch "^4.0.0"
-prop-types@^15.8.1:
+prop-types@^15.6.1, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -2011,6 +2041,11 @@ react-is@^16.13.1, react-is@^16.7.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+react-lifecycles-compat@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
+ integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
+
react-popper@^2.2.5:
version "2.3.0"
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.3.0.tgz#17891c620e1320dce318bad9fede46a5f71c70ba"
@@ -2314,7 +2349,7 @@ vite@^2:
optionalDependencies:
fsevents "~2.3.2"
-warning@^4.0.2:
+warning@^4.0.2, warning@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==