Skip to content
Snippets Groups Projects
Commit 25ff6f76 authored by Remi  PLANEL's avatar Remi PLANEL
Browse files

Merge branch 'main' of gitlab.pasteur.fr:mdm-lab/wiki

parents b9db5408 3ea7b76a
No related branches found
No related tags found
No related merge requests found
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: never
- when: always
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: never
- when: always
# Functions that should be executed before the build script is run
......@@ -31,8 +26,6 @@ cache:
stages:
- zotero
- get-meili-key
- build
......@@ -43,7 +36,7 @@ stages:
- deploy-meilisearch
- update-meilisearch-indexes
- deploy
# - load-website
- post-deploy
.docker-login: &docker-login
- i=0; while [ "$i" -lt 12 ]; do docker info && break; sleep 5; i=$(( i + 1 )) ; done
......@@ -199,6 +192,12 @@ lint:
MEILI_HOST: "http://localhost:7700"
script:
# - rm data/list-systems.json
- >
df-wiki-cli
meilisearch
--host ${MEILI_HOST}
--key ${MEILI_MASTER_KEY}
delete-all-documents refseq
- >
df-wiki-cli
content systems
......@@ -213,6 +212,14 @@ lint:
update
--file data/refseq_res.csv
--document refseq
- >
df-wiki-cli
meilisearch
--host ${MEILI_HOST}
--key ${MEILI_MASTER_KEY}
update
--file data/refseq_res.csv
--document refseqtaxo
- >
df-wiki-cli
meilisearch
......@@ -229,6 +236,8 @@ lint:
update
--file data/list-systems.json
--document systems
allow_failure: false
when: manual
......@@ -360,96 +369,6 @@ build:prod:wiki:
- if: $CI_COMMIT_BRANCH == "main"
# build-wiki:dev:
# stage: build-wiki
# needs:
# - set-meili-env:dev
# rules:
# - if: $CI_COMMIT_BRANCH != "main"
# image: node:21.1-bookworm-slim
# variables:
# NODE_OPTIONS: --max_old_space_size=12288
# NUXT_APP_BASE_URL: /wiki/
# NUXT_PUBLIC_MEILISEARCH_CLIENT_HOST_URL: ${MEILI_HOST}
# NUXT_PUBLIC_MEILISEARCH_CLIENT_SEARCH_API_KEY: ${MEILI_API_KEY}
# NUXT_PUBLIC_MEILI_HOST: ${MEILI_HOST}
# NUXT_PUBLIC_MEILI_API_KEY: ${MEILI_API_KEY}
# before_script:
# - npm install
# script:
# - npm run generate
# artifacts:
# paths:
# - .output/public
# build-wiki:prod:
# stage: build-wiki
# rules:
# - if: $CI_COMMIT_BRANCH == "main"
# needs:
# - set-meili-env:prod
# - get-zotero
# image: node:21.1-bookworm-slim
# variables:
# NODE_OPTIONS: --max_old_space_size=12288
# NUXT_APP_BASE_URL: /wiki/
# NUXT_PUBLIC_MEILISEARCH_CLIENT_HOST_URL: ${MEILI_HOST}
# NUXT_PUBLIC_MEILISEARCH_CLIENT_SEARCH_API_KEY: ${MEILI_API_KEY}
# NUXT_PUBLIC_MEILI_HOST: ${MEILI_HOST}
# NUXT_PUBLIC_MEILI_API_KEY: ${MEILI_API_KEY}
# before_script:
# - npm install
# script:
# - npm run generate
# artifacts:
# paths:
# - .output/public
# load-website:dev:
# image: harbor.pasteur.fr/kube-system/helm-kubectl:$HELM_VERSION
# stage: load-website
# needs:
# - build-wiki:dev
# - deploy:dev
# variables:
# NAMESPACE: "defense-finder-dev"
# environment:
# name: "k8sdev-01"
# rules:
# - if: $CI_COMMIT_BRANCH != "main"
# script:
# - kubectl --namespace ${NAMESPACE} wait pod -l "app.kubernetes.io/name=df-wiki" --for condition=Ready --timeout=600s
# - echo "Le pod est ready"
# - WIKI_POD=$(kubectl --namespace ${NAMESPACE} get pods -l "app.kubernetes.io/name=df-wiki" --output jsonpath='{.items[0].metadata.name}')
# - kubectl --namespace ${NAMESPACE} cp .output/public/ ${WIKI_POD}:/website
# - |
# kubectl --namespace ${NAMESPACE}
# exec ${WIKI_POD} -- bash -c 'cd /structure-data/sanitized-dump && find * -type d -exec sh -c "for d in "$@"; do (cd "/usr/share/nginx/html/$d"; cp --archive --recursive --symbolic-link /structure-data/sanitized-dump/$d/* .) done" argv0 {} +'
# load-website:prod:
# image: harbor.pasteur.fr/kube-system/helm-kubectl:$HELM_VERSION
# stage: load-website
# needs:
# - build-wiki:prod
# - deploy:prod
# environment:
# name: "k8sprod-02"
# variables:
# NAMESPACE: "defense-finder-prod"
# rules:
# - if: $CI_COMMIT_BRANCH == "main"
# script:
# - kubectl --namespace ${NAMESPACE} wait pod -l "app.kubernetes.io/name=df-wiki" --for condition=Ready --timeout=600s
# - echo "Le pod est ready"
# - WIKI_POD=$(kubectl --namespace ${NAMESPACE} get pods -l "app.kubernetes.io/name=df-wiki" --output jsonpath='{.items[0].metadata.name}')
# - kubectl --namespace ${NAMESPACE} cp .output/public/ ${WIKI_POD}:/website
# - kubectl --namespace ${NAMESPACE} cp scripts/copy-structure-data.sh ${WIKI_POD}:/structure-data/sanitized-dump
# - kubectl --namespace ${NAMESPACE} exec ${WIKI_POD} -- bash -c 'cd /structure-data/sanitized-dump && bash copy-structure-data.sh'
################ DEPLOY ##########################
......@@ -474,11 +393,11 @@ build:prod:wiki:
--values deploy/df-wiki/values.yaml
--values deploy/df-wiki/values.${ENV:-development}.yaml
after_script:
- sleep 30
- kubectl --namespace ${KUBE_NAMESPACE} wait pod -l "app.kubernetes.io/name=df-wiki" --for condition=Ready --timeout=600s
- echo "Wiki pod is ready"
- WIKI_POD=$(kubectl --namespace ${KUBE_NAMESPACE} get pods -l "app.kubernetes.io/name=df-wiki" --output jsonpath='{.items[0].metadata.name}')
- echo ${WIKI_POD}
# - kubectl --namespace ${KUBE_NAMESPACE} cp scripts/copy-structure-data.sh ${WIKI_POD}:/structure-data/sanitized-dump
- kubectl --namespace ${KUBE_NAMESPACE} exec ${WIKI_POD} -- rsync -avz /public-website/ /usr/share/nginx/html/
......@@ -486,7 +405,7 @@ build:prod:wiki:
deploy:dev:
extends: .deploy
rules:
- if: $CI_COMMIT_BRANCH == "dev" || $CI_COMMIT_BRANCH == "public-as-mount-volume"
- if: $CI_COMMIT_BRANCH == "dev" || $CI_COMMIT_BRANCH == "refseq-no-sys"
needs:
- "build:dev:wiki"
when: manual
......@@ -551,3 +470,34 @@ delete-helm-release:prod:
- helm delete -n ${NAMESPACE} $CI_PROJECT_NAME-$CI_ENVIRONMENT_NAME
.post-deploy:
stage: post-deploy
image: harbor.pasteur.fr/kube-system/helm-kubectl:$HELM_VERSION
when: manual
variables:
CI_DEBUG_TRACE: "false"
TEAM_ID: "df"
script:
- kubectl --namespace ${KUBE_NAMESPACE} wait pod -l "app.kubernetes.io/name=df-wiki" --for condition=Ready --timeout=600s
- echo "Wiki pod is ready"
- WIKI_POD=$(kubectl --namespace ${KUBE_NAMESPACE} get pods -l "app.kubernetes.io/name=df-wiki" --output jsonpath='{.items[0].metadata.name}')
- echo ${WIKI_POD}
# - kubectl --namespace ${KUBE_NAMESPACE} exec ${WIKI_POD} -- rsync -avz /public-website/ /usr/share/nginx/html/
- kubectl --namespace ${KUBE_NAMESPACE} exec ${WIKI_POD} -- bash -c "cd /usr/share/nginx/html/ && find ./ -name '*.pdb' -exec tar -czvf /usr/share/nginx/html/df-all-pdbs.tar.gz {} +"
- kubectl --namespace ${KUBE_NAMESPACE} exec ${WIKI_POD} -- bash -c "cd /usr/share/nginx/html/ && find ./ -name '*.cif' -exec tar -czvf /usr/share/nginx/html/df-all-cifs.tar.gz {} +"
post-deploy:dev:
extends: .post-deploy
needs:
- "deploy:dev"
variables:
NODE_ENV: "development"
KUBE_NAMESPACE: "defense-finder-dev"
PUBLIC_URL: "${HOST_DEV}"
CI_DEBUG_TRACE: "true"
ENV: "development"
environment:
name: k8sdev-01
url: "https://${HOST_DEV}"
......@@ -54,7 +54,7 @@ function onScroll() {
<v-container v-scroll="onScroll" :fluid="fluid">
<v-row justify="center">
<v-col cols="auto" class="pa-0">
<v-card flat color="transparent" :min-width="mobile ? undefined : 900" :max-width="fluid ? undefined : 1500">
<v-card flat color="transparent" :min-width="mobile ? undefined : 900" :max-width="fluid ? undefined : 1280">
<v-card-text class="pa-0">
<slot />
</v-card-text>
......
......@@ -309,26 +309,28 @@ function focusedOrBlur(isFocused: boolean) {
<template #top>
<v-card variant="flat" color="transparent">
<v-card-title>
<v-badge :content="totalHits" color="primary" class="mr-3">
<v-card-text class="d-flex flex-row">
<v-badge :content="totalHits" color="primary" class="me-auto">
<v-btn prepend-icon="md:download" :loading="pendingDownloadData" variant="text" color="primary"
@click="downloadData()">{{
props.title }}
</v-btn>
</v-badge>
</v-card-title>
<v-card-title>
<slot name="toolbar-items"></slot>
</v-card-text>
<v-card-text>
<v-text-field v-model="search" label="Search..." hide-details="auto" :disabled="pendingDownloadData"
prepend-inner-icon="mdi-magnify" single-line clearable
@update:focused="focusedOrBlur"></v-text-field>
</v-card-title>
<v-card-title>
</v-card-text>
<v-card-text>
<AutocompleteMeiliFacets v-model="msFilterCompo" v-bind="props.autocompleteMeiliFacetsProps"
:is-valid-filters="isValidFilters">
</AutocompleteMeiliFacets>
</v-card-title>
</v-card-text>
</v-card>
......
......@@ -13,6 +13,7 @@ export interface Props {
dataUrls?: string[]
dataUrl?: string
uniq?: boolean
format?: "pdb" | "cif"
}
const { mobile } = useDisplay()
......@@ -52,7 +53,8 @@ const refinedDataUrls = computed(() => {
// const selectedPdb = ref(refinedDataUrls.value?.length > 0 ? refinedDataUrls.value[0] : null)
const props = withDefaults(defineProps<Props>(), {
height: 600,
uniq: false
uniq: false,
format: 'pdb'
})
const { width, height } = useDisplay()
......@@ -158,10 +160,23 @@ const moleculeFormat: Ref<string> = ref("pdb")
<template>
<template v-if="uniq">
<v-row>
<v-btn size="x-small" variant="text" icon="md:visibility" @click="setSelectedPdbToFirst()"></v-btn>
<v-btn :disabled="!structureToDownload" size="x-small" variant="text" icon="md:download" class="ml-1"
:href="structureToDownload"></v-btn>
<v-row justify="space-between" dense no-gutters align="center">
<v-col>
<v-btn size="x-small" variant="text" icon="md:visibility" @click="setSelectedPdbToFirst()"></v-btn>
</v-col>
<v-col>
<v-menu>
<template v-slot:activator="{ props }">
<v-btn :disabled="refinedDataUrls?.length < 1" size="x-small" variant="text" icon="md:download"
class="ml-1" v-bind="props"></v-btn>
</template>
<v-list>
<v-list-item v-for="(item, index) in refinedDataUrls" :key="index" :value="index" :href="item">
<v-list-item-title>{{ item.split('.').slice(-1)[0] }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-col>
</v-row>
</template>
<v-row v-else>
......@@ -195,7 +210,7 @@ const moleculeFormat: Ref<string> = ref("pdb")
sequence-panel="true" landscape="false" :custom-data-format="moleculeFormat"></pdbe-molstar>
</v-sheet>
</v-col>
<v-col :cols="mobile ? 12 : undefined">
<v-col v-if="moleculeFormat === 'cif'" :cols="mobile ? 12 : undefined">
<v-img :src="selectedPaePath"></v-img>
<!-- <PlotFigure v-if="sanitizedPaeData?.length > 0 && paeError === null" defer
......
<script setup lang="ts">
import * as d3 from "d3";
import * as Plot from "@observablehq/plot";
import PlotFigure from "~/components/PlotFigure";
import { useDisplay } from "vuetify";
......@@ -25,24 +27,49 @@ onBeforeMount(async () => {
filter: [],
page: 1,
hitsPerPage: 25,
}
})
autocompleteMeiliFacetsProps.value.facetDistribution = toValue(data)?.facetDistribution
// allHitsDb.value = toValue(data)?.hits
const { data: taxo } = await useAsyncMeiliSearch({
index: toValue("refseqtaxo"), query: "", params: {
facets: ["*"],
filter: [],
page: 1,
hitsPerPage: 25,
}
})
taxonomyFacet.value = toValue(taxo)?.facetDistribution
})
const taxonomyFacet = ref<Record<string, any> | undefined>(undefined)
// const allHitsDb = ref<Record<string, any>[] | undefined>(undefined)
onMounted(async () => {
const { data } = await useAsyncMeiliSearch({
index: toValue(dbName), query: "", params: {
facets: ["*"],
filter: [],
page: 1,
hitsPerPage: 25,
// limit: 500000,
// sort: ["type:asc"]
}
})
autocompleteMeiliFacetsProps.value.facetDistribution = toValue(data)?.facetDistribution
// allHitsDb.value = toValue(data)?.hits
const { data: taxo } = await useAsyncMeiliSearch({
index: toValue("refseqtaxo"), query: "", params: {
facets: ["*"],
filter: [],
page: 1,
hitsPerPage: 25,
}
})
taxonomyFacet.value = toValue(taxo)?.facetDistribution
})
......@@ -99,19 +126,22 @@ const availableTaxo: Ref<string[]> = ref([
"genus",
"family",
"order",
"class",
"phylum",
"Superkingdom"
]);
const scaleTypes = ref<string[]>(['linear', 'sqrt', 'log', 'symlog'])
const selectedTaxoRank = ref("Superkingdom");
const selectedTaxoRank = ref<"species" | "genus" | "family" | "order" | "class" | "phylum" | "Superkingdom">("Superkingdom");
const headers = ref([
{ title: "Replicon", key: "replicon" },
{
title: "System",
key: "type",
fixed: true
},
{ title: "Assembly", key: "Assembly" },
{ title: "Replicon", key: "replicon" },
{
title: "Subsystem",
key: "subtype",
......@@ -145,15 +175,25 @@ const computedWidth = computed(() => {
const allHits: Ref<Record<string, any> | undefined> = ref(undefined)
const pendingAllHits = ref(false)
async function getAllHits(params: { index: string, params: Record<string, any>, query: string }) {
console.log(params.index)
if (!params?.params?.filter || params?.params?.filter?.length === 0) {
selectedTaxoRank.value = "Superkingdom"
}
if (params.index === toValue(dbName)) {
console.log("get all hits in function ")
console.log(params)
pendingAllHits.value = true
try {
const { data, error } = await useAsyncMeiliSearch(params)
console.log(params.params.filter)
const { data, error } = await useAsyncMeiliSearch({
...params,
params: {
...params.params,
'attributesToRetrieve': ['type', 'Assembly', ...toValue(availableTaxo)]
}
})
allHits.value = data.value
console.log(error.value)
} finally {
......@@ -203,6 +243,8 @@ const computedSystemDistribution = computed(() => {
})
const computedDistriSystemOptions = computed(() => {
// const toValNormalizePerAssembly = toValue(normalizePerAssembly)
return {
...defaultBarPlotOptions.value,
marginBottom: 100,
......@@ -226,10 +268,12 @@ const computedDistriSystemOptions = computed(() => {
// Taxo distri
const computedTaxonomyDistribution = computed(() => {
if (toValue(msResult)?.facetDistribution?.[selectedTaxoRank.value]) {
return Object.entries(toValue(msResult).facetDistribution[selectedTaxoRank.value]).map(([key, value]) => {
const toValSelectedTaxoRank = toValue(selectedTaxoRank)
const toValFacetsPerRank = toValue(msResult)?.facetDistribution?.[toValSelectedTaxoRank]
if (toValFacetsPerRank) {
return Object.entries(toValFacetsPerRank).map(([key, value]) => {
return {
[selectedTaxoRank.value]: key,
[toValSelectedTaxoRank]: key,
count: value
}
}).sort()
......@@ -246,6 +290,7 @@ const computedDistriTaxoOptions = computed(() => {
width: computedWidth.value,
marks: [
Plot.barY(
toValue(computedTaxonomyDistribution),
{
y: "count",
......@@ -277,18 +322,54 @@ function namesToAccessionChips(names: string[]) {
}
const systemPanel: Ref<string[]> = ref([])
const layoutPlot: Ref<string> = ref("grid")
const binPlotOptions = ref({
marginLeft: 150,
marginBottom: 200,
padding: 0,
grid: true,
x: { tickRotate: 90, tip: true, label: "Systems" },
// y: { tickFormat: 's' },
color: { scheme: "plasma", legend: true },
const binPlotOptions = computed(() => {
return {
marginLeft: 150,
marginBottom: 200,
padding: 0,
grid: true,
x: { tickRotate: 90, label: "Systems" },
// y: { tickFormat: 's' },
color: { scheme: "plasma", legend: true, label: `Proportion of genomes with defense system X for a given ${selectedTaxoRank.value} clade`, domain: [0, 100] },
}
})
const binPlotGroup = computed(() => {
return Plot.group(
{
label: (d) => d.fill,
fill: {
reduceIndex: function (I, X) {
const toValTaxonomyFacet = toValue(taxonomyFacet)
if (toValTaxonomyFacet !== undefined) {
const clade = X[I[0]][selectedTaxoRank.value]
const system = X[I[0]].type
// Get the list of item for this group
const itemsPerGroup = d3.rollup(I.map(index => {
return X[index]
}), D => D.length, d => d.type, d => d.Assembly)
const countForClade = toValTaxonomyFacet[selectedTaxoRank.value][clade]
console.log(`${itemsPerGroup.get(system).size} / ${countForClade}`)
const frequency = (itemsPerGroup.get(system).size / countForClade) * 100
return frequency
}
return I.length
}
}
},
{
x: "type",
y: selectedTaxoRank.value,
tip: true,
inset: 0.5,
sort: { y: "fill" }
})
})
const binPlotDataOptions = computed(() => {
const toValueAllHits = toValue(allHits)
const data = toValueAllHits?.hits ?? []
return toValueAllHits?.hits?.length > 0 ? {
...binPlotOptions.value,
width: width.value,
......@@ -298,14 +379,16 @@ const binPlotDataOptions = computed(() => {
type: scaleType.value,
tickFormat: '~s',
ticks: scaleType.value === 'symlog' ? 3 : 5,
},
marks: [
Plot.cell(toValueAllHits?.hits ?? [], Plot.group({ fill: "count" }, { x: "type", y: selectedTaxoRank.value, tip: true, inset: 0.5, sort: { y: "fill" } })),
Plot.cell(data, toValue(binPlotGroup)),
]
} : null
})
const scaleType = ref("linear")
const systemsDistributionPlot = ref<ComponentPublicInstance | null>(null)
const taxonomicDistributionPlot = ref<ComponentPublicInstance | null>(null)
......@@ -464,7 +547,6 @@ async function downloadPng(component: ComponentPublicInstance | null, filename:
</v-expansion-panel-text>
</v-expansion-panel>
</v-expansion-panels>
<ServerDbTable title="RefSeq" :sortBy="sortBy"
:autocomplete-meili-facets-props="computedAutocompleteMeiliFacetsProps"
:data-table-server-props="dataTableServerProps" @refresh:search="(params) => getAllHits(params)">
......@@ -474,14 +556,29 @@ async function downloadPng(component: ComponentPublicInstance | null, filename:
</CollapsibleChips>
</template>
<template #[`item.type`]="{ item }">
<v-chip color="info" link size="small" :to="`/defense-systems/${item.type.toLowerCase()}`" target="_blank"> {{
item.type }}
<v-chip color="info" link size="small" :to="`/defense-systems/${item.type.toLowerCase()}`"
target="_blank"> {{
item.type }}
</v-chip>
</template>
<template #[`item.Assembly`]="{ item }">
<v-chip color="info" link size="small"
:href="`https://www.ncbi.nlm.nih.gov/datasets/genome/${item.Assembly}`" target="_blank"> {{
item.Assembly }}
</v-chip>
</template>
<template #[`item.replicon`]="{ item }">
<v-chip color="info" link size="small" :href="`https://www.ncbi.nlm.nih.gov/nuccore/${item.replicon}`"
target="_blank"> {{
item.replicon }}
</v-chip>
</template>
<!-- -->
<template #[`item.subtype`]="{ item }">
<v-chip color="info" link size="small" :to="`/defense-systems/${item.type.toLowerCase()}`" target="_blank"> {{
item.subtype }}
<v-chip color="info" link size="small" :to="`/defense-systems/${item.type.toLowerCase()}`"
target="_blank"> {{
item.subtype }}
</v-chip>
</template>
</ServerDbTable>
......
......@@ -18,7 +18,6 @@ const itemValue = ref("id");
const dbName = ref("structure")
onBeforeMount(async () => {
console.log("dans le mounted refseq")
const { data } = await useAsyncMeiliSearch({
index: toValue(dbName), query: "", params: {
facets: ["*"],
......@@ -72,7 +71,7 @@ const computedAutocompleteMeiliFacetsProps = computed(() => {
const headers: Ref<Object[]> = ref([
{ title: 'Structure', key: 'structure', sortable: false, removable: false },
{ title: 'Structure', key: 'structure', sortable: false, removable: false, fixed: true, minWidth: "110px" },
{ title: 'Foldseek', key: 'Foldseek_name', sortable: false },
{ title: "System", key: "System", removable: false },
{ title: "Gene name", key: "gene_name", removable: false },
......@@ -125,7 +124,6 @@ const dataTableServerProps = computed(() => {
function toFolseekUrl(item: Item) {
const url = joinURL("/" + item.System_name_ok, item.Foldseek_name)
const { refinedUrl } = useRefinedUrl(url)
console.log(toValue(refinedUrl))
return toValue(refinedUrl)
}
......@@ -143,6 +141,9 @@ function pdbNameToCif(pdbPath: string) {
return `${cifPath}.cif`
}
const { refinedUrl: downloadAllPdbUrl } = useRefinedUrl("/df-all-pdbs.tar.gz")
const { refinedUrl: downloadAllCifUrl } = useRefinedUrl("/df-all-cifs.tar.gz")
</script>
<template>
<ServerDbTable title="Predicted Structures" :sortBy="sortBy" :data-table-server-props="dataTableServerProps"
......@@ -210,9 +211,18 @@ function pdbNameToCif(pdbPath: string) {
<CollapsibleChips :items="namesToCollapsibleChips(item.system_genes, item.System_name_ok)"></CollapsibleChips>
</template>
<template #[`item.structure`]="{ item }">
<MolstarPdbePlugin v-if="item?.pdb && item.pdb !== 'na'"
:data-urls="[`/${item.System_name_ok}/${pdbNameToCif(item.pdb)}`]" uniq>
</MolstarPdbePlugin>
<v-row no-gutters align="center">
<MolstarPdbePlugin v-if="item?.pdb && item.pdb !== 'na'"
:data-urls="[`/${item.System_name_ok}/${pdbNameToCif(item.pdb)}`, `/${item.System_name_ok}/${item.pdb}`]" uniq format="cif">
</MolstarPdbePlugin>
</v-row>
<!-- <v-row no-gutters align="center">
<MolstarPdbePlugin v-if="item?.pdb && item.pdb !== 'na'"
:data-urls="[`/${item.System_name_ok}/${item.pdb}`]" uniq format="pdb">
</MolstarPdbePlugin>
</v-row> -->
<!-- <v-icon v-else color="warning" icon="md:dangerous"></v-icon> -->
......@@ -221,5 +231,22 @@ function pdbNameToCif(pdbPath: string) {
<v-icon v-if="item.completed" color="success" icon="md:check"></v-icon>
<v-icon v-else color="warning" icon="md:dangerous"></v-icon>
</template>
<template #toolbar-items>
<v-menu>
<template v-slot:activator="{ props }">
<!-- <v-tooltip activator="parent" location="top">Download all structures</v-tooltip> -->
<v-btn class="align-self-end" v-bind="props" icon="md:download">
</v-btn>
</template>
<v-list>
<v-list-item value="pdb" :href="downloadAllPdbUrl">
<v-list-item-title>all pdbs</v-list-item-title>
</v-list-item>
<v-list-item value="cif" :href="downloadAllCifUrl">
<v-list-item-title>all cifs</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</template>
</ServerDbTable>
</template>
\ No newline at end of file
Source diff could not be displayed: it is stored in LFS. Options to address this: view the blob.
......@@ -9,7 +9,7 @@ meilisearch:
persistence:
enabled: true
storageClass: isilon
size: "1Gi"
size: "4Gi"
resources:
limits:
cpu: 2000m
......
......@@ -11,7 +11,7 @@ meilisearch:
path: /
persistence:
enabled: true
storageClass: isilon
storageClass: ceph-block
size: "10Gi"
resources:
limits:
......
......@@ -10,6 +10,24 @@ export default defineNuxtConfig({
'nuxt-meilisearch',
'@nuxtjs/plausible',
],
app: {
head: {
script: [
{
defer: true,
"data-domaim": "defense-finder.dev.pasteur.cloud",
src: "https://plausible.dev.pasteur.cloud/js/script.js"
},
{
defer: true,
"data-domaim": "defense-finder.dev.pasteur.cloud",
src: "https://plausible.pasteur.cloud/js/script.js"
}
]
}
},
content: {
documentDriven: {
injectPage: false,
......
......@@ -270,6 +270,8 @@ def refseq(
writer = csv.DictWriter(out, fieldnames=fieldnames)
writer.writeheader()
for row in reader:
if row["sys_id"] == "":
row["sys_id"] = f'{row["Assembly"]}_{row["replicon"]}'
result = re.sub(r"^(\w+)\.\d+(_.*)$", r"\1\2", row["sys_id"])
console.print(f"[green]{row['sys_id']} -> {result}")
row["sys_id"] = result
......
......@@ -11,15 +11,22 @@ from rich.console import Console
console = Console()
def emptyStringToNone(val: str) -> None | int:
if val == "":
return None
return int(float(val))
class RefSeqCsv(BaseModel):
sys_id: str
Assembly: str
replicon: str
type: str
subtype: str
sys_beg: str
sys_end: str
protein_in_syst: List[str]
genes_count: int
genes_count: Annotated[int | None, BeforeValidator(emptyStringToNone)]
name_of_profiles_in_sys: List[str]
accession_in_sys: List[str]
Superkingdom: str
......@@ -71,6 +78,66 @@ class StrucutreStatistics(BaseModel):
Foldseek_name: Optional[str]
def update_refseqtaxo(host: str, key: str, file: Path, document: str):
client = meilisearch.Client(host, key)
index = client.index(document.lower())
documents = []
with open(file, "r") as csvfile:
csvreader = csv.DictReader(csvfile)
assembly = {}
for row in csvreader:
assembly_id = row["Assembly"]
assembly[row["Assembly"]] = {
k: row[k]
for k in (
"Superkingdom",
"phylum",
"class",
"order",
"family",
"genus",
"species",
"Assembly",
)
if k in row
}
assembly[assembly_id]["Assembly"] = assembly[assembly_id]["Assembly"].split('.')[0]
for item in assembly.values():
documents.append(item)
tasks = index.add_documents_in_batches(documents, primary_key="Assembly")
print(tasks)
index.update_pagination_settings({"maxTotalHits": 1000000})
index.update_filterable_attributes(
body=[
"Superkingdom",
"phylum",
"class",
"order",
"family",
"genus",
"species",
"Assembly",
]
)
index.update_sortable_attributes(
[
"Superkingdom",
"phylum",
"class",
"order",
"family",
"genus",
"species",
"Assembly",
]
)
params = {
"maxValuesPerFacet": 1000000,
"sortFacetValuesBy": {"*": "count"},
}
index.update_faceting_settings(params)
def update_refseq(
host: str,
key: str,
......@@ -97,10 +164,12 @@ def update_refseq(
index.update_filterable_attributes(
body=[
"replicon",
"Assembly",
"type",
"subtype",
"Superkingdom",
"phylum",
"class",
"order",
"family",
"genus",
......@@ -110,10 +179,12 @@ def update_refseq(
index.update_sortable_attributes(
[
"replicon",
"Assembly",
"type",
"subtype",
"Superkingdom",
"phylum",
"class",
"order",
"family",
"genus",
......
......@@ -2,7 +2,12 @@ import typer
import meilisearch
from typing_extensions import Annotated
from pathlib import Path
from df_wiki_cli.meilisearch import update_refseq, update_structure, update_systems
from df_wiki_cli.meilisearch import (
update_refseq,
update_structure,
update_systems,
update_refseqtaxo,
)
from enum import Enum
from types import SimpleNamespace
from rich.console import Console
......@@ -14,6 +19,7 @@ app = typer.Typer()
class Documents(str, Enum):
refseqtaxo = "refseqtaxo"
refseq = "refseq"
structure = "structure"
systems = "systems"
......@@ -55,6 +61,8 @@ def update(
] = Documents.refseq,
content_type: Annotated[str, typer.Option(help="Content-Type header")] = "text/csv",
):
if document == "refseqtaxo":
update_refseqtaxo(ctx.obj.host, ctx.obj.key, file, document)
if document == "refseq":
update_refseq(ctx.obj.host, ctx.obj.key, file, document)
if document == "structure":
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment