Skip to content

Commit

Permalink
Completes the asset library (#78)
Browse files Browse the repository at this point in the history
  - 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 <[email protected]>
Co-authored-by: Asger <[email protected]>
  • Loading branch information
Omarley7 authored Sep 3, 2023
1 parent 0aaa611 commit a321d6d
Show file tree
Hide file tree
Showing 74 changed files with 1,988 additions and 215 deletions.
1 change: 1 addition & 0 deletions client/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.graphql.ts auto eol=lf
1 change: 1 addition & 0 deletions client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
5 changes: 4 additions & 1 deletion client/config/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
};

REACT_APP_BACKEND_URL_GITLAB: 'gitlab.foo.com',
REACT_APP_BACKEND_GITLAB_GROUP: 'dtaas1',
};
9 changes: 6 additions & 3 deletions client/config/prod.js
Original file line number Diff line number Diff line change
@@ -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: '',
Expand All @@ -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',
};

REACT_APP_BACKEND_URL_GITLAB: 'https://gitlab.foo.com/api/graphql',
REACT_APP_BACKEND_GITLAB_GROUP: 'dtaas',
};
8 changes: 6 additions & 2 deletions client/config/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
};
};
2 changes: 2 additions & 0 deletions client/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down
5 changes: 4 additions & 1 deletion client/jest.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "<rootDir>/coverage/",
Expand Down
14 changes: 11 additions & 3 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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": {
Expand Down
1 change: 1 addition & 0 deletions client/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default defineConfig({
],
use: {
baseURL: BASE_URI,
trace: 'retain-on-failure',
},
projects: [
// Setup project
Expand Down
Binary file added client/public/static/images/file.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/public/static/images/folder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions client/relay.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"src": "./src",
"language": "typescript",
"schema": "./src/schema.graphql",
"exclude": [
"**/node_modules/**",
"**/__mocks__/**",
"**/__generated__/**"
]
}
7 changes: 5 additions & 2 deletions client/script/config.bash
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion client/script/install.bash
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/bash
yarn install --frozen-lockfile
npx playwright install-deps
yarn playwright install --with-deps
28 changes: 18 additions & 10 deletions client/src/AppProvider.tsx
Original file line number Diff line number Diff line change
@@ -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: {
Expand All @@ -12,15 +14,21 @@ const mdTheme: Theme = createTheme({
});

export function AppProvider({ children }: { children: React.ReactNode }) {
const store = setupStore();

return (
<Provider store={store}>
<ThemeProvider theme={mdTheme}>
<AuthProvider>
<CssBaseline />
{children}
</AuthProvider>
</ThemeProvider>
</Provider>
<ReduxProvider store={store}>
<RelayEnvironmentProvider environment={RelayEnvironment}>
<React.Suspense fallback={<div>Loading...</div>}>
<ThemeProvider theme={mdTheme}>
<AuthProvider>
<CssBaseline />
{children}
</AuthProvider>
</ThemeProvider>
</React.Suspense>
</RelayEnvironmentProvider>
</ReduxProvider>
);
}

Expand Down
42 changes: 42 additions & 0 deletions client/src/RelayEnvironment.ts
Original file line number Diff line number Diff line change
@@ -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;
24 changes: 24 additions & 0 deletions client/src/components/asset/AddButton.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Button
variant="contained"
fullWidth
disabled={!!state.assets.find((a) => a.path === asset.path)}
size="small"
color="primary"
onClick={() => {
actions.add(asset);
}}
>
Select
</Button>
);
}

export default AddButton;
5 changes: 5 additions & 0 deletions client/src/components/asset/Asset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface Asset {
name: string;
description?: string;
path: string;
}
45 changes: 45 additions & 0 deletions client/src/components/asset/AssetBoard.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<em style={{ textAlign: 'center' }}>{assetsFetched.errorMessage}</em>
);
}

return (
<Grid {...outerGridContainerProps}>
{assetsFetched.data.map((asset, i) => (
<Grid key={i} item xs={12} sm={6} md={4} lg={3} sx={{ minWidth: 250 }}>
<AssetCard asset={asset} />
</Grid>
))}
</Grid>
);
}

export default AssetBoard;
Loading

0 comments on commit a321d6d

Please sign in to comment.