diff --git a/client/locales.md b/client/locales.md index a287b058..dededf63 100644 --- a/client/locales.md +++ b/client/locales.md @@ -12,8 +12,8 @@ | /pages/bugs | OK | Mihoub | FR,EN,ES,DE | | /pages/home | OK | Mihoub | FR,EN,ES,DE | | /pages/organization | OK | Mihoub | FR,EN,ES,DE | -| /pages/projects | TODO | Mihoub | FR,EN,ES,DE | -| /pages/publications | TODO | Mihoub | FR,EN,ES,DE | +| /pages/projects | OK | FRED | FR,EN,ES,DE | +| /pages/publications | OK | FRED | FR,EN,ES,DE | | /components/api-deprecation-banner | OK | FRED | FR,EN | | /components/contact-form | OK | FRED | FR,EN | | /components/copy | OK | FRED | FR,EN | @@ -25,4 +25,6 @@ | /components/truncate | OK | FRED | FR,EN,ES,DE | | /components/websites | OK | FRED | FR,EN | | /components/wiki | OK | FRED | FR,EN | -| /components/share | TODO | FRED | FR,EN | +| /components/share | OK | FRED | FR,EN | +| /components/analytics-graph | OK | FRED | FR,EN | +| /layout/* | OK | FRED | FR,EN | \ No newline at end of file diff --git a/client/package-lock.json b/client/package-lock.json index 85b72b1e..9c27e79b 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -2778,9 +2778,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.28.8", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.28.8.tgz", - "integrity": "sha512-cx64XHeB0kvKxFt22ibvegPeOxnaWVFUbAuhXoIrb7+XePEexHWoB9Kq5n9qroNPkRwQZwgFAP9HNbQz5ohoIg==", + "version": "5.28.9", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.28.9.tgz", + "integrity": "sha512-hNlfCiqZevr3GRVPXS3MhaGW5hjcxvCsIQ4q6ff7EPlvFwYZaS+0d9EIIgofnegDaU2BbCDlyURoYfRl5rmzow==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" @@ -2796,11 +2796,11 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.28.8", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.28.8.tgz", - "integrity": "sha512-4XYhoRmcThqziB32HsyiBLNXJcukaeGfYwAQ+fZqUUE3ZP4oB/Zy41UJdql+TUg98+vsezfbixxAwAbGHfc5Hg==", + "version": "5.28.9", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.28.9.tgz", + "integrity": "sha512-vwifBkGXsydsLxFOBMe3+f8kvtDoqDRDwUNjPHVDDt+FoBetCbOWAUHgZn4k+CVeZgLmy7bx6aKeDbe3e8koOQ==", "dependencies": { - "@tanstack/query-core": "5.28.8" + "@tanstack/query-core": "5.28.9" }, "funding": { "type": "github", @@ -2811,9 +2811,9 @@ } }, "node_modules/@tanstack/react-query-devtools": { - "version": "5.28.8", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.28.8.tgz", - "integrity": "sha512-NorR2ueGlGdB5PTvt1WynzjfNI/OJwiisB1r0UAwgi0Em2UalZpMltwvoIrGhJ0T2V+8b0MV5wD+cmf0PPdHGA==", + "version": "5.28.9", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.28.9.tgz", + "integrity": "sha512-GHbJDJIhAak2B+7NJvSfT+jfajxMf/CEwbVn4Z+JSVLUZ21/TITwQWaihN1WKKj/nMbizUu6U2O9MTNHW4YPqg==", "dependencies": { "@tanstack/query-devtools": "5.28.6" }, @@ -2822,7 +2822,7 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-query": "^5.28.8", + "@tanstack/react-query": "^5.28.9", "react": "^18.0.0" } }, @@ -2894,12 +2894,11 @@ "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { - "version": "18.2.71", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.71.tgz", - "integrity": "sha512-PxEsB9OjmQeYGffoWnYAd/r5FiJuUw2niFQHPc2v2idwh8wGPkkYzOHuinNJJY6NZqfoTCiOIizDOz38gYNsyw==", + "version": "18.2.72", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.72.tgz", + "integrity": "sha512-/e7GWxGzXQF7OJAua7UAYqYi/4VpXEfbGtmYQcAQwP3SjjjAXfybTf/JK5S+SaetB/ChXl8Y2g1hCsj7jDXxcg==", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, @@ -2912,11 +2911,6 @@ "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==" - }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", @@ -5450,9 +5444,9 @@ } }, "node_modules/react-intl": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.6.3.tgz", - "integrity": "sha512-vLKI0f+Q3pXD5szmCUPikTY7CJDPtxCBMG5YABQZ3IGEKzNB47zlvXyasUFfT25zpgQXeOfhRCdx4q6ubuR6bA==", + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.6.4.tgz", + "integrity": "sha512-bD+7hVTX3zBFI3z/ffIVZrNkCVK0/sQguQ/DqW5uZ6JFWsuiwOieVcLnmtFiUgMQZLdmwNl2Ur5c10RaO7NWBQ==", "dependencies": { "@formatjs/ecma402-abstract": "1.18.2", "@formatjs/icu-messageformat-parser": "2.7.6", diff --git a/client/src/api/networks/network/communities.ts b/client/src/api/networks/network/communities.ts index a5323f5a..9198757d 100644 --- a/client/src/api/networks/network/communities.ts +++ b/client/src/api/networks/network/communities.ts @@ -2,19 +2,19 @@ import Graph from "graphology-types" import louvain from "graphology-communities-louvain" import { arrayPush, labelClean } from "../_utils/functions" import { networkSearchHits } from "../search/search" -import { ElasticHits } from "../../../types/network" +import { ElasticHits, NetworkCommunities, NetworkFilters } from "../../../types/network" import { openAiLabeledClusters } from "./openai" import { vosColors } from "../_utils/constants" import { GetColorName } from "hex-color-to-color-name" -const communityGetAttribute = (graph: Graph, community: number, name: string): Array => +const communityGetAttribute = (graph: Graph, community: number, name: string): Array | Array => graph.reduceNodes( (acc, _, attr) => (attr.community === community && attr?.[name] ? (acc = arrayPush(acc, attr[name])) : acc), [] ) const communityGetLinks = (graph: Graph, community: number): Array => [ - ...new Set(communityGetAttribute(graph, community, "links").flat(1)), + ...new Set(communityGetAttribute(graph, community, "links").flat(1).map(String)), ] const communityGetIds = (graph: Graph, community: number): Array => @@ -24,10 +24,10 @@ const communityGetSize = (graph: Graph, community: number): number => graph.filterNodes((_, attr) => attr?.community === community).length const communityGetMaxYear = (graph: Graph, community: number): number => - Math.max(...communityGetAttribute(graph, community, "maxYear")) + Math.max(...communityGetAttribute(graph, community, "maxYear").map(Number)) const communityGetMaxWeightNodes = (graph: Graph, community: number): Array => { - const maxWeight = Math.max(...communityGetAttribute(graph, community, "weight")) + const maxWeight = Math.max(...communityGetAttribute(graph, community, "weight").map(Number)) const labels = graph.reduceNodes( (acc, _, attr) => (acc = attr?.community === community && attr?.weight === maxWeight ? [...acc, attr.label] : acc), [] @@ -35,7 +35,7 @@ const communityGetMaxWeightNodes = (graph: Graph, community: number): Array +const communityGetYears = (hits: ElasticHits): Record => hits.reduce((acc, hit) => { const year = hit.year acc[year] = acc[year] ? acc[year] + 1 : 1 @@ -44,7 +44,7 @@ const communityGetYears = (hits: ElasticHits) => // const communityGetPublications = (hits: ElasticHits): Array => hits.map((hit) => hit.title.default) -const communityGetDomains = (hits: ElasticHits): any => +const communityGetDomains = (hits: ElasticHits): Record => hits.reduce((acc, hit) => { if (hit?.domains) { hit.domains.forEach(({ label, count }) => { @@ -58,9 +58,10 @@ const communityGetDomains = (hits: ElasticHits): any => const communityGetOaPercent = (hits: ElasticHits): number => (hits.map((hit) => hit.isOa).filter(Boolean).length / hits.length) * 100 -export default async function communitiesCreate(graph: Graph, computeClusters: boolean): Promise { - const query = graph.getAttribute("query") - const model = graph.getAttribute("model") +export default async function communitiesCreate(graph: Graph, computeClusters: boolean): Promise { + const query: string = graph.getAttribute("query") + const model: string = graph.getAttribute("model") + const filters: NetworkFilters = graph.getAttribute("filters") // Assign communities louvain.assign(graph) @@ -74,21 +75,22 @@ export default async function communitiesCreate(graph: Graph, computeClusters: b // Create communities array const communities = Promise.all( Array.from({ length: count }, async (_, index) => { - const hits = await networkSearchHits(query, model, communityGetLinks(graph, index)) + // Get elastic publications + const hits = await networkSearchHits({ model, query, filters, links: communityGetLinks(graph, index) }) const community = { - index: index, + cluster: index, label: vosColors?.[index] ? GetColorName(vosColors[index]) : `Unnamed ${index + 1}`, color: vosColors?.[index] ?? "#e2e2e2", - ids: communityGetIds(graph, index), size: communityGetSize(graph, index), + ids: communityGetIds(graph, index), maxYear: communityGetMaxYear(graph, index), maxWeightNodes: communityGetMaxWeightNodes(graph, index), ...(hits && { - domains: communityGetDomains(hits), - oaPercent: communityGetOaPercent(hits), hits: hits.length, years: communityGetYears(hits), + domains: communityGetDomains(hits), + oaPercent: communityGetOaPercent(hits), }), } return community diff --git a/client/src/api/networks/network/config.ts b/client/src/api/networks/network/config.ts index 0448a56f..c892024d 100644 --- a/client/src/api/networks/network/config.ts +++ b/client/src/api/networks/network/config.ts @@ -1,3 +1,4 @@ +import { Attributes } from "graphology-types" import { NetworkConfig } from "../../../types/network" const CONFIG = { @@ -41,7 +42,7 @@ const CONFIG = { }, }, domains: { - url: (_: string, attr: any) => `/search/publications?q="${attr.label.replace(/ /g, "+")}"`, + url: (_: string, attr: Attributes) => `/search/publications?q="${attr.label.replace(/ /g, "+")}"`, terminology: { item: "domain", items: "domains", @@ -54,7 +55,7 @@ const CONFIG = { }, }, software: { - url: (_: string, attr: any) => `/search/publications?q="${attr.label.replace(/ /g, "+")}"`, + url: (_: string, attr: Attributes) => `/search/publications?q="${attr.label.replace(/ /g, "+")}"`, terminology: { item: "software", items: "software", @@ -73,7 +74,7 @@ const configGetItemDescription = () => const configGetLinkDescription = (model: string) => `
Co-${model} link
` -export function configGetItemUrl(model: string, key: string, attr: any): string { +export function configGetItemUrl(model: string, key: string, attr: Attributes): string { const targetUrl = CONFIG?.[model]?.url(key, attr) ?? "" const baseUrl = window?.location?.href?.split("/networks")[0] ?? "" return baseUrl + targetUrl diff --git a/client/src/api/networks/network/network.ts b/client/src/api/networks/network/network.ts index 197dd66b..000157c7 100644 --- a/client/src/api/networks/network/network.ts +++ b/client/src/api/networks/network/network.ts @@ -3,7 +3,7 @@ import subgraph from "graphology-operators/subgraph" import { connectedComponents } from "graphology-components" import random from "graphology-layout/random" import forceAtlas2 from "graphology-layout-forceatlas2" -import { NetworkData } from "../../../types/network" +import { ElasticBuckets, NetworkFilters, NetworkData } from "../../../types/network" import communitiesCreate from "./communities" import { configGetItemUrl } from "./config" @@ -15,13 +15,15 @@ const nodeConcatMaxYear = (nodeMaxYear: number, maxYear: number) => (nodeMaxYear export default async function networkCreate( query: string, model: string, - aggregation: Array, + filters: NetworkFilters, + aggregation: ElasticBuckets, computeClusters: boolean ): Promise { // Create Graph object let graph = new UndirectedGraph() graph.setAttribute("query", query) graph.setAttribute("model", model) + graph.setAttribute("filters", filters) aggregation.forEach((item) => { const { key, doc_count: count } = item @@ -88,7 +90,7 @@ export default async function networkCreate( console.log("Graph nodes", Array.from(graph.nodeEntries())) // Create network - const network = { + const network: NetworkData = { items: graph.mapNodes((key, attr) => ({ id: key, x: attr.x, @@ -102,15 +104,11 @@ export default async function networkCreate( links: graph.mapEdges((_, attr, source, target) => ({ source_id: source, target_id: target, - strength: attr?.weight, - })), - clusters: communities.map((community) => ({ - ...community, - cluster: community.index + 1, + strength: attr.weight, })), + clusters: communities, } console.log("network", network) - return network } diff --git a/client/src/api/networks/network/openai.ts b/client/src/api/networks/network/openai.ts index 9c3b9139..144bcadb 100644 --- a/client/src/api/networks/network/openai.ts +++ b/client/src/api/networks/network/openai.ts @@ -1,8 +1,9 @@ import MistralClient, { ResponseFormats } from "@mistralai/mistralai" +import { NetworkCommunities } from "../../../types/network" const ENABLED = false -async function mistralLabelsFromDomains(domains: any): Promise { +async function mistralLabelsFromDomains(domains: string): Promise { const { VITE_MISTRAL_API_KEY } = import.meta.env if (!VITE_MISTRAL_API_KEY) { @@ -35,7 +36,7 @@ async function mistralLabelsFromDomains(domains: any): Promise { return answer } -export async function openAiLabeledClusters(clusters: Array) { +export async function openAiLabeledClusters(clusters: NetworkCommunities): Promise { if (!ENABLED) return clusters const prefix = "list" @@ -50,7 +51,7 @@ export async function openAiLabeledClusters(clusters: Array) { acc = acc + `${prefix}${index + 1} = [${topDomains}], ` } return acc - }, "") + }, "") as string console.log("domains", domains) if (!domains) return clusters diff --git a/client/src/api/networks/search/search.ts b/client/src/api/networks/search/search.ts index c3001a84..da332598 100644 --- a/client/src/api/networks/search/search.ts +++ b/client/src/api/networks/search/search.ts @@ -1,5 +1,5 @@ import { publicationsIndex, postHeaders } from "../../../config/api" -import { Network, NetworkSearchBody, NetworkSearchArgs, ElasticHits } from "../../../types/network" +import { Network, NetworkSearchBody, NetworkSearchArgs, ElasticHits, NetworkSearchHitsArgs } from "../../../types/network" import networkCreate from "../network/network" import configCreate from "../network/config" import infoCreate from "../network/info" @@ -43,7 +43,7 @@ export async function networkSearch({ model, query, options, filters }: NetworkS headers: postHeaders, }) if (res.status !== 200) { - throw new Error(`Elasticsearch error: ${res.status}`); + throw new Error(`Elasticsearch error: ${res.status}`) } const json = await res.json() console.log("endOfSearch", json) @@ -54,7 +54,7 @@ export async function networkSearch({ model, query, options, filters }: NetworkS } const computeClusters = options?.computeClusters ?? false - const network = await networkCreate(query, model, aggregation, computeClusters) + const network = await networkCreate(query, model, filters, aggregation, computeClusters) const config = configCreate(model) const info = infoCreate(query, model) @@ -72,7 +72,8 @@ export async function networkSearch({ model, query, options, filters }: NetworkS return data } -export async function networkSearchHits(query: string, model: string, links: Array): Promise { +export async function networkSearchHits({ model, query, filters, links }: NetworkSearchHitsArgs): Promise { + const linksFilter = { terms: { [`co_${model}.keyword`]: links } } const body = { size: DEFAULT_SIZE, _source: HIT_FIELDS, @@ -86,11 +87,7 @@ export async function networkSearchHits(query: string, model: string, links: Arr }, }, ], - filter: { - terms: { - [`co_${model}.keyword`]: links, - }, - }, + filter: filters.concat(linksFilter), }, }, } diff --git a/client/src/api/publications/[id]/index.ts b/client/src/api/publications/[id]/index.ts index 2128e27f..5244336a 100644 --- a/client/src/api/publications/[id]/index.ts +++ b/client/src/api/publications/[id]/index.ts @@ -7,7 +7,7 @@ export async function getPublicationById(id: string): Promise { _source: [ "title", "summary", "authors.fullName", "authors.person", "authors.role", "authors.affiliations", "domains", "affiliations", "source", "isOa", 'type', 'id', "year", "oaEvidence", "projects", "externalIds", - "pdfUrl", "landingPage" + "pdfUrl", "landingPage", "softwares", ], query: { bool: { diff --git a/client/src/api/publications/more-like-this/index.ts b/client/src/api/publications/more-like-this/index.ts index b2515a78..9791eb1b 100644 --- a/client/src/api/publications/more-like-this/index.ts +++ b/client/src/api/publications/more-like-this/index.ts @@ -8,7 +8,7 @@ export async function getMorePublicationsLikeThis(id: string) { size: 3, query: { more_like_this: { - fields: ["title.default"], + fields: ["title.default", "domains.label.*"], like: [{ _id: id }], min_term_freq: 1, max_query_terms: 12, diff --git a/client/src/components/analytics-graph/index.tsx b/client/src/components/analytics-graph/index.tsx index 231a61d9..d17b28af 100644 --- a/client/src/components/analytics-graph/index.tsx +++ b/client/src/components/analytics-graph/index.tsx @@ -1,8 +1,17 @@ -import { Title, MenuButton, MenuSection, MenuItem, Modal, ModalTitle, ModalContent } from "@dataesr/dsfr-plus" +import { Title, MenuButton, MenuSection, MenuItem, Modal, ModalTitle, ModalContent, useDSFRConfig } from "@dataesr/dsfr-plus" import HighchartsReact, { HighchartsReactProps } from "highcharts-react-official"; import React, { useId, useRef, useState } from "react"; import Highcharts from "./highcharts"; +import { RawIntlProvider, createIntl } from 'react-intl'; +const modules = import.meta.glob('./locales/*.json', { eager: true, import: 'default' }) +const messages = Object.keys(modules).reduce((acc, key) => { + const locale = key.match(/\.\/locales\/(.+)\.json$/)?.[1]; + if (locale) { + return { ...acc, [locale]: modules[key] } + } + return acc; +}, {}); export type AnalyticsGraphProps = { title: string, description?: React.ReactNode, @@ -12,6 +21,8 @@ export type AnalyticsGraphProps = { export default function AnalyticsGraph({ title, description, comment, options }: AnalyticsGraphProps) { + const { locale } = useDSFRConfig(); + const intl = createIntl({ locale, messages: messages[locale] }); const descriptionId = useId(); const titleId = useId(); const chartRef = useRef(null); @@ -33,74 +44,86 @@ export default function AnalyticsGraph({ title, description, comment, options }: } return ( -
-
-
- - {title} - - {description &&

{description}

} -
-
- - - } - > - Plein écran - - } - > - {showTable ? "Masquer" : "Voir"} les données - - - - } - > - Exporter une image png - - } - > - PDF - - - - } - > - Télécharger les données en csv - - - + +
+
+
+ + {title} + + {description &&

{description}

} +
+
+ + + } + > + + {intl.formatMessage({ id: "analytics.graph.fullscreen" })} + + + } + > + + {intl.formatMessage({ id: "analytics.graph.view.table" })} + + + + + } + > + + {intl.formatMessage({ id: "analytics.graph.export.png" })} + + + } + > + + {intl.formatMessage({ id: "analytics.graph.export.pdf" })} + + + + + } + > + + {intl.formatMessage({ id: "analytics.graph.download.csv" })} + + + + +
+ + {comment &&

{comment}

} + setShowTable(false)}> + {title} + +
+ +
- - {comment &&

{comment}

} - setShowTable(false)}> - {title} - -
- - -
+ ) } \ No newline at end of file diff --git a/client/src/components/analytics-graph/locales/en.json b/client/src/components/analytics-graph/locales/en.json new file mode 100644 index 00000000..42452869 --- /dev/null +++ b/client/src/components/analytics-graph/locales/en.json @@ -0,0 +1,7 @@ +{ + "analytics.graph.fullscreen": "Full screen", + "analytics.graph.view.table": "View data", + "analytics.graph.export.png": "Export as PNG", + "analytics.graph.export.pdf": "Export as PDF", + "analytics.graph.download.csv": "Download data as CSV" +} \ No newline at end of file diff --git a/client/src/components/analytics-graph/locales/fr.json b/client/src/components/analytics-graph/locales/fr.json new file mode 100644 index 00000000..d448538e --- /dev/null +++ b/client/src/components/analytics-graph/locales/fr.json @@ -0,0 +1,7 @@ +{ + "analytics.graph.fullscreen": "Plein écran", + "analytics.graph.view.table": "Voir les données", + "analytics.graph.export.png": "Exporter en PNG", + "analytics.graph.export.pdf": "Exporter en PDF", + "analytics.graph.download.csv": "Télécharger les données en CSV" +} \ No newline at end of file diff --git a/client/src/components/contact-form/locales/fr.json b/client/src/components/contact-form/locales/fr.json index 39fde7cb..fcc3990c 100644 --- a/client/src/components/contact-form/locales/fr.json +++ b/client/src/components/contact-form/locales/fr.json @@ -6,7 +6,7 @@ "contact.error.retry": "Réessayer", "contact.form.name": "Votre nom et prénom", "contact.form.email": "Renseignez votre email", - "contact.form.email.hint": "Cet email sera utilisé que pour vous informer de la prise en compte de votre contribution.", + "contact.form.email.hint": "Cet email ne sera utilisé que pour vous informer de la prise en compte de votre contribution.", "contact.form.organization": "Votre organisation", "contact.form.fonction": "Votre fonction", "contact.form.position": "Votre fonction", diff --git a/client/src/components/footer/index.tsx b/client/src/components/footer/index.tsx index c5071117..02f2cbce 100644 --- a/client/src/components/footer/index.tsx +++ b/client/src/components/footer/index.tsx @@ -1,8 +1,6 @@ import React from "react"; -import cn from "classnames"; -import { Col, Container, Link, Logo, Row, Title } from "@dataesr/dsfr-plus"; -import { IntlProvider, createIntl } from "react-intl"; -import styles from "./styles.module.scss"; +import { Container, Link, Logo } from "@dataesr/dsfr-plus"; +import { IntlProvider } from "react-intl"; const modules = import.meta.glob("./locales/*.json", { eager: true, @@ -16,8 +14,9 @@ const messages = Object.keys(modules).reduce((acc, key) => { return acc; }, {}); -const locale = "fr"; -const intl = createIntl({ locale, messages: messages[locale] }); +export function FooterTop({ children }: { children?: React.ReactNode }) { + return
{children}
; +} export function Footer({ children, @@ -26,203 +25,9 @@ export function Footer({ children?: React.ReactNode; fluid?: boolean; }) { - const version = import.meta.env?.VITE_VERSION; return (
-
- - - - -
- - {intl.formatMessage({ - id: "layout.footer.top.about.help", - })} - -
    -
  • - - {intl.formatMessage({ - id: "layout.footer.top.about.faq", - })} - -
  • -
  • - - {intl.formatMessage({ - id: "layout.footer.top.about.team", - })} - -
  • -
  • - - {intl.formatMessage({ - id: "layout.footer.top.about.resources", - })} - -
  • - {/*
  • - - {intl.formatMessage({ - id: "layout.footer.top.about.tutorial", - })} - -
  • */} - {/*
  • - - {intl.formatMessage({ - id: "layout.footer.top.about.glossary", - })} - -
  • */} -
  • - - {intl.formatMessage({ - id: "layout.footer.top.about.contact", - })} - -
  • -
