Skip to content

Commit

Permalink
feat(ui-debug): add export button for json and text files
Browse files Browse the repository at this point in the history
  • Loading branch information
skamril committed Sep 13, 2024
1 parent eb16e04 commit 298f883
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 94 deletions.
79 changes: 38 additions & 41 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Folder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
type TreeFolder,
type DataCompProps,
} from "../utils";
import ViewWrapper from "../../../../../common/page/ViewWrapper";
import { Fragment } from "react";
import EmptyView from "../../../../../common/page/SimpleContent";
import { useTranslation } from "react-i18next";
Expand All @@ -28,47 +27,45 @@ function Folder({
const list = Object.entries(treeData as TreeFolder);

return (
<ViewWrapper>
<List
subheader={<ListSubheader>{filename}</ListSubheader>}
sx={{
height: 1,
overflow: "auto",
}}
dense
>
{list.length > 0 ? (
list.map(([filename, data], index, arr) => {
const fileType = getFileType(data);
const Icon = getFileIcon(fileType);
const isLast = index === arr.length - 1;
<List
subheader={<ListSubheader>{filename}</ListSubheader>}
sx={{
height: 1,
overflow: "auto",
}}
dense
>
{list.length > 0 ? (
list.map(([filename, data], index, arr) => {
const fileType = getFileType(data);
const Icon = getFileIcon(fileType);
const isLast = index === arr.length - 1;

return (
<Fragment key={filename}>
<ListItemButton
onClick={() =>
setSelectedFile({
fileType,
filename,
filePath: `${filePath}/${filename}`,
treeData: data,
})
}
>
<ListItemIcon>
<Icon />
</ListItemIcon>
<ListItemText primary={filename} />
</ListItemButton>
{!isLast && <Divider variant="fullWidth" />}
</Fragment>
);
})
) : (
<EmptyView title={t("study.debug.folder.empty")} icon={FolderIcon} />
)}
</List>
</ViewWrapper>
return (
<Fragment key={filename}>
<ListItemButton
onClick={() =>
setSelectedFile({
fileType,
filename,
filePath: `${filePath}/${filename}`,
treeData: data,
})
}
>
<ListItemIcon>
<Icon />
</ListItemIcon>
<ListItemText primary={filename} />
</ListItemButton>
{!isLast && <Divider variant="fullWidth" />}
</Fragment>
);
})
) : (
<EmptyView title={t("study.debug.folder.empty")} icon={FolderIcon} />
)}
</List>
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import { useTranslation } from "react-i18next";
import EmptyView from "../../../../../common/page/SimpleContent";
import ViewWrapper from "../../../../../common/page/ViewWrapper";
import ImageIcon from "@mui/icons-material/Image";

function Image() {
const { t } = useTranslation();

return (
<ViewWrapper>
<EmptyView icon={ImageIcon} title={t("study.debug.file.image")} />
</ViewWrapper>
);
return <EmptyView icon={ImageIcon} title={t("study.debug.file.image")} />;
}

export default Image;
58 changes: 37 additions & 21 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Json.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { useTranslation } from "react-i18next";
import { useSnackbar } from "notistack";
import { Box } from "@mui/material";
import { editStudy, getStudyData } from "../../../../../../services/api/study";
import JSONEditor, { JSONEditorProps } from "../../../../../common/JSONEditor";
import usePromiseWithSnackbarError from "../../../../../../hooks/usePromiseWithSnackbarError";
import UsePromiseCond from "../../../../../common/utils/UsePromiseCond";
import ViewWrapper from "../../../../../common/page/ViewWrapper";
import type { DataCompProps } from "../utils";
import DownloadButton from "../../../../../common/buttons/DownloadButton";
import { downloadFile } from "../../../../../../utils/fileUtils";
import { useEffect, useState } from "react";
import { Flex, Menubar } from "./styles";

function Json({ filePath, studyId }: DataCompProps) {
function Json({ filePath, filename, studyId }: DataCompProps) {
const [t] = useTranslation();
const { enqueueSnackbar } = useSnackbar();
const [currentJson, setCurrentJson] = useState<JSONEditorProps["json"]>();

const res = usePromiseWithSnackbarError(
() => getStudyData(studyId, filePath, -1),
Expand All @@ -20,6 +23,10 @@ function Json({ filePath, studyId }: DataCompProps) {
},
);

useEffect(() => {
setCurrentJson(res.data);
}, [res.data]);

////////////////////////////////////////////////////////////////
// Event Handlers
////////////////////////////////////////////////////////////////
Expand All @@ -28,34 +35,43 @@ function Json({ filePath, studyId }: DataCompProps) {
return editStudy(json, studyId, filePath);
};

const handleSaveSuccessful = () => {
const handleSaveSuccessful: JSONEditorProps["onSaveSuccessful"] = (json) => {
setCurrentJson(json);

enqueueSnackbar(t("studies.success.saveData"), {
variant: "success",
});
};

const handleDownload = () => {
if (currentJson !== undefined) {
downloadFile(JSON.stringify(currentJson, null, 2), `${filename}.json`);
}
};

////////////////////////////////////////////////////////////////
// JSX
////////////////////////////////////////////////////////////////

return (
<ViewWrapper>
<UsePromiseCond
response={res}
ifResolved={(json) => (
<Box sx={{ overflow: "auto" }}>
<JSONEditor
json={json}
modes={["tree", "code"]}
enableSort={false}
enableTransform={false}
onSave={handleSave}
onSaveSuccessful={handleSaveSuccessful}
/>
</Box>
)}
/>
</ViewWrapper>
<UsePromiseCond
response={res}
ifResolved={(json) => (
<Flex>
<Menubar>
<DownloadButton onClick={handleDownload} />
</Menubar>
<JSONEditor
json={json}
modes={["tree", "code"]}
enableSort={false}
enableTransform={false}
onSave={handleSave}
onSaveSuccessful={handleSaveSuccessful}
/>
</Flex>
)}
/>
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import { MatrixStats } from "../../../../../../common/types";
import MatrixInput from "../../../../../common/MatrixInput";
import ViewWrapper from "../../../../../common/page/ViewWrapper";
import type { DataCompProps } from "../utils";

function Matrix({ studyId, filename, filePath, enableImport }: DataCompProps) {
return (
<ViewWrapper>
<MatrixInput
title={filename}
study={studyId}
url={filePath}
computStats={MatrixStats.NOCOL}
disableImport={!enableImport}
/>
</ViewWrapper>
<MatrixInput
title={filename}
study={studyId}
url={filePath}
computStats={MatrixStats.NOCOL}
disableImport={!enableImport}
/>
);
}

Expand Down
35 changes: 25 additions & 10 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Box, useTheme } from "@mui/material";
import { getStudyData } from "../../../../../../services/api/study";
import usePromiseWithSnackbarError from "../../../../../../hooks/usePromiseWithSnackbarError";
import UsePromiseCond from "../../../../../common/utils/UsePromiseCond";
import ViewWrapper from "../../../../../common/page/ViewWrapper";
import {
Light as SyntaxHighlighter,
type SyntaxHighlighterProps,
Expand All @@ -14,6 +13,9 @@ import ini from "react-syntax-highlighter/dist/esm/languages/hljs/ini";
import properties from "react-syntax-highlighter/dist/esm/languages/hljs/properties";
import { atomOneDark } from "react-syntax-highlighter/dist/esm/styles/hljs";
import type { DataCompProps } from "../utils";
import DownloadButton from "../../../../../common/buttons/DownloadButton";
import { downloadFile } from "../../../../../../utils/fileUtils";
import { Flex, Menubar } from "./styles";

SyntaxHighlighter.registerLanguage("xml", xml);
SyntaxHighlighter.registerLanguage("plaintext", plaintext);
Expand Down Expand Up @@ -46,7 +48,7 @@ function getSyntaxProps(data: string | string[]): SyntaxHighlighterProps {
};
}

function Text({ studyId, filePath }: DataCompProps) {
function Text({ studyId, filePath, filename }: DataCompProps) {
const { t } = useTranslation();
const theme = useTheme();

Expand All @@ -58,15 +60,28 @@ function Text({ studyId, filePath }: DataCompProps) {
},
);

////////////////////////////////////////////////////////////////
// Event Handlers
////////////////////////////////////////////////////////////////

const handleDownload = () => {
if (res.data) {
downloadFile(res.data, `${filename}.txt`);
}
};

////////////////////////////////////////////////////////////////
// JSX
////////////////////////////////////////////////////////////////

return (
<ViewWrapper>
<UsePromiseCond
response={res}
ifResolved={(data) => (
<UsePromiseCond
response={res}
ifResolved={(text) => (
<Flex>
<Menubar>
<DownloadButton onClick={handleDownload} />
</Menubar>
<Box sx={{ height: 1, display: "flex", flexDirection: "column" }}>
<SyntaxHighlighter
style={atomOneDark}
Expand All @@ -81,12 +96,12 @@ function Text({ studyId, filePath }: DataCompProps) {
borderRadius: theme.shape.borderRadius,
fontSize: theme.typography.body2.fontSize,
}}
{...getSyntaxProps(data)}
{...getSyntaxProps(text)}
/>
</Box>
)}
/>
</ViewWrapper>
</Flex>
)}
/>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Matrix from "./Matrix";
import Folder from "./Folder";
import type { FileInfo, FileType } from "../utils";
import type { DataCompProps } from "../utils";
import ViewWrapper from "../../../../../common/page/ViewWrapper";

interface Props extends FileInfo {
studyId: string;
Expand All @@ -30,12 +31,14 @@ function Data({ studyId, setSelectedFile, ...fileInfo }: Props) {
const DataViewer = componentByFileType[fileType];

return (
<DataViewer
{...fileInfo}
studyId={studyId}
enableImport={enableImport}
setSelectedFile={setSelectedFile}
/>
<ViewWrapper>
<DataViewer
{...fileInfo}
studyId={studyId}
enableImport={enableImport}
setSelectedFile={setSelectedFile}
/>
</ViewWrapper>
);
}

Expand Down
13 changes: 13 additions & 0 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { styled } from "@mui/material";

export const Flex = styled("div")(({ theme }) => ({
height: "100%",
display: "flex",
flexDirection: "column",
gap: theme.spacing(1),
}));

export const Menubar = styled("div")({
display: "flex",
justifyContent: "flex-end",
});

0 comments on commit 298f883

Please sign in to comment.