diff options
author | Leandro Alves <leandroalves@yahooinc.com> | 2022-06-22 12:47:27 +0200 |
---|---|---|
committer | Leandro Alves <leandroalves@yahooinc.com> | 2022-06-22 12:47:27 +0200 |
commit | 9be2d3ba0d7e7a68d99bad06f514dfe8cff03ed5 (patch) | |
tree | dde812c664f68b33a1a8bdd28e710cd184498407 /client | |
parent | 587d2b646501a434ed79d8c520487141b93fda8b (diff) |
Add basic app router structure
Diffstat (limited to 'client')
-rw-r--r-- | client/js/app/package.json | 1 | ||||
-rw-r--r-- | client/js/app/src/app/components/index.js | 2 | ||||
-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.jsx | 25 | ||||
-rw-r--r-- | client/js/app/src/app/libs/app-router.jsx | 42 | ||||
-rw-r--r-- | client/js/app/src/app/pages/main.jsx | 9 | ||||
-rw-r--r-- | client/js/app/src/app/pages/query-builder/index.js | 1 | ||||
-rw-r--r-- | client/js/app/src/app/pages/query-builder/query-builder.jsx | 5 | ||||
-rw-r--r-- | client/js/app/yarn.lock | 43 |
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== |