From 816ff2f6e2da9020cf04cb9429139f8d120f2026 Mon Sep 17 00:00:00 2001 From: anna-parker <50943381+anna-parker@users.noreply.github.com> Date: Thu, 4 Dec 2025 11:01:36 +0100 Subject: [PATCH 01/14] feat(website): do not include fasta description in fastaId on website edit page --- .../src/components/Submission/FileUpload/fileProcessing.spec.ts | 2 +- website/src/components/Submission/FileUpload/fileProcessing.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/src/components/Submission/FileUpload/fileProcessing.spec.ts b/website/src/components/Submission/FileUpload/fileProcessing.spec.ts index 96a5e0223a..d1ac95539f 100644 --- a/website/src/components/Submission/FileUpload/fileProcessing.spec.ts +++ b/website/src/components/Submission/FileUpload/fileProcessing.spec.ts @@ -70,7 +70,7 @@ describe('fileProcessing', () => { }); test('Plain segment file content is extracted correctly', async () => { - const dummyFile = new File(['>fooid\nACTG\n\nACTG\nACTG\n'], 'example.fasta', { type: 'text/plain' }); + const dummyFile = new File(['>fooid description\nACTG\n\nACTG\nACTG\n'], 'example.fasta', { type: 'text/plain' }); const result = await PLAIN_SEGMENT_KIND.processRawFile(dummyFile); if (result.isErr()) { fail(`result was error: ${result._unsafeUnwrapErr().message}`); diff --git a/website/src/components/Submission/FileUpload/fileProcessing.ts b/website/src/components/Submission/FileUpload/fileProcessing.ts index b28ee15c48..ecefec3184 100644 --- a/website/src/components/Submission/FileUpload/fileProcessing.ts +++ b/website/src/components/Submission/FileUpload/fileProcessing.ts @@ -94,7 +94,7 @@ export const PLAIN_SEGMENT_KIND: FileKind = { new Error(`Found ${headerLines.length} headers in uploaded file, only a single header is allowed.`), ); } - const header = headerLines.length === 1 ? headerLines[0].substring(1).trim() : null; + const header = headerLines.length === 1 ? headerLines[0].substring(1).trim().split(/\s+/)[0] : null; const segmentData = lines .filter((l) => !l.startsWith('>')) .map((l) => l.trim()) From 7da848fc32655d2a8f9e687730c86661d8c7e715 Mon Sep 17 00:00:00 2001 From: anna-parker <50943381+anna-parker@users.noreply.github.com> Date: Thu, 4 Dec 2025 11:04:04 +0100 Subject: [PATCH 02/14] add description to integration tests for good measure --- integration-tests/tests/test-data/cchfv_test_sequences.fasta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/tests/test-data/cchfv_test_sequences.fasta b/integration-tests/tests/test-data/cchfv_test_sequences.fasta index 2406f4adf4..606166f744 100644 --- a/integration-tests/tests/test-data/cchfv_test_sequences.fasta +++ b/integration-tests/tests/test-data/cchfv_test_sequences.fasta @@ -1,4 +1,4 @@ ->test_NIHPAK-19_L +>test_NIHPAK-19_L description to be ignored CCACATTGACACAGANAGCTCCAGTAGTGGTTCTCTGTCCTTATTAAACCATGGACTTCTTAAGAAACCTTGACTGGACTCAGGTGATTGCTAGTCAGTATGTGACCAATCCCAGGTTTAATATCTCTGATTACTTCGAGATTGTTCGACAGCCTGGTGACGGGAACTGTTTCTACCACAGTATAGCTGAGTTAACCATGCCCAACAAAACAGATCACTCATACCATAACATCAAACATCTGACTGAGGTGGCAGCACGGAAGTATTATCAGGAGGAGCCGGAGGCTAAGCTCATTGGCCTGAGTCTGGAAGACTATCTTAAGAGGATGCTATCTGACAACGAATGGGGATCGACTCTTGAGGCATCTATGTTGGCTAAGGAAATGGGTATTACTATCATCATTTGGACTGTTGCAGCCAGTGACGAAGTGGAAGCAGGCATAAAGTTTGGTGATGGTGATGTGTTTACAGCCGTGAATCTTCTGCACTCCGGACAGACACACTTTGATGCCCTCAGAATACTGCCNCANTTTGAGGCTGACACAAGAGAGNCCTTNAGTCTGGTAGACAANNTNATAGCTGTGGACCANNTGACCTCNTCTTCAAGTGATGAANTGCAGGACTANGAAGANCTTGCTTTAGCACTTACNAGNGCGGAAGAACCATNTAGACGGTCTAGCNTGGATGAGGTNACCCTNTCTAAGAAACAAGCAGAGNTATTGAGGCAGAAGGCATCTCAGTTGTCNAAACTGGTTAATAAAAGTCAGAACATACCGACTAGAGTTGGCAGGGTTCTGGACTGTATGTTTAACTGCAAACTATGTGTTGAAATATCAGCTGACACTCTAATTCTGCGACCAGAATCTAAAGAAAGAATTGGTGAAGTTATGTCGTTGCGACAGCTAGGTCACAAATTGCTAACACGAGATAAACAAATTAAGCAGGAGTTCTCTAGAATGAAGCTCTATGTTACCAAAGATCTGCTTGANCATCTNGATGTTGGTGGGNTNTTNAGAGCAGCCTTCCCTGGAACAGGGATAGANAGACATATGCAGNTGNTACANTCTGAAATGATACTGGACATTTGTACNGTNTCACTTGGCGTCATGTTATCAACATTCTTATACGGCTCTAACAACAAAAACAAGAAAAAATTCATCACCAACTGCTTGCTTAGCACAGCCNTGTCTGGNAAGAAGGTGTACAAGGTTCTTGGTAACTTAGGNAATGAACTGTTNTATAANGCACCNAGAAAGGCCTTNGCAACCGTCTGTNGTGCNCTNTTTGGNAAACANNTAAACAAGCTTCAGAACTGCTTCAGGACTATAAGTCCTGTTAGCCTGCTTGCACTAAGAAACCTGGACTTTGACTGTCTTAGTGTGCAAGACTACAATGGTATGATAGAAAATATGTCCAAATTGGACAACACAGATGTTGAATTCAACCACAGAGAAATAGCCGATCTCAACCAGTTAACTTCTCGGCTTATCACATTGAGGAAAGAGAAAGACACTGATCTCCTCAAGCAATGGTTTCCTGAGGGTGATCTCACTCGTAGAAGCACCAGGAACGTTGCAAATGCAGAAGAATTTGTCATATCTGAATTCTTTAAGAGGAAAGACATTATGAAGTTTATCAGCACCTCAGGAAGAGCAATGAGTGCAGGCAAAATTGGTAATGTCCTTTCCTATGCACATAACCTTTATTTGAGCAAGTCTAGCCTAAACATGACTTCTGAAGATATTTCACAGCTTCTAATCGAGATTAAGAGGCTGTATGCTCTACAAGAAGATTCTGAAGTAGAGCCAATAGCCATAATTTGTGATGGCATTGAGAGCAACATGAAGCAGTTATTTGCTATATTNCCTCCNGACTGTGCAAGAGAGTGNGANGTTCTCTTTGATGACATAAGAAANTCTCCAACGCACAGTACAGCNTGGAAGCATGCCCTTCGATTAAAGGGNACNGCATATGAGGGTNTNTTTGCCAACTGNTATGGATGGCANTANATCCCGGAAGACATTAAACCAAGCTTGACCATGTTGATACAGACATTGTTCCCTGACAAATTTGAAGATTTTTTGGACCGAACTCAATTACATCCAGAGTTCAGAGATTTAACTCCTGACTTTTCGCTTACACAAAAGGTTCATTTCAAAAGGAATCAGATACCCAGTGTTGAAAACGTTCAGATCTCCATAGATGCATCATTGCCTGAATCTGTGGAGGCAGTGCCAGTGACAGAAAGGAAAATGTTCCCCCTACCTGAGACTCCATTAAGTGAGGTACATTCAATAGAGCGCATCATGGAAAATTTCACTCGCCTCATGCATGAAGGAAAGCCTTCAACCAAGAGAAAAGATGAAGATTCAACAGAACAGAACGGTCAGCAGAATACTGCTGAACATGAGAGTTCAAGCATCTTGACTTTTAAGGACTATGGAGAGAGGGGAATAGTTGAGGAGAATCACATGAGGTTCAGTGAAGAGGATCAGCTGGAAACNAGNCAGTTGTTGTTGGTAGAAGTTGGTTTTCAAACTGANATTGATGGGAAAATAAGAACAGACCANAAAAAATGGAAAGATATATTAAAGCTGTTNGAGTTACTNGGAATNAAGTGCTCATTCATTGCCTGTGCTGACTGNTCGNCTACACCNCCAGACAGATGGTGGATTACTGAGGACAGAGTACGAGTCTTAAAGAACTCAGTCAGCTTTCTCTTCAACAAACTCTCCAGGAACTCACCTACAGAGGTTACTGACATAGTTGTTGGGGCCATAAGTACTCAAAAGGTTAGAAGTTACTTAAANGCAGGGACTGCNACAAAAACCCCTGTGTCAACNAAAGANGTTCTAGAGACTTGGGAAAGAATGAAAGANCATATACTTAACAGGCCNACAGGTTTNACACTNCCNNCCAGTTTGGAGCAGGCAATGCGCAAAGGANTAGTCGAGGGNGTGGTNATCTCCAAGGNGGGCTCTGAATCNTGCATNNANATGTTNAAGGAAAANTTGGACCGAATAACTGATGAATTTGAGCGGACGAAATTTAAACATGAGCTTACNCAGAATGTTACTACTNGTGAAAAGATGCTGTTAAGTTGGTTAAGTGAAGACATAAAATCATCGAGATGTAGTGAGTGTCTTGCTAATATAAAGAAAACTGTTGATGAGACTGCCAACCTATCAGAGAAGATCGAACTGCTTGCTTATAATTTGCAACTTACTAGTCACTGTGGTAACTGTCACCCCAACGGTGTGAACATTAGCAACATATCAAATGTATGCAAGAGGTGTCCCAAGATAGAAGTGGTCAGTCATTGTGAGAACAAAGGTTTTGAGGATAGCAATGAATGCTTAACAGACTTAGACAGACTTGTTAGACTCACATTACCGGGAAAAACTGAGAAAGAGAGAAGAGTCAAGCGTAATGTAGAATATCTGATAAAATTGATGATGAGCATGTCAGGCATCGACTGTATAAAGTATCCTACAGGACAGCTTATTACTCATGGNAGNGTAAGTGCAAAGCANAATGATGGAANCNTGAAAGATAGGAGTGATGACGACCAAAGACTNGCTGAGAAGANAGATACTGTNAGNAAAGAGCTTTCNGAAACNAANNTNAAAGANTATTCANCNTATGCAAGAGGNGTAATCTCAAATTCGCTAAAAAACCTCTCGAAGCAAGGCAAATCAAAGTGNTCTGTGCCAAGATCTTGGCTTGAAAAGATACTGTTTGACTTAAAAGTGCCCACTAAAGACGAAGAAGTGCTGATAAACATCAGGAATTCACTGAAGGCTAGATCTGAGTATGTTAGAAACAANGACAAACTACTNATAAGATCCAANGAAGAACTCAAAAAATGTTTCGATGCGCAGTCTTTTAAATTGATGAAAAACAAACAACCTGTGCCTTTTCANGTTGANTGTATACTGTTTAAGGAAGTGGCAGCAGAGTGCATGAAAAGATATATTGGCACACCTTATGAAGGAATTATAGANACTTTAGTNTCNTTAATCAATGTGTTAACAAGATTCACTTGGTTTCAGGANGTAGTGCTNTATGGTAAGATATGTGANACCTTCTTAAGGTGNTGCACNGAATTCAATAGATCAGGGGTTAAGCTAGTNAAGGTAAGNCACTGTGANATTAACNTATCAGTCAAGCTGCCATCAAACAAAAANGAGAANATGTTATGTTGNNTATACAGTAGTAACATGGAGCTCTTACANGGACCTTTCTANTTGAACAGGAGGCAAGCTGTCCTTGGCTCATCATACCTTTACATNGTCATTACGCTNTACATACAAGTGCTGCAGCAGTACAGGTGTCTAGAAGTCATAAATAGCGTGAATGAGAAAACATTGCAGGACATTGAAAATCACTCTATGACTCTGCTAGAAGATGCATTCAAAGAACTTACTTCTGCGCTTGAGGGTAGATTTGAAGAATCTTACAAAGTACGAACTTCAAGGTGCAAAGCTAGCGGAAATTTCTTAAACAGAAGCAGTAGAGACCACTTTATAAGTATTGTTTCAGGCTTAAACCTGGTTTATGGCTTCCTCATGAAAGATAACTTATTGGCCAACTCTCAGCAACAAAACAAACAACTTCAAATGCTTCGTTTTGGTATGCTTGCAGGGCTTAGTAGGCTTGTCTGTCCTAATGAGTTGGGAAAAAAGTTTTCAACAAGTTGTAGAAGAATTGAAGATAACATTGCAAGACTTTACTTACAAACGTCTATATACTGNTCAGTTAGAGATGTGGAAGANAATATCAAGCACTGGAAGCANAGAGANNTGTGCCCTGAAGTGACNATTCCATGTTTTACAGTCTATGGNACCTTTNTNAACAGCGACAGACAGCTGATTTTTGACATTTACAATGTGCATATATACAATAANGANATGGACAACTTTGACGAAGGATGTATCAGCGTCCTGGAAGAAACAGCAGAAAGGCANATGCTTTGGGAGCTTGATCTGATGAATTCACTCTGTTCTGACGAAAAAAGAGATGCTAGAACCGCAAGACTACTTTTGGGCTGCCCAAACGTGAGAAAAGCTGCGAATAAAGAAGGGAAAAAGCTGTTAAAGTTAAACAGCGATACATCCACTGACACACAAAGCGTTGCTTCTGAAGTGTCAGACAGGAGATCCTNTAGCTCAAGCAAGAGTAGAATTCGTAGTATTTTTGGAAGATACAATTCTCANAAAAAACCATTTGAACTAAGGTCAGGCCTCGAAGTCTTCAATGACCCTTTCAATGATTATCAGCAAGCAATAACAGATATTTGTCAATTTTCTGAGTACACACCAAACAAAGAAAGCATTCTGAAGGATTGCCTTCAAATCATACGGAAAAACCCCAGCCACACAATGGGCTCTTTTGAGTTGATCCAAGCAGTCTCAGAGTTTGGCATGAGTAAGTTTCCTCCCGAGAATATAGACAAGGCAAGGAGGGATCCAAAGAACTGGGTCAGCATCTCTGAAGTAACAGAGACAACAAGTATAGTCGCATCGCCTAAAACTCACATGATGCTAAAGGACTGCTTTAAAATCATACTGGGCACTGAGAATAAAAAAATAGTTAAAATGCTTCGAGGGAAGCTAAAGAAACTTGGTGCTATCACTACAAACATAGAGATCGGAAAAAGGGATTGCCTNGATCTACTCAGCACGGTTGACGGTCTAACAGATCAACAAAAAGAAAACATCGTGAATGGGATTTTCGAACCTTCAAAGCTGTCCTTCTACCATTGGAAAGAATTAGTCAAGAAAAGCATAGATGAGGTTCTGCTTACTGAGGATGGAAATCTAATCTTCTGCTGGTTAAAAACAATCTCATCCTCAGTTAAAGGAAGCTTGAAGAAAAGACTCAAGTTTATGAATATACATGCTCCAGAACTGATGCCAGAAAACTGTCTCTTTTCCAGCGAGGAGTTTAATGAGTTGATTAAGTTGAAGAAACTTCTCCTCAACGAACAACAAGATGAACAGGAGTTGAAGCAAGATCTTTTAATATCTTCTTGGATTAAGTGTATAATGGCTTGTAAGGACTTTGCTAGTATCAATGACAAGGTTCAAAAATTTATTTATCATCTGTCTGAAGAGCTATATAACATAAGGCTGCAACATCTGGAACTATCAAAGCTTAAGCAGGAGCATCCAAGTGTCAGCTTCACTAAGGAGGAGGTTTTAATAAAGCGGCTGGAGAAGAATTTCCTTAAGCAACACAATCTAGAAATTATGGAAACAGTAAACCTTATATTCTTTGCTGCACTTTCAGCTCCTTGGTGTCTACACTATAAAGCACTAGAATCTTATTTGGTAAGACATCCAGAGATACTCGACTGTGGTTCTAAGGAGGATTGTAGGCTCACTCTACTTGATCTGTCAGTTTCTAAACTATTAGTTTGTTTGTATCGAAAAGATGATGAGGAACTAACAAACAGCTCAAGTTTGAAACTNGGGTTNTTAGTGAANTATGCTNTCACCNTATTTACATCNAATGGNGAGCCTTTCTCACTTAGTCTGAACGACGGGGGTTTGGACCTTGATTTACACAAAACCACTGACGAGAAGTTGCTACATCAAACAAAGATAGTTTTTGCTAAGATTGGTCTGTCCGGGAACGGTTATGACTTCATCTGGACCACTCAAATGATAGCAAATAGCAACTTTAATGTCTGCAAAAGATTGACNGGAAGGAGTACNGGGGAAAGGCTTCCNAGAAGTGTCAGGAGCAAGGTCATTTATGAAATGGTAAAACTGGTAGGAGAAACAGGCATGGCAATATTGCAACAGTTAGCTTTTGCACAGGCACTAAATTATGAACACCGNTTTTATGCAGTTTTAGCACCTAAAGCACAGCTAGGAGGAGCAAGAGATCTGTTAGTGCAGGAAACTGGCACTAAAGTCATGCATGCAACTACTGAAATGTTCAGTAGAAACCTCTTAAAGACAACATCAGANGACGGCCTTACAAACCCACATCTTAAAGAGNCAATCCTTAATGTGGGATTGGACTGTCTTACCAATATGCGAAACCTTGACGGAAAGCCCATAAGTGAAGGTAGCAACTTGGTTAACTTTTACAAGGTCATNTGTATTTCGGGTGACAATACCAAGTGGGGCCCAATACACTGCTGTTCATTCTTTTCAGGTATGATGCAGCAGGTTCTTAAAAATGTTCCAGATTGGTGTTCATTCTATAAACTAACATTTATTAAGAACTTGTGTAGGCAAGTAGAGATACCAGCAGGCAGTATTAAAAAGATCTTAAATGTTCTTAGATACAAACTNTGCAGCAAAGGAGGTGTAGAGCAGCACAGTGAAGAGGANNTNAGNAAGTTNNTGNTAGACAANTTGGACAGCTGGGATGGNAACGACACAGTNAAGTTNTTAGTCACAACNTATATAAGCAAGGGGCTCATGGCACTAAACAGNTACAACCATATGGGTCANGGCATTCACCATGCAACCTCNTCAGTGTTAACTTCTTTNGCTGCNGTNCTTTTCGANGANCTAGCANTNTTTTATCTNAAGAGNAGCTTACCNCAGACAACAGTACATGTTGAGCATGCNGGCAGNTCTGATGATTANGCAAAGTGTATAGTAGTAACTGGCATACTATCCAAAGAGCTTTACTCCCAGTATGATGAGACATTTTGGAAGCATGCCTGTAGACTTAAGAATTTCACAGCTGCTGTNCAAAGGTGTTGTCAAATGAAAGATAGTGCTAAAACCNTAGTTAGCGACTGTTTTCTTGAGTTTTACAGCGAGTTCATGATGGGCTACAGAGTGACNCCTGCTGTAATTAAATTNATGTTNACTGGACTGATAAATAGCTCTGTAACTTCTCCTCAGAGCTTGATGCAGGCATGCCAAGTTTCATCTCAACAGGCCATGTATAATAGTGTTCCCCTTGTNACCAACACCACCTTTACCTTACTNAGGCAACAGATTTTCTTTAATCATGTTGAAGACTTTATCAGAAGGTATGGCNTATTAACTCTNGGAACCTTATCTCCCTTTGGNAGGCTNTTTGTNCCGACCTANTCTGGATTNGTNAGCTCAGCGGTTGCTCTGGAAGATGCTGAAGTCATTGCNAGNGCAGCTCAAACACTTCATATGAACAGTGTGTCNATCCAGTCAAGTAGCTTGACTACATTAGACAGTTTAGGTCGTAGCAGGACAAGTTCCATAGTTGAAGATAGCAGCAGTGTAAGCGACACTACTGTTGCTTCTCATGATTCGGGATCATCATCATCAAGCTTCTCTTTTGAGCTCAATAGGCCTCTATCTGAAACTGAACTACAATTCATCAAAGCACTAAACAGCCTCAAATCAACCCAAGCTTGTGAGATAATTCAGAACAGGATTACAGGTCTTTATTGTAATAGCAATGAAGGACCCCTCGACAGACACAATGTTATTTACAGTAGCAGAATGGCAGATTCTTGTGACTGGCTAAAAGATGGTAAGAGAAGAGGGAATCTAGAACTNGCAAANAGAATCCANTCTGTACTNTGTGTTNTNATAGCNGGNTACTACAGATCATTTGGNGGGGAAGGGACTGANAAACAGGTAAANGCATCATTNAATAGGGANGACAATAAAATCATCGAAGATCCTATGATACAANTGATTCCGGAGAAACTGAGGAGNGAGTTGGANAGGTTAGGGGTTTCTAGAATGGAAGTCGATGANCTGATGCCAAGNATTAGCCCTGATGANACNTTAGCCCAACTTGTGGCAAAAAAACTAATNAGCCTCAATGTTTCGACAGAAGAATACTCNGCAGAGGTNTCTAGGCTCAANCAAACNCTAACNGCNCGNAATGTTTTGCACGGGTTNGCTGGAGGAATAAAAGANCTCTCGCTTCCTATATATACAATATTCATGAAGTCATACTTCTTCAAAGACAANGTNTTNNTGTCACTGACAGACAGNTGGTCNACCAAGCANAGCACGAACTACCGTGACAGCTGCGGTAAACAGTTGACTGGTAGGATAATCACNAAGTACACTCACTGGTTGGACACTTTNCTAAGCTGCTCTGTNTCCATTAANAGGCANACAACTGTNAAGGAGCCTTCCCTTTTTAATCCGAACATCAGGTGTGTCAACCTGATCACATTTGAAGACGGTTTGAGGGAACTTTCAGTGATACAGAGTCATCTCAAAGTTTTTGAGAACGAATTCACTAACTTAAACCTTCAGTTCTCTGACCCAAACAGACAGAAACTTAGGATAGTTGAATCTAGACCTGCAGAATCTGAGTTAGAGGCAAATCGTGCAGTGATTGTTAAGACTAAACTGTTTTCAGCAACCGAACAGGTCCGANTATCTAANAACCCTGCAGTTGTCATGGGTTATCTATTAGACGAGTCAGCAATTTCTGAAGTTAAACCTACCAAGGTTGATTTTTCGAATTTACTTAAAGATCGCTTCAAAATAATGCAATTTTTCCCTTCTGTGTTCACTTTGATCAAAATGCTAACAGATGAGTCGTCAGACTCAGAAAAGAATGGCCTTAGCCCAGATTTGCAACAAGTTGCAAGGTATTCTAACCATTTAACCTTGCTTAGTAGAATGATACAACAAGCAAAGCCAACTGTAACTGTTTTCTACATGCTAAAGGGTAACTTAATGAACACAGAACCGACAGTCGCTGAGCTTGTCAGTTACGGTATAAAGGAAGGTAGGTTCTATAGGCTTTCTGACACCGGAATTGATGCAAGTACATATTCTGTAAAATACTGGAAAATTCTCCACTGTATTTCTGCTATCGGATGCCTACCTCTGAGTCAAGCAGATAAGTCTTCACTACTCATGAGTTTCTTAAATTGGAGGGTGAACATGGACATTAGAACTTCTGACTGTCCATTGTCTAGCCATGAGGCAAGTATACTTAGTGAATTTGACGGACAAGTTATTGCTAATATACTTGCCAGTGAATTAAGTTCTGTAAAACGAGACTCTGAACGNGAAGGTCTAACTGATCTCCTTGATTACCTAAANTCACCNACTGAACTGTTNAAGAAGAAGCCNTANTTAGGAACAACCTGCAAGTTCANCACTTGGGGAGACTCAAANAGNTCTGGTAAGTTTACATACAGTAGCAGATCTGGNGAGTCAATTGGTATCTTCATTGCAGGGAAATTGCACATCCATCTTTCATCTGAGTCTGTTGCCCTNTTGTGTGAGACTGAAAGGCAAGTGCTCTCTTGGATGAGCAAAAGGAGGACTGAGGTGATAACTAAGGAACAACATCAATTGTTCCTGAGCCTCCTTCCACAATCTCATGAATGNTTACAAAAGCACAANGATGGCAGTGCACTGTCAGTNATACCTGATNGNAGCAANCCTCGNCTACTAAAATTTGTGCCTCTCAAGAAGGGGCTNGCAGTGGTGAAGATNAAAAAACAAATTTTGACAGTNAAGAANCAAGTNGTGTTTGATGCTGAAAGCGAGCCCAGNTTNCAATGGGGGCATGGCTGCTTGTCCATTGTTTATGACGAAACCGACACTCAGACCACATACCATGAAAACCTTTTGAAGGTGAAGCAGCTTGTTGACTGCTCTACCGACAGAAAGAAGCTTTTACCTCAGTCTGTGTTTTCTGATTCCAAAGTCGTCCTCTCAAGAATTAAGTTTAAAACGGAACTCCTTCTTAACTCATTGACGTTGCTCCACTGTTTCTTGAAACATGCCCCTAGTGATGCTATAATGGAAGTGGAGAGTAAAAGTAACCTACTACATAAGTACCTCAAATCAGGAGGTGTTAGGCAGCGGAATACTGAGGTNCTCTTNAGNGAAAAGTTGAANAAGGTNGTTATAAAGGANAACCTTGAGCAAGGNGTGGAAGAAGAGATTGANTTNTGCAACAACCTNACCAAGANTGTTTCNGAGAATCCGCTACCACTCAGCTGTTGGTCTGAAGTTCAAAGCTATATTGAAGACATAGGCTTCAACAATGTGCTTGTGAATATTGACAGAAACACTGTTAAAAGTGAACTTTTGTGGAAATTTACGTTAGACACCAATGTAAGTACCACAAGTACCATCAAGGATGTGAGGACACTGGTATCCTACGTTAGCACTGAAACGATCCCTAAATTTCTGCTTGCATTTCTTCTTTATGAAGAAGTGTTGATGAACTTAATTAACCAGTGCAAGGCAGTAAAGGAACTCATCAACAGCACAGGACTCTCAGATCTAGAATTAGAGAGCTTGCTCACTTTGTGTGCTTTTTATTTCCAAAATGAGTGCAGTAAGAGAGATGGACCTAGGTGTTCNTTCGCAGCACTGTTAAGCTTAGTTCATGAAGATTGGCAAANGNTAGGNAAAAACATCCTTGTTCGTGCAAACAATGAGCTGGGTGANGTGTCNCTNAAGGTNAANATTGTCCTGGTGCCNCTCAANGACATGTCCAAGCCNAANCCTGAGAGAGTNGTTATAGCCAGAAGGTCACTGAATCANGCTCTNTCCTTAATGTTTTTGGATGAAATGTCATTACCTGAGCTTAAATCCTTATCTGTTAATTGCAGAATGGGNAACTTTGAAGGGCAGGAGTGCTTTGAGTTCACNATTTTNAANGACAACAGCNCAAGGCTGGATTACAACAAANTAATTGACCACTGTGTGGACATGGAAAAAAAGAGGGACGCAGTTAGAGCAGTAGAAGATTTAGTTNTGATGTTGACAGGCAGGGCAGTCAAACCTAGCACTGTAACACCAGNTGCACANGAAGANGAGCAGTGTCAGGAGCAAATAAGNCTNGATGATCTAATGGCAAGTGACACAGTGACAGACCTNCCNGANAGGGAAGCAGAGGCCCTNAAAACAGGNAANCTTGGCTTTAACTGGGATTCAGATTGANCACNNTNTCTGTNTNAATNATTNATACCTNTCANTNTCNNNAGGGNAAGTAAGGCAATTTATACCATGCCATTTGTTGACATCTGAACTTTCAAATAAGTCAGCTGCTCTGCATCTCTTACCAATTCAATTGTTTCACTACAATGTTTTCAGCTACTGGTCAACCTTTAATATCCAACTACTCCACTCTCTTTGCTGCTCATGTC >test_NIHPAK-19_M GTGGATTGAGCATCTTAATTGCAGCATACTTGTCAACATCATGCATATATCATTGATGTATGCAGTTTTCTGCTTGCAGCTGTGCGGTCTAGGGAAAACTAACGGACTACACAATGGGACTGAACACAATAAGACACACGTTATGACAACGCCTGATGACAGTCAGAGCCCTGAACCGCCAGTGAGCACAGCCCTGCCTGTCACACCGGACCCTTCCACTGTCACACCTACAACACCAGCCAGCGGATTAGAAGGCTCAGGAGAGGTTCACACATCCTCTCCAATCACCACCAAGGGTTTGTCTCTGCCGGGGGCTACATCTGAGCTCCCTGCGACTACTAGCATAGTCACTTCAGGTGCAAGTGATGCCGATTCTAGCACACAGGCAGCCAGAGACACCCCTAAACCATCAGTCCGCACGAGTCTGCCCAACAGCCCTAGCACACCATCCACACCACAAGGCACACACCATCCCGTGAGGAGTCTGCTTTCAGTCACGAGCCCTAAGCCAGAAGAAACACCAACACCGTCAAAATCAAGCAAAGATAGCTCAGCAACCAACAGTCCTCACCCAGCCGCCAGCAGACCAACAACCCCTCCCACAACAGCCCAGAGACCCGCTGAAAACAACAGCCACAACACCACCGAACAGCTTGAGTCCTTAACACAATTAGCAACTTCAGGTTCAATGATCTCTCCAACACAGACAGTCCTCCCAAAGAGTGTTACTTCTATAGCCATTCAAGACATTCATCCCAGCCCAACAAATAGGTCTAAAAGAAACCTTGATATGGAAATAATCTTGACGTTATCTCAGGGTCTGAAAAAGTATTATGGCAAAATACTTAAGCTCCTGCATCTCACCTTAGAGGAAGACACTGAAGGCTTGTTAGAATGGTGCAAGAGAAATCTCGGTCTTGACTGTGATGACACCTTCTTTCAAAAAAGAATTGAAGAATTCTTTATAACTGGTGAGGGTCATTTCAATGAAGTTTTACAATTTAGAACACTAGGCACATTGAGCACTACAGAGTCAACGCATGCTGGATCACCAACAGTTGAACCCTTCAAATCCTACTTTGCTAAAGGTTTCCTTTCAATAGATTCAGGTTATTTCTCTGCCAAATGTTATTCAAGAACATCCAATTCAGGGCTCCAATTGATTAATGTTACCCGACATTCATCTAGGATAGCTGACACGCCTGGGCCCAAGATCACTAACCTAAAGACCATCAATTGCATAAACTTAAAAGCATCCGTCTTTAAAGAACATAGAGAGGTTGAAATCAATGTGCTTCTCCCTCAAGTTGCAGTCAACCTCTCAAACTGTCATGTTGCAATCAAATCACATGTCTGCGACTATTCTTTGGACACTGACGGGGCGATTAGGCTTCCTCATATTCATCATGAAGGTACTTTTATCCCAGGTACTTACAAAATAGTGATAGACCAAAAAAGTAAGCTGAATGACAGGTGCACCCTATTCACCAACTGTGTGATAAAAGGAAGAGAAGTTCGTAAAGGCCAGTCAGTCCTAAGGCAATATAAGACAGAAATTAGAATTGGCAGGGCATCAACTGGTTCTAGGAGATTGCTTTCCGAAGAATCTGGTGATGACTGCATATCAAGAACTCAGCTATTGAGGACAGAGACTGCAGAGGTCCATGGCGATAACNNNNNNNNNNCAGGTGATAAGATAACCATCTGTAATGGTTCAACTGTTGTAGATCAAAGACTGGGTAGTGAACTGGGGTGTTACACTATCAATAGAGTGAGGTCATTCAAGCTATGCGAAAACAGTGCCACAGGGAAGAGCTGTGAAATAGACAGTATCCCAGTTAAGTGTAGGCAGGGTTATTGCCTAAAAATCACTCAGGAAGGGAGGGGCCATGTGAAATTATCTAGAGGCTCAGAAGTTGTCTTGGATGTATGTGACTCAAGCTGTGAAGTGATGATACCTAAGGGCACTGGTGACATTCTAGTAGATTGTTCAGGTGGGCAGCAACATTTTTTAAAAGACAACCTGGTTGATCTAGGATGTCCCAAAATTCCATTATTGGGCAAAATGGCTATTTATATCTGCAGAATGTCGAATCACCCCAAAACAACCATGGCCTTCCTCTTTTGGTTCAGCTTTGGCTATGTGGTAACTTGTATACTTTGCAAGGCCATTTTTTTCTTATTAATAATTTTTGGAACACTAGGGAAAAGGTTCAAGCAGTACAGAGAGCTGAAACCCCAGACCTGCACCATTTGTGAGACAACACCTGTAAATGCAATAGATGCTGAAATGCATGATCTCAACTGCAGTTACAATATATGTCCCTATTGTGCGTCTAGACTGACTTCAGATGGGCTTGCTAGGCATGTAACACAATGCCCTAGACGGAAGGAGAAAGTGGAGGAAACCGAATTGTACCTGAATTTAGAGAGAATTCCTTGGGTTGTAAGAAAGCTATTACAGGTGTCAGAGTCCACTGGTACAGTATTAAAAAGGAGCAGTTGGCTAATTGTTCTACTTGTGCTGTTCACAGTTTCATTATCACCAGTTCAATCAGCACCCATTGGTCACGGGAGAACAATTGAAACATACCGGGTTAGGGAGGAATACACAAGTATTTGCCTCTTTGTACTAGGAAGTATCCTGTTTATGGTTTCTTGTCTAATGAAAGGACTAGTTGACAGTGTTGGCAACATCTTCTTTCCTGGGCTGTCCGTTTGTAAGACATGCTCTATAGGTAGCATTAATGGCTTTGAAATTGAGTCTCATAAGTGCTACTGTAGCTTGTTTTGTTGCCCTTATTGTAGGCACTGCTCTGCTGATAGAGAGATTCATCAGCTGCACTTGAGCATCTGCAAAAAAAGGAAGACAGGAAGTAATGTTATGCTAGCTGTTTGCAAACGCATGTGTTTCAGGGCAACTATGGAAGTGAGCAACAAAGCCCTATTTATCCGTAGCATTATCAACACCACTTTTGTTGTGTGCATACTGATACTAGCAGTCTGTGTTGTTAGCACCTCAGCAGTAGAAATGGAAAGCCTGCCAGCTGGGACCTGGGAAAGAGAAGAAGACCTAACAAATTTCTGCCATCAGGAATGCCAGGTCACGGAGACTGAGTGCCTCTGCCCTTATGAAGCTCTAGTGCTCAGAAGGCCCCTATTTCTAGATAGTATAGTCAAAGGCATGAAAAATCTGCTAAACTCAACAAGTCTAGAAACAAGCTTATCAATTGAAGCACCGTGGGGAGCAATTAATGTTCAGTCAACCTACAAACCAACTGTATCAACTGCAAACATAGCACTTAGTTGGAGCTCAGTGGAACACAGAGGCAATAAGGTTTTGGTCTCAGGCAGATCAGAATCAATTATGAAGCTGGAAGAAAGGACAGGAATCAGCTGGGATCTTGGCGTAGAAGATGCCTCTGAGTCTAAGCTACTTACAGTTTCAGTCATGGATTTGTCTCAGATGTACTCTCCTGTCTTCGAGTACTTATCAGGTGACAGACAAGTGGAAGAGTGGCCTAAAGCAACCTGTACAGGTGACTGCCCAGAAAGATGTGGCTGCACATCATCAACCTGCTTACACAAAGAGTGGCCCCATTCAAGGAATTGGAGATGTAATCCTACTTGGTGCTGGGGTGTGGGGACTGGCTGCACCTGTTGTGGTTTAGATGTGAAAGACCTTTTCACAGATTACATGTTCGTCAAGTGGAAAGTTGAGTACATTAAGACAGAGGCCATAGTATGTGTGGAACTAACCAGTCAAGAAAGACAGTGTAGCTTGATTGAGGCGGGCACAAGATTCAATTTAGGTTCTGTGACTATTACATTGTCAGAACCAAGGAACATTCAACAAAAGCTCCCTCCTGAAATAATCACACTGCACCCCAAGATTGAGGAAGGTTTTTTTGACCTAATGCATATACAAAAAGTGCTATCGGCAAGCACAGTGTGTAAGTTGCAGAGTTGCACACATGGTGTGCCAGGAGATCTGCAGGTCTACCACATCGGAAACCTATTAAAAGGGGACAGAGTAAATGGACACCTGATTCACAAAATTGAGCAACACCTCAACACCTCCTGGATGTCCTGGGATGGTTGCGACCTAGACTACTACTGTAACATGGGAGACTGGCCTTCCTGCACATATACCGGAGTCACTCAGCACAATCATGCTTCATTTGTAAACCTGCTCAACATTGAAACTGATTATACAAAAACCTTCCACTTTCACTCTAAAAGGGTTACTGCACATGGAGACACACCACAACTAGATCTGAAGGCAAGGCCAACCTATGGTGCAGGTGAGATCACCGTGCTGGTGGAAGTTGCTGACATGGAGTTACACACAAAGAAGATTGAAATATCAGGCTTAAAATTTGCAAGCCTAACTTGCACAGGTTGTTATGCTTGTAGTTCTGGCATCTCCTGTAAAGTTAGAATTCATGTGGATGAACCAGATGAACTTACAGTACATGTTAAAAGTGATGACCCAGATGTAGTTGCAGCTAGCTCAAGTCTCATGGCAAGGAAGCTTGAATTTGGAACAGACAGTACATTTAAAGCTTTCTCAGCCATGCCAAAAACTTCCCTATGTTTCTACATTGTGGAAAGAGAATACTGTAAGAGCTGCAGTAAAGAAGACACACAGAAATGTGTTAACACGAAACTCGAACAACCACAGAGCATTTTGATCGAACATAAGGGAACTATAATTGGAAAGCAAAACAATACTTGCACGGCTAAAGCGAGCTGCTGGTTAGAGTCAGTTAAGAGTTTTTTTTATGGTCTGAAGAATATGCTTGGTGGCATTTTTGGCAATGTTTTTATAGGCATTTTCACATTTCTTGCCCCCTTTATCNTNTTAATACTTTTCTTTATGTTTGGGTGGAGGGTCTTGTTTTGCTTCAAGTGTTGCAGAAGAACCAGAGGCCTATTCAAGTACAGGCACCTCAAAGACGATGAAGAAACTGGTTACAGAAAGATCATTGAAAGACTGAACAACAAAAAAGGAAAAAACAAGCTGCTTGATGGTGAAAGACTTGCTGACAGAAAGATTGCTGAACTGTTCTCTACAAAAACACACATTGGCTAGATCAACCGGAGGGGCCTGGGNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNTGCATCCCCACCATATTATCATCACAATATGCCACATCTAAGCTGATTCACTGTATCTGCAAACAGACTCTGTAATGCTTGAAACTGCCT From 8050481b86034e75f611fbea65febf34580265ff Mon Sep 17 00:00:00 2001 From: anna-parker <50943381+anna-parker@users.noreply.github.com> Date: Thu, 4 Dec 2025 11:06:44 +0100 Subject: [PATCH 03/14] include description in more integration tests --- integration-tests/tests/specs/features/revise-sequence.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/tests/specs/features/revise-sequence.spec.ts b/integration-tests/tests/specs/features/revise-sequence.spec.ts index 50aa369def..e38206540e 100644 --- a/integration-tests/tests/specs/features/revise-sequence.spec.ts +++ b/integration-tests/tests/specs/features/revise-sequence.spec.ts @@ -100,7 +100,7 @@ groupTest.describe('Bulk sequence revision', () => { const revisionMetadata = createRevisionMetadataTsv(accessionsToRevise, baseSubmissionId); const revisedSequences = accessionsToRevise.map((accession, i) => ({ - id: `${baseSubmissionId}-${i}`, + id: `${baseSubmissionId}-${i} description`, sequence: EBOLA_SUDAN_SHORT_SEQUENCE + 'GGGGGG', })); const fastaContent = createFastaContent(revisedSequences); From f21a1b70fbf8ab263a8b2fa0f12b9815092c2d38 Mon Sep 17 00:00:00 2001 From: anna-parker <50943381+anna-parker@users.noreply.github.com> Date: Thu, 4 Dec 2025 11:07:30 +0100 Subject: [PATCH 04/14] format --- .../components/Submission/FileUpload/fileProcessing.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/src/components/Submission/FileUpload/fileProcessing.spec.ts b/website/src/components/Submission/FileUpload/fileProcessing.spec.ts index d1ac95539f..d717416baa 100644 --- a/website/src/components/Submission/FileUpload/fileProcessing.spec.ts +++ b/website/src/components/Submission/FileUpload/fileProcessing.spec.ts @@ -70,7 +70,9 @@ describe('fileProcessing', () => { }); test('Plain segment file content is extracted correctly', async () => { - const dummyFile = new File(['>fooid description\nACTG\n\nACTG\nACTG\n'], 'example.fasta', { type: 'text/plain' }); + const dummyFile = new File(['>fooid description\nACTG\n\nACTG\nACTG\n'], 'example.fasta', { + type: 'text/plain', + }); const result = await PLAIN_SEGMENT_KIND.processRawFile(dummyFile); if (result.isErr()) { fail(`result was error: ${result._unsafeUnwrapErr().message}`); From 644b3c70f0fdd69a9a072ef5cc1fd280d20b0196 Mon Sep 17 00:00:00 2001 From: anna-parker <50943381+anna-parker@users.noreply.github.com> Date: Thu, 4 Dec 2025 11:10:08 +0100 Subject: [PATCH 05/14] more integration tests --- integration-tests/tests/specs/features/revise-sequence.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/tests/specs/features/revise-sequence.spec.ts b/integration-tests/tests/specs/features/revise-sequence.spec.ts index e38206540e..afe1572ce1 100644 --- a/integration-tests/tests/specs/features/revise-sequence.spec.ts +++ b/integration-tests/tests/specs/features/revise-sequence.spec.ts @@ -45,7 +45,7 @@ sequenceTest( await page.getByTestId('Add a segment_segment_file').setInputFiles({ name: 'update_S.txt', mimeType: 'text/plain', - buffer: Buffer.from('>S\n' + CCHF_S_SEGMENT_FULL_SEQUENCE), + buffer: Buffer.from('>S description\n' + CCHF_S_SEGMENT_FULL_SEQUENCE), }); await page.getByRole('button', { name: 'Submit' }).click(); From dc86ce77c9ff3071171911cb666d3f37489b3dbb Mon Sep 17 00:00:00 2001 From: anna-parker <50943381+anna-parker@users.noreply.github.com> Date: Thu, 4 Dec 2025 20:00:51 +0100 Subject: [PATCH 06/14] remove change - should cause integration tests to fail --- .../src/components/Submission/FileUpload/fileProcessing.spec.ts | 2 +- website/src/components/Submission/FileUpload/fileProcessing.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/src/components/Submission/FileUpload/fileProcessing.spec.ts b/website/src/components/Submission/FileUpload/fileProcessing.spec.ts index d717416baa..5dc4e8784b 100644 --- a/website/src/components/Submission/FileUpload/fileProcessing.spec.ts +++ b/website/src/components/Submission/FileUpload/fileProcessing.spec.ts @@ -80,6 +80,6 @@ describe('fileProcessing', () => { const processedFile = result._unsafeUnwrap(); const processedText = await processedFile.text(); expect(processedText).toBe('ACTGACTGACTG'); - expect(processedFile.fastaHeader()).toBe('fooid'); + expect(processedFile.fastaHeader()).toBe('fooid description'); }); }); diff --git a/website/src/components/Submission/FileUpload/fileProcessing.ts b/website/src/components/Submission/FileUpload/fileProcessing.ts index ecefec3184..b28ee15c48 100644 --- a/website/src/components/Submission/FileUpload/fileProcessing.ts +++ b/website/src/components/Submission/FileUpload/fileProcessing.ts @@ -94,7 +94,7 @@ export const PLAIN_SEGMENT_KIND: FileKind = { new Error(`Found ${headerLines.length} headers in uploaded file, only a single header is allowed.`), ); } - const header = headerLines.length === 1 ? headerLines[0].substring(1).trim().split(/\s+/)[0] : null; + const header = headerLines.length === 1 ? headerLines[0].substring(1).trim() : null; const segmentData = lines .filter((l) => !l.startsWith('>')) .map((l) => l.trim()) From ae2d34df9040312fd302361e20de61f9adc58a5a Mon Sep 17 00:00:00 2001 From: Cornelius Roemer Date: Thu, 4 Dec 2025 18:05:07 +0100 Subject: [PATCH 07/14] fix(website): only user fasta id in fastaIds Resolves #5627 --- website/src/components/Edit/SequencesForm.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/website/src/components/Edit/SequencesForm.tsx b/website/src/components/Edit/SequencesForm.tsx index b981c4b3dc..334d6bcb7b 100644 --- a/website/src/components/Edit/SequencesForm.tsx +++ b/website/src/components/Edit/SequencesForm.tsx @@ -159,8 +159,13 @@ export class EditableSequences { } getFastaIds(): string { - const filledRows = this.rows.filter((row) => row.value !== null); - return filledRows.map((sequence) => sequence.fastaHeader).join(FASTA_IDS_SEPARATOR); + return this.rows + .flatMap((row) => { + if (row.value === null) return []; + const id = row.fastaHeader?.match(/^\S+/)?.[0]; + return id ? [id] : []; + }) + .join(FASTA_IDS_SEPARATOR); } getSequenceFasta(): File | undefined { From e1a37a48f1d46b686e22204eee422e5cd434d106 Mon Sep 17 00:00:00 2001 From: anna-parker <50943381+anna-parker@users.noreply.github.com> Date: Thu, 4 Dec 2025 20:23:00 +0100 Subject: [PATCH 08/14] feat(website): make difference between fasta header and fasta ID clearer on edit page --- .../components/Edit/SequencesForm.spec.tsx | 39 ++++++++++++++----- website/src/components/Edit/SequencesForm.tsx | 10 +++-- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/website/src/components/Edit/SequencesForm.spec.tsx b/website/src/components/Edit/SequencesForm.spec.tsx index 3428287115..cca1766eca 100644 --- a/website/src/components/Edit/SequencesForm.spec.tsx +++ b/website/src/components/Edit/SequencesForm.spec.tsx @@ -96,6 +96,7 @@ describe('SequencesForm', () => { fastaHeader: 'subId_Segment1', }, ]); + expect(editableSequences.getFastaIds()).toEqual('subId_Segment1'); } }); @@ -112,16 +113,22 @@ describe('SequencesForm', () => { let secondKey; { - editableSequences = editableSequences.update(firstKey, 'ATCG', 'Segment 1', 'subId_Segment1'); + editableSequences = editableSequences.update(firstKey, 'ATCG', 'Segment 1', 'subId_Segment1 description'); const fasta = editableSequences.getSequenceFasta(); expect(fasta).not.toBeUndefined(); const fastaText = await fasta!.text(); - expect.soft(fastaText).toBe('>subId_Segment1\nATCG'); - expect(editableSequences.getSequenceRecord()).deep.equals({ subId_Segment1: 'ATCG' }); + expect.soft(fastaText).toBe('>subId_Segment1 description\nATCG'); + expect(editableSequences.getSequenceRecord()).deep.equals({ 'subId_Segment1 description': 'ATCG' }); const rows = editableSequences.rows; expect(rows).toEqual([ - { label: 'Segment 1', value: 'ATCG', initialValue: null, fastaHeader: 'subId_Segment1', key: firstKey }, + { + label: 'Segment 1', + value: 'ATCG', + initialValue: null, + fastaHeader: 'subId_Segment1 description', + key: firstKey, + }, { label: 'Add a segment', value: null, initialValue: null, fastaHeader: null, key: expect.any(String) }, ]); secondKey = rows[1].key; @@ -132,12 +139,21 @@ describe('SequencesForm', () => { const fasta = editableSequences.getSequenceFasta(); expect(fasta).not.toBeUndefined(); const fastaText = await fasta!.text(); - expect.soft(fastaText).toBe('>subId_Segment1\nATCG\n>subId_Segment2\nTT'); - expect(editableSequences.getSequenceRecord()).deep.equals({ subId_Segment1: 'ATCG', subId_Segment2: 'TT' }); + expect.soft(fastaText).toBe('>subId_Segment1 description\nATCG\n>subId_Segment2\nTT'); + expect(editableSequences.getSequenceRecord()).deep.equals({ + 'subId_Segment1 description': 'ATCG', + 'subId_Segment2': 'TT', + }); const rows = editableSequences.rows; expect(rows).deep.equals([ - { label: 'Segment 1', value: 'ATCG', initialValue: null, key: firstKey, fastaHeader: 'subId_Segment1' }, + { + label: 'Segment 1', + value: 'ATCG', + initialValue: null, + key: firstKey, + fastaHeader: 'subId_Segment1 description', + }, { label: 'Segment 2', value: 'TT', initialValue: null, key: secondKey, fastaHeader: 'subId_Segment2' }, ]); } @@ -145,6 +161,7 @@ describe('SequencesForm', () => { expect(() => editableSequences.update('another key', 'GG', 'another key', 'anything')).toThrowError( 'Maximum limit reached — you can add up to 2 sequence file(s) only.', ); + expect(editableSequences.getFastaIds()).toEqual('subId_Segment1 subId_Segment2'); }); test('GIVEN a multi-segmented organism THEN do not allow duplicate fasta headers', () => { @@ -162,9 +179,9 @@ describe('SequencesForm', () => { const rowsAfterFirstUpdate = editableSequences.rows; const secondKey = rowsAfterFirstUpdate[1].key; - editableSequences = editableSequences.update(secondKey, 'TT', 'Segment 2', 'subId_Segment'); + editableSequences = editableSequences.update(secondKey, 'TT', 'Segment 2', 'subId_Segment description'); - const errorMessage = 'A sequence with the fastaHeader subId_Segment already exists.'; + const errorMessage = 'A sequence with the fastaID subId_Segment already exists.'; expect(toast.error).toHaveBeenCalledWith(expect.stringContaining(errorMessage)); // Expect that the second sequence was not added @@ -172,6 +189,7 @@ describe('SequencesForm', () => { { label: 'Segment 1', value: 'ATCG', initialValue: null, key: firstKey, fastaHeader: 'subId_Segment' }, { label: 'Add a segment', value: null, initialValue: null, fastaHeader: null, key: expect.any(String) }, ]); + expect(editableSequences.getFastaIds()).toEqual('subId_Segment'); }); test('GIVEN a single-segmented organism THEN only allows 1 input and fasta header does not contain the segment name', async () => { @@ -216,6 +234,7 @@ describe('SequencesForm', () => { expect(editableSequences.rows).toEqual([ { label: 'Add a segment', value: null, initialValue: null, fastaHeader: null, key: expect.any(String) }, ]); + expect(editableSequences.getFastaIds()).toEqual(''); }); test('GIVEN initial data with an empty segment THEN the fasta does not contain the empty segment', async () => { @@ -230,6 +249,7 @@ describe('SequencesForm', () => { expect.soft(fastaText).toBe('>subId_label\nATCG'); expect(editableSequences.getSequenceRecord()).deep.equals({ subId_label: 'ATCG' }); + expect(editableSequences.getFastaIds()).toEqual('subId_label'); }); test('GIVEN initial segment data that is then deleted as an edit THEN the edit record does not contain the segment key but input field is kept', () => { @@ -264,5 +284,6 @@ describe('SequencesForm', () => { key: expect.any(String), }, ]); + expect(editableSequences.getFastaIds()).toEqual(''); }); }); diff --git a/website/src/components/Edit/SequencesForm.tsx b/website/src/components/Edit/SequencesForm.tsx index 334d6bcb7b..07b821152a 100644 --- a/website/src/components/Edit/SequencesForm.tsx +++ b/website/src/components/Edit/SequencesForm.tsx @@ -22,6 +22,10 @@ function generateAndDownloadFastaFile(fastaHeader: string, sequenceData: string) URL.revokeObjectURL(url); } +function getFastaId(fastaHeader: string | null): string | null { + return fastaHeader?.match(/^\S+/)?.[0] ?? null; +} + type EditableSequenceFile = { key: string; label: string | null; @@ -136,8 +140,8 @@ export class EditableSequences { } fastaHeader ??= value == null ? null : key; // Ensure fastaHeader is never null if a sequence exists - if (this.editableSequenceFiles.some((seq) => seq.fastaHeader === fastaHeader)) { - toast.error(`A sequence with the fastaHeader ${fastaHeader} already exists.`); + if (this.editableSequenceFiles.some((seq) => getFastaId(seq.fastaHeader) === getFastaId(fastaHeader))) { + toast.error(`A sequence with the fastaID ${getFastaId(fastaHeader)} already exists.`); return new EditableSequences( this.editableSequenceFiles.filter((file) => file.value !== null), this.maxNumberOfRows, @@ -162,7 +166,7 @@ export class EditableSequences { return this.rows .flatMap((row) => { if (row.value === null) return []; - const id = row.fastaHeader?.match(/^\S+/)?.[0]; + const id = getFastaId(row.fastaHeader); return id ? [id] : []; }) .join(FASTA_IDS_SEPARATOR); From 50de3c1bb1dfb3460566337a1eca0cd6b83517d8 Mon Sep 17 00:00:00 2001 From: anna-parker <50943381+anna-parker@users.noreply.github.com> Date: Fri, 5 Dec 2025 12:45:38 +0100 Subject: [PATCH 09/14] handle case where fastaHeader is an empty string --- .../components/Edit/SequencesForm.spec.tsx | 27 ++++++++++++++++++- website/src/components/Edit/SequencesForm.tsx | 3 ++- .../Submission/FileUpload/fileProcessing.ts | 6 ++++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/website/src/components/Edit/SequencesForm.spec.tsx b/website/src/components/Edit/SequencesForm.spec.tsx index cca1766eca..331f4fa971 100644 --- a/website/src/components/Edit/SequencesForm.spec.tsx +++ b/website/src/components/Edit/SequencesForm.spec.tsx @@ -192,7 +192,7 @@ describe('SequencesForm', () => { expect(editableSequences.getFastaIds()).toEqual('subId_Segment'); }); - test('GIVEN a single-segmented organism THEN only allows 1 input and fasta header does not contain the segment name', async () => { + test('GIVEN a single-segmented organism THEN only allows 1 input', async () => { let editableSequences = EditableSequences.fromSequenceNames(makeReferenceGenomeLightweightSchema(['foo'])); const initialRows = editableSequences.rows; @@ -217,6 +217,31 @@ describe('SequencesForm', () => { ); }); + test('GIVEN an edit with an empty fasta header THEN use key as fasta header', async () => { + let editableSequences = EditableSequences.fromSequenceNames(makeReferenceGenomeLightweightSchema(['foo'])); + + const initialRows = editableSequences.rows; + expect(initialRows).toEqual([ + { label: 'Add a segment', value: null, initialValue: null, fastaHeader: null, key: expect.any(String) }, + ]); + const key = initialRows[0].key; + + editableSequences = editableSequences.update(key, 'ATCG', 'subId', null); + const fasta = editableSequences.getSequenceFasta(); + expect(fasta).not.toBeUndefined(); + const fastaText = await fasta!.text(); + expect.soft(fastaText).toBe(`>${key}\nATCG`); + + expect(editableSequences.getSequenceRecord()).deep.equals({ [key]: 'ATCG' }); + + const rows = editableSequences.rows; + expect(rows).deep.equals([{ label: "subId", value: 'ATCG', initialValue: null, fastaHeader: key, key }]); + + expect(() => editableSequences.update('another key', 'GG', 'another key', 'anything')).toThrowError( + 'Maximum limit reached — you can add up to 1 sequence file(s) only.', + ); + }); + test('GIVEN no initial data WHEN I add and remove a sequence THEN input is also removed again', () => { let editableSequences = EditableSequences.fromSequenceNames( makeReferenceGenomeLightweightSchema(['foo', 'bar']), diff --git a/website/src/components/Edit/SequencesForm.tsx b/website/src/components/Edit/SequencesForm.tsx index 07b821152a..28b8aa21af 100644 --- a/website/src/components/Edit/SequencesForm.tsx +++ b/website/src/components/Edit/SequencesForm.tsx @@ -23,7 +23,8 @@ function generateAndDownloadFastaFile(fastaHeader: string, sequenceData: string) } function getFastaId(fastaHeader: string | null): string | null { - return fastaHeader?.match(/^\S+/)?.[0] ?? null; + if (!fastaHeader) return null; + return fastaHeader.split(/\s+/)[0] || null; } type EditableSequenceFile = { diff --git a/website/src/components/Submission/FileUpload/fileProcessing.ts b/website/src/components/Submission/FileUpload/fileProcessing.ts index b28ee15c48..f3c1000868 100644 --- a/website/src/components/Submission/FileUpload/fileProcessing.ts +++ b/website/src/components/Submission/FileUpload/fileProcessing.ts @@ -94,7 +94,11 @@ export const PLAIN_SEGMENT_KIND: FileKind = { new Error(`Found ${headerLines.length} headers in uploaded file, only a single header is allowed.`), ); } - const header = headerLines.length === 1 ? headerLines[0].substring(1).trim() : null; + let header: string | null = null; + if (headerLines.length === 1) { + const trimmed = headerLines[0].substring(1).trim(); + header = trimmed === '' ? null : trimmed; + } const segmentData = lines .filter((l) => !l.startsWith('>')) .map((l) => l.trim()) From 98b0b5ed856e96634179bbe3cdc8dc4c4a799b37 Mon Sep 17 00:00:00 2001 From: anna-parker <50943381+anna-parker@users.noreply.github.com> Date: Fri, 5 Dec 2025 12:55:08 +0100 Subject: [PATCH 10/14] wupps --- website/src/components/Edit/SequencesForm.spec.tsx | 2 +- website/src/components/Edit/SequencesForm.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/components/Edit/SequencesForm.spec.tsx b/website/src/components/Edit/SequencesForm.spec.tsx index 331f4fa971..9dca757d25 100644 --- a/website/src/components/Edit/SequencesForm.spec.tsx +++ b/website/src/components/Edit/SequencesForm.spec.tsx @@ -235,7 +235,7 @@ describe('SequencesForm', () => { expect(editableSequences.getSequenceRecord()).deep.equals({ [key]: 'ATCG' }); const rows = editableSequences.rows; - expect(rows).deep.equals([{ label: "subId", value: 'ATCG', initialValue: null, fastaHeader: key, key }]); + expect(rows).deep.equals([{ label: 'subId', value: 'ATCG', initialValue: null, fastaHeader: key, key }]); expect(() => editableSequences.update('another key', 'GG', 'another key', 'anything')).toThrowError( 'Maximum limit reached — you can add up to 1 sequence file(s) only.', diff --git a/website/src/components/Edit/SequencesForm.tsx b/website/src/components/Edit/SequencesForm.tsx index 28b8aa21af..9dc574a748 100644 --- a/website/src/components/Edit/SequencesForm.tsx +++ b/website/src/components/Edit/SequencesForm.tsx @@ -23,8 +23,8 @@ function generateAndDownloadFastaFile(fastaHeader: string, sequenceData: string) } function getFastaId(fastaHeader: string | null): string | null { - if (!fastaHeader) return null; - return fastaHeader.split(/\s+/)[0] || null; + if (!fastaHeader) return null; + return fastaHeader.split(/\s+/)[0] || null; } type EditableSequenceFile = { From 154c04af3fc1913889f895edb77f371990bb14d2 Mon Sep 17 00:00:00 2001 From: anna-parker <50943381+anna-parker@users.noreply.github.com> Date: Fri, 5 Dec 2025 13:09:32 +0100 Subject: [PATCH 11/14] use constants in tests --- .../components/Edit/SequencesForm.spec.tsx | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/website/src/components/Edit/SequencesForm.spec.tsx b/website/src/components/Edit/SequencesForm.spec.tsx index 9dca757d25..baa480b96a 100644 --- a/website/src/components/Edit/SequencesForm.spec.tsx +++ b/website/src/components/Edit/SequencesForm.spec.tsx @@ -48,6 +48,7 @@ describe('SequencesForm', () => { }); test('GIVEN organism with 2 suborganisms with 1 segment each THEN allows at max 1 inputs', async () => { + const FASTAHEADER = 'FASTAHEADER'; let editableSequences = EditableSequences.fromSequenceNames( makeSubOrganismReferenceSchema(['suborg1', 'suborg2']), ); @@ -57,19 +58,20 @@ describe('SequencesForm', () => { ]); const firstKey = initialRows[0].key; { - editableSequences = editableSequences.update(firstKey, 'ATCG', 'Segment 1', 'subId_Segment1'); + editableSequences = editableSequences.update(firstKey, 'ATCG', 'Segment 1', FASTAHEADER); const fasta = editableSequences.getSequenceFasta(); expect(fasta).not.toBeUndefined(); const fastaText = await fasta!.text(); - expect.soft(fastaText).toBe('>subId_Segment1\nATCG'); - expect(editableSequences.getSequenceRecord()).deep.equals({ subId_Segment1: 'ATCG' }); + expect.soft(fastaText).toBe(`>${FASTAHEADER}\nATCG`); + expect(editableSequences.getSequenceRecord()).deep.equals({ [FASTAHEADER]: 'ATCG' }); const rows = editableSequences.rows; expect(rows).toEqual([ - { label: 'Segment 1', value: 'ATCG', initialValue: null, key: firstKey, fastaHeader: 'subId_Segment1' }, + { label: 'Segment 1', value: 'ATCG', initialValue: null, key: firstKey, fastaHeader: FASTAHEADER }, ]); } - expect(() => editableSequences.update('another key', 'GG', 'another key', 'subId_anotherkey')).toThrowError( + + expect(() => editableSequences.update('another key', 'GG', 'another key', 'FASTAHEADER_anotherkey')).toThrowError( 'Maximum limit reached — you can add up to 1 sequence file(s) only.', ); editableSequences = editableSequences.update(firstKey, null, null, null); @@ -79,12 +81,12 @@ describe('SequencesForm', () => { const rowsAfterDeletion = editableSequences.rows; const newFirstKey = rowsAfterDeletion[0].key; { - editableSequences = editableSequences.update(newFirstKey, 'ATCG', 'Segment 1', 'subId_Segment1'); + editableSequences = editableSequences.update(newFirstKey, 'ATCG', 'Segment 1', FASTAHEADER); const fasta = editableSequences.getSequenceFasta(); expect(fasta).not.toBeUndefined(); const fastaText = await fasta!.text(); - expect.soft(fastaText).toBe('>subId_Segment1\nATCG'); - expect(editableSequences.getSequenceRecord()).deep.equals({ subId_Segment1: 'ATCG' }); + expect.soft(fastaText).toBe(`>${FASTAHEADER}\nATCG`); + expect(editableSequences.getSequenceRecord()).deep.equals({ [FASTAHEADER]: 'ATCG' }); const rows = editableSequences.rows; expect(rows).toEqual([ @@ -93,14 +95,17 @@ describe('SequencesForm', () => { value: 'ATCG', initialValue: null, key: newFirstKey, - fastaHeader: 'subId_Segment1', + fastaHeader: FASTAHEADER, }, ]); - expect(editableSequences.getFastaIds()).toEqual('subId_Segment1'); + expect(editableSequences.getFastaIds()).toEqual(FASTAHEADER); } }); test('GIVEN organism with 2 segments THEN allows at max 2 inputs', async () => { + const FASTAHEADER_SEGMENT1 = 'FASTAHEADER'; + const FASTAHEADER_WITH_DESCRIPTION = FASTAHEADER_SEGMENT1 + ' description'; + const FASTAHEADER_SEGMENT2 = 'FASTAHEADER_SEGMENT2'; let editableSequences = EditableSequences.fromSequenceNames( makeReferenceGenomeLightweightSchema(['foo', 'bar']), ); @@ -113,12 +118,12 @@ describe('SequencesForm', () => { let secondKey; { - editableSequences = editableSequences.update(firstKey, 'ATCG', 'Segment 1', 'subId_Segment1 description'); + editableSequences = editableSequences.update(firstKey, 'ATCG', 'Segment 1', FASTAHEADER_WITH_DESCRIPTION); const fasta = editableSequences.getSequenceFasta(); expect(fasta).not.toBeUndefined(); const fastaText = await fasta!.text(); - expect.soft(fastaText).toBe('>subId_Segment1 description\nATCG'); - expect(editableSequences.getSequenceRecord()).deep.equals({ 'subId_Segment1 description': 'ATCG' }); + expect.soft(fastaText).toBe(`>${FASTAHEADER_WITH_DESCRIPTION}\nATCG`); + expect(editableSequences.getSequenceRecord()).deep.equals({ [FASTAHEADER_WITH_DESCRIPTION]: 'ATCG' }); const rows = editableSequences.rows; expect(rows).toEqual([ @@ -126,7 +131,7 @@ describe('SequencesForm', () => { label: 'Segment 1', value: 'ATCG', initialValue: null, - fastaHeader: 'subId_Segment1 description', + fastaHeader: FASTAHEADER_WITH_DESCRIPTION, key: firstKey, }, { label: 'Add a segment', value: null, initialValue: null, fastaHeader: null, key: expect.any(String) }, @@ -135,14 +140,14 @@ describe('SequencesForm', () => { } { - editableSequences = editableSequences.update(secondKey, 'TT', 'Segment 2', 'subId_Segment2'); + editableSequences = editableSequences.update(secondKey, 'TT', 'Segment 2', FASTAHEADER_SEGMENT2); const fasta = editableSequences.getSequenceFasta(); expect(fasta).not.toBeUndefined(); const fastaText = await fasta!.text(); - expect.soft(fastaText).toBe('>subId_Segment1 description\nATCG\n>subId_Segment2\nTT'); + expect.soft(fastaText).toBe(`>${FASTAHEADER_WITH_DESCRIPTION}\nATCG\n>${FASTAHEADER_SEGMENT2}\nTT`); expect(editableSequences.getSequenceRecord()).deep.equals({ - 'subId_Segment1 description': 'ATCG', - 'subId_Segment2': 'TT', + [FASTAHEADER_WITH_DESCRIPTION]: 'ATCG', + [FASTAHEADER_SEGMENT2]: 'TT', }); const rows = editableSequences.rows; @@ -152,19 +157,20 @@ describe('SequencesForm', () => { value: 'ATCG', initialValue: null, key: firstKey, - fastaHeader: 'subId_Segment1 description', + fastaHeader: FASTAHEADER_WITH_DESCRIPTION, }, - { label: 'Segment 2', value: 'TT', initialValue: null, key: secondKey, fastaHeader: 'subId_Segment2' }, + { label: 'Segment 2', value: 'TT', initialValue: null, key: secondKey, fastaHeader: FASTAHEADER_SEGMENT2 }, ]); } expect(() => editableSequences.update('another key', 'GG', 'another key', 'anything')).toThrowError( 'Maximum limit reached — you can add up to 2 sequence file(s) only.', ); - expect(editableSequences.getFastaIds()).toEqual('subId_Segment1 subId_Segment2'); + expect(editableSequences.getFastaIds()).toEqual(`${FASTAHEADER_SEGMENT1} ${FASTAHEADER_SEGMENT2}`); }); test('GIVEN a multi-segmented organism THEN do not allow duplicate fasta headers', () => { + const FASTAHEADER = 'FASTAHEADER'; let editableSequences = EditableSequences.fromSequenceNames( makeReferenceGenomeLightweightSchema(['foo', 'bar']), ); @@ -175,24 +181,25 @@ describe('SequencesForm', () => { ]); const firstKey = initialRows[0].key; - editableSequences = editableSequences.update(firstKey, 'ATCG', 'Segment 1', 'subId_Segment'); + editableSequences = editableSequences.update(firstKey, 'ATCG', 'Segment 1', FASTAHEADER); const rowsAfterFirstUpdate = editableSequences.rows; const secondKey = rowsAfterFirstUpdate[1].key; - editableSequences = editableSequences.update(secondKey, 'TT', 'Segment 2', 'subId_Segment description'); + editableSequences = editableSequences.update(secondKey, 'TT', 'Segment 2', 'FASTAHEADER description'); - const errorMessage = 'A sequence with the fastaID subId_Segment already exists.'; + const errorMessage = `A sequence with the fastaID ${FASTAHEADER} already exists.`; expect(toast.error).toHaveBeenCalledWith(expect.stringContaining(errorMessage)); // Expect that the second sequence was not added expect(editableSequences.rows).toEqual([ - { label: 'Segment 1', value: 'ATCG', initialValue: null, key: firstKey, fastaHeader: 'subId_Segment' }, + { label: 'Segment 1', value: 'ATCG', initialValue: null, key: firstKey, fastaHeader: FASTAHEADER }, { label: 'Add a segment', value: null, initialValue: null, fastaHeader: null, key: expect.any(String) }, ]); - expect(editableSequences.getFastaIds()).toEqual('subId_Segment'); + expect(editableSequences.getFastaIds()).toEqual(FASTAHEADER); }); test('GIVEN a single-segmented organism THEN only allows 1 input', async () => { + const FASTAHEADER = 'FASTAHEADER'; let editableSequences = EditableSequences.fromSequenceNames(makeReferenceGenomeLightweightSchema(['foo'])); const initialRows = editableSequences.rows; @@ -201,16 +208,16 @@ describe('SequencesForm', () => { ]); const key = initialRows[0].key; - editableSequences = editableSequences.update(key, 'ATCG', key, 'subId'); + editableSequences = editableSequences.update(key, 'ATCG', key, FASTAHEADER); const fasta = editableSequences.getSequenceFasta(); expect(fasta).not.toBeUndefined(); const fastaText = await fasta!.text(); - expect.soft(fastaText).toBe('>subId\nATCG'); + expect.soft(fastaText).toBe(`>${FASTAHEADER}\nATCG`); - expect(editableSequences.getSequenceRecord()).deep.equals({ subId: 'ATCG' }); + expect(editableSequences.getSequenceRecord()).deep.equals({ [FASTAHEADER]: 'ATCG' }); const rows = editableSequences.rows; - expect(rows).deep.equals([{ label: key, value: 'ATCG', initialValue: null, fastaHeader: 'subId', key }]); + expect(rows).deep.equals([{ label: key, value: 'ATCG', initialValue: null, fastaHeader: FASTAHEADER, key }]); expect(() => editableSequences.update('another key', 'GG', 'another key', 'anything')).toThrowError( 'Maximum limit reached — you can add up to 1 sequence file(s) only.', @@ -263,18 +270,19 @@ describe('SequencesForm', () => { }); test('GIVEN initial data with an empty segment THEN the fasta does not contain the empty segment', async () => { + const FASTAHEADER = 'FASTAHEADER_label'; let editableSequences = EditableSequences.fromInitialData( defaultReviewData, makeReferenceGenomeLightweightSchema(['originalSequenceName', 'anotherSequenceName']), ); - editableSequences = editableSequences.update(editableSequences.rows[0].key, 'ATCG', 'label', 'subId_label'); + editableSequences = editableSequences.update(editableSequences.rows[0].key, 'ATCG', 'label', FASTAHEADER); const fasta = editableSequences.getSequenceFasta(); expect(fasta).not.toBeUndefined(); const fastaText = await fasta!.text(); - expect.soft(fastaText).toBe('>subId_label\nATCG'); + expect.soft(fastaText).toBe(`>${FASTAHEADER}\nATCG`); - expect(editableSequences.getSequenceRecord()).deep.equals({ subId_label: 'ATCG' }); - expect(editableSequences.getFastaIds()).toEqual('subId_label'); + expect(editableSequences.getSequenceRecord()).deep.equals({ [FASTAHEADER]: 'ATCG' }); + expect(editableSequences.getFastaIds()).toEqual(FASTAHEADER); }); test('GIVEN initial segment data that is then deleted as an edit THEN the edit record does not contain the segment key but input field is kept', () => { From a453b0036bc6f294bc3c41b0dd16a5da23441a59 Mon Sep 17 00:00:00 2001 From: anna-parker <50943381+anna-parker@users.noreply.github.com> Date: Fri, 5 Dec 2025 13:24:41 +0100 Subject: [PATCH 12/14] format --- .../src/components/Edit/SequencesForm.spec.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/website/src/components/Edit/SequencesForm.spec.tsx b/website/src/components/Edit/SequencesForm.spec.tsx index baa480b96a..9633e392b0 100644 --- a/website/src/components/Edit/SequencesForm.spec.tsx +++ b/website/src/components/Edit/SequencesForm.spec.tsx @@ -29,7 +29,6 @@ function makeSubOrganismReferenceSchema(suborganisms: string[]): ReferenceGenome return result; } -/* eslint-disable @typescript-eslint/naming-convention -- this test has keys that expectedly contain spaces */ describe('SequencesForm', () => { beforeEach(() => { vi.spyOn(toast, 'error'); @@ -71,9 +70,9 @@ describe('SequencesForm', () => { ]); } - expect(() => editableSequences.update('another key', 'GG', 'another key', 'FASTAHEADER_anotherkey')).toThrowError( - 'Maximum limit reached — you can add up to 1 sequence file(s) only.', - ); + expect(() => + editableSequences.update('another key', 'GG', 'another key', 'FASTAHEADER_anotherkey'), + ).toThrowError('Maximum limit reached — you can add up to 1 sequence file(s) only.'); editableSequences = editableSequences.update(firstKey, null, null, null); expect(editableSequences.rows).toEqual([ { label: 'Add a segment', value: null, fastaHeader: null, initialValue: null, key: expect.any(String) }, @@ -159,7 +158,13 @@ describe('SequencesForm', () => { key: firstKey, fastaHeader: FASTAHEADER_WITH_DESCRIPTION, }, - { label: 'Segment 2', value: 'TT', initialValue: null, key: secondKey, fastaHeader: FASTAHEADER_SEGMENT2 }, + { + label: 'Segment 2', + value: 'TT', + initialValue: null, + key: secondKey, + fastaHeader: FASTAHEADER_SEGMENT2, + }, ]); } From 66df04ba4b062a0b49e095fe060686ffc5efaa65 Mon Sep 17 00:00:00 2001 From: "Anna (Anya) Parker" <50943381+anna-parker@users.noreply.github.com> Date: Fri, 5 Dec 2025 14:07:13 +0100 Subject: [PATCH 13/14] Update website/src/components/Edit/SequencesForm.tsx Co-authored-by: Fabian Engelniederhammer <92720311+fengelniederhammer@users.noreply.github.com> --- website/src/components/Edit/SequencesForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/components/Edit/SequencesForm.tsx b/website/src/components/Edit/SequencesForm.tsx index 9dc574a748..0ca6f2fc0e 100644 --- a/website/src/components/Edit/SequencesForm.tsx +++ b/website/src/components/Edit/SequencesForm.tsx @@ -24,7 +24,7 @@ function generateAndDownloadFastaFile(fastaHeader: string, sequenceData: string) function getFastaId(fastaHeader: string | null): string | null { if (!fastaHeader) return null; - return fastaHeader.split(/\s+/)[0] || null; + return fastaHeader.split(/\s+/)[0] ?? null; } type EditableSequenceFile = { From d924b46bdcf57c789e565285fc2e67bac53dfeb6 Mon Sep 17 00:00:00 2001 From: anna-parker <50943381+anna-parker@users.noreply.github.com> Date: Fri, 5 Dec 2025 14:09:25 +0100 Subject: [PATCH 14/14] make explicit --- website/src/components/Edit/SequencesForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/components/Edit/SequencesForm.tsx b/website/src/components/Edit/SequencesForm.tsx index 0ca6f2fc0e..2f5a9d63bc 100644 --- a/website/src/components/Edit/SequencesForm.tsx +++ b/website/src/components/Edit/SequencesForm.tsx @@ -168,7 +168,7 @@ export class EditableSequences { .flatMap((row) => { if (row.value === null) return []; const id = getFastaId(row.fastaHeader); - return id ? [id] : []; + return id === null || id === '' ? [] : [id]; }) .join(FASTA_IDS_SEPARATOR); }