Skip to content

Commit

Permalink
wip: Updated help text throughout new SDS 3 pages
Browse files Browse the repository at this point in the history
  • Loading branch information
JacobiClark committed Jan 22, 2025
1 parent 4df849b commit 2da10b2
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,28 @@ import { Text, Image } from "@mantine/core";
// Each section specifies its type (e.g., text, image) and associated data.
const contentLookup = {
"sub-": [
{ type: "text", data: "This is the first section for key1." },
{ type: "image", data: "https://via.placeholder.com/150" }, // Example image URL
{ type: "text", data: "Here is another section for key1." },
{
type: "text",
data: "Each subject must be uniquely identified with a subject ID. SODA provides three options for specifying subject IDs based on the number of subjects and your preference:",
},
{
type: "text",
data: "<b>1. Manual Entry (Recommended for fewer than 10 subjects):</b> Manually enter subject IDs directly into the interface below. This is ideal for small datasets or if you prefer not to use automated methods.",
},
{
type: "text",
data: "<b>2. Spreadsheet Entry (Recommended for more than 10 subjects):</b> Upload a spreadsheet file containing subject IDs. This method is suited for larger datasets or when you already have the subject IDs organized in a file.",
},
{
type: "text",
data: "<b>3. Extract from Folder Names (Recommended if you imported folders with names that subject IDs can be extracted from):</b> Automatically generate subject IDs by extracting them from folder names. Use this method if your data is already organized into folders named after the subjects.",
},
],
"sam-": [
{ type: "text", data: "This is the first section for key2." },
{
type: "text",
data: "If any measurements were taken from samples collected from subjects (e.g. tissue samples), you can specify the samples in the interface below.",
},
{ type: "image", data: "https://via.placeholder.com/300" },
{ type: "text", data: "And yet another section for key2." },
],
Expand All @@ -35,7 +51,9 @@ const InstructionalTextSection = ({ textSectionKey }) => {
switch (section.type) {
case "text":
// Render a text section
return <Text key={index}>{section.data}</Text>;
// Use the dangerouslySetInnerHTML prop to render HTML content because the text
// may contain HTML tags (e.g., <b>Manual</b>)
return <Text key={index} dangerouslySetInnerHTML={{ __html: section.data }} />;
case "image":
// Render an image section
return <Image key={index} src={section.data} alt={`Section image ${index}`} />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ import {
getEntityForRelativePath,
} from "../../../stores/slices/datasetEntitySelectorSlice";

import { naturalSort } from "../../shared/utils/util-functions";

const ENTITY_PREFIXES = ["sub-", "sam-", "perf-"];

const handleEntityClick = (entity) => setActiveEntity(entity);
Expand Down
52 changes: 38 additions & 14 deletions src/renderer/src/components/pages/EntitySelector/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
removeEntityFromEntityList,
} from "../../../stores/slices/datasetEntitySelectorSlice";
import { naturalSort } from "../../shared/utils/util-functions";
import { swalFileListDoubleAction } from "../../../scripts/utils/swal-utils";

const EntitySelectorPage = ({
pageName,
Expand All @@ -35,7 +36,7 @@ const EntitySelectorPage = ({
datasetEntityObj: state.datasetEntityObj,
}));
const [newEntityName, setNewEntityName] = useState("");
const [activeTab, setActiveTab] = useState("manual");
const [activeTab, setActiveTab] = useState("instructions");

const isNewEntityNameValid = window.evaluateStringAgainstSdsRequirements?.(
newEntityName,
Expand Down Expand Up @@ -102,22 +103,30 @@ const EntitySelectorPage = ({
<InstructionalTextSection textSectionKey={entityTypePrefix} />
<GuidedModeSection>
<Group>
<Tabs color="indigo" variant="pills" value={activeTab} onChange={setActiveTab} w="100%">
<Tabs.List mb="md">
<Tabs color="indigo" variant="default" value={activeTab} onChange={setActiveTab} w="100%">
<Tabs.List mb="md" justify="center" grow={1}>
<Tabs.Tab value="instructions" style={{ display: "none" }}>
Instructions
</Tabs.Tab>
<Tabs.Tab value="manual">manual</Tabs.Tab>
<Tabs.Tab value="spreadsheet">spreadsheet</Tabs.Tab>
<Tabs.Tab value="folderSelect">folderSelect</Tabs.Tab>
<Tabs.Tab value="folderSelect">Extract from folder names</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="instructions">
<Text align="center" c="dimmed" pt="md">
Select a tab above to begin specifying {entityTypeStringPlural}.
</Text>
</Tabs.Panel>
<Tabs.Panel value="manual">
<Stack spacing="xs" mb="md">
<Group spacing="xs" align="start" width="100%">
<TextInput
flex={1}
placeholder={`Enter new ${entityTypeStringSingular} name`}
placeholder={`Enter ${entityTypeStringSingular} name`}
value={newEntityName}
onChange={(event) => setNewEntityName(event.currentTarget.value)}
onKeyDown={(event) => {
if (event.key === "Enter") {
if (event.which === 13) {
handleAddEntity();
}
}}
Expand Down Expand Up @@ -155,16 +164,31 @@ const EntitySelectorPage = ({

<DatasetTreeViewRenderer
folderActions={{
"on-folder-click": (folderName, folderContents, folderIsSelected) => {
"on-folder-click": async (folderName, folderContents, folderIsSelected) => {
const childFolderNames = Object.keys(folderContents.folders);
console.log("childFolderNames: ", naturalSort(childFolderNames));
const potentialEntities = naturalSort(childFolderNames).map(
(childFolderName) => {
const formattedName =
entityTypePrefix && !childFolderName.startsWith(entityTypePrefix)
? `${entityTypePrefix}${childFolderName}`
: childFolderName;
return formattedName;
}
);

const continueWithEntityIdImport = await swalFileListDoubleAction(
potentialEntities,
`Confirm ${entityTypeStringPlural} Import`,
`The following ${entityTypeStringPlural} have been detected in the selected folder. If you proceed, they will be added to your list of ${entityTypeStringPlural}:`,
`Import Selected ${entityTypeStringPlural}`,
`Cancel Import`,
""
);

for (const childFolderName of naturalSort(childFolderNames)) {
const formattedName =
entityTypePrefix && !childFolderName.startsWith(entityTypePrefix)
? `${entityTypePrefix}${childFolderName}`
: childFolderName;
addEntityToEntityList(entityType, formattedName);
if (continueWithEntityIdImport) {
for (const entityName of potentialEntities) {
addEntityToEntityList(entityType, entityName);
}
}
},
"folder-click-hover-text": `Import ${entityTypeStringSingular} IDs from folders in this folder`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ const ContextMenu = () => {
window.electron.ipcRenderer.send("open-folders-organize-datasets-dialog", {
importRelativePath: contextMenuItemData.relativePath,
});
closeContextMenu();
}}
>
Import data into {contextMenuItemName}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ const FileItem = ({ name, content, onFileClick, isFileSelected, allowStructureEd
const fileRelativePathEqualsContextMenuItemRelativePath =
contextMenuIsOpened && contextMenuItemData?.relativePath === content.relativePath;

const fileIsSelected = isFileSelected?.(content);

if (fileIsSelected) {
console.log("File is selected");
console.log(content.relativePath);
}

const handleFileContextMenuOpen = (e) => {
e.preventDefault();
e.stopPropagation();
Expand Down Expand Up @@ -100,13 +107,19 @@ const FolderItem = ({
allowStructureEditing,
folderClickHoverText,
}) => {
const { folderMoveModeIsActive, contextMenuItemType, contextMenuItemData, contextMenuIsOpened } =
useGlobalStore((state) => ({
folderMoveModeIsActive: state.folderMoveModeIsActive,
contextMenuItemType: state.contextMenuItemType,
contextMenuItemData: state.contextMenuItemData,
contextMenuIsOpened: state.contextMenuIsOpened,
}));
const {
folderMoveModeIsActive,
contextMenuItemType,
contextMenuItemData,
contextMenuIsOpened,
contextMenuItemName,
} = useGlobalStore((state) => ({
folderMoveModeIsActive: state.folderMoveModeIsActive,
contextMenuItemType: state.contextMenuItemType,
contextMenuItemData: state.contextMenuItemData,
contextMenuIsOpened: state.contextMenuIsOpened,
contextMenuItemName: state.contextMenuItemName,
}));

const [isOpen, setIsOpen] = useState(false);
const { hovered, ref } = useHover();
Expand Down Expand Up @@ -134,9 +147,11 @@ const FolderItem = ({
const folderIsEmpty =
!content ||
(Object.keys(content.folders).length === 0 && Object.keys(content.files).length === 0);

const folderIsPassThrough = content.passThrough;

const folderOnlyHasFolders =
Object.keys(content.folders).length > 0 && Object.keys(content.files).length === 0;
const folderOnlyHasFiles =
Object.keys(content.folders).length === 0 && Object.keys(content.files).length > 0;
const folderRelativePathEqualsContextMenuItemRelativePath =
contextMenuIsOpened && contextMenuItemData?.relativePath === content.relativePath;

Expand Down Expand Up @@ -249,14 +264,26 @@ const FolderItem = ({
};

const DatasetTreeViewRenderer = ({ folderActions, fileActions, allowStructureEditing }) => {
const { renderDatasetStructureJSONObj, datasetStructureSearchFilter, folderMoveModeIsActive } =
useGlobalStore((state) => ({
renderDatasetStructureJSONObj: state.renderDatasetStructureJSONObj,
datasetStructureSearchFilter: state.datasetStructureSearchFilter,
folderMoveModeIsActive: state.folderMoveModeIsActive,
}));
const {
renderDatasetStructureJSONObj,
datasetStructureSearchFilter,
folderMoveModeIsActive,
contextMenuItemType,
contextMenuItemData,
contextMenuIsOpened,
contextMenuItemName,
} = useGlobalStore((state) => ({
renderDatasetStructureJSONObj: state.renderDatasetStructureJSONObj,
datasetStructureSearchFilter: state.datasetStructureSearchFilter,
folderMoveModeIsActive: state.folderMoveModeIsActive,
folderMoveModeIsActive: state.folderMoveModeIsActive,
contextMenuItemType: state.contextMenuItemType,
contextMenuItemData: state.contextMenuItemData,
contextMenuIsOpened: state.contextMenuIsOpened,
contextMenuItemName: state.contextMenuItemName,
}));

const searcDebounceTime = 300; // Set the debounce time for the search filter (in milliseconds)
const searchDebounceTime = 300; // Set the debounce time for the search filter (in milliseconds)

const [inputSearchFilter, setInputSearchFilter] = useState(datasetStructureSearchFilter); // Local state for input
const searchTimeoutRef = useRef(null);
Expand All @@ -274,7 +301,7 @@ const DatasetTreeViewRenderer = ({ folderActions, fileActions, allowStructureEdi
// Set a new timeout to update the global state
searchTimeoutRef.current = setTimeout(() => {
setDatasetStructureSearchFilter(value); // Update the global state after the debounce delay
}, searcDebounceTime);
}, searchDebounceTime);
};

useEffect(() => {
Expand Down Expand Up @@ -350,7 +377,7 @@ const DatasetTreeViewRenderer = ({ folderActions, fileActions, allowStructureEdi
/* make A ui that allows the user to cancel the move operation */
<Group justify="space-between" bg="aliceblue" p="xs">
<Text size="lg" fw={500}>
Select a folder to move the data to
Select a folder to move the {contextMenuItemType} '{contextMenuItemName}' to:
</Text>
<Button
size="xs"
Expand Down
33 changes: 26 additions & 7 deletions src/renderer/src/scripts/guided-mode/guided-curate-dataset.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
setEntityListForEntityType,
setActiveEntity,
getDatasetEntityObj,
setDatasetEntityObj,
} from "../../stores/slices/datasetEntitySelectorSlice";
import {
setDatasetStructureSearchFilter,
Expand Down Expand Up @@ -613,12 +614,26 @@ const savePageChanges = async (pageBeingLeftID) => {
// Check if the page being left is part of a page set
const pageBeingLeftElement = document.getElementById(pageBeingLeftID);
const pageBeingLeftDataSet = pageBeingLeftElement.dataset;
console.log("pageBeingLeftDataSet", pageBeingLeftDataSet);

// Handle page exit logic for pages that are controlled by React components
if (pageBeingLeftDataSet.componentType) {
const pageBeingLeftComponentType = pageBeingLeftDataSet.componentType;
if (pageBeingLeftComponentType === "entity-management-page") {
const entityType = pageBeingLeftDataSet.entityType;
const entityTypeSingular = pageBeingLeftDataSet.entityTypeStringSingular;
const datasetEntityObj = getDatasetEntityObj();
console.log("datasetEntityObj", datasetEntityObj);
console.log("entityType", entityType);
if (!datasetEntityObj?.[entityType]) {
errorArray.push({
type: "notyf",
message: `Please select at least one ${entityTypeSingular} to continue`,
});
throw errorArray;
}
// Save the dataset entity object to the progress file
window.sodaJSONObj["dataset-entity-obj"] = datasetEntityObj;
}
if (pageBeingLeftComponentType === "entity-selection-page") {
console.log("BONGO");
Expand Down Expand Up @@ -5156,10 +5171,13 @@ window.openPage = async (targetPageID) => {
if (targetPageDataset.componentType) {
const targetPageComponentType = targetPageDataset.componentType;
if (targetPageComponentType === "entity-management-page") {
console.log("DINGO");
// Set the dataset entity object to the saved dataset entity object from the JSON
const savedDatasetEntityObj = window.sodaJSONObj["dataset-entity-obj"] || {};
setDatasetEntityObj(savedDatasetEntityObj);
setTreeViewDatasetStructure(window.datasetStructureJSONObj, ["primary"]);
}
if (targetPageComponentType === "entity-selection-page") {
console.log("DONGO");
setTreeViewDatasetStructure(window.datasetStructureJSONObj, ["primary"]);
}
}

Expand Down Expand Up @@ -11578,14 +11596,14 @@ const setUiBasedOnSavedDatasetStructurePath = (pathToSpreadsheet) => {
}
};

document
/*document
.getElementById("guided-button-choose-dataset-structure-spreadsheet-path")
.addEventListener("click", () => {
// Create a new spreadsheet based on the dataset structure
window.electron.ipcRenderer.send(
"open-create-dataset-structure-spreadsheet-path-selection-dialog"
);
});
});*/

window.electron.ipcRenderer.on(
"selected-create-dataset-structure-spreadsheet-path",
Expand Down Expand Up @@ -11628,7 +11646,7 @@ window.electron.ipcRenderer.on(
}
);

document
/* document
.getElementById("guided-button-open-dataset-structure-spreadsheet")
.addEventListener("click", async () => {
const savedTemplatePath = window.sodaJSONObj["dataset-structure-spreadsheet-path"];
Expand All @@ -11637,7 +11655,7 @@ document
return;
}
window.electron.ipcRenderer.send("open-file-at-path", savedTemplatePath);
});
}); */

const validateDatasetStructureSpreadsheet = async (sheetData) => {
const invalidSubjectNames = [];
Expand Down Expand Up @@ -11778,6 +11796,7 @@ const validateDatasetStructureSpreadsheet = async (sheetData) => {
};

// CLICK HANDLER THAT EXTRACTS THE DATASET STRUCTURE FROM A SPREADSHEET
/*
document
.getElementById("guided-button-import-dataset-structure-from-spreadsheet")
.addEventListener("click", async () => {
Expand Down Expand Up @@ -11837,6 +11856,7 @@ document
$("#guided-next-button").click();
});

*/
const guidedExtractEntityNamesFromFolders = async (entityType) => {
if (entityType === "subjects") {
window.electron.ipcRenderer.send("open-subject-multi-folder-import-dialog");
Expand Down Expand Up @@ -18012,7 +18032,6 @@ const continueHackGm = true;

const doTheHack = async () => {
console.log("Doing the hack");
return;
// wait for a second
await new Promise((resolve) => setTimeout(resolve, 5000));
document.getElementById("button-homepage-guided-mode").click();
Expand Down
Loading

0 comments on commit 2da10b2

Please sign in to comment.