Skip to content

Commit 99220d6

Browse files
committed
[DOP-27446] Allow to filter datatasets & jobs by tags
1 parent f4726b8 commit 99220d6

File tree

6 files changed

+150
-23
lines changed

6 files changed

+150
-23
lines changed

src/components/dataset/DatasetRaListFilters.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Box, InputAdornment } from "@mui/material";
44
import SearchIcon from "@mui/icons-material/Search";
55
import { TextInput } from "react-admin";
66
import { LocationRaTypeFilter } from "@/components/location";
7+
import TagsRaFilter from "@/components/tag/TagsRaFilter";
78

89
const DatasetRaListFilters = ({
910
withLocationType = true,
@@ -14,12 +15,31 @@ const DatasetRaListFilters = ({
1415
<FilterLiveForm>
1516
<Box display="flex" alignItems="flex-end">
1617
{withLocationType && (
17-
<Box component="span" mr={2} sx={{ flex: "0.2" }}>
18+
<Box
19+
component="span"
20+
mr={2}
21+
sx={{ flex: "0.2", minWidth: "50px" }}
22+
>
1823
<LocationRaTypeFilter />
1924
</Box>
2025
)}
2126

22-
<Box component="span" mr={2} sx={{ flex: "0.3 1 1" }}>
27+
<Box
28+
component="span"
29+
mr={2}
30+
sx={{ flex: "0.3", minWidth: "50px" }}
31+
>
32+
<TagsRaFilter
33+
label="resources.datasets.filters.tags.label"
34+
helperText="resources.datasets.filters.tags.helperText"
35+
/>
36+
</Box>
37+
38+
<Box
39+
component="span"
40+
mr={2}
41+
sx={{ flex: "0.3", minWidth: "50px" }}
42+
>
2343
{/* Not using SearchInput here because it doesn't match styles with other filters */}
2444
<TextInput
2545
source="search_query"

src/components/job/JobRaListFilters.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import SearchIcon from "@mui/icons-material/Search";
55
import { TextInput } from "react-admin";
66
import JobTypeRaFilter from "./JobRaTypeFilter";
77
import { LocationRaTypeFilter } from "../location";
8+
import TagsRaFilter from "@/components/tag/TagsRaFilter";
89

910
const JobRaListFilters = ({
1011
withLocationType = true,
@@ -24,7 +25,22 @@ const JobRaListFilters = ({
2425
<JobTypeRaFilter />
2526
</Box>
2627

27-
<Box component="span" mr={2} sx={{ flex: "0.3 1 1" }}>
28+
<Box
29+
component="span"
30+
mr={2}
31+
sx={{ flex: "0.3", minWidth: "50px" }}
32+
>
33+
<TagsRaFilter
34+
label="resources.jobs.filters.tags.label"
35+
helperText="resources.jobs.filters.tags.helperText"
36+
/>
37+
</Box>
38+
39+
<Box
40+
component="span"
41+
mr={2}
42+
sx={{ flex: "0.3", minWidth: "50px" }}
43+
>
2844
{/* Not using SearchInput here because it doesn't match styles with other filters */}
2945
<TextInput
3046
source="search_query"
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { TagDetailedResponseV1 } from "@/dataProvider/types";
2+
import { useMemo, useState } from "react";
3+
import {
4+
useGetList,
5+
AutocompleteArrayInput,
6+
AutocompleteArrayInputProps,
7+
} from "react-admin";
8+
9+
type TagsRaFilterProps = Omit<
10+
AutocompleteArrayInputProps,
11+
| "source"
12+
| "choices"
13+
| "value"
14+
| "optionValue"
15+
| "optionText"
16+
| "onChange"
17+
| "isPending"
18+
| "loading"
19+
| "onInputChange"
20+
| "shouldRenderSuggestions"
21+
>;
22+
23+
const TagsRaFilter = (props: TagsRaFilterProps) => {
24+
const [searchQuery, setSearchQuery] = useState<string>("");
25+
const [selectedTagValues, setSelectedTagValues] =
26+
useState<TagDetailedResponseV1[]>();
27+
28+
const tagFilter =
29+
searchQuery.length > 2 ? { search_query: searchQuery } : {};
30+
31+
const { data, isPending, isLoading } = useGetList<TagDetailedResponseV1>(
32+
"tags",
33+
{ filter: tagFilter },
34+
);
35+
36+
const tagValues = useMemo(
37+
() =>
38+
data?.flatMap((tag) => {
39+
const tagInfo = tag;
40+
return (
41+
tag.data.values.map((tagValue) => ({
42+
label: `${tagInfo.data.name}:${tagValue.value}`,
43+
...tagValue,
44+
})) ?? []
45+
);
46+
}),
47+
[data],
48+
);
49+
50+
return (
51+
<AutocompleteArrayInput
52+
source="tag_value_id"
53+
choices={tagValues}
54+
value={selectedTagValues}
55+
optionValue="id"
56+
optionText="label"
57+
isPending={isPending}
58+
loading={isLoading}
59+
onChange={(value) => setSelectedTagValues(value)}
60+
onInputChange={(_e, value) => setSearchQuery(value)}
61+
shouldRenderSuggestions={(val: string) => {
62+
return val.trim().length === 0 || val.trim().length > 2;
63+
}}
64+
{...props}
65+
/>
66+
);
67+
};
68+
69+
export default TagsRaFilter;

src/dataProvider/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ interface TagResponseV1 {
4444
values: TagValueResponseV1[];
4545
}
4646

47+
interface TagDetailedResponseV1 {
48+
id: string;
49+
data: TagResponseV1;
50+
}
51+
4752
interface DatasetResponseV1 extends RaRecord {
4853
id: string;
4954
type: string;
@@ -338,5 +343,6 @@ export type {
338343
PersonalTokenDetailedResponseV1,
339344
PersonalTokenCreateDetailedResponseV1,
340345
TagResponseV1,
346+
TagDetailedResponseV1,
341347
TagValueResponseV1,
342348
};

src/i18n/en.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ const customEnglishMessages: TranslationMessages = {
5858
filters: {
5959
location_type: {
6060
label: "Location Type",
61-
helperText: "Only selected",
61+
helperText: "With any of selected types",
6262
},
6363
search_query: {
6464
label: "Search",
65-
helperText: "Filter by name or address",
65+
helperText: "Search by name or address",
6666
},
6767
},
6868
tabs: {
@@ -88,7 +88,7 @@ const customEnglishMessages: TranslationMessages = {
8888
},
8989
search: {
9090
name: "Search",
91-
placeholder: "Filter by name",
91+
placeholder: "Search by name",
9292
},
9393
pagination: {
9494
all: "All",
@@ -101,11 +101,15 @@ const customEnglishMessages: TranslationMessages = {
101101
filters: {
102102
location_type: {
103103
label: "Location Type",
104-
helperText: "Only selected",
104+
helperText: "With location type",
105105
},
106106
search_query: {
107107
label: "Search",
108-
helperText: "Filter by name or address",
108+
helperText: "Search by name or address",
109+
},
110+
tags: {
111+
label: "Tags",
112+
helperText: "With all selected tags",
109113
},
110114
},
111115
},
@@ -134,15 +138,19 @@ const customEnglishMessages: TranslationMessages = {
134138
filters: {
135139
location_type: {
136140
label: "Location Type",
137-
helperText: "Only selected",
141+
helperText: "With any location types",
138142
},
139143
job_type: {
140144
label: "Job Type",
141-
helperText: "Only selected",
145+
helperText: "With any job types",
142146
},
143147
search_query: {
144148
label: "Search",
145-
helperText: "Filter by name or address",
149+
helperText: "Search by name or address",
150+
},
151+
tags: {
152+
label: "Tags",
153+
helperText: "With all tags",
146154
},
147155
},
148156
},
@@ -211,7 +219,7 @@ const customEnglishMessages: TranslationMessages = {
211219
},
212220
status: {
213221
label: "Status",
214-
helperText: "Only selected",
222+
helperText: "With status",
215223
},
216224
started_by_user: {
217225
label: "Started by user",
@@ -220,7 +228,7 @@ const customEnglishMessages: TranslationMessages = {
220228
search_query: {
221229
label: "Search",
222230
helperText:
223-
"Filter by external ID (including partial match)",
231+
"Search by external ID (including partial match)",
224232
},
225233
apply_button: "Apply",
226234
},

src/i18n/ru.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ const customRussianMessages: TranslationMessages = {
5858
filters: {
5959
location_type: {
6060
label: "Тип расположения",
61-
helperText: "Только выбранные",
61+
helperText: "Любой из типов расположения",
6262
},
6363
search_query: {
6464
label: "Поиск",
65-
helperText: "Фильтр по имени или адресу",
65+
helperText: "Поиск по имени или адресу",
6666
},
6767
},
6868
tabs: {
@@ -88,7 +88,7 @@ const customRussianMessages: TranslationMessages = {
8888
},
8989
search: {
9090
name: "Поиск",
91-
placeholder: "Фильтр по имени",
91+
placeholder: "Поиск по имени",
9292
},
9393
pagination: {
9494
all: "Все",
@@ -101,11 +101,15 @@ const customRussianMessages: TranslationMessages = {
101101
filters: {
102102
location_type: {
103103
label: "Тип расположения",
104-
helperText: "Только выбранные",
104+
helperText: "Любой из типов расположения",
105105
},
106106
search_query: {
107107
label: "Поиск",
108-
helperText: "Фильтр по имени или адресу",
108+
helperText: "Поиск по имени или адресу",
109+
},
110+
tags: {
111+
label: "Теги",
112+
helperText: "Со всеми выбранными тегами",
109113
},
110114
},
111115
},
@@ -134,15 +138,19 @@ const customRussianMessages: TranslationMessages = {
134138
filters: {
135139
location_type: {
136140
label: "Тип расположения",
137-
helperText: "Только выбранные",
141+
helperText: "С одним из типов расположения",
138142
},
139143
job_type: {
140144
label: "Тип джобы",
141-
helperText: "Только выбранные",
145+
helperText: "С одним из типов джобы",
142146
},
143147
search_query: {
144148
label: "Поиск",
145-
helperText: "Фильтр по имени или адресу",
149+
helperText: "Поиск по имени или адресу",
150+
},
151+
tags: {
152+
label: "Теги",
153+
helperText: "Со всеми выбранными тегами",
146154
},
147155
},
148156
},
@@ -210,15 +218,15 @@ const customRussianMessages: TranslationMessages = {
210218
},
211219
status: {
212220
label: "Статус",
213-
helperText: "Только выбранные",
221+
helperText: "С одним из выбранных статусов",
214222
},
215223
started_by_user: {
216224
label: "Запущен пользователем",
217225
helperText: "Имя пользователя (точное совпадение)",
218226
},
219227
search_query: {
220228
label: "Поиск",
221-
helperText: "Фильтр по внешнему ID (частичное совпадение)",
229+
helperText: "Поиск по внешнему ID (частичное совпадение)",
222230
},
223231
apply_button: "Применить",
224232
},

0 commit comments

Comments
 (0)