Skip to content

Commit

Permalink
wip: Updated entity importation page
Browse files Browse the repository at this point in the history
  • Loading branch information
JacobiClark committed Jan 17, 2025
1 parent 5edc38d commit 93f7aee
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 73 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import GuidedModeSection from "../../containers/GuidedModeSection";
import { Text, Image } from "@mantine/core";

// Content lookup object that maps keys to arrays of content sections.
// 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." },
],
"sam-": [
{ type: "text", data: "This is the first section for key2." },
{ type: "image", data: "https://via.placeholder.com/300" },
{ type: "text", data: "And yet another section for key2." },
],
"sites-": [
{ type: "text", data: "This is the first section for key2." },
{ type: "image", data: "https://via.placeholder.com/300" },
{ type: "text", data: "And yet another section for key2." },
],
};

const InstructionalTextSection = ({ textSectionKey }) => {
// Retrieve content sections for the given key. If the key is not found,
// provide a fallback with a "Content not found" message.
const contentSections = contentLookup[textSectionKey] || [
{ type: "text", data: "Content not found." },
];

return (
<GuidedModeSection>
{/* Render each section based on its type */}
{contentSections.map((section, index) => {
switch (section.type) {
case "text":
// Render a text section
return <Text key={index}>{section.data}</Text>;
case "image":
// Render an image section
return <Image key={index} src={section.data} alt={`Section image ${index}`} />;
default:
// Handle unknown or unsupported section types
return null;
}
})}
</GuidedModeSection>
);
};

export default InstructionalTextSection;
224 changes: 162 additions & 62 deletions src/renderer/src/components/pages/EntitySelector/index.jsx
Original file line number Diff line number Diff line change
@@ -1,76 +1,176 @@
import { useState } from "react";
import GuidedModePage from "../../containers/GuidedModePage";
import GuidedModeSection from "../../containers/GuidedModeSection";
import DropDownNote from "../../utils/ui/DropDownNote";
import { TextInput, Textarea, Text } from "@mantine/core";
import ExternalLink from "../../buttons/ExternalLink";
import { IconPlus, IconTrash, IconEdit } from "@tabler/icons-react";
import {
TextInput,
Textarea,
ActionIcon,
Text,
Tabs,
Stack,
Group,
Button,
ScrollArea,
Box,
} from "@mantine/core";
import useGlobalStore from "../../../stores/globalStore";
import DatasetTreeViewRenderer from "../../shared/DatasetTreeViewRenderer";
import InstructionalTextSection from "../../common/InstructionalTextSection";
import {
setGuidedDatasetName,
setGuidedDatasetSubtitle,
} from "../../../stores/slices/guidedModeSlice";
addEntityToEntityList,
removeEntityFromEntityList,
} from "../../../stores/slices/datasetEntitySelectorSlice";

