Skip to content

Commit 58d7574

Browse files
committed
rework and openalex tests
1 parent 4dd3ab8 commit 58d7574

File tree

41 files changed

+1267
-861
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1267
-861
lines changed

client/nginx.conf

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,8 @@ server {
3232
proxy_set_header X-Real-IP $remote_addr;
3333
proxy_pass https://ec.europa.eu/info/funding-tenders/opportunities/data/topicDetails/$1.json;
3434
}
35-
}
35+
location ~ ^/openalex/(.*)$ {
36+
proxy_set_header X-Real-IP $remote_addr;
37+
proxy_pass https://api.openalex.org/$1&api_key=$OPENALEX_API_KEY;
38+
}
39+
}

client/src/api/openalex/analytic-tool.ts.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,39 @@
11
import { AggregationArgs } from "../../types/commons";
22

3-
const getUrl = (query: string, groupBy: string) =>
4-
`https://api.openalex.org/works?page=1&[email protected]&filter=title_and_abstract.search:${query}&group_by=${groupBy}`;
3+
import { getOpenalexUrl } from "./config";
54

65
const groupBys = [
76
"publication_year",
87
"type",
98
"authorships.countries",
109
"authorships.author.id",
11-
// "authorships.author.id###authorships.countries:countries/fr",
1210
"authorships.institutions.lineage",
1311
"primary_topic.id",
1412
// "keywords.id",
1513
"primary_location.source.id",
1614
"grants.funder",
17-
"authorships.institutions.continent",
15+
// "authorships.institutions.continent",
1816
];
1917

