Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: mutations relative to arbitrary node (extended) #1492

Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
1fda656
feat(web): add toggles for insertions and frame shifts markers
ivan-aksamentov Jun 12, 2024
f206800
Merge remote-tracking branch 'origin/master' into feat/web-seq-markers
ivan-aksamentov Jun 13, 2024
3b8fb05
fix: prevent duplicate node names in output auspice json
ivan-aksamentov Jun 13, 2024
590bfd4
chore(infra): remove feature-policy header, remove interest-cohort fr…
ivan-aksamentov Jun 13, 2024
b5a311b
Merge pull request #1486 from nextstrain/fix/prevent-duplicate-node-n…
ivan-aksamentov Jun 13, 2024
57d53df
fix(web): correctly display 'updated at' time of datasets
ivan-aksamentov Jun 14, 2024
42f3aee
fix(web): styling of details & summary in markdown content
ivan-aksamentov Jun 14, 2024
9d7c283
Merge pull request #1489 from nextstrain/fix/web-updated-at
ivan-aksamentov Jun 14, 2024
f94b2e3
feat: add ancestral search
ivan-aksamentov Jun 17, 2024
b09abd1
feat: add multiple criteria per search
ivan-aksamentov Jun 17, 2024
46566c8
feat: allow multiple criteria per node and query
ivan-aksamentov Jun 17, 2024
29170fd
feat: actually run the search
ivan-aksamentov Jun 17, 2024
2330352
fix: infinite loop
ivan-aksamentov Jun 17, 2024
60e2a70
fix: field name mismatch
ivan-aksamentov Jun 17, 2024
0e5b114
chore(deps): bump auspice in /packages/nextclade-web
dependabot[bot] Jun 17, 2024
27d1c32
Merge pull request #1491 from nextstrain/dependabot/npm_and_yarn/pack…
ivan-aksamentov Jun 18, 2024
60732f5
feat: adjust private nuc mutation search for the new format of ref nodes
ivan-aksamentov Jun 18, 2024
3f9e11f
fix: apply query criteria correctly
ivan-aksamentov Jun 18, 2024
5f18529
refactor: split modules for relative mutations - for nuc and aa
ivan-aksamentov Jun 18, 2024
02ffd3b
feat: adjust private aa mutation search for the new format of ref nodes
ivan-aksamentov Jun 18, 2024
2654b2a
feat: add node name to search result
ivan-aksamentov Jun 18, 2024
348e244
feat: remove old node search format, adjust code for the new format
ivan-aksamentov Jun 18, 2024
6c6cf9f
feat: adjust web ui for the new ref node desc format
ivan-aksamentov Jun 18, 2024
455efe2
feat: add ref node name to csv output
ivan-aksamentov Jun 18, 2024
dda188f
feat(web): add ref node name to mut tooltip
ivan-aksamentov Jun 18, 2024
aacb3e9
fix(web): infinite loading due to uninitialized atom
ivan-aksamentov Jun 18, 2024
cabb6db
fix: select all queries if qry criteria are not specified
ivan-aksamentov Jun 18, 2024
62b4298
feat: make `default` and `search` config fields optional
ivan-aksamentov Jun 18, 2024
eef7019
Merge pull request #1490 from nextstrain/fix/web-md-details
ivan-aksamentov Jun 19, 2024
5f6b431
Merge pull request #1483 from nextstrain/feat/web-seq-markers
ivan-aksamentov Jun 19, 2024
cf1eb54
chore: release cli & web 3.7.2
ivan-aksamentov Jun 19, 2024
1f06cfb
fix(web): downgrade auspice to avoid crash on tree page
ivan-aksamentov Jun 19, 2024
8b72e93
chore: release cli & web 3.7.3
ivan-aksamentov Jun 19, 2024
25a812b
Merge remote-tracking branch 'origin/master' into feat/mutations-rela…
ivan-aksamentov Jun 19, 2024
bca3613
chore: fix port clash in dev container setup
ivan-aksamentov Jun 19, 2024
804bd74
feat: upgrade auspice and add polyfills
ivan-aksamentov Jun 19, 2024
5be5925
Merge pull request #1493 from nextstrain/fix/add-polyfills
ivan-aksamentov Jun 19, 2024
a71fa13
chore: release cli & web 3.7.4
ivan-aksamentov Jun 19, 2024
c62b7a4
Merge branch 'master' into feat/mutations-relative-to-node-ext
ivan-aksamentov Jun 19, 2024
3aa580c
feat: add built-in ancestral search for clade founders
ivan-aksamentov Jun 20, 2024
5638475
feat(web): display "Clade founder" mutations
ivan-aksamentov Jun 20, 2024
83c8dc5
feat(web): display rel mutations for clade-like attr founder nodes
ivan-aksamentov Jun 20, 2024
f5d9110
fix: lookup clade-like values correctly
ivan-aksamentov Jun 20, 2024
966fcd3
fix: correctly display aa mutations for clade-like attr founders
ivan-aksamentov Jun 20, 2024
39a4785
fix: emit clade founder mutations into csv
ivan-aksamentov Jun 20, 2024
b9610f1
feat(web): add founder muts checkbox into csv column config
ivan-aksamentov Jun 20, 2024
5e168a8
feat: reorder csv columns
ivan-aksamentov Jun 20, 2024
8f5da60
fix(web): description and behavior of clade column checkboxes
ivan-aksamentov Jun 21, 2024
e62022c
fix: buffer overflow when inserting csv headers
ivan-aksamentov Jun 21, 2024
7c60909
feat: add skipAsReference field to allow excluding clade-like atts
ivan-aksamentov Jun 21, 2024
f5fcd80
refactor: lint
ivan-aksamentov Jun 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,63 @@
## Nextclade 3.7.4

