Skip to content

Commit

Permalink
fix(ui-debug): prevent empty text files display
Browse files Browse the repository at this point in the history
  • Loading branch information
hdinia committed Dec 4, 2024
1 parent 645dc44 commit cc6b26c
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 49 deletions.
1 change: 0 additions & 1 deletion webapp/public/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,6 @@
"study.district": "District",
"study.bindingconstraints": "Binding Constraints",
"study.debug": "Debug",
"study.debug.file.image": "Image file",
"study.debug.file.unsupported": "Unsupported file type",
"study.debug.file.deleteConfirm.title": "Delete File?",
"study.debug.file.deleteConfirm.message": "Are you sure you want to delete the file?",
Expand Down
1 change: 0 additions & 1 deletion webapp/public/locales/fr/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,6 @@
"study.district": "District",
"study.bindingconstraints": "Contraintes Couplantes",
"study.debug": "Debug",
"study.debug.file.image": "Fichier image",
"study.debug.folder.empty": "Le dossier est vide",
"study.debug.file.unsupported": "Type de fichier non supporté",
"study.debug.file.deleteConfirm.title": "Supprimer le fichier ?",
Expand Down
53 changes: 36 additions & 17 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import DownloadButton from "../../../../../common/buttons/DownloadButton";
import { downloadFile } from "../../../../../../utils/fileUtils";
import { Filename, Flex, Menubar } from "./styles";
import UploadFileButton from "../../../../../common/buttons/UploadFileButton";
import EmptyView from "@/components/common/page/SimpleContent";
import GridOffIcon from "@mui/icons-material/GridOff";

SyntaxHighlighter.registerLanguage("xml", xml);
SyntaxHighlighter.registerLanguage("plaintext", plaintext);
Expand All @@ -42,6 +44,16 @@ const logsRegex = /^(\[[^\]]*\]){3}/;
// Ex: "EXP : 0"
const propertiesRegex = /^[^:]+ : [^:]+/;

function isEmptyContent(text: string | string[]): boolean {
if (Array.isArray(text)) {
return (
text.length === 0 ||
text.every((line) => typeof line === "string" && !line.trim())
);
}
return typeof text !== "string" || !text.trim();
}

function getSyntaxProps(data: string | string[]): SyntaxHighlighterProps {
const isArray = Array.isArray(data);
const text = isArray ? data.join("\n") : data;
Expand Down Expand Up @@ -111,24 +123,31 @@ function Text({ studyId, filePath, filename, canEdit }: DataCompProps) {
onUploadSuccessful={handleUploadSuccessful}
/>
)}
<DownloadButton onClick={handleDownload} />
</Menubar>
<Box sx={{ overflow: "auto" }}>
<SyntaxHighlighter
style={atomOneDark}
lineNumberStyle={{
opacity: 0.5,
paddingRight: theme.spacing(3),
}}
customStyle={{
margin: 0,
padding: theme.spacing(2),
borderRadius: theme.shape.borderRadius,
fontSize: theme.typography.body2.fontSize,
}}
{...getSyntaxProps(text)}
<DownloadButton
onClick={handleDownload}
disabled={isEmptyContent(text)}
/>
</Box>
</Menubar>
{isEmptyContent(text) ? (
<EmptyView icon={GridOffIcon} title={t("study.results.noData")} />
) : (
<Box sx={{ overflow: "auto" }}>
<SyntaxHighlighter
style={atomOneDark}
lineNumberStyle={{
opacity: 0.5,
paddingRight: theme.spacing(3),
}}
customStyle={{
margin: 0,
padding: theme.spacing(2),
borderRadius: theme.shape.borderRadius,
fontSize: theme.typography.body2.fontSize,
}}
{...getSyntaxProps(text)}
/>
</Box>
)}
</Flex>
)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@ function Unsupported({ studyId, filePath, filename }: DataCompProps) {

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

Expand All @@ -62,7 +59,6 @@ function Unsupported({ studyId, filePath, filename }: DataCompProps) {
<UploadFileButton
studyId={studyId}
path={filePath}
accept={{ "text/plain": [".txt"] }}
onUploadSuccessful={handleUploadSuccessful}
/>
<DownloadButton onClick={handleDownload} />
Expand Down
45 changes: 20 additions & 25 deletions webapp/src/components/App/Singlestudy/explore/Debug/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,17 @@ export interface DataCompProps extends FileInfo {
}

////////////////////////////////////////////////////////////////
// File Info
// Utils
////////////////////////////////////////////////////////////////

const URL_SCHEMES = {
MATRIX: ["matrix://", "matrixfile://"],
JSON: ["json://"],
FILE: ["file://"],
} as const;

const SUPPORTED_EXTENSIONS = [".txt", ".log", ".csv", ".tsv", ".ini"] as const;

// Maps file types to their corresponding icon components.
const iconByFileType: Record<FileType, SvgIconComponent> = {
matrix: DatasetIcon,
Expand Down Expand Up @@ -88,45 +96,32 @@ export function getFileType(treeData: TreeData): FileType {
}

if (typeof treeData === "string") {
// Handle matrix files
if (
treeData.startsWith("matrix://") ||
treeData.startsWith("matrixfile://")
) {
if (URL_SCHEMES.MATRIX.some((scheme) => treeData.startsWith(scheme))) {
return "matrix";
}

// Handle files displayed as JSON by the API even though they are .ini files in the filesystem.
// The json:// prefix or .json extension indicates the content should be viewed as JSON.
if (treeData.startsWith("json://") || treeData.endsWith(".json")) {
if (
URL_SCHEMES.JSON.some((scheme) => treeData.startsWith(scheme)) ||
treeData.endsWith(".json")
) {
return "json";
}

// Handle regular files with file:// prefix
// All files except matrices and json-formatted content use this prefix
// We filter to only allow extensions that can be properly displayed (.txt, .log, .csv, .tsv, .ini)
// Other extensions (like .RDS or .xlsx) are marked as unsupported since they can't be shown in the UI
if (treeData.startsWith("file://")) {
const supportedTextExtensions = [".txt", ".log", ".csv", ".tsv", ".ini"];

// Check if the file ends with any of the supported extensions
if (supportedTextExtensions.some((ext) => treeData.endsWith(ext))) {
return "text";
}

// Any other extension with file:// prefix is unsupported
return "unsupported";
if (
URL_SCHEMES.FILE.some((scheme) => treeData.startsWith(scheme)) &&
SUPPORTED_EXTENSIONS.some((ext) => treeData.endsWith(ext))
) {
return "text";
}
}

// Default to text for any other string content
return "text";
return "unsupported";
}

////////////////////////////////////////////////////////////////
// Rights
////////////////////////////////////////////////////////////////

/**
* Checks if a study's file can be edited.
*
Expand Down

0 comments on commit cc6b26c

Please sign in to comment.