Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plasmids Activity #80

Merged
merged 8 commits into from
Feb 12, 2025
14 changes: 10 additions & 4 deletions src/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function ExplorerActivityView({ }) {

return workingDirectory ?
<>
<ExplorerList currentDirectory = {workingDirectory.name} />
<ExplorerList workDir = {workingDirectory} />
<Center mt={20}>
<FolderSelect onSelect={handleDirectorySelection}>
Switch Folder
Expand Down
13 changes: 9 additions & 4 deletions src/components/activities/explorer/ExplorerList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -29,7 +34,7 @@ export default function ExplorerList({currentDirectory}) {
return (
<ScrollArea style={{ height: 'calc(100vh - 120px)' }}>
<Title mt={10} order={6}>
Current Folder: {currentDirectory}
Current Folder: {workDir.name}
</Title>

<Accordion
Expand Down
4 changes: 2 additions & 2 deletions src/components/panels/Panel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ const Tab = forwardRef(({ id, ...props }, ref) => {
})

function Content({ id, ...props }) {

const panelType = usePanelType(id)
const fileHandle = usePanelProperty(id, 'fileHandle')

return (
<MantineTabs.Panel value={id} {...props}>
<panelType.component id={id} />
<panelType.component id={id} fileObjectTypeId={fileHandle.objectType} />
</MantineTabs.Panel>
)
}
Expand Down
8 changes: 4 additions & 4 deletions src/components/panels/sbol-editor/CanvasFrame.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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
)
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/panels/sbol-editor/SBOLEditorPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<PanelContext.Provider value={activePanel}>
Expand All @@ -27,7 +27,7 @@ export default function SBOLEditorPanel({id}) {
</Center>
</Tabs.Tab>
</Tabs> */}
<CanvasFrame />
<CanvasFrame fileTypeObjectId={fileObjectTypeId}/>
<PanelSaver id={activePanel} />
</PanelContext.Provider>
)
Expand Down
39 changes: 30 additions & 9 deletions src/objectTypes.js
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -12,6 +14,7 @@ export const ObjectTypes = {
createable: true,
extension: '.xml',
badgeLabel: "SBOL",
directory: "main"
},
SBML: {
id: "synbio.object-type.sbml",
Expand All @@ -20,6 +23,7 @@ export const ObjectTypes = {
fileMatch: /<sbml/,
createable: false,
badgeLabel: "SBML",
directory: "main"
},
OMEX: {
id: "synbio.object-type.omex-archive",
Expand All @@ -29,6 +33,7 @@ export const ObjectTypes = {
icon: BiWorld,
createable: false,
badgeLabel: "OMEX",
directory: "main"
},
Analysis: {
id: "synbio.object-type.analysis",
Expand All @@ -38,24 +43,40 @@ export const ObjectTypes = {
icon: IoAnalyticsSharp,
createable: true,
extension: '.analysis',
directory: "main"
},
Plasmids:{
id: "synbio.object-type.plasmid",
title: "Plasmid",
listTitle: "Plasmids",
createable: true,
extension: '.xml',
icon: TbComponents,
directory: 'Plasmid',
fileNameMatch: /\.xml$/
}
}

export function getObjectType(id) {
return Object.values(ObjectTypes).find(ot => 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
}
}
4 changes: 2 additions & 2 deletions src/panels.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 => ({
Expand Down
37 changes: 28 additions & 9 deletions src/redux/hooks/workingDirectoryHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
Expand All @@ -72,7 +73,7 @@ export function useCreateFileWithFilePicker() {
}]
})
.then(fileHandle => {
addFileMetadata(fileHandle)
addFileMetadata(fileHandle, null)
dispatch(actions.addFile(fileHandle))
openPanel(fileHandle)
})
Expand Down Expand Up @@ -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) {
Expand Down
Loading