Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Create tab into Digital Twins page preview #1005

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
d2a6df7
Start create page
VanessaScherma Oct 25, 2024
d9a9a4b
Complete start page
VanessaScherma Oct 25, 2024
92cb369
Little fix
VanessaScherma Oct 25, 2024
2bacabe
Move field for DT name
VanessaScherma Oct 26, 2024
d50cae0
Fix reconfigure
VanessaScherma Oct 26, 2024
5395574
Refactor gitlabDigitalTwin
VanessaScherma Oct 27, 2024
53c3e30
Fix codeclimate issue (gitlabDigitalTwin)
VanessaScherma Oct 27, 2024
41a36cb
Refactor CreatePage
VanessaScherma Oct 27, 2024
5051ce2
Refactor CreatePage
VanessaScherma Oct 28, 2024
39fc69a
Refactor Create dialogs
VanessaScherma Oct 28, 2024
a18bca8
Fix codeclimate issues
VanessaScherma Oct 28, 2024
fc573bb
Refactor Sidebar
VanessaScherma Oct 28, 2024
fbaf9b7
Fix codeclimate issues
VanessaScherma Oct 28, 2024
47a66e4
Fix codeclimate issues
VanessaScherma Oct 28, 2024
1949343
Apply changes and refactor
VanessaScherma Oct 31, 2024
ed8fa36
Remove duplication from files reducers
VanessaScherma Oct 31, 2024
16093b1
Apply requested changes
VanessaScherma Nov 1, 2024
511d5c3
Fix and add unit tests
Nov 5, 2024
f79f9f9
Fix integration tests
Nov 6, 2024
e60abe5
Apply requested changes
Nov 7, 2024
89cd7d6
Add integration tests
Nov 7, 2024
3148f9b
rebase
Nov 7, 2024
cb476a6
Little fix
Nov 7, 2024
6c71a0d
Little fix
Nov 7, 2024
0c00214
Refactor DigitalTwin class and add DTAssets class
Nov 8, 2024
1c4f56b
Update unit tests
Nov 9, 2024
cea5cd1
Upgrade integration tests
Nov 9, 2024
58ff8a6
Working integration tests
Nov 12, 2024
c53bdcd
Update test coverage
Nov 13, 2024
4e2b938
Update eslint.config.mjs
Nov 13, 2024
7eec74a
Update test commands
Nov 13, 2024
c433a39
PR review changes
VanessaScherma Nov 14, 2024
787c0c5
Update package.json
VanessaScherma Nov 14, 2024
6a9b885
Update text in Manage page
VanessaScherma Nov 14, 2024
d1008c3
Yarn format changes
VanessaScherma Nov 14, 2024
ba118c3
Add dt_preview to test.js
VanessaScherma Nov 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ jobs:
yarn test:unit
yarn test:preview:unit
yarn test:preview:int
yarn test:coverage:int-unit

- name: Upload unit and integration test coverage to Codecov
uses: codecov/codecov-action@v3
Expand Down
2 changes: 1 addition & 1 deletion client/DEVELOPER.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,5 +218,5 @@ and tested using the following yarn commands.
```bash
yarn test:preview:int
yarn test:preview:unit
yarn test:coverage:int-unit
```

