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

Foldseek pages

parent 015ff6ba
No related branches found
No related tags found
1 merge request!203Foldseek pages
Showing
with 211 additions and 67 deletions
......@@ -203,15 +203,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
......@@ -328,7 +319,7 @@ get-zotero:
variables:
CONTEXT: "."
DOCKERFILE: "Dockerfile"
BASE_URL: /wiki/
BASE_URL: /
MEILI_HOST: "http://localhost:7700"
before_script:
- *docker-login
......@@ -337,7 +328,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 +341,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 +357,8 @@ build:prod:wiki:
# - get-pfam
variables:
BASE_URL: /wiki/
HOST_URL: https://${HOST_PROD}
rules:
- if: $CI_COMMIT_BRANCH == "main"
......@@ -495,7 +489,7 @@ build:prod:wiki:
deploy:dev:
extends: .deploy
rules:
- if: $CI_COMMIT_BRANCH == "dev" || $CI_COMMIT_BRANCH == "refactor-facet-autocomplete"
- if: $CI_COMMIT_BRANCH == "dev" || $CI_COMMIT_BRANCH == "foldseek-pages"
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
......
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", },
......
<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
......
navigation.icon: "md:help"
navigation.icon: 'i-tabler:help'
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
---
title: RefSeq DB
layout: db
navigation:
icon: "mdi-database"
navigation.icon: 'i-tabler:database'
---
# RefSeq DB
......
......@@ -2,7 +2,7 @@
title: Structures DB
layout: db
navigation:
icon: "mdi-database"
icon: 'i-tabler:database'
---
# Structure's prediction DB
......
......@@ -8,6 +8,7 @@ services:
BASE_URL: /wiki/
MEILI_HOST: http://localhost:7700
MEILI_API_KEY: f9cc073016cbb392365aae86517878cb3f3408bb85c1fafd06e27f73ccb35e3d
HOST_URL: http://localhost:8082
container_name: nuxt
environment:
HOST: 0.0.0.0
......
......@@ -4,7 +4,7 @@ const { page } = useContent();
</script>
<template>
<LayoutWrapper :title="page.title" :fluid="true" :toc="false" :edit="false" :nav-drawer="false">
<LayoutWrapper :title="page?.title" :fluid="true" :toc="false" :edit="false" :nav-drawer="false">
<slot />
</LayoutWrapper>
</template>
......
<template>
<LayoutWrapper title="Foldseek results" :density="'compact'" :fluid="true" :toc="false" :edit="false"
:nav-drawer="false">
<slot />
</LayoutWrapper>
</template>
......@@ -2,12 +2,13 @@ import { md3 } from 'vuetify/blueprints'
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
modules: [
'@unocss/nuxt',
'@nuxt/content',
'vuetify-nuxt-module',
'@vueuse/nuxt',
'@pinia/nuxt',
'nuxt-meilisearch',
// '@unocss/nuxt',
],
content: {
documentDriven: {
......@@ -24,8 +25,15 @@ export default defineNuxtConfig({
vuetifyOptions: {
labComponents: true,
icons: {
defaultSet: 'mdi',
defaultSet: 'unocss-mdi',
sets: ['mdi', 'fa', 'md'],
unocssIcons: {
// default is i-mdi:close-circle
// database: 'i-tabler:database',
// even from another collection, default is i-mdi:chevron-up
// generalconcept: 'i-mdi:book-education-outline',
// help: 'i-tabler:help'
}
},
blueprint: md3
......@@ -44,12 +52,13 @@ export default defineNuxtConfig({
public: {
defenseFinderWebservice: '/',
hostUrl: "http://localhost:8082",
meilisearchClient: {
hostUrl: 'http://localhost:7700',
searchApiKey: 'api_key',
},
meiliHost: 'http://localhost:7700',
meiliApiKey: 'api_key'
// meiliHost: 'http://localhost:7700',
// meiliApiKey: 'api_key'
}
},
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment