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

get article from meilisearch + cache

parent 4d4bba17
No related branches found
No related tags found
1 merge request!224Resolve "Rework references"
Pipeline #124708 canceled with stages
in 1 minute and 5 seconds
<script setup lang="ts"> <script setup lang="ts">
import { useDisplay } from "vuetify"; import { useDisplay } from "vuetify";
import { useArticlesStore } from '@/stores/articles' import type { WikiArticle } from '@/types/articles';
export interface Props { export interface Props {
index?: number; index?: number;
...@@ -19,11 +19,14 @@ const props = withDefaults(defineProps<Props>(), { ...@@ -19,11 +19,14 @@ const props = withDefaults(defineProps<Props>(), {
isRelevant: false, isRelevant: false,
}); });
const { article } = useFetchArticle(props.doi); const article = ref<WikiArticle | undefined>(undefined)
const { mobile } = useDisplay(); const { mobile } = useDisplay();
const show = ref(false); const show = ref(false);
onMounted(async () => {
const { article: articleOnMounted } = await useFetchArticle(props.doi);
article.value = articleOnMounted.value
})
const articleTitle = computed(() => { const articleTitle = computed(() => {
return props?.title ?? article?.value?.title ?? props.doi; return props?.title ?? article?.value?.title ?? props.doi;
}); });
...@@ -32,16 +35,11 @@ const articleAbstract = computed(() => { ...@@ -32,16 +35,11 @@ const articleAbstract = computed(() => {
}); });
</script> </script>
<template> <template>
<v-list-item :href="article?.href" :id="`ref-${props.doi}`" :target="article?.target" density="compact" color="transparent" <v-list-item :href="article?.href" :id="`ref-${props.doi}`" :target="article?.target" density="compact"
class="px-1"> color="transparent" class="px-1">
<template v-if="!mobile" #prepend> <template v-if="!mobile" #prepend>
<v-icon icon="md:star" :color="props.isRelevant ? 'info' : 'transparent'"></v-icon> <v-icon icon="md:star" :color="props.isRelevant ? 'info' : 'transparent'"></v-icon>
</template> </template>
<!-- <template v-if="!mobile" #append>
<v-btn v-if="articleAbstract" size="x-small" variant="plain"
:append-icon="show ? 'mdi-chevron-up' : 'mdi-chevron-down'" class="px-0"
@click.stop.prevent="show = !show">Abstract</v-btn>
</template> -->
<v-card flat color="transparent" density="compact" class="my-0 article-ref"> <v-card flat color="transparent" density="compact" class="my-0 article-ref">
<v-card-item density="compact" class="pa-0"> <v-card-item density="compact" class="pa-0">
<v-toolbar class="py-0 d-flex align-start article-toolbar" color="transparent" :height="20"> <v-toolbar class="py-0 d-flex align-start article-toolbar" color="transparent" :height="20">
...@@ -51,9 +49,6 @@ const articleAbstract = computed(() => { ...@@ -51,9 +49,6 @@ const articleAbstract = computed(() => {
:append-icon="show ? 'mdi-chevron-up' : 'mdi-chevron-down'" class="px-1 align-center" :append-icon="show ? 'mdi-chevron-up' : 'mdi-chevron-down'" class="px-1 align-center"
@click.stop.prevent="show = !show">Abstract</v-btn> @click.stop.prevent="show = !show">Abstract</v-btn>
</v-toolbar> </v-toolbar>
<!-- <v-card-title class="py-0"><span class="font-weight-bold">{{
articleTitle
}}</span></v-card-title> -->
<v-card-subtitle class="py-0"> <v-card-subtitle class="py-0">
{{ article?.subtitle ?? "no authors" }}</v-card-subtitle> {{ article?.subtitle ?? "no authors" }}</v-card-subtitle>
<v-card-subtitle class="py-0"> <v-card-subtitle class="py-0">
......
import { useArticlesStore } from '../stores/articles' import { ref, toValue } from "vue"
import { ref, computed, watchEffect, toValue } from "vue" import { StorageSerializers } from "@vueuse/core"
// import { useFetch } from '#app'; import type { CslJson, WikiArticle } from '@/types/articles';
// import { useFetch } from "nuxt" import type { SearchParams } from 'meilisearch'
import { type MaybeRef, useFetch } from '#imports'
import type { CslJson, CrossrefArticle, SrcArticle } from '@/types/articles';
export async function useFetchArticle(doi: string = "") {
export function useFetchArticle(doi: MaybeRef<string> = ref("")) {
// const article = ref<Article>()
// const rawArticle = ref<RawArticle>()
const srcArticle = ref<SrcArticle | null>(null)
const store = useArticlesStore()
const pending = ref(false)
const doiBaseUrl = ref(new URL("https://doi.org/")); const doiBaseUrl = ref(new URL("https://doi.org/"));
const url = ref(new URL(`/works/${toValue(doi)}`, " https://api.crossref.org/").href); // const article = ref<WikiArticle | undefined>(undefined)
const article = ref() const article = useSessionStorage<WikiArticle>(doi, null, { serializer: StorageSerializers.object })
const zoteroArticles = ref() const client = useMeiliSearchRef()
const index = ref("article")
const params = ref<SearchParams>({
facets: ["*"],
filter: [`DOI='${doi}'`],
limit: 1
})
function getReferenceUrl(doi: string) {
return new URL(doi, doiBaseUrl.value).href;
}
function toAuthorsString(authors: Array<{ family: string; given: string }>) { function toAuthorsString(authors: Array<{ family: string; given: string }>) {
return authors return authors
.map((curr) => { .map((curr) => {
...@@ -28,12 +24,7 @@ export function useFetchArticle(doi: MaybeRef<string> = ref("")) { ...@@ -28,12 +24,7 @@ export function useFetchArticle(doi: MaybeRef<string> = ref("")) {
}) })
.join(", "); .join(", ");
} }
function zoteroArticleToArticle(zoteroArticle: CslJson): WikiArticle | undefined {
function getReferenceUrl(doi: string) {
return new URL(doi, doiBaseUrl.value).href;
}
function zoteroArticleToArticle(zoteroArticle: CslJson) {
if (zoteroArticle != undefined) { if (zoteroArticle != undefined) {
const { const {
DOI, DOI,
...@@ -56,74 +47,38 @@ export function useFetchArticle(doi: MaybeRef<string> = ref("")) { ...@@ -56,74 +47,38 @@ export function useFetchArticle(doi: MaybeRef<string> = ref("")) {
target: "_blank", target: "_blank",
prependIcon: "mdi-newspaper-variant-outline", prependIcon: "mdi-newspaper-variant-outline",
} }
} } else { return undefined }
}
if (!article.value) {
const { data, error } = await useAsyncData(
doi,
async () => {
return await client.index(toValue(index)).search<CslJson>("", toValue(params))
},
{
transform: function (data) {
if (data !== undefined && data?.hits.length >= 1) {
return zoteroArticleToArticle(data.hits[0])
}
}
}
)
} if (error.value) {
function crossrefToArticle(article: CrossrefArticle): WikiArticle { throw createError({
const { title, DOI, type, "container-title": ct, "short-container-title": sct, abstract, author, issued } = article ...error.value,
// let sanitizedAbstract = abstract statusMessage: `Could not fetch article ${doi}`
const sanitizedAbstract = abstract ? /(?:\<jats\:p\>)?(.*)(?:\<\/jats\:p\>)?/.exec(abstract)?.[1] ?? '' : '' })
const sanitizedContainerTitle = sct?.length > 0 ? sct[0] : ct?.length > 0 ? ct[0] : ""
return {
title: title?.length > 0 ? title[0] : "",
DOI,
abstract: sanitizedAbstract,
containerTitle: sanitizedContainerTitle,
subtitle: toAuthorsString(author || []),
author,
year: issued?.["date-parts"][0][0] ?? '',
href: getReferenceUrl(DOI),
target: "_blank",
prependIcon: "mdi-newspaper-variant-outline"
} }
article.value = data.value
} }
return { article }
}
function crossrefToCsl(article: CrossrefArticle): CslJson {
const { title, DOI, type, "container-title": ct, "short-container-title": sct, abstract, author, issued } = article
// let sanitizedAbstract = abstract
const sanitizedAbstract = abstract ? /(?:\<jats\:p\>)?(.*)(?:\<\/jats\:p\>)?/.exec(abstract)?.[1] ?? '' : ''
const sanitizedContainerTitle = sct?.length > 0 ? sct[0] : ct?.length > 0 ? ct[0] : ""
return {
title: title?.length > 0 ? title[0] : "",
type,
DOI,
abstract: sanitizedAbstract,
author,
"container-title": sanitizedContainerTitle,
issued
}
}
if (store.articles.has(toValue(doi))) {
const cslArticle = store.articles.get(toValue(doi))
article.value = cslArticle ? zoteroArticleToArticle(cslArticle) : undefined
}
else {
useFetch<RawArticle>(toValue(url), {
lazy: true, server: false,
}).then(({ data, pending: pendingUseFetch }) => {
if (data.value?.message) {
article.value = crossrefToArticle(data.value.message)
store.add(crossrefToCsl(data.value.message))
}
pending.value = pendingUseFetch.value
})
}
// const fetchCrossRef = () => {
// useFetch<RawArticle>(toValue(url), {
// lazy: true, server: false,
// }).then(({ data, pending: pendingUseFetch }) => {
// if (data.value?.message) {
// srcArticle.value = data.value.message
// }
// pending.value = pendingUseFetch.value
// })
// }
return { article, pending }
}
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