From a321d6de678aded49ba564388ad0f3012c75ea1f Mon Sep 17 00:00:00 2001 From: Omarley7 <51030995+Omarley7@users.noreply.github.com> Date: Sun, 3 Sep 2023 14:57:32 +0200 Subject: [PATCH] Completes the asset library (#78) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The library page now loads assets from an external source and allows users to select their combination. - It introduces error handling if the username is not a repository found on the endpoint. - All shared states are now using Redux via `Access` modules. - Correct use of naming convention in react hooks in the `envUtil` module. - Introduces graphQL schema in `client/src/schema.graphql` - Improved unit testing structure. - Playwright now uses a time limit of 200ms on non API click events for E2E testing. --------- Co-authored-by: Mathias Brændgaard Co-authored-by: Asger <71492620+SyntaxXeror@users.noreply.github.com> --- client/.gitattributes | 1 + client/README.md | 1 + client/config/dev.js | 5 +- client/config/prod.js | 9 +- client/config/test.js | 8 +- client/env.d.ts | 2 + client/jest.config.json | 5 +- client/package.json | 14 +- client/playwright.config.ts | 1 + client/public/static/images/file.png | Bin 0 -> 385 bytes client/public/static/images/folder.png | Bin 0 -> 340 bytes client/relay.config.json | 10 + client/script/config.bash | 7 +- client/script/install.bash | 2 +- client/src/AppProvider.tsx | 28 +- client/src/RelayEnvironment.ts | 42 +++ client/src/components/asset/AddButton.tsx | 24 ++ client/src/components/asset/Asset.ts | 5 + client/src/components/asset/AssetBoard.tsx | 45 ++++ client/src/components/asset/AssetCard.tsx | 89 +++++++ client/src/components/cart/CartList.tsx | 20 ++ client/src/components/cart/ShoppingCart.tsx | 26 ++ .../{ => linkButtons}/LinkButtons.tsx | 0 .../{ => linkButtons}/LinkIconsLib.tsx | 0 client/src/components/tab/TabComponent.tsx | 5 +- .../tab/subcomponents/TabRender.tsx | 7 +- client/src/index.tsx | 5 +- client/src/page/DrawerComponent.tsx | 6 +- client/src/page/Menu.tsx | 20 +- client/src/page/MenuToolbar.tsx | 14 +- client/src/react-app-env.d.ts | 5 + client/src/route/library/Library.tsx | 55 +++- client/src/route/workbench/Workbench.tsx | 6 +- client/src/schema.graphql | 70 +++++ client/src/store/AppAccess.ts | 15 ++ client/src/store/CartAccess.ts | 17 ++ client/src/store/Redux/hooks.ts | 5 + .../store/{ => Redux/slices}/auth.slice.ts | 0 client/src/store/Redux/slices/cart.slice.ts | 30 +++ .../store/{ => Redux/slices}/menu.slice.ts | 0 client/src/store/Redux/store.ts | 21 ++ client/src/store/UserAccess.ts | 13 + client/src/store/store.ts | 16 -- client/src/util/apiUtil.ts | 149 +++++++++++ client/src/util/auth/Authentication.ts | 2 +- client/src/util/envUtil.ts | 36 ++- .../gitLabDirectoryListQuery.graphql.ts | 183 +++++++++++++ .../gitLabReadmeQuery.graphql.ts | 168 ++++++++++++ client/src/util/queries/gitLab.ts | 39 +++ client/test/e2e/playwright/Auth.test.ts | 14 +- client/test/e2e/playwright/Menu.test.ts | 12 +- client/test/integration/authRedux.test.tsx | 2 +- client/test/testUtil.ts | 12 - .../unitTests/Components/AssetBoard.test.tsx | 13 + .../unitTests/Components/AssetCard.test.tsx | 29 +++ .../unitTests/Components/Linkbuttons.test.tsx | 4 +- .../unitTests/Routes/DigitalTwins.test.tsx | 2 +- client/test/unitTests/Routes/Library.test.tsx | 19 +- .../test/unitTests/Store/AppAccess.test.tsx | 38 +++ .../test/unitTests/Store/CartAccess.test.tsx | 62 +++++ .../test/unitTests/Store/UserAccess.test.tsx | 19 ++ client/test/unitTests/Util/Store.test.ts | 7 +- client/test/unitTests/Util/apiUtil.test.ts | 143 +++++++++++ client/test/unitTests/Util/envUtil.test.ts | 97 +++++-- .../unitTests/__mocks__/component_mocks.tsx | 20 +- .../test/unitTests/__mocks__/global_mocks.ts | 29 --- .../test/unitTests/__mocks__/store_mocks.ts | 29 +++ client/test/unitTests/__mocks__/util_mocks.ts | 71 ++++++ client/test/unitTests/jest.setup.ts | 3 +- client/test/unitTests/testUtils.tsx | 63 ++++- client/yarn.lock | 240 +++++++++++++++++- docs/admin/client/CLIENT.md | 6 + docs/developer/client/CLIENT-dev.md | 19 ++ .../developer/client/uml/package-diagram.puml | 19 +- 74 files changed, 1988 insertions(+), 215 deletions(-) create mode 100644 client/.gitattributes create mode 100644 client/public/static/images/file.png create mode 100644 client/public/static/images/folder.png create mode 100644 client/relay.config.json create mode 100644 client/src/RelayEnvironment.ts create mode 100644 client/src/components/asset/AddButton.tsx create mode 100644 client/src/components/asset/Asset.ts create mode 100644 client/src/components/asset/AssetBoard.tsx create mode 100644 client/src/components/asset/AssetCard.tsx create mode 100644 client/src/components/cart/CartList.tsx create mode 100644 client/src/components/cart/ShoppingCart.tsx rename client/src/components/{ => linkButtons}/LinkButtons.tsx (100%) rename client/src/components/{ => linkButtons}/LinkIconsLib.tsx (100%) create mode 100644 client/src/react-app-env.d.ts create mode 100644 client/src/schema.graphql create mode 100644 client/src/store/AppAccess.ts create mode 100644 client/src/store/CartAccess.ts create mode 100644 client/src/store/Redux/hooks.ts rename client/src/store/{ => Redux/slices}/auth.slice.ts (100%) create mode 100644 client/src/store/Redux/slices/cart.slice.ts rename client/src/store/{ => Redux/slices}/menu.slice.ts (100%) create mode 100644 client/src/store/Redux/store.ts create mode 100644 client/src/store/UserAccess.ts delete mode 100644 client/src/store/store.ts create mode 100644 client/src/util/apiUtil.ts create mode 100644 client/src/util/queries/__generated__/gitLabDirectoryListQuery.graphql.ts create mode 100644 client/src/util/queries/__generated__/gitLabReadmeQuery.graphql.ts create mode 100644 client/src/util/queries/gitLab.ts delete mode 100644 client/test/testUtil.ts create mode 100644 client/test/unitTests/Components/AssetBoard.test.tsx create mode 100644 client/test/unitTests/Components/AssetCard.test.tsx create mode 100644 client/test/unitTests/Store/AppAccess.test.tsx create mode 100644 client/test/unitTests/Store/CartAccess.test.tsx create mode 100644 client/test/unitTests/Store/UserAccess.test.tsx create mode 100644 client/test/unitTests/Util/apiUtil.test.ts delete mode 100644 client/test/unitTests/__mocks__/global_mocks.ts create mode 100644 client/test/unitTests/__mocks__/store_mocks.ts create mode 100644 client/test/unitTests/__mocks__/util_mocks.ts create mode 100644 docs/developer/client/CLIENT-dev.md diff --git a/client/.gitattributes b/client/.gitattributes new file mode 100644 index 000000000..37ef122cf --- /dev/null +++ b/client/.gitattributes @@ -0,0 +1 @@ +*.graphql.ts auto eol=lf diff --git a/client/README.md b/client/README.md index 5333073e5..f7d6ca192 100644 --- a/client/README.md +++ b/client/README.md @@ -13,6 +13,7 @@ cd client yarn install #install the nodejs dependencies yarn format #format .ts[x] and .js[x] files with prettier. yarn syntax #perform linting and static analysis +yarn relay #generate graphql relay files - run after modifying graphql schema or queries for updated type syntax yarn build #build the react app into build/ directory yarn develop #start the development server without building. Great for live edits. diff --git a/client/config/dev.js b/client/config/dev.js index 3c73cc2bf..f19de52ab 100644 --- a/client/config/dev.js +++ b/client/config/dev.js @@ -15,4 +15,7 @@ window.env = { REACT_APP_REDIRECT_URI: 'https://foo.com/Library', REACT_APP_LOGOUT_REDIRECT_URI: 'https://foo.com/', REACT_APP_GITLAB_SCOPES: 'openid profile read_user read_repository api', -}; \ No newline at end of file + + REACT_APP_BACKEND_URL_GITLAB: 'gitlab.foo.com', + REACT_APP_BACKEND_GITLAB_GROUP: 'dtaas1', +}; diff --git a/client/config/prod.js b/client/config/prod.js index 3c73cc2bf..6c52f6d60 100644 --- a/client/config/prod.js +++ b/client/config/prod.js @@ -1,6 +1,6 @@ window.env = { - REACT_APP_ENVIRONMENT: 'dev', - REACT_APP_URL: 'https://foo.com/', + REACT_APP_ENVIRONMENT: 'prod', + REACT_APP_URL: 'https://foo.com', REACT_APP_URL_BASENAME: 'dtaas', REACT_APP_URL_DTLINK: '/lab', REACT_APP_URL_LIBLINK: '', @@ -15,4 +15,7 @@ window.env = { REACT_APP_REDIRECT_URI: 'https://foo.com/Library', REACT_APP_LOGOUT_REDIRECT_URI: 'https://foo.com/', REACT_APP_GITLAB_SCOPES: 'openid profile read_user read_repository api', -}; \ No newline at end of file + + REACT_APP_BACKEND_URL_GITLAB: 'https://gitlab.foo.com/api/graphql', + REACT_APP_BACKEND_GITLAB_GROUP: 'dtaas', +}; diff --git a/client/config/test.js b/client/config/test.js index c6db9e06e..7063ea537 100644 --- a/client/config/test.js +++ b/client/config/test.js @@ -10,9 +10,13 @@ window.env = { REACT_APP_WORKBENCHLINK_JUPYTERLAB: '/lab', REACT_APP_WORKBENCHLINK_JUPYTERNOTEBOOK: '', - REACT_APP_CLIENT_ID: '1be55736756190b3ace4c2c4fb19bde386d1dcc748d20b47ea8cfb5935b8446c', + REACT_APP_BACKEND_URL_GITLAB: 'https://gitlab.com/api/graphql', + REACT_APP_BACKEND_GITLAB_GROUP: 'dtaas1', + + REACT_APP_CLIENT_ID: + '1be55736756190b3ace4c2c4fb19bde386d1dcc748d20b47ea8cfb5935b8446c', REACT_APP_AUTH_AUTHORITY: 'https://gitlab.com/', REACT_APP_REDIRECT_URI: 'http://localhost:4000/Library', REACT_APP_LOGOUT_REDIRECT_URI: 'http://localhost:4000/', REACT_APP_GITLAB_SCOPES: 'openid profile read_user read_repository api', -}; \ No newline at end of file +}; diff --git a/client/env.d.ts b/client/env.d.ts index 8b77ac590..a82fbda36 100644 --- a/client/env.d.ts +++ b/client/env.d.ts @@ -19,6 +19,8 @@ declare global { REACT_APP_REDIRECT_URI: string; REACT_APP_LOGOUT_REDIRECT_URI: string; REACT_APP_GITLAB_SCOPES: string; + REACT_APP_BACKEND_URL_GITLAB: string; + REACT_APP_BACKEND_GITLAB_GROUP: string; } } diff --git a/client/jest.config.json b/client/jest.config.json index 4b4d4ca77..06ba14ea6 100644 --- a/client/jest.config.json +++ b/client/jest.config.json @@ -13,7 +13,10 @@ "build", "src/index.tsx", "src/AppProvider.tsx", - "src/store/store.ts" + "src/store/Redux/store.ts", + "src/util/queries/__generated__/", + "src/util/queries/", + "src/react-app-env.d.ts" ], "modulePathIgnorePatterns": ["test/e2e", "mocks", "config"], "coverageDirectory": "/coverage/", diff --git a/client/package.json b/client/package.json index e007508f9..d7e521d48 100644 --- a/client/package.json +++ b/client/package.json @@ -13,14 +13,15 @@ "private": false, "type": "module", "scripts": { - "develop": "npx react-scripts start", + "develop": "relay-compiler --validate && npx react-scripts start", "test": "script/test.bash", "syntax": "script/syntax.bash", - "build": "script/build.bash", + "build": "relay-compiler --validate && script/build.bash", "configapp": "script/config.bash", "start": "script/start.bash", "clean": "script/clean.bash", - "format": "prettier --ignore-path ../.gitignore --write \"**/*.{ts,tsx,css,scss}\"" + "format": "prettier --ignore-path .eslintignore --write \"**/*.{ts,tsx,css,scss}\"", + "relay": "relay-compiler" }, "eslintConfig": { "extends": [ @@ -39,15 +40,19 @@ "@reduxjs/toolkit": "^1.9.5", "dotenv": "^16.1.4", "oidc-client-ts": "^2.2.2", + "axios": "^1.4.0", + "babel-plugin-relay": "^15.0.0", "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-is": "^18.2.0", "react-oidc-context": "^2.2.2", "react-redux": "^8.0.5", + "react-relay": "15.0.0", "react-router-dom": "^6.3.0", "react-tabs": "^6.0.0", "redux": "^4.2.1", + "relay-runtime": "15.0.0", "resize-observer-polyfill": "^1.5.1", "serve": "^14.0.1", "styled-components": "^5.3.9", @@ -65,6 +70,8 @@ "@types/jest": "^29.5.0", "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", + "@types/react-relay": "14.1.3", + "@types/relay-runtime": "14.1.10", "@types/styled-components": "^5.1.26", "@typescript-eslint/eslint-plugin": "^5.34.0", "@typescript-eslint/parser": "^5.34.0", @@ -81,6 +88,7 @@ "prettier": "2.7.1", "react-iframe": "^1.8.5", "react-scripts": "^5.0.1", + "relay-compiler": "15.0.0", "ts-jest": "^29.0.5" }, "browserslist": { diff --git a/client/playwright.config.ts b/client/playwright.config.ts index b4eb033d6..224f55890 100644 --- a/client/playwright.config.ts +++ b/client/playwright.config.ts @@ -25,6 +25,7 @@ export default defineConfig({ ], use: { baseURL: BASE_URI, + trace: 'retain-on-failure', }, projects: [ // Setup project diff --git a/client/public/static/images/file.png b/client/public/static/images/file.png new file mode 100644 index 0000000000000000000000000000000000000000..c4bd665d86e50162a23883fea479d63af8cc4869 GIT binary patch literal 385 zcmV-{0e=38P)Px$J4r-ARA@u(ncWS-FbssRo4_V)0-FGn0F%HbunEW#4;6}%bK?97_cgBV&*#={ zvS9LSnLK|uKyL+E1r7lA0Cq+Rp8=dKd@%qL=x7n_$A<|71Mmc}sQ@4@iy;_*_bPeD zKE@hSvj~Dos5U^65~BcQLyQEF1u+_c8e&8M6~w3jG{ndN6vXHN0ujxzHGoWXW~$%W z;n^C1{UV`w?kMP*yo+PRI0Tz_99Bs#_?qmOFg{%Q^=I)gSf zZK0Y+OevxlfNji(`6H7P%1bIzrS;_T69XW*351+fGTVX{EDr!T0N0c=79i!P+qwgE fEB!a{^a^|c9+Y4)ry4?}00000NkvXXu0mjfcAuH; literal 0 HcmV?d00001 diff --git a/client/public/static/images/folder.png b/client/public/static/images/folder.png new file mode 100644 index 0000000000000000000000000000000000000000..8efb7008c23d5430022590f577beae4d855af5da GIT binary patch literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^Tn)&mjw^%;(gwT*V!!iY+ka@KIOq>7FP$B z6D)P#TEZCo7{r8`t(Yu)=9KnM<;aGR?jBqn45)(tT@^M(Em?e?WgWw{^;L?mUC$md z-?x31W%Qk2XMGb+o^DI*y|XmrX7%alvWXumB{}-9XlgK>J8;Neyzzs_+@`z26$}?P WxEeZMdfo~QCI(MeKbLh*2~7ZcB7h+P literal 0 HcmV?d00001 diff --git a/client/relay.config.json b/client/relay.config.json new file mode 100644 index 000000000..c9d26f36d --- /dev/null +++ b/client/relay.config.json @@ -0,0 +1,10 @@ +{ + "src": "./src", + "language": "typescript", + "schema": "./src/schema.graphql", + "exclude": [ + "**/node_modules/**", + "**/__mocks__/**", + "**/__generated__/**" + ] +} \ No newline at end of file diff --git a/client/script/config.bash b/client/script/config.bash index 769416f28..50ba74e51 100755 --- a/client/script/config.bash +++ b/client/script/config.bash @@ -4,7 +4,7 @@ # https://dev.to/akdevcraft/react-runtime-variables-49dc mode=$1 if [ -z "$mode" ]; then - printf "Use yarn configapp with either dev, prod or test:" + printf "Use yarn configapp with either dev, prod, test or ci:" printf "i.e. \"yarn configapp dev\" " exit 1 fi @@ -27,8 +27,11 @@ case "$mode" in test) set_env test ;; + ci) + set_env ci + ;; *) - echo "Invalid mode $mode - use 'dev', 'prod' or 'test'" + echo "Invalid mode $mode - use 'dev', 'prod', 'test' or 'ci'" exit 1 ;; esac diff --git a/client/script/install.bash b/client/script/install.bash index 60a2ee173..81ebc5743 100755 --- a/client/script/install.bash +++ b/client/script/install.bash @@ -1,3 +1,3 @@ #!/bin/bash yarn install --frozen-lockfile -npx playwright install-deps \ No newline at end of file +yarn playwright install --with-deps diff --git a/client/src/AppProvider.tsx b/client/src/AppProvider.tsx index eeaaae513..18ca6412b 100644 --- a/client/src/AppProvider.tsx +++ b/client/src/AppProvider.tsx @@ -1,9 +1,11 @@ import { CssBaseline } from '@mui/material'; import { ThemeProvider, createTheme, Theme } from '@mui/material/styles'; import AuthProvider from 'route/auth/AuthProvider'; +import RelayEnvironment from 'RelayEnvironment'; import * as React from 'react'; -import { Provider } from 'react-redux'; -import store from 'store/store'; +import { Provider as ReduxProvider } from 'react-redux'; +import { RelayEnvironmentProvider } from 'react-relay'; +import { setupStore } from 'store/Redux/store'; const mdTheme: Theme = createTheme({ palette: { @@ -12,15 +14,21 @@ const mdTheme: Theme = createTheme({ }); export function AppProvider({ children }: { children: React.ReactNode }) { + const store = setupStore(); + return ( - - - - - {children} - - - + + + Loading...}> + + + + {children} + + + + + ); } diff --git a/client/src/RelayEnvironment.ts b/client/src/RelayEnvironment.ts new file mode 100644 index 000000000..7dbf837f3 --- /dev/null +++ b/client/src/RelayEnvironment.ts @@ -0,0 +1,42 @@ +import { + Environment, + Network, + RecordSource, + Store, + FetchFunction, +} from 'relay-runtime'; +import axios from 'axios'; +import { getGitlabURL } from 'util/envUtil'; + +const HTTP_ENDPOINT = getGitlabURL(); + +const fetchFn: FetchFunction = async (request, variables) => { + const resp = await axios.post( + HTTP_ENDPOINT, + { + query: request.text, + variables, + }, + { + headers: { + Accept: + 'application/graphql-response+json; charset=utf-8, application/json; charset=utf-8', + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + // <-- Additional headers like 'Authorization' would go here + }, + } + ); + + return resp.data; +}; + +function createRelayEnvironment() { + return new Environment({ + network: Network.create(fetchFn), + store: new Store(new RecordSource()), + }); +} + +const RelayEnvironment = createRelayEnvironment(); +export default RelayEnvironment; diff --git a/client/src/components/asset/AddButton.tsx b/client/src/components/asset/AddButton.tsx new file mode 100644 index 000000000..a805785dc --- /dev/null +++ b/client/src/components/asset/AddButton.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import { Button } from '@mui/material'; +import { Asset } from 'components/asset/Asset'; +import useCart from 'store/CartAccess'; + +function AddButton(asset: Asset) { + const { state, actions } = useCart(); + return ( + + ); +} + +export default AddButton; diff --git a/client/src/components/asset/Asset.ts b/client/src/components/asset/Asset.ts new file mode 100644 index 000000000..70a8e8717 --- /dev/null +++ b/client/src/components/asset/Asset.ts @@ -0,0 +1,5 @@ +export interface Asset { + name: string; + description?: string; + path: string; +} diff --git a/client/src/components/asset/AssetBoard.tsx b/client/src/components/asset/AssetBoard.tsx new file mode 100644 index 000000000..626946cb5 --- /dev/null +++ b/client/src/components/asset/AssetBoard.tsx @@ -0,0 +1,45 @@ +import * as React from 'react'; +import { Grid } from '@mui/material'; +import useAssets from 'util/apiUtil'; +import AssetCard from './AssetCard'; + +const outerGridContainerProps = { + container: true, + spacing: 2, + sx: { + justifyContent: 'flex-start', + overflow: 'auto', + maxHeight: 'inherent', + }, +}; + +// TODO: Make it not capital letters.! + +/** + * Displays a board with navigational properties to locate and select assets for DT configuration. + * @param props Takes relative path to Assets. E.g `Functions` for function assets. + * @returns + */ +function AssetBoard(props: { pathToAssets: string; privateRepo?: boolean }) { + // eslint-disable-next-line no-console + console.log(props.pathToAssets); + const assetsFetched = useAssets(props.pathToAssets, props.privateRepo); + + if (!assetsFetched.data.length) { + return ( + {assetsFetched.errorMessage} + ); + } + + return ( + + {assetsFetched.data.map((asset, i) => ( + + + + ))} + + ); +} + +export default AssetBoard; diff --git a/client/src/components/asset/AssetCard.tsx b/client/src/components/asset/AssetCard.tsx new file mode 100644 index 000000000..d4be2ad3e --- /dev/null +++ b/client/src/components/asset/AssetCard.tsx @@ -0,0 +1,89 @@ +import * as React from 'react'; +import Card from '@mui/material/Card'; +import CardContent from '@mui/material/CardContent'; +import Typography from '@mui/material/Typography'; +import { Button, CardActions, Grid, Icon, SxProps, Theme } from '@mui/material'; +import styled from '@emotion/styled'; +import AddButton from 'components/asset/AddButton'; +import { Asset } from './Asset'; + +interface CardProps { + asset: Asset; + sx?: SxProps; +} + +const Header = styled(Typography)` + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + white-space. nowrap; + overflow: hidden; + text-overflow: ellipsis; +`; + +const Description = styled(Typography)` + display: -webkit-box; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; +`; + +function CardActionAreaContainer(asset: Asset) { + return ( + + + + + {asset.description} + + + + + folder + + + ); +} + +function CardButtonsContainer(asset: Asset) { + return ( + + {asset.description && ( + + )} + + + ); +} + +function AssetCard(props: CardProps) { + const { asset: data, sx } = props; + + return ( + +
{data.name}
+ + +
+ ); +} + +export default AssetCard; diff --git a/client/src/components/cart/CartList.tsx b/client/src/components/cart/CartList.tsx new file mode 100644 index 000000000..4d962b355 --- /dev/null +++ b/client/src/components/cart/CartList.tsx @@ -0,0 +1,20 @@ +import { Asset } from 'components/asset/Asset'; +import React from 'react'; +import useCart from 'store/CartAccess'; + +function CartList() { + const { state } = useCart(); + return ( +
    + {state.assets.map((a, i) => ( + + ))} +
+ ); +} + +function CartItemRender(props: { asset: Asset }) { + return
  • {props.asset.path}
  • ; +} + +export default CartList; diff --git a/client/src/components/cart/ShoppingCart.tsx b/client/src/components/cart/ShoppingCart.tsx new file mode 100644 index 000000000..d2cabdf28 --- /dev/null +++ b/client/src/components/cart/ShoppingCart.tsx @@ -0,0 +1,26 @@ +import { Button } from '@mui/material'; +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import useCart from 'store/CartAccess'; +import CartList from './CartList'; + +function ShoppingCart() { + const { actions } = useCart(); + const navigate = useNavigate(); + + return ( + <> + +
    + + +
    + + ); +} + +export default ShoppingCart; diff --git a/client/src/components/LinkButtons.tsx b/client/src/components/linkButtons/LinkButtons.tsx similarity index 100% rename from client/src/components/LinkButtons.tsx rename to client/src/components/linkButtons/LinkButtons.tsx diff --git a/client/src/components/LinkIconsLib.tsx b/client/src/components/linkButtons/LinkIconsLib.tsx similarity index 100% rename from client/src/components/LinkIconsLib.tsx rename to client/src/components/linkButtons/LinkIconsLib.tsx diff --git a/client/src/components/tab/TabComponent.tsx b/client/src/components/tab/TabComponent.tsx index f61bccabb..cd905e998 100644 --- a/client/src/components/tab/TabComponent.tsx +++ b/client/src/components/tab/TabComponent.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; -import { Paper } from '@mui/material'; +import { Paper, SxProps, Theme } from '@mui/material'; import TabRender, { TabData } from './subcomponents/TabRender'; import { Tab, TabList, TabPanel, Tabs } from './subcomponents/TabStyles'; -function TabComponent(props: { tabs: TabData[] }) { +function TabComponent(props: { tabs: TabData[]; sx?: SxProps }) { return ( diff --git a/client/src/components/tab/subcomponents/TabRender.tsx b/client/src/components/tab/subcomponents/TabRender.tsx index 16d22b954..0901084d5 100644 --- a/client/src/components/tab/subcomponents/TabRender.tsx +++ b/client/src/components/tab/subcomponents/TabRender.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import { Box } from '@mui/material'; interface TabRenderProps { index: number; @@ -15,11 +14,11 @@ function TabRender(props: TabRenderProps) { const { children: tab, index } = props; return ( - {tab.body} - + ); } diff --git a/client/src/index.tsx b/client/src/index.tsx index 40b8c7369..3f8d8dd11 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -4,9 +4,9 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import ReactDOM from 'react-dom/client'; import WorkBench from 'route/workbench/Workbench'; import AppProvider from 'AppProvider'; -import { useURLbasename } from 'util/envUtil'; import LayoutPublic from 'page/LayoutPublic'; import PrivateRoute from 'route/auth/PrivateRoute'; +import { getURLbasename } from 'util/envUtil'; import Library from './route/library/Library'; import DigitalTwins from './route/digitaltwins/DigitalTwins'; import SignIn from './route/auth/Signin'; @@ -55,8 +55,9 @@ const router = createBrowserRouter( ), }, ], + { - basename: `/${useURLbasename()}`, + basename: `/${getURLbasename()}`, } ); diff --git a/client/src/page/DrawerComponent.tsx b/client/src/page/DrawerComponent.tsx index d2b1ea1e1..f874b190f 100644 --- a/client/src/page/DrawerComponent.tsx +++ b/client/src/page/DrawerComponent.tsx @@ -7,10 +7,10 @@ import { transition } from './MenuToolbar'; import MenuItems from './MenuItems'; import DrawerHeaderComponent from './DrawerHeaderComponent'; -const drawerWidth = 240; +const drawerwidth = 240; const openedMixin = (theme: Theme): CSSObject => ({ - width: drawerWidth, + width: drawerwidth, transition: transition({ theme, open: true }), overflowX: 'hidden', }); @@ -27,7 +27,7 @@ const closedMixin = (theme: Theme): CSSObject => ({ const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== 'open', })(({ theme, open }) => ({ - width: drawerWidth, + width: drawerwidth, flexShrink: 0, whiteSpace: 'nowrap', boxSizing: 'border-box', diff --git a/client/src/page/Menu.tsx b/client/src/page/Menu.tsx index 9466e8f7d..099fe68f2 100644 --- a/client/src/page/Menu.tsx +++ b/client/src/page/Menu.tsx @@ -1,35 +1,33 @@ import * as React from 'react'; import { useTheme } from '@mui/material/styles'; import Box from '@mui/material/Box'; -import { useDispatch, useSelector } from 'react-redux'; -import { closeMenu, openMenu } from 'store/menu.slice'; -import { RootState } from 'store/store'; +import useAppState from 'store/AppAccess'; import MenuToolbar from './MenuToolbar'; import DrawerComponent from './DrawerComponent'; -const drawerWidth = 240; +const drawerwidth = 240; const hooks = () => { const theme = useTheme(); - const menuState = useSelector((state: RootState) => state.menu); - const dispatch = useDispatch(); + const { state: menuState, actions: menuAction } = useAppState(); const [anchorElUser, setAnchorElUser] = React.useState(null); - return { theme, menuState, dispatch, anchorElUser, setAnchorElUser }; + return { theme, menuState, menuAction, anchorElUser, setAnchorElUser }; }; function MiniDrawer() { - const { theme, menuState, dispatch, anchorElUser, setAnchorElUser } = hooks(); + const { theme, menuState, menuAction, anchorElUser, setAnchorElUser } = + hooks(); const handleCloseUserMenu = () => setAnchorElUser(null); const handleOpenUserMenu = (event: React.MouseEvent) => setAnchorElUser(event.currentTarget); - const handleDrawerOpen = () => dispatch(openMenu()); - const handleDrawerClose = () => dispatch(closeMenu()); + const handleDrawerOpen = () => menuAction.open(); + const handleDrawerClose = () => menuAction.close(); return ( prop !== 'open', -})(({ theme, open, drawerWidth }) => ({ +})(({ theme, open, drawerwidth }) => ({ zIndex: theme.zIndex.drawer + 1, transition: transition({ theme, open }), ...(open && { - marginLeft: drawerWidth, - width: `calc(100% - ${drawerWidth}px)`, + marginLeft: drawerwidth, + width: `calc(100% - ${drawerwidth}px)`, transition: transition({ theme, open }), }), })); @@ -49,13 +49,13 @@ interface MenuToolbarProps { handleDrawerOpen: () => void; handleOpenUserMenu: (event: React.MouseEvent) => void; handleCloseUserMenu: () => void; - drawerWidth: number; + drawerwidth: number; anchorElUser: HTMLElement | null; } function MenuToolbar({ open, - drawerWidth, + drawerwidth, handleCloseUserMenu, handleOpenUserMenu, handleDrawerOpen, @@ -69,7 +69,7 @@ function MenuToolbar({ } }; return ( - + ({ label: tab.label, body: ( <> {tab.body} -