Skip to content

Commit

Permalink
feat(ui-debug): add import and export buttons on data views
Browse files Browse the repository at this point in the history
* add `path` URL parameter
* display filename
  • Loading branch information
skamril committed Sep 16, 2024
1 parent 5ed44cb commit 55263f3
Show file tree
Hide file tree
Showing 10 changed files with 249 additions and 94 deletions.
143 changes: 98 additions & 45 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Folder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,56 +16,109 @@ import {
import { Fragment } from "react";
import EmptyView from "../../../../../common/page/SimpleContent";
import { useTranslation } from "react-i18next";
import { Filename, Menubar } from "./styles";
import UploadFileButton from "../../../../../common/buttons/UploadFileButton";
import ConfirmationDialog from "../../../../../common/dialogs/ConfirmationDialog";
import useConfirm from "../../../../../../hooks/useConfirm";

function Folder(props: DataCompProps) {
const {
filename,
filePath,
treeData,
enableImport,
setSelectedFile,
reloadTreeData,
studyId,
} = props;

function Folder({
filename,
filePath,
treeData,
setSelectedFile,
}: DataCompProps) {
const { t } = useTranslation();
const list = Object.entries(treeData as TreeFolder);
const replaceFile = useConfirm();
const treeFolder = treeData as TreeFolder;
const list = Object.entries(treeFolder);

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

const handleValidateUpload = (file: File) => {
if (treeFolder[file.name]) {
return replaceFile.showConfirm();
}
};

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

return (
<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>
<Menubar>
<Filename>{filename}</Filename>
{enableImport && (
<UploadFileButton
studyId={studyId}
path={(file) => `${filePath}/${file.name}`}
onUploadSuccessful={reloadTreeData}
validate={handleValidateUpload}
/>
)}
</Menubar>
</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>
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>
<ConfirmationDialog
title="Replace File?"
confirmButtonText="Replace"
cancelButtonText="Cancel"
maxWidth="xs"
open={replaceFile.isPending}
onConfirm={replaceFile.yes}
onCancel={replaceFile.no}
>
Another file with the same name already exists. Replacing it will
overwrite its content.
</ConfirmationDialog>
</>
);
}

Expand Down
13 changes: 11 additions & 2 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { useTranslation } from "react-i18next";
import EmptyView from "../../../../../common/page/SimpleContent";
import ImageIcon from "@mui/icons-material/Image";
import { Filename, Flex, Menubar } from "./styles";
import type { DataCompProps } from "../utils";

function Image() {
function Image({ filename }: DataCompProps) {
const { t } = useTranslation();

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

export default Image;
23 changes: 20 additions & 3 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Json.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ 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";
import { Filename, Flex, Menubar } from "./styles";
import UploadFileButton from "../../../../../common/buttons/UploadFileButton";

function Json({ filePath, filename, studyId }: DataCompProps) {
function Json({ filePath, filename, studyId, enableImport }: DataCompProps) {
const [t] = useTranslation();
const { enqueueSnackbar } = useSnackbar();
const [currentJson, setCurrentJson] = useState<JSONEditorProps["json"]>();
Expand Down Expand Up @@ -45,10 +46,17 @@ function Json({ filePath, filename, studyId }: DataCompProps) {

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

const handleUploadSuccessful = () => {
res.reload();
};

////////////////////////////////////////////////////////////////
// JSX
////////////////////////////////////////////////////////////////
Expand All @@ -59,6 +67,15 @@ function Json({ filePath, filename, studyId }: DataCompProps) {
ifResolved={(json) => (
<Flex>
<Menubar>
<Filename>{filename}</Filename>
{enableImport && (
<UploadFileButton
studyId={studyId}
path={filePath}
accept={{ "application/json": [".json"] }}
onUploadSuccessful={handleUploadSuccessful}
/>
)}
<DownloadButton onClick={handleDownload} />
</Menubar>
<JSONEditor
Expand Down
23 changes: 20 additions & 3 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ 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";
import { Filename, Flex, Menubar } from "./styles";
import UploadFileButton from "../../../../../common/buttons/UploadFileButton";

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

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

Expand All @@ -66,10 +67,17 @@ function Text({ studyId, filePath, filename }: DataCompProps) {

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

const handleUploadSuccessful = () => {
res.reload();
};

////////////////////////////////////////////////////////////////
// JSX
////////////////////////////////////////////////////////////////
Expand All @@ -80,6 +88,15 @@ function Text({ studyId, filePath, filename }: DataCompProps) {
ifResolved={(text) => (
<Flex>
<Menubar>
<Filename>{filename}</Filename>
{enableImport && (
<UploadFileButton
studyId={studyId}
path={filePath}
accept={{ "text/plain": [".txt"] }}
onUploadSuccessful={handleUploadSuccessful}
/>
)}
<DownloadButton onClick={handleDownload} />
</Menubar>
<Box sx={{ height: 1, display: "flex", flexDirection: "column" }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import ViewWrapper from "../../../../../common/page/ViewWrapper";
interface Props extends FileInfo {
studyId: string;
setSelectedFile: (file: FileInfo) => void;
reloadTreeData: () => void;
}

type DataComponent = React.ComponentType<DataCompProps>;
Expand All @@ -22,13 +23,15 @@ const componentByFileType: Record<FileType, DataComponent> = {
folder: Folder,
} as const;

function Data({ studyId, setSelectedFile, ...fileInfo }: Props) {
function Data(props: Props) {
const { studyId, setSelectedFile, reloadTreeData, ...fileInfo } = props;
const { fileType, filePath } = fileInfo;
const DataViewer = componentByFileType[fileType];

const enableImport =
(filePath === "user" || filePath.startsWith("user/")) &&
// To remove when Xpansion tool configuration will be moved to "input/expansion" directory
!(filePath === "user/expansion" || filePath.startsWith("user/expansion/"));
const DataViewer = componentByFileType[fileType];

return (
<ViewWrapper>
Expand All @@ -37,6 +40,7 @@ function Data({ studyId, setSelectedFile, ...fileInfo }: Props) {
studyId={studyId}
enableImport={enableImport}
setSelectedFile={setSelectedFile}
reloadTreeData={reloadTreeData}
/>
</ViewWrapper>
);
Expand Down
13 changes: 0 additions & 13 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/styles.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
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")(({ theme }) => ({
display: "flex",
justifyContent: "flex-end",
alignItems: "center",
gap: theme.spacing(1),
}));

export const Filename = styled((props: { children?: string }) => (
<div title={props.children} {...props} />
))({
flex: 1,
overflow: "hidden",
textOverflow: "ellipsis",
});
Loading

0 comments on commit 55263f3

Please sign in to comment.