diff --git a/apps/server/app.py b/apps/server/app.py index 7ee0d89..fc4fd59 100644 --- a/apps/server/app.py +++ b/apps/server/app.py @@ -117,7 +117,7 @@ def create_app(): # only retrieves feature library that already exists after setup # might create a libarary in the future def create_feature_library(part_library_file_name): - if part_library_file_name.startswith('https://synbiohub.org'): #if url, return the obj if indexed with url(sbh downloads only) + if ('synbiohub.org' in part_library_file_name): #if url, return the obj if indexed with url(sbh downloads only) if part_library_file_name in FEATURE_LIBRARIES: return FEATURE_LIBRARIES[part_library_file_name] else: #for locally stored sbh collections(indexed with file name for annotation) @@ -201,6 +201,7 @@ def run_synbict(sbol_content: str, part_library_file_names: list[str]) -> tuple[ target_library = FeatureLibrary([target_doc]) # feature_library = FEATURE_LIBRARIES[0] feature_library = create_feature_library(part_lib_f_name) + print(f"feature library for {part_lib_f_name}: {feature_library}") min_feature_length = 10 annotater = FeatureAnnotater(feature_library, min_feature_length) min_target_length = 10 @@ -424,6 +425,43 @@ def annotate_text(): biobert_result = run_biobert(free_text) return {"text": free_text, "annotations": biobert_result} +@app.post("/api/importUserLibrary") +def import_library(): + request_data = request.get_json() + SBHSessionToken = request_data['sessionToken'] + collectionURL = request_data['url'] + + headers = { + "Accept": "text/plain", + "X-authorization": SBHSessionToken + } + + response = requests.get(collectionURL, headers=headers) + + # Check if the request was successful + if response.status_code == 200: + feature_doc = sbol2.Document() + feature_doc.readString(response.text) + FEATURE_LIBRARIES[collectionURL] = FeatureLibrary([feature_doc]) + print(f"all libraries: {FEATURE_LIBRARIES.keys()}") + + return {"response": response.text} + else: + print(f"Request failed with status code: {response.status_code}") + return {"response": response.text} + +@app.post("/api/deleteUserLibrary") +def remove_library(): + request_data = request.get_json() + collectionURL = request_data['url'] + + if FEATURE_LIBRARIES[collectionURL]: del FEATURE_LIBRARIES[collectionURL] + else: return {"response": "Library does not exist"} + + print(f"\nupdated libraries: {FEATURE_LIBRARIES.keys()}") + + return {"response": "Library successfully deleted"} + # if __name__ == '__main__': # app.run(debug=True,host='0.0.0.0',port=5000) if __name__ == "__main__": diff --git a/apps/web/src/components/CurationForm.jsx b/apps/web/src/components/CurationForm.jsx index 96f84ca..06071cd 100644 --- a/apps/web/src/components/CurationForm.jsx +++ b/apps/web/src/components/CurationForm.jsx @@ -43,7 +43,7 @@ function SynBioHubClient({opened, onClose, setIsInteractingWithSynBioHub, synBio ); } -function SynBioHubClientLogin({ synBioHubs }) { +export function SynBioHubClientLogin({ synBioHubs }) { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [inputError, setInputError] = useState(false); @@ -62,7 +62,15 @@ function SynBioHubClientLogin({ synBioHubs }) { data={synBioHubs} onChange={(v) => { setWorkingSynBioHubUrlPrefix(v); - }} + }} + searchable + creatable + getCreateLabel={(query) => `Custom SBH: ${query}`} + onCreate={(query) => { + const item = { value: query, label: query }; + synBioHubs.push(query) + return item; + }} /> { const response = await fetch("https://wor.synbiohub.org/instances"); const registries = await response.json(); - setSynBioHubs(registries.map(r => r.uriPrefix)); + if (localStorage.getItem("synBioHubs")) setSynBioHubs(JSON.parse(localStorage.getItem("synBioHubs"))) + else setSynBioHubs(registries.map(r => r.uriPrefix)); }; function isValid(sequence) { diff --git a/apps/web/src/components/SequenceSection.jsx b/apps/web/src/components/SequenceSection.jsx index d29dd6a..007a602 100644 --- a/apps/web/src/components/SequenceSection.jsx +++ b/apps/web/src/components/SequenceSection.jsx @@ -1,7 +1,7 @@ import { useState, useEffect, forwardRef, createElement } from "react" import { useForceUpdate } from "@mantine/hooks" -import { Checkbox } from '@mantine/core'; -import { Button, Center, Group, Loader, NavLink, Space, CopyButton, ActionIcon, Tooltip, Textarea, MultiSelect, Text, Highlight} from "@mantine/core" +import { Checkbox, CloseButton, Flex, Grid, SegmentedControl, Select, Title } from '@mantine/core'; +import { Button, Center, Group, Stack, Loader, Modal, NavLink, Space, CopyButton, ActionIcon, Tooltip, Textarea, MultiSelect, Text, Highlight} from "@mantine/core" import { FiDownloadCloud } from "react-icons/fi" import { FaCheck, FaPencilAlt, FaPlus, FaTimes, FaArrowRight } from "react-icons/fa" import { mutateDocument, mutateSequencePartLibrariesSelected, useAsyncLoader, useStore } from "../modules/store" @@ -9,9 +9,12 @@ import AnnotationCheckbox from "./AnnotationCheckbox" import FormSection from "./FormSection" import SequenceHighlighter from "./SequenceHighlighter" import { Copy, Check } from "tabler-icons-react" -import { showErrorNotification } from '../modules/util' +import { showErrorNotification, showNotificationSuccess } from "../modules/util" import "../../src/sequence-edit.css" import { HighlightWithinTextarea } from 'react-highlight-within-textarea' +import { openConfirmModal, openContextModal } from "@mantine/modals" +import { SynBioHubClientLogin } from "./CurationForm"; +import { importLibrary } from "../modules/api"; const WORDSIZE = 8; @@ -143,21 +146,7 @@ function Sequence({ colors }) { } style={{ maxWidth: "800px" }} > - {workingSequence !== false ? //TextArea is the editor // TODO: add highlight in TextArea - //