From 00c5830fd057633d735e75cd25f830937e68c935 Mon Sep 17 00:00:00 2001 From: Ryan Greer Date: Wed, 3 Jul 2024 16:56:06 -0600 Subject: [PATCH 1/6] added sbol object for subcomponents in exported xml --- apps/web/src/modules/api.js | 3 +++ apps/web/src/modules/sbol.js | 12 ++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/web/src/modules/api.js b/apps/web/src/modules/api.js index 7dc74b6..e1ae7b5 100644 --- a/apps/web/src/modules/api.js +++ b/apps/web/src/modules/api.js @@ -126,6 +126,8 @@ export async function fetchAnnotateSequence({ sbolContent, selectedLibraryFileNa const annDoc = new SBOL2GraphView(new Graph()); await annDoc.loadString(sbolAnnotated); + // console.log("annDoc rootcomponentdefinitions: " + annDoc.rootComponentDefinitions[0].sequenceAnnotations[1].component.displayName) + // concatenate new annotations to result annotations = annotations.concat(annDoc.rootComponentDefinitions[0].sequenceAnnotations // filter annotations already in original document @@ -135,6 +137,7 @@ export async function fetchAnnotateSequence({ sbolContent, selectedLibraryFileNa name: sa.displayName, id: sa.persistentIdentity, location: [sa.rangeMin, sa.rangeMax], + componentInstance: sa.component, featureLibrary: partLibrary, }))); })(); diff --git a/apps/web/src/modules/sbol.js b/apps/web/src/modules/sbol.js index 534fa56..6bf4218 100644 --- a/apps/web/src/modules/sbol.js +++ b/apps/web/src/modules/sbol.js @@ -1,5 +1,5 @@ import { set } from "lodash" -import { Graph, S2ComponentDefinition, SBOL2GraphView } from "sbolgraph" +import { Graph, S2ComponentDefinition, S2ComponentInstance, SBOL2GraphView } from "sbolgraph" import { TextBuffer } from "text-ranger" import { mutateDocument, useAsyncLoader, useStore } from "./store" @@ -157,13 +157,21 @@ export function hasSequenceAnnotation(componentDefinition, annotationId) { * id: string, * name: string, * location: number[], + * componentInstance: S2ComponentInstance, * }} annoInfo */ export function addSequenceAnnotation(componentDefinition, annoInfo) { + console.log("annoInfo:" + annoInfo.componentInstance.displayName) + if (hasSequenceAnnotation(componentDefinition, annoInfo.id)) return - const sa = componentDefinition.annotateRange(annoInfo.location[0], annoInfo.location[1], annoInfo.name) + // const sa = componentDefinition.annotateRange(annoInfo.location[0], annoInfo.location[1], annoInfo.name) + // sa.persistentIdentity = annoInfo.id + // sa.name = annoInfo.name + + + const sa = componentDefinition.addSequenceAnnotationForComponent(annoInfo.componentInstance) sa.persistentIdentity = annoInfo.id sa.name = annoInfo.name } From 84d4951a121656101dce87b71f8463cdabaeec2e Mon Sep 17 00:00:00 2001 From: Ryan Greer Date: Mon, 8 Jul 2024 13:21:55 -0600 Subject: [PATCH 2/6] annotation checkboxes are checked by default --- apps/web/src/components/SequenceSection.jsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/web/src/components/SequenceSection.jsx b/apps/web/src/components/SequenceSection.jsx index 148bd45..4ff1c41 100644 --- a/apps/web/src/components/SequenceSection.jsx +++ b/apps/web/src/components/SequenceSection.jsx @@ -263,6 +263,11 @@ function Annotations({ colors }) { const [sequencePartLibrariesSelected, setSequencePartLibrariesSelected] = useState([]); + // check all anno boxes by default + useEffect(() => { + annotations.forEach(anno => setActive(anno.id, true)); + }, [annotations, setActive]); + const AnnotationCheckboxContainer = forwardRef((props, ref) => (
From f3474420d62b55bf5a4e39ffe0e5cfff9ccd3681 Mon Sep 17 00:00:00 2001 From: Ryan Greer Date: Wed, 10 Jul 2024 17:33:27 -0600 Subject: [PATCH 3/6] decoupled annotation checkboxes from direct document modification --- apps/web/src/components/SequenceSection.jsx | 6 -- apps/web/src/modules/api.js | 7 ++- apps/web/src/modules/sbol.js | 69 ++++++++++++++------- apps/web/src/modules/store.js | 64 ++++++++++--------- 4 files changed, 86 insertions(+), 60 deletions(-) diff --git a/apps/web/src/components/SequenceSection.jsx b/apps/web/src/components/SequenceSection.jsx index 4ff1c41..150a3cd 100644 --- a/apps/web/src/components/SequenceSection.jsx +++ b/apps/web/src/components/SequenceSection.jsx @@ -263,10 +263,6 @@ function Annotations({ colors }) { const [sequencePartLibrariesSelected, setSequencePartLibrariesSelected] = useState([]); - // check all anno boxes by default - useEffect(() => { - annotations.forEach(anno => setActive(anno.id, true)); - }, [annotations, setActive]); const AnnotationCheckboxContainer = forwardRef((props, ref) => (
@@ -315,8 +311,6 @@ function Annotations({ colors }) { // mutate the libraries Selected in the store mutateSequencePartLibrariesSelected(useStore.setState, state => { if(chosenLibraries.some(item => item.value === 'local_libraries')) { - console.log(true) - state.sequencePartLibrariesSelected = chosenLibraries.filter(item => item.value !== 'local_libraries') state.sequencePartLibrariesSelected.push(...localLibraries) } diff --git a/apps/web/src/modules/api.js b/apps/web/src/modules/api.js index e1ae7b5..365d078 100644 --- a/apps/web/src/modules/api.js +++ b/apps/web/src/modules/api.js @@ -119,14 +119,14 @@ export async function fetchAnnotateSequence({ sbolContent, selectedLibraryFileNa .map(sa => sa.persistentIdentity); let annotations = []; + const annDoc = new SBOL2GraphView(new Graph()); await Promise.all(annoLibsAssoc.map(([ sbolAnnotated, partLibrary ]) => { return (async () => { // create and load annotated doc - const annDoc = new SBOL2GraphView(new Graph()); + // const annDoc = new SBOL2GraphView(new Graph()); await annDoc.loadString(sbolAnnotated); - // console.log("annDoc rootcomponentdefinitions: " + annDoc.rootComponentDefinitions[0].sequenceAnnotations[1].component.displayName) // concatenate new annotations to result annotations = annotations.concat(annDoc.rootComponentDefinitions[0].sequenceAnnotations @@ -139,11 +139,12 @@ export async function fetchAnnotateSequence({ sbolContent, selectedLibraryFileNa location: [sa.rangeMin, sa.rangeMax], componentInstance: sa.component, featureLibrary: partLibrary, + enabled: true, }))); })(); })); - return annotations; + return { fetchedAnnotations: annotations, synbictDoc: annDoc }; } export async function fetchAnnotateText(text) { diff --git a/apps/web/src/modules/sbol.js b/apps/web/src/modules/sbol.js index 6bf4218..3a7ae17 100644 --- a/apps/web/src/modules/sbol.js +++ b/apps/web/src/modules/sbol.js @@ -123,7 +123,7 @@ Object.defineProperties(S2ComponentDefinition.prototype, { * @return {SBOL2GraphView} */ export async function createSBOLDocument(sbolContent) { - const document = new SBOL2GraphView(new Graph()); + let document = new SBOL2GraphView(new Graph()); await document.loadString(sbolContent); // initialize rich description as regular description if one doesn't exist @@ -139,12 +139,19 @@ export async function createSBOLDocument(sbolContent) { * by the passed annotation ID. * * @export - * @param {S2ComponentDefinition} componentDefinition + * @param {array} sequenceAnnotations * @param {string} annotationId * @return {boolean} */ -export function hasSequenceAnnotation(componentDefinition, annotationId) { - return !!componentDefinition.sequenceAnnotations.find(sa => sa.persistentIdentity == annotationId) +// export function hasSequenceAnnotation(componentDefinition, annotationId) { +// // console.log(!!componentDefinition.sequenceAnnotations.find(sa => sa.persistentIdentity == annotationId))/ +// return !!componentDefinition.sequenceAnnotations.find(sa => sa.persistentIdentity == annotationId) +// } + +export function hasSequenceAnnotation(sequenceAnnotations, annotationId) { + const anno = sequenceAnnotations.find((sa) => sa.id == annotationId) + + return anno.enabled } /** @@ -152,7 +159,7 @@ export function hasSequenceAnnotation(componentDefinition, annotationId) { * to the passed ComponentDefinition. * * @export - * @param {S2ComponentDefinition} componentDefinition + * @param {array} sequenceAnnotations * @param {{ * id: string, * name: string, @@ -160,20 +167,32 @@ export function hasSequenceAnnotation(componentDefinition, annotationId) { * componentInstance: S2ComponentInstance, * }} annoInfo */ -export function addSequenceAnnotation(componentDefinition, annoInfo) { - console.log("annoInfo:" + annoInfo.componentInstance.displayName) +// export function addSequenceAnnotation(componentDefinition, annoInfo) { +// // console.log("annoInfo:" + annoInfo.componentInstance.displayName) - if (hasSequenceAnnotation(componentDefinition, annoInfo.id)) - return +// if (hasSequenceAnnotation(componentDefinition, annoInfo.id)) +// return + +// const component = componentDefinition.addComponent(annoInfo.componentInstance) + +// const sa = componentDefinition.annotateRange(annoInfo.location[0], annoInfo.location[1], annoInfo.name) +// sa.component = annoInfo.componentInstance +// sa.persistentIdentity = annoInfo.id +// sa.name = annoInfo.name +// // new implmentation: +// // take the sbol xml from synbict, check all by default +// // only remove sequence annotation(and associated components) if components are unchecked in seqimprove - // const sa = componentDefinition.annotateRange(annoInfo.location[0], annoInfo.location[1], annoInfo.name) - // sa.persistentIdentity = annoInfo.id - // sa.name = annoInfo.name +// // THIS MUST HAPPEN WHEN THE DOCUMENT IS EXPORTED, NO MORE EDITING THE SBOLGRAPH DOC + XML STRING ON STATE UPDATES +// } - const sa = componentDefinition.addSequenceAnnotationForComponent(annoInfo.componentInstance) - sa.persistentIdentity = annoInfo.id - sa.name = annoInfo.name +export function addSequenceAnnotation(sequenceAnnotations, annotationId) { + if (hasSequenceAnnotation(sequenceAnnotations, annotationId)) return + + let annoIndex = sequenceAnnotations.findIndex((sa) => sa.id == annotationId) + + return annoIndex } /** @@ -181,15 +200,23 @@ export function addSequenceAnnotation(componentDefinition, annoInfo) { * ComponentDefinition. * * @export - * @param {S2ComponentDefinition} componentDefinition + * @param {array} sequenceAnnotations * @param {{string}} id */ -export function removeSequenceAnnotation(componentDefinition, { id }) { - if (!hasSequenceAnnotation(componentDefinition, id)) - return +// export function removeSequenceAnnotation(componentDefinition, { id }) { +// if (!hasSequenceAnnotation(componentDefinition, id)) +// return - const annotation = componentDefinition.sequenceAnnotations.find(sa => sa.persistentIdentity == id) - annotation.destroy() +// const annotation = componentDefinition.sequenceAnnotations.find(sa => sa.persistentIdentity == id) +// annotation.destroy() +// } + +export function removeSequenceAnnotation(sequenceAnnotations, annotationId) { + if (!hasSequenceAnnotation(sequenceAnnotations, annotationId)) return + + let annoIndex = sequenceAnnotations.findIndex((sa) => sa.id == annotationId) + + return annoIndex } diff --git a/apps/web/src/modules/store.js b/apps/web/src/modules/store.js index 0bfc8ad..88cf5cc 100644 --- a/apps/web/src/modules/store.js +++ b/apps/web/src/modules/store.js @@ -188,11 +188,13 @@ export const useStore = create((set, get) => ({ set({ loadingSequenceAnnotations: true }); try { - const fetchedAnnotations = await fetchAnnotateSequence({ + const result = await fetchAnnotateSequence({ sbolContent: get().document.serializeXML(), selectedLibraryFileNames: get().sequencePartLibrariesSelected.map(lib => lib.value), }) ?? []; + let { fetchedAnnotations, synbictDoc } = result; + set({ sequenceAnnotations: produce(get().sequenceAnnotations, draft => { fetchedAnnotations.forEach(anno => { @@ -202,7 +204,8 @@ export const useStore = create((set, get) => ({ } }); }), - loadingSequenceAnnotations: false + loadingSequenceAnnotations: false, + document: synbictDoc, }); } catch (err) { showErrorNotification("Load Error", "Could not load sequence annotations"); @@ -230,34 +233,34 @@ export const useStore = create((set, get) => ({ sequenceAnnotationActions: createAnnotationActions(set, get, state => state.sequenceAnnotations, { test: hasSequenceAnnotation, - add: async (...args) => { - addSequenceAnnotation(...args); - - let xml = get().document.serializeXML(); - let xmlChunks = []; - let matchData = xml.match(/\=\"https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//= ]*)"/); - - while (matchData) { - xmlChunks.push(xml.slice(0, matchData.index)); - const uri = matchData[0]; - const validURI = uri.replace(/ /g, '') - xmlChunks.push(validURI); + add: (...args) => { + const index = addSequenceAnnotation(...args); - xml = xml.slice(matchData.index + uri.length); - matchData = xml.match(/\=\"https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//= ]*)"/); - } - xml = xmlChunks.concat(xml).join(''); - const sequenceAnnotations = get().sequenceAnnotations; - - try { - var document = await createSBOLDocument(xml); - } catch (err) { - console.error(err); - throw err; - } - set({ document }); + set({ + sequenceAnnotations: produce(get().sequenceAnnotations, draft => { + args[0].forEach(anno => { + if (!draft.find(a => a.id == anno.id)) { + draft.push(anno) + } + }); + draft[index].enabled = true + }), + }); + }, + remove: (...args) => { + const index = removeSequenceAnnotation(...args); + + set({ + sequenceAnnotations: produce(get().sequenceAnnotations, draft => { + args[0].forEach(anno => { + if (!draft.find(a => a.id == anno.id)) { + draft.push(anno) + } + }); + draft[index].enabled = false + }), + }); }, - remove: removeSequenceAnnotation, }), @@ -470,10 +473,11 @@ function createAnnotationActions(set, get, selector, { test, add, remove } = {}) const getAnnotation = id => selector(get()).find(anno => anno.id == id) - const isActive = id => test(get().document.root, id) + const isActive = id => test(get().sequenceAnnotations, id) const setActive = (id, value) => { mutateDocument(set, state => { - (value ? add : remove)(state.document.root, getAnnotation(id)) + // (value ? add : remove)(state.document.root, getAnnotation(id)) + (value ? add : remove)(get().sequenceAnnotations, id) }) } From 17e661e3444a5b8bb2b386a1cb23948ddf1ba1e0 Mon Sep 17 00:00:00 2001 From: Ryan Greer Date: Thu, 11 Jul 2024 14:16:18 -0600 Subject: [PATCH 4/6] fixed bug where running sequence analyzer twice would add duplicate annotations --- apps/web/src/modules/api.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/modules/api.js b/apps/web/src/modules/api.js index 365d078..d653dba 100644 --- a/apps/web/src/modules/api.js +++ b/apps/web/src/modules/api.js @@ -116,7 +116,7 @@ export async function fetchAnnotateSequence({ sbolContent, selectedLibraryFileNa // make a list of persistentIds to avoid const originalAnnotations = originalDoc.rootComponentDefinitions[0].sequenceAnnotations - .map(sa => sa.persistentIdentity); + .map(sa => sa.persistentIdentity.slice(0, -2)) //synbict increments a number at the end of the persistent identities, so we cut off the last 2 chars to compare let annotations = []; const annDoc = new SBOL2GraphView(new Graph()); @@ -131,7 +131,7 @@ export async function fetchAnnotateSequence({ sbolContent, selectedLibraryFileNa // concatenate new annotations to result annotations = annotations.concat(annDoc.rootComponentDefinitions[0].sequenceAnnotations // filter annotations already in original document - .filter(sa => !originalAnnotations.includes(sa.persistentIdentity)) + .filter(sa => !originalAnnotations.includes(sa.persistentIdentity.slice(0, -2))) // just return the info we need .map(sa => ({ name: sa.displayName, From 03950fbc238b4db1d67219e824dd17c198cee84e Mon Sep 17 00:00:00 2001 From: Ryan Greer Date: Fri, 12 Jul 2024 16:53:28 -0600 Subject: [PATCH 5/6] added full functionality for adding/removing annotations --- apps/web/src/modules/sbol.js | 111 +++++++++++++++++++--------------- apps/web/src/modules/store.js | 22 ++++++- 2 files changed, 84 insertions(+), 49 deletions(-) diff --git a/apps/web/src/modules/sbol.js b/apps/web/src/modules/sbol.js index 3a7ae17..9a552cb 100644 --- a/apps/web/src/modules/sbol.js +++ b/apps/web/src/modules/sbol.js @@ -135,19 +135,13 @@ export async function createSBOLDocument(sbolContent) { } /** - * Checks if the passed ComponentDefinition contains the sequence annotation specified - * by the passed annotation ID. + * Return the active status of any annotation in the sequenceAnnotations array * * @export * @param {array} sequenceAnnotations * @param {string} annotationId * @return {boolean} */ -// export function hasSequenceAnnotation(componentDefinition, annotationId) { -// // console.log(!!componentDefinition.sequenceAnnotations.find(sa => sa.persistentIdentity == annotationId))/ -// return !!componentDefinition.sequenceAnnotations.find(sa => sa.persistentIdentity == annotationId) -// } - export function hasSequenceAnnotation(sequenceAnnotations, annotationId) { const anno = sequenceAnnotations.find((sa) => sa.id == annotationId) @@ -155,38 +149,13 @@ export function hasSequenceAnnotation(sequenceAnnotations, annotationId) { } /** - * Adds a sequence annotation with the information from the passed annotation object - * to the passed ComponentDefinition. - * + * Returns the index of an annotation with the specified id + * * @export * @param {array} sequenceAnnotations - * @param {{ - * id: string, - * name: string, - * location: number[], - * componentInstance: S2ComponentInstance, - * }} annoInfo + * @param {string} annotationId + * @return {boolean} */ -// export function addSequenceAnnotation(componentDefinition, annoInfo) { -// // console.log("annoInfo:" + annoInfo.componentInstance.displayName) - -// if (hasSequenceAnnotation(componentDefinition, annoInfo.id)) -// return - -// const component = componentDefinition.addComponent(annoInfo.componentInstance) - -// const sa = componentDefinition.annotateRange(annoInfo.location[0], annoInfo.location[1], annoInfo.name) -// sa.component = annoInfo.componentInstance -// sa.persistentIdentity = annoInfo.id -// sa.name = annoInfo.name -// // new implmentation: -// // take the sbol xml from synbict, check all by default -// // only remove sequence annotation(and associated components) if components are unchecked in seqimprove - -// // THIS MUST HAPPEN WHEN THE DOCUMENT IS EXPORTED, NO MORE EDITING THE SBOLGRAPH DOC + XML STRING ON STATE UPDATES - -// } - export function addSequenceAnnotation(sequenceAnnotations, annotationId) { if (hasSequenceAnnotation(sequenceAnnotations, annotationId)) return @@ -196,21 +165,13 @@ export function addSequenceAnnotation(sequenceAnnotations, annotationId) { } /** - * Removes the sequence annotation matching the passed annotation ID from the passed - * ComponentDefinition. - * + * Returns the index of an annotation with the specified id + * * @export * @param {array} sequenceAnnotations - * @param {{string}} id + * @param {string} annotationId + * @return {boolean} */ -// export function removeSequenceAnnotation(componentDefinition, { id }) { -// if (!hasSequenceAnnotation(componentDefinition, id)) -// return - -// const annotation = componentDefinition.sequenceAnnotations.find(sa => sa.persistentIdentity == id) -// annotation.destroy() -// } - export function removeSequenceAnnotation(sequenceAnnotations, annotationId) { if (!hasSequenceAnnotation(sequenceAnnotations, annotationId)) return @@ -219,6 +180,60 @@ export function removeSequenceAnnotation(sequenceAnnotations, annotationId) { return annoIndex } +/** + * Return the active status of any annotation in the sequenceAnnotations array + * + * @export + * @param {array} sequenceAnnotations + * @param {string} annotationId + * @return {boolean} + */ +export function hasSequenceAnnotationSBOL(componentDefinition, annotationId) { + return !!componentDefinition.sequenceAnnotations.find(sa => sa.persistentIdentity == annotationId) +} + +/** + * Removes any duplicate annotation and its associated component instance from SBOL document + * + * @export + * @param {S2ComponentDefinition} componentDefinition + * @param {array} sequenceAnnotations + */ +export function removeDuplicateComponentAnnotation(componentDefinition, id) { + console.log(id) + if (!hasSequenceAnnotationSBOL(componentDefinition, id)) + return + + + const annotation = componentDefinition.sequenceAnnotations.find(sa => sa.persistentIdentity == id) + const associatedComponent = annotation.component + + annotation.destroy() + associatedComponent.destroy() +} + +/** + * Removes annotation, component instance, component definition, and associated sequence from SBOL document + * + * @export + * @param {S2ComponentDefinition} componentDefinition + * @param {array} sequenceAnnotations + */ +export function removeAnnotationWithDefinition(componentDefinition, id) { + console.log(id) + if (!hasSequenceAnnotationSBOL(componentDefinition, id)) + return + + const annotation = componentDefinition.sequenceAnnotations.find(sa => sa.persistentIdentity == id) + const associatedComponent = annotation.component + const definition = associatedComponent.definition + const sequences = definition.sequences + + sequences[0].destroy() + annotation.destroy() + associatedComponent.destroy() + definition.destroy() +} /** * Finds existing SequenceAnnotations on a ComponentDefinition and returns diff --git a/apps/web/src/modules/store.js b/apps/web/src/modules/store.js index 88cf5cc..ee0487b 100644 --- a/apps/web/src/modules/store.js +++ b/apps/web/src/modules/store.js @@ -2,7 +2,7 @@ import _, { remove } from "lodash" import create from "zustand" import produce from "immer" import { getSearchParams, showErrorNotification } from "./util" -import { addSequenceAnnotation, addTextAnnotation, createSBOLDocument, getExistingSequenceAnnotations, hasSequenceAnnotation, hasTextAnnotation, parseTextAnnotations, removeSequenceAnnotation, removeTextAnnotation } from "./sbol" +import { addSequenceAnnotation, addTextAnnotation, createSBOLDocument, getExistingSequenceAnnotations, hasSequenceAnnotation, hasTextAnnotation, parseTextAnnotations, removeAnnotationWithDefinition, removeDuplicateComponentAnnotation, removeSequenceAnnotation, removeTextAnnotation } from "./sbol" import { fetchAnnotateSequence, fetchAnnotateText, fetchSBOL } from "./api" import { SBOL2GraphView } from "sbolgraph" import fileDownload from "js-file-download" @@ -146,6 +146,26 @@ export const useStore = create((set, get) => ({ // } // }), exportDocument: (download = true) => { + const annotations = get().sequenceAnnotations + + //remove duplicate annotation and component instance + for (const rootAnno of get().document.root.sequenceAnnotations) { + console.log(rootAnno.persistentIdentity) + for (const anno of annotations) { + if (rootAnno.persistentIdentity && (anno.id.slice(0, -2) === rootAnno.persistentIdentity.slice(0, -2) && rootAnno.persistentIdentity.slice(-1) >= 2)) { //potential bug: persistentIdentities may match but locations are different. The second instance will be removed if the part appears multiple times in the sequence + console.log("duplicate: " + rootAnno.persistentIdentity) + removeDuplicateComponentAnnotation(get().document.root, rootAnno.persistentIdentity) + } + } + } + + + //if disabled(in annos array but enabled=false), REMOVE: component & sequence annotation (children of root component definition), component definition, associated sequence + for (const anno of annotations) { + console.log(anno.id + " enabled=" + anno.enabled) + if (!anno.enabled) removeAnnotationWithDefinition(get().document.root, anno.id) + } + const xml = get().document.serializeXML(); if (download) { From ee9ed071d9925a157c8bf0d3d011240b39e2d935 Mon Sep 17 00:00:00 2001 From: Ryan Greer Date: Fri, 12 Jul 2024 17:06:04 -0600 Subject: [PATCH 6/6] comment --- apps/web/src/modules/sbol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/modules/sbol.js b/apps/web/src/modules/sbol.js index 9a552cb..ccf5535 100644 --- a/apps/web/src/modules/sbol.js +++ b/apps/web/src/modules/sbol.js @@ -184,7 +184,7 @@ export function removeSequenceAnnotation(sequenceAnnotations, annotationId) { * Return the active status of any annotation in the sequenceAnnotations array * * @export - * @param {array} sequenceAnnotations + * @param {S2ComponentDefinition} componentDefinition * @param {string} annotationId * @return {boolean} */