Skip to content

Commit fb3a194

Browse files
committed
fix(fundings): Add selector on data table
1 parent 6e9ddb0 commit fb3a194

2 files changed

Lines changed: 64 additions & 31 deletions

File tree

client/src/boards/financements-par-aap/pages/structures/components/projects-data/datatable.tsx

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useEffect, useState } from "react";
33

44
import "./style.scss";
55

6-
export default function DataTable({ columns, dataTable, filters, numberOfResults, pagination, setFilters, setPagination, setSorting, sorting }) {
6+
export default function DataTable({ aggregations, columns, dataTable, filters, numberOfResults, pagination, setFilters, setPagination, setSorting, sorting }) {
77
const inputsTmp = {}
88
filters.forEach((filter) => {
99
inputsTmp[filter.id] = filter.value
@@ -56,18 +56,15 @@ export default function DataTable({ columns, dataTable, filters, numberOfResults
5656
}
5757
}
5858

59-
const handles = {
60-
county: (event) => setInputs({ ...inputs, county: event.target.value }),
61-
id: (event) => setInputs({ ...inputs, id: event.target.value }),
62-
instrument: (event) => setInputs({ ...inputs, instrument: event.target.value }),
63-
label: (event) => setInputs({ ...inputs, label: event.target.value }),
64-
participationIsCoordinator: (event) => setInputs({ ...inputs, participationIsCoordinator: event.target.value }),
65-
type: (event) => setInputs({ ...inputs, type: event.target.value }),
66-
year: (event) => setInputs({ ...inputs, year: event.target.value }),
59+
const handleFilter = (column: { id: string }, event) => {
60+
if (event.target.value === '') {
61+
const { [column.id]: _, ...rest } = inputs;
62+
setInputs(rest);
63+
} else {
64+
setInputs({ ...inputs, [column.id]: event.target.value });
65+
}
6766
}
6867

69-
const handleInputChange = (event, column) => handles[column.id](event)
70-
7168
useEffect(() => {
7269
const timeoutId = setTimeout(() => {
7370
setFilters(Object.keys(inputs).map((id) => ({ id, value: inputs[id] })).filter((filter) => filter.value.length > 0))
@@ -86,21 +83,40 @@ export default function DataTable({ columns, dataTable, filters, numberOfResults
8683
{column.isPlaceholder ? null : (
8784
<>
8885
<div>
89-
{column.label}
86+
{column?.label ?? column.id}
9087
{' '}
9188
{column?.isFilterable && <i className="ri-filter-line" />}
9289
{' '}
9390
{getSortableIcon(column)}
9491
</div>
9592
{column?.isFilterable && (
96-
<div>
97-
<input
98-
className="border"
99-
onChange={(event) => handleInputChange(event, column)}
100-
type="text"
93+
column?.isFilterableBySelect && aggregations?.[column.id] ? (
94+
<select
95+
name={`fundings-structure-data-${column.id}`}
96+
id={`fundings-structure-data-${column.id}`}
97+
className="fr-mb-2w fr-select"
10198
value={inputs[column.id]}
102-
/>
103-
</div>
99+
onChange={(event) => handleFilter(column, event)}
100+
>
101+
<option key='all' value=''>
102+
Tout
103+
</option>
104+
{(aggregations?.[column.id]?.buckets ?? []).map((bucket) => (
105+
<option key={bucket.key} value={bucket.key}>
106+
{bucket.key} ({bucket.doc_count})
107+
</option>
108+
))}
109+
</select>
110+
) : (
111+
<div>
112+
<input
113+
className="border"
114+
onChange={(event) => handleFilter(column, event)}
115+
type="text"
116+
value={inputs[column.id]}
117+
/>
118+
</div>
119+
)
104120
)}
105121
</>
106122
)}

client/src/boards/financements-par-aap/pages/structures/components/projects-data/index.tsx

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ import DataTable from "./datatable.tsx";
1010
const { VITE_APP_ES_INDEX_PARTICIPATIONS, VITE_APP_SERVER_URL } = import.meta.env;
1111

1212
type Column = {
13-
id: string
14-
isSortable: boolean
15-
label: string
13+
id: string,
14+
isFilterable?: boolean, // Is the column filterable, by default a simple tetx input is displayed. False if omitted
15+
isFilterableBySelect?: boolean, // If true and if an aggregation named like the colummn id exists, display a select, feeded by the aggregations buckets
16+
isSortable?: boolean, // Is the column sortable. False if omitted
17+
label?: string, // Column label as header. If omitted, the column id is displayed instead
18+
sortableField?: string, // Is the column sortable
1619
}
1720

1821
type Filter = {
@@ -54,25 +57,33 @@ export default function ProjectsData() {
5457
size: pagination?.size ?? 10,
5558
}
5659

60+
const aggregations = {
61+
county: { terms: { field: 'participant_region_with_labs.keyword' } },
62+
instrument: { terms: { field: 'project_instrument.keyword' } },
63+
participationIsCoordinator: { terms: { field: 'participation_is_coordinator' } },
64+
type: { terms: { field: 'project_type.keyword' } },
65+
year: { terms: { field: 'project_year' } },
66+
};
67+
5768
if (sorting?.id) {
5869
body.sort = { [sorting.id]: sorting.order }
5970
}
6071
if (filters.length > 0) {
6172
filters.forEach((filter) => {
6273
if (filter.id === 'county') {
63-
body.query.bool.filter.push({ query_string: { default_field: 'participant_region_with_labs.keyword', query: filter.value } })
74+
body.query.bool.filter.push({ match: { 'participant_region_with_labs.keyword': filter.value } })
6475
} else if (filter.id === 'id') {
6576
body.query.bool.filter.push({ match: { 'project_id.keyword': filter.value } })
6677
} else if (filter.id === 'instrument') {
67-
body.query.bool.filter.push({ match: { project_instrument: { query: filter.value } }})
78+
body.query.bool.filter.push({ match: { 'project_instrument.keyword': filter.value } })
6879
} else if (filter.id === 'label') {
6980
body.query.bool.filter.push({ query_string: { default_field: 'project_label.keyword', query: filter.value } })
7081
} else if (filter.id === 'participationIsCoordinator') {
71-
body.query.bool.filter.push({ query_string: { default_field: 'participation_is_coordinator', query: filter.value } })
82+
body.query.bool.filter.push({ term: { participation_is_coordinator: filter.value === "1" } })
7283
} else if (filter.id === 'type') {
73-
body.query.bool.filter.push({ wildcard: { 'project_type.keyword': { query: `*${filter.value}*`, case_insensitive: true } }})
84+
body.query.bool.filter.push({ match: { 'project_type.keyword': filter.value } })
7485
} else if (filter.id === 'year') {
75-
body.query.bool.filter.push({ query_string: { default_field: 'project_year', query: filter.value } })
86+
body.query.bool.filter.push({ match: { project_year: filter.value } })
7687
} else {
7788
console.error(`Filter id not supported : ${filter.id}`)
7889
}
@@ -93,10 +104,10 @@ export default function ProjectsData() {
93104
});
94105

95106
const { data: dataAll, isLoading: isLoadingAll } = useQuery({
96-
queryKey: ["fundings-data", filters, "all", sorting, structure, yearMax, yearMin],
107+
queryKey: ["fundings-data-all", structure, yearMax, yearMin],
97108
queryFn: () =>
98109
fetch(`${VITE_APP_SERVER_URL}/elasticsearch?index=${VITE_APP_ES_INDEX_PARTICIPATIONS}`, {
99-
body: JSON.stringify({ ...body, from: 0, size: 10000}),
110+
body: JSON.stringify({ ...body, from: 0, size: 10000, aggregations }),
100111
headers: {
101112
"Access-Control-Allow-Origin": "*",
102113
"Content-Type": "application/json",
@@ -106,7 +117,7 @@ export default function ProjectsData() {
106117
});
107118

108119
const dataTable: Project[] = (data?.hits?.hits ?? []).map((hit) => ({
109-
county: hit._source?.participant_region_with_labs,
120+
county: hit._source?.participant_region_with_labs.join(', '),
110121
id: hit._source?.project_id,
111122
instrument: hit._source?.project_instrument,
112123
label: hit._source?.project_label,
@@ -120,7 +131,7 @@ export default function ProjectsData() {
120131
const numberOfResults = data?.hits?.total?.value ?? 0
121132

122133
const dataTableAll: Project[] = (dataAll?.hits?.hits ?? []).map((hit) => ({
123-
county: hit._source?.participant_region_with_labs,
134+
county: hit._source?.participant_region_with_labs.join(', '),
124135
id: hit._source?.project_id,
125136
instrument: hit._source?.project_instrument,
126137
label: hit._source?.project_label,
@@ -136,13 +147,15 @@ export default function ProjectsData() {
136147
{
137148
id: 'year',
138149
isFilterable: true,
150+
isFilterableBySelect: true,
139151
isSortable: true,
140152
label: 'Année',
141153
sortableField: 'project_year',
142154
},
143155
{
144156
id: 'type',
145157
isFilterable: true,
158+
isFilterableBySelect: true,
146159
isSortable: true,
147160
label: 'Type',
148161
sortableField: 'project_type.keyword',
@@ -156,6 +169,7 @@ export default function ProjectsData() {
156169
{
157170
id: 'county',
158171
isFilterable: true,
172+
isFilterableBySelect: true,
159173
isSortable: false,
160174
label: 'Région',
161175
},
@@ -168,13 +182,15 @@ export default function ProjectsData() {
168182
{
169183
id: 'instrument',
170184
isFilterable: true,
185+
isFilterableBySelect: true,
171186
isSortable: true,
172187
label: 'Instrument de financement',
173188
sortableField: 'project_instrument.keyword',
174189
},
175190
{
176191
id: 'participationIsCoordinator',
177192
isFilterable: true,
193+
isFilterableBySelect: true,
178194
isSortable: true,
179195
label: 'Coordinateur',
180196
sortableField: 'participation_is_coordinator',
@@ -245,6 +261,7 @@ export default function ProjectsData() {
245261
<Row>
246262
<Col>
247263
<DataTable
264+
aggregations={dataAll?.aggregations ?? {}}
248265
columns={columns}
249266
dataTable={dataTable}
250267
filters={filters}

0 commit comments

Comments
 (0)