From ab5b2bd1b4224765cb6ca0484844f4a475d70a0e Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Thu, 11 Apr 2024 00:17:17 -0500 Subject: [PATCH 1/4] refactor the stacked list to include info tooltip --- .../components/datasets/DatasetDetails.tsx | 29 ++++++++--- frontend/src/components/files/FileDetails.tsx | 49 ++++++++++++++----- frontend/src/components/util/StackedList.tsx | 32 ++++++------ 3 files changed, 76 insertions(+), 34 deletions(-) diff --git a/frontend/src/components/datasets/DatasetDetails.tsx b/frontend/src/components/datasets/DatasetDetails.tsx index 206d573d3..ac21bf8fa 100644 --- a/frontend/src/components/datasets/DatasetDetails.tsx +++ b/frontend/src/components/datasets/DatasetDetails.tsx @@ -13,15 +13,28 @@ export function DatasetDetails(props: DatasetAboutProps) { const { myRole } = props; const { id, created, modified, creator, status, downloads } = props.details; - const details = new Map(); - details.set("Owner", `${creator.first_name} ${creator.last_name}`); - details.set("Created on", parseDate(created)); - details.set("Updated on", parseDate(modified)); - details.set("Status", status); - details.set("Dataset id", id); - details.set("Downloads", downloads); + const details = new Map< + string, + { value: string | undefined; info?: string } + >(); + details.set("Owner", { value: `${creator.first_name} ${creator.last_name}` }); + details.set("Created on", { + value: parseDate(created), + info: "Date and time of dataset creation", + }); + details.set("Updated on", { + value: parseDate(modified), + info: "Date and time of dataset modification", + }); + details.set("Status", { value: status }); + details.set("Dataset id", { value: id }); + details.set("Downloads", { value: downloads, info: "Number of downloads" }); - if (myRole) details.set("My Role", myRole ? myRole.toUpperCase() : ""); + if (myRole) + details.set("My Role", { + value: myRole ? myRole.toUpperCase() : "", + info: "Your role in the dataset", + }); return ( diff --git a/frontend/src/components/files/FileDetails.tsx b/frontend/src/components/files/FileDetails.tsx index b92181cd5..1b728bdf7 100644 --- a/frontend/src/components/files/FileDetails.tsx +++ b/frontend/src/components/files/FileDetails.tsx @@ -23,35 +23,60 @@ export function FileDetails(props: FileAboutProps) { storage_type, } = props.fileSummary; - const details = new Map(); - details.set("Size", prettyBytes(bytes)); - details.set("Content type", content_type.content_type); - details.set("Updated on", parseDate(created)); - details.set("Uploaded as", name); + const details = new Map< + string, + { value: string | undefined; info?: string } + >(); + details.set("Size", { value: prettyBytes(bytes) }); + details.set("Content type", { value: content_type.content_type }); + details.set("Updated on", { + value: parseDate(created), + info: "Latest date and time of the file being updated", + }); + details.set("Uploaded as", { value: name, info: "Name of the file" }); details.set("Uploaded by", `${creator.first_name} ${creator.last_name}`); switch (storage_type) { case "minio": { - details.set("Storage location", "Database"); + details.set("Storage location", { + value: "Database", + info: "Data stored in the Minio instance", + }); break; } case "local": { - details.set("Storage location", "Local file system"); + details.set("Storage location", { + value: "Local file system", + info: "Data stored in the local file system", + }); break; } case "remote": { - details.set("Storage location", "Remote URL"); + details.set("Storage location", { + value: "Remote URL", + info: "Data stored in a remote location", + }); break; } default: { - details.set("Storage location", `${storage_type}`); + details.set("Storage location", { + value: `${storage_type}`, + info: `Data stored in ${storage_type}`, + }); break; } } - details.set("File id", id); - details.set("Downloads", downloads); + details.set("File id", { value: id }); + details.set("Downloads", { + value: downloads.toString(), + info: "Number of downloads", + }); - if (myRole) details.set("My Role", myRole ? myRole.toUpperCase() : ""); + if (myRole) + details.set("My Role", { + value: myRole ? myRole.toUpperCase() : "", + info: "Your role in the file", + }); return ( diff --git a/frontend/src/components/util/StackedList.tsx b/frontend/src/components/util/StackedList.tsx index c00330342..bcb96286e 100644 --- a/frontend/src/components/util/StackedList.tsx +++ b/frontend/src/components/util/StackedList.tsx @@ -1,25 +1,29 @@ import React from "react"; -import { Box, Stack, Typography } from "@mui/material"; +import { Box, Stack, Tooltip, Typography } from "@mui/material"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; type StackedListProps = { - keyValues: Map; + keyValues: Map; }; export function StackedList(props: StackedListProps) { const { keyValues } = props; - const entries: Array = []; - // forEach expects value first and then key - keyValues.forEach((value, key) => { - entries.push( - - {value} - - {key} - - - ); - }); + const entries = Array.from(keyValues, ([key, { value, info }]) => ( + + {value} + + + + {key} + + {info && ( + + )} + + + + )); return {entries}; } From bf8ac5a3ed11988d4de50aa95a660c5ce45682ec Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Fri, 12 Apr 2024 11:44:08 -0500 Subject: [PATCH 2/4] add info option to all details --- .../components/datasets/DatasetDetails.tsx | 9 +- frontend/src/components/files/FileDetails.tsx | 6 +- frontend/src/components/files/FileHistory.tsx | 36 +++++--- .../listeners/ListenerInfoDetails.tsx | 86 ++++++++++++------- .../VisualizationDataDetail.tsx | 41 +++++---- .../VisualizationParamDetail.tsx | 7 +- 6 files changed, 117 insertions(+), 68 deletions(-) diff --git a/frontend/src/components/datasets/DatasetDetails.tsx b/frontend/src/components/datasets/DatasetDetails.tsx index ac21bf8fa..42ae00933 100644 --- a/frontend/src/components/datasets/DatasetDetails.tsx +++ b/frontend/src/components/datasets/DatasetDetails.tsx @@ -2,7 +2,7 @@ import React from "react"; import { Box, Typography } from "@mui/material"; import { parseDate } from "../../utils/common"; import { StackedList } from "../util/StackedList"; -import { Dataset } from "../../types/data"; +import { DatasetOut as Dataset } from "../../openapi/v2"; type DatasetAboutProps = { myRole?: string; @@ -26,9 +26,12 @@ export function DatasetDetails(props: DatasetAboutProps) { value: parseDate(modified), info: "Date and time of dataset modification", }); - details.set("Status", { value: status }); + details.set("Status", { value: status, info: "Public or private dataset" }); details.set("Dataset id", { value: id }); - details.set("Downloads", { value: downloads, info: "Number of downloads" }); + details.set("Downloads", { + value: downloads, + info: "Number of downloads", + }); if (myRole) details.set("My Role", { diff --git a/frontend/src/components/files/FileDetails.tsx b/frontend/src/components/files/FileDetails.tsx index 1b728bdf7..f808304b1 100644 --- a/frontend/src/components/files/FileDetails.tsx +++ b/frontend/src/components/files/FileDetails.tsx @@ -34,7 +34,9 @@ export function FileDetails(props: FileAboutProps) { info: "Latest date and time of the file being updated", }); details.set("Uploaded as", { value: name, info: "Name of the file" }); - details.set("Uploaded by", `${creator.first_name} ${creator.last_name}`); + details.set("Uploaded by", { + value: `${creator.first_name} ${creator.last_name}`, + }); switch (storage_type) { case "minio": { @@ -68,7 +70,7 @@ export function FileDetails(props: FileAboutProps) { } details.set("File id", { value: id }); details.set("Downloads", { - value: downloads.toString(), + value: downloads, info: "Number of downloads", }); diff --git a/frontend/src/components/files/FileHistory.tsx b/frontend/src/components/files/FileHistory.tsx index 9d93291b3..dbcf98788 100644 --- a/frontend/src/components/files/FileHistory.tsx +++ b/frontend/src/components/files/FileHistory.tsx @@ -39,25 +39,33 @@ export function FileHistory(props: FileHistoryAboutProps) { } }, [selectedVersionNum]); - const details = new Map(); + const details = new Map< + string, + { value: string | undefined; info?: string } + >(); + if ( selectedFileVersionDetail !== null && selectedFileVersionDetail !== undefined ) { - details.set( - "Size", - selectedFileVersionDetail.bytes + details.set("Size", { + value: selectedFileVersionDetail.bytes ? prettyBytes(selectedFileVersionDetail.bytes) - : "NA" - ); - details.set("Content type", contentType ?? "NA"); - details.set("Updated on", parseDate(selectedFileVersionDetail.created)); - details.set("Uploaded as", name ?? "NA"); - details.set( - "Uploaded by", - `${selectedFileVersionDetail.creator.first_name} ${selectedFileVersionDetail.creator.last_name}` - ); - details.set("File id", selectedFileVersionDetail.file_id); + : "NA", + }); + details.set("Content type", { value: contentType ?? "NA" }); + details.set("Updated on", { + value: parseDate(selectedFileVersionDetail.created), + info: "Latest date and time of the file being updated", + }); + details.set("Uploaded as", { + value: name ?? "NA", + info: "Name of the file", + }); + details.set("Uploaded by", { + value: `${selectedFileVersionDetail.creator.first_name} ${selectedFileVersionDetail.creator.last_name}`, + }); + details.set("File id", { value: selectedFileVersionDetail.file_id }); } return ( diff --git a/frontend/src/components/listeners/ListenerInfoDetails.tsx b/frontend/src/components/listeners/ListenerInfoDetails.tsx index 762f4bf31..3664bfd35 100644 --- a/frontend/src/components/listeners/ListenerInfoDetails.tsx +++ b/frontend/src/components/listeners/ListenerInfoDetails.tsx @@ -17,66 +17,83 @@ export function ListenerInfoDetails(props: ListenerAboutProps) { defaultExpanded ? defaultExpanded : false ); - const handleChange = - (panel: string) => (event: React.SyntheticEvent, isExpanded: boolean) => { - setExpanded(isExpanded ? panel : false); - }; - - const details = new Map(); - details.set("Last Alive", parseDate(listener.lastAlive ?? "")); - details.set("Last Modified", parseDate(listener.modified ?? "")); + const details = new Map< + string, + { value: string | undefined; info?: string } + >(); + + details.set("Last Alive", { + value: parseDate(listener.lastAlive ?? ""), + info: "Last time the listener was up" + " running", + }); + details.set("Last Modified", { + value: parseDate(listener.modified ?? ""), + info: "Last time the listener was modified", + }); if (listener.properties) { - details.set("Maturity", listener.properties.maturity ?? ""); + details.set("Maturity", { + value: listener.properties.maturity ?? "", + info: "Stage of the listener. e.g. alpha, beta, stable", + }); if ( listener.properties.contributors && listener.properties.contributors.length > 0 ) { - details.set("Contributors", listener.properties.contributors.join(", ")); + details.set("Contributors", { + value: listener.properties.contributors.join(", "), + }); } if ( listener.properties.external_services && listener.properties.external_services.length > 0 ) { - details.set( - "External Services", - listener.properties.external_services.join(", ") - ); + details.set("External Services", { + value: listener.properties.external_services.join(", "), + info: "External services used by the listener", + }); } if ( listener.properties.categories && listener.properties.categories.length > 0 ) { - details.set("Categories", listener.properties.categories.join(", ")); + details.set("Categories", { + value: listener.properties.categories.join(", "), + info: "Categories of the" + " listener", + }); } if (listener.properties.bibtex && listener.properties.bibtex.length > 0) { - details.set( - "Bibtex", - listener.properties.bibtex.join(", ") !== "" - ? listener.properties.bibtex.join(", ") - : "Not Available" - ); + details.set("Bibtex", { + value: + listener.properties.bibtex.join(", ") !== "" + ? listener.properties.bibtex.join(", ") + : "Not Available", + info: "Bibtex format of citation of the listener", + }); } if ( listener.properties.default_labels && listener.properties.default_labels.length > 0 ) { - details.set( - "Default Labels", - listener.properties.default_labels.join(", ") - ); + details.set("Default Labels", { + value: listener.properties.default_labels.join(", "), + info: "Labels of the listener", + }); } if ( listener.properties.libraries && listener.properties.libraries.length > 0 ) { - details.set("Libraries", listener.properties.libraries.join(", ")); + details.set("Libraries", { + value: listener.properties.libraries.join(", "), + info: "Libraries used by the listener", + }); } if ( @@ -84,10 +101,9 @@ export function ListenerInfoDetails(props: ListenerAboutProps) { Object.keys(listener.properties.process).length > 0 ) { Object.keys(listener.properties.process).forEach((key) => { - details.set( - `Process ${key} by`, - listener.properties.process[key].join(", ") - ); + details.set(`Process ${key} by`, { + value: listener.properties.process[key].join(", "), + }); }); } @@ -97,7 +113,10 @@ export function ListenerInfoDetails(props: ListenerAboutProps) { ) { listener.properties.contexts.forEach((context) => { Object.keys(context).forEach((key) => { - details.set(`Context: ${key}`, context[key]); + details.set(`Context: ${key}`, { + value: context[key], + info: "Context of the listener", + }); }); }); } @@ -108,7 +127,10 @@ export function ListenerInfoDetails(props: ListenerAboutProps) { ) { listener.properties.repository.forEach((repo) => { Object.keys(repo).forEach((key) => { - details.set(key, repo[key] !== "" ? repo[key] : "Not Available"); + details.set(key, { + value: repo[key] !== "" ? repo[key] : "Not Available", + info: "Code repository of the listener", + }); }); }); } diff --git a/frontend/src/components/visualizations/VisualizationDataDetail.tsx b/frontend/src/components/visualizations/VisualizationDataDetail.tsx index e0752e2df..870b32447 100644 --- a/frontend/src/components/visualizations/VisualizationDataDetail.tsx +++ b/frontend/src/components/visualizations/VisualizationDataDetail.tsx @@ -12,22 +12,33 @@ type FileAboutProps = { export function VisualizationDataDetail(props: FileAboutProps) { const { visualizationDataItem } = props; - const details = new Map(); - details.set("Size", prettyBytes(visualizationDataItem.bytes ?? 0)); - details.set( - "Content type", - visualizationDataItem.content_type + const details = new Map< + string, + { value: string | undefined; info?: string } + >(); + + details.set("Size", { value: prettyBytes(visualizationDataItem.bytes ?? 0) }); + details.set("Content type", { + value: visualizationDataItem.content_type ? visualizationDataItem.content_type.content_type - : "NA" - ); - details.set("Updated on", parseDate(visualizationDataItem.created)); - details.set("Uploaded as", visualizationDataItem.name); - details.set( - "Uploaded by", - `${visualizationDataItem.creator.first_name} ${visualizationDataItem.creator.last_name}` - ); - details.set("Visualization id", visualizationDataItem.id); - details.set("Descriptions", visualizationDataItem.description); + : "NA", + }); + details.set("Updated on", { + value: parseDate(visualizationDataItem.created), + info: "Latest date and time of the file being updated", + }); + details.set("Uploaded as", { + value: visualizationDataItem.name, + info: "Name of the file", + }); + details.set("Uploaded by", { + value: `${visualizationDataItem.creator.first_name} ${visualizationDataItem.creator.last_name}`, + }); + details.set("Visualization id", { value: visualizationDataItem.id }); + details.set("Descriptions", { + value: visualizationDataItem.description, + info: "Description of the visualization", + }); return ( <> diff --git a/frontend/src/components/visualizations/VisualizationParamDetail.tsx b/frontend/src/components/visualizations/VisualizationParamDetail.tsx index 18311838c..e278de46a 100644 --- a/frontend/src/components/visualizations/VisualizationParamDetail.tsx +++ b/frontend/src/components/visualizations/VisualizationParamDetail.tsx @@ -10,10 +10,13 @@ type FileAboutProps = { export function VisualizationParamDetail(props: FileAboutProps) { const { visConfigEntry } = props; - const details = new Map(); + const details = new Map< + string, + { value: string | undefined; info?: string } + >(); for (const key in visConfigEntry.parameters) { - details.set(key, visConfigEntry.parameters[key]); + details.set(key, { value: visConfigEntry.parameters[key] }); } return ( From 68fe4c2a7c8140632e01c12634cafa3e216aa805 Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Fri, 12 Apr 2024 11:50:59 -0500 Subject: [PATCH 3/4] tweak a few wording --- frontend/src/components/datasets/DatasetDetails.tsx | 2 +- frontend/src/components/files/FileDetails.tsx | 2 +- .../src/components/visualizations/VisualizationDataDetail.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/datasets/DatasetDetails.tsx b/frontend/src/components/datasets/DatasetDetails.tsx index 42ae00933..c0110c88b 100644 --- a/frontend/src/components/datasets/DatasetDetails.tsx +++ b/frontend/src/components/datasets/DatasetDetails.tsx @@ -36,7 +36,7 @@ export function DatasetDetails(props: DatasetAboutProps) { if (myRole) details.set("My Role", { value: myRole ? myRole.toUpperCase() : "", - info: "Your role in the dataset", + info: "Your role on the dataset. E.g. Owner, Editor, Uploader, Viewer.", }); return ( diff --git a/frontend/src/components/files/FileDetails.tsx b/frontend/src/components/files/FileDetails.tsx index f808304b1..38df7216a 100644 --- a/frontend/src/components/files/FileDetails.tsx +++ b/frontend/src/components/files/FileDetails.tsx @@ -77,7 +77,7 @@ export function FileDetails(props: FileAboutProps) { if (myRole) details.set("My Role", { value: myRole ? myRole.toUpperCase() : "", - info: "Your role in the file", + info: "Your role on the file. E.g. Owner, Editor, Uploader, Viewer.", }); return ( diff --git a/frontend/src/components/visualizations/VisualizationDataDetail.tsx b/frontend/src/components/visualizations/VisualizationDataDetail.tsx index 870b32447..c4ccf33a5 100644 --- a/frontend/src/components/visualizations/VisualizationDataDetail.tsx +++ b/frontend/src/components/visualizations/VisualizationDataDetail.tsx @@ -29,7 +29,7 @@ export function VisualizationDataDetail(props: FileAboutProps) { }); details.set("Uploaded as", { value: visualizationDataItem.name, - info: "Name of the file", + info: "Name of the visualization extractor", }); details.set("Uploaded by", { value: `${visualizationDataItem.creator.first_name} ${visualizationDataItem.creator.last_name}`, From af1ac5b9b7ca85648df6b940fd4ea7c37bcf1be0 Mon Sep 17 00:00:00 2001 From: Luigi Marini Date: Fri, 12 Apr 2024 16:33:29 -0500 Subject: [PATCH 4/4] Simplified details keys. --- .../src/components/datasets/DatasetDetails.tsx | 8 ++++---- frontend/src/components/files/FileDetails.tsx | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/frontend/src/components/datasets/DatasetDetails.tsx b/frontend/src/components/datasets/DatasetDetails.tsx index c0110c88b..932fbd673 100644 --- a/frontend/src/components/datasets/DatasetDetails.tsx +++ b/frontend/src/components/datasets/DatasetDetails.tsx @@ -18,23 +18,23 @@ export function DatasetDetails(props: DatasetAboutProps) { { value: string | undefined; info?: string } >(); details.set("Owner", { value: `${creator.first_name} ${creator.last_name}` }); - details.set("Created on", { + details.set("Created", { value: parseDate(created), info: "Date and time of dataset creation", }); - details.set("Updated on", { + details.set("Updated", { value: parseDate(modified), info: "Date and time of dataset modification", }); details.set("Status", { value: status, info: "Public or private dataset" }); - details.set("Dataset id", { value: id }); + details.set("Dataset identifier", { value: id }); details.set("Downloads", { value: downloads, info: "Number of downloads", }); if (myRole) - details.set("My Role", { + details.set("My role", { value: myRole ? myRole.toUpperCase() : "", info: "Your role on the dataset. E.g. Owner, Editor, Uploader, Viewer.", }); diff --git a/frontend/src/components/files/FileDetails.tsx b/frontend/src/components/files/FileDetails.tsx index 38df7216a..4fbdf3937 100644 --- a/frontend/src/components/files/FileDetails.tsx +++ b/frontend/src/components/files/FileDetails.tsx @@ -29,20 +29,20 @@ export function FileDetails(props: FileAboutProps) { >(); details.set("Size", { value: prettyBytes(bytes) }); details.set("Content type", { value: content_type.content_type }); - details.set("Updated on", { + details.set("Updated", { value: parseDate(created), info: "Latest date and time of the file being updated", }); - details.set("Uploaded as", { value: name, info: "Name of the file" }); - details.set("Uploaded by", { + details.set("Uploaded", { value: name, info: "Name of the file" }); + details.set("Uploader", { value: `${creator.first_name} ${creator.last_name}`, }); switch (storage_type) { case "minio": { details.set("Storage location", { - value: "Database", - info: "Data stored in the Minio instance", + value: "Local object store", + info: "Data stored in the MinIO instance", }); break; } @@ -68,14 +68,14 @@ export function FileDetails(props: FileAboutProps) { break; } } - details.set("File id", { value: id }); + details.set("File identifier", { value: id }); details.set("Downloads", { value: downloads, info: "Number of downloads", }); if (myRole) - details.set("My Role", { + details.set("My role", { value: myRole ? myRole.toUpperCase() : "", info: "Your role on the file. E.g. Owner, Editor, Uploader, Viewer.", });