-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1885 from AntaresSimulatorTeam/feature/ANT-966-de…
…bug-view-editor
- Loading branch information
Showing
26 changed files
with
1,121 additions
and
946 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
webapp/src/components/App/Singlestudy/explore/Modelization/Debug/Data/Json.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import { useState } from "react"; | ||
import { useTranslation } from "react-i18next"; | ||
import { AxiosError } from "axios"; | ||
import { useSnackbar } from "notistack"; | ||
import SaveIcon from "@mui/icons-material/Save"; | ||
import { Box, Button, Typography } from "@mui/material"; | ||
import { useUpdateEffect } from "react-use"; | ||
import { | ||
editStudy, | ||
getStudyData, | ||
} from "../../../../../../../services/api/study"; | ||
import { Header, Root } from "./style"; | ||
import SimpleLoader from "../../../../../../common/loaders/SimpleLoader"; | ||
import JSONEditor from "../../../../../../common/JSONEditor"; | ||
import usePromiseWithSnackbarError from "../../../../../../../hooks/usePromiseWithSnackbarError"; | ||
import UsePromiseCond from "../../../../../../common/utils/UsePromiseCond"; | ||
import SimpleContent from "../../../../../../common/page/SimpleContent"; | ||
import useEnqueueErrorSnackbar from "../../../../../../../hooks/useEnqueueErrorSnackbar"; | ||
|
||
interface Props { | ||
path: string; | ||
studyId: string; | ||
} | ||
|
||
function Json({ path, studyId }: Props) { | ||
const [t] = useTranslation(); | ||
const { enqueueSnackbar } = useSnackbar(); | ||
const enqueueErrorSnackbar = useEnqueueErrorSnackbar(); | ||
const [jsonData, setJsonData] = useState<string | null>(null); | ||
const [isSaveAllowed, setSaveAllowed] = useState(false); | ||
|
||
const res = usePromiseWithSnackbarError( | ||
() => getStudyData(studyId, path, -1), | ||
{ | ||
errorMessage: t("studies.error.retrieveData"), | ||
deps: [studyId, path], | ||
}, | ||
); | ||
|
||
/* Reset save button when path changes */ | ||
useUpdateEffect(() => { | ||
setSaveAllowed(false); | ||
}, [studyId, path]); | ||
|
||
//////////////////////////////////////////////////////////////// | ||
// Event Handlers | ||
//////////////////////////////////////////////////////////////// | ||
|
||
const handleSaveJson = async () => { | ||
if (isSaveAllowed && jsonData) { | ||
try { | ||
await editStudy(jsonData, studyId, path); | ||
enqueueSnackbar(t("studies.success.saveData"), { | ||
variant: "success", | ||
}); | ||
setSaveAllowed(false); | ||
} catch (e) { | ||
enqueueErrorSnackbar(t("studies.error.saveData"), e as AxiosError); | ||
} | ||
} | ||
}; | ||
|
||
const handleJsonChange = (newJson: string) => { | ||
setJsonData(newJson); | ||
setSaveAllowed(true); | ||
}; | ||
|
||
//////////////////////////////////////////////////////////////// | ||
// JSX | ||
//////////////////////////////////////////////////////////////// | ||
|
||
return ( | ||
<Root> | ||
<Header> | ||
<Button | ||
variant="outlined" | ||
color="primary" | ||
startIcon={<SaveIcon sx={{ width: 15, height: 15 }} />} | ||
onClick={handleSaveJson} | ||
disabled={!isSaveAllowed} | ||
> | ||
<Typography sx={{ fontSize: "12px" }}>{t("global.save")}</Typography> | ||
</Button> | ||
</Header> | ||
<UsePromiseCond | ||
response={res} | ||
ifPending={() => <SimpleLoader />} | ||
ifResolved={(json) => ( | ||
<Box | ||
sx={{ | ||
width: 1, | ||
height: 1, | ||
}} | ||
> | ||
<JSONEditor | ||
json={json} | ||
onChangeJSON={handleJsonChange} | ||
onChangeText={handleJsonChange} // only for code mode | ||
modes={["tree", "code"]} | ||
enableSort={false} | ||
enableTransform={false} | ||
/> | ||
</Box> | ||
)} | ||
ifRejected={(error) => <SimpleContent title={error?.toString()} />} | ||
/> | ||
</Root> | ||
); | ||
} | ||
|
||
export default Json; |
26 changes: 26 additions & 0 deletions
26
webapp/src/components/App/Singlestudy/explore/Modelization/Debug/Data/Matrix.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { useOutletContext } from "react-router"; | ||
import { MatrixStats, StudyMetadata } from "../../../../../../../common/types"; | ||
import { Root, Content } from "./style"; | ||
import MatrixInput from "../../../../../../common/MatrixInput"; | ||
|
||
interface Props { | ||
path: string; | ||
} | ||
|
||
function Matrix({ path }: Props) { | ||
const { study } = useOutletContext<{ study: StudyMetadata }>(); | ||
|
||
//////////////////////////////////////////////////////////////// | ||
// JSX | ||
//////////////////////////////////////////////////////////////// | ||
|
||
return ( | ||
<Root> | ||
<Content> | ||
<MatrixInput study={study} url={path} computStats={MatrixStats.NOCOL} /> | ||
</Content> | ||
</Root> | ||
); | ||
} | ||
|
||
export default Matrix; |
91 changes: 91 additions & 0 deletions
91
webapp/src/components/App/Singlestudy/explore/Modelization/Debug/Data/Text.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { useState } from "react"; | ||
import { AxiosError } from "axios"; | ||
import { useSnackbar } from "notistack"; | ||
import { useTranslation } from "react-i18next"; | ||
import { Button } from "@mui/material"; | ||
import UploadOutlinedIcon from "@mui/icons-material/UploadOutlined"; | ||
import { | ||
getStudyData, | ||
importFile, | ||
} from "../../../../../../../services/api/study"; | ||
import { Content, Header, Root } from "./style"; | ||
import useEnqueueErrorSnackbar from "../../../../../../../hooks/useEnqueueErrorSnackbar"; | ||
import SimpleLoader from "../../../../../../common/loaders/SimpleLoader"; | ||
import ImportDialog from "../../../../../../common/dialogs/ImportDialog"; | ||
import usePromiseWithSnackbarError from "../../../../../../../hooks/usePromiseWithSnackbarError"; | ||
import SimpleContent from "../../../../../../common/page/SimpleContent"; | ||
import UsePromiseCond from "../../../../../../common/utils/UsePromiseCond"; | ||
import { useDebugContext } from "../DebugContext"; | ||
|
||
interface Props { | ||
studyId: string; | ||
path: string; | ||
} | ||
|
||
function Text({ studyId, path }: Props) { | ||
const [t] = useTranslation(); | ||
const { reloadTreeData } = useDebugContext(); | ||
const { enqueueSnackbar } = useSnackbar(); | ||
const enqueueErrorSnackbar = useEnqueueErrorSnackbar(); | ||
const [openImportDialog, setOpenImportDialog] = useState(false); | ||
|
||
const res = usePromiseWithSnackbarError(() => getStudyData(studyId, path), { | ||
errorMessage: t("studies.error.retrieveData"), | ||
deps: [studyId, path], | ||
}); | ||
|
||
//////////////////////////////////////////////////////////////// | ||
// Event Handlers | ||
//////////////////////////////////////////////////////////////// | ||
|
||
const handleImport = async (file: File) => { | ||
try { | ||
await importFile(file, studyId, path); | ||
reloadTreeData(); | ||
enqueueSnackbar(t("studies.success.saveData"), { | ||
variant: "success", | ||
}); | ||
} catch (e) { | ||
enqueueErrorSnackbar(t("studies.error.saveData"), e as AxiosError); | ||
} | ||
}; | ||
|
||
//////////////////////////////////////////////////////////////// | ||
// JSX | ||
//////////////////////////////////////////////////////////////// | ||
|
||
return ( | ||
<Root> | ||
<Header> | ||
<Button | ||
variant="outlined" | ||
color="primary" | ||
startIcon={<UploadOutlinedIcon />} | ||
onClick={() => setOpenImportDialog(true)} | ||
sx={{ mb: 1 }} | ||
> | ||
{t("global.import")} | ||
</Button> | ||
</Header> | ||
<UsePromiseCond | ||
response={res} | ||
ifPending={() => <SimpleLoader />} | ||
ifResolved={(data) => ( | ||
<Content> | ||
<code style={{ whiteSpace: "pre" }}>{data}</code> | ||
</Content> | ||
)} | ||
ifRejected={(error) => <SimpleContent title={error?.toString()} />} | ||
/> | ||
{openImportDialog && ( | ||
<ImportDialog | ||
open={openImportDialog} | ||
onClose={() => setOpenImportDialog(false)} | ||
onImport={handleImport} | ||
/> | ||
)} | ||
</Root> | ||
); | ||
} | ||
|
||
export default Text; |
24 changes: 24 additions & 0 deletions
24
webapp/src/components/App/Singlestudy/explore/Modelization/Debug/Data/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import Text from "./Text"; | ||
import Json from "./Json"; | ||
import Matrix from "./Matrix"; | ||
import { FileType } from "../utils"; | ||
|
||
interface Props { | ||
studyId: string; | ||
fileType: FileType; | ||
filePath: string; | ||
} | ||
|
||
const componentByFileType = { | ||
matrix: Matrix, | ||
json: Json, | ||
file: Text, | ||
} as const; | ||
|
||
function Data({ studyId, fileType, filePath }: Props) { | ||
const DataViewer = componentByFileType[fileType]; | ||
|
||
return <DataViewer studyId={studyId} path={filePath} />; | ||
} | ||
|
||
export default Data; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
webapp/src/components/App/Singlestudy/explore/Modelization/Debug/DebugContext.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { createContext, useContext } from "react"; | ||
import { FileType, TreeData } from "./utils"; | ||
|
||
interface DebugContextProps { | ||
treeData: TreeData; | ||
onFileSelect: (fileType: FileType, filePath: string) => void; | ||
reloadTreeData: () => void; | ||
} | ||
|
||
const initialDebugContextValue: DebugContextProps = { | ||
treeData: {}, | ||
onFileSelect: () => {}, | ||
reloadTreeData: () => {}, | ||
}; | ||
|
||
const DebugContext = createContext<DebugContextProps>(initialDebugContextValue); | ||
|
||
export const useDebugContext = (): DebugContextProps => | ||
useContext(DebugContext); | ||
|
||
export default DebugContext; |
64 changes: 64 additions & 0 deletions
64
webapp/src/components/App/Singlestudy/explore/Modelization/Debug/Tree/FileTreeItem.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { Box } from "@mui/material"; | ||
import { TreeItem } from "@mui/x-tree-view"; | ||
import { TreeData, determineFileType, getFileIcon } from "../utils"; | ||
import { useDebugContext } from "../DebugContext"; | ||
|
||
interface Props { | ||
name: string; | ||
content: TreeData; | ||
path: string; | ||
} | ||
|
||
function FileTreeItem({ name, content, path }: Props) { | ||
const { onFileSelect } = useDebugContext(); | ||
const fullPath = `${path}/${name}`; | ||
const fileType = determineFileType(content); | ||
const FileIcon = getFileIcon(fileType); | ||
const isFolderEmpty = !Object.keys(content).length; | ||
|
||
//////////////////////////////////////////////////////////////// | ||
// Event handlers | ||
//////////////////////////////////////////////////////////////// | ||
|
||
const handleClick = () => { | ||
if (fileType !== "folder") { | ||
onFileSelect(fileType, fullPath); | ||
} | ||
}; | ||
|
||
//////////////////////////////////////////////////////////////// | ||
// JSX | ||
//////////////////////////////////////////////////////////////// | ||
|
||
return ( | ||
<TreeItem | ||
nodeId={fullPath} | ||
label={ | ||
<Box | ||
role="button" | ||
sx={{ | ||
display: "flex", | ||
alignItems: "center", | ||
...(isFolderEmpty && { opacity: 0.5 }), | ||
}} | ||
onClick={handleClick} | ||
> | ||
<FileIcon sx={{ width: 20, height: "auto", p: 0.2 }} /> | ||
<span style={{ marginLeft: 4 }}>{name}</span> | ||
</Box> | ||
} | ||
> | ||
{typeof content === "object" && | ||
Object.keys(content).map((childName) => ( | ||
<FileTreeItem | ||
key={childName} | ||
name={childName} | ||
content={content[childName]} | ||
path={fullPath} | ||
/> | ||
))} | ||
</TreeItem> | ||
); | ||
} | ||
|
||
export default FileTreeItem; |
Oops, something went wrong.