Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • mdm-lab/wiki
  • hvaysset/wiki
  • jsousa/wiki
  • tclabby/wiki
4 results
Show changes
Commits on Source (106)
Showing
with 316 additions and 82 deletions
......@@ -32,15 +32,16 @@ cache:
stages:
- zotero
- get-meili-key
- build
# - build-wiki
- delete-release
- build-df-cli
- lint
- get-data
- deploy-meilisearch
- update-meilisearch-indexes
- get-meili-key
- build
# - build-wiki
- deploy
# - load-website
......@@ -112,6 +113,7 @@ build:df-wiki-cli:
# sleep 1
# kubectl -n=${KUBE_NAMESPACE} get po
# done
when: manual
deploy:meilisearch:dev:
......@@ -143,7 +145,7 @@ deploy:meilisearch:prod:
url: "https://${MEILI_HOST_PROD}"
############### DELETE RELEASE
delete-meili-helm-release:
rules:
......@@ -203,15 +205,6 @@ lint:
--dir content/3.defense-systems/
--pfam public/pfam-a-hmm.csv
--output data/list-systems.json
- df-wiki-cli meilisearch delete-all-documents refseq
- >
df-wiki-cli
meilisearch
--host ${MEILI_HOST}
--key ${MEILI_MASTER_KEY}
index-update
refseq
sys_id
- >
df-wiki-cli
meilisearch
......@@ -237,14 +230,13 @@ lint:
--file data/list-systems.json
--document systems
allow_failure: false
when: manual
update-meilisearch-index:dev:
rules:
- if: $CI_COMMIT_BRANCH != "main"
extends: .update-meilisearch-index
needs:
- deploy:meilisearch:dev
variables:
MEILI_HOST: "https://${MEILI_HOST_DEV}"
......@@ -253,8 +245,6 @@ update-meilisearch-index:prod:
rules:
- if: $CI_COMMIT_BRANCH == "main"
extends: .update-meilisearch-index
needs:
- deploy:meilisearch:prod
variables:
MEILI_HOST: "https://${MEILI_HOST_PROD}"
......@@ -281,8 +271,6 @@ update-meilisearch-index:prod:
set-meili-env:dev:
extends: .set-meili-env
needs:
- deploy:meilisearch:dev
variables:
MEILI_HOST: "https://${MEILI_HOST_DEV}"
rules:
......@@ -298,7 +286,7 @@ set-meili-env:prod:
##############################
get-zotero:
extends: .df-wiki-cli-run
stage: get-data
stage: zotero
script:
- df-wiki-cli articles --key ${ZOTERO_API_KEY} --output content/_data/_articles.json
artifacts:
......@@ -328,7 +316,7 @@ get-zotero:
variables:
CONTEXT: "."
DOCKERFILE: "Dockerfile"
BASE_URL: /wiki/
BASE_URL: /
MEILI_HOST: "http://localhost:7700"
before_script:
- *docker-login
......@@ -337,7 +325,7 @@ get-zotero:
docker buildx build --pull -t "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA"
--build-arg "BASE_URL=$BASE_URL"
--build-arg "MEILI_HOST=$MEILI_HOST"
--build-arg "MEILI_API_KEY=$MEILI_API_KEY"
--build-arg "MEILI_API_KEY=$MEILI_API_KEY"
-f $DOCKERFILE $CONTEXT
- docker push "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA"
......@@ -350,6 +338,7 @@ build:dev:wiki:
# - get-pfam
variables:
BASE_URL: /wiki/
HOST_URL: https://${HOST_DEV}
before_script:
- *docker-login
# - "sed -i 's/MEILISEARCH_API_KEY/${$MEILI_API_KEY}/g' nuxt.config.ts"
......@@ -365,6 +354,8 @@ build:prod:wiki:
# - get-pfam
variables:
BASE_URL: /wiki/
HOST_URL: https://${HOST_PROD}
rules:
- if: $CI_COMMIT_BRANCH == "main"
......@@ -487,15 +478,15 @@ build:prod:wiki:
- 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} -- bash -c 'cd /structure-data/sanitized-dump && bash copy-structure-data.sh'
# - 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/
deploy:dev:
extends: .deploy
rules:
- if: $CI_COMMIT_BRANCH == "dev" || $CI_COMMIT_BRANCH == "refactor-facet-autocomplete"
- if: $CI_COMMIT_BRANCH == "dev" || $CI_COMMIT_BRANCH == "public-as-mount-volume"
needs:
- "build:dev:wiki"
when: manual
......
......@@ -15,14 +15,14 @@ FROM node:21.1-bookworm-slim as dev
ARG BASE_URL=/
ARG MEILI_HOST=http://localhost:7700
ARG MEILI_API_KEY=api_key
ARG HOST_URL
ENV NUXT_APP_BASE_URL=${BASE_URL}
# nuxt module
ENV NUXT_PUBLIC_MEILISEARCH_CLIENT_HOST_URL=${MEILI_HOST}
ENV NUXT_PUBLIC_MEILISEARCH_CLIENT_SEARCH_API_KEY=${MEILI_API_KEY}
ENV NUXT_PUBLIC_MEILI_HOST=${MEILI_HOST}
ENV NUXT_PUBLIC_MEILI_API_KEY=${MEILI_API_KEY}
ENV NUXT_PUBLIC_HOST_URL=${HOST_URL}
# ENV NUXT_PUBLIC_MEILI_HOST=${MEILI_HOST}
# ENV NUXT_PUBLIC_MEILI_API_KEY=${MEILI_API_KEY}
WORKDIR /usr/src/app
......@@ -43,10 +43,21 @@ RUN npm run build
### STAGE: serve ###
FROM node:21.1-bookworm-slim as serve
ARG BASE_URL=/
ARG MEILI_HOST=http://localhost:7700
ARG MEILI_API_KEY
ARG HOST_URL
WORKDIR /usr/src/app
COPY --from=build /usr/src/app/.output ./
ENV NUXT_APP_BASE_URL=${BASE_URL}
# nuxt module
ENV NUXT_PUBLIC_MEILISEARCH_CLIENT_HOST_URL=${MEILI_HOST}
ENV NUXT_PUBLIC_MEILISEARCH_CLIENT_SEARCH_API_KEY=${MEILI_API_KEY}
ENV NUXT_PUBLIC_HOST_URL=${HOST_URL}
WORKDIR /usr/src/app
COPY --chown=node:node --from=build /usr/src/app/.output ./
USER node
CMD [ "node", "server/index.mjs"]
......@@ -55,6 +66,7 @@ FROM node:21.1-bookworm-slim as generate
ARG BASE_URL=/
ARG MEILI_HOST=http://localhost:7700
ARG MEILI_API_KEY
ARG HOST_URL
ENV NODE_OPTIONS=--max_old_space_size=12288
ENV NUXT_APP_BASE_URL=${BASE_URL}
......@@ -62,9 +74,11 @@ ENV NUXT_APP_BASE_URL=${BASE_URL}
# nuxt module
ENV NUXT_PUBLIC_MEILISEARCH_CLIENT_HOST_URL=${MEILI_HOST}
ENV NUXT_PUBLIC_MEILISEARCH_CLIENT_SEARCH_API_KEY=${MEILI_API_KEY}
ENV NUXT_PUBLIC_HOST_URL=${HOST_URL}
ENV NUXT_PUBLIC_MEILI_HOST=${MEILI_HOST}
ENV NUXT_PUBLIC_MEILI_API_KEY=${MEILI_API_KEY}
# ENV NUXT_PUBLIC_MEILI_HOST=${MEILI_HOST}
# ENV NUXT_PUBLIC_MEILI_API_KEY=${MEILI_API_KEY}
WORKDIR /usr/src/app
......@@ -77,9 +91,13 @@ RUN npm run generate
FROM nginx:1.25-bookworm
# RUN rm -rf /usr/share/nginx/html/*
RUN apt update -y && apt install rsync -y
RUN mkdir /public-website
RUN chown nginx:nginx /public-website
COPY nginx.conf /etc/nginx/nginx.conf
RUN chown nginx:nginx /usr/share/nginx/html
COPY --chown=nginx:nginx --from=generate /usr/src/app/.output/public /usr/share/nginx/html
# RUN chmod -R nginx:nginx /usr/share/nginx/html/
USER nginx
COPY --chown=nginx:nginx --from=generate /usr/src/app/.output/public /public-website
CMD ["nginx", "-g", "daemon off;"]
\ No newline at end of file
assets/foldseek.png

