From 7f6cd6bdc1cf5dd70491ef36496f549a195a2009 Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Thu, 29 Sep 2022 19:32:19 +0200 Subject: [PATCH 01/11] feat: allow hiding custom clade columns --- .../nextclade-web/src/state/results.state.ts | 18 ++++++++++++++++-- .../nextclade-web/src/types/auspice/index.d.ts | 1 + packages_rs/nextclade/src/tree/tree.rs | 2 ++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages_rs/nextclade-web/src/state/results.state.ts b/packages_rs/nextclade-web/src/state/results.state.ts index 1c07602726..29c2211a0b 100644 --- a/packages_rs/nextclade-web/src/state/results.state.ts +++ b/packages_rs/nextclade-web/src/state/results.state.ts @@ -215,11 +215,25 @@ export const hasTreeAtom = selector({ }, }) -export const cladeNodeAttrDescsAtom = atom({ - key: 'cladeNodeAttrDescs', +const cladeNodeAttrDescsStorageAtom = atom({ + key: 'cladeNodeAttrDescsStorage', default: [], }) +export const cladeNodeAttrDescsAtom = selector({ + key: 'cladeNodeAttrDescs', + get({ get }): CladeNodeAttrDesc[] { + return get(cladeNodeAttrDescsStorageAtom).filter(({ showInWeb }) => showInWeb) + }, + + set({ set, reset }, descs: CladeNodeAttrDesc[] | DefaultValue) { + set(cladeNodeAttrDescsStorageAtom, descs) + if (!isDefaultValue(descs)) { + reset(cladeNodeAttrDescsStorageAtom) + } + }, +}) + export const cladeNodeAttrKeysAtom = selector({ key: 'cladeNodeAttrKeys', get: ({ get }) => get(cladeNodeAttrDescsAtom).map((desc) => desc.name), diff --git a/packages_rs/nextclade-web/src/types/auspice/index.d.ts b/packages_rs/nextclade-web/src/types/auspice/index.d.ts index 5caad5c8fa..205050f216 100644 --- a/packages_rs/nextclade-web/src/types/auspice/index.d.ts +++ b/packages_rs/nextclade-web/src/types/auspice/index.d.ts @@ -203,6 +203,7 @@ declare module 'auspice' { name: string displayName: string description: string + showInWeb: boolean } export declare interface AuspiceMetadata { diff --git a/packages_rs/nextclade/src/tree/tree.rs b/packages_rs/nextclade/src/tree/tree.rs index de0b9c45ee..c0bc9a6655 100644 --- a/packages_rs/nextclade/src/tree/tree.rs +++ b/packages_rs/nextclade/src/tree/tree.rs @@ -167,6 +167,8 @@ pub struct CladeNodeAttrKeyDesc { pub name: String, pub display_name: String, pub description: String, + #[serde(default)] + pub show_in_web: bool, } #[derive(Clone, Serialize, Deserialize, Validate, Debug)] From 8e7eb6468099a40ebba11f190cc7c4083f70b6de Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Thu, 29 Sep 2022 19:54:33 +0200 Subject: [PATCH 02/11] fix: show custom clade columns by default Let's flip the boolean, so that it's natural default is `false` --- packages_rs/nextclade-web/src/state/results.state.ts | 2 +- packages_rs/nextclade-web/src/types/auspice/index.d.ts | 2 +- packages_rs/nextclade/src/tree/tree.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages_rs/nextclade-web/src/state/results.state.ts b/packages_rs/nextclade-web/src/state/results.state.ts index 29c2211a0b..49802ccc41 100644 --- a/packages_rs/nextclade-web/src/state/results.state.ts +++ b/packages_rs/nextclade-web/src/state/results.state.ts @@ -223,7 +223,7 @@ const cladeNodeAttrDescsStorageAtom = atom({ export const cladeNodeAttrDescsAtom = selector({ key: 'cladeNodeAttrDescs', get({ get }): CladeNodeAttrDesc[] { - return get(cladeNodeAttrDescsStorageAtom).filter(({ showInWeb }) => showInWeb) + return get(cladeNodeAttrDescsStorageAtom).filter(({ hideInWeb }) => !hideInWeb) }, set({ set, reset }, descs: CladeNodeAttrDesc[] | DefaultValue) { diff --git a/packages_rs/nextclade-web/src/types/auspice/index.d.ts b/packages_rs/nextclade-web/src/types/auspice/index.d.ts index 205050f216..52d79e2ee7 100644 --- a/packages_rs/nextclade-web/src/types/auspice/index.d.ts +++ b/packages_rs/nextclade-web/src/types/auspice/index.d.ts @@ -203,7 +203,7 @@ declare module 'auspice' { name: string displayName: string description: string - showInWeb: boolean + hideInWeb: boolean } export declare interface AuspiceMetadata { diff --git a/packages_rs/nextclade/src/tree/tree.rs b/packages_rs/nextclade/src/tree/tree.rs index c0bc9a6655..1a4ad872fa 100644 --- a/packages_rs/nextclade/src/tree/tree.rs +++ b/packages_rs/nextclade/src/tree/tree.rs @@ -168,7 +168,7 @@ pub struct CladeNodeAttrKeyDesc { pub display_name: String, pub description: String, #[serde(default)] - pub show_in_web: bool, + pub hide_in_web: bool, } #[derive(Clone, Serialize, Deserialize, Validate, Debug)] From 54117cf874a501233de65f136747d7c62718f276 Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Mon, 3 Oct 2022 22:23:40 +0200 Subject: [PATCH 03/11] fix: remove unused data from outputs Removes `results[].phenotypeValues.nameFriendly` and `results[].phenotypeValues.description` from output JSON and NDJSON. These fields were not intended to be used, are repeated and increase file size needlessly. --- packages_rs/nextclade/src/run/nextclade_run_one.rs | 2 -- packages_rs/nextclade/src/types/outputs.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/packages_rs/nextclade/src/run/nextclade_run_one.rs b/packages_rs/nextclade/src/run/nextclade_run_one.rs index 181df9dda0..0db3648a26 100644 --- a/packages_rs/nextclade/src/run/nextclade_run_one.rs +++ b/packages_rs/nextclade/src/run/nextclade_run_one.rs @@ -175,8 +175,6 @@ pub fn nextclade_run_one( Some(PhenotypeValue { name: name.clone(), gene: gene.clone(), - name_friendly: name_friendly.clone(), - description: description.clone(), value: phenotype, }) }) diff --git a/packages_rs/nextclade/src/types/outputs.rs b/packages_rs/nextclade/src/types/outputs.rs index bce11625a3..a7ce7413c3 100644 --- a/packages_rs/nextclade/src/types/outputs.rs +++ b/packages_rs/nextclade/src/types/outputs.rs @@ -39,8 +39,6 @@ pub struct NextalignOutputs { pub struct PhenotypeValue { pub name: String, pub gene: String, - pub name_friendly: String, - pub description: String, pub value: f64, } From ee0c659d3df32c226dd1cefc6d738bebf831f499 Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Mon, 3 Oct 2022 22:43:13 +0200 Subject: [PATCH 04/11] fix: add descriptions for phenotype attributes to outputs Adds descriptions of phenotype attributes to `.phenotypeAttrKeys` of JSON output. This is for symmetry with the similarly implemented `.cladeNodeAttrKeys` attributes. --- .../nextclade-cli/src/cli/nextclade_loop.rs | 6 ++-- .../src/cli/nextclade_ordered_writer.rs | 17 +++++++---- .../src/hooks/useExportResults.ts | 3 +- packages_rs/nextclade-web/src/wasm/main.rs | 16 +++++++++-- .../nextclade-web/src/workers/ExportThread.ts | 9 +++++- .../src/workers/nextcladeWasm.worker.ts | 2 ++ packages_rs/nextclade/src/io/results_json.rs | 28 +++++++++++++++---- 7 files changed, 63 insertions(+), 18 deletions(-) diff --git a/packages_rs/nextclade-cli/src/cli/nextclade_loop.rs b/packages_rs/nextclade-cli/src/cli/nextclade_loop.rs index 427de46d5e..34442a576b 100644 --- a/packages_rs/nextclade-cli/src/cli/nextclade_loop.rs +++ b/packages_rs/nextclade-cli/src/cli/nextclade_loop.rs @@ -10,7 +10,7 @@ use itertools::Itertools; use log::info; use nextclade::align::gap_open::{get_gap_open_close_scores_codon_aware, get_gap_open_close_scores_flat}; use nextclade::align::params::AlignPairwiseParams; -use nextclade::analyze::phenotype::get_phenotype_attr_keys; +use nextclade::analyze::phenotype::get_phenotype_attr_descs; use nextclade::io::fasta::{FastaReader, FastaRecord}; use nextclade::io::fs::has_extension; use nextclade::io::json::json_write; @@ -130,7 +130,7 @@ pub fn nextclade_run(run_args: NextcladeRunArgs) -> Result<(), Report> { let should_keep_outputs = output_tree.is_some(); let mut outputs = Vec::::new(); - let phenotype_attr_keys = get_phenotype_attr_keys(&virus_properties); + let phenotype_attrs = &get_phenotype_attr_descs(&virus_properties); std::thread::scope(|s| { const CHANNEL_SIZE: usize = 128; @@ -223,7 +223,7 @@ pub fn nextclade_run(run_args: NextcladeRunArgs) -> Result<(), Report> { let mut output_writer = NextcladeOrderedWriter::new( gene_map, clade_node_attrs, - &phenotype_attr_keys, + phenotype_attrs, &output_fasta, &output_json, &output_ndjson, diff --git a/packages_rs/nextclade-cli/src/cli/nextclade_ordered_writer.rs b/packages_rs/nextclade-cli/src/cli/nextclade_ordered_writer.rs index d2080795dd..9579758c9b 100644 --- a/packages_rs/nextclade-cli/src/cli/nextclade_ordered_writer.rs +++ b/packages_rs/nextclade-cli/src/cli/nextclade_ordered_writer.rs @@ -2,6 +2,7 @@ use crate::cli::nextclade_loop::NextcladeRecord; use eyre::{Report, WrapErr}; use itertools::Itertools; use log::warn; +use nextclade::analyze::virus_properties::PhenotypeAttrDesc; use nextclade::io::errors_csv::ErrorsCsvWriter; use nextclade::io::fasta::{FastaPeptideWriter, FastaRecord, FastaWriter}; use nextclade::io::gene_map::GeneMap; @@ -38,7 +39,7 @@ impl<'a> NextcladeOrderedWriter<'a> { pub fn new( gene_map: &'a GeneMap, clade_node_attr_key_descs: &[CladeNodeAttrKeyDesc], - phenotype_attr_keys: &[String], + phenotype_attr_key_desc: &[PhenotypeAttrDesc], output_fasta: &Option, output_json: &Option, output_ndjson: &Option, @@ -59,8 +60,9 @@ impl<'a> NextcladeOrderedWriter<'a> { let errors_csv_writer = output_errors.map_ref_fallible(|output_errors| ErrorsCsvWriter::new(gene_map, &output_errors))?; - let output_json_writer = - output_json.map_ref_fallible(|output_json| ResultsJsonWriter::new(&output_json, clade_node_attr_key_descs))?; + let output_json_writer = output_json.map_ref_fallible(|output_json| { + ResultsJsonWriter::new(&output_json, clade_node_attr_key_descs, phenotype_attr_key_desc) + })?; let output_ndjson_writer = output_ndjson.map_ref_fallible(NdjsonFileWriter::new)?; @@ -69,12 +71,17 @@ impl<'a> NextcladeOrderedWriter<'a> { .map(|desc| desc.name.clone()) .collect_vec(); + let phenotype_attr_keys = phenotype_attr_key_desc + .iter() + .map(|desc| desc.name.clone()) + .collect_vec(); + let output_csv_writer = output_csv.map_ref_fallible(|output_csv| { - NextcladeResultsCsvFileWriter::new(&output_csv, b';', &clade_node_attr_keys, phenotype_attr_keys) + NextcladeResultsCsvFileWriter::new(&output_csv, b';', &clade_node_attr_keys, &phenotype_attr_keys) })?; let output_tsv_writer = output_tsv.map_ref_fallible(|output_tsv| { - NextcladeResultsCsvFileWriter::new(&output_tsv, b'\t', &clade_node_attr_keys, phenotype_attr_keys) + NextcladeResultsCsvFileWriter::new(&output_tsv, b'\t', &clade_node_attr_keys, &phenotype_attr_keys) })?; Ok(Self { diff --git a/packages_rs/nextclade-web/src/hooks/useExportResults.ts b/packages_rs/nextclade-web/src/hooks/useExportResults.ts index c826f8088e..bd78d59e7d 100644 --- a/packages_rs/nextclade-web/src/hooks/useExportResults.ts +++ b/packages_rs/nextclade-web/src/hooks/useExportResults.ts @@ -112,7 +112,8 @@ async function prepareResultsJson(snapshot: Snapshot, worker: ExportWorker) { const results = await mapGoodResults(snapshot, (result) => result.analysisResult) const errors = await mapErrors(snapshot, (err) => err) const cladeNodeAttrDescs = await snapshot.getPromise(cladeNodeAttrDescsAtom) - return worker.serializeResultsJson(results, errors, cladeNodeAttrDescs, PACKAGE_VERSION) + const phenotypeAttrDescs = await snapshot.getPromise(phenotypeAttrDescsAtom) + return worker.serializeResultsJson(results, errors, cladeNodeAttrDescs, phenotypeAttrDescs, PACKAGE_VERSION) } export function useExportJson() { diff --git a/packages_rs/nextclade-web/src/wasm/main.rs b/packages_rs/nextclade-web/src/wasm/main.rs index d2a8f57b62..84640a4e73 100644 --- a/packages_rs/nextclade-web/src/wasm/main.rs +++ b/packages_rs/nextclade-web/src/wasm/main.rs @@ -119,6 +119,7 @@ impl NextcladeWasm { outputs_json_str: &str, errors_json_str: &str, clade_node_attrs_json_str: &str, + phenotype_attrs_json_str: &str, nextclade_web_version: Option, ) -> Result { let outputs: Vec = jserr( @@ -134,9 +135,20 @@ impl NextcladeWasm { .wrap_err("When serializing results JSON: When parsing clade node attrs JSON internally"), )?; + let phenotype_attrs: Vec = jserr( + json_parse(phenotype_attrs_json_str) + .wrap_err("When serializing results JSON: When parsing phenotypes attr keys JSON internally"), + )?; + jserr( - results_to_json_string(&outputs, &errors, &clade_node_attrs, &nextclade_web_version) - .wrap_err("When serializing results JSON"), + results_to_json_string( + &outputs, + &errors, + &clade_node_attrs, + &phenotype_attrs, + &nextclade_web_version, + ) + .wrap_err("When serializing results JSON"), ) } diff --git a/packages_rs/nextclade-web/src/workers/ExportThread.ts b/packages_rs/nextclade-web/src/workers/ExportThread.ts index 3615525a6e..20df8edee2 100644 --- a/packages_rs/nextclade-web/src/workers/ExportThread.ts +++ b/packages_rs/nextclade-web/src/workers/ExportThread.ts @@ -27,9 +27,16 @@ export class ExportWorker { outputs: AnalysisResult[], errors: AnalysisError[], cladeNodeAttrsJson: CladeNodeAttrDesc[], + phenotypeAttrsJson: PhenotypeAttrDesc[], nextcladeWebVersion: string, ): Promise { - return this.thread.serializeResultsJson(outputs, errors, cladeNodeAttrsJson, nextcladeWebVersion) + return this.thread.serializeResultsJson( + outputs, + errors, + cladeNodeAttrsJson, + phenotypeAttrsJson, + nextcladeWebVersion, + ) } public async serializeResultsCsv( diff --git a/packages_rs/nextclade-web/src/workers/nextcladeWasm.worker.ts b/packages_rs/nextclade-web/src/workers/nextcladeWasm.worker.ts index 37c4e6ba0d..f0013b4282 100644 --- a/packages_rs/nextclade-web/src/workers/nextcladeWasm.worker.ts +++ b/packages_rs/nextclade-web/src/workers/nextcladeWasm.worker.ts @@ -194,12 +194,14 @@ export async function serializeResultsJson( outputs: AnalysisResult[], errors: AnalysisError[], cladeNodeAttrsJson: CladeNodeAttrDesc[], + phenotypeAttrsJson: PhenotypeAttrDesc[], nextcladeWebVersion: string, ) { return NextcladeWasm.serialize_results_json( JSON.stringify(outputs), JSON.stringify(errors), JSON.stringify(cladeNodeAttrsJson), + JSON.stringify(phenotypeAttrsJson), nextcladeWebVersion, ) } diff --git a/packages_rs/nextclade/src/io/results_json.rs b/packages_rs/nextclade/src/io/results_json.rs index c01ee5e2e1..9bcf534fd3 100644 --- a/packages_rs/nextclade/src/io/results_json.rs +++ b/packages_rs/nextclade/src/io/results_json.rs @@ -1,3 +1,4 @@ +use crate::analyze::virus_properties::PhenotypeAttrDesc; use crate::io::json::{json_stringify, json_write}; use crate::io::ndjson::NdjsonWriter; use crate::tree::tree::CladeNodeAttrKeyDesc; @@ -23,13 +24,15 @@ pub struct ResultsJson { pub clade_node_attr_keys: Vec, + pub phenotype_attr_keys: Vec, + pub results: Vec, pub errors: Vec, } impl ResultsJson { - pub fn new(clade_node_attrs: &[CladeNodeAttrKeyDesc]) -> Self { + pub fn new(clade_node_attrs: &[CladeNodeAttrKeyDesc], phenotype_attr_keys: &[PhenotypeAttrDesc]) -> Self { const VERSION: &str = env!("CARGO_PKG_VERSION"); Self { @@ -37,7 +40,8 @@ impl ResultsJson { nextclade_algo_version: VERSION.to_owned(), nextclade_web_version: None, created_at: date_iso_now(), - clade_node_attr_keys: Vec::::from(clade_node_attrs), + clade_node_attr_keys: clade_node_attrs.to_vec(), + phenotype_attr_keys: phenotype_attr_keys.to_vec(), results: vec![], errors: vec![], } @@ -47,9 +51,10 @@ impl ResultsJson { outputs: &[NextcladeOutputs], errors: &[NextcladeErrorOutputs], clade_node_attrs: &[CladeNodeAttrKeyDesc], + phenotype_attr_keys: &[PhenotypeAttrDesc], nextclade_web_version: &Option, ) -> Self { - let mut this = Self::new(clade_node_attrs); + let mut this = Self::new(clade_node_attrs, phenotype_attr_keys); this.results = outputs.to_vec(); this.errors = errors.to_vec(); this.nextclade_web_version = nextclade_web_version.clone(); @@ -63,10 +68,14 @@ pub struct ResultsJsonWriter { } impl ResultsJsonWriter { - pub fn new(filepath: impl AsRef, clade_node_attrs: &[CladeNodeAttrKeyDesc]) -> Result { + pub fn new( + filepath: impl AsRef, + clade_node_attrs: &[CladeNodeAttrKeyDesc], + phenotype_attr_keys: &[PhenotypeAttrDesc], + ) -> Result { Ok(Self { filepath: filepath.as_ref().to_owned(), - result: ResultsJson::new(clade_node_attrs), + result: ResultsJson::new(clade_node_attrs, phenotype_attr_keys), }) } @@ -98,9 +107,16 @@ pub fn results_to_json_string( outputs: &[NextcladeOutputs], errors: &[NextcladeErrorOutputs], clade_node_attrs: &[CladeNodeAttrKeyDesc], + phenotype_attr_keys: &[PhenotypeAttrDesc], nextclade_web_version: &Option, ) -> Result { - let results_json = ResultsJson::from_outputs(outputs, errors, clade_node_attrs, nextclade_web_version); + let results_json = ResultsJson::from_outputs( + outputs, + errors, + clade_node_attrs, + phenotype_attr_keys, + nextclade_web_version, + ); json_stringify(&results_json) } From d30d60885f8a68d382b04570f388cdeb094503aa Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Tue, 4 Oct 2022 00:37:01 +0200 Subject: [PATCH 05/11] fix: reset node attr state correctly across runs --- packages_rs/nextclade-web/src/state/results.state.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages_rs/nextclade-web/src/state/results.state.ts b/packages_rs/nextclade-web/src/state/results.state.ts index 49802ccc41..5a807e3782 100644 --- a/packages_rs/nextclade-web/src/state/results.state.ts +++ b/packages_rs/nextclade-web/src/state/results.state.ts @@ -228,7 +228,7 @@ export const cladeNodeAttrDescsAtom = selector({ set({ set, reset }, descs: CladeNodeAttrDesc[] | DefaultValue) { set(cladeNodeAttrDescsStorageAtom, descs) - if (!isDefaultValue(descs)) { + if (isDefaultValue(descs)) { reset(cladeNodeAttrDescsStorageAtom) } }, From 1c3377b22b43acb5b7231300897d29636b78dd02 Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Tue, 4 Oct 2022 02:37:50 +0200 Subject: [PATCH 06/11] chore: speedup wasm dev build Here for wasm dev build I replace the `wasm-pack` which is nice, but behind its defaults it hides lots of useful stuff, and I call `cargo build`, `wasm-bindgen` and `wasm-opt` explicitly. Notably `wasm-pack` does not allow custom cargo profiles (https://github.com/rustwasm/wasm-pack/issues/1111). I also add the new "opt-dev" cargo profile, which is something in the middle between `release` and `dev` - a balance between rebuild speed and runtime performance. This should save lots of time during day-to-day work. The production version still uses `wasm-pack` and a more tried solution. The dev version now requires cargo wasm toolchain, `wasm-bindgen` and `wasm-opt` (from `binaryen` project) installed manually. Previously `wasm-pack` would handle that. The dev docker image was updated accordingly. --- .cargo/config.toml | 27 ++++++++++++++++++++++++++ docker/docker-dev.dockerfile | 5 +++++ packages_rs/nextclade-web/package.json | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index e2c7ff48e3..01addc37cd 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -22,6 +22,33 @@ opt-level = 3 [profile.dev.package.pretty_assertions] opt-level = 3 + +[profile.opt-dev] +inherits = "dev" +codegen-units = 128 +incremental = true +opt-level = 2 +lto = "off" +panic = "abort" +strip = true + +# Optimize dependencies even in debug mode +[profile.opt-dev.package."*"] +opt-level = 2 +[profile.opt-dev.package.backtrace] +opt-level = 3 +[profile.opt-dev.package.color-spantrace] +opt-level = 3 +[profile.opt-dev.package.tracing] +opt-level = 3 +[profile.opt-dev.package.tracing-error] +opt-level = 3 +[profile.opt-dev.package.tracing-subscriber] +opt-level = 3 +[profile.opt-dev.package.pretty_assertions] +opt-level = 3 + + [profile.release] codegen-units = 1 incremental = false diff --git a/docker/docker-dev.dockerfile b/docker/docker-dev.dockerfile index a8d13d4e50..6e1a13b5dc 100644 --- a/docker/docker-dev.dockerfile +++ b/docker/docker-dev.dockerfile @@ -186,6 +186,11 @@ RUN set -euxo pipefail >/dev/null \ && curl -sSL "https://github.com/rustwasm/wasm-bindgen/releases/download/${WASM_BINDGEN_CLI_VERSION}/wasm-bindgen-${WASM_BINDGEN_CLI_VERSION}-x86_64-unknown-linux-musl.tar.gz" | tar -C "${CARGO_HOME}/bin" --strip-components=1 -xz "wasm-bindgen-${WASM_BINDGEN_CLI_VERSION}-x86_64-unknown-linux-musl/wasm-bindgen" \ && chmod +x "${CARGO_HOME}/bin/wasm-bindgen" +RUN set -euxo pipefail >/dev/null \ +&& export BINARYEN_VERSION="110" \ +&& curl -sSL "https://github.com/WebAssembly/binaryen/releases/download/version_${BINARYEN_VERSION}/binaryen-version_${BINARYEN_VERSION}-x86_64-linux.tar.gz" | tar -C "${CARGO_HOME}/bin" --strip-components=2 -xz "binaryen-version_${BINARYEN_VERSION}/bin/wasm-opt" \ +&& chmod +x "${CARGO_HOME}/bin/wasm-opt" + # Install executable dependencies RUN set -euxo pipefail >/dev/null \ && cargo quickinstall cargo-audit \ diff --git a/packages_rs/nextclade-web/package.json b/packages_rs/nextclade-web/package.json index 253273d385..e8c2187f72 100644 --- a/packages_rs/nextclade-web/package.json +++ b/packages_rs/nextclade-web/package.json @@ -78,7 +78,7 @@ "monkey-patch": "bash tools/auspice-monkey-patch.sh && yarn run:node tools/monkeyPatch.ts", "changelog": "yarn conventional-changelog -p angular -i CHANGELOG.md -s -r 1", "serve-data": "babel-node --config-file \"./babel-node.config.js\" --extensions \".ts\" ./tools/server/dataServer.ts", - "wasm-dev": "wasm-pack --quiet --log-level=error build --dev --target=bundler --out-dir=.build/wasm-dev/ --out-name=nextclade-wasm -- --package=nextclade-web --locked && mkdir -p src/gen/ && cp .build/wasm-dev/* src/gen/", + "wasm-dev": "cargo build -q --profile=opt-dev --package=nextclade-web --lib --target=wasm32-unknown-unknown --target-dir=.build/docker/wasm-dev/ && wasm-bindgen .build/docker/wasm-dev/wasm32-unknown-unknown/opt-dev/nextclade_web.wasm --target=bundler --out-dir=.build/wasm-prod/ --out-name=nextclade-wasm && wasm-opt -O --optimize-level=1 --shrink-level=1 .build/docker/wasm-dev/wasm32-unknown-unknown/opt-dev/nextclade_web.wasm -o .build/wasm-prod/nextclade-wasm.wasm && mkdir -p src/gen/ && cp .build/wasm-prod/* src/gen/", "wasm-prod": "wasm-pack --quiet --log-level=error build --release --target=bundler --out-dir=.build/wasm-prod/ --out-name=nextclade-wasm -- --package=nextclade-web --locked && mkdir -p src/gen/ && cp .build/wasm-prod/* src/gen/" }, "dependencies": { From ae497682278c2319fa5013e35479359d4a8a5dc8 Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Tue, 4 Oct 2022 02:49:31 +0200 Subject: [PATCH 07/11] fix: adjust import For the changes in 1c3377b22b43acb5b7231300897d29636b78dd02 (there no longer is `package.json`, so import of the directory does not work) --- packages_rs/nextclade-web/src/workers/launchAnalysis.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages_rs/nextclade-web/src/workers/launchAnalysis.ts b/packages_rs/nextclade-web/src/workers/launchAnalysis.ts index de4eef9fec..1a9a49de8c 100644 --- a/packages_rs/nextclade-web/src/workers/launchAnalysis.ts +++ b/packages_rs/nextclade-web/src/workers/launchAnalysis.ts @@ -4,7 +4,7 @@ import { isEmpty } from 'lodash' import { AlgorithmGlobalStatus, PhenotypeAttrDesc } from 'src/types' import type { AlgorithmInput, DatasetFiles, Dataset, FastaRecordId, Gene, NextcladeResult } from 'src/types' -import type { NextcladeParamsPojo } from 'src/gen' +import type { NextcladeParamsPojo } from 'src/gen/nextclade-wasm' import { ErrorInternal } from 'src/helpers/ErrorInternal' import type { LauncherThread } from 'src/workers/launcher.worker' import { spawn } from 'src/workers/spawn' From 4f5db091285a390bccc966283aafa78b61e7d21e Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Tue, 4 Oct 2022 13:48:11 +0200 Subject: [PATCH 08/11] fix(web): crash when exporting files in web Followup of https://github.com/nextstrain/nextclade/pull/1006 The PR https://github.com/nextstrain/nextclade/pull/1006 introduced a bug: it filters away hidden columns from recoil state, thus making them unavailable for export functions. The mismatch in expected columns caused crash on Rust side. Here I modify the filtering logic, moving it to the actual rendering site, instead of filtering globally. This way, hidden columns are not rendered, but are still be available for export. --- .../src/components/Results/ResultsTable.tsx | 46 +++++++++---------- .../components/Results/ResultsTableRow.tsx | 14 +++--- .../Results/ResultsTableRowResult.tsx | 31 +++++++------ .../nextclade-web/src/state/results.state.ts | 18 +------- 4 files changed, 49 insertions(+), 60 deletions(-) diff --git a/packages_rs/nextclade-web/src/components/Results/ResultsTable.tsx b/packages_rs/nextclade-web/src/components/Results/ResultsTable.tsx index 1f72455434..f654ceff78 100644 --- a/packages_rs/nextclade-web/src/components/Results/ResultsTable.tsx +++ b/packages_rs/nextclade-web/src/components/Results/ResultsTable.tsx @@ -16,9 +16,7 @@ import { } from 'src/state/settings.state' import { cladeNodeAttrDescsAtom, - cladeNodeAttrKeysAtom, phenotypeAttrDescsAtom, - phenotypeAttrKeysAtom, seqIndicesFilteredAtom, sortAnalysisResultsAtom, sortAnalysisResultsByKeyAtom, @@ -69,9 +67,7 @@ export function ResultsTable() { const columnWidthsPx = useRecoilValue(resultsTableColumnWidthsPxAtom) const dynamicCladeColumnWidthPx = useRecoilValue(resultsTableDynamicCladeColumnWidthPxAtom) const dynamicPhenotypeColumnWidthPx = useRecoilValue(resultsTableDynamicPhenotypeColumnWidthPxAtom) - const cladeNodeAttrKeys = useRecoilValue(cladeNodeAttrKeysAtom) const cladeNodeAttrDescs = useRecoilValue(cladeNodeAttrDescsAtom) - const phenotypeAttrKeys = useRecoilValue(phenotypeAttrKeysAtom) const phenotypeAttrDescs = useRecoilValue(phenotypeAttrDescsAtom) const isResultsFilterPanelCollapsed = useRecoilValue(isResultsFilterPanelCollapsedAtom) @@ -84,15 +80,15 @@ export function ResultsTable() { columnWidthsPx, dynamicCladeColumnWidthPx, dynamicPhenotypeColumnWidthPx, - cladeNodeAttrKeys, - phenotypeAttrKeys, + cladeNodeAttrDescs, + phenotypeAttrDescs, })) }, [ - cladeNodeAttrKeys, + cladeNodeAttrDescs, columnWidthsPx, dynamicCladeColumnWidthPx, dynamicPhenotypeColumnWidthPx, - phenotypeAttrKeys, + phenotypeAttrDescs, seqIndices, viewedGene, ]) @@ -176,22 +172,24 @@ export function ResultsTable() { }, []) // prettier-ignore const dynamicCladeColumns = useMemo(() => { - return cladeNodeAttrDescs.map(({ name: attrKey, displayName, description }) => { - const sortAsc = sortByKey(attrKey, SortDirection.asc) - const sortDesc = sortByKey(attrKey, SortDirection.desc) - return ( - - - {displayName} - - - -
{`Column: ${displayName}`}
-

{description}

-
-
- ) - }) + return cladeNodeAttrDescs + .filter((attr) => !attr.hideInWeb) + .map(({ name: attrKey, displayName, description }) => { + const sortAsc = sortByKey(attrKey, SortDirection.asc) + const sortDesc = sortByKey(attrKey, SortDirection.desc) + return ( + + + {displayName} + + + +
{`Column: ${displayName}`}
+

{description}

+
+
+ ) + }) }, [cladeNodeAttrDescs, dynamicCladeColumnWidthPx, sortByKey]) const dynamicPhenotypeColumns = useMemo(() => { diff --git a/packages_rs/nextclade-web/src/components/Results/ResultsTableRow.tsx b/packages_rs/nextclade-web/src/components/Results/ResultsTableRow.tsx index 0ace9d0981..b73de3b79a 100644 --- a/packages_rs/nextclade-web/src/components/Results/ResultsTableRow.tsx +++ b/packages_rs/nextclade-web/src/components/Results/ResultsTableRow.tsx @@ -2,6 +2,8 @@ import React, { memo, useMemo } from 'react' import { areEqual, ListChildComponentProps } from 'react-window' import { useRecoilValue } from 'recoil' +import type { CladeNodeAttrDesc } from 'auspice' +import type { PhenotypeAttrDesc } from 'src/types' import { COLUMN_WIDTHS } from 'src/components/Results/ResultsTableStyle' import { analysisResultAtom } from 'src/state/results.state' import { ResultsTableRowError } from './ResultsTableRowError' @@ -14,8 +16,8 @@ export interface TableRowDatum { columnWidthsPx: Record dynamicCladeColumnWidthPx: string dynamicPhenotypeColumnWidthPx: string - cladeNodeAttrKeys: string[] - phenotypeAttrKeys: string[] + cladeNodeAttrDescs: CladeNodeAttrDesc[] + phenotypeAttrDescs: PhenotypeAttrDesc[] } export interface RowProps extends ListChildComponentProps { @@ -31,8 +33,8 @@ function ResultsTableRowUnmemoed({ index, data, ...restProps }: RowProps) { columnWidthsPx, dynamicCladeColumnWidthPx, dynamicPhenotypeColumnWidthPx, - cladeNodeAttrKeys, - phenotypeAttrKeys, + cladeNodeAttrDescs, + phenotypeAttrDescs, } = useMemo(() => data[index], [data, index]) const { result, error } = useRecoilValue(analysisResultAtom(seqIndex)) @@ -49,8 +51,8 @@ function ResultsTableRowUnmemoed({ index, data, ...restProps }: RowProps) { columnWidthsPx={columnWidthsPx} dynamicCladeColumnWidthPx={dynamicCladeColumnWidthPx} dynamicPhenotypeColumnWidthPx={dynamicPhenotypeColumnWidthPx} - cladeNodeAttrKeys={cladeNodeAttrKeys} - phenotypeAttrKeys={phenotypeAttrKeys} + cladeNodeAttrDescs={cladeNodeAttrDescs} + phenotypeAttrDescs={phenotypeAttrDescs} viewedGene={viewedGene} /> ) diff --git a/packages_rs/nextclade-web/src/components/Results/ResultsTableRowResult.tsx b/packages_rs/nextclade-web/src/components/Results/ResultsTableRowResult.tsx index 64e9dddc95..d04f9d95f9 100644 --- a/packages_rs/nextclade-web/src/components/Results/ResultsTableRowResult.tsx +++ b/packages_rs/nextclade-web/src/components/Results/ResultsTableRowResult.tsx @@ -2,7 +2,7 @@ import { mix } from 'polished' import React, { ReactNode, Suspense, useMemo } from 'react' import { useRecoilValue } from 'recoil' -import { QcStatus } from 'src/types' +import { PhenotypeAttrDesc, QcStatus } from 'src/types' import { ColumnClade } from 'src/components/Results/ColumnClade' import { ColumnCustomNodeAttr } from 'src/components/Results/ColumnCustomNodeAttr' import { ColumnFrameShifts } from 'src/components/Results/ColumnFrameShifts' @@ -27,12 +27,13 @@ import { SequenceView } from 'src/components/SequenceView/SequenceView' import { GENE_OPTION_NUC_SEQUENCE } from 'src/constants' import { analysisResultAtom } from 'src/state/results.state' import { ColumnCoverage } from 'src/components/Results/ColumnCoverage' +import { CladeNodeAttrDesc } from 'auspice' export interface ResultsTableRowResultProps { index: number viewedGene: string - cladeNodeAttrKeys: string[] - phenotypeAttrKeys: string[] + cladeNodeAttrDescs: CladeNodeAttrDesc[] + phenotypeAttrDescs: PhenotypeAttrDesc[] columnWidthsPx: Record dynamicCladeColumnWidthPx: string dynamicPhenotypeColumnWidthPx: string @@ -74,8 +75,8 @@ export function TableRowColored({ export function ResultsTableRowResult({ index, viewedGene, - cladeNodeAttrKeys, - phenotypeAttrKeys, + cladeNodeAttrDescs, + phenotypeAttrDescs, columnWidthsPx, dynamicCladeColumnWidthPx, dynamicPhenotypeColumnWidthPx, @@ -118,15 +119,17 @@ export function ResultsTableRowResult({ - {cladeNodeAttrKeys.map((attrKey) => ( - - - - ))} - - {phenotypeAttrKeys.map((attrKey) => ( - - + {cladeNodeAttrDescs + .filter((attr) => !attr.hideInWeb) + .map(({ name }) => ( + + + + ))} + + {phenotypeAttrDescs.map(({ name }) => ( + + ))} diff --git a/packages_rs/nextclade-web/src/state/results.state.ts b/packages_rs/nextclade-web/src/state/results.state.ts index 5a807e3782..1c07602726 100644 --- a/packages_rs/nextclade-web/src/state/results.state.ts +++ b/packages_rs/nextclade-web/src/state/results.state.ts @@ -215,23 +215,9 @@ export const hasTreeAtom = selector({ }, }) -const cladeNodeAttrDescsStorageAtom = atom({ - key: 'cladeNodeAttrDescsStorage', - default: [], -}) - -export const cladeNodeAttrDescsAtom = selector({ +export const cladeNodeAttrDescsAtom = atom({ key: 'cladeNodeAttrDescs', - get({ get }): CladeNodeAttrDesc[] { - return get(cladeNodeAttrDescsStorageAtom).filter(({ hideInWeb }) => !hideInWeb) - }, - - set({ set, reset }, descs: CladeNodeAttrDesc[] | DefaultValue) { - set(cladeNodeAttrDescsStorageAtom, descs) - if (isDefaultValue(descs)) { - reset(cladeNodeAttrDescsStorageAtom) - } - }, + default: [], }) export const cladeNodeAttrKeysAtom = selector({ From f0975a2914b6f073dd1a3314c9006e5bab7463ef Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Tue, 4 Oct 2022 13:58:06 +0200 Subject: [PATCH 09/11] chore: remove unused script [skip ci] --- convert.py | 45 --------------------------------------------- 1 file changed, 45 deletions(-) delete mode 100644 convert.py diff --git a/convert.py b/convert.py deleted file mode 100644 index 2e88b716b7..0000000000 --- a/convert.py +++ /dev/null @@ -1,45 +0,0 @@ -import json -from pprint import pprint - -# - "rbdRange" renamed to "aaRange" -# - "weights" and "coefficients" are merged into an object, to avoid useless lookup. One-to-one mapping is assumed. -# - entries where weight is 0 are removed -# - "locations" is a map of either: -# - position to coefficient -# - position to a map of AA to a coefficient -if __name__ == '__main__': - with open("data_dev/virus_properties_.json") as f: - data = json.load(f) - - def convert_escape_data(escapeData): - weights = escapeData["weights"] - coefficients = escapeData["coefficients"] - - data = [] - for name, weight in weights.items(): - if weight == 0: - continue - - coeffs = coefficients.get(name) - - data.append({ - "name": name, - "weight": weight, - "locations": coeffs, - }) - - escapeData = { - **escapeData, - "aaRange": escapeData["rbdRange"], - "data": data - } - del escapeData["weights"] - del escapeData["coefficients"] - del escapeData["rbdRange"] - - return escapeData - - data["escapeData"] = list(map(convert_escape_data, data["escapeData"])) - - with open("data_dev/virus_properties.json", "w") as f: - json.dump(data, f, indent=2) From 19b1932d2cd252e85745e0e3fac3bc83121e0669 Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Tue, 4 Oct 2022 14:19:09 +0200 Subject: [PATCH 10/11] chore: document dev scripts [skip ci] --- docker-cross | 2 ++ docker-dev | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/docker-cross b/docker-cross index 476f3e4a43..cace3dec7b 100755 --- a/docker-cross +++ b/docker-cross @@ -1,5 +1,7 @@ #!/usr/bin/env bash +# Runs bulk cross-compilation of CLI binaries for all supported platforms + set -euo pipefail function abspath() { diff --git a/docker-dev b/docker-dev index d209fbc1bb..a751b782bb 100755 --- a/docker-dev +++ b/docker-dev @@ -1,5 +1,60 @@ #!/usr/bin/env bash +# Runs various day-to-day dev commands inside dev docker container. +# +# The container includes all the tools required for maintaining the project. But this container and script exist +# for convenience only and are not required for operations. The usual `cargo` and `yarn` workflows can still be used +# (see dev guide). +# +# See the full list of possible commands in the long `case` block halfway through the script. +# Here are some of the most useful ones: +# +# * Build nextclade binary in debug mode: +# ./docker-dev b nextclade +# +# * Build nextclade binary in release mode: +# ./docker-dev br nextclade +# +# * Build and run nextclade binary in debug mode, with arguments: +# ./docker-dev r nextclade -- dataset list --help +# +# * Build and run nextclade binary in release mode, with arguments: +# ./docker-dev rr nextclade -- dataset list --help +# +# * Cross-compile nextclade binary for Windows in release mode: +# CROSS=x86_64-pc-windows-gnu ./docker-dev br +# +# * Build WebAssembly module in debug mode: +# ./docker-dev W +# +# * Build WebAssembly module in release mode: +# ./docker-dev Wr +# +# * Build and run web application in debug mode: +# ./docker-dev a +# +# * Build and run web application in release mode: +# ./docker-dev war +# +# * Lint Rust code: +# ./docker-dev l +# +# * Lint Rust code, apply automatic fixes: +# ./docker-dev lf +# +# * Format Rust code: +# ./docker-dev f +# +# * Shell into the container: +# ./docker-dev bash +# +# * Run arbitrary command inside the container: +# ./docker-dev cargo --version +# +# * Run arbitrary yarn command, in the context of web app, inside the container: +# ./docker-dev a yarn add --dev react +# + set -euo pipefail function abspath() { From 66c6dd25b01a762afe915c2f349c9a876b0d53ea Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Wed, 5 Oct 2022 16:23:09 +0200 Subject: [PATCH 11/11] chore: release web and cli 2.7.0 --- CHANGELOG.md | 11 +++++++++++ Cargo.lock | 6 +++--- packages_rs/nextclade-cli/Cargo.toml | 2 +- packages_rs/nextclade-web/Cargo.toml | 2 +- packages_rs/nextclade-web/package.json | 2 +- packages_rs/nextclade/Cargo.toml | 2 +- 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 219642f040..1d861ffecb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## Nextclade Web 2.7.0 (2022-10-05) + +### Hide custom clade columns + +We added ability to mark certain custom clade columns as hidden. In this case they are not shown in Nextclade Web. This prepares the web application for the upcoming reorganization of clade columns. It should not affect current users. + +### Remove unused fields from output files, add custom phenotype key list + +We removed extra repetitive fields related to custom phenotype columns (e.g. "Immune escape" and "ACE-2 binding") entries from JSON and NDJSON output files. We also added keys for custom phenotype columns to the header section of output JSON, for symmetry with custom clade columns. These changes should not affect most users. + + ## Nextclade Web 2.6.1 (2022-09-28) ### Prettier tooltips diff --git a/Cargo.lock b/Cargo.lock index 97b4d4dcaf..18d6381eea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1461,7 +1461,7 @@ dependencies = [ [[package]] name = "nextclade" -version = "2.6.0" +version = "2.7.0" dependencies = [ "assert2", "atty", @@ -1511,7 +1511,7 @@ dependencies = [ [[package]] name = "nextclade-cli" -version = "2.6.0" +version = "2.7.0" dependencies = [ "assert2", "clap 3.1.18", @@ -1550,7 +1550,7 @@ dependencies = [ [[package]] name = "nextclade-web" -version = "2.6.0" +version = "2.7.0" dependencies = [ "assert2", "console_error_panic_hook", diff --git a/packages_rs/nextclade-cli/Cargo.toml b/packages_rs/nextclade-cli/Cargo.toml index 5598fe1e0a..b337c8a389 100644 --- a/packages_rs/nextclade-cli/Cargo.toml +++ b/packages_rs/nextclade-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nextclade-cli" -version = "2.6.0" +version = "2.7.0" description = "Alignment, mutation calling, phylogenetic placement, clade assignment and quality control checks for viral genetic sequences. CLI module." repository = "https://github.com/nextstrain/nextclade" documentation = "https://docs.nextstrain.org/projects/nextclade/en/stable/" diff --git a/packages_rs/nextclade-web/Cargo.toml b/packages_rs/nextclade-web/Cargo.toml index f803c2303d..53ba67ccff 100644 --- a/packages_rs/nextclade-web/Cargo.toml +++ b/packages_rs/nextclade-web/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nextclade-web" -version = "2.6.0" +version = "2.7.0" description = "Alignment, mutation calling, phylogenetic placement, clade assignment and quality control checks for viral genetic sequences. WebAssembly module." edition = "2021" license = "MIT" diff --git a/packages_rs/nextclade-web/package.json b/packages_rs/nextclade-web/package.json index e8c2187f72..d17dea9230 100644 --- a/packages_rs/nextclade-web/package.json +++ b/packages_rs/nextclade-web/package.json @@ -1,6 +1,6 @@ { "name": "@nextstrain/nextclade-web", - "version": "2.6.1", + "version": "2.7.0", "description": "Clade assignment, mutation calling, and sequence quality checks", "homepage": "https://clades.nextstrain.org", "repository": { diff --git a/packages_rs/nextclade/Cargo.toml b/packages_rs/nextclade/Cargo.toml index 8ceff1c683..d3bca73fde 100644 --- a/packages_rs/nextclade/Cargo.toml +++ b/packages_rs/nextclade/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nextclade" -version = "2.6.0" +version = "2.7.0" description = "Alignment, mutation calling, phylogenetic placement, clade assignment and quality control checks for viral genetic sequences. Library module." repository = "https://github.com/nextstrain/nextclade" documentation = "https://docs.nextstrain.org/projects/nextclade/en/stable/"