### Nextclade Web

### Upgrade Auspice to 2.55.0, add polyfills

This definitively resolves crash due to missing JavaScript polyfills, which occurred in Nextclade Web 3.7.2

## Nextclade 3.7.3

### Nextclade Web

### Fix crash on tree page in Nextclade Web

Temporarily downgrade Auspice from 2.55.0 to 2.54.3 to prevent the tree page in Nextclade Web from crashing. The definitive fix will follow.

## Nextclade 3.7.2

### General

### [fix] Avoid duplicate node names in the output Auspice JSON tree

When multiple query samples were to be placed onto the same node on the reference tree, sometimes multiple auxiliary nodes could be created having the same name. Node names are expected to be unique for Auspice visualization to work correctly, so when visualizing the tree Auspice have been renaming these nodes and emitting warnings into browsers' dev console.

In this version we pick unique names for the auxiliary nodes during placement, so that there are no more warnings. Users may observe changes in some of the node names when inspecting output Auspice JSON file. However, this unlikely to affect most users' work.

### Nextclade Web

### [fix] Ensure dataset "updated at" date is displayed in Nextclade Web

Since 3.7.0 Nextclade Web is not showing "updated at" date for any datasets. This has been fixed.

### [fix] Ensure frame shift and insertion markers in sequence views can also be toggled

Most markers can be toggled on or off on the sequence views in "Settings" page in Nextclade Web, however frame shifts and insertions could not be. We added the missing toggles.

### [fix] Correctly style details/summary component

The text in details/summary ("collapse", "spoiler") component (e.g. the list of SC2 lineages) overflowing and producing garbled text in dataset readmes and changelogs. This has been fixed.

### [dep] Update Auspice tree visualization to 2.55.0