-
-
- - - -
- - {intl.formatMessage({ - id: "layout.footer.top.about.follow", - })} - -
    -
  • - - X - -
  • -
  • - - Linkedin - -
  • -
  • - - Facebook - -
  • -
-
-
- - - -
- - {intl.formatMessage({ - id: "layout.footer.top.about.also", - })} - -
    -
  • - - GitHub - {version && ` – v${version}`} - -
  • -
  • - - CurieXplore - -
  • -
  • - - Baromètre de la Science Ouverte - -
  • -
  • - - #dataESR - -
  • -
  • - - Plateforme Open Data - -
  • -
-
-
- -
-
-
{children}
@@ -238,7 +43,7 @@ export function FooterBottom({ }) { const childs = React.Children.toArray(children); return ( -
+
    {childs.map((child, i) => (
  • @@ -270,7 +75,7 @@ export function FooterBody({ )?.[0]; return ( -
    +
    {logo ? (
    {logo}
    ) : null} diff --git a/client/src/components/share/index.tsx b/client/src/components/share/index.tsx index f102995e..ff0a8bc3 100644 --- a/client/src/components/share/index.tsx +++ b/client/src/components/share/index.tsx @@ -1,46 +1,21 @@ -import { Link } from "@dataesr/dsfr-plus"; +import { Link, useDSFRConfig } from "@dataesr/dsfr-plus"; import useConsent from "../../hooks/useConsent"; import useCopyToClipboard from "../../hooks/useCopyToClipboard"; +import { RawIntlProvider, createIntl } from "react-intl"; -const onClickFacebook = (e: { preventDefault: () => void }) => { - e.preventDefault(); - window.open( - "https://www.facebook.com/sharer.php", - "Partager sur Facebook", - "toolbar=no,location=yes,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=450" - ); -}; - -const onClickTwitter = (e: { preventDefault: () => void }) => { - e.preventDefault(); - const currentURL = window.location.href; - const text = "#dataEsr #scanR"; - const twitterShareURL = `https://twitter.com/intent/tweet?url=${encodeURIComponent( - currentURL - )}&text=${encodeURIComponent(text)}`; - - window.open( - twitterShareURL, - "Partager sur Twitter", - "toolbar=no,location=yes,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=420" - ); -}; +const modules = import.meta.glob('./locales/*.json', { eager: true, import: 'default' }) +const messages = Object.keys(modules).reduce((acc, key) => { + const locale = key.match(/\.\/locales\/(.+)\.json$/)?.[1]; + if (locale) { + return { ...acc, [locale]: modules[key] } + } + return acc; +}, {}); -const onClickLinkedin = (e) => { - e.preventDefault(); - const currentURL = encodeURIComponent("www.google.fr"); - const text = "#dataEsr #scanR"; - const linkedinShareURL = `https://www.linkedin.com/sharing/share-offsite/?url=${currentURL}&text=${encodeURIComponent( - text - )}`; - window.open( - linkedinShareURL, - "Partager sur LinkedIn", - "toolbar=no,location=yes,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=420" - ); -}; export default function Share() { + const { locale } = useDSFRConfig(); + const intl = createIntl({ locale, messages: messages[locale] }); const url = window.location.href; const { consent, dialogId } = useConsent(); const { copy } = useCopyToClipboard(); @@ -50,93 +25,137 @@ export default function Share() { url )}`; + const formating = { + authorize: (chunks: any) => ( + + {chunks} + + ), + }; + + const onClickFacebook = (e: { preventDefault: () => void }) => { + e.preventDefault(); + window.open( + "https://www.facebook.com/sharer.php", + intl.formatMessage({ id: "share.facebook" }), + "toolbar=no,location=yes,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=450" + ); + }; + + const onClickTwitter = (e: { preventDefault: () => void }) => { + e.preventDefault(); + const currentURL = window.location.href; + const text = "#dataEsr #scanR"; + const twitterShareURL = `https://twitter.com/intent/tweet?url=${encodeURIComponent( + currentURL + )}&text=${encodeURIComponent(text)}`; + + window.open( + twitterShareURL, + intl.formatMessage({ id: "share.twitter" }), + "toolbar=no,location=yes,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=420" + ); + }; + + const onClickLinkedin = (e) => { + e.preventDefault(); + const currentURL = encodeURIComponent("www.google.fr"); + const text = "#dataEsr #scanR"; + const linkedinShareURL = `https://www.linkedin.com/sharing/share-offsite/?url=${currentURL}&text=${encodeURIComponent( + text + )}`; + window.open( + linkedinShareURL, + intl.formatMessage({ id: "share.linkedin" }), + "toolbar=no,location=yes,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=420" + ); + }; + return ( -
    - {(!twitter || !facebook || !linkedin) && ( -

    - Veuillez{" "} - - autoriser le dépot de cookies - {" "} - pour partager sur Facebook, Twitter et LinkedIn. -

    - )} - -
    + +
    + {(!twitter || !facebook || !linkedin) && ( +

    + {intl.formatMessage({ id: "share.cookies.personalize" }, formating)} +

    + )} + +
    +
    ); } diff --git a/client/src/components/share/locales/en.json b/client/src/components/share/locales/en.json new file mode 100644 index 00000000..32d3ebb2 --- /dev/null +++ b/client/src/components/share/locales/en.json @@ -0,0 +1,10 @@ +{ + "share.facebook": "Share on Facebook", + "share.twitter": "Share on Twitter", + "share.linkedin": "Share on LinkedIn", + "share.email": "Share via email", + "share.copy": "Copy to clipboard", + "share.inactive": "- inactive", + "share.cookies": "Customize cookies", + "share.cookies.personalize": "Please authorize the use of cookies to share on Facebook, Twitter, and LinkedIn." +} \ No newline at end of file diff --git a/client/src/components/share/locales/fr.json b/client/src/components/share/locales/fr.json index e69de29b..11470864 100644 --- a/client/src/components/share/locales/fr.json +++ b/client/src/components/share/locales/fr.json @@ -0,0 +1,10 @@ +{ + "share.facebook": "Partager sur Facebook", + "share.twitter": "Partager sur Twitter", + "share.linkedin": "Partager sur LinkedIn", + "share.email": "Partager par email", + "share.copy": "Copier dans le presse-papier", + "share.inactive": "- désactivé", + "share.cookies": "Personnaliser les cookies", + "share.cookies.personalize": "Veuillez autoriser le dépôt de cookies pour partager sur Facebook, Twitter et LinkedIn." +} \ No newline at end of file diff --git a/client/src/components/switch-theme.tsx b/client/src/components/switch-theme.tsx deleted file mode 100644 index d39c01e6..00000000 --- a/client/src/components/switch-theme.tsx +++ /dev/null @@ -1,77 +0,0 @@ -export default function SwitchTheme() { - return ( - -
    -
    -
    -
    -
    - -
    -
    -

    - Paramètres d’affichage -

    -
    -
    - - Choisissez un thème pour personnaliser l’apparence du site. - -
    -
    - - -
    - -
    -
    -
    -
    -
    - - -
    - -
    -
    -
    -
    -
    - - -
    - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - ) -} \ No newline at end of file diff --git a/client/src/layout/Footer.tsx b/client/src/layout/Footer.tsx deleted file mode 100644 index 99f3bdc9..00000000 --- a/client/src/layout/Footer.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { Link, Logo } from "@dataesr/dsfr-plus"; -import { Footer, FooterBody, FooterBottom } from "../components/footer"; -import { useIntl } from "react-intl"; -import SwitchTheme from "../components/switch-theme"; -import useConsent from "../hooks/useConsent"; - -export default function MainFooter() { - const intl = useIntl(); - const { dialogId } = useConsent(); - return ( -
    - - - - legifrance.gouv.fr - - - gouvernement.fr - - - service-public.fr - - - data.gouv.fr - - - - - {intl.formatMessage({ - id: "layout.footer.legal-notice", - })} - - - {intl.formatMessage({ - id: "layout.footer.personal-data", - })} - - - {intl.formatMessage({ - id: "layout.footer.accessibility", - })} - - - - - -
    - ); -} diff --git a/client/src/layout/consent.tsx b/client/src/layout/components/consent/index.tsx similarity index 73% rename from client/src/layout/consent.tsx rename to client/src/layout/components/consent/index.tsx index 30cdee99..f07ead48 100644 --- a/client/src/layout/consent.tsx +++ b/client/src/layout/components/consent/index.tsx @@ -1,14 +1,31 @@ -import useConsent from "../hooks/useConsent"; +import { RawIntlProvider, createIntl } from "react-intl"; +import useConsent from "../../../hooks/useConsent"; +import { useDSFRConfig } from "@dataesr/dsfr-plus"; + +const modules = import.meta.glob('./locales/*.json', { eager: true, import: 'default' }) +const messages = Object.keys(modules).reduce((acc, key) => { + const locale = key.match(/\.\/locales\/(.+)\.json$/)?.[1]; + if (locale) { + return { ...acc, [locale]: modules[key] } + } + return acc; +}, {}); export default function Consent() { + const { locale } = useDSFRConfig(); + const intl = createIntl({ locale, messages: messages[locale] }); const { dialogId, consent, setConsent, set } = useConsent({ twitter: 0, matomo: 0, youtube: 0, facebook: 0, linkedin: 0 }); return ( - <> + {!set &&
    -

    À propos des cookies sur scanr.enseignementsup-recherche.gouv.fr

    +

    + {intl.formatMessage({ id: "layout.consent.title" })} +

    -

    Bienvenue ! Nous utilisons des cookies pour améliorer votre expérience et les services disponibles sur ce site. Pour en savoir plus, visitez la page Données personnelles et cookies. Vous pouvez, à tout moment, avoir le contrôle sur les cookies que vous souhaitez activer.

    +

    + {intl.formatMessage({ id: "layout.consent.content" })} +

    • @@ -17,7 +34,7 @@ export default function Consent() { title="Autoriser tous les cookies" onClick={() => setConsent({ twitter: 1, matomo: 1, youtube: 1, facebook: 1, linkedin: 1 })} > - Tout accepter + {intl.formatMessage({ id: "layout.consent.accept-all" })}
    • @@ -26,7 +43,7 @@ export default function Consent() { title="Refuser tous les cookies" onClick={() => setConsent({ twitter: 0, matomo: 0, youtube: 0, facebook: 0, linkedin: 0 })} > - Tout refuser + {intl.formatMessage({ id: "layout.consent.refuse-all" })}
    • @@ -36,7 +53,7 @@ export default function Consent() { aria-controls={dialogId} title="Personnaliser les cookies" > - Personnaliser + {intl.formatMessage({ id: "layout.consent.customize" })}
    @@ -49,17 +66,18 @@ export default function Consent() {

    - Panneau de gestion des cookies + {intl.formatMessage({ id: "layout.consent.cookies" })}

    - Préférences pour tous les services. Données personnelles et cookies + + {intl.formatMessage({ id: "layout.consent.cookies.preferences" })}
    @@ -77,7 +95,7 @@ export default function Consent() { }} />
    @@ -95,7 +113,7 @@ export default function Consent() { }} />
    @@ -103,7 +121,9 @@ export default function Consent() {
    - Statistique + + {intl.formatMessage({ id: "layout.consent.cookies.finality.stats" })} +
    { consent.matomo = 1 }} />
    @@ -126,18 +146,20 @@ export default function Consent() { onChange={() => { consent.matomo = 0 }} />

    - Les cookies statistiques aident, par la collecte d'informations anonymisées, à comprendre comment les visiteurs interagissent avec scanR. + {intl.formatMessage({ id: "layout.consent.cookies.finality.stats.desc" })}

    - Partage + + {intl.formatMessage({ id: "layout.consent.cookies.finality.share" })} +
    @@ -169,20 +191,57 @@ export default function Consent() { }} />

    - Afin de pouvoir partager les pages de scanR, il est nécessaire d'accepter les cookies de partage des réseaux sociaux. + {intl.formatMessage({ id: "layout.consent.cookies.finality.share.desc" })}

    - +
    - Facebook + + Youtube + +
    +
    + { consent.youtube = 1 }} + /> + +
    +
    + { consent.youtube = 0 }} + /> + +
    +
    +
    +
    +
    +
    + + Facebook +
    { consent.facebook = 1 }} />
    @@ -205,7 +264,7 @@ export default function Consent() { onChange={() => { consent.facebook = 0 }} />
    @@ -226,7 +285,7 @@ export default function Consent() { onChange={() => { consent.twitter = 1 }} />
    @@ -238,7 +297,7 @@ export default function Consent() { onChange={() => { consent.twitter = 0 }} />
    @@ -258,7 +317,7 @@ export default function Consent() { onChange={() => { consent.linkedin = 1 }} />
    @@ -270,7 +329,7 @@ export default function Consent() { onChange={() => { consent.linkedin = 0 }} />
    @@ -301,6 +360,6 @@ export default function Consent() {
    - + ) } \ No newline at end of file diff --git a/client/src/layout/components/consent/locales/en.json b/client/src/layout/components/consent/locales/en.json new file mode 100644 index 00000000..9f8ed995 --- /dev/null +++ b/client/src/layout/components/consent/locales/en.json @@ -0,0 +1,19 @@ +{ + "layout.consent.title": "About cookies on scanr.enseignementsup-recherche.gouv.fr", + "layout.consent.content": "Welcome! We use cookies to enhance your experience and the services available on this site. You can have control over the cookies you wish to enable at any time.", + "layout.consent.accept-all": "Accept All", + "layout.consent.refuse-all": "Refuse All", + "layout.consent.customize": "Customize", + "layout.consent.confirm": "Confirm My Choices", + "layout.consent.cookies.close": "Close", + "layout.consent.cookies": "Cookie Management Panel", + "layout.consent.cookies.preferences": "Preferences for all services.", + "layout.consent.cookies.all.desc": "To learn more, visit the Personal Data and Cookies page.", + "layout.consent.cookies.finality.stats": "Statistics", + "layout.consent.cookies.finality.stats.desc": "Statistical cookies help understand how visitors interact with scanR by collecting anonymized information.", + "layout.consent.cookies.finality.share": "Sharing", + "layout.consent.cookies.finality.share.desc": "To be able to share scanR pages, it is necessary to accept social media sharing cookies.", + "layout.consent.cookies.accept": "Accept", + "layout.consent.cookies.refuse": "Refuse", + "layout.consent.cookies.finality.toggle": "See more details" +} \ No newline at end of file diff --git a/client/src/layout/components/consent/locales/fr.json b/client/src/layout/components/consent/locales/fr.json new file mode 100644 index 00000000..c28ec566 --- /dev/null +++ b/client/src/layout/components/consent/locales/fr.json @@ -0,0 +1,19 @@ +{ + "layout.consent.title": "À propos des cookies sur scanr.enseignementsup-recherche.gouv.fr", + "layout.consent.content": "Bienvenue ! Nous utilisons des cookies pour améliorer votre expérience et les services disponibles sur ce site. Vous pouvez, à tout moment, avoir le contrôle sur les cookies que vous souhaitez activer.", + "layout.consent.accept-all": "Tout accepter", + "layout.consent.refuse-all": "Tout refuser", + "layout.consent.customize": "Personnaliser", + "layout.consent.confirm": "Confirmer mes choix", + "layout.consent.cookies.close": "Fermer", + "layout.consent.cookies": "Panneau de gestion des cookies", + "layout.consent.cookies.preferences": "Préférences pour tous les services.", + "layout.consent.cookies.all.desc": "Pour en savoir plus, visitez la page Données personnelles et cookies.", + "layout.consent.cookies.finality.stats": "Statistique", + "layout.consent.cookies.finality.stats.desc": "Les cookies statistiques aident, par la collecte d'informations anonymisées, à comprendre comment les visiteurs interagissent avec scanR.", + "layout.consent.cookies.finality.share": "Partage", + "layout.consent.cookies.finality.share.desc": "Afin de pouvoir partager les pages de scanR, il est nécessaire d'accepter les cookies de partage des réseaux sociaux.", + "layout.consent.cookies.accept": "Accepter", + "layout.consent.cookies.refuse": "Refuser", + "layout.consent.cookies.finality.toggle": "Voir plus de détails" +} \ No newline at end of file diff --git a/client/src/layout/components/footer/index.tsx b/client/src/layout/components/footer/index.tsx new file mode 100644 index 00000000..8758a1e3 --- /dev/null +++ b/client/src/layout/components/footer/index.tsx @@ -0,0 +1,318 @@ +import cn from "classnames"; +import { + Col, + Container, + Link, + Logo, + Row, + Title, + useDSFRConfig, +} from "@dataesr/dsfr-plus"; +import { + Footer, + FooterBody, + FooterBottom, + FooterTop, +} from "../../../components/footer"; +import { RawIntlProvider, createIntl } from "react-intl"; +import SwitchTheme from "../switch-theme"; +import useConsent from "../../../hooks/useConsent"; +import { version } from "react"; +import styles from "./styles.module.scss"; + +const modules = import.meta.glob("./locales/*.json", { + eager: true, + import: "default", +}); +const messages = Object.keys(modules).reduce((acc, key) => { + const locale = key.match(/\.\/locales\/(.+)\.json$/)?.[1]; + if (locale) { + return { ...acc, [locale]: modules[key] }; + } + return acc; +}, {}); + +export default function MainFooter() { + const { locale } = useDSFRConfig(); + const intl = createIntl({ locale, messages: messages[locale] }); + const { dialogId } = useConsent(); + return ( + +
    + + + + + +
    + + {intl.formatMessage({ + id: "layout.footer.top.about.help", + })} + +
      +
    • + + {intl.formatMessage({ + id: "layout.footer.top.about.faq", + })} + +
    • +
    • + + {intl.formatMessage({ + id: "layout.footer.top.about.team", + })} + +
    • +
    • + + {intl.formatMessage({ + id: "layout.footer.top.about.resources", + })} + +
    • + {/*
    • + + {intl.formatMessage({ + id: "layout.footer.top.about.tutorial", + })} + +
    • */} + {/*
    • + + {intl.formatMessage({ + id: "layout.footer.top.about.glossary", + })} + +
    • */} +
    • + + {intl.formatMessage({ + id: "layout.footer.top.about.contact", + })} + +
    • +
    +
    +
    + + + +
    + + {intl.formatMessage({ + id: "layout.footer.top.about.follow", + })} + +
      +
    • + + X + +
    • +
    • + + Linkedin + +
    • +
    • + + Facebook + +
    • +
    +
    +
    + + + +
    + + {intl.formatMessage({ + id: "layout.footer.top.about.also", + })} + +
      +
    • + + GitHub + {version && ` – v${version}`} + +
    • +
    • + + CurieXplore + +
    • +
    • + + Baromètre de la Science Ouverte + +
    • +
    • + + #dataESR + +
    • +
    • + + Plateforme Open Data + +
    • +
    +
    +
    + +
    +
    +
    + + + + legifrance.gouv.fr + + + gouvernement.fr + + + service-public.fr + + + data.gouv.fr + + + + {/* + {intl.formatMessage({ + id: "layout.footer.legal-notice", + })} + + + {intl.formatMessage({ + id: "layout.footer.personal-data", + })} + + + {intl.formatMessage({ + id: "layout.footer.accessibility", + })} + */} + + + + +
    +
    + ); +} diff --git a/client/src/layout/components/footer/locales/en.json b/client/src/layout/components/footer/locales/en.json new file mode 100644 index 00000000..3ed1c1fd --- /dev/null +++ b/client/src/layout/components/footer/locales/en.json @@ -0,0 +1,18 @@ +{ + "layout.footer.top.about": "About", + "layout.footer.top.about.faq": "FAQ", + "layout.footer.top.about.team": "Team", + "layout.footer.top.about.help": "Help", + "layout.footer.top.about.also": "See also", + "layout.footer.top.about.follow": "Follow us", + "layout.footer.top.about.resources": "Data sources", + "layout.footer.top.about.tutorial": "Tutorial", + "layout.footer.top.about.glossary": "Glossary", + "layout.footer.top.about.contact": "Contact", + "layout.footer.tagline": "Explore the world of French Research and Innovation with scanR", + "layout.footer.legal-notice": "Legal Notice", + "layout.footer.personal-data": "Personal Data", + "layout.footer.cookies": "Cookies", + "layout.footer.accessibility": "Accessibility", + "layout.footer.switch-theme": "Theme" +} \ No newline at end of file diff --git a/client/src/layout/components/footer/locales/fr.json b/client/src/layout/components/footer/locales/fr.json new file mode 100644 index 00000000..87f24d5b --- /dev/null +++ b/client/src/layout/components/footer/locales/fr.json @@ -0,0 +1,18 @@ +{ + "layout.footer.top.about": "A propos", + "layout.footer.top.about.faq": "FAQ", + "layout.footer.top.about.team": "L'équipe", + "layout.footer.top.about.help": "Aide", + "layout.footer.top.about.also": "Voir aussi", + "layout.footer.top.about.follow": "Nous suivre", + "layout.footer.top.about.resources": "Sources de données", + "layout.footer.top.about.tutorial": "Tutoriel", + "layout.footer.top.about.glossary": "Glossaire", + "layout.footer.top.about.contact": "Contact", + "layout.footer.tagline": "Explorez le monde de la Recherche et de l'Innovation françaises", + "layout.footer.legal-notice": "Mentions légales", + "layout.footer.personal-data": "Données personnelles", + "layout.footer.cookies": "Cookies", + "layout.footer.accessibility": "Accessibilité", + "layout.footer.switch-theme": "Thème" +} \ No newline at end of file diff --git a/client/src/layout/components/footer/styles.module.scss b/client/src/layout/components/footer/styles.module.scss new file mode 100644 index 00000000..0f01013c --- /dev/null +++ b/client/src/layout/components/footer/styles.module.scss @@ -0,0 +1,11 @@ +.text-right { + text-align: right; +} + +.text-left { + text-align: left; +} + +.text-center { + text-align: center; +} \ No newline at end of file diff --git a/client/src/layout/Header.tsx b/client/src/layout/components/header/index.tsx similarity index 75% rename from client/src/layout/Header.tsx rename to client/src/layout/components/header/index.tsx index 44f29e57..d0aaca02 100644 --- a/client/src/layout/Header.tsx +++ b/client/src/layout/components/header/index.tsx @@ -9,17 +9,28 @@ import { Nav, FastAccess, Button, + useDSFRConfig, // Autocomplete, // AutocompleteItem, // useAutocompleteList, // useDSFRConfig, } from '@dataesr/dsfr-plus'; -import { FormattedMessage, useIntl } from 'react-intl'; -import SwitchLanguage from '../components/switch-language'; +import { createIntl } from 'react-intl'; +import SwitchLanguage from '../../../components/switch-language'; // import { autocompleteOrganizations } from '../api/organizations/autocomplete'; // import { LightOrganization } from '../types/organization'; // import getLangFieldValue from '../utils/lang'; +const modules = import.meta.glob('./locales/*.json', { eager: true, import: 'default' }) +const messages = Object.keys(modules).reduce((acc, key) => { + const locale = key.match(/\.\/locales\/(.+)\.json$/)?.[1]; + if (locale) { + return { ...acc, [locale]: modules[key] } + } + return acc; +}, {}); + + const languages = [ { shortName: 'FR', fullName: 'Français', key: 'fr' }, { shortName: 'EN', fullName: 'English', key: 'en' }, @@ -29,9 +40,9 @@ const languages = [ ]; export default function Header() { - // const { locale } = useDSFRConfig(); + const { locale } = useDSFRConfig(); + const intl = createIntl({ locale, messages: messages[locale] }); const { pathname } = useLocation(); - const intl = useIntl(); // const authorsAutocompletedList = useAutocompleteList({ // async load({ filterText }) { @@ -49,7 +60,7 @@ export default function Header() { @@ -77,25 +88,27 @@ export default function Header() { )} */}
    {logoUrl && (
    @@ -220,9 +224,13 @@ export default function ProjectPresentation({ data }: { data: Project }) { - + {accomplishment && (
    + + + software.wikidata) + .filter((wikidata) => !!wikidata) + .map((wikidata) => ({ code: wikidata })); + + const { data: wikis } = useQuery({ + queryKey: ["wikidatas", codes.map(c => c.code), locale], + queryFn: () => getWikidataPreviews(codes, locale), + enabled: !!codes?.length, + }); + + const getSoftwareContexts = (softwareName: string, contexts?: string[]) => { + if (!contexts.length) return null; + const newContexts = contexts.map((context) => { + const regexp = new RegExp(softwareName, "ig") + const newContext = context.replace(regexp, `${softwareName}`); + return newContext; + }); + const stringContexts = newContexts.reduce((acc, cur) => { + if (acc.length === 0) return cur; + if (acc.length > 300) return acc; + return `${acc} ... ${cur}`; + }, ""); + + return + } + + const _softwares = softwares.map((software) => { + const wiki = wikis?.find((w) => w.code === software.wikidata); + return { ...software, wiki }; + }) + + + if (!softwares.length) return null; + return ( + + + {_softwares.map((software) => ( +
    + + {software.softwareName} + {software?.wiki?.code && } + + {software?.wiki?.code && ( + + + + )} + {!!software?.contexts?.length && ( + + {getSoftwareContexts(software.softwareName, software.contexts)} + + )} +
    + ))} + +
    + ); +} \ No newline at end of file diff --git a/client/src/pages/publications/[id]/locales/de.json b/client/src/pages/publications/[id]/locales/de.json new file mode 100644 index 00000000..2f9d78f5 --- /dev/null +++ b/client/src/pages/publications/[id]/locales/de.json @@ -0,0 +1,39 @@ +{ + "publications.breadcrumb.home": "Startseite", + "publications.breadcrumb.search": "Veröffentlichungen", + "publications.section.author": "Thesis-Autor", + "publications.section.affiliations": "Autoren-Affiliationen", + "publications.section.affiliations.map": "Affiliationen auf einer Karte anzeigen", + "publications.section.affiliations.map-title": "Karte der Autoren-Affiliationen", + "publications.section.fundings": "Finanzierungen", + "publications.section.more-like-this": "Ähnliche Veröffentlichungen", + "publications.section.access": "Zugriff auf Veröffentlichung", + "publications.section.access.download": "Veröffentlichung herunterladen", + "publications.section.access.visit": "Auf der Website des Verlags anzeigen", + "publications.section.access.download-thesis": "Thesis herunterladen", + "publications.section.access.visit-thesis": "Auf theses.fr anzeigen", + "publications.section.identifiers": "Veröffentlichungs-Identifikatoren", + "publications.section.identifiers-description": "Zum Kopieren klicken", + "publications.section.wikis": "Wikipedia-Konzepte", + "publications.section.share": "Seite teilen", + "publications.section.contribute": "Beitragen", + "publications.section.jury": "Zusammensetzung der Jury", + "publications.section.jury.directeurthese": "Thesis-Betreuer", + "publications.section.jury.presidentjury": "Jury-Präsident", + "publications.section.jury.rapporteur": "Rapporteur", + "publications.section.jury.membrejury": "Jury-Mitglied", + "publications.header.thesis.by": "von ", + "publications.header.thesis.and": " und ", + "publications.header.thesis.directed": " unter der Betreuung von ", + "publications.header.thesis.date": "verteidigt am {date}", + "publications.header.thesis.year": "verteidigt im Jahr {year}", + "publications.header.summary": "Zusammenfassung", + "publications.header.no-summary": "Keine Zusammenfassung verfügbar", + "publications.header.oa.true": "Open Access", + "publications.header.oa.false": "Geschlossener Zugriff", + "publications.signals.author": "Einen Autor identifizieren", + "publications.signals.fundings": "Finanzierung hinzufügen", + "publications.signals.bug": "Einen Fehler melden", + "publications.section.softwares.title": "Softwareerwähnungen", + "publications.section.softwares.legend": "Softwareerwähnungen, die von scanR in der Veröffentlichung gefunden wurden." +} \ No newline at end of file diff --git a/client/src/pages/publications/[id]/locales/en.json b/client/src/pages/publications/[id]/locales/en.json new file mode 100644 index 00000000..e2ef5f9c --- /dev/null +++ b/client/src/pages/publications/[id]/locales/en.json @@ -0,0 +1,39 @@ +{ + "publications.breadcrumb.home": "Home", + "publications.breadcrumb.search": "Publications", + "publications.section.author": "Thesis author", + "publications.section.affiliations": "Author's affiliations", + "publications.section.affiliations.map": "Show affiliations on a map", + "publications.section.affiliations.map-title": "Map of author affiliations", + "publications.section.fundings": "Fundings", + "publications.section.more-like-this": "Similar publications", + "publications.section.access": "Access publication", + "publications.section.access.download": "Download publication", + "publications.section.access.visit": "View on publisher's website", + "publications.section.access.download-thesis": "Download thesis", + "publications.section.access.visit-thesis": "View on theses.fr", + "publications.section.identifiers": "Publication identifiers", + "publications.section.identifiers-description": "Click to copy to clipboard", + "publications.section.wikis": "Wikipedia concepts", + "publications.section.share": "Share", + "publications.section.contribute": "Contribute", + "publications.section.jury": "Jury composition", + "publications.section.jury.directeurthese": "Thesis supervisor", + "publications.section.jury.presidentjury": "Jury president", + "publications.section.jury.rapporteur": "Rapporteur", + "publications.section.jury.membrejury": "Jury member", + "publications.header.thesis.by": "by ", + "publications.header.thesis.and": " and ", + "publications.header.thesis.directed": " under the supervision of ", + "publications.header.thesis.date": "defended on {date}", + "publications.header.thesis.year": "defended in {year}", + "publications.header.summary": "Summary", + "publications.header.no-summary": "No summary available", + "publications.header.oa.true": "Open access", + "publications.header.oa.false": "Closed access", + "publications.signals.author": "Identify an author", + "publications.signals.fundings": "Add funding", + "publications.signals.bug": "Report an error", + "publications.section.softwares.title": "Software Mentions", + "publications.section.softwares.legend": "Software mentions found by scanR in the publication." +} \ No newline at end of file diff --git a/client/src/pages/publications/[id]/locales/es.json b/client/src/pages/publications/[id]/locales/es.json new file mode 100644 index 00000000..03bf514a --- /dev/null +++ b/client/src/pages/publications/[id]/locales/es.json @@ -0,0 +1,39 @@ +{ + "publications.breadcrumb.home": "Inicio", + "publications.breadcrumb.search": "Publicaciones", + "publications.section.author": "Autor de la Tesis", + "publications.section.affiliations": "Afiliaciones del Autor", + "publications.section.affiliations.map": "Mostrar afiliaciones en un mapa", + "publications.section.affiliations.map-title": "Mapa de afiliaciones del autor", + "publications.section.fundings": "Financiamientos", + "publications.section.more-like-this": "Publicaciones Similares", + "publications.section.access": "Acceso a la Publicación", + "publications.section.access.download": "Descargar Publicación", + "publications.section.access.visit": "Ver en el Sitio del Editor", + "publications.section.access.download-thesis": "Descargar Tesis", + "publications.section.access.visit-thesis": "Ver en theses.fr", + "publications.section.identifiers": "Identificadores de la Publicación", + "publications.section.identifiers-description": "Haz clic para copiar al portapapeles", + "publications.section.wikis": "Conceptos de Wikipedia", + "publications.section.share": "Compartir Página", + "publications.section.contribute": "Contribuir", + "publications.section.jury": "Composición del Jurado", + "publications.section.jury.directeurthese": "Supervisor de la Tesis", + "publications.section.jury.presidentjury": "Presidente del Jurado", + "publications.section.jury.rapporteur": "Rapporteur", + "publications.section.jury.membrejury": "Miembro del Jurado", + "publications.header.thesis.by": "por ", + "publications.header.thesis.and": " y ", + "publications.header.thesis.directed": " bajo la supervisión de ", + "publications.header.thesis.date": "defendida el {date}", + "publications.header.thesis.year": "defendida en {year}", + "publications.header.summary": "Resumen", + "publications.header.no-summary": "No hay resumen disponible", + "publications.header.oa.true": "Acceso Abierto", + "publications.header.oa.false": "Acceso Restringido", + "publications.signals.author": "Identificar un autor", + "publications.signals.fundings": "Agregar financiamiento", + "publications.signals.bug": "Reportar un error", + "publications.section.softwares.title": "Menciones de Software", + "publications.section.softwares.legend": "Menciones de software encontradas por scanR en la publicación." +} \ No newline at end of file diff --git a/client/src/pages/publications/[id]/locales/fr.json b/client/src/pages/publications/[id]/locales/fr.json index 4afeb754..ad8ce030 100644 --- a/client/src/pages/publications/[id]/locales/fr.json +++ b/client/src/pages/publications/[id]/locales/fr.json @@ -24,6 +24,9 @@ "publications.section.jury.membrejury": "Membre du jury", "publications.header.thesis.by": "par ", "publications.header.thesis.and": " et ", + "search.publications.openAccess": "Accès ouvert", + "search.publications.closedAccess": "Accès fermé", + "search.publications.other": "Autre", "publications.header.thesis.directed": " sous la direction de ", "publications.header.thesis.date": "soutenue le {date}", "publications.header.thesis.year": "soutenue en {year}", @@ -33,5 +36,7 @@ "publications.header.oa.false": "Accès fermé", "publications.signals.author": "Identifier un auteur", "publications.signals.fundings": "Ajouter un financement", - "publications.signals.bug": "Signaler une erreur" + "publications.signals.bug": "Signaler une erreur", + "publications.section.softwares.title": "Mentions de logiciels", + "publications.section.softwares.legend": "Les mentions de logiciels retrouvées par scanR dans la publication." } \ No newline at end of file diff --git a/client/src/pages/search/components/authors/author-item.tsx b/client/src/pages/search/components/authors/author-item.tsx index 71388f5b..dea22553 100644 --- a/client/src/pages/search/components/authors/author-item.tsx +++ b/client/src/pages/search/components/authors/author-item.tsx @@ -6,48 +6,63 @@ import { LightAuthor } from "../../../../types/author"; import { getAuthorById } from "../../../../api/authors/[id]"; import { ItemProps } from "../../types"; import CopyBadge from "../../../../components/copy/copy-badge"; +import { useIntl } from "react-intl"; +export default function AuthorItem({ + data: author, + highlight, +}: ItemProps) { + const intl = useIntl(); -export default function AuthorItem({ data: author, highlight }: ItemProps) { const queryClient = useQueryClient(); function prefetchAuthor(id: string) { queryClient.prefetchQuery({ - queryKey: ['author', id], + queryKey: ["author", id], queryFn: () => getAuthorById(id), - }) + }); } return (
    - Auteur + + {intl.formatMessage({ id: "search.section.author.badge" })} + - prefetchAuthor(author.id)}> - {author.fullName} - + prefetchAuthor(author.id)}> + + {author.fullName} + {author?.domains - ?.filter((domain) => (domain.type === "wikidata")) + ?.filter((domain) => domain.type === "wikidata") ?.slice(0, 8) .map((domain, k) => ( - {(k > 0) ? ', ' : ''} - #{domain?.label.default} + {k > 0 ? ", " : ""} + + #{domain?.label.default} + - ) - )} + ))}
    {[ { id: author.id.replace("idref", ""), type: "idref" }, - { id: author.orcid, type: 'orcid' }, - { id: author.id_hal, type: 'idhal' }] + { id: author.orcid, type: "orcid" }, + { id: author.id_hal, type: "idhal" }, + ] .filter((identifier) => identifier.id) - .map(({ id, type }) => {type} : {id}) - } + .map(({ id, type }) => ( + + {type} : {id} + + ))}
    {Object.values(highlight || {}).map((value, i) => ( @@ -56,5 +71,5 @@ export default function AuthorItem({ data: author, highlight }: ItemProps - ) -} \ No newline at end of file + ); +} diff --git a/client/src/pages/search/components/authors/filters/awards.tsx b/client/src/pages/search/components/authors/filters/awards.tsx index e7d047ab..28576fe5 100644 --- a/client/src/pages/search/components/authors/filters/awards.tsx +++ b/client/src/pages/search/components/authors/filters/awards.tsx @@ -48,6 +48,7 @@ export default function AuthorAwardsFilter() { />
    setSearchInput(e.target.value)} placeholder={intl.formatMessage({ id: "search.filters.search-tags" })} diff --git a/client/src/pages/search/components/commons/current-filters.tsx b/client/src/pages/search/components/commons/current-filters.tsx index c6cbf604..51074c35 100644 --- a/client/src/pages/search/components/commons/current-filters.tsx +++ b/client/src/pages/search/components/commons/current-filters.tsx @@ -28,7 +28,7 @@ export default function CurrentFilters() {
    - Filtres + {intl.formatMessage({ id: "search.filters.current.title" })}
    {Object.keys(currentFilters)?.length ? ( diff --git a/client/src/pages/search/components/organizations/filters/localisation.tsx b/client/src/pages/search/components/organizations/filters/localisation.tsx index a8514914..74715520 100644 --- a/client/src/pages/search/components/organizations/filters/localisation.tsx +++ b/client/src/pages/search/components/organizations/filters/localisation.tsx @@ -1,25 +1,36 @@ -import { Autocomplete, AutocompleteItem, DissmissibleTag, TagGroup, Text, useAutocompleteList } from "@dataesr/dsfr-plus"; +import { + Autocomplete, + AutocompleteItem, + DissmissibleTag, + TagGroup, + Text, + useAutocompleteList, +} from "@dataesr/dsfr-plus"; import { FormattedMessage } from "react-intl"; import useUrl from "../../../hooks/useUrl"; -import { LocalisationAutocomplete, autocompleteLocalisations } from "../../../../../api/localisations"; +import { + LocalisationAutocomplete, + autocompleteLocalisations, +} from "../../../../../api/localisations"; import OperatorButton from "../../../../../components/operator-button"; export default function OrganizationLocalisationsFilter() { - const { currentFilters, handleFilterChange, setOperator } = useUrl() + const { currentFilters, handleFilterChange, setOperator } = useUrl(); - const localisationAutocompletedList = useAutocompleteList({ - async load({ filterText }) { - if (!filterText) { - return { items: [] }; - } - const res = await autocompleteLocalisations({ query: filterText }) + const localisationAutocompletedList = + useAutocompleteList({ + async load({ filterText }) { + if (!filterText) { + return { items: [] }; + } + const res = await autocompleteLocalisations({ query: filterText }); - return { items: res.data?.map((org) => org._source) }; - } - }); + return { items: res.data?.map((org) => org._source) }; + }, + }); - const filter = currentFilters?.['address.localisationSuggestions'] - const operator = filter?.operator || 'or' + const filter = currentFilters?.["address.localisationSuggestions"]; + const operator = filter?.operator || "or"; return ( <> @@ -32,11 +43,21 @@ export default function OrganizationLocalisationsFilter() {
    - setOperator('address.localisationSuggestions', (key === 'and') ? 'and' : 'or')} /> + + setOperator( + "address.localisationSuggestions", + key === "and" ? "and" : "or" + ) + } + />
    - {filter ? ( - Sélectionnées: - ) : null} + {filter ? ( + + Sélectionnées: + + ) : null} {filter?.values?.map(({ value, label }) => ( { e.preventDefault(); - handleFilterChange({ field: 'address.localisationSuggestions', value }) + handleFilterChange({ + field: "address.localisationSuggestions", + value, + }); }} > {label || value} @@ -58,12 +82,15 @@ export default function OrganizationLocalisationsFilter() { inputValue={localisationAutocompletedList.filterText} onInputChange={localisationAutocompletedList.setFilterText} loadingState={localisationAutocompletedList.loadingState} - placeholder="Ex: Ile de france, Bas-Rhin, Lyon..." + placeholder="Ex: Ile de France, Bas-Rhin, Lyon..." // menuTrigger="focus" size="md" onSelectionChange={(item) => { if (!item) return; - handleFilterChange({ field: 'address.localisationSuggestions', value: item }) + handleFilterChange({ + field: "address.localisationSuggestions", + value: item, + }); }} > {({ autocompleted }) => ( @@ -73,5 +100,5 @@ export default function OrganizationLocalisationsFilter() { )} - ) -} \ No newline at end of file + ); +} diff --git a/client/src/pages/search/components/projects/project-item.tsx b/client/src/pages/search/components/projects/project-item/index.tsx similarity index 71% rename from client/src/pages/search/components/projects/project-item.tsx rename to client/src/pages/search/components/projects/project-item/index.tsx index 777df0dd..38e37374 100644 --- a/client/src/pages/search/components/projects/project-item.tsx +++ b/client/src/pages/search/components/projects/project-item/index.tsx @@ -7,10 +7,23 @@ import { Badge, useDSFRConfig, } from "@dataesr/dsfr-plus"; -import { ItemProps } from "../../types"; -import { LightProject } from "../../../../types/project"; -import { getProjectById } from "../../../../api/projects/[id]"; -import getLangFieldValue from "../../../../utils/lang"; +import { ItemProps } from "../../../types"; +import { LightProject } from "../../../../../types/project"; +import { getProjectById } from "../../../../../api/projects/[id]"; +import getLangFieldValue from "../../../../../utils/lang"; +import { RawIntlProvider, createIntl } from "react-intl"; + +const modules = import.meta.glob("./locales/*.json", { + eager: true, + import: "default", +}); +const messages = Object.keys(modules).reduce((acc, key) => { + const locale = key.match(/\.\/locales\/(.+)\.json$/)?.[1]; + if (locale) { + return { ...acc, [locale]: modules[key] }; + } + return acc; +}, {}); export default function ProjectItem({ data: project, @@ -18,6 +31,7 @@ export default function ProjectItem({ }: ItemProps) { const queryClient = useQueryClient(); const { locale } = useDSFRConfig(); + const intl = createIntl({ locale, messages: messages[locale] }); function prefetchAuthor(id: string) { queryClient.prefetchQuery({ @@ -37,7 +51,7 @@ export default function ProjectItem({ : project?.participants; return ( - +
    @@ -52,8 +66,10 @@ export default function ProjectItem({ - {shouldFilterParticipants && - `${project.participants?.length} participants dont ${frenchParticipants?.length} français`} + {shouldFilterParticipants && intl.formatMessage( + { id: "project.item.participants.filtered" }, + { total: project.participants?.length, french: frenchParticipants?.length } + )} {shouldFilterParticipants &&
    } {participants?.map((p, k) => ( @@ -75,6 +91,6 @@ export default function ProjectItem({
    ))}
    -
    + ); } diff --git a/client/src/pages/search/components/projects/project-item/locales/en.json b/client/src/pages/search/components/projects/project-item/locales/en.json new file mode 100644 index 00000000..e27cfae7 --- /dev/null +++ b/client/src/pages/search/components/projects/project-item/locales/en.json @@ -0,0 +1,3 @@ +{ + "project.item.participants.filtered": "{total} participants, {french} french" +} \ No newline at end of file diff --git a/client/src/pages/search/components/projects/project-item/locales/fr.json b/client/src/pages/search/components/projects/project-item/locales/fr.json new file mode 100644 index 00000000..3d4be0b2 --- /dev/null +++ b/client/src/pages/search/components/projects/project-item/locales/fr.json @@ -0,0 +1,3 @@ +{ + "project.item.participants.filtered": "{total} participants dont ${french} français" +} \ No newline at end of file diff --git a/client/src/pages/search/components/publications/publication-item.tsx b/client/src/pages/search/components/publications/publication-item.tsx index 4ee27d2a..9aa42cb7 100644 --- a/client/src/pages/search/components/publications/publication-item.tsx +++ b/client/src/pages/search/components/publications/publication-item.tsx @@ -5,50 +5,87 @@ import { publicationTypeMapping, encode } from "../../../../utils/string"; import { getPublicationById } from "../../../../api/publications/[id]"; import { LightPublication } from "../../../../types/publication"; import { ItemProps } from "../../types"; +import { useIntl } from "react-intl"; - -export default function PublicationItem({ data: publication, highlight }: ItemProps) { +export default function PublicationItem({ + data: publication, + highlight, +}: ItemProps) { const queryClient = useQueryClient(); + const intl = useIntl(); function prefetch(id: string) { if (!id) return; queryClient.prefetchQuery({ - queryKey: ['publication', id], + queryKey: ["publication", id], queryFn: () => getPublicationById(id), - }) + }); } + return ( -
    +
    - {publicationTypeMapping[publication.type] || "Autre"} - - {publication.isOa ? 'Accès ouvert' : 'Accès fermé'} + + {publicationTypeMapping[publication.type] || + intl.formatMessage({ id: "search.publications.other" })} + + + {publication.isOa + ? intl.formatMessage({ id: "search.publications.openAccess" }) + : intl.formatMessage({ id: "search.publications.closedAccess" })} - prefetch(publication.id)}> - {highlight?.["title.default"] - ? () - : publication.title.default || publication.title?.fr || publication.title?.en} - + prefetch(publication.id)}> + + {highlight?.["title.default"] ? ( + + ) : ( + publication.title.default || + publication.title?.fr || + publication.title?.en + )} + - {publication?.authors?.slice(0, 5).map((author, k) => ( - - {(k > 0) ? ', ' : ''} - {(author?.person) ? {author.fullName} : author.fullName} + {publication?.authors?.slice(0, 5).map((author, index) => ( + + {index > 0 && ", "} + {author.person ? ( + + {author.fullName} + + ) : ( + author.fullName + )} ))} - {publication?.authors?.length > 5 && {' '}et al.} + {publication?.authors?.length > 5 && ( + + et al. + + )} - {publication?.source?.title && `${publication?.source?.title}`} - {publication?.source?.volume && `, ${publication.source?.volume}`} - {publication?.source?.issue && ` (${publication.source?.issue})`} - {(publication?.year && publication?.source?.title) && ", "} - {publication?.year && `${publication.year}`} - {publication?.source?.publisher && `, ${publication?.source?.publisher}`} + {publication.source?.title && `${publication.source?.title}`} + {publication.source?.volume && `, ${publication.source?.volume}`} + {publication.source?.issue && ` (${publication.source?.issue})`} + {publication.year && publication.source?.title && ", "} + {publication.year && `${publication.year}`} + {publication.source?.publisher && + `, ${publication.source?.publisher}`} {Object.values(highlight || {}).map((value, i) => ( @@ -58,5 +95,5 @@ export default function PublicationItem({ data: publication, highlight }: ItemPr ))}
    - ) -} \ No newline at end of file + ); +} diff --git a/client/src/pages/search/he.tsx b/client/src/pages/search/he.tsx index 2e61639e..f07869cf 100644 --- a/client/src/pages/search/he.tsx +++ b/client/src/pages/search/he.tsx @@ -129,10 +129,10 @@ export default function HEPartners() { - + - + {heData?.title} diff --git a/client/src/pages/search/index.tsx b/client/src/pages/search/index.tsx index 1ef9f696..c9e23915 100644 --- a/client/src/pages/search/index.tsx +++ b/client/src/pages/search/index.tsx @@ -168,7 +168,11 @@ export default function Search() { {intl.formatMessage( { id: `search.top.${api}.result` }, - { count: total, query: currentQuery } + { count: total } + )} + {currentQuery && intl.formatMessage( + { id: "search.top.result-for-query" }, + { query: currentQuery } )} ) : isFetchingNextPage ? ( @@ -179,12 +183,12 @@ export default function Search() {
    {data?.length ? data.map(({ _source: data, highlight }) => ( - - )) + + )) : null}
    diff --git a/client/src/pages/search/locales/de.json b/client/src/pages/search/locales/de.json index 7e6cdba4..e8b32006 100644 --- a/client/src/pages/search/locales/de.json +++ b/client/src/pages/search/locales/de.json @@ -1,11 +1,13 @@ { "search.top.breadcrumb.home": "Startseite", + "search.top.breadcrumb.find-partners": "Partner finden", "search.top.breadcrumb.publications": "Suche nach Veröffentlichungen", "search.top.breadcrumb.authors": "Suche nach Autoren", "search.top.breadcrumb.projects": "Suche nach Finanzierung", "search.top.breadcrumb.patents": "Suche nach Patenten", "search.top.breadcrumb.organizations": "Suche nach Organisationen", "search.top.main-search-bar": "Suche", + "search.section.author.badge": "Autor", "search.top.patent.family.badge": "Patentfamilie", "search.top.filters-button-label": "Filter hinzufügen", "search.top.filters.clear": "Filter löschen", @@ -18,11 +20,12 @@ "search.filters.publications.active-filter-title": "Aktive Filter", "search.filters.publications.active-filter-empty": "Keine aktiven Filter", "search.top.result-more-than": "Mehr als ", - "search.top.publications.result": "{count, plural, =0 {# Veröffentlichung} one {# Veröffentlichung} other {# Veröffentlichungen}} für Suchbegriff « {query} »", - "search.top.authors.result": "{count, plural, =0 {# Autor} one {# Autor} other {# Autoren}} für Suchbegriff « {query} »", - "search.top.organizations.result": "{count, plural, =0 {# Organisation} one {# Organisation} other {# Organisationen}} für Suchbegriff « {query} »", - "search.top.projects.result": "{count, plural, =0 {# Finanzierung} one {# Finanzierung} other {# Finanzierungen}} für Suchbegriff « {query} »", - "search.top.patents.result": "{count, plural, =0 {# Patent} one {# Patent} other {# Patente}} für Suchbegriff « {query} »", + "search.top.result-for-query": " für Suchbegriff « {query} »", + "search.top.publications.result": "{count, plural, =0 {# Veröffentlichung} one {# Veröffentlichung} other {# Veröffentlichungen}}", + "search.top.authors.result": "{count, plural, =0 {# Autor} one {# Autor} other {# Autoren}}", + "search.top.organizations.result": "{count, plural, =0 {# Organisation} one {# Organisation} other {# Organisationen}}", + "search.top.projects.result": "{count, plural, =0 {# Finanzierung} one {# Finanzierung} other {# Finanzierungen}}", + "search.top.patents.result": "{count, plural, =0 {# Patent} one {# Patent} other {# Patente}}", "search.top.publications.filters.result-count": "{count, plural, =0 {# Veröffentlichung} one {# Veröffentlichung} other {# Veröffentlichungen}}", "search.top.organizations.filters.result-count": "{count, plural, =0 {# Organisationen} one {# Organisation} other {# Organisationen}}", "search.top.projects.filters.result-count": "{count, plural, =0 {# Finanzierungen} one {# Finanzierung} other {# Finanzierungen}}", @@ -37,6 +40,9 @@ "search.filters.publications.by-type-description": "Einen oder mehrere Publikationstypen auswählen", "search.filters.publications.filters-modal-title": "Filter", "search.filters.publications.by-author": "Nach Autor filtern", + "search.publications.openAccess": "Offener Zugang", + "search.publications.closedAccess": "Geschlossener Zugang", + "search.publications.other": "Andere", "search.filters.publications.by-author-description": "Einen oder mehrere Autoren auswählen", "search.filters.publications.by-is-oa": "Open Access", "search.filters.publications.by-is-oa-label": "Nur Open-Access-Veröffentlichungen anzeigen", @@ -94,6 +100,7 @@ "search.organizations.analytics.by-fundings.title": "Nach Finanzierungstypen", "search.filters.add": "Filter hinzufügen", "search.filters.clear": "Filter zurücksetzen", + "search.filters.current.title": "Filter", "search.filters.current.no-filter": "Kein aktiver Filter", "search.filters.current.organizations.kind": "Branche", "search.filters.current.organizations.level": "Organisationstyp", @@ -125,7 +132,7 @@ "search.results.pagination.next": "Weitere Ergebnisse anzeigen", "search.results.pagination.end": "Keine weiteren Ergebnisse für die Suche « {query} »", "search.exports.title": "Ergebnisse exportieren", - "search.exports.description": "Aus Leistungsgründen exportiert scanr maximal 1000 Ergebnisse. Sie können Ihre Suche verfeinern, um einen umfassenderen Export zu erhalten.", + "search.exports.description": "Aus Leistungsgründen exportiert scanR maximal 1000 Ergebnisse. Sie können Ihre Suche verfeinern, um einen umfassenderen Export zu erhalten.", "search.exports.is-exporting": "Daten werden heruntergeladen, bitte warten...", "search.exports.csv.title": "CSV", "search.exports.csv.description": "Ergebnisse im CSV-Format exportieren", diff --git a/client/src/pages/search/locales/en.json b/client/src/pages/search/locales/en.json index 93d08784..bc85ecd4 100644 --- a/client/src/pages/search/locales/en.json +++ b/client/src/pages/search/locales/en.json @@ -1,11 +1,13 @@ { "search.top.breadcrumb.home": "Home", + "search.top.breadcrumb.find-partners": "Find partners", "search.top.breadcrumb.publications": "Search Publications", "search.top.breadcrumb.authors": "Search Authors", "search.top.breadcrumb.projects": "Search Funding", "search.top.breadcrumb.patents": "Search Patents", "search.top.breadcrumb.organizations": "Search Organizations", "search.top.main-search-bar": "Search", + "search.section.author.badge": "Author", "search.top.patent.family.badge": "Patent Family", "search.top.filters-button-label": "Add Filters", "search.top.filters.clear": "Clear Filters", @@ -18,11 +20,12 @@ "search.filters.publications.active-filter-title": "Active Filters", "search.filters.publications.active-filter-empty": "No active filters", "search.top.result-more-than": "More than ", - "search.top.publications.result": "{count, plural, =0 {# publication} one {# publication} other {# publications}} for search term « {query} »", - "search.top.authors.result": "{count, plural, =0 {# author} one {# author} other {# authors}} for search term « {query} »", - "search.top.organizations.result": "{count, plural, =0 {# organization} one {# organization} other {# organizations}} for search term « {query} »", - "search.top.projects.result": "{count, plural, =0 {# funding} one {# funding} other {# fundings}} for search term « {query} »", - "search.top.patents.result": "{count, plural, =0 {# patent} one {# patent} other {# patents}} for search term « {query} »", + "search.top.result-for-query": " for search term « {query} »", + "search.top.publications.result": "{count, plural, =0 {# publication} one {# publication} other {# publications}}", + "search.top.authors.result": "{count, plural, =0 {# author} one {# author} other {# authors}}", + "search.top.organizations.result": "{count, plural, =0 {# organization} one {# organization} other {# organizations}}", + "search.top.projects.result": "{count, plural, =0 {# funding} one {# funding} other {# fundings}}", + "search.top.patents.result": "{count, plural, =0 {# patent} one {# patent} other {# patents}}", "search.top.publications.filters.result-count": "{count, plural, =0 {# publication} one {# publication} other {# publications}}", "search.top.organizations.filters.result-count": "{count, plural, =0 {# organizations} one {# organization} other {# organizations}}", "search.top.projects.filters.result-count": "{count, plural, =0 {# fundings} one {# funding} other {# fundings}}", @@ -37,6 +40,9 @@ "search.filters.publications.by-type-description": "Select one or more publication types", "search.filters.publications.filters-modal-title": "Filters", "search.filters.publications.by-author": "Filter by Author", + "search.publications.openAccess": "Open access", + "search.publications.closedAccess": "Closed access", + "search.publications.other": "Other", "search.filters.publications.by-author-description": "Select one or more authors", "search.filters.publications.by-is-oa": "Open Access", "search.filters.publications.by-is-oa-label": "Show only open access publications", @@ -94,6 +100,7 @@ "search.organizations.analytics.by-fundings.title": "By Funding Type", "search.filters.add": "Add Filters", "search.filters.clear": "Reset Filters", + "search.filters.current.title": "Filters", "search.filters.current.no-filter": "No active filters", "search.filters.current.organizations.kind": "Sector", "search.filters.current.organizations.level": "Organization Type", @@ -125,7 +132,7 @@ "search.results.pagination.next": "Show More Results", "search.results.pagination.end": "No additional results for search term « {query} »", "search.exports.title": "Export Results", - "search.exports.description": "For performance reasons, scanr only exports a maximum of 1000 results. You can refine your search to get a more complete export.", + "search.exports.description": "For performance reasons, scanR only exports a maximum of 1000 results. You can refine your search to get a more complete export.", "search.exports.is-exporting": "Downloading data, please wait...", "search.exports.csv.title": "CSV", "search.exports.csv.description": "Export results in CSV format", diff --git a/client/src/pages/search/locales/es.json b/client/src/pages/search/locales/es.json index 2463a8de..64b97b8e 100644 --- a/client/src/pages/search/locales/es.json +++ b/client/src/pages/search/locales/es.json @@ -1,11 +1,13 @@ { "search.top.breadcrumb.home": "Inicio", + "search.top.breadcrumb.find-partners": "Buscar socios", "search.top.breadcrumb.publications": "Buscar Publicaciones", "search.top.breadcrumb.authors": "Buscar Autores", "search.top.breadcrumb.projects": "Buscar Financiamiento", "search.top.breadcrumb.patents": "Buscar Patentes", "search.top.breadcrumb.organizations": "Buscar Organizaciones", "search.top.main-search-bar": "Buscar", + "search.section.author.badge": "Autor", "search.top.patent.family.badge": "Familia de Patentes", "search.top.filters-button-label": "Agregar Filtros", "search.top.filters.clear": "Limpiar Filtros", @@ -18,11 +20,12 @@ "search.filters.publications.active-filter-title": "Filtros Activos", "search.filters.publications.active-filter-empty": "Sin filtros activos", "search.top.result-more-than": "Más de ", - "search.top.publications.result": "{count, plural, =0 {# publicación} one {# publicación} other {# publicaciones}} para el término de búsqueda « {query} »", - "search.top.authors.result": "{count, plural, =0 {# autor} one {# autor} other {# autores}} para el término de búsqueda « {query} »", - "search.top.organizations.result": "{count, plural, =0 {# organización} one {# organización} other {# organizaciones}} para el término de búsqueda « {query} »", - "search.top.projects.result": "{count, plural, =0 {# financiamiento} one {# financiamiento} other {# financiamientos}} para el término de búsqueda « {query} »", - "search.top.patents.result": "{count, plural, =0 {# patente} one {# patente} other {# patentes}} para el término de búsqueda « {query} »", + "search.top.result-for-query": " para el término de búsqueda « {query} »", + "search.top.publications.result": "{count, plural, =0 {# publicación} one {# publicación} other {# publicaciones}}", + "search.top.authors.result": "{count, plural, =0 {# autor} one {# autor} other {# autores}}", + "search.top.organizations.result": "{count, plural, =0 {# organización} one {# organización} other {# organizaciones}}", + "search.top.projects.result": "{count, plural, =0 {# financiamiento} one {# financiamiento} other {# financiamientos}}", + "search.top.patents.result": "{count, plural, =0 {# patente} one {# patente} other {# patentes}}", "search.top.publications.filters.result-count": "{count, plural, =0 {# publicación} one {# publicación} other {# publicaciones}}", "search.top.organizations.filters.result-count": "{count, plural, =0 {# organizaciones} one {# organización} other {# organizaciones}}", "search.top.projects.filters.result-count": "{count, plural, =0 {# financiamientos} one {# financiamiento} other {# financiamientos}}", @@ -37,6 +40,9 @@ "search.filters.publications.by-type-description": "Selecciona uno o más tipos de publicación", "search.filters.publications.filters-modal-title": "Filtros", "search.filters.publications.by-author": "Filtrar por Autor", + "search.publications.openAccess": "Acceso abierto", + "search.publications.closedAccess": "Acceso cerrado", + "search.publications.other": "Otro", "search.filters.publications.by-author-description": "Selecciona uno o más autores", "search.filters.publications.by-is-oa": "Acceso Abierto", "search.filters.publications.by-is-oa-label": "Mostrar solo publicaciones de acceso abierto", @@ -94,6 +100,7 @@ "search.organizations.analytics.by-fundings.title": "Por Tipo de Financiamiento", "search.filters.add": "Agregar Filtros", "search.filters.clear": "Restablecer Filtros", + "search.filters.current.title": "Filtros", "search.filters.current.no-filter": "Sin filtros activos", "search.filters.current.organizations.kind": "Sector", "search.filters.current.organizations.level": "Tipo de Organización", @@ -125,7 +132,7 @@ "search.results.pagination.next": "Mostrar Más Resultados", "search.results.pagination.end": "No hay resultados adicionales para el término de búsqueda « {query} »", "search.exports.title": "Exportar Resultados", - "search.exports.description": "Por razones de rendimiento, scanr solo exporta un máximo de 1000 resultados. Puedes refinar tu búsqueda para obtener una exportación más completa.", + "search.exports.description": "Por razones de rendimiento, scanR solo exporta un máximo de 1000 resultados. Puedes refinar tu búsqueda para obtener una exportación más completa.", "search.exports.is-exporting": "Descargando datos, por favor espera...", "search.exports.csv.title": "CSV", "search.exports.csv.description": "Exportar resultados en formato CSV", diff --git a/client/src/pages/search/locales/fr.json b/client/src/pages/search/locales/fr.json index 74c8c2c0..ac6c0ffd 100644 --- a/client/src/pages/search/locales/fr.json +++ b/client/src/pages/search/locales/fr.json @@ -1,11 +1,13 @@ { "search.top.breadcrumb.home": "Accueil", + "search.top.breadcrumb.find-partners": "Trouver des partenaires", "search.top.breadcrumb.publications": "Rechercher des publications", "search.top.breadcrumb.authors": "Rechercher des auteurs", "search.top.breadcrumb.projects": "Rechercher des financements", "search.top.breadcrumb.patents": "Rechercher des brevets", "search.top.breadcrumb.organizations": "Rechercher des structures", "search.top.main-search-bar": "Rechercher", + "search.section.author.badge": "Auteur", "search.top.patent.family.badge": "Famille de brevet", "search.top.filters-button-label": "Ajouter des filtres", "search.top.filters.clear": "Réintitialiser les filtres", @@ -18,11 +20,12 @@ "search.filters.publications.active-filter-title": "Filtres actifs", "search.filters.publications.active-filter-empty": "Aucun filtre actif", "search.top.result-more-than": "Plus de ", - "search.top.publications.result": "{count, plural, =0 {# publication} one {# publication} other {# publications}} pour la recherche « {query} »", - "search.top.authors.result": "{count, plural, =0 {# auteur} one {# auteur} other {# auteurs}} pour la recherche « {query} »", - "search.top.organizations.result": "{count, plural, =0 {# structure} one {# structure} other {# structures}} pour la recherche « {query} »", - "search.top.projects.result": "{count, plural, =0 {# financements} one {# financement} other {# financements}} pour la recherche « {query} »", - "search.top.patents.result": "{count, plural, =0 {# brevets} one {# brevet} other {# brevets}} pour la recherche « {query} »", + "search.top.result-for-query": " pour la recherche « {query} »", + "search.top.publications.result": "{count, plural, =0 {# publication} one {# publication} other {# publications}}", + "search.top.authors.result": "{count, plural, =0 {# auteur} one {# auteur} other {# auteurs}}", + "search.top.organizations.result": "{count, plural, =0 {# structure} one {# structure} other {# structures}}", + "search.top.projects.result": "{count, plural, =0 {# financements} one {# financement} other {# financements}}", + "search.top.patents.result": "{count, plural, =0 {# brevets} one {# brevet} other {# brevets}}", "search.top.publications.filters.result-count": "{count, plural, =0 {# publication} one {# publication} other {# publications}}", "search.top.organizations.filters.result-count": "{count, plural, =0 {# structures} one {# structure} other {# structures}}", "search.top.projects.filters.result-count": "{count, plural, =0 {# financements} one {# financements} other {# financements}}", @@ -31,19 +34,22 @@ "search.filters.publications.by-year": "Filtrer par année", "search.filters.publications.by-year-description": "Période sélectionnée {min} - {max}", "search.filters.publications.by-year-tooltip": "Publications en {year}", - "search.filters.publications.by-project": "Filtrer par type de financements", - "search.filters.publications.by-project-description": "Sélectionnez un ou plusieurs types de financements", + "search.filters.publications.by-project": "Filtrer par type de financement", + "search.filters.publications.by-project-description": "Sélectionnez un ou plusieurs types de financement", "search.filters.publications.by-type": "Filtrer par type de publication", "search.filters.publications.by-type-description": "Sélectionnez un ou plusieurs types de publications", "search.filters.publications.filters-modal-title": "Filtres", "search.filters.publications.by-author": "Filtrer par auteur", + "search.publications.openAccess": "Accès ouvert", + "search.publications.closedAccess": "Accès fermé", + "search.publications.other": "Autre", "search.filters.publications.by-author-description": "Sélectionnez un ou plusieurs auteurs", "search.filters.publications.by-is-oa": "Accès ouvert", "search.filters.publications.by-is-oa-label": "Afficher uniquement les publications en accès ouvert", "search.filters.publications.by-organization": "Filtrer par affiliation", "search.filters.publications.by-organization-description": "Sélectionnez une ou plusieurs affiliations", - "search.filters.organizations.by-project": "Filtrer par type de financements", - "search.filters.organizations.by-project-description": "Sélectionnez un ou plusieurs types de financements", + "search.filters.organizations.by-project": "Filtrer par type de financement", + "search.filters.organizations.by-project-description": "Sélectionnez un ou plusieurs types de financement", "search.filters.organizations.by-kind": "Filtrer par secteur", "search.filters.organizations.by-kind-description": "Sélectionnez un ou plusieurs secteurs", "search.filters.organizations.by-level": "Filtrer par type d'organisme", @@ -73,7 +79,7 @@ "search.filters.projects.by-type": "Filtrer par type de financement", "search.filters.projects.by-type-description": "Sélectionnez un ou plusieurs types de financements", "search.filters.projects.by-year": "Filtrer par année", - "search.filters.patents.by-year": "Filtrer par date de dépot", + "search.filters.patents.by-year": "Filtrer par date de dépôt", "search.filters.current.patents.year": "Années de publication du brevet", "search.filters.patent.by-year-description": "Sélectionnez une période", "search.filters.patents.regions": "Caractéristiques de la famille de brevet", @@ -94,6 +100,7 @@ "search.organizations.analytics.by-fundings.title": "Par type de financement", "search.filters.add": "Ajouter des filtres", "search.filters.clear": "Réinitialiser les filtres", + "search.filters.current.title": "Filtres", "search.filters.current.no-filter": "Aucun filtre actif", "search.filters.current.organizations.kind": "Secteur", "search.filters.current.organizations.level": "Type d'organisme", @@ -125,7 +132,7 @@ "search.results.pagination.next": "Afficher plus de résultats", "search.results.pagination.end": "Pas de résultats supplémentaires pour la recherche « {query} »", "search.exports.title": "Exporter les résultats", - "search.exports.description": "Pour des raisons de performance, scanr n'exporte qu'un maximum de 1000 résultats. Vous pouvez affiner votre recherche pour obtenir un export plus complet.", + "search.exports.description": "Pour des raisons de performance, scanR n'exporte qu'un maximum de 1000 résultats. Vous pouvez affiner votre recherche pour obtenir un export plus complet.", "search.exports.is-exporting": "Téléchargement des données en cours, veuillez patienter...", "search.exports.csv.title": "CSV", "search.exports.csv.description": "Exporter les résultats au format CSV", diff --git a/client/src/pages/suggest/item.tsx b/client/src/pages/suggest/item.tsx index 883afd0b..017c9f80 100644 --- a/client/src/pages/suggest/item.tsx +++ b/client/src/pages/suggest/item.tsx @@ -1,5 +1,12 @@ import { Fragment } from "react"; -import { BadgeGroup, Badge, Text, Link, ButtonGroup, Button } from "@dataesr/dsfr-plus"; +import { + BadgeGroup, + Badge, + Text, + Link, + ButtonGroup, + Button, +} from "@dataesr/dsfr-plus"; import { publicationTypeMapping, encode } from "../../utils/string"; import { LightPublication } from "../../types/publication"; import { useIntl } from "react-intl"; @@ -9,55 +16,81 @@ export type AddItemProps = { highlight?: Record; addItem?: (item: T) => void; disabled: boolean; -} +}; export type RemoveItemProps = { data: T; removeItem?: (item: T) => void; -} +}; -export function SuggestionAddItem({ data: publication, highlight, addItem, disabled }: AddItemProps) { +export function SuggestionAddItem({ + data: publication, + highlight, + addItem, + disabled, +}: AddItemProps) { const intl = useIntl(); return (
    - {publicationTypeMapping[publication.type] || "Autre"} - - {publication.isOa ? 'Accès ouvert' : 'Accès fermé'} + + {publicationTypeMapping[publication.type] || + intl.formatMessage({ id: "search.publications.other" })} + + + {publication.isOa + ? intl.formatMessage({ id: "search.publications.openAccess" }) + : intl.formatMessage({ id: "search.publications.closedAccess" })} - {publication.title.default || publication.title?.fr || publication.title?.en} + {publication.title.default || + publication.title?.fr || + publication.title?.en} {publication?.authors?.slice(0, 5).map((author, k) => ( - {(k > 0) ? ', ' : ''} + {k > 0 ? ", " : ""} {author.fullName} ))} - {publication?.authors?.length > 5 && {' '}et al.} + {publication?.authors?.length > 5 && ( + + et al. + + )} {publication?.source?.title && `${publication?.source?.title}`} {publication?.source?.volume && `, ${publication.source?.volume}`} {publication?.source?.issue && ` (${publication.source?.issue})`} - {(publication?.year && publication?.source?.title) && ", "} + {publication?.year && publication?.source?.title && ", "} {publication?.year && `${publication.year}`} - {publication?.source?.publisher && `, ${publication?.source?.publisher}`} + {publication?.source?.publisher && + `, ${publication?.source?.publisher}`} {highlight?.["domains.label.default"] && ( - Mots clés: - {' '} - + Mots clés:{" "} + )} {highlight?.["summary.default"] && ( ... - + ... )} @@ -69,37 +102,53 @@ export function SuggestionAddItem({ data: publication, highlight, addItem, disab iconPosition="right" disabled={disabled} > - {intl.formatMessage({ id: 'suggest.items.add' })} + {intl.formatMessage({ id: "suggest.items.add" })}
    - ) + ); } -export function SuggestionRemoveItem({ data: publication, removeItem }: RemoveItemProps) { +export function SuggestionRemoveItem({ + data: publication, + removeItem, +}: RemoveItemProps) { const intl = useIntl(); return (
    - {publication.title.default || publication.title?.fr || publication.title?.en} + {publication.title.default || + publication.title?.fr || + publication.title?.en} {publication?.authors?.slice(0, 5).map((author, k) => ( - {(k > 0) ? ', ' : ''} - {(author?.person) ? {author.fullName} : author.fullName} + {k > 0 ? ", " : ""} + {author?.person ? ( + + {author.fullName} + + ) : ( + author.fullName + )} ))} - {publication?.authors?.length > 5 && {' '}et al.} + {publication?.authors?.length > 5 && ( + + et al. + + )} {publication?.source?.title && `${publication?.source?.title}`} {publication?.source?.volume && `, ${publication.source?.volume}`} {publication?.source?.issue && ` (${publication.source?.issue})`} - {(publication?.year && publication?.source?.title) && ", "} + {publication?.year && publication?.source?.title && ", "} {publication?.year && `${publication.year}`} - {publication?.source?.publisher && `, ${publication?.source?.publisher}`} + {publication?.source?.publisher && + `, ${publication?.source?.publisher}`}
    @@ -111,9 +160,9 @@ export function SuggestionRemoveItem({ data: publication, removeItem }: RemoveIt icon="delete-bin-line" iconPosition="right" > - {intl.formatMessage({ id: 'suggest.items.remove' })} + {intl.formatMessage({ id: "suggest.items.remove" })}
    - ) -} \ No newline at end of file + ); +} diff --git a/client/src/types/network.ts b/client/src/types/network.ts index c2969306..4747068d 100644 --- a/client/src/types/network.ts +++ b/client/src/types/network.ts @@ -3,67 +3,110 @@ import { LangField } from "./commons" export type Network = { network: NetworkData config?: NetworkConfig + info?: NetworkInfo } export type NetworkData = { - items: Array - links: Array - clusters?: Array + items: NetworkItems + links: NetworkLinks + clusters?: NetworkCommunities +} +export type NetworkItems = Array +export type NetworkItem = { + id: string + label: string + x: number + y: number + cluster: number + weights: Record + scores: Record + page?: string +} +export type NetworkLinks = Array +export type NetworkLink = { + source_id: string + target_id: string + strength: number +} +export type NetworkCommunities = Array +export type NetworkCommunity = { + cluster: number + label: string + size: number + color: string + ids?: Array + maxYear?: number + maxWeightNodes?: Array + hits?: number + years?: Record + domains?: Record + oaPercent?: number } export type NetworkConfig = { - terminology?: object - color_schemes?: object - templates?: object - styles?: object + terminology?: Record + color_schemes?: Record + templates?: Record + styles?: Record } export type NetworkInfo = { - title: string - description: string + title?: string + description?: string } export type NetworkSearchBody = { size: number - query: any - aggs: any + query: { + bool?: { + must?: Array> + filter?: Array> + } + function_score?: Record + } + aggs?: Record } export type NetworkSearchArgs = { model: string query?: string + filters?: NetworkFilters options?: { computeClusters?: boolean } - filters?: Record[] -} -export type NetworkHitsBody = { - size: number - query: any - _source: Array } - -export type Community = { - index: number - label: string - ids: Array - size: number - maxYear?: number - maxWeightNodes?: Array - domains?: any +export type NetworkSearchHitsArgs = { + model: string + query?: string + filters?: NetworkFilters + links?: Array } -export type Communities = Array +export type NetworkHits = Array export type NetworkHit = { id: string - title: string - type: string - isOa: boolean - domains: any + title?: string + type?: string + isOa?: boolean + year?: number + domains?: Record } -export type NetworkHits = Array +export type NetworkFilters = Array +export type NetworkFilter = Record + +export type ElasticBuckets = Array +export type ElasticBucket = { + key: string + doc_count: number + max_year?: { + value: number + } +} + +export type ElasticDomains = Array export type ElasticDomain = { label: LangField count: number } -export type ElasticDomains = Array + +export type ElasticHits = Array export type ElasticHit = { id: string title?: LangField @@ -72,4 +115,3 @@ export type ElasticHit = { domains?: ElasticDomains year?: number } -export type ElasticHits = Array diff --git a/client/src/types/publication.ts b/client/src/types/publication.ts index 8822df6a..e8dfd9fe 100644 --- a/client/src/types/publication.ts +++ b/client/src/types/publication.ts @@ -38,6 +38,13 @@ type BasePublication = { year: number; }; +export type SoftwareMention = { + softwareName: string; + contexts: string[]; + id_name: string; + wikidata?: string; +} + export type LightPublication = BasePublication & { authors: { fullName: string; @@ -50,6 +57,7 @@ export type Publication = BasePublication & { _id: string; summary: LangField; domains: DomainsData[]; + softwares: SoftwareMention[]; landingPage?: string; pdfUrl?: string; affiliations: { diff --git a/client/tsconfig.node.json b/client/tsconfig.node.json index 42872c59..73dbb0b0 100644 --- a/client/tsconfig.node.json +++ b/client/tsconfig.node.json @@ -6,5 +6,7 @@ "moduleResolution": "bundler", "allowSyntheticDefaultImports": true }, - "include": ["vite.config.ts"] -} + "include": [ + "vite.config.ts" + ] +} \ No newline at end of file