diff --git a/src/commands.js b/src/commands.js index 84dc02a..6b00e7b 100644 --- a/src/commands.js +++ b/src/commands.js @@ -19,13 +19,19 @@ export default { execute: async fileNameOrId => { // try to find file by ID first, then by name const file = findFileByNameOrId(fileNameOrId) - // quit if this file doesn't exist if (!file) return "File doesn't exist." - - // delete file from disk - await store.getState().workingDirectory.directoryHandle?.removeEntry(file.name) + + // delete file from disk, try to see if in subdirectory first else delete from root + const directory = file.id.split("/")[0] + try{ + const tempDirectory = await store.getState().workingDirectory.directoryHandle.getDirectoryHandle(directory) + await tempDirectory.removeEntry(file.name) + } + catch{ + await store.getState().workingDirectory.directoryHandle?.removeEntry(file.name) + } // close panel if it's open store.dispatch(panelsActions.closePanel(file.id)) diff --git a/src/components/activities/explorer/ExplorerActivityView.jsx b/src/components/activities/explorer/ExplorerActivityView.jsx index e04c4d7..25285d1 100644 --- a/src/components/activities/explorer/ExplorerActivityView.jsx +++ b/src/components/activities/explorer/ExplorerActivityView.jsx @@ -24,7 +24,7 @@ export default function ExplorerActivityView({ }) { return workingDirectory ? <> - +
Switch Folder diff --git a/src/components/activities/explorer/ExplorerList.jsx b/src/components/activities/explorer/ExplorerList.jsx index 2e41121..acfa46b 100644 --- a/src/components/activities/explorer/ExplorerList.jsx +++ b/src/components/activities/explorer/ExplorerList.jsx @@ -6,15 +6,20 @@ import ExplorerListItem from './ExplorerListItem' import SaveIndicatorDisplay from '../../saveIndicatorDisplay' -export default function ExplorerList({currentDirectory}) { +export default function ExplorerList({workDir}) { // grab file handles const files = useFiles() + let tempDirectory; // handle creation const createFile = useCreateFile() - const handleCreateObject = objectType => fileName => { - createFile(fileName + objectType.extension, objectType.id) + const handleCreateObject = objectType => async fileName => { + if(objectType.title === "Plasmid"){ // Retrieve Plasmid directory, if it doesn't exist create it first + tempDirectory = await workDir.getDirectoryHandle("plasmid", { create: true }); + + } + createFile(fileName + objectType.extension, objectType.id, tempDirectory) } // generate DragObjects based on data @@ -29,7 +34,7 @@ export default function ExplorerList({currentDirectory}) { return ( - Current Folder: {currentDirectory} + Current Folder: {workDir.name} { }) function Content({ id, ...props }) { - const panelType = usePanelType(id) + const fileHandle = usePanelProperty(id, 'fileHandle') return ( - + ) } diff --git a/src/components/panels/sbol-editor/CanvasFrame.jsx b/src/components/panels/sbol-editor/CanvasFrame.jsx index 95ce8e2..bfe7b0c 100644 --- a/src/components/panels/sbol-editor/CanvasFrame.jsx +++ b/src/components/panels/sbol-editor/CanvasFrame.jsx @@ -5,10 +5,9 @@ import { PanelContext } from './SBOLEditorPanel' import { usePanelProperty } from "../../../redux/hooks/panelsHooks" -export default function CanvasFrame() { +export default function CanvasFrame({fileTypeObjectId}) { const panelId = useContext(PanelContext) - // state containing full SBOL content const [sbolContent, setSBOLContent] = usePanelProperty(panelId, "sbol", false) @@ -50,9 +49,10 @@ export default function CanvasFrame() { // post message iframeRef.current.contentWindow.postMessage( + sbolContent ? - { sbol: sbolContent } : // either send SBOL content - 'hello canvas', // or send dummy message + { sbol: sbolContent, panelType: fileTypeObjectId} : // either send SBOL content + {panelType: fileTypeObjectId}, // if no sbolContent, just send in panel type import.meta.env.VITE_SBOL_CANVAS_URL ) } diff --git a/src/components/panels/sbol-editor/SBOLEditorPanel.jsx b/src/components/panels/sbol-editor/SBOLEditorPanel.jsx index 0b01779..ddd5734 100644 --- a/src/components/panels/sbol-editor/SBOLEditorPanel.jsx +++ b/src/components/panels/sbol-editor/SBOLEditorPanel.jsx @@ -6,7 +6,7 @@ import { useSelector } from 'react-redux' export const PanelContext = createContext() -export default function SBOLEditorPanel({id}) { +export default function SBOLEditorPanel({id, fileObjectTypeId}) { const activePanel = useSelector(state => state.panels.active) return ( @@ -27,7 +27,7 @@ export default function SBOLEditorPanel({id}) {
*/} - + ) diff --git a/src/objectTypes.js b/src/objectTypes.js index 5e1fd1d..05cc12f 100644 --- a/src/objectTypes.js +++ b/src/objectTypes.js @@ -1,7 +1,9 @@ import { BiWorld } from "react-icons/bi" import { IoAnalyticsSharp } from "react-icons/io5" import { TbComponents } from "react-icons/tb" - +import { GrTestDesktop } from "react-icons/gr"; +import { MdAlignVerticalTop } from "react-icons/md"; +import { VscOutput } from "react-icons/vsc"; export const ObjectTypes = { SBOL: { id: "synbio.object-type.sbol", @@ -12,6 +14,7 @@ export const ObjectTypes = { createable: true, extension: '.xml', badgeLabel: "SBOL", + directory: "main" }, SBML: { id: "synbio.object-type.sbml", @@ -20,6 +23,7 @@ export const ObjectTypes = { fileMatch: / ot.id == id) } -export async function classifyFile(file) { +export async function classifyFile(file, subDirectoryName) { // try to match by file name const matchFromFileName = Object.values(ObjectTypes).find( ot => ot.fileNameMatch?.test(file.name) )?.id - if(matchFromFileName) - return matchFromFileName - + if (!subDirectoryName && matchFromFileName && matchFromFileName && matchFromFileName != ObjectTypes.Plasmids.id) { + return matchFromFileName; + } + else if (subDirectoryName != null && subDirectoryName.toLowerCase() === "plasmid" && ObjectTypes.Plasmids.fileNameMatch?.test(file.name)) { + return ObjectTypes.Plasmids.id; + } // otherwise, read file content - const fileContent = await (await file.getFile()).text() - return Object.values(ObjectTypes).find( - ot => ot.fileMatch?.test(fileContent) - )?.id + if(subDirectoryName == null){ + const fileContent = await (await file.getFile()).text() + return Object.values(ObjectTypes).find( + ot => ot.fileMatch?.test(fileContent) + )?.id + } } \ No newline at end of file diff --git a/src/panels.js b/src/panels.js index 1b6bbc9..35b0114 100644 --- a/src/panels.js +++ b/src/panels.js @@ -25,12 +25,12 @@ export const PanelTypes = { const { id, fileHandle, type, ...restOfPanel } = panel return JSON.stringify(restOfPanel) } - }, + }, SBOLEditor: { id: "synbio.panel-type.sbol-editor", title: "SBOL Canvas", component: SBOLEditorPanel, - objectTypes: [ ObjectTypes.SBOL.id ], + objectTypes: [ ObjectTypes.SBOL.id, ObjectTypes.Plasmids.id ], icon: CanvasIcon, deserialize: content => ({ diff --git a/src/redux/hooks/workingDirectoryHooks.js b/src/redux/hooks/workingDirectoryHooks.js index 4460a9d..fb50d8c 100644 --- a/src/redux/hooks/workingDirectoryHooks.js +++ b/src/redux/hooks/workingDirectoryHooks.js @@ -46,14 +46,15 @@ export function useWorkingDirectory() { // Action hooks + export function useCreateFile() { const dispatch = useDispatch() const openPanel = useOpenPanel() const workDir = useSelector(state => state.workingDirectory.directoryHandle) - return (fileName, objectType) => { - workDir.getFileHandle(fileName, { create: true }) + return (fileName, objectType, directory = workDir) => { // Optional arg directory in which the file will be created + directory.getFileHandle(fileName, { create: true }) .then(fileHandle => { - addFileMetadata(fileHandle, { objectType }) + addFileMetadata(fileHandle, directory.name, { objectType }) dispatch(actions.addFile(fileHandle)) openPanel(fileHandle) }) @@ -72,7 +73,7 @@ export function useCreateFileWithFilePicker() { }] }) .then(fileHandle => { - addFileMetadata(fileHandle) + addFileMetadata(fileHandle, null) dispatch(actions.addFile(fileHandle)) openPanel(fileHandle) }) @@ -103,24 +104,42 @@ export function useSafeName(baseName) { // Utility -async function findFilesInDirectory(dirHandle) { +export async function findFilesInDirectory(dirHandle) { const files = [] + // loop through async iterator of file names (called keys here) for await (const handle of dirHandle.values()) { if (handle.kind == 'file') { - await addFileMetadata(handle) + await addFileMetadata(handle, null) files.push(handle) } + } + // Check for subfolders "output" and "metadata" + for await (const [name, subHandle] of dirHandle.entries()) { + if (subHandle.kind === 'directory' && (name.toLowerCase() === 'output' || name.toLowerCase() === 'metadata' || name.toLowerCase() === "plasmid")) { + for await (const handle of subHandle.values()) { + if (handle.kind === 'file') { + await addFileMetadata(handle, name) + files.push(handle) + } + } + } + } + return files } -async function addFileMetadata(handle, { objectType } = {}) { +async function addFileMetadata(handle, subDirectoryName, { objectType } = {}) { // handle.id = uuidv4() - handle.id = handle.name - handle.objectType = objectType || await classifyFile(handle) + if (subDirectoryName === null) { + handle.id = handle.name; + } else { + handle.id = (subDirectoryName + '/' + handle.name); + } + handle.objectType = objectType || await classifyFile(handle, subDirectoryName) } export function titleFromFileName(fileName) {