1 change: 1 addition & 0 deletions client/config/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ if (typeof window !== 'undefined') {
REACT_APP_WORKBENCHLINK_VSCODE: '/tools/vscode/',
REACT_APP_WORKBENCHLINK_JUPYTERLAB: '/lab',
REACT_APP_WORKBENCHLINK_JUPYTERNOTEBOOK: '',
REACT_APP_WORKBENCHLINK_DT_PREVIEW: '/preview/digitaltwins',

REACT_APP_CLIENT_ID: '1be55736756190b3ace4c2c4fb19bde386d1dcc748d20b47ea8cfb5935b8446c',
REACT_APP_AUTH_AUTHORITY: 'https://gitlab.com/',
Expand Down
8 changes: 0 additions & 8 deletions client/jest.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,6 @@
"config"
],
"coverageDirectory": "<rootDir>/coverage/",
"coverageThreshold": {
"global": {
"branches": 20,
"functions": 30,
"lines": 50,
"statements": 50
}
},
"globals": {
"window.ENV.SERVER_HOSTNAME": "localhost",
"window.ENV.SERVER_PORT": 3500
Expand Down
9 changes: 5 additions & 4 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@
"test:all": "yarn test:unit && yarn test:int && yarn test:e2e",
"test:e2e:ext": "cross-env ext=true yarn test:e2e",
"test:e2e": "yarn config:test && playwright test -c ./playwright.config.ts",
"test:int": "jest -c ./jest.config.json ../test/integration --setupFilesAfterEnv ./test/integration/jest.setup.ts",
"test:unit": "jest -c ./jest.config.json ../test/unit --setupFilesAfterEnv ./test/unit/jest.setup.ts",
"test:preview:int": "jest -c ./jest.config.json ../test/preview/integration --setupFilesAfterEnv ./test/preview/integration/jest.setup.ts",
"test:preview:unit": "jest -c ./jest.config.json ../test/preview/unit --setupFilesAfterEnv ./test/preview/unit/jest.setup.ts"
"test:coverage:int-unit": "npx istanbul-combine -d coverage/all -r lcov -r json -r text coverage/unit/coverage-final.json coverage/int/coverage-final.json coverage/preview/unit/coverage-final.json coverage/preview/int/coverage-final.json",
"test:int": "jest -c ./jest.config.json jest --coverage --coverageDirectory=coverage/int ../test/integration --setupFilesAfterEnv ./test/integration/jest.setup.ts",
"test:unit": "jest -c ./jest.config.json --coverageDirectory=coverage/unit ../test/unit --setupFilesAfterEnv ./test/unit/jest.setup.ts",
"test:preview:int": "jest -c ./jest.config.json --coverageDirectory=coverage/preview/int ../test/preview/integration --setupFilesAfterEnv ./test/preview/integration/jest.setup.ts",
"test:preview:unit": "jest -c ./jest.config.json --coverageDirectory=coverage/preview/unit ../test/preview/unit --setupFilesAfterEnv ./test/preview/unit/jest.setup.ts"
},
"eslintConfig": {
"extends": [
Expand Down
14 changes: 11 additions & 3 deletions client/src/preview/components/asset/AssetBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { Grid } from '@mui/material';
import { useSelector, useDispatch } from 'react-redux';
import { RootState } from 'store/store';
import { deleteAsset } from 'preview/store/assets.slice';
import { AssetCardExecute, AssetCardManage } from './AssetCard';
import { fetchAssets } from 'preview/util/init';
import { Asset } from './Asset';
import { AssetCardExecute, AssetCardManage } from './AssetCard';

const outerGridContainerProps = {
container: true,
Expand All @@ -19,7 +20,6 @@ const outerGridContainerProps = {

interface AssetBoardProps {
tab: string;
error: string | null;
}

const AssetGridItem: React.FC<{
Expand All @@ -44,10 +44,18 @@ const AssetGridItem: React.FC<{
</Grid>
);

const AssetBoard: React.FC<AssetBoardProps> = ({ tab, error }) => {
const AssetBoard: React.FC<AssetBoardProps> = ({ tab }) => {
const assets = useSelector((state: RootState) => state.assets.items);
const [error, setError] = React.useState<string | null>(null);
const dispatch = useDispatch();

React.useEffect(() => {
const fetchData = async () => {
await fetchAssets(dispatch, setError);
};
fetchData();
}, [dispatch]);

const handleDelete = (deletedAssetPath: string) => {
dispatch(deleteAsset(deletedAssetPath));
};
Expand Down
2 changes: 1 addition & 1 deletion client/src/preview/components/asset/AssetCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import CardContent from '@mui/material/CardContent';
import Typography from '@mui/material/Typography';
import { AlertColor, CardActions, Grid } from '@mui/material';
import styled from '@emotion/styled';
import { formatName } from 'preview/util/gitlabDigitalTwin';
import { formatName } from 'preview/util/digitalTwin';
import CustomSnackbar from 'preview/route/digitaltwins/Snackbar';
import { useSelector } from 'react-redux';
import { selectDigitalTwinByName } from 'preview/store/digitalTwin.slice';
Expand Down
2 changes: 1 addition & 1 deletion client/src/preview/components/asset/DetailsButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Dispatch, SetStateAction } from 'react';
import { Button } from '@mui/material';
import { useSelector } from 'react-redux';
import { selectDigitalTwinByName } from '../../store/digitalTwin.slice';
import DigitalTwin from '../../util/gitlabDigitalTwin';
import DigitalTwin from '../../util/digitalTwin';

interface DialogButtonProps {
assetName: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { ITabs } from 'route/IData';
const tabs: ITabs[] = [
{
label: 'Create',
body: `Create digital twins from tools provided within user workspaces. Each digital twin will have one directory. It is suggested that user provide one bash shell script to run their digital twin. Users can create the required scripts and other files from tools provided in Workbench page.`,
body: `Create and save new digital twins. The new digital twins are saved in the linked gitlab repository. Remember to add valid '.gitlab-ci.yml' configuration as it is used for execution of digital twin.`,
},
{
label: 'Manage',
body: `Read the complete description of digital twins. If necessary, users can delete a digital twin, removing it from the workspace with all its associated data. Users can also reconfigure the digital twin.`,
body: `Explore, edit and delete existing digital twins. The changes get saved in the linked gitlab repository.`,
},
{
label: 'Execute',
body: 'Execute the Digital Twins using Gitlab CI/CD workflows.',
body: 'Execute existing digital twins using CI/CD pipelines of the linked gitlab repository. Availability of gitlab runners is required for execution of digital twins.',
},
{
label: 'Analyze',
Expand Down
119 changes: 51 additions & 68 deletions client/src/preview/route/digitaltwins/DigitalTwinsPreview.tsx
Original file line number Diff line number Diff line change
@@ -1,96 +1,79 @@
import * as React from 'react';
import { useState, useEffect } from 'react';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { Typography } from '@mui/material';
import Layout from 'page/Layout';
import TabComponent from 'components/tab/TabComponent';
import { TabData } from 'components/tab/subcomponents/TabRender';
import AssetBoard from 'preview/components/asset/AssetBoard';
import GitlabInstance from 'preview/util/gitlab';
import { getAuthority } from 'util/envUtil';
import { setAssets } from 'preview/store/assets.slice';
import { Asset } from 'preview/components/asset/Asset';
import DigitalTwin from 'preview/util/gitlabDigitalTwin';
import { setDigitalTwin } from 'preview/store/digitalTwin.slice';
import { defaultFiles } from 'preview/util/fileUtils';
import { addOrUpdateFile } from 'preview/store/file.slice';
import tabs from './DigitalTwinTabDataPreview';
import CreatePage from './create/CreatePage';

export const createDTTab = (error: string | null): TabData[] =>
interface DTTabProps {
newDigitalTwinName: string;
setNewDigitalTwinName: React.Dispatch<React.SetStateAction<string>>;
}

export const createDTTab = ({
newDigitalTwinName,
setNewDigitalTwinName,
}: DTTabProps): TabData[] =>
tabs
.filter((tab) => tab.label === 'Manage' || tab.label === 'Execute')
.filter(
(tab) =>
tab.label === 'Manage' ||
tab.label === 'Execute' ||
tab.label === 'Create',
)
.map((tab) => ({
label: tab.label,
body: (
<>
<Typography variant="body1">{tab.body}</Typography>
<AssetBoard tab={tab.label} error={error} />
</>
),
body:
tab.label === 'Create' ? (
<>
<Typography variant="body1">{tab.body}</Typography>
<CreatePage
newDigitalTwinName={newDigitalTwinName}
setNewDigitalTwinName={setNewDigitalTwinName}
/>
</>
) : (
<>
<Typography variant="body1">{tab.body}</Typography>
<AssetBoard tab={tab.label} />
</>
),
}));

export const fetchSubfolders = async (
gitlabInstance: GitlabInstance,
dispatch: ReturnType<typeof useDispatch>,
setError: React.Dispatch<React.SetStateAction<string | null>>,
) => {
try {
await gitlabInstance.init();
if (gitlabInstance.projectId) {
const subfolders = await gitlabInstance.getDTSubfolders(
gitlabInstance.projectId,
);
dispatch(setAssets(subfolders));
return subfolders;
}
dispatch(setAssets([]));
return [];
} catch (_error) {
setError(`An error occurred`);
return [];
}
};

export const createDigitalTwinsForAssets = async (
assets: Asset[],
dispatch: ReturnType<typeof useDispatch>,
) => {
assets.forEach(async (asset) => {
const gitlabInstance = new GitlabInstance(
sessionStorage.getItem('username') || '',
getAuthority(),
sessionStorage.getItem('access_token') || '',
);
await gitlabInstance.init();
const digitalTwin = new DigitalTwin(asset.name, gitlabInstance);
await digitalTwin.getDescription();
dispatch(setDigitalTwin({ assetName: asset.name, digitalTwin }));
});
};

export const DTContent = () => {
prasadtalasila marked this conversation as resolved.
Show resolved Hide resolved
const [error, setError] = useState<string | null>(null);
const [newDigitalTwinName, setNewDigitalTwinName] = React.useState('');
const dispatch = useDispatch();

useEffect(() => {
const gitlabInstance = new GitlabInstance(
sessionStorage.getItem('username') || '',
getAuthority(),
sessionStorage.getItem('access_token') || '',
);
fetchSubfolders(gitlabInstance, dispatch, setError).then((assets) => {
if (assets) {
createDigitalTwinsForAssets(assets, dispatch);
}
defaultFiles.forEach((file) => {
dispatch(
addOrUpdateFile({
name: file.name,
content: '',
isNew: true,
isModified: false,
}),
);
});
}, [dispatch]);

return (
<Layout>
<Typography variant="body1" style={{ marginBottom: 0 }}>
This page demonstrates integration of DTaaS with gitlab CI/CD workflows.
The feature is experimental and requires certain gitlab setup in order
<Typography variant="body1" sx={{ marginBottom: 0 }}>
This page demonstrates integration of DTaaS with GitLab CI/CD workflows.
The feature is experimental and requires certain GitLab setup in order
for it to work.
</Typography>
<TabComponent assetType={createDTTab(error)} scope={[]} />
<TabComponent
assetType={createDTTab({ newDigitalTwinName, setNewDigitalTwinName })}
scope={[]}
/>
</Layout>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import * as React from 'react';
import {
Dialog,
DialogActions,
DialogContent,
DialogTitle,
TextField,
Button,
Typography,
} from '@mui/material';
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
import { handleChangeFileName } from 'preview/util/fileUtils';
import { useDispatch, useSelector } from 'react-redux';
import { RootState } from 'store/store';

interface ChangeFileNameDialogProps {
open: boolean;
setOpenChangeFileNameDialog: Dispatch<SetStateAction<boolean>>;
fileName: string;
setFileName: Dispatch<SetStateAction<string>>;
setFileType: Dispatch<SetStateAction<string>>;
}

const ChangeFileNameDialog: React.FC<ChangeFileNameDialogProps> = ({
open,
setOpenChangeFileNameDialog,
fileName,
setFileName,
setFileType,
}) => {
const [modifiedFileName, setModifiedFileName] = useState(fileName);
const [errorChangeMessage, setErrorChangeMessage] = useState('');

const files = useSelector((state: RootState) => state.files);
const dispatch = useDispatch();

useEffect(() => {
setModifiedFileName(fileName);
}, [fileName]);

const handleCloseChangeFileNameDialog = () => {
setOpenChangeFileNameDialog(false);
setErrorChangeMessage('');
setModifiedFileName(fileName);
};

return (
<Dialog open={open} onClose={setOpenChangeFileNameDialog}>
<DialogTitle>Change the file name</DialogTitle>
<DialogContent>
<TextField
autoFocus
margin="dense"
label="New File Name"
fullWidth
variant="outlined"
value={modifiedFileName}
onChange={(e) => setModifiedFileName(e.target.value)}
/>
<Typography style={{ color: 'red' }}>{errorChangeMessage}</Typography>
</DialogContent>
<DialogActions>
<Button
onClick={() => handleCloseChangeFileNameDialog()}
color="primary"
>
Cancel
</Button>
<Button
onClick={() =>
handleChangeFileName(
files,
modifiedFileName,
fileName,
setFileName,
setFileType,
setErrorChangeMessage,
setOpenChangeFileNameDialog,
dispatch,
)
}
color="secondary"
>
Change
</Button>
</DialogActions>
</Dialog>
);
};

export default ChangeFileNameDialog;
Loading
Loading