const NameAndSubtitlePage = () => {
const { guidedDatasetName, guidedDatasetSubtitle } = useGlobalStore((state) => ({
guidedDatasetName: state.guidedDatasetName,
guidedDatasetSubtitle: state.guidedDatasetSubtitle,
const EntitySelectorPage = ({
entityType,
entityTypeStringSingular,
entityTypeStringPlural,
entityTypePrefix,
}) => {
const { datasetEntityObj } = useGlobalStore((state) => ({
datasetEntityObj: state.datasetEntityObj,
}));
const [newEntityName, setNewEntityName] = useState("");
const [activeTab, setActiveTab] = useState("manual");

const isNewEntityNameValid = window.evaluateStringAgainstSdsRequirements?.(
newEntityName,
"string-adheres-to-identifier-conventions"
);

const entityList = Object.keys(datasetEntityObj?.[entityType] || {});

const handleAddEntity = () => {
const trimmedName = newEntityName.trim();
if (trimmedName) {
const formattedName =
entityTypePrefix && !trimmedName.startsWith(entityTypePrefix)
? `${entityTypePrefix}${trimmedName}`
: trimmedName;
addEntityToEntityList(entityType, formattedName);
setNewEntityName("");
}
};

const handleRemoveEntity = (entityName) => {
removeEntityFromEntityList(entityType, entityName);
};

const handleImportEntitiesFromLocalFoldersClick = () => {
window.electron.ipcRenderer.send("open-entity-id-import-selector");
};

const renderEntityList = (width) =>
entityList.length > 0 ? (
<Stack w={width}>
{entityList.map((entityName) => (
<Group
key={entityName}
justify="space-between"
px="sm"
py="xs"
style={{ borderBottom: "1px solid #eaeaea" }}
>
<Text>{entityName}</Text>
<Group gap="xs">
<ActionIcon color="blue">
<IconEdit size={16} />
</ActionIcon>
<ActionIcon color="red" onClick={() => handleRemoveEntity(entityName)}>
<IconTrash size={16} />
</ActionIcon>
</Group>
</Group>
))}
</Stack>
) : (
<Text align="center" c="dimmed" px="sm" py="xs">
No {entityTypeStringPlural} added yet.
</Text>
);

return (
<GuidedModePage pageHeader="Dataset name and subtitle">
<GuidedModeSection>
<TextInput
label="Dataset Name:"
placeholder="Enter dataset name"
value={guidedDatasetName}
onChange={(event) => setGuidedDatasetName(event.target.value)}
/>
<DropDownNote
dropDownIcon="info"
dropDownButtonText="What is the dataset name used for?"
dropDownNote={
<Text>
This field will be displayed in public as the title of the dataset once it is
published on the
<ExternalLink
href="https://sparc.science/"
buttonText="SPARC Data Portal"
buttonType="anchor"
/>
. Please make sure that your dataset name is unique and relatively informative.
</Text>
}
/>
</GuidedModeSection>
<GuidedModePage pageHeader={`${entityTypeStringSingular} management`}>
<InstructionalTextSection textSectionKey={entityTypePrefix} />
<GuidedModeSection>
<Textarea
label="Dataset Subtitle:"
placeholder="Enter dataset subtitle"
autosize
minRows={5}
value={guidedDatasetSubtitle}
onChange={(event) => setGuidedDatasetSubtitle(event.target.value)}
maxLength={255}
/>
<Text align="right" style={{ marginTop: "-35px", zIndex: "10", marginRight: "10px" }}>
{255 - guidedDatasetSubtitle.length} characters remaining
</Text>
<DropDownNote
dropDownIcon="info"
dropDownButtonText="What is the dataset subtitle used for?"
dropDownNote={
<Text>
This field will become the short description visible immediately under the title of
your dataset once it is published on the
<ExternalLink
href="https://sparc.science/"
buttonText="SPARC Data Portal"
buttonType="anchor"
/>
</Text>
}
/>
<Group>
<Tabs color="indigo" variant="pills" value={activeTab} onChange={setActiveTab} w="100%">
<Tabs.List mb="md">
<Tabs.Tab value="manual">manual</Tabs.Tab>
<Tabs.Tab value="spreadsheet">spreadsheet</Tabs.Tab>
<Tabs.Tab value="folderSelect">folderSelect</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="manual">
<Stack spacing="xs" mb="md">
<Group spacing="xs" align="start" width="100%">
<TextInput
flex={1}
placeholder={`Enter new ${entityTypeStringSingular} name`}
value={newEntityName}
onChange={(event) => setNewEntityName(event.currentTarget.value)}
onKeyDown={(event) => {
if (event.key === "Enter") {
handleAddEntity();
}
}}
error={
!isNewEntityNameValid &&
`${entityTypeStringSingular} does not adhere to identifier conventions.`
}
/>
<Button onClick={handleAddEntity} leftIcon={<IconPlus />}>
Add {entityTypeStringSingular}
</Button>
</Group>
</Stack>

<ScrollArea height={300} type="auto">
<Box>{renderEntityList()}</Box>
</ScrollArea>
</Tabs.Panel>

<Tabs.Panel value="spreadsheet">
<Group spacing="xs" align="start" width="100%">
{renderEntityList("300px")}
<Button
size="xs"
color="blue"
variant="outline"
onClick={handleImportEntitiesFromLocalFoldersClick}
>
Import {entityTypeStringSingular} IDs from local folders/files
</Button>
</Group>
</Tabs.Panel>

<Tabs.Panel value="folderSelect">
<Group spacing="xs" align="start" width="100%">
{renderEntityList("300px")}

<DatasetTreeViewRenderer
folderActions={{
"on-folder-click": (folderName, folderContents, folderIsSelected) => {
console.log("folderName", folderName);
console.log("folderContents", folderContents);
console.log("folderIsSelected", folderIsSelected);
},
"is-folder-selected": (folderName, folderContents) => {
/*
console.log("folderName", folderName);
console.log("folderContents", folderContents);
*/
},
}}
/>
</Group>
</Tabs.Panel>
</Tabs>
</Group>
</GuidedModeSection>
</GuidedModePage>
);
};

export default NameAndSubtitlePage;
export default EntitySelectorPage;
35 changes: 24 additions & 11 deletions src/renderer/src/components/renderers/ReactComponentRenderer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import SodaComponentWrapper from "../utils/SodaComponentWrapper";
import ExternalLink from "../buttons/ExternalLink";
import NavigationButton from "../buttons/Navigation";
import NameAndSubtitlePage from "../pages/NameAndSubtitle";
import EntitySelectorPage from "../pages/EntitySelector";
import DropdownSelect from "../common/DropdownSelect";
import GenericButton from "../buttons/Generic";
import SingleColumnTable from "../tables/singleColumn";
Expand Down Expand Up @@ -99,20 +100,17 @@ const componentTypeRenderers = {
},

"manifest-entity-manager": (componentSlot) => {
const entityType = componentSlot.getAttribute("data-entity-type");
const entityTypeStringSingular = componentSlot.getAttribute("data-entity-type-string-singular");
const entityTypeStringPlural = componentSlot.getAttribute("data-entity-type-string-plural");
const entityTypePrefix = componentSlot.getAttribute("data-entity-type-prefix");

const props = {
entityType: componentSlot.getAttribute("data-entity-type"),
entityTypeStringSingular: componentSlot.getAttribute("data-entity-type-string-singular"),
entityTypeStringPlural: componentSlot.getAttribute("data-entity-type-string-plural"),
entityTypePrefix: componentSlot.getAttribute("data-entity-type-prefix"),
};
console.log("bing", props);
const root = createRoot(componentSlot);
root.render(
<SodaComponentWrapper>
<DatasetEntityManager
entityType={entityType}
entityTypeStringSingular={entityTypeStringSingular}
entityTypeStringPlural={entityTypeStringPlural}
entityTypePrefix={entityTypePrefix}
/>
<DatasetEntityManager {...props} />
</SodaComponentWrapper>
);
},
Expand All @@ -125,6 +123,21 @@ const componentTypeRenderers = {
</SodaComponentWrapper>
);
},
"entity-management-page": (componentSlot) => {
const root = createRoot(componentSlot);
const props = {
entityType: componentSlot.getAttribute("data-entity-type"),
entityTypeStringSingular: componentSlot.getAttribute("data-entity-type-string-singular"),
entityTypeStringPlural: componentSlot.getAttribute("data-entity-type-string-plural"),
entityTypePrefix: componentSlot.getAttribute("data-entity-type-prefix"),
};

root.render(
<SodaComponentWrapper>
<EntitySelectorPage {...props} />
</SodaComponentWrapper>
);
},
divider: (componentSlot) => {
const root = createRoot(componentSlot);
root.render(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import GuidedModeSection from "../../containers/GuidedModeSection";

const InstructionalTextSection = (textSectionKey) => {
return <GuidedModeSection>hi</GuidedModeSection>;
};

export default InstructionalTextSection;
Original file line number Diff line number Diff line change
Expand Up @@ -1393,6 +1393,15 @@ <h1 class="text-sub-step-title">Subjects specification</h1>
</div>
</div>
-->
<div
id="guided-subject-entity-addition-tab"
data-page-name="Subjects management"
class="guided--page"
data-component-type="entity-management-page"
data-entity-type-string-singular="subject"
data-entity-type-string-plural="subjects"
data-entity-type-prefix="sub-"
></div>
<div
id="guided-z-entity-addition-tab"
class="guided--page"
Expand Down

0 comments on commit 93f7aee

Please sign in to comment.