142 KiB

<template>
<v-row>
<v-col>
<v-btn prepend-icon="mdi-gitlab" variant="text" size="small" :href="path" target="_blank">Edit on gitlab</v-btn>
<v-btn prepend-icon="i-vscode-icons:file-type-gitlab" variant="text" size="small" :href="path" target="_blank">Edit on gitlab</v-btn>
<v-divider> </v-divider>
</v-col>
</v-row>
......
<script setup lang="ts">
interface Props {
foldseekPath: string
title: string
}
const props = withDefaults(defineProps<Props>(), { title: "Result of Foldseek search" });
const { width, height } = useDisplay()
const dialog = ref(false)
const iframe = ref()
const layout = ref({
scrollbarWidth: 15,
paddingLeft: 24,
paddingRight: 24,
toolbarHeight: 48,
containerPaddingTop: 16,
containerPaddingBottom: 10
})
const xMargin = computed(() => {
const toValLayout = toValue(layout)
return toValLayout.scrollbarWidth + toValLayout.paddingLeft + toValLayout.paddingRight
})
const yMargin = computed(() => {
const toValLayout = toValue(layout)
return toValLayout.toolbarHeight + toValLayout.containerPaddingBottom + toValLayout.containerPaddingTop
})
const computedWidth = computed(() => {
return toValue(width) - toValue(xMargin)
})
const computedHeight = computed(() => {
return toValue(height) - toValue(yMargin)
})
function fullscreen() {
console.log(iframe.value)
iframe.value.requestFullscreen();
}
</script>
<template>
<v-dialog v-model="dialog" fullscreen transition="dialog-bottom-transition">
<template v-slot:activator="{ props }">
<v-avatar>
<v-img src="~/assets/foldseek.png" alt="Foldseek results" v-bind="props" class="cursor-pointer"></v-img>
<!-- <v-btn color="primary" dark v-bind="props">
<v-img src="~/assets/foldseek.png" alt="Foldseek results"></v-img>
</v-btn> -->
</v-avatar>
</template>
<v-card variant="flat">
<v-toolbar flat color="transparent" density="compact">
<v-btn variant="text" color="primary" prepend-icon="mdi-arrow-left" @click="dialog = false">
Return to structure list
</v-btn>
<v-divider vertical inset></v-divider>
<v-toolbar-title> {{ props.title }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn @click="fullscreen()" icon="md:fullscreen"></v-btn>
</v-toolbar-items>
</v-toolbar>
<v-card-text>
<iframe ref="iframe" :width="computedWidth" :height="computedHeight" allow="fullscreen" loading="eager"
:src="props.foldseekPath"></iframe>
</v-card-text>
</v-card>
</v-dialog>
</template>
<style scoped>
.cursor-pointer {
cursor: pointer
}
</style>
\ No newline at end of file
......@@ -9,6 +9,7 @@ export interface Props {
edit?: boolean
navDrawer?: boolean
title?: string
density?: 'compact' | 'prominent'
}
const props = withDefaults(defineProps<Props>(), {
......@@ -16,15 +17,31 @@ const props = withDefaults(defineProps<Props>(), {
toc: true,
edit: true,
navDrawer: true,
title: null
title: "",
density: undefined
});
const drawer = ref(true);
const { page } = useContent();
const scrollThreshold = ref(200)
const density = ref<'compact' | 'prominent'>("prominent")
onMounted(() => {
if (props?.density) {
density.value = props.density
} else {
density.value = "prominent"
}
})
function onScroll() {
if (window.scrollY > scrollThreshold.value) {
if (props?.density) {
return props.density
}
else if (window.scrollY > scrollThreshold.value) {
density.value = "compact"
}
else { density.value = "prominent" }
......@@ -36,9 +53,9 @@ function onScroll() {
<v-main style="min-height: 300px">
<v-container v-scroll="onScroll" :fluid="fluid">
<v-row justify="center">
<v-col cols="auto">
<v-col cols="auto" class="pa-0">
<v-card flat color="transparent" :min-width="mobile ? undefined : 900" :max-width="fluid ? undefined : 1500">
<v-card-text>
<v-card-text class="pa-0">
<slot />
</v-card-text>
<EditGitlab v-if="edit" />
......@@ -48,6 +65,10 @@ function onScroll() {
</v-row>
</v-container>
<!-- <Footer></Footer> -->
<!-- <div class="i-ph-anchor-simple-thin d-none" />
<div class="i-tabler:database d-none" />
<div class="i-mdi:book-education-outline d-none" />
<div class="i-tabler:help d-none" /> -->
</v-main>
<NavNavbar v-model:drawer="drawer" :title="title !== null ? title : undefined" :density="density"
:drawer-enabled="navDrawer" />
......
......@@ -54,16 +54,16 @@ const autocompleteMeiliFacetsProps = ref<AutocompleteMeiliFacetProps>({
db: toValue(dbName),
facets: [
{ title: "Defense System", type: "subheader" },
{ title: "System", value: "type", type: "facet", icon: "mdi-virus-outline", },
{ title: "Subsystem", value: "subtype", type: "facet", icon: "mdi-virus-outline" },
{ title: "System", value: "type", type: "facet", icon: "i-tabler:virus-off", },
{ title: "Subsystem", value: "subtype", type: "facet", icon: "i-tabler:virus-off" },
{ type: "divider" },
{ title: "Taxonomy", type: "subheader" },
{ title: "Superkingdom", value: "Superkingdom", type: "facet", icon: "mdi-family-tree" },
{ title: "Phylum", value: "phylum", type: "facet", icon: "mdi-family-tree" },
{ title: "Order", value: "order", type: "facet", icon: "mdi-family-tree" },
{ title: "Family", value: "family", type: "facet", icon: "mdi-family-tree" },
{ title: "Genus", value: "genus", type: "facet", icon: "mdi-family-tree" },
{ title: "Species", value: "species", type: "facet", icon: "mdi-family-tree" },
{ title: "Superkingdom", value: "Superkingdom", type: "facet", icon: "i-tabler:binary-tree" },
{ title: "Phylum", value: "phylum", type: "facet", icon: "i-tabler:binary-tree" },
{ title: "Order", value: "order", type: "facet", icon: "i-tabler:binary-tree" },
{ title: "Family", value: "family", type: "facet", icon: "i-tabler:binary-tree" },
{ title: "Genus", value: "genus", type: "facet", icon: "i-tabler:binary-tree" },
{ title: "Species", value: "species", type: "facet", icon: "i-tabler:binary-tree" },
{ type: "divider" },
{ title: "Replicon", value: "replicon", type: "facet", icon: "mdi-dna", },
......@@ -104,7 +104,7 @@ const availableTaxo: Ref<string[]> = ref([
]);
const scaleTypes = ref<string[]>(['linear', 'sqrt', 'log', 'symlog'])
const selectedTaxoRank = ref("phylum");
const selectedTaxoRank = ref("Superkingdom");
const headers = ref([
{ title: "Replicon", key: "replicon" },
......@@ -284,7 +284,7 @@ const binPlotOptions = ref({
grid: true,
x: { tickRotate: 90, tip: true, label: "Systems" },
// y: { tickFormat: 's' },
color: { scheme: "turbo", legend: true },
color: { scheme: "plasma", legend: true },
})
const binPlotDataOptions = computed(() => {
......
<script setup lang="ts">
import * as Plot from "@observablehq/plot";
import PlotFigure from "~/components/PlotFigure";
import type { SortItem, AutocompleteMeiliFacetProps } from "@/components/ServerDbTable.vue"
import { useNumericalFilter } from "@/composables/useNumericalfilter"
import type { FacetInputItem } from '@/components/AutocompleteMeiliFacets.vue'
import { useRefinedUrl } from "@/composables/useRefinedUrl"
import { ServerDbTable } from "#components"
import { withQuery, joinURL, withTrailingSlash } from 'ufo'
interface Item {
Foldseek_name: string
System_name_ok: string
}
const sortBy: Ref<SortItem[]> = ref([{ key: 'System', order: "asc" }])
const itemValue = ref("id");
const dbName = ref("structure")
......@@ -32,12 +36,12 @@ const autocompleteMeiliFacetsProps = ref<AutocompleteMeiliFacetProps>({
db: toValue(dbName),
facets: [
{ title: "Defense System", type: "subheader" },
{ title: "System", value: "System", type: "facet", icon: "mdi-virus-outline", },
{ title: "Subsystem", value: "subtype", type: "facet", icon: "mdi-virus-outline" },
{ title: "System", value: "System", type: "facet", icon: "i-tabler:virus-off", },
{ title: "Subsystem", value: "subtype", type: "facet", icon: "i-tabler:virus-off" },
{ type: "divider" },
{ title: "Gene name", value: "gene_name", type: "facet", icon: "mdi-dna" },
{ title: "Completed", value: "completed", type: "facet", icon: "md:done" },
{ title: "Prediction type", value: "prediction_type", type: "facet", icon: "mdi-molecule" },
{ title: "Prediction type", value: "prediction_type", type: "facet", icon: "i-gravity-ui:molecule" },
],
facetDistribution: undefined
})
......@@ -69,6 +73,7 @@ const computedAutocompleteMeiliFacetsProps = computed(() => {
const headers: Ref<Object[]> = ref([
{ title: 'Structure', key: 'structure', sortable: false, removable: false },
{ title: 'Foldseek', key: 'Foldseek_name', sortable: false },
{ title: "System", key: "System", removable: false },
{ title: "Gene name", key: "gene_name", removable: false },
{ title: "Subtype", key: "subtype", removable: false },
......@@ -99,9 +104,7 @@ function isString(item: Ref<string | undefined>): item is Ref<string> {
}
const numericalFilters = computed(() => {
console.log("je compute mes numerical filters")
const listFilters = [plddtsFilter, iptmFilter, pdockqFilter].filter(isString).map(f => toValue(f))
console.log(listFilters)
return listFilters.length > 0 ? listFilters : undefined
})
......@@ -119,6 +122,12 @@ 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)
}
function namesToCollapsibleChips(names: string[], systemDir: string, file: string | null = null) {
......@@ -146,7 +155,7 @@ function pdbNameToCif(pdbPath: string) {
pLDDT
</v-list-item-title>
<v-row>
<v-col class="pt-8 pl-8">
<v-col class="pt-8 pl-8" :lg="8">
<v-range-slider v-model="plddtsRange" strict density="compact" hide-details="auto" step="0.5"
:min="0" :max="100" thumb-label="always" @update:modelValue="search()">
<template #append>
......@@ -161,7 +170,7 @@ function pdbNameToCif(pdbPath: string) {
iptm+ptm
</v-list-item-title>
<v-row>
<v-col class="pt-8 pl-8">
<v-col class="pt-8 pl-8" :lg="8">
<v-range-slider v-model="iptmRange" strict density="compact" hide-details="auto" step="0.1"
:min="0" :max="1" thumb-label="always" @update:modelValue="search()">
<template #append>
......@@ -173,7 +182,7 @@ function pdbNameToCif(pdbPath: string) {
<v-list-item>
<v-list-item-title class="text-subtitle-1 text-medium-emphasis">pDockQ</v-list-item-title>
<v-row>
<v-col class="pt-8 pl-8">
<v-col class="pt-8 pl-8" :lg="8">
<v-range-slider v-model="pdockqRange" density="compact" strict hide-details="auto" step="0.1"
:min="0" :max="1" thumb-label="always" @update:modelValue="search()">
<template #append>
......@@ -184,7 +193,14 @@ function pdbNameToCif(pdbPath: string) {
</v-list-item>
</v-list>
</template>
<template #[`item.Foldseek_name`]="{ item }">
<FoldseekDialog v-if="item.Foldseek_name !== 'na'" :foldseek-path="toFolseekUrl(item)"></FoldseekDialog>
<!-- <NuxtLink v-if="item.Foldseek_name !== 'na'" :to="toFolseekUrl(item)" :external="false">
<v-avatar>
<v-img src="~/assets/foldseek.png" alt="Foldseek results"></v-img>
</v-avatar>
</NuxtLink> -->
</template>
<template #[`item.proteins_in_the_prediction`]="{ item }">
<CollapsibleChips
:items="namesToCollapsibleChips(item.proteins_in_the_prediction, item.System_name_ok, item.fasta_file)">
......
......@@ -23,22 +23,22 @@ const autocompleteMeiliFacetsProps = ref<AutocompleteMeiliFacetProps>({
db: toValue(dbName),
facets: [
{ title: "Defense System", type: "subheader" },
{ title: 'System', value: "title", type: "facet", icon: "mdi-virus-outline" },
{ title: 'System', value: "title", type: "facet", icon: "i-tabler:virus-off" },
{ type: "divider" },
{ title: "Mechanism", type: "subheader" },
{ title: 'Sensor', value: "Sensor", type: "facet", icon: "mdi-cog" },
{ title: 'Effector', value: "Effector", type: "facet", icon: "mdi-cog" },
{ title: 'Activator', value: "Activator", type: "facet", icon: "mdi-cog" },
{ title: 'Sensor', value: "Sensor", type: "facet", icon: "i-tabler:shield-cog" },
{ title: 'Effector', value: "Effector", type: "facet", icon: "i-tabler:shield-cog" },
{ title: 'Activator', value: "Activator", type: "facet", icon: "i-tabler:shield-cog" },
{ type: "divider" },
{ title: "PFAM", type: "subheader" },
{ title: 'Acession', value: "PFAM.AC", type: "facet", icon: "mdi-key" },
{ title: 'Description', value: "PFAM.DE", type: "facet", icon: "md:description" },
{ title: 'Acession', value: "PFAM.AC", type: "facet", icon: "i-tabler:circle-key" },
{ title: 'Description', value: "PFAM.DE", type: "facet", icon: "i-tabler:file-description" },
{ type: "divider" },
{ title: 'Contributor', value: "contributors", type: "facet", icon: "md:person" },
{ title: 'Contributor', value: "contributors", type: "facet", icon: "i-tabler:user-heart" },
],
facetDistribution: undefined
})
......@@ -118,4 +118,5 @@ const columnsToDownload = ref(['title', 'doi', 'Sensor', 'Activator', 'Effector'
<CollapsibleChips v-if="item?.contributors" :items="item.contributors.map(it => ({ title: it }))">
</CollapsibleChips>
</template>
</ServerDbTable></template>
\ No newline at end of file
</ServerDbTable>
</template>
\ No newline at end of file
......@@ -17,8 +17,8 @@ export async function useFetchMsDocument(
const runtimeConfig = useRuntimeConfig();
const client = new MeiliSearch({
host: runtimeConfig.public.meiliHost,
apiKey: runtimeConfig.public.meiliApiKey
host: runtimeConfig.public.meilisearchClient.hostUrl,
apiKey: runtimeConfig.public.meilisearchClient.searchApiKey
})
const pending = ref(false)
const filterError: Ref<string | null> = ref(null)
......
---
title: Contributing to the Wiki
layout: article
navigation:
---
# Contributing to the Wiki
......@@ -99,6 +98,16 @@ dataUrls:
::
```
**3. To edit the Experimental validation section**
This part is a bit tricky to edit. Your first option is to create an issue or send us an email and we'll do it on our side. You need to provide the reference, in which bug it was discovered, in which bug it was expressed and against which phages it was effective.
The second option is that you can try within this live editor : https://mermaid.live/
You can copy paste everything that is within `<mermaid></mermaid>` tags in the editor field of the [live editor](https://mermaid.live/), it should reproduce what you site on the website. From there you can try to modify it until you get what you want.
Here is the documentation about mermaid (the software behind this syntax) : https://mermaid.js.org/intro/
**Custom containers:**
Custom containers can be defined by their types, titles, and contents.
......
navigation.icon: "md:help"
navigation.icon: 'i-tabler:help'
......@@ -19,6 +19,7 @@ relevantAbstracts:
- doi: 10.1038/s41579-023-00934-x
---
# Abortive Infection
The term abortive infection was coined in the 1950s :ref{doi=10.1128/jb.68.1.36-42.1954}
to describe the observations that a fraction of the bacterial population did not support phage replication.
......
......@@ -5,8 +5,9 @@ toc: true
contributors:
- Hugo Vaysset
---
# Defensive Domains
# What are protein domains ?
## What are protein domains ?
Proteins can typically be decomposed into a set of structural or functional units called "domains" where each individual domain has a specific biological function (e.g. catalyzing a chemical reaction or binding to another protein). The combination of one or several protein domains within a protein determines its biological function.
......@@ -14,10 +15,10 @@ Proteins can typically be decomposed into a set of structural or functional unit
To examplify this idea, the figure is a depiction of the ThsA protein involved in the [Thoeris](/defense-systems/thoeris) defense system in *Bacillus cereus*. The protein is composed of two domains : a SIR2-like domain (blue) and a SLOG domain (green). The SLOG domain of ThsA is able to bind to cyclic Adenosine Diphosphate Ribose (cADPR), a signalling molecule produced by ThsB upon phage infection. Binding of cADPR activates the Nicotinamide Adenine Dinucleotide (NAD) depletion activity of the SIR2-like domain which causes abortive infection. This shows how the presence of two domains in this protein allows it to be activated by the sensor component of the system (ThsB) and to trigger the immune response mechanism :ref{doi=10.1038/s41586-021-04098-7}.
# Domain characterization helps to understand the biological function of a protein
## Domain characterization helps to understand the biological function of a protein
Although a considerable diversity of molecular mechanisms have been described for defense systems, it is striking to observe that some functional domains are recurrently involved in antiphage defense :ref{doi=10.1038/s41586-021-04098-7}. When studying the presence of a new defense system, the *in silico* characterization of the domains present in the system can provide valuable information regarding the molecular mechanism of the system. If one protein of the system contains for example a TerB domain, this might indicate that the system is involved in membrane integrity surveillance as this domain was previously shown to be associated with the periplasmic membrane :ref{doi=10.1016/j.chom.2022.09.017}. If a protein of the system contains a TIR domain this might indicate that the system possess a NAD degradation activity or that the protein could multimerize as both functions have been shown for this domain in the past :ref{doi=10.3389/fimmu.2021.784484}.
# Domains can be conserved throughout evolution
## Domains can be conserved throughout evolution
It is clear that some defense systems can be conserved among different clades of bacteria but it was also observed that the unit of evolutionary conservation can be the protein domain :ref{doi=10.1038/s41467-022-30269-9}. As a consequence, it is frequent to find the same domain associated with a wide range of distinct other domains in different defense systems :ref{doi=10.1016/j.mib.2023.102312}. This is well illustrated by defense systems such [Avs](/defense-systems/avs) or [CBASS](/defense-systems/cbass) that can be constituted of diverse effector proteins which differ from each other based on the specific domains that compose them :ref{doi=10.1126/science.aba0372}, :ref{doi=10.1038/s41564-022-01239-0}, :ref{doi=10.1038/s41564-020-0777-y}. The modular aspect of protein domains fits with the concept of "evolution as tinkering" stating that already existing objects (here protein domains) can often be repurposed in new manners, allowing the efficient development of novel functions :ref{doi=10.1126/science.860134}.
......@@ -4,5 +4,6 @@ contributors:
- Marian Dominguez-Mirazo
layout: article
---
# Defense Systems and Mobile Genetic Elements
Mobile genetic elements (MGEs), such as plasmids, bacteriophages, and phage satellites, facilitate horizontal gene transfer (HGT) within microbial populations, playing a crucial role in the genetic diversity and genomic evolution of bacteria :ref{doi=10.1098/rstb.2020.0460}. These elements expedite the exchange of genetic material among bacterial cells, promoting the dissemination of advantageous traits like antibiotic resistance, virulence factors, and metabolic capabilities, allowing bacteria to adapt to dynamic environments :ref{doi=10.1098/rstb.2020.0460}. However, the presence of MGEs can impose a substantial fitness cost on the bacterial host, as in the case of lytic phage infections. To counteract parasitic genomic elements, including viruses and other MGEs, bacteria have evolved defense systems. These defense systems are often disadvantageous under low parasite pressure, leading to their occasional loss. However, as the pressure from parasites increases, these defense systems become advantageous. Consequently, defense systems in bacteria exhibit high mobility and transfer rates :ref{doi=10.1038/s41576-019-0172-9}. Interestingly, a large fraction of defense systems in bacteria are encoded by MGEs :ref{doi=10.1038/s41467-022-30269-9,10.1371/journal.pbio.3001514}. While sometimes the fitness interests of MGEs and the bacterial host are aligned, these systems are likely to be selected because they benefit the MGE encoding it rather than the host cell who :ref{doi=10.1371/journal.pbio.3001514,10.1038/s41576-019-0172-9}. This benefit may include preventing other mobile elements from infecting the same cell and competing for essential resources. The presence of defense systems can, in turn, have an effect in gene flow who :ref{doi=10.1371/journal.pbio.3001514}.
navigation.icon: "md:history_edu"
navigation.icon: 'i-mdi:book-education-outline'
title: Defense Systems
navigation.icon: 'md:list'
\ No newline at end of file
navigation.icon: 'i-tabler:virus-off'
\ No newline at end of file
......@@ -6,16 +6,28 @@ tableColumns:
doi: 10.1016/j.mib.2005.06.006
abstract: |
Abortive infection (Abi) systems, also called phage exclusion, block phage multiplication and cause premature bacterial cell death upon phage infection. This decreases the number of progeny particles and limits their spread to other cells allowing the bacterial population to survive. Twenty Abi systems have been isolated in Lactococcus lactis, a bacterium used in cheese-making fermentation processes, where phage attacks are of economical importance. Recent insights in their expression and mode of action indicate that, behind diverse phenotypic and molecular effects, lactococcal Abis share common traits with the well-studied Escherichia coli systems Lit and Prr. Abis are widespread in bacteria, and recent analysis indicates that Abis might have additional roles other than conferring phage resistance.
Sensor: ''
Activator: ''
Effector: ''
Sensor: Unknown
Activator: Direct Binding
Effector: Unknown
PFAM: PF07751
contributors:
- Marian Dominguez-Mirazo
relevantAbstracts:
- doi: 10.1016/j.mib.2005.06.006
---
# Abi2
## Description
The Abi2 system corresponds to a group of abortive infection systems: [AbiD](/defense-systems/abid), AbiD1 and AbiF.
The Abi2/AbiD1 system of lactococci is composed of a single protein Abi_2 :ref{doi=10.1016/j.mib.2005.06.006}. Expression of the protein is toxic to the bacteria and is therefore highly regulated. Expression of the protein is triggered by the orf1 of phage bIL66 which results in inhibition of the phage RuvC-like endonuclease activity and stops phage multiplication.
## Molecular mechanism
For AbiD1 :ref{doi=10.1128/jb.177.13.3824-3829.1995} (AAA79209), the expression of the protein is toxic to the bacteria and is therefore highly regulated. Expression of the protein is triggered by the orf1 of phage bIL66 which results in inhibition of the phage RuvC-like endonuclease activity and stops phage multiplication.
## Example of genomic structure
......@@ -27,6 +39,9 @@ Here is an example found in the RefSeq database:
The Abi2 system in *Veillonella parvula* (GCF_002005185.1, NZ_CP019721) is composed of 1 protein: Abi_2 (WP_077707938.1)
## Molecular mechanisms
As far as we are aware, the molecular mechanisms remain unclear.
## Distribution of the system among prokaryotes
Among the 22,803 complete genomes of RefSeq, the Abi2 is detected in 1231 genomes (5.4 %).
......@@ -37,3 +52,48 @@ The system was detected in 202 different species.
Proportion of genome encoding the Abi2 system for the 14 phyla with more than 50 genomes in the RefSeq database.
## Structure
### Abi2/AbiD
##### Example 1
::molstar-pdbe-plugin
---
height: 700
dataUrls:
- /abid/AbiD__AbiD.cif
---
::
## Experimental validation
As Abi2 is a group of different Abortive infection systems, here is the experimental validation of AbiD:
<mermaid>
graph LR;
Chopin_2005[<a href='https://doi.org/10.1016/j.mib.2005.06.006'>Chopin et al., 2005</a>] --> Origin_0
Origin_0[lactococcal plasmid
<a href='https://ncbi.nlm.nih.gov/protein/AAA63619.1'>AAA63619.1</a>] --> Expressed_0[lactococci]
Expressed_0[lactococci] ----> 936 & c2 & P335
subgraph Title1[Reference]
Chopin_2005
end
subgraph Title2[System origin]
Origin_0
end
subgraph Title3[Expression species]
Expressed_0
end
subgraph Title4[Phage infected]
936
c2
P335
end
style Title1 fill:none,stroke:none,stroke-width:none
style Title2 fill:none,stroke:none,stroke-width:none
style Title3 fill:none,stroke:none,stroke-width:none
style Title4 fill:none,stroke:none,stroke-width:none
</mermaid>
......@@ -10,13 +10,29 @@ tableColumns:
Activator: Unknown
Effector: Unknown
PFAM: PF16872
contributors:
- Florian Tesson
relevantAbstracts:
- doi: 10.1023/A:1002027321171
- doi: 10.1016/j.mib.2005.06.006
- doi: 10.1128/jb.174.22.7463-7469.1992
---
# AbiC
## Description
AbiC was discovered in *Lactococcus lactis* plasmid in 1992 :ref{doi=10.1128/jb.174.22.7463-7469.1992}
AbiC is one of the so-called "Abi" systems for "Abortive infection" discovered in the 90's in research related to the dairy industry :ref{doi=10.1016/j.mib.2005.06.006}. AbiC is classified as abortive infection in :ref{doi=10.1016/j.mib.2023.102312}.
AbiC is a single gene system composed of the protein AbiC.
## Molecular mechanism
As far as we are aware, the molecular mechanism is unknown.
## Example of genomic structure
The AbiC is composed of 1 protein: AbiC.
......
......@@ -10,13 +10,29 @@ tableColumns:
Activator: Unknown
Effector: Unknown
PFAM: PF07751
contributors:
- Marian Dominguez-Mirazo
- Florian Tesson
relevantAbstracts:
- doi: 10.1023/A:1002027321171
- doi: 10.1016/j.mib.2005.06.006
- doi: 10.1128/aem.61.5.2023-2026.1995
---
# AbiD
## Description
AbiD is a single gene system system discovered in May 1995 in the plasmid pBF61 of *Lactococcus lactis* :ref{doi=10.1128/aem.61.5.2023-2026.1995}. An homolog of AbiD, named AbiD1 was discovered in July 1995 :ref{doi=10.1128/jb.177.13.3818-3823.1995}.
AbiD is one of the so-called "Abi" systems for "Abortive infection" discovered in the 90's in research related to the dairy industry :ref{doi=10.1016/j.mib.2005.06.006}. AbiR is classified as a possible abortive infection in :ref{doi=10.1016/j.mib.2023.102312}.
This antiphage defense system is very close to AbiD1 and AbiF :ref{doi=10.1128/aem.61.12.4321-4328.1995} and is categorized as the same system. Furthermore, AbiD is also detected as the [Abi2](/defense-systems/abi2) system.
### Molecular mechanism
For AbiD1 :ref{doi=10.1128/jb.177.13.3824-3829.1995} ([AAA79209](https://www.ncbi.nlm.nih.gov/protein/AAA79209)), the expression of the protein is toxic to the bacteria and is therefore highly regulated. Expression of the protein is triggered by the orf1 of phage bIL66 which results in inhibition of the phage RuvC-like endonuclease activity and stops phage multiplication.
## Example of genomic structure
The AbiD is composed of 1 protein: AbiD.
......@@ -79,4 +95,3 @@ end
style Title3 fill:none,stroke:none,stroke-width:none
style Title4 fill:none,stroke:none,stroke-width:none
</mermaid>