Auspice tree visualization package has been updated from 2.53.0 to 2.55.0. See Auspice changelog [here](https://github.com/nextstrain/auspice/releases).

### Internal

### [infra] Fix feature-policy and permission-policy HTTP headers

The deprecated `feature-policy` header was removed entirely and `interest-cohort` entry was removed from the `permission-policy` header. Latest versions of web browsers should no longer emit warnings into console.

### [test] Test Nextclade CLI on more Linx distros

Additionally to the previous, we now test Nextclade CLI on the following newer Linux distributions:

- Amazon Linux 2.0.2024
- Debian 12
- Fedora 41
- Oracle Linux 8.9
- Ubuntu 24.04

## Nextclade 3.7.1

### Warn if reference sequence does not match root sequence of the tree
Expand Down
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ exclude = [

[workspace.package]
name = "nextclade"
version = "3.7.1"
version = "3.7.4"
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/"
Expand Down
19 changes: 16 additions & 3 deletions docker/dev
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,13 @@ if ! docker inspect --format '{{.Id}}' "${DOCKER_REPO}:${DOCKER_TARGET}-${DOCKER
"${DOCKER_REPO}:${DOCKER_TARGET}-${DOCKER_IMAGE_VERSION}"
)

parallel 'docker pull -q {} >/dev/null 2>&1 || true' ::: "${images[@]}"
function docker_image_maybe_pull() {
if [ -z "$(docker images -q "$1" 2> /dev/null)" ]; then
docker pull -q "$1" >/dev/null 2>&1 || true
fi
}
export -f docker_image_maybe_pull
parallel docker_image_maybe_pull ::: "${images[@]}"

${NICE} docker buildx build \
--file="docker/docker-dev.dockerfile" \
Expand Down Expand Up @@ -488,9 +494,16 @@ elif [ "${BUILD}" == "1" ]; then
elif [ "${SMOKE_TEST}" == "1" ]; then
COMMAND="./tests/run-smoke-tests 'cargo run -q --target-dir='${BUILD_DIR_REL}' ${RUST_TARGET} ${RELEASE} --bin=nextclade'"
elif [ "${WASM}" == "1" ]; then
COMMAND="bash -c \"set -euo pipefail && cd packages/nextclade-web && yarn install && yarn wasm-${RELEASE}\""
COMMAND=${COMMAND:=yarn install && yarn wasm-${RELEASE}}
COMMAND="bash -c \"set -euo pipefail && cd packages/nextclade-web && ${COMMAND}\""
elif [ "${WEB}" == "1" ]; then
PORTS="-p 3000:3000"
if [[ "${RELEASE}" == *"dev"* ]]; then
WEB_PORT_DEV=${WEB_PORT_DEV:-3000}
PORTS="-p ${WEB_PORT_DEV}:${WEB_PORT_DEV}"
else
WEB_PORT_PROD=${WEB_PORT_PROD:-8080}
PORTS="-p ${WEB_PORT_PROD}:${WEB_PORT_PROD}"
fi
COMMAND=${COMMAND:=yarn install && yarn ${RELEASE}}
COMMAND="bash -c \"set -euo pipefail && cd packages/nextclade-web && ${COMMAND}\""
elif [ "${TEST}" == "1" ]; then
Expand Down
6 changes: 4 additions & 2 deletions docker/docker-dev.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ RUN set -euxo pipefail >/dev/null \
--create-home \
--shell /bin/bash \
--gid ${GROUP} \
--groups "${SUDO_GROUP},${GROUP}" \
--groups ${SUDO_GROUP},${GROUP} \
--uid ${UID} \
${USER}; \
else \
Expand All @@ -145,7 +145,7 @@ RUN set -euxo pipefail >/dev/null \
--move-home \
--shell /bin/bash \
--gid ${GROUP} \
--groups "${SUDO_GROUP},${GROUP}" \
--groups ${SUDO_GROUP},${GROUP} \
--append \
--uid ${UID} \
--login "${USER}" \
Expand Down Expand Up @@ -316,6 +316,8 @@ ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=x86_64-linux-musl-gcc
# Cross-compilation to WebAssembly
FROM base as cross-wasm32-unknown-unknown

USER 0

SHELL ["bash", "-euxo", "pipefail", "-c"]

RUN set -euxo pipefail >/dev/null \
Expand Down
4 changes: 2 additions & 2 deletions packages/nextclade-cli/src/cli/nextclade_ordered_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use nextclade::io::results_json::ResultsJsonWriter;
use nextclade::run::nextclade_wasm::AnalysisOutput;
use nextclade::run::params::NextcladeInputParams;
use nextclade::translate::translate_genes::Translation;
use nextclade::tree::tree::{AuspiceRefNode, CladeNodeAttrKeyDesc};
use nextclade::tree::tree::{AuspiceRefNodesDesc, CladeNodeAttrKeyDesc};
use nextclade::types::outputs::NextcladeOutputs;
use nextclade::utils::error::report_to_string;
use nextclade::utils::option::OptionMapRefFallible;
Expand All @@ -37,7 +37,7 @@ impl NextcladeOrderedWriter {
gene_map: &GeneMap,
clade_node_attr_key_descs: &[CladeNodeAttrKeyDesc],
phenotype_attr_key_desc: &[PhenotypeAttrDesc],
ref_nodes: &[AuspiceRefNode],
ref_nodes: &AuspiceRefNodesDesc,
aa_motifs_keys: &[String],
csv_column_config: &CsvColumnConfig,
output_params: &NextcladeRunOutputArgs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,23 @@
// Usage: Create an AWS Lambda@Edge function and attach it to "Viewer Response"
// event of a Cloudfront distribution

const FEATURE_POLICY = {
accelerometer: `'none'`,
camera: `'none'`,
geolocation: `'none'`,
gyroscope: `'none'`,
magnetometer: `'none'`,
microphone: `'none'`,
payment: `'none'`,
usb: `'none'`,
}

function generateFeaturePolicyHeader(featurePolicyObject) {
return Object.entries(featurePolicyObject)
.map(([policy, value]) => `${policy} ${value}`)
.join('; ')
}

const PERMISSIONS_POLICY = {
'accelerometer': '()',
'camera': '()',
'geolocation': '()',
'gyroscope': '()',
'magnetometer': '()',
'microphone': '()',
'payment': '()',
'usb': '()',
'interest-cohort': '()',
accelerometer: '()',
camera: '()',
geolocation: '()',
gyroscope: '()',
magnetometer: '()',
microphone: '()',
payment: '()',
usb: '()',
}

function generatePermissionsPolicyHeader(permissionsPolicyObject) {
return Object.entries(permissionsPolicyObject)
.map(([policy, value]) => `${policy}=${value}`)
.join(', ')
}

const NEW_HEADERS = {
'Content-Security-Policy':
"default-src 'self'; script-src 'self' 'unsafe-eval' plausible.io; style-src 'self' 'unsafe-inline'; img-src 'self' data: *.githubusercontent.com; connect-src *",
Expand All @@ -51,7 +34,6 @@ const NEW_HEADERS = {
'X-Download-Options': 'noopen',
'X-Frame-Options': 'SAMEORIGIN',
'X-XSS-Protection': '1; mode=block',
'Feature-Policy': generateFeaturePolicyHeader(FEATURE_POLICY),
'Permissions-Policy': generatePermissionsPolicyHeader(PERMISSIONS_POLICY),
}

Expand Down
4 changes: 2 additions & 2 deletions packages/nextclade-web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nextstrain/nextclade-web",
"version": "3.7.1",
"version": "3.7.4",
"description": "Clade assignment, mutation calling, and sequence quality checks",
"homepage": "https://clades.nextstrain.org",
"repository": {
Expand Down Expand Up @@ -90,7 +90,7 @@
"@hapi/accept": "6.0.3",
"@hapi/content": "6.0.0",
"animate.css": "4.1.1",
"auspice": "2.54.3",
"auspice": "2.55.0",
"autoprefixer": "10.4.5",
"awesomplete": "1.1.5",
"axios": "0.27.1",
Expand Down
59 changes: 42 additions & 17 deletions packages/nextclade-web/src/components/Results/ColumnMutations.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useCallback, useMemo, useState } from 'react'
import { useRecoilValue } from 'recoil'
import { REF_NODE_PARENT, REF_NODE_ROOT } from 'src/constants'
import { REF_NODE_CLADE_FOUNDER, REF_NODE_PARENT, REF_NODE_ROOT } from 'src/constants'
import { findCladeNodeAttrFounderInfo, getAaMutations, getNucMutations } from 'src/helpers/relativeMuts'
import { currentRefNodeNameAtom } from 'src/state/results.state'
import { getAaMutations, getNucMutations } from 'src/types'
import type { ColumnCladeProps } from 'src/components/Results/ColumnClade'
import { getSafeId } from 'src/helpers/getSafeId'
import { TableSlim } from 'src/components/Common/TableSlim'
Expand All @@ -17,22 +17,45 @@ export function ColumnMutations({ analysisResult }: ColumnCladeProps) {
const onMouseEnter = useCallback(() => setShowTooltip(true), [])
const onMouseLeave = useCallback(() => setShowTooltip(false), [])

const { index, seqName } = analysisResult
const { index, seqName, refName, nearestNodeName, refNodeSearchResults, cladeFounderInfo, cladeNodeAttrFounderInfo } =
analysisResult
const id = getSafeId('mutations-label', { index, seqName })

const refNodeName = useRecoilValue(currentRefNodeNameAtom)
const nucMuts = getNucMutations(analysisResult, refNodeName)
const aaMuts = getAaMutations(analysisResult, refNodeName)
const nodeSearchName = useRecoilValue(currentRefNodeNameAtom)
const nucMuts = getNucMutations(analysisResult, nodeSearchName)
const aaMuts = getAaMutations(analysisResult, nodeSearchName)

const nodeName = useMemo(() => {
if (refNodeName === REF_NODE_ROOT) {
return t('reference')
const { searchNameFriendly, nodeName } = useMemo(() => {
if (nodeSearchName === REF_NODE_ROOT) {
return { searchNameFriendly: t('reference'), nodeName: refName }
}
if (refNodeName === REF_NODE_PARENT) {
return t('parent')
if (nodeSearchName === REF_NODE_PARENT) {
return { searchNameFriendly: t('parent'), nodeName: nearestNodeName }
}
return refNodeName
}, [refNodeName, t])
if (nodeSearchName === REF_NODE_CLADE_FOUNDER) {
return { searchNameFriendly: t('clade founder'), nodeName: cladeFounderInfo?.nodeName }
}
const cladeNodeAttr = findCladeNodeAttrFounderInfo(cladeNodeAttrFounderInfo, nodeSearchName)
if (cladeNodeAttr) {
return {
searchNameFriendly: t('Founder of {{ attr }}', { attr: cladeNodeAttr.key }),
nodeName: cladeFounderInfo?.nodeName,
}
}
const nodeName =
refNodeSearchResults.find((r) => r.search.name === nodeSearchName)?.result?.match?.nodeName ?? t('unknown')
const searchNameFriendly =
refNodeSearchResults.find((r) => r.search.name === nodeSearchName)?.search.displayName ?? t('unknown')
return { searchNameFriendly, nodeName }
}, [
nodeSearchName,
cladeNodeAttrFounderInfo,
refNodeSearchResults,
t,
refName,
nearestNodeName,
cladeFounderInfo?.nodeName,
])

if (!nucMuts) {
return (
Expand All @@ -51,8 +74,9 @@ export function ColumnMutations({ analysisResult }: ColumnCladeProps) {
<tbody>
<tr>
<th>
{t('Nucleotide mutations relative to "{{ what }}" ({{ quantity }})', {
what: nodeName,
{t('{{ quantity }} nucleotide mutations relative to "{{ what }}" ("{{ node }}")', {
what: searchNameFriendly,
node: nodeName,
quantity: nucMuts?.subs.length,
})}
</th>
Expand All @@ -65,8 +89,9 @@ export function ColumnMutations({ analysisResult }: ColumnCladeProps) {

<tr>
<th>
{t('Aminoacid substitutions relative to "{{ what }}" ({{ quantity }})', {
what: nodeName,
{t('{{ quantity }} aminoacid mutations relative to "{{ what }}" ("{{ node }}")', {
what: searchNameFriendly,
node: nodeName,
quantity: aaMuts?.aaSubs.length,
})}
</th>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { isEmpty, isNil } from 'lodash'
import React, { ReactNode } from 'react'
import { useRecoilValue } from 'recoil'
import { REF_NODE_PARENT } from 'src/constants'
import { getNucMutations } from 'src/helpers/relativeMuts'
import { currentRefNodeNameAtom } from 'src/state/results.state'
import { type AnalysisResult, getNucMutations, NucSub, NucSubLabeled } from 'src/types'
import { type AnalysisResult, NucSub, NucSubLabeled } from 'src/types'
import { LiInvisible, UlInvisible } from 'src/components/Common/List'
import { ListOfMutationsGeneric } from 'src/components/Results/ListOfMutationsGeneric'
import { useTranslationSafe } from 'src/helpers/useTranslationSafe'
Expand Down
Loading
Loading