2018
export async function fetchOpenAlexAggregations({ query, filters = [] }: AggregationArgs): Promise<any> {
21-
console.log(filters)
19+
console.log("fetchOpenAlexAggregations", query, filters)
2220
const urls = groupBys.map((groupBy) => {
23-
// if (groupBy.split("###").length > 1) {
24-
// return getUrl(`${query},${groupBy.split("###")[1]}`, groupBy.split("###")[0]);
25-
// }
26-
if (filters) {
21+
if (filters.length) {
2722
/* @ts-expect-error unknown */
28-
const [yearMin, yearMax] = [filters?.[0]?.range?.year?.gte, filters?.[0]?.range?.year?.lte]
29-
if (!yearMin || !yearMax) return getUrl(query, groupBy);
30-
return getUrl(`${query},publication_year:${yearMin}-${yearMax}`, groupBy);
23+
const yearRange: any = filters.find((el: any) => el?.range?.year)?.range?.year
24+
const [yearMin, yearMax] = [yearRange?.gte, yearRange?.lte]
25+
const types = filters
26+
?.find((el) => el?.terms?.["type.keyword"])
27+
?.terms["type.keyword"]
28+
?.map((type: string) => `types/${type}`);
29+
30+
const typesFilter = types?.length > 0 ? `type:${types.join("|")}` : "";
31+
const yearsFilter = (yearMin && yearMax) ? `publication_year:${parseInt(yearMin)}-${parseInt(yearMax)}` : "";
32+
const finalQuery= [query, typesFilter, yearsFilter].filter(Boolean).join(",")
33+
console.log("finalQuery", finalQuery)
34+
return getOpenalexUrl(finalQuery, groupBy);
3135
}
32-
return getUrl(query, groupBy);
36+
return getOpenalexUrl(query, groupBy);
3337
});
3438

3539
const responses = await Promise.all(urls.map((url) => fetch(url)));
@@ -39,13 +43,12 @@ export async function fetchOpenAlexAggregations({ query, filters = [] }: Aggrega
3943
publicationType,
4044
authorshipsCountries,
4145
authorshipsAllAuthors,
42-
// authorshipsFrenchAuthors,
4346
authorshipsAuthorsInstitutions,
4447
primaryTopic,
4548
// keywords,
4649
primaryLocationUrl,
4750
grantsFunder,
48-
authorshipsAuthorsInstitutionsContinents,
51+
// authorshipsAuthorsInstitutionsContinents,
4952
] = results.map((result) => {
5053
const agg = result.group_by;
5154

@@ -75,6 +78,6 @@ export async function fetchOpenAlexAggregations({ query, filters = [] }: Aggrega
7578
// keywords,
7679
primaryLocationUrl,
7780
grantsFunder,
78-
authorshipsAuthorsInstitutionsContinents,
81+
// authorshipsAuthorsInstitutionsContinents,
7982
};
8083
}

client/src/api/openalex/config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const VITE_OPENALEX_URL = import.meta.env.VITE_OPENALEX_URL;
2+
3+
export const OPENALEX_URL = VITE_OPENALEX_URL || '/openalex';
4+
5+
export const getOpenalexUrl = (query: string, groupBy: string) =>
6+
`${OPENALEX_URL}/works?page=1&filter=title_and_abstract.search:${query}&group_by=${groupBy}`;

client/src/api/openalex/filters.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,38 @@
11
import { fillWithMissingYears } from "../utils/years";
2+
import { getOpenalexUrl } from "./config";
23

3-
const getUrl = (query: string) =>
4-
`https://api.openalex.org/works?page=1&[email protected]&filter=title_and_abstract.search:${query}&group_by=publication_year`;
4+
const groupBysFilters = [
5+
"publication_year",
6+
"type",
7+
];
58

6-
export async function fetchOpenYearFilters({
9+
export async function fetchOpenFilters({
710
query
811
}: {
912
query: string;
1013
}): Promise<any> {
11-
const url = getUrl(query);
12-
const response = await fetch(url);
13-
const json = await response.json();
14-
console.log("JSON", json)
15-
const data = json.group_by.map((item) => ({
14+
const urls = groupBysFilters.map((groupBy) => getOpenalexUrl(query, groupBy));
15+
16+
const responses = await Promise.all(urls.map((url) => fetch(url)));
17+
const results = await Promise.all(responses.map((res) => res.json()));
18+
const years = results?.[0]?.group_by.map((item) => ({
1619
value: parseInt(item.key, 10),
1720
label: parseInt(item.key_display_name, 10),
1821
count: item.count,
1922
}))
20-
const _100Year = Math.max(...data.map((el) => el.count));
21-
const byYear = data.filter((element) => element.value > 1990).map((element) => {
23+
const _100Year = Math.max(...years.map((el) => el.count));
24+
const byYear = years.filter((element) => element.value > 1990).map((element) => {
2225
return {
2326
...element,
2427
normalizedCount: element.doc_count * 100 / _100Year,
2528
}
2629
}).sort((a, b) => a.label - b.label).reduce(fillWithMissingYears, []) || [];
27-
console.log("OPENALEX", byYear)
30+
const byType = results?.[1]?.group_by.map((item) => ({
31+
value: item.key_display_name,
32+
label: item.key_display_name,
33+
count: item.count,
34+
}));
35+
console.log("byType", byType)
2836

29-
return { byYear }
37+
return { byYear, byType }
3038
}

client/src/api/patents/aggregate/analytic-tool.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { FIELDS } from "../_utils/constants";
66

77

88
export async function aggregatePatentsForAnalyticTool(
9-
{ query }: AggregationArgs
9+
{ query, filters = [] }: AggregationArgs
1010
): Promise<PatentsAggregationsForAnalyticTool> {
1111
const body: any = {
1212
size: 0,
@@ -51,8 +51,25 @@ export async function aggregatePatentsForAnalyticTool(
5151
}
5252
}
5353
},
54+
byCpc: {
55+
terms: {
56+
field: "cpc.classe.code.keyword",
57+
size: 10000,
58+
},
59+
aggs: {
60+
bySectionLabel: {
61+
terms: {
62+
field: "cpc.section.label.keyword",
63+
size: 1,
64+
},
65+
},
66+
},
67+
},
5468
}
5569
}
70+
if (filters.length > 0) {
71+
body.query.bool.filter = filters
72+
}
5673
const res = await fetch(
5774
`${patentsIndex}/_search`,
5875
{ method: 'POST', body: JSON.stringify(body), headers: postHeaders })

client/src/api/projects/aggregate/anaytic-tool.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { fillWithMissingYears } from "../../utils/years";
55
import { FIELDS } from "../_utils/constants";
66

77
export async function aggregateProjectsForAnalyticsTool(
8-
{ query }: AggregationArgs
8+
{ query, filters = [] }: AggregationArgs
99
): Promise<ProjectAggregationsForAnalyticsTool> {
1010
const body: any = {
1111
size: 0,
@@ -42,9 +42,24 @@ export async function aggregateProjectsForAnalyticsTool(
4242
field: "participants.structure.id_name.keyword",
4343
size: 500,
4444
}
45-
}
45+
},
46+
byKeywordsFr: {
47+
terms: {
48+
field: "keywords.fr.keyword",
49+
size: 50,
50+
},
51+
},
52+
byKeywordsEn: {
53+
terms: {
54+
field: "keywords.en.keyword",
55+
size: 50,
56+
},
57+
},
4658
}
4759
}
60+
if (filters.length > 0) {
61+
body.query.bool.filter = filters
62+
}
4863
const res = await fetch(
4964
`${projectsIndex}/_search`,
5065
{ method: 'POST', body: JSON.stringify(body), headers: postHeaders })
@@ -78,6 +93,15 @@ export async function aggregateProjectsForAnalyticsTool(
7893
}
7994
}).filter(el => el) || [];
8095
const projectsCount = data?.projectsCount?.value || 0;
81-
return { byInstitution, byYear, byType, projectsCount};
96+
const keywordsBuckets = [...data?.byKeywordsFr?.buckets || [], ...data?.byKeywordsEn?.buckets || []];
97+
98+
const byKeywords = keywordsBuckets.map((element) => {
99+
return {
100+
value: element.key,
101+
label: element.key,
102+
count: element.doc_count,
103+
}
104+
}).filter(el => el).sort((a, b) => a.count - b.count).slice(0, 30) || [];
105+
return { byInstitution, byYear, byType, byKeywords, projectsCount};
82106

83107
}

client/src/api/publications/aggregate/analytic-tool.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { AggregationArgs } from "../../../types/commons";
33
import { PublicationAggregationsForAnalyticTool } from "../../../types/publication";
44
import { publicationTypeMapping } from "../../../utils/string";
55
import { fillWithMissingYears } from "../../utils/years";
6-
import { FIELDS } from "../_utils/constants";
76

87
interface StackedChartSeries {
98
name: string;
@@ -94,7 +93,7 @@ export async function aggregatePublicationsForAnalyticTool(
9493
{
9594
query_string: {
9695
query: query || '*',
97-
fields: FIELDS,
96+
fields: ["title_abs_text"],
9897
},
9998
}
10099
]

client/src/pages/analytics/openalex/components/current-filters.tsx renamed to client/src/pages/analytics/components/current-filters.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,39 @@
11
import {
22
Row,
33
Col,
4-
Title,
54
Button,
65
Tag,
6+
Text,
77
} from "@dataesr/dsfr-plus";
8-
import useUrl from "../../hooks/useUrl";
9-
import useFilters from "../hooks/useFilters";
8+
import useUrl from "../hooks/useUrl";
9+
import { useId } from "react";
1010

11-
export default function CurrentFilters() {
11+
export default function CurrentFilters({ FilterModal }: { FilterModal: React.ComponentType<{ id: string }> }) {
12+
const id = useId();
1213
const {
1314
currentFilters,
1415
handleFilterChange,
1516
handleDeleteFilter,
1617
clearFilters,
1718
handleRangeFilterChange,
1819
} = useUrl();
19-
const { isLoading, isError } = useFilters();
2020
return (
2121
<Row className="fr-mb-1w">
22+
<FilterModal id={id} />
2223
<Col xs="12">
2324
<div style={{ display: "flex", alignItems: "center" }}>
2425
<div style={{ flexGrow: 1 }}>
25-
<Title as="h1" className="fr-text--lg fr-text--bold fr-m-0">
26-
Filtres
27-
</Title>
26+
<Text bold className="fr-m-0">
27+
Filtres spécifiques au corpus
28+
</Text>
2829
</div>
2930
<div>
3031
<Button
3132
icon="add-circle-line"
3233
iconPosition="left"
3334
as="button"
34-
aria-controls="tools-analytics-openalex-filters"
35+
aria-controls={id}
3536
data-fr-opened="false"
36-
disabled={isLoading || isError}
3737
variant="text"
3838
size="sm"
3939
>
@@ -46,7 +46,7 @@ export default function CurrentFilters() {
4646
icon="delete-bin-line"
4747
iconPosition="right"
4848
onClick={clearFilters}
49-
disabled={isLoading || isError}
49+
disabled={!!currentFilters?.length}
5050
variant="text"
5151
size="sm"
5252
color="pink-macaron"

0 commit comments

Comments
 (0)