diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template index 03b32625..80a9d9cd 100644 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/default.conf.template @@ -11,5 +11,6 @@ server { proxy_set_header content-type application/json; proxy_ssl_server_name on; proxy_pass https://api.brevo.com/v3/smtp/email; + client_max_body_size 10M; } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 8f4efe1c..2331bd95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6150,9 +6150,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001591", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz", - "integrity": "sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==", + "version": "1.0.30001662", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001662.tgz", + "integrity": "sha512-sgMUVwLmGseH8ZIrm1d51UbrhqMCH3jvS7gF/M6byuHOnKyLOBL7W8yz5V02OHwgLGA36o/AFhWzzh4uc5aqTA==", "funding": [ { "type": "opencollective", diff --git a/src/components/Charts/publications/general/langues-evolution/get-data.js b/src/components/Charts/publications/general/langues-evolution/get-data.js new file mode 100644 index 00000000..f44ad3b3 --- /dev/null +++ b/src/components/Charts/publications/general/langues-evolution/get-data.js @@ -0,0 +1,77 @@ +import Axios from 'axios'; +import { useCallback, useEffect, useState } from 'react'; +import { useIntl } from 'react-intl'; + +import { ES_API_URL, HEADERS } from '../../../../../config/config'; +import getFetchOptions from '../../../../../utils/chartFetchOptions'; + +function useGetData(observationSnap, domain) { + const intl = useIntl(); + const [allData, setData] = useState({}); + const [isLoading, setLoading] = useState(true); + const [isError, setError] = useState(false); + + const getDataForLastObservationSnap = useCallback( + async (lastObservationSnap) => { + const query = getFetchOptions({ + key: 'publicationsByYear', + domain, + parameters: [lastObservationSnap, 'lang.keyword'], + objectType: ['publications'], + }); + const res = await Axios.post(ES_API_URL, query, HEADERS); + const data = res.data.aggregations.by_year.buckets; + data.sort((a, b) => a.key - b.key); // Tri pour avoir les années dans l'ordre d'affichage du graphe + + const categories = Object.values(data).map((d) => d.key); // Elements d'abscisse + + const dataByLang = {}; + data.forEach((year) => year.by_custom.buckets.forEach((lang) => { + dataByLang[lang.key] = [ + ...(dataByLang?.[lang.key] ?? []), + { year: year.key, count: lang.doc_count }, + ]; + })); + + const dataGraph = Object.entries(dataByLang).map(([key, values]) => ({ + name: intl.formatMessage({ id: `app.lang.${key}` }), + data: values.map((v) => ({ + name: v.year, + y: v.count, + lang: intl.formatMessage({ id: `app.lang.${key}` }), + })), + })); + + const sum = (array) => array.reduce((acc, value) => acc + value, 0); + dataGraph.sort( + (a, b) => sum(b.data.map(({ y }) => y)) - sum(a.data.map(({ y }) => y)), + ); + + return { + categories, + dataGraph: dataGraph.slice(0, 5), + }; + }, + [domain, intl], + ); + + useEffect(() => { + async function getData() { + try { + const dataGraph = await getDataForLastObservationSnap(observationSnap); + setData(dataGraph); + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + setError(true); + } finally { + setLoading(false); + } + } + getData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [observationSnap]); + + return { allData, isError, isLoading }; +} +export default useGetData; diff --git a/src/components/Charts/publications/general/langues-evolution/langues-by-year.js b/src/components/Charts/publications/general/langues-evolution/langues-by-year.js new file mode 100644 index 00000000..f6d9370a --- /dev/null +++ b/src/components/Charts/publications/general/langues-evolution/langues-by-year.js @@ -0,0 +1,84 @@ +import Highcharts from 'highcharts'; +import HCExportingData from 'highcharts/modules/export-data'; +import HCExporting from 'highcharts/modules/exporting'; +import HighchartsReact from 'highcharts-react-official'; +import PropTypes from 'prop-types'; +import React, { useEffect, useRef, useState } from 'react'; +import { useIntl } from 'react-intl'; + +import customComments from '../../../../../utils/chartComments'; +import { chartOptions } from '../../../../../utils/chartOptions'; +import { domains, graphIds } from '../../../../../utils/constants'; +import { getObservationLabel, withDomain } from '../../../../../utils/helpers'; +import useGlobals from '../../../../../utils/Hooks/useGetGlobals'; +import WrapperChart from '../../../../WrapperChart'; +import GraphComments from '../../../graph-comments'; +import useGetData from './get-data'; + +HCExporting(Highcharts); +HCExportingData(Highcharts); + +const Chart = ({ domain, hasComments, hasFooter, id }) => { + const [chartComments, setChartComments] = useState(''); + const chartRef = useRef(); + const intl = useIntl(); + const { beforeLastObservationSnap, lastObservationSnap } = useGlobals(); + const { allData, isError, isLoading } = useGetData( + lastObservationSnap, + domain, + ); + const { dataGraph, categories } = allData; + const dataTitle = { + publicationYear: getObservationLabel(beforeLastObservationSnap, intl), + }; + const idWithDomain = withDomain(id, domain); + const optionsGraph = chartOptions[id].getOptions( + idWithDomain, + intl, + categories, + dataGraph, + dataTitle, + ); + + useEffect(() => { + setChartComments(customComments(allData, idWithDomain, intl)); + }, [allData, idWithDomain, intl]); + + return ( + + + {hasComments && chartComments && ( + + )} + + ); +}; + +Chart.defaultProps = { + domain: '', + hasComments: true, + hasFooter: true, + id: 'publi.general.langues.chart-publications-by-year', +}; +Chart.propTypes = { + domain: PropTypes.oneOf(domains), + hasComments: PropTypes.bool, + hasFooter: PropTypes.bool, + id: PropTypes.oneOf(graphIds), +}; + +export default Chart; diff --git a/src/components/SubmissionForm/index.js b/src/components/SubmissionForm/index.js index 4ff295ea..1918ceb9 100644 --- a/src/components/SubmissionForm/index.js +++ b/src/components/SubmissionForm/index.js @@ -101,7 +101,7 @@ const SubmissionForm = () => { setIsError(true); const errorMessage = errors.length === 1 ? `Un caractère spécial a été détecté à la ligne ${errors[0]}. Merci de corriger votre fichier afin de le soumettre.` - : `Un caractère spécial a été détecté aux ${errors.join( + : `Un caractère spécial a été détecté aux lignes ${errors.join( ', ', )}. Merci de corriger votre fichier afin de le soumettre.`; setMessage(errorMessage); @@ -145,10 +145,11 @@ const SubmissionForm = () => { "Merci pour votre envoi! Si tout s'est bien passé, vous allez recevoir une copie du mail envoyé à l'équipe du baromètre.", ); }) - .catch(() => { + .catch((e) => { + console.error(e); setIsError(true); setMessage( - "Error lors de l'envoi de votre fichier, merci de contacter bso@recherche.gouv.fr.", + "Erreur lors de l'envoi de votre fichier, merci de contacter bso@recherche.gouv.fr.", ); }); }; diff --git a/src/pages/BaroNational/NationalPublications/index.js b/src/pages/BaroNational/NationalPublications/index.js index 32a81c00..587d91b9 100644 --- a/src/pages/BaroNational/NationalPublications/index.js +++ b/src/pages/BaroNational/NationalPublications/index.js @@ -177,6 +177,10 @@ export default function NationalPublications() { anchorId='general.langues-ouverture' > + In particular, we note that among publications published in {publicationYear}, there are {publicationsEnglishTotal} publications in English of which {publicationsEnglishOpen} are open and {publicationsEnglishClosed} are closed (i.e. an open access rate of {publicationsEnglishRate}%), and {publicationsFrenchTotal} publications in French of which {publicationsFrenchOpen} are open and {publicationsFrenchClosed} closed (i.e. a rate of {publicationsFrenchRate}%). French-language publications are therefore less open than English-language publications. Publications in Spanish, German and Portuguese represent smaller numbers, statistically less significant.", "app.health-publi.general.langues-ouverture.chart-repartition-publications.comments": "This graph shows the open access rate of publications {commentsName} in health released in {publicationYear} according to their language of publication, while specifying the open access routes. The language data was extracted from PubMed metadata if available, or inferred from the title and abstract in the remaining cases. In particular, we note that among publications published in {publicationYear}, there are {publicationsEnglishTotal} publications in English of which {publicationsEnglishOpen} are open and {publicationsEnglishClosed} are closed (i.e. an open access rate of {publicationsEnglishRate}%), and {publicationsFrenchTotal} publications in French of which {publicationsFrenchOpen} are open and {publicationsFrenchClosed} closed (i.e. a rate of {publicationsFrenchRate}%). French-language publications are therefore less open than English-language publications. Publications in Spanish, German and Portuguese represent smaller numbers, statistically less significant.", + "app.national-publi.general.langues.chart-publications-by-year.title": "Evolution of the number of publications {commentsName} according to their language of publication", "app.national-publi.general.voies-ouverture.description": "Open access to scientific publications can be achieved through several routes: natively open access publication by the publisher on a dissemination platform or deposit by the author in an app.glossary.archive-ouverte-min. These two routes are not exclusive, as a publication may be hosted both on an open repository and on the publisher's publishing platform. This simultaneity, which tends to increase over time, is a factor of resilience since it makes it possible to offer editorial quality and guarantee the durability of access to French scientific publications.", "app.health-publi.general.voies-ouverture.description": "Open access to scientific publications can be achieved through several routes: natively open access publication by the publisher on a dissemination platform or deposit by the author in an app.glossary.archive-ouverte-min. These two routes are not exclusive, as a publication may be hosted both on an open repository and on the publisher's publishing platform. This simultaneity, which tends to increase over time, is a factor of resilience since it makes it possible to offer editorial quality and guarantee the durability of access to French scientific publications.", "app.national-publi.general.voies-ouverture.chart-evolution-taux.tooltip": "Publication year {point.x}
• Open access rate
with hosting {series.name}:
{point.y:.2f}% ({point.y_abs} / {point.y_tot})
• Total open access rate:
{point.stackTotal:.2f}% ({point.y_oa} / {point.y_tot})", @@ -1015,6 +1016,7 @@ "app.publi.general.genres-ouverture.chart-repartition-genres.tooltip": "{point.name} published in {point.publicationDate} ({point.bsoDomain})
{point.value} in {point.oaType}
i.e. {point.percentage:.2f}% of the total of the publications of {point.publicationDate}", "app.publi.general.genres-ouverture.chart-repartition-taux.tooltip": "{point.x_val} ({point.bsoDomain})
• Open access rate
with hosting {series.name}:
{point.y:.2f}% ({point.y_abs} / {point.y_tot})
• Total open access rate: {point.stacktotal:.2f}%", "app.publi.general.langues-ouverture.chart-repartition-publications.tooltip": "{point.name} published in {point.publicationDate} ({point.bsoDomain})
{point.value} in {point.oaType}
that is {point.percentage:.2f}% of the total publications of {point.publicationDate}", + "app.publi.general.langues.chart-publications-by-year.tooltip": "{point.lang}: {point.y} publications in {point.name}
", "app.publi.navigation.go-to-page": "Go to page", "app.publi.navigation.affiliation.dynamique": "The opening trends by type of affiliation", "app.publi.navigation.affiliation.impact": "Impact of affiliate countries", diff --git a/src/translations/fr.json b/src/translations/fr.json index 5e483610..0741544c 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -932,6 +932,7 @@ "app.health-publi.general.langues-ouverture.chart-repartition-publications.title": "Taux d'accès ouvert par langue de publications {commentsName} dans le domaine de la santé, publications de {publicationYear}", "app.national-publi.general.langues-ouverture.chart-repartition-publications.comments": "Ce graphique montre le taux d'accès ouvert des publications {commentsName} parues en {publicationYear} en fonction de leur langue de publication, tout en précisant les voies de l'ouverture. La donnée concernant la langue a été extraite des métadonnées de PubMed si disponible, ou inférée à partir du titre et du résumé dans le reste des cas.On remarque notamment que, parmi les publications parues en {publicationYear}, on dénombre {publicationsEnglishTotal} publications en anglais dont {publicationsEnglishOpen} ouvertes et {publicationsEnglishClosed} fermées (soit un taux d'accès ouvert de {publicationsEnglishRate} %), et {publicationsFrenchTotal} publications en français dont {publicationsFrenchOpen} ouvertes et {publicationsFrenchClosed} fermées (soit un taux de {publicationsFrenchRate} %). Les publications en langue française sont donc moins ouvertes que les publications en langue anglaise. Les publications en espagnol, allemand et portugais représentent de plus petits effectifs, statistiquement moins significatifs.", "app.health-publi.general.langues-ouverture.chart-repartition-publications.comments": "Ce graphique montre le taux d'accès ouvert des publications {commentsName} en santé parues en {publicationYear} en fonction de leur langue de publication, tout en précisant les voies de l'ouverture. La donnée concernant la langue a été extraite des métadonnées de PubMed si disponible, ou inférée à partir du titre et du résumé dans le reste des cas.On remarque notamment que, parmi les publications parues en {publicationYear}, on dénombre {publicationsEnglishTotal} publications en anglais dont {publicationsEnglishOpen} ouvertes et {publicationsEnglishClosed} fermées (soit un taux d'accès ouvert de {publicationsEnglishRate} %), et {publicationsFrenchTotal} publications en français dont {publicationsFrenchOpen} ouvertes et {publicationsFrenchClosed} fermées (soit un taux de {publicationsFrenchRate} %). Les publications en langue française sont donc moins ouvertes que les publications en langue anglaise. Les publications en espagnol, allemand et portugais représentent de plus petits effectifs, statistiquement moins significatifs.", + "app.national-publi.general.langues.chart-publications-by-year.title": "Évolution du nombre de publications {commentsName} par langue de publication", "app.national-publi.general.voies-ouverture.description": "L'accès ouvert aux publications scientifiques peut se faire par plusieurs voies : la publication nativement en accès ouvert par l'éditeur sur une plateforme de publication ou le dépôt par l'auteur dans une app.glossary.archive-ouverte-min. Ces deux voies ne sont pas exclusives, une publication pouvant être à la fois hébergée sur une archive ouverte et sur la plateforme de publication de l'éditeur. Cette simultanéité, qui tend à s'accroître au cours du temps, est un facteur de résilience puisqu'elle permet à la fois d'offrir la qualité éditoriale et de garantir la pérennité de l'accès aux publications scientifiques françaises.", "app.health-publi.general.voies-ouverture.description": "L'accès ouvert aux publications scientifiques peut se faire par plusieurs voies : la publication nativement en accès ouvert par l'éditeur sur une plateforme de publication ou le dépôt par l'auteur dans une app.glossary.archive-ouverte-min. Ces deux voies ne sont pas exclusives, une publication pouvant être à la fois hébergée sur une archive ouverte et sur la plateforme de publication de l'éditeur. Cette simultanéité, qui tend à s'accroître au cours du temps, est un facteur de résilience puisqu'elle permet à la fois d'offrir la qualité éditoriale et de garantir la pérennité de l'accès aux publications scientifiques françaises.", "app.national-publi.general.voies-ouverture.chart-evolution-taux.tooltip": "Année de publication {point.x}
• Taux d'accès ouvert
avec hébergement {series.name} :
{point.y:.2f} % ({point.y_abs} / {point.y_tot})
• Taux d'accès ouvert total :
{point.stackTotal:.2f} % ({point.y_oa} / {point.y_tot})", @@ -1195,6 +1196,7 @@ "app.publi.general.genres-ouverture.chart-repartition-genres.tooltip": "{point.name} publiés en {point.publicationDate} ({point.bsoDomain})
{point.value} en {point.oaType}
soit {point.percentage:.2f} % du total des publications de {point.publicationDate}", "app.publi.general.genres-ouverture.chart-repartition-taux.tooltip": "{point.x_val} ({point.bsoDomain})
• Taux d'accès ouvert
avec hébergement {series.name} :
{point.y:.2f} % ({point.y_abs} / {point.y_tot})
• Taux d'accès ouvert total :
{point.stackTotal:.2f} % ({point.y_oa} / {point.y_tot})", "app.publi.general.langues-ouverture.chart-repartition-publications.tooltip": "{point.name} publiés en {point.publicationDate} ({point.bsoDomain})
{point.value} en {point.oaType}
soit {point.percentage:.2f} % du total des publications de {point.publicationDate}", + "app.publi.general.langues.chart-publications-by-year.tooltip": "{point.lang}: {point.y} publications en {point.name}", "app.publi.navigation.go-to-page": "Aller à la page", "app.publi.navigation.affiliation.dynamique": "La dynamique d'ouverture par type d'affiliation", "app.publi.navigation.affiliation.impact": "Impact des pays d'affiliation", diff --git a/src/utils/chartComponents.js b/src/utils/chartComponents.js index 96043e53..001f2f3f 100644 --- a/src/utils/chartComponents.js +++ b/src/utils/chartComponents.js @@ -105,6 +105,9 @@ const ChartRepartitionTauxFinancement = lazy(() => import( const ChartLanguesOuverture = lazy(() => import( '../components/Charts/publications/general/langues-ouverture/langues-ouverture' )); +const ChartLanguesByYear = lazy(() => import( + '../components/Charts/publications/general/langues-evolution/langues-by-year' +)); const ChartRepartitionPublications = lazy(() => import( '../components/Charts/publications/general/voies-ouverture/chart-repartition-publications' )); @@ -336,6 +339,7 @@ const chartComponents = { ChartRepartitionPublications, 'publi.general.langues-ouverture.chart-repartition-publications': ChartLanguesOuverture, + 'publi.general.langues.chart-publications-by-year': ChartLanguesByYear, 'publi.general.impact-financement.chart-taux-ouverture': ChartTauxOuvertureFinancement, 'publi.general.impact-financement.chart-business-model': diff --git a/src/utils/chartFetchOptions.js b/src/utils/chartFetchOptions.js index 6f00e9b4..67ff03e4 100644 --- a/src/utils/chartFetchOptions.js +++ b/src/utils/chartFetchOptions.js @@ -2217,6 +2217,44 @@ export default function getFetchOptions({ }, }, }), + publicationsByYear: ([ + lastObservationSnap, + customField, + minPublicationDate = 2013, + ]) => ({ + size: 0, + query: { + bool: { + filter: [ + { + range: { + year: { + gte: minPublicationDate, + lte: getPublicationYearFromObservationSnap( + lastObservationSnap, + ), + }, + }, + }, + ], + }, + }, + aggs: { + by_year: { + terms: { + field: 'year', + size: 15, + }, + aggs: { + by_custom: { + terms: { + field: customField, + }, + }, + }, + }, + }, + }), retractionsByYear: ([lastObservationSnap, minPublicationDate = 2013]) => ({ size: 0, query: { diff --git a/src/utils/chartOptions.js b/src/utils/chartOptions.js index efda4a0e..6dd8fea1 100644 --- a/src/utils/chartOptions.js +++ b/src/utils/chartOptions.js @@ -963,6 +963,38 @@ export const chartOptions = { return options; }, }, + 'publi.general.langues.chart-publications-by-year': { + getOptions: (id, intl, categories, data, dataTitle) => { + const options = getGraphOptions({ id, intl, dataTitle }); + options.chart.type = 'spline'; + options.xAxis = { + categories, + title: { text: intl.formatMessage({ id: 'app.publication-year' }) }, + }; + options.yAxis = { + type: 'logarithmic', + title: { + text: intl.formatMessage({ id: 'app.publi.nb-publications' }), + }, + }; + options.legend.title.text = intl.formatMessage({ + id: 'app.publication-lang', + }); + options.tooltip.pointFormat = intl.formatMessage({ + id: 'app.publi.general.langues.chart-publications-by-year.tooltip', + }); + options.plotOptions = { + spline: { + dataLabels: { + enabled: false, + }, + }, + }; + options.series = data; + + return options; + }, + }, 'publi.general.impact-financement.chart-taux-ouverture': { getOptions: (id, intl, categories, data, agency) => { const options = getGraphOptions({ id, intl });