@strapi/admin 5.39.0 → 5.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/admin/src/components/Filters.js +109 -69
- package/dist/admin/admin/src/components/Filters.js.map +1 -1
- package/dist/admin/admin/src/components/Filters.mjs +109 -69
- package/dist/admin/admin/src/components/Filters.mjs.map +1 -1
- package/dist/admin/admin/src/pages/Home/HomePage.js +102 -28
- package/dist/admin/admin/src/pages/Home/HomePage.js.map +1 -1
- package/dist/admin/admin/src/pages/Home/HomePage.mjs +103 -29
- package/dist/admin/admin/src/pages/Home/HomePage.mjs.map +1 -1
- package/dist/admin/admin/src/translations/en.json.js +1 -0
- package/dist/admin/admin/src/translations/en.json.js.map +1 -1
- package/dist/admin/admin/src/translations/en.json.mjs +1 -0
- package/dist/admin/admin/src/translations/en.json.mjs.map +1 -1
- package/dist/admin/src/components/Filters.d.ts +3 -1
- package/package.json +10 -10
|
@@ -11,7 +11,39 @@ import { Form } from './Form.mjs';
|
|
|
11
11
|
import { InputRenderer as MemoizedInputRenderer } from './FormInputs/Renderer.mjs';
|
|
12
12
|
|
|
13
13
|
const [FiltersProvider, useFilters] = createContext('Filters');
|
|
14
|
+
const getFilterDetails = (filterEntry, options)=>{
|
|
15
|
+
const [name] = Object.keys(filterEntry);
|
|
16
|
+
const option = options.find((o)=>o.name === name);
|
|
17
|
+
if (!option) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const operatorObj = option.type === 'relation' ? filterEntry[name]?.[option.mainField?.name ?? 'id'] : filterEntry[name];
|
|
21
|
+
if (typeof operatorObj !== 'object' || operatorObj === null) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const [operator] = Object.keys(operatorObj);
|
|
25
|
+
if (!operator) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
name,
|
|
30
|
+
operator,
|
|
31
|
+
value: operatorObj[operator]
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
const isFilterMatch = (filterEntry, options, target)=>{
|
|
35
|
+
const details = getFilterDetails(filterEntry, options);
|
|
36
|
+
if (!details || details.name !== target.name || details.operator !== target.filter) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
if (FILTERS_WITH_NO_VALUE.includes(target.filter)) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
const decoded = typeof details.value === 'string' ? decodeURIComponent(details.value) : details.value;
|
|
43
|
+
return decoded === target.value;
|
|
44
|
+
};
|
|
14
45
|
const Root = ({ children, disabled = false, onChange, options = [], onOpenChange, open: openProp, defaultOpen, ...restProps })=>{
|
|
46
|
+
const [editingFilter, setEditingFilter] = React.useState(null);
|
|
15
47
|
const handleChange = (data)=>{
|
|
16
48
|
if (onChange) {
|
|
17
49
|
onChange(data);
|
|
@@ -22,6 +54,13 @@ const Root = ({ children, disabled = false, onChange, options = [], onOpenChange
|
|
|
22
54
|
defaultProp: defaultOpen,
|
|
23
55
|
onChange: onOpenChange
|
|
24
56
|
});
|
|
57
|
+
React.useEffect(()=>{
|
|
58
|
+
if (!open) {
|
|
59
|
+
setEditingFilter(null);
|
|
60
|
+
}
|
|
61
|
+
}, [
|
|
62
|
+
open
|
|
63
|
+
]);
|
|
25
64
|
return /*#__PURE__*/ jsx(Popover.Root, {
|
|
26
65
|
open: open,
|
|
27
66
|
onOpenChange: setOpen,
|
|
@@ -31,6 +70,8 @@ const Root = ({ children, disabled = false, onChange, options = [], onOpenChange
|
|
|
31
70
|
disabled: disabled,
|
|
32
71
|
onChange: handleChange,
|
|
33
72
|
options: options,
|
|
73
|
+
editingFilter: editingFilter,
|
|
74
|
+
setEditingFilter: setEditingFilter,
|
|
34
75
|
children: children
|
|
35
76
|
})
|
|
36
77
|
});
|
|
@@ -68,6 +109,17 @@ const Root = ({ children, disabled = false, onChange, options = [], onOpenChange
|
|
|
68
109
|
const options = useFilters('Popover', ({ options })=>options);
|
|
69
110
|
const onChange = useFilters('Popover', ({ onChange })=>onChange);
|
|
70
111
|
const setOpen = useFilters('Popover', ({ setOpen })=>setOpen);
|
|
112
|
+
const editingFilter = useFilters('Popover', ({ editingFilter })=>editingFilter);
|
|
113
|
+
const setEditingFilter = useFilters('Popover', ({ setEditingFilter })=>setEditingFilter);
|
|
114
|
+
const initialValues = React.useMemo(()=>{
|
|
115
|
+
return editingFilter ?? {
|
|
116
|
+
name: options[0]?.name,
|
|
117
|
+
filter: BASE_FILTERS[0].value
|
|
118
|
+
};
|
|
119
|
+
}, [
|
|
120
|
+
editingFilter,
|
|
121
|
+
options
|
|
122
|
+
]);
|
|
71
123
|
if (options.length === 0) {
|
|
72
124
|
return null;
|
|
73
125
|
}
|
|
@@ -94,15 +146,20 @@ const Root = ({ children, disabled = false, onChange, options = [], onOpenChange
|
|
|
94
146
|
*/ const operatorValuePairing = {
|
|
95
147
|
[data.filter]: value
|
|
96
148
|
};
|
|
97
|
-
const
|
|
149
|
+
const newFilterEntry = {
|
|
150
|
+
[data.name]: fieldOptions.type === 'relation' ? {
|
|
151
|
+
[fieldOptions.mainField?.name ?? 'id']: operatorValuePairing
|
|
152
|
+
} : operatorValuePairing
|
|
153
|
+
};
|
|
154
|
+
const existingFilters = query.filters?.$and ?? [];
|
|
155
|
+
const newFilterQuery = editingFilter ? {
|
|
156
|
+
...query.filters,
|
|
157
|
+
$and: existingFilters.map((filter)=>isFilterMatch(filter, options, editingFilter) ? newFilterEntry : filter)
|
|
158
|
+
} : {
|
|
98
159
|
...query.filters,
|
|
99
160
|
$and: [
|
|
100
|
-
...
|
|
101
|
-
|
|
102
|
-
[data.name]: fieldOptions.type === 'relation' ? {
|
|
103
|
-
[fieldOptions.mainField?.name ?? 'id']: operatorValuePairing
|
|
104
|
-
} : operatorValuePairing
|
|
105
|
-
}
|
|
161
|
+
...existingFilters,
|
|
162
|
+
newFilterEntry
|
|
106
163
|
]
|
|
107
164
|
};
|
|
108
165
|
setQuery({
|
|
@@ -110,6 +167,7 @@ const Root = ({ children, disabled = false, onChange, options = [], onOpenChange
|
|
|
110
167
|
page: 1
|
|
111
168
|
}, 'push', true);
|
|
112
169
|
setOpen(false);
|
|
170
|
+
setEditingFilter(null);
|
|
113
171
|
};
|
|
114
172
|
return /*#__PURE__*/ jsx(Popover.Content, {
|
|
115
173
|
style: {
|
|
@@ -119,10 +177,7 @@ const Root = ({ children, disabled = false, onChange, options = [], onOpenChange
|
|
|
119
177
|
padding: 3,
|
|
120
178
|
children: /*#__PURE__*/ jsx(Form, {
|
|
121
179
|
method: "POST",
|
|
122
|
-
initialValues:
|
|
123
|
-
name: options[0]?.name,
|
|
124
|
-
filter: BASE_FILTERS[0].value
|
|
125
|
-
},
|
|
180
|
+
initialValues: initialValues,
|
|
126
181
|
onSubmit: handleSubmit,
|
|
127
182
|
children: ({ values: formValues, modified, isSubmitting })=>{
|
|
128
183
|
const filter = options.find((filter)=>filter.name === formValues.name);
|
|
@@ -171,7 +226,7 @@ const Root = ({ children, disabled = false, onChange, options = [], onOpenChange
|
|
|
171
226
|
].map((field)=>/*#__PURE__*/ jsx(MemoizedInputRenderer, {
|
|
172
227
|
...field
|
|
173
228
|
}, field.name)),
|
|
174
|
-
filter && formValues.filter &&
|
|
229
|
+
filter && formValues.filter && !FILTERS_WITH_NO_VALUE.includes(formValues.filter) ? /*#__PURE__*/ jsx(Input, {
|
|
175
230
|
...filter,
|
|
176
231
|
label: null,
|
|
177
232
|
"aria-label": filter.label,
|
|
@@ -186,7 +241,10 @@ const Root = ({ children, disabled = false, onChange, options = [], onOpenChange
|
|
|
186
241
|
startIcon: /*#__PURE__*/ jsx(Plus, {}),
|
|
187
242
|
type: "submit",
|
|
188
243
|
fullWidth: true,
|
|
189
|
-
children: formatMessage({
|
|
244
|
+
children: editingFilter ? formatMessage({
|
|
245
|
+
id: 'app.utils.update-filter',
|
|
246
|
+
defaultMessage: 'Update filter'
|
|
247
|
+
}) : formatMessage({
|
|
190
248
|
id: 'app.utils.add-filter',
|
|
191
249
|
defaultMessage: 'Add filter'
|
|
192
250
|
})
|
|
@@ -194,7 +252,7 @@ const Root = ({ children, disabled = false, onChange, options = [], onOpenChange
|
|
|
194
252
|
]
|
|
195
253
|
});
|
|
196
254
|
}
|
|
197
|
-
})
|
|
255
|
+
}, editingFilter ? `edit-${editingFilter.name}-${editingFilter.filter}-${editingFilter.value ?? 'empty'}` : 'create')
|
|
198
256
|
})
|
|
199
257
|
});
|
|
200
258
|
};
|
|
@@ -264,25 +322,11 @@ const Root = ({ children, disabled = false, onChange, options = [], onOpenChange
|
|
|
264
322
|
* Check the name, operator and value to see if it already exists in the query
|
|
265
323
|
* if it does, remove it.
|
|
266
324
|
*/ const nextFilters = (query?.filters?.$and ?? []).filter((filter)=>{
|
|
267
|
-
const
|
|
268
|
-
if (
|
|
325
|
+
const details = getFilterDetails(filter, options);
|
|
326
|
+
if (!details) {
|
|
269
327
|
return true;
|
|
270
328
|
}
|
|
271
|
-
|
|
272
|
-
if (type === 'relation') {
|
|
273
|
-
const filterObj = filter[attributeName][mainField?.name ?? 'id'];
|
|
274
|
-
if (typeof filterObj === 'object') {
|
|
275
|
-
const [operator] = Object.keys(filterObj);
|
|
276
|
-
const value = filterObj[operator];
|
|
277
|
-
return !(operator === data.filter && value === data.value);
|
|
278
|
-
}
|
|
279
|
-
return true;
|
|
280
|
-
} else {
|
|
281
|
-
const filterObj = filter[attributeName];
|
|
282
|
-
const [operator] = Object.keys(filterObj);
|
|
283
|
-
const value = filterObj[operator];
|
|
284
|
-
return !(operator === data.filter && value === data.value);
|
|
285
|
-
}
|
|
329
|
+
return !(details.name === data.name && details.operator === data.filter && details.value === data.value);
|
|
286
330
|
});
|
|
287
331
|
setQuery({
|
|
288
332
|
filters: {
|
|
@@ -296,48 +340,37 @@ const Root = ({ children, disabled = false, onChange, options = [], onOpenChange
|
|
|
296
340
|
}
|
|
297
341
|
return /*#__PURE__*/ jsx(Fragment, {
|
|
298
342
|
children: query?.filters?.$and?.map((queryFilter)=>{
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
const filterObj = queryFilter[attributeName];
|
|
302
|
-
if (!filter || typeof filterObj !== 'object' || filterObj === null) {
|
|
343
|
+
const details = getFilterDetails(queryFilter, options);
|
|
344
|
+
if (!details || typeof details.value === 'object') {
|
|
303
345
|
return null;
|
|
304
346
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
if (typeof modelFilter === 'object') {
|
|
308
|
-
const [operator] = Object.keys(modelFilter);
|
|
309
|
-
const value = modelFilter[operator];
|
|
310
|
-
return /*#__PURE__*/ jsx(AttributeTag, {
|
|
311
|
-
...filter,
|
|
312
|
-
onClick: handleClick,
|
|
313
|
-
operator: operator,
|
|
314
|
-
value: value
|
|
315
|
-
}, `${attributeName}-${operator}-${value}`);
|
|
316
|
-
}
|
|
347
|
+
const filter = options.find(({ name })=>name === details.name);
|
|
348
|
+
if (!filter) {
|
|
317
349
|
return null;
|
|
318
|
-
} else {
|
|
319
|
-
const [operator] = Object.keys(filterObj);
|
|
320
|
-
const value = filterObj[operator];
|
|
321
|
-
/**
|
|
322
|
-
* Something has gone wrong here, because the attribute is not a relation
|
|
323
|
-
* but we have a nested filter object.
|
|
324
|
-
*/ if (typeof value === 'object') {
|
|
325
|
-
return null;
|
|
326
|
-
}
|
|
327
|
-
return /*#__PURE__*/ jsx(AttributeTag, {
|
|
328
|
-
...filter,
|
|
329
|
-
onClick: handleClick,
|
|
330
|
-
operator: operator,
|
|
331
|
-
value: value
|
|
332
|
-
}, `${attributeName}-${operator}-${value}`);
|
|
333
350
|
}
|
|
351
|
+
return /*#__PURE__*/ jsx(AttributeTag, {
|
|
352
|
+
...filter,
|
|
353
|
+
onRemove: handleClick,
|
|
354
|
+
operator: details.operator,
|
|
355
|
+
value: String(details.value)
|
|
356
|
+
}, `${details.name}-${details.operator}-${details.value}`);
|
|
334
357
|
})
|
|
335
358
|
});
|
|
336
359
|
};
|
|
337
|
-
const AttributeTag = ({ input, label, mainField, name,
|
|
360
|
+
const AttributeTag = ({ input, label, mainField, name, onRemove, operator, options, value, ...filter })=>{
|
|
338
361
|
const { formatMessage, formatDate, formatTime, formatNumber } = useIntl();
|
|
339
|
-
const
|
|
340
|
-
|
|
362
|
+
const setOpen = useFilters('AttributeTag', ({ setOpen })=>setOpen);
|
|
363
|
+
const setEditingFilter = useFilters('AttributeTag', ({ setEditingFilter })=>setEditingFilter);
|
|
364
|
+
const handleEdit = ()=>{
|
|
365
|
+
setEditingFilter({
|
|
366
|
+
name,
|
|
367
|
+
filter: operator,
|
|
368
|
+
value: FILTERS_WITH_NO_VALUE.includes(operator) ? undefined : decodeURIComponent(value)
|
|
369
|
+
});
|
|
370
|
+
setOpen(true);
|
|
371
|
+
};
|
|
372
|
+
const handleRemove = ()=>{
|
|
373
|
+
onRemove({
|
|
341
374
|
name,
|
|
342
375
|
value,
|
|
343
376
|
filter: operator
|
|
@@ -382,15 +415,22 @@ const AttributeTag = ({ input, label, mainField, name, onClick, operator, option
|
|
|
382
415
|
});
|
|
383
416
|
formattedValue = selectedOption ? typeof selectedOption === 'string' ? selectedOption : selectedOption.label ?? selectedOption.value : value;
|
|
384
417
|
}
|
|
385
|
-
const
|
|
418
|
+
const operatorLabel = formatMessage({
|
|
386
419
|
id: `components.FilterOptions.FILTER_TYPES.${operator}`,
|
|
387
420
|
defaultMessage: operator
|
|
388
|
-
})
|
|
421
|
+
});
|
|
422
|
+
const content = FILTERS_WITH_NO_VALUE.includes(operator) ? `${label} ${operatorLabel}` : `${label} ${operatorLabel} ${formattedValue}`;
|
|
389
423
|
return /*#__PURE__*/ jsx(Tag, {
|
|
390
424
|
padding: 1,
|
|
391
|
-
onClick:
|
|
425
|
+
onClick: handleRemove,
|
|
392
426
|
icon: /*#__PURE__*/ jsx(Cross, {}),
|
|
393
|
-
|
|
427
|
+
label: content,
|
|
428
|
+
children: /*#__PURE__*/ jsx(Box, {
|
|
429
|
+
tag: "span",
|
|
430
|
+
cursor: "pointer",
|
|
431
|
+
onClick: handleEdit,
|
|
432
|
+
children: content
|
|
433
|
+
})
|
|
394
434
|
});
|
|
395
435
|
};
|
|
396
436
|
/* -------------------------------------------------------------------------------------------------
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Filters.mjs","sources":["../../../../../admin/src/components/Filters.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Box, Button, Flex, Popover, Tag } from '@strapi/design-system';\nimport { Plus, Filter as FilterIcon, Cross } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\n\nimport {\n BASE_FILTERS,\n CONTAINS_FILTERS,\n FilterOption,\n IS_SENSITIVE_FILTERS,\n NUMERIC_FILTERS,\n STRING_PARSE_FILTERS,\n FILTERS_WITH_NO_VALUE,\n} from '../constants/filters';\nimport { useControllableState } from '../hooks/useControllableState';\nimport { useQueryParams } from '../hooks/useQueryParams';\n\nimport { createContext } from './Context';\nimport { Form, InputProps } from './Form';\nimport { InputRenderer } from './FormInputs/Renderer';\n\nimport type { Schema } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * Root\n * -----------------------------------------------------------------------------------------------*/\n\ninterface FilterFormData {\n name: string;\n filter: string;\n value?: string;\n}\n\ninterface FitlersContextValue {\n disabled: boolean;\n onChange: (data: FilterFormData) => void;\n options: Filters.Filter[];\n setOpen: (open: boolean) => void;\n}\n\nconst [FiltersProvider, useFilters] = createContext<FitlersContextValue>('Filters');\n\ninterface RootProps extends Partial<FitlersContextValue>, Popover.Props {\n children: React.ReactNode;\n}\n\nconst Root = ({\n children,\n disabled = false,\n onChange,\n options = [],\n onOpenChange,\n open: openProp,\n defaultOpen,\n ...restProps\n}: RootProps) => {\n const handleChange = (data: FilterFormData) => {\n if (onChange) {\n onChange(data);\n }\n };\n const [open = false, setOpen] = useControllableState({\n prop: openProp,\n defaultProp: defaultOpen,\n onChange: onOpenChange,\n });\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen} {...restProps}>\n <FiltersProvider\n setOpen={setOpen}\n disabled={disabled}\n onChange={handleChange}\n options={options}\n >\n {children}\n </FiltersProvider>\n </Popover.Root>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * Trigger\n * -----------------------------------------------------------------------------------------------*/\n\nconst Trigger = React.forwardRef<HTMLButtonElement, Filters.TriggerProps>(\n ({ label }, forwardedRef) => {\n const { formatMessage } = useIntl();\n const disabled = useFilters('Trigger', ({ disabled }) => disabled);\n\n return (\n <Popover.Trigger>\n <Button\n variant=\"tertiary\"\n ref={forwardedRef}\n startIcon={<FilterIcon />}\n size=\"S\"\n disabled={disabled}\n >\n {label || formatMessage({ id: 'app.utils.filters', defaultMessage: 'Filters' })}\n </Button>\n </Popover.Trigger>\n );\n }\n);\n\n/* -------------------------------------------------------------------------------------------------\n * Popover\n * -----------------------------------------------------------------------------------------------*/\n/**\n * The zIndex property is used to override the zIndex of the Portal element of the Popover.\n * This is needed to ensure that the DatePicker is rendered above the Popover when opened.\n * The issue was that both the DatePicker and the Popover are rendered in a Portal and have the same zIndex.\n * On init, since the DatePicker is rendered before the Popover in the DOM,\n * it's causing the issue of appearing behind the Popover.\n */\nconst PopoverImpl = ({ zIndex }: { zIndex?: number }) => {\n const [{ query }, setQuery] = useQueryParams<Filters.Query>();\n const { formatMessage } = useIntl();\n const options = useFilters('Popover', ({ options }) => options);\n const onChange = useFilters('Popover', ({ onChange }) => onChange);\n const setOpen = useFilters('Popover', ({ setOpen }) => setOpen);\n\n if (options.length === 0) {\n return null;\n }\n\n const handleSubmit = (data: FilterFormData) => {\n const value = FILTERS_WITH_NO_VALUE.includes(data.filter)\n ? 'true'\n : encodeURIComponent(data.value ?? '');\n\n if (!value) {\n return;\n }\n\n if (onChange) {\n onChange(data);\n }\n\n /**\n * There will ALWAYS be an option because we use the options to create the form data.\n */\n const fieldOptions = options.find((filter) => filter.name === data.name)!;\n\n /**\n * If the filter is a relation, we need to nest the filter object,\n * we filter based on the mainField of the relation, if there is no mainField, we use the id.\n * At the end, we pass the operator & value. This value _could_ look like:\n * ```json\n * {\n * \"$eq\": \"1\",\n * }\n * ```\n */\n const operatorValuePairing = {\n [data.filter]: value,\n };\n\n const newFilterQuery = {\n ...query.filters,\n $and: [\n ...(query.filters?.$and ?? []),\n {\n [data.name]:\n fieldOptions.type === 'relation'\n ? {\n [fieldOptions.mainField?.name ?? 'id']: operatorValuePairing,\n }\n : operatorValuePairing,\n },\n ],\n };\n\n setQuery({ filters: newFilterQuery, page: 1 }, 'push', true);\n setOpen(false);\n };\n\n return (\n <Popover.Content style={{ zIndex }}>\n <Box padding={3}>\n <Form\n method=\"POST\"\n initialValues={\n {\n name: options[0]?.name,\n filter: BASE_FILTERS[0].value,\n } satisfies FilterFormData\n }\n onSubmit={handleSubmit}\n >\n {({ values: formValues, modified, isSubmitting }) => {\n const filter = options.find((filter) => filter.name === formValues.name);\n const Input = filter?.input || InputRenderer;\n return (\n <Flex direction=\"column\" alignItems=\"stretch\" gap={2} style={{ minWidth: 184 }}>\n {[\n {\n ['aria-label']: formatMessage({\n id: 'app.utils.select-field',\n defaultMessage: 'Select field',\n }),\n name: 'name',\n options: options.map((filter) => ({\n label: filter.label,\n value: filter.name,\n })),\n placholder: formatMessage({\n id: 'app.utils.select-field',\n defaultMessage: 'Select field',\n }),\n type: 'enumeration' as const,\n },\n {\n ['aria-label']: formatMessage({\n id: 'app.utils.select-filter',\n defaultMessage: 'Select filter',\n }),\n name: 'filter',\n options:\n filter?.operators ||\n getFilterList(filter).map((opt) => ({\n label: formatMessage(opt.label),\n value: opt.value,\n })),\n placeholder: formatMessage({\n id: 'app.utils.select-filter',\n defaultMessage: 'Select filter',\n }),\n type: 'enumeration' as const,\n },\n ].map((field) => (\n <InputRenderer key={field.name} {...field} />\n ))}\n {filter &&\n formValues.filter &&\n formValues.filter !== '$null' &&\n formValues.filter !== '$notNull' ? (\n <Input\n {...filter}\n label={null}\n aria-label={filter.label}\n name=\"value\"\n // @ts-expect-error – if type is `custom` then `Input` will be a custom component.\n type={filter.mainField?.type ?? filter.type}\n />\n ) : null}\n <Button\n disabled={!modified || isSubmitting}\n size=\"L\"\n variant=\"secondary\"\n startIcon={<Plus />}\n type=\"submit\"\n fullWidth\n >\n {formatMessage({ id: 'app.utils.add-filter', defaultMessage: 'Add filter' })}\n </Button>\n </Flex>\n );\n }}\n </Form>\n </Box>\n </Popover.Content>\n );\n};\n\n/**\n * Depending on the selected field find the possible filters to apply\n */\nconst getFilterList = (filter?: Filters.Filter): FilterOption[] => {\n if (!filter) {\n return [];\n }\n\n const type = filter.mainField?.type ? filter.mainField.type : filter.type;\n\n switch (type) {\n case 'email':\n case 'text':\n case 'string': {\n return [\n ...BASE_FILTERS,\n ...IS_SENSITIVE_FILTERS,\n ...CONTAINS_FILTERS,\n ...STRING_PARSE_FILTERS,\n ];\n }\n\n case 'float':\n case 'integer':\n case 'biginteger':\n case 'decimal': {\n return [...BASE_FILTERS, ...NUMERIC_FILTERS];\n }\n case 'time':\n case 'date': {\n return [...BASE_FILTERS, ...NUMERIC_FILTERS, ...CONTAINS_FILTERS];\n }\n\n case 'datetime': {\n return [...BASE_FILTERS, ...NUMERIC_FILTERS];\n }\n\n case 'enumeration': {\n return BASE_FILTERS;\n }\n\n default:\n return [...BASE_FILTERS, ...IS_SENSITIVE_FILTERS];\n }\n};\n\n/* -------------------------------------------------------------------------------------------------\n * List\n * -----------------------------------------------------------------------------------------------*/\n\nconst List = () => {\n const [{ query }, setQuery] = useQueryParams<Filters.Query>();\n\n const options = useFilters('List', ({ options }) => options);\n\n const handleClick = (data: FilterFormData) => {\n /**\n * Check the name, operator and value to see if it already exists in the query\n * if it does, remove it.\n */\n const nextFilters = (query?.filters?.$and ?? []).filter((filter) => {\n const [attributeName] = Object.keys(filter);\n if (attributeName !== data.name) {\n return true;\n }\n\n const { type, mainField } = options.find(({ name }) => name === attributeName)!;\n\n if (type === 'relation') {\n const filterObj = filter[attributeName][mainField?.name ?? 'id'];\n\n if (typeof filterObj === 'object') {\n const [operator] = Object.keys(filterObj);\n const value = filterObj[operator];\n\n return !(operator === data.filter && value === data.value);\n }\n\n return true;\n } else {\n const filterObj = filter[attributeName];\n const [operator] = Object.keys(filterObj);\n const value = filterObj[operator];\n\n return !(operator === data.filter && value === data.value);\n }\n });\n\n setQuery({ filters: { $and: nextFilters }, page: 1 });\n };\n\n if (!query?.filters?.$and?.length) {\n return null;\n }\n\n return (\n <>\n {query?.filters?.$and?.map((queryFilter) => {\n const [attributeName] = Object.keys(queryFilter);\n const filter = options.find(({ name }) => name === attributeName);\n const filterObj = queryFilter[attributeName];\n\n if (!filter || typeof filterObj !== 'object' || filterObj === null) {\n return null;\n }\n\n if (filter.type === 'relation') {\n const modelFilter = filterObj[filter.mainField?.name ?? 'id'];\n\n if (typeof modelFilter === 'object') {\n const [operator] = Object.keys(modelFilter);\n const value = modelFilter[operator];\n return (\n <AttributeTag\n key={`${attributeName}-${operator}-${value}`}\n {...filter}\n onClick={handleClick}\n operator={operator}\n value={value}\n />\n );\n }\n\n return null;\n } else {\n const [operator] = Object.keys(filterObj);\n const value = filterObj[operator];\n\n /**\n * Something has gone wrong here, because the attribute is not a relation\n * but we have a nested filter object.\n */\n if (typeof value === 'object') {\n return null;\n }\n\n return (\n <AttributeTag\n key={`${attributeName}-${operator}-${value}`}\n {...filter}\n onClick={handleClick}\n operator={operator}\n value={value}\n />\n );\n }\n })}\n </>\n );\n};\n\ninterface AttributeTagProps extends Filters.Filter {\n onClick: (data: FilterFormData) => void;\n operator: string;\n value: string;\n}\n\nconst AttributeTag = ({\n input,\n label,\n mainField,\n name,\n onClick,\n operator,\n options,\n value,\n ...filter\n}: AttributeTagProps) => {\n const { formatMessage, formatDate, formatTime, formatNumber } = useIntl();\n\n const handleClick = () => {\n onClick({ name, value, filter: operator });\n };\n\n const type = mainField?.type ? mainField.type : filter.type;\n\n let formattedValue: string = value;\n\n switch (type) {\n case 'date':\n formattedValue = formatDate(value, { dateStyle: 'full' });\n break;\n case 'datetime':\n formattedValue = formatDate(value, { dateStyle: 'full', timeStyle: 'short' });\n break;\n case 'time':\n const [hour, minute] = value.split(':');\n const date = new Date();\n date.setHours(Number(hour));\n date.setMinutes(Number(minute));\n\n formattedValue = formatTime(date, {\n hour: 'numeric',\n minute: 'numeric',\n });\n break;\n case 'float':\n case 'integer':\n case 'biginteger':\n case 'decimal':\n formattedValue = formatNumber(Number(value));\n break;\n }\n\n // Handle custom input\n if (input && options) {\n // If the custom input has an options array, find the option with a customValue matching the query value\n const selectedOption = options.find((option) => {\n return (typeof option === 'string' ? option : option.value) === value;\n });\n\n formattedValue = selectedOption\n ? typeof selectedOption === 'string'\n ? selectedOption\n : (selectedOption.label ?? selectedOption.value)\n : value;\n }\n\n const content = `${label} ${formatMessage({\n id: `components.FilterOptions.FILTER_TYPES.${operator}`,\n defaultMessage: operator,\n })} ${operator !== '$null' && operator !== '$notNull' ? formattedValue : ''}`;\n\n return (\n <Tag padding={1} onClick={handleClick} icon={<Cross />}>\n {content}\n </Tag>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * EXPORTS\n * -----------------------------------------------------------------------------------------------*/\n\nconst Filters = {\n List,\n Popover: PopoverImpl,\n Root,\n Trigger,\n};\n\ninterface MainField {\n name: string;\n type: Schema.Attribute.Kind | 'custom';\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nnamespace Filters {\n export interface Filter {\n input?: React.ComponentType<ValueInputProps>;\n label: string;\n /**\n * the name of the attribute we use to display the actual name e.g. relations\n * are just ids, so we use the mainField to display something meaninginful by\n * looking at the target's schema\n */\n mainField?: MainField;\n name: string;\n operators?: Array<{\n label: string;\n value: string;\n }>;\n options?: Array<{ label?: string; value: string }> | string[];\n type: InputProps['type'] | 'relation' | 'custom';\n }\n\n export interface ValueInputProps extends Omit<Filter, 'label'> {\n ['aria-label']: string;\n }\n\n export type Props = RootProps;\n\n export interface TriggerProps {\n label?: string;\n }\n\n export interface Query {\n filters?: {\n /**\n * Typically, a filter will be:\n * ```ts\n * {\n * [attributeName]: {\n * [operator]: value\n * }\n * }\n * ```\n * However, for relation items it becomes more nested.\n * ```ts\n * {\n * [attributeName]: {\n * [relationTargetAttribute]: {\n * [operator]: value\n * }\n * }\n * }\n * ```\n */\n $and?: Array<Record<string, Record<string, string | Record<string, string>>>>;\n };\n page?: number;\n }\n}\n\nexport { Filters };\n"],"names":["FiltersProvider","useFilters","createContext","Root","children","disabled","onChange","options","onOpenChange","open","openProp","defaultOpen","restProps","handleChange","data","setOpen","useControllableState","prop","defaultProp","_jsx","Popover","Trigger","React","forwardRef","label","forwardedRef","formatMessage","useIntl","Button","variant","ref","startIcon","FilterIcon","size","id","defaultMessage","PopoverImpl","zIndex","query","setQuery","useQueryParams","length","handleSubmit","value","FILTERS_WITH_NO_VALUE","includes","filter","encodeURIComponent","fieldOptions","find","name","operatorValuePairing","newFilterQuery","filters","$and","type","mainField","page","Content","style","Box","padding","Form","method","initialValues","BASE_FILTERS","onSubmit","values","formValues","modified","isSubmitting","Input","input","InputRenderer","_jsxs","Flex","direction","alignItems","gap","minWidth","map","placholder","operators","getFilterList","opt","placeholder","field","aria-label","Plus","fullWidth","IS_SENSITIVE_FILTERS","CONTAINS_FILTERS","STRING_PARSE_FILTERS","NUMERIC_FILTERS","List","handleClick","nextFilters","attributeName","Object","keys","filterObj","operator","_Fragment","queryFilter","modelFilter","AttributeTag","onClick","formatDate","formatTime","formatNumber","formattedValue","dateStyle","timeStyle","hour","minute","split","date","Date","setHours","Number","setMinutes","selectedOption","option","content","Tag","icon","Cross","Filters"],"mappings":";;;;;;;;;;;;AAyCA,MAAM,CAACA,eAAAA,EAAiBC,UAAAA,CAAW,GAAGC,aAAAA,CAAmC,SAAA,CAAA;AAMzE,MAAMC,IAAAA,GAAO,CAAC,EACZC,QAAQ,EACRC,QAAAA,GAAW,KAAK,EAChBC,QAAQ,EACRC,UAAU,EAAE,EACZC,YAAY,EACZC,IAAAA,EAAMC,QAAQ,EACdC,WAAW,EACX,GAAGC,SAAAA,EACO,GAAA;AACV,IAAA,MAAMC,eAAe,CAACC,IAAAA,GAAAA;AACpB,QAAA,IAAIR,QAAAA,EAAU;YACZA,QAAAA,CAASQ,IAAAA,CAAAA;AACX,QAAA;AACF,IAAA,CAAA;AACA,IAAA,MAAM,CAACL,IAAAA,GAAO,KAAK,EAAEM,OAAAA,CAAQ,GAAGC,oBAAAA,CAAqB;QACnDC,IAAAA,EAAMP,QAAAA;QACNQ,WAAAA,EAAaP,WAAAA;QACbL,QAAAA,EAAUE;AACZ,KAAA,CAAA;IAEA,qBACEW,GAAA,CAACC,QAAQjB,IAAI,EAAA;QAACM,IAAAA,EAAMA,IAAAA;QAAMD,YAAAA,EAAcO,OAAAA;AAAU,QAAA,GAAGH,SAAS;AAC5D,QAAA,QAAA,gBAAAO,GAAA,CAACnB,eAAAA,EAAAA;YACCe,OAAAA,EAASA,OAAAA;YACTV,QAAAA,EAAUA,QAAAA;YACVC,QAAAA,EAAUO,YAAAA;YACVN,OAAAA,EAASA,OAAAA;AAERH,YAAAA,QAAAA,EAAAA;;;AAIT,CAAA;AAEA;;qGAIA,MAAMiB,wBAAUC,KAAAA,CAAMC,UAAU,CAC9B,CAAC,EAAEC,KAAK,EAAE,EAAEC,YAAAA,GAAAA;IACV,MAAM,EAAEC,aAAa,EAAE,GAAGC,OAAAA,EAAAA;AAC1B,IAAA,MAAMtB,WAAWJ,UAAAA,CAAW,SAAA,EAAW,CAAC,EAAEI,QAAQ,EAAE,GAAKA,QAAAA,CAAAA;IAEzD,qBACEc,GAAA,CAACC,QAAQC,OAAO,EAAA;AACd,QAAA,QAAA,gBAAAF,GAAA,CAACS,MAAAA,EAAAA;YACCC,OAAAA,EAAQ,UAAA;YACRC,GAAAA,EAAKL,YAAAA;AACLM,YAAAA,SAAAA,gBAAWZ,GAAA,CAACa,MAAAA,EAAAA,EAAAA,CAAAA;YACZC,IAAAA,EAAK,GAAA;YACL5B,QAAAA,EAAUA,QAAAA;AAETmB,YAAAA,QAAAA,EAAAA,KAAAA,IAASE,aAAAA,CAAc;gBAAEQ,EAAAA,EAAI,mBAAA;gBAAqBC,cAAAA,EAAgB;AAAU,aAAA;;;AAIrF,CAAA,CAAA;AAGF;;;;;;;;AASC,IACD,MAAMC,WAAAA,GAAc,CAAC,EAAEC,MAAM,EAAuB,GAAA;AAClD,IAAA,MAAM,CAAC,EAAEC,KAAK,EAAE,EAAEC,SAAS,GAAGC,cAAAA,EAAAA;IAC9B,MAAM,EAAEd,aAAa,EAAE,GAAGC,OAAAA,EAAAA;AAC1B,IAAA,MAAMpB,UAAUN,UAAAA,CAAW,SAAA,EAAW,CAAC,EAAEM,OAAO,EAAE,GAAKA,OAAAA,CAAAA;AACvD,IAAA,MAAMD,WAAWL,UAAAA,CAAW,SAAA,EAAW,CAAC,EAAEK,QAAQ,EAAE,GAAKA,QAAAA,CAAAA;AACzD,IAAA,MAAMS,UAAUd,UAAAA,CAAW,SAAA,EAAW,CAAC,EAAEc,OAAO,EAAE,GAAKA,OAAAA,CAAAA;IAEvD,IAAIR,OAAAA,CAAQkC,MAAM,KAAK,CAAA,EAAG;QACxB,OAAO,IAAA;AACT,IAAA;AAEA,IAAA,MAAMC,eAAe,CAAC5B,IAAAA,GAAAA;QACpB,MAAM6B,KAAAA,GAAQC,qBAAAA,CAAsBC,QAAQ,CAAC/B,IAAAA,CAAKgC,MAAM,CAAA,GACpD,MAAA,GACAC,kBAAAA,CAAmBjC,IAAAA,CAAK6B,KAAK,IAAI,EAAA,CAAA;AAErC,QAAA,IAAI,CAACA,KAAAA,EAAO;AACV,YAAA;AACF,QAAA;AAEA,QAAA,IAAIrC,QAAAA,EAAU;YACZA,QAAAA,CAASQ,IAAAA,CAAAA;AACX,QAAA;AAEA;;QAGA,MAAMkC,YAAAA,GAAezC,OAAAA,CAAQ0C,IAAI,CAAC,CAACH,MAAAA,GAAWA,MAAAA,CAAOI,IAAI,KAAKpC,IAAAA,CAAKoC,IAAI,CAAA;AAEvE;;;;;;;;;AASC,QACD,MAAMC,oBAAAA,GAAuB;YAC3B,CAACrC,IAAAA,CAAKgC,MAAM,GAAGH;AACjB,SAAA;AAEA,QAAA,MAAMS,cAAAA,GAAiB;AACrB,YAAA,GAAGd,MAAMe,OAAO;YAChBC,IAAAA,EAAM;mBACAhB,KAAAA,CAAMe,OAAO,EAAEC,IAAAA,IAAQ,EAAE;AAC7B,gBAAA;AACE,oBAAA,CAACxC,KAAKoC,IAAI,GACRF,YAAAA,CAAaO,IAAI,KAAK,UAAA,GAClB;AACE,wBAAA,CAACP,YAAAA,CAAaQ,SAAS,EAAEN,IAAAA,IAAQ,OAAOC;qBAC1C,GACAA;AACR;AACD;AACH,SAAA;QAEAZ,QAAAA,CAAS;YAAEc,OAAAA,EAASD,cAAAA;YAAgBK,IAAAA,EAAM;AAAE,SAAA,EAAG,MAAA,EAAQ,IAAA,CAAA;QACvD1C,OAAAA,CAAQ,KAAA,CAAA;AACV,IAAA,CAAA;IAEA,qBACEI,GAAA,CAACC,QAAQsC,OAAO,EAAA;QAACC,KAAAA,EAAO;AAAEtB,YAAAA;AAAO,SAAA;AAC/B,QAAA,QAAA,gBAAAlB,GAAA,CAACyC,GAAAA,EAAAA;YAAIC,OAAAA,EAAS,CAAA;AACZ,YAAA,QAAA,gBAAA1C,GAAA,CAAC2C,IAAAA,EAAAA;gBACCC,MAAAA,EAAO,MAAA;gBACPC,aAAAA,EACE;oBACEd,IAAAA,EAAM3C,OAAO,CAAC,CAAA,CAAE,EAAE2C,IAAAA;AAClBJ,oBAAAA,MAAAA,EAAQmB,YAAY,CAAC,CAAA,CAAE,CAACtB;AAC1B,iBAAA;gBAEFuB,QAAAA,EAAUxB,YAAAA;AAET,gBAAA,QAAA,EAAA,CAAC,EAAEyB,MAAAA,EAAQC,UAAU,EAAEC,QAAQ,EAAEC,YAAY,EAAE,GAAA;oBAC9C,MAAMxB,MAAAA,GAASvC,OAAAA,CAAQ0C,IAAI,CAAC,CAACH,SAAWA,MAAAA,CAAOI,IAAI,KAAKkB,UAAAA,CAAWlB,IAAI,CAAA;oBACvE,MAAMqB,KAAAA,GAAQzB,QAAQ0B,KAAAA,IAASC,qBAAAA;AAC/B,oBAAA,qBACEC,IAAA,CAACC,IAAAA,EAAAA;wBAAKC,SAAAA,EAAU,QAAA;wBAASC,UAAAA,EAAW,SAAA;wBAAUC,GAAAA,EAAK,CAAA;wBAAGnB,KAAAA,EAAO;4BAAEoB,QAAAA,EAAU;AAAI,yBAAA;;AAC1E,4BAAA;AACC,gCAAA;oCACE,CAAC,YAAA,GAAerD,aAAAA,CAAc;wCAC5BQ,EAAAA,EAAI,wBAAA;wCACJC,cAAAA,EAAgB;AAClB,qCAAA,CAAA;oCACAe,IAAAA,EAAM,MAAA;AACN3C,oCAAAA,OAAAA,EAASA,OAAAA,CAAQyE,GAAG,CAAC,CAAClC,UAAY;AAChCtB,4CAAAA,KAAAA,EAAOsB,OAAOtB,KAAK;AACnBmB,4CAAAA,KAAAA,EAAOG,OAAOI;yCAChB,CAAA,CAAA;AACA+B,oCAAAA,UAAAA,EAAYvD,aAAAA,CAAc;wCACxBQ,EAAAA,EAAI,wBAAA;wCACJC,cAAAA,EAAgB;AAClB,qCAAA,CAAA;oCACAoB,IAAAA,EAAM;AACR,iCAAA;AACA,gCAAA;oCACE,CAAC,YAAA,GAAe7B,aAAAA,CAAc;wCAC5BQ,EAAAA,EAAI,yBAAA;wCACJC,cAAAA,EAAgB;AAClB,qCAAA,CAAA;oCACAe,IAAAA,EAAM,QAAA;oCACN3C,OAAAA,EACEuC,MAAAA,EAAQoC,aACRC,aAAAA,CAAcrC,MAAAA,CAAAA,CAAQkC,GAAG,CAAC,CAACI,OAAS;4CAClC5D,KAAAA,EAAOE,aAAAA,CAAc0D,IAAI5D,KAAK,CAAA;AAC9BmB,4CAAAA,KAAAA,EAAOyC,IAAIzC;yCACb,CAAA,CAAA;AACF0C,oCAAAA,WAAAA,EAAa3D,aAAAA,CAAc;wCACzBQ,EAAAA,EAAI,yBAAA;wCACJC,cAAAA,EAAgB;AAClB,qCAAA,CAAA;oCACAoB,IAAAA,EAAM;AACR;AACD,6BAAA,CAACyB,GAAG,CAAC,CAACM,KAAAA,iBACLnE,GAAA,CAACsD,qBAAAA,EAAAA;AAAgC,oCAAA,GAAGa;AAAhBA,iCAAAA,EAAAA,KAAAA,CAAMpC,IAAI,CAAA,CAAA;4BAE/BJ,MAAAA,IACDsB,UAAAA,CAAWtB,MAAM,IACjBsB,UAAAA,CAAWtB,MAAM,KAAK,OAAA,IACtBsB,UAAAA,CAAWtB,MAAM,KAAK,UAAA,iBACpB3B,GAAA,CAACoD,KAAAA,EAAAA;AACE,gCAAA,GAAGzB,MAAM;gCACVtB,KAAAA,EAAO,IAAA;AACP+D,gCAAAA,YAAAA,EAAYzC,OAAOtB,KAAK;gCACxB0B,IAAAA,EAAK,OAAA;;AAELK,gCAAAA,IAAAA,EAAMT,MAAAA,CAAOU,SAAS,EAAED,IAAAA,IAAQT,OAAOS;AAEvC,6BAAA,CAAA,GAAA,IAAA;0CACJpC,GAAA,CAACS,MAAAA,EAAAA;AACCvB,gCAAAA,QAAAA,EAAU,CAACgE,QAAAA,IAAYC,YAAAA;gCACvBrC,IAAAA,EAAK,GAAA;gCACLJ,OAAAA,EAAQ,WAAA;AACRE,gCAAAA,SAAAA,gBAAWZ,GAAA,CAACqE,IAAAA,EAAAA,EAAAA,CAAAA;gCACZjC,IAAAA,EAAK,QAAA;gCACLkC,SAAS,EAAA,IAAA;0CAER/D,aAAAA,CAAc;oCAAEQ,EAAAA,EAAI,sBAAA;oCAAwBC,cAAAA,EAAgB;AAAa,iCAAA;;;;AAIlF,gBAAA;;;;AAKV,CAAA;AAEA;;IAGA,MAAMgD,gBAAgB,CAACrC,MAAAA,GAAAA;AACrB,IAAA,IAAI,CAACA,MAAAA,EAAQ;AACX,QAAA,OAAO,EAAE;AACX,IAAA;IAEA,MAAMS,IAAAA,GAAOT,MAAAA,CAAOU,SAAS,EAAED,IAAAA,GAAOT,MAAAA,CAAOU,SAAS,CAACD,IAAI,GAAGT,MAAAA,CAAOS,IAAI;IAEzE,OAAQA,IAAAA;QACN,KAAK,OAAA;QACL,KAAK,MAAA;QACL,KAAK,QAAA;AAAU,YAAA;gBACb,OAAO;AACFU,oBAAAA,GAAAA,YAAAA;AACAyB,oBAAAA,GAAAA,oBAAAA;AACAC,oBAAAA,GAAAA,gBAAAA;AACAC,oBAAAA,GAAAA;AACJ,iBAAA;AACH,YAAA;QAEA,KAAK,OAAA;QACL,KAAK,SAAA;QACL,KAAK,YAAA;QACL,KAAK,SAAA;AAAW,YAAA;gBACd,OAAO;AAAI3B,oBAAAA,GAAAA,YAAAA;AAAiB4B,oBAAAA,GAAAA;AAAgB,iBAAA;AAC9C,YAAA;QACA,KAAK,MAAA;QACL,KAAK,MAAA;AAAQ,YAAA;gBACX,OAAO;AAAI5B,oBAAAA,GAAAA,YAAAA;AAAiB4B,oBAAAA,GAAAA,eAAAA;AAAoBF,oBAAAA,GAAAA;AAAiB,iBAAA;AACnE,YAAA;QAEA,KAAK,UAAA;AAAY,YAAA;gBACf,OAAO;AAAI1B,oBAAAA,GAAAA,YAAAA;AAAiB4B,oBAAAA,GAAAA;AAAgB,iBAAA;AAC9C,YAAA;QAEA,KAAK,aAAA;AAAe,YAAA;gBAClB,OAAO5B,YAAAA;AACT,YAAA;AAEA,QAAA;YACE,OAAO;AAAIA,gBAAAA,GAAAA,YAAAA;AAAiByB,gBAAAA,GAAAA;AAAqB,aAAA;AACrD;AACF,CAAA;AAEA;;AAEkG,qGAElG,MAAMI,IAAAA,GAAO,IAAA;AACX,IAAA,MAAM,CAAC,EAAExD,KAAK,EAAE,EAAEC,SAAS,GAAGC,cAAAA,EAAAA;AAE9B,IAAA,MAAMjC,UAAUN,UAAAA,CAAW,MAAA,EAAQ,CAAC,EAAEM,OAAO,EAAE,GAAKA,OAAAA,CAAAA;AAEpD,IAAA,MAAMwF,cAAc,CAACjF,IAAAA,GAAAA;AACnB;;;AAGC,QACD,MAAMkF,WAAAA,GAAc,CAAC1D,KAAAA,EAAOe,OAAAA,EAASC,IAAAA,IAAQ,EAAE,EAAER,MAAM,CAAC,CAACA,MAAAA,GAAAA;AACvD,YAAA,MAAM,CAACmD,aAAAA,CAAc,GAAGC,MAAAA,CAAOC,IAAI,CAACrD,MAAAA,CAAAA;YACpC,IAAImD,aAAAA,KAAkBnF,IAAAA,CAAKoC,IAAI,EAAE;gBAC/B,OAAO,IAAA;AACT,YAAA;AAEA,YAAA,MAAM,EAAEK,IAAI,EAAEC,SAAS,EAAE,GAAGjD,OAAAA,CAAQ0C,IAAI,CAAC,CAAC,EAAEC,IAAI,EAAE,GAAKA,IAAAA,KAAS+C,aAAAA,CAAAA;AAEhE,YAAA,IAAI1C,SAAS,UAAA,EAAY;AACvB,gBAAA,MAAM6C,YAAYtD,MAAM,CAACmD,cAAc,CAACzC,SAAAA,EAAWN,QAAQ,IAAA,CAAK;gBAEhE,IAAI,OAAOkD,cAAc,QAAA,EAAU;AACjC,oBAAA,MAAM,CAACC,QAAAA,CAAS,GAAGH,MAAAA,CAAOC,IAAI,CAACC,SAAAA,CAAAA;oBAC/B,MAAMzD,KAAAA,GAAQyD,SAAS,CAACC,QAAAA,CAAS;oBAEjC,OAAO,EAAEA,QAAAA,KAAavF,IAAAA,CAAKgC,MAAM,IAAIH,KAAAA,KAAU7B,IAAAA,CAAK6B,KAAK,CAAD;AAC1D,gBAAA;gBAEA,OAAO,IAAA;YACT,CAAA,MAAO;gBACL,MAAMyD,SAAAA,GAAYtD,MAAM,CAACmD,aAAAA,CAAc;AACvC,gBAAA,MAAM,CAACI,QAAAA,CAAS,GAAGH,MAAAA,CAAOC,IAAI,CAACC,SAAAA,CAAAA;gBAC/B,MAAMzD,KAAAA,GAAQyD,SAAS,CAACC,QAAAA,CAAS;gBAEjC,OAAO,EAAEA,QAAAA,KAAavF,IAAAA,CAAKgC,MAAM,IAAIH,KAAAA,KAAU7B,IAAAA,CAAK6B,KAAK,CAAD;AAC1D,YAAA;AACF,QAAA,CAAA,CAAA;QAEAJ,QAAAA,CAAS;YAAEc,OAAAA,EAAS;gBAAEC,IAAAA,EAAM0C;AAAY,aAAA;YAAGvC,IAAAA,EAAM;AAAE,SAAA,CAAA;AACrD,IAAA,CAAA;AAEA,IAAA,IAAI,CAACnB,KAAAA,EAAOe,OAAAA,EAASC,IAAAA,EAAMb,MAAAA,EAAQ;QACjC,OAAO,IAAA;AACT,IAAA;IAEA,qBACEtB,GAAA,CAAAmF,QAAA,EAAA;kBACGhE,KAAAA,EAAOe,OAAAA,EAASC,IAAAA,EAAM0B,GAAAA,CAAI,CAACuB,WAAAA,GAAAA;AAC1B,YAAA,MAAM,CAACN,aAAAA,CAAc,GAAGC,MAAAA,CAAOC,IAAI,CAACI,WAAAA,CAAAA;YACpC,MAAMzD,MAAAA,GAASvC,QAAQ0C,IAAI,CAAC,CAAC,EAAEC,IAAI,EAAE,GAAKA,IAAAA,KAAS+C,aAAAA,CAAAA;YACnD,MAAMG,SAAAA,GAAYG,WAAW,CAACN,aAAAA,CAAc;AAE5C,YAAA,IAAI,CAACnD,MAAAA,IAAU,OAAOsD,SAAAA,KAAc,QAAA,IAAYA,cAAc,IAAA,EAAM;gBAClE,OAAO,IAAA;AACT,YAAA;YAEA,IAAItD,MAAAA,CAAOS,IAAI,KAAK,UAAA,EAAY;AAC9B,gBAAA,MAAMiD,cAAcJ,SAAS,CAACtD,OAAOU,SAAS,EAAEN,QAAQ,IAAA,CAAK;gBAE7D,IAAI,OAAOsD,gBAAgB,QAAA,EAAU;AACnC,oBAAA,MAAM,CAACH,QAAAA,CAAS,GAAGH,MAAAA,CAAOC,IAAI,CAACK,WAAAA,CAAAA;oBAC/B,MAAM7D,KAAAA,GAAQ6D,WAAW,CAACH,QAAAA,CAAS;AACnC,oBAAA,qBACElF,GAAA,CAACsF,YAAAA,EAAAA;AAEE,wBAAA,GAAG3D,MAAM;wBACV4D,OAAAA,EAASX,WAAAA;wBACTM,QAAAA,EAAUA,QAAAA;wBACV1D,KAAAA,EAAOA;AAJF,qBAAA,EAAA,CAAA,EAAGsD,cAAc,CAAC,EAAEI,QAAAA,CAAS,CAAC,EAAE1D,KAAAA,CAAAA,CAAO,CAAA;AAOlD,gBAAA;gBAEA,OAAO,IAAA;YACT,CAAA,MAAO;AACL,gBAAA,MAAM,CAAC0D,QAAAA,CAAS,GAAGH,MAAAA,CAAOC,IAAI,CAACC,SAAAA,CAAAA;gBAC/B,MAAMzD,KAAAA,GAAQyD,SAAS,CAACC,QAAAA,CAAS;AAEjC;;;cAIA,IAAI,OAAO1D,KAAAA,KAAU,QAAA,EAAU;oBAC7B,OAAO,IAAA;AACT,gBAAA;AAEA,gBAAA,qBACExB,GAAA,CAACsF,YAAAA,EAAAA;AAEE,oBAAA,GAAG3D,MAAM;oBACV4D,OAAAA,EAASX,WAAAA;oBACTM,QAAAA,EAAUA,QAAAA;oBACV1D,KAAAA,EAAOA;AAJF,iBAAA,EAAA,CAAA,EAAGsD,cAAc,CAAC,EAAEI,QAAAA,CAAS,CAAC,EAAE1D,KAAAA,CAAAA,CAAO,CAAA;AAOlD,YAAA;AACF,QAAA,CAAA;;AAGN,CAAA;AAQA,MAAM8D,YAAAA,GAAe,CAAC,EACpBjC,KAAK,EACLhD,KAAK,EACLgC,SAAS,EACTN,IAAI,EACJwD,OAAO,EACPL,QAAQ,EACR9F,OAAO,EACPoC,KAAK,EACL,GAAGG,MAAAA,EACe,GAAA;IAClB,MAAM,EAAEpB,aAAa,EAAEiF,UAAU,EAAEC,UAAU,EAAEC,YAAY,EAAE,GAAGlF,OAAAA,EAAAA;AAEhE,IAAA,MAAMoE,WAAAA,GAAc,IAAA;QAClBW,OAAAA,CAAQ;AAAExD,YAAAA,IAAAA;AAAMP,YAAAA,KAAAA;YAAOG,MAAAA,EAAQuD;AAAS,SAAA,CAAA;AAC1C,IAAA,CAAA;AAEA,IAAA,MAAM9C,OAAOC,SAAAA,EAAWD,IAAAA,GAAOC,UAAUD,IAAI,GAAGT,OAAOS,IAAI;AAE3D,IAAA,IAAIuD,cAAAA,GAAyBnE,KAAAA;IAE7B,OAAQY,IAAAA;QACN,KAAK,MAAA;AACHuD,YAAAA,cAAAA,GAAiBH,WAAWhE,KAAAA,EAAO;gBAAEoE,SAAAA,EAAW;AAAO,aAAA,CAAA;AACvD,YAAA;QACF,KAAK,UAAA;AACHD,YAAAA,cAAAA,GAAiBH,WAAWhE,KAAAA,EAAO;gBAAEoE,SAAAA,EAAW,MAAA;gBAAQC,SAAAA,EAAW;AAAQ,aAAA,CAAA;AAC3E,YAAA;QACF,KAAK,MAAA;AACH,YAAA,MAAM,CAACC,IAAAA,EAAMC,MAAAA,CAAO,GAAGvE,KAAAA,CAAMwE,KAAK,CAAC,GAAA,CAAA;AACnC,YAAA,MAAMC,OAAO,IAAIC,IAAAA,EAAAA;YACjBD,IAAAA,CAAKE,QAAQ,CAACC,MAAAA,CAAON,IAAAA,CAAAA,CAAAA;YACrBG,IAAAA,CAAKI,UAAU,CAACD,MAAAA,CAAOL,MAAAA,CAAAA,CAAAA;AAEvBJ,YAAAA,cAAAA,GAAiBF,WAAWQ,IAAAA,EAAM;gBAChCH,IAAAA,EAAM,SAAA;gBACNC,MAAAA,EAAQ;AACV,aAAA,CAAA;AACA,YAAA;QACF,KAAK,OAAA;QACL,KAAK,SAAA;QACL,KAAK,YAAA;QACL,KAAK,SAAA;AACHJ,YAAAA,cAAAA,GAAiBD,aAAaU,MAAAA,CAAO5E,KAAAA,CAAAA,CAAAA;AACrC,YAAA;AACJ;;AAGA,IAAA,IAAI6B,SAASjE,OAAAA,EAAS;;AAEpB,QAAA,MAAMkH,cAAAA,GAAiBlH,OAAAA,CAAQ0C,IAAI,CAAC,CAACyE,MAAAA,GAAAA;YACnC,OAAQ,CAAA,OAAOA,MAAAA,KAAW,WAAWA,MAAAA,GAASA,MAAAA,CAAO/E,KAAI,MAAOA,KAAAA;AAClE,QAAA,CAAA,CAAA;QAEAmE,cAAAA,GAAiBW,cAAAA,GACb,OAAOA,cAAAA,KAAmB,QAAA,GACxBA,cAAAA,GACCA,eAAejG,KAAK,IAAIiG,cAAAA,CAAe9E,KAAK,GAC/CA,KAAAA;AACN,IAAA;AAEA,IAAA,MAAMgF,OAAAA,GAAU,CAAA,EAAGnG,KAAAA,CAAM,CAAC,EAAEE,aAAAA,CAAc;QACxCQ,EAAAA,EAAI,CAAC,sCAAsC,EAAEmE,QAAAA,CAAAA,CAAU;QACvDlE,cAAAA,EAAgBkE;AAClB,KAAA,CAAA,CAAG,CAAC,EAAEA,QAAAA,KAAa,WAAWA,QAAAA,KAAa,UAAA,GAAaS,iBAAiB,EAAA,CAAA,CAAI;AAE7E,IAAA,qBACE3F,GAAA,CAACyG,GAAAA,EAAAA;QAAI/D,OAAAA,EAAS,CAAA;QAAG6C,OAAAA,EAASX,WAAAA;AAAa8B,QAAAA,IAAAA,gBAAM1G,GAAA,CAAC2G,KAAAA,EAAAA,EAAAA,CAAAA;AAC3CH,QAAAA,QAAAA,EAAAA;;AAGP,CAAA;AAEA;;AAEkG,2GAE5FI,OAAAA,GAAU;AACdjC,IAAAA,IAAAA;IACA1E,OAAAA,EAASgB,WAAAA;AACTjC,IAAAA,IAAAA;AACAkB,IAAAA;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"Filters.mjs","sources":["../../../../../admin/src/components/Filters.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Box, Button, Flex, Popover, Tag } from '@strapi/design-system';\nimport { Plus, Filter as FilterIcon, Cross } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\n\nimport {\n BASE_FILTERS,\n CONTAINS_FILTERS,\n FilterOption,\n IS_SENSITIVE_FILTERS,\n NUMERIC_FILTERS,\n STRING_PARSE_FILTERS,\n FILTERS_WITH_NO_VALUE,\n} from '../constants/filters';\nimport { useControllableState } from '../hooks/useControllableState';\nimport { useQueryParams } from '../hooks/useQueryParams';\n\nimport { createContext } from './Context';\nimport { Form, InputProps } from './Form';\nimport { InputRenderer } from './FormInputs/Renderer';\n\nimport type { Schema } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * Root\n * -----------------------------------------------------------------------------------------------*/\n\ninterface FilterFormData {\n name: string;\n filter: string;\n value?: string;\n}\n\ninterface FitlersContextValue {\n disabled: boolean;\n onChange: (data: FilterFormData) => void;\n options: Filters.Filter[];\n setOpen: (open: boolean) => void;\n editingFilter: FilterFormData | null;\n setEditingFilter: (filter: FilterFormData | null) => void;\n}\n\nconst [FiltersProvider, useFilters] = createContext<FitlersContextValue>('Filters');\n\nconst getFilterDetails = (\n filterEntry: Record<string, unknown>,\n options: Filters.Filter[]\n): { name: string; operator: string; value: unknown } | null => {\n const [name] = Object.keys(filterEntry);\n const option = options.find((o) => o.name === name);\n if (!option) {\n return null;\n }\n\n const operatorObj =\n option.type === 'relation'\n ? (filterEntry[name] as Record<string, unknown>)?.[option.mainField?.name ?? 'id']\n : filterEntry[name];\n\n if (typeof operatorObj !== 'object' || operatorObj === null) {\n return null;\n }\n\n const [operator] = Object.keys(operatorObj as Record<string, unknown>);\n if (!operator) {\n return null;\n }\n\n return { name, operator, value: (operatorObj as Record<string, unknown>)[operator] };\n};\n\nconst isFilterMatch = (\n filterEntry: Record<string, unknown>,\n options: Filters.Filter[],\n target: FilterFormData\n): boolean => {\n const details = getFilterDetails(filterEntry, options);\n if (!details || details.name !== target.name || details.operator !== target.filter) {\n return false;\n }\n if (FILTERS_WITH_NO_VALUE.includes(target.filter)) {\n return true;\n }\n\n const decoded =\n typeof details.value === 'string' ? decodeURIComponent(details.value) : details.value;\n return decoded === target.value;\n};\n\ninterface RootProps\n extends Partial<Pick<FitlersContextValue, 'disabled' | 'onChange' | 'options'>>,\n Popover.Props {\n children: React.ReactNode;\n}\n\nconst Root = ({\n children,\n disabled = false,\n onChange,\n options = [],\n onOpenChange,\n open: openProp,\n defaultOpen,\n ...restProps\n}: RootProps) => {\n const [editingFilter, setEditingFilter] = React.useState<FilterFormData | null>(null);\n\n const handleChange = (data: FilterFormData) => {\n if (onChange) {\n onChange(data);\n }\n };\n\n const [open = false, setOpen] = useControllableState({\n prop: openProp,\n defaultProp: defaultOpen,\n onChange: onOpenChange,\n });\n\n React.useEffect(() => {\n if (!open) {\n setEditingFilter(null);\n }\n }, [open]);\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen} {...restProps}>\n <FiltersProvider\n setOpen={setOpen}\n disabled={disabled}\n onChange={handleChange}\n options={options}\n editingFilter={editingFilter}\n setEditingFilter={setEditingFilter}\n >\n {children}\n </FiltersProvider>\n </Popover.Root>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * Trigger\n * -----------------------------------------------------------------------------------------------*/\n\nconst Trigger = React.forwardRef<HTMLButtonElement, Filters.TriggerProps>(\n ({ label }, forwardedRef) => {\n const { formatMessage } = useIntl();\n const disabled = useFilters('Trigger', ({ disabled }) => disabled);\n\n return (\n <Popover.Trigger>\n <Button\n variant=\"tertiary\"\n ref={forwardedRef}\n startIcon={<FilterIcon />}\n size=\"S\"\n disabled={disabled}\n >\n {label || formatMessage({ id: 'app.utils.filters', defaultMessage: 'Filters' })}\n </Button>\n </Popover.Trigger>\n );\n }\n);\n\n/* -------------------------------------------------------------------------------------------------\n * Popover\n * -----------------------------------------------------------------------------------------------*/\n/**\n * The zIndex property is used to override the zIndex of the Portal element of the Popover.\n * This is needed to ensure that the DatePicker is rendered above the Popover when opened.\n * The issue was that both the DatePicker and the Popover are rendered in a Portal and have the same zIndex.\n * On init, since the DatePicker is rendered before the Popover in the DOM,\n * it's causing the issue of appearing behind the Popover.\n */\nconst PopoverImpl = ({ zIndex }: { zIndex?: number }) => {\n const [{ query }, setQuery] = useQueryParams<Filters.Query>();\n const { formatMessage } = useIntl();\n const options = useFilters('Popover', ({ options }) => options);\n const onChange = useFilters('Popover', ({ onChange }) => onChange);\n const setOpen = useFilters('Popover', ({ setOpen }) => setOpen);\n const editingFilter = useFilters('Popover', ({ editingFilter }) => editingFilter);\n const setEditingFilter = useFilters('Popover', ({ setEditingFilter }) => setEditingFilter);\n\n const initialValues = React.useMemo(() => {\n return editingFilter ?? { name: options[0]?.name, filter: BASE_FILTERS[0].value };\n }, [editingFilter, options]);\n\n if (options.length === 0) {\n return null;\n }\n\n const handleSubmit = (data: FilterFormData) => {\n const value = FILTERS_WITH_NO_VALUE.includes(data.filter)\n ? 'true'\n : encodeURIComponent(data.value ?? '');\n\n if (!value) {\n return;\n }\n\n if (onChange) {\n onChange(data);\n }\n\n /**\n * There will ALWAYS be an option because we use the options to create the form data.\n */\n const fieldOptions = options.find((filter) => filter.name === data.name)!;\n\n /**\n * If the filter is a relation, we need to nest the filter object,\n * we filter based on the mainField of the relation, if there is no mainField, we use the id.\n * At the end, we pass the operator & value. This value _could_ look like:\n * ```json\n * {\n * \"$eq\": \"1\",\n * }\n * ```\n */\n const operatorValuePairing = {\n [data.filter]: value,\n };\n\n const newFilterEntry = {\n [data.name]:\n fieldOptions.type === 'relation'\n ? {\n [fieldOptions.mainField?.name ?? 'id']: operatorValuePairing,\n }\n : operatorValuePairing,\n };\n\n const existingFilters = query.filters?.$and ?? [];\n\n const newFilterQuery = editingFilter\n ? {\n ...query.filters,\n $and: existingFilters.map((filter) =>\n isFilterMatch(filter, options, editingFilter) ? newFilterEntry : filter\n ),\n }\n : {\n ...query.filters,\n $and: [...existingFilters, newFilterEntry],\n };\n\n setQuery({ filters: newFilterQuery, page: 1 }, 'push', true);\n setOpen(false);\n setEditingFilter(null);\n };\n\n return (\n <Popover.Content style={{ zIndex }}>\n <Box padding={3}>\n <Form\n method=\"POST\"\n initialValues={initialValues}\n onSubmit={handleSubmit}\n key={\n editingFilter\n ? `edit-${editingFilter.name}-${editingFilter.filter}-${editingFilter.value ?? 'empty'}`\n : 'create'\n }\n >\n {({ values: formValues, modified, isSubmitting }) => {\n const filter = options.find((filter) => filter.name === formValues.name);\n const Input = filter?.input || InputRenderer;\n return (\n <Flex direction=\"column\" alignItems=\"stretch\" gap={2} style={{ minWidth: 184 }}>\n {[\n {\n ['aria-label']: formatMessage({\n id: 'app.utils.select-field',\n defaultMessage: 'Select field',\n }),\n name: 'name',\n options: options.map((filter) => ({\n label: filter.label,\n value: filter.name,\n })),\n placholder: formatMessage({\n id: 'app.utils.select-field',\n defaultMessage: 'Select field',\n }),\n type: 'enumeration' as const,\n },\n {\n ['aria-label']: formatMessage({\n id: 'app.utils.select-filter',\n defaultMessage: 'Select filter',\n }),\n name: 'filter',\n options:\n filter?.operators ||\n getFilterList(filter).map((opt) => ({\n label: formatMessage(opt.label),\n value: opt.value,\n })),\n placeholder: formatMessage({\n id: 'app.utils.select-filter',\n defaultMessage: 'Select filter',\n }),\n type: 'enumeration' as const,\n },\n ].map((field) => (\n <InputRenderer key={field.name} {...field} />\n ))}\n {filter &&\n formValues.filter &&\n !FILTERS_WITH_NO_VALUE.includes(formValues.filter) ? (\n <Input\n {...filter}\n label={null}\n aria-label={filter.label}\n name=\"value\"\n // @ts-expect-error – if type is `custom` then `Input` will be a custom component.\n type={filter.mainField?.type ?? filter.type}\n />\n ) : null}\n <Button\n disabled={!modified || isSubmitting}\n size=\"L\"\n variant=\"secondary\"\n startIcon={<Plus />}\n type=\"submit\"\n fullWidth\n >\n {editingFilter\n ? formatMessage({\n id: 'app.utils.update-filter',\n defaultMessage: 'Update filter',\n })\n : formatMessage({ id: 'app.utils.add-filter', defaultMessage: 'Add filter' })}\n </Button>\n </Flex>\n );\n }}\n </Form>\n </Box>\n </Popover.Content>\n );\n};\n\n/**\n * Depending on the selected field find the possible filters to apply\n */\nconst getFilterList = (filter?: Filters.Filter): FilterOption[] => {\n if (!filter) {\n return [];\n }\n\n const type = filter.mainField?.type ? filter.mainField.type : filter.type;\n\n switch (type) {\n case 'email':\n case 'text':\n case 'string': {\n return [\n ...BASE_FILTERS,\n ...IS_SENSITIVE_FILTERS,\n ...CONTAINS_FILTERS,\n ...STRING_PARSE_FILTERS,\n ];\n }\n\n case 'float':\n case 'integer':\n case 'biginteger':\n case 'decimal': {\n return [...BASE_FILTERS, ...NUMERIC_FILTERS];\n }\n case 'time':\n case 'date': {\n return [...BASE_FILTERS, ...NUMERIC_FILTERS, ...CONTAINS_FILTERS];\n }\n\n case 'datetime': {\n return [...BASE_FILTERS, ...NUMERIC_FILTERS];\n }\n\n case 'enumeration': {\n return BASE_FILTERS;\n }\n\n default:\n return [...BASE_FILTERS, ...IS_SENSITIVE_FILTERS];\n }\n};\n\n/* -------------------------------------------------------------------------------------------------\n * List\n * -----------------------------------------------------------------------------------------------*/\n\nconst List = () => {\n const [{ query }, setQuery] = useQueryParams<Filters.Query>();\n\n const options = useFilters('List', ({ options }) => options);\n\n const handleClick = (data: FilterFormData) => {\n /**\n * Check the name, operator and value to see if it already exists in the query\n * if it does, remove it.\n */\n const nextFilters = (query?.filters?.$and ?? []).filter((filter) => {\n const details = getFilterDetails(filter, options);\n if (!details) {\n return true;\n }\n\n return !(\n details.name === data.name &&\n details.operator === data.filter &&\n details.value === data.value\n );\n });\n\n setQuery({ filters: { $and: nextFilters }, page: 1 });\n };\n\n if (!query?.filters?.$and?.length) {\n return null;\n }\n\n return (\n <>\n {query?.filters?.$and?.map((queryFilter) => {\n const details = getFilterDetails(queryFilter, options);\n if (!details || typeof details.value === 'object') {\n return null;\n }\n\n const filter = options.find(({ name }) => name === details.name);\n if (!filter) {\n return null;\n }\n return (\n <AttributeTag\n key={`${details.name}-${details.operator}-${details.value}`}\n {...filter}\n onRemove={handleClick}\n operator={details.operator}\n value={String(details.value)}\n />\n );\n })}\n </>\n );\n};\n\ninterface AttributeTagProps extends Filters.Filter {\n onRemove: (data: FilterFormData) => void;\n operator: string;\n value: string;\n}\n\nconst AttributeTag = ({\n input,\n label,\n mainField,\n name,\n onRemove,\n operator,\n options,\n value,\n ...filter\n}: AttributeTagProps) => {\n const { formatMessage, formatDate, formatTime, formatNumber } = useIntl();\n const setOpen = useFilters('AttributeTag', ({ setOpen }) => setOpen);\n const setEditingFilter = useFilters('AttributeTag', ({ setEditingFilter }) => setEditingFilter);\n\n const handleEdit = () => {\n setEditingFilter({\n name,\n filter: operator,\n value: FILTERS_WITH_NO_VALUE.includes(operator) ? undefined : decodeURIComponent(value),\n });\n setOpen(true);\n };\n\n const handleRemove = () => {\n onRemove({ name, value, filter: operator });\n };\n\n const type = mainField?.type ? mainField.type : filter.type;\n\n let formattedValue: string = value;\n\n switch (type) {\n case 'date':\n formattedValue = formatDate(value, { dateStyle: 'full' });\n break;\n case 'datetime':\n formattedValue = formatDate(value, { dateStyle: 'full', timeStyle: 'short' });\n break;\n case 'time':\n const [hour, minute] = value.split(':');\n const date = new Date();\n date.setHours(Number(hour));\n date.setMinutes(Number(minute));\n\n formattedValue = formatTime(date, {\n hour: 'numeric',\n minute: 'numeric',\n });\n break;\n case 'float':\n case 'integer':\n case 'biginteger':\n case 'decimal':\n formattedValue = formatNumber(Number(value));\n break;\n }\n\n // Handle custom input\n if (input && options) {\n // If the custom input has an options array, find the option with a customValue matching the query value\n const selectedOption = options.find((option) => {\n return (typeof option === 'string' ? option : option.value) === value;\n });\n\n formattedValue = selectedOption\n ? typeof selectedOption === 'string'\n ? selectedOption\n : (selectedOption.label ?? selectedOption.value)\n : value;\n }\n\n const operatorLabel = formatMessage({\n id: `components.FilterOptions.FILTER_TYPES.${operator}`,\n defaultMessage: operator,\n });\n\n const content = FILTERS_WITH_NO_VALUE.includes(operator)\n ? `${label} ${operatorLabel}`\n : `${label} ${operatorLabel} ${formattedValue}`;\n\n return (\n <Tag padding={1} onClick={handleRemove} icon={<Cross />} label={content}>\n <Box tag=\"span\" cursor=\"pointer\" onClick={handleEdit}>\n {content}\n </Box>\n </Tag>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * EXPORTS\n * -----------------------------------------------------------------------------------------------*/\n\nconst Filters = {\n List,\n Popover: PopoverImpl,\n Root,\n Trigger,\n};\n\ninterface MainField {\n name: string;\n type: Schema.Attribute.Kind | 'custom';\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nnamespace Filters {\n export interface Filter {\n input?: React.ComponentType<ValueInputProps>;\n label: string;\n /**\n * the name of the attribute we use to display the actual name e.g. relations\n * are just ids, so we use the mainField to display something meaninginful by\n * looking at the target's schema\n */\n mainField?: MainField;\n name: string;\n operators?: Array<{\n label: string;\n value: string;\n }>;\n options?: Array<{ label?: string; value: string }> | string[];\n type: InputProps['type'] | 'relation' | 'custom';\n }\n\n export interface ValueInputProps extends Omit<Filter, 'label'> {\n ['aria-label']: string;\n }\n\n export type Props = RootProps;\n\n export interface TriggerProps {\n label?: string;\n }\n\n export interface Query {\n filters?: {\n /**\n * Typically, a filter will be:\n * ```ts\n * {\n * [attributeName]: {\n * [operator]: value\n * }\n * }\n * ```\n * However, for relation items it becomes more nested.\n * ```ts\n * {\n * [attributeName]: {\n * [relationTargetAttribute]: {\n * [operator]: value\n * }\n * }\n * }\n * ```\n */\n $and?: Array<Record<string, Record<string, string | Record<string, string>>>>;\n };\n page?: number;\n }\n}\n\nexport { Filters };\n"],"names":["FiltersProvider","useFilters","createContext","getFilterDetails","filterEntry","options","name","Object","keys","option","find","o","operatorObj","type","mainField","operator","value","isFilterMatch","target","details","filter","FILTERS_WITH_NO_VALUE","includes","decoded","decodeURIComponent","Root","children","disabled","onChange","onOpenChange","open","openProp","defaultOpen","restProps","editingFilter","setEditingFilter","React","useState","handleChange","data","setOpen","useControllableState","prop","defaultProp","useEffect","_jsx","Popover","Trigger","forwardRef","label","forwardedRef","formatMessage","useIntl","Button","variant","ref","startIcon","FilterIcon","size","id","defaultMessage","PopoverImpl","zIndex","query","setQuery","useQueryParams","initialValues","useMemo","BASE_FILTERS","length","handleSubmit","encodeURIComponent","fieldOptions","operatorValuePairing","newFilterEntry","existingFilters","filters","$and","newFilterQuery","map","page","Content","style","Box","padding","Form","method","onSubmit","values","formValues","modified","isSubmitting","Input","input","InputRenderer","_jsxs","Flex","direction","alignItems","gap","minWidth","placholder","operators","getFilterList","opt","placeholder","field","aria-label","Plus","fullWidth","IS_SENSITIVE_FILTERS","CONTAINS_FILTERS","STRING_PARSE_FILTERS","NUMERIC_FILTERS","List","handleClick","nextFilters","_Fragment","queryFilter","AttributeTag","onRemove","String","formatDate","formatTime","formatNumber","handleEdit","undefined","handleRemove","formattedValue","dateStyle","timeStyle","hour","minute","split","date","Date","setHours","Number","setMinutes","selectedOption","operatorLabel","content","Tag","onClick","icon","Cross","tag","cursor","Filters"],"mappings":"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"}
|
|
@@ -45,6 +45,14 @@ function _interopNamespaceDefault(e) {
|
|
|
45
45
|
|
|
46
46
|
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
47
47
|
|
|
48
|
+
const getWidgetPermissionsCacheKey = (permissions)=>{
|
|
49
|
+
return permissions.map((permission)=>JSON.stringify({
|
|
50
|
+
action: permission.action,
|
|
51
|
+
subject: permission.subject,
|
|
52
|
+
conditions: permission.conditions ?? [],
|
|
53
|
+
properties: permission.properties ?? {}
|
|
54
|
+
})).sort().join('|');
|
|
55
|
+
};
|
|
48
56
|
// Styled wrapper for the drag preview
|
|
49
57
|
const DragPreviewWrapper = styled.styled.div`
|
|
50
58
|
max-width: ${(props)=>props.$maxWidth};
|
|
@@ -84,11 +92,19 @@ const DragPreviewWrapper = styled.styled.div`
|
|
|
84
92
|
const user = Auth.useAuth('HomePageCE', (state)=>state.user);
|
|
85
93
|
const displayName = user?.firstname ?? user?.username ?? user?.email;
|
|
86
94
|
const getAllWidgets = StrapiApp.useStrapiApp('UnstableHomepageCe', (state)=>state.widgets.getAll);
|
|
95
|
+
const allWidgets = React__namespace.useMemo(()=>getAllWidgets(), [
|
|
96
|
+
getAllWidgets
|
|
97
|
+
]);
|
|
87
98
|
const checkUserHasPermissions = Auth.useAuth('WidgetRoot', (state)=>state.checkUserHasPermissions);
|
|
88
99
|
const { data: homepageLayout, isLoading: _isLoadingLayout } = homepage.useGetHomepageLayoutQuery();
|
|
100
|
+
// Prefetch expensive widget data as soon as the homepage route is active.
|
|
101
|
+
homepage.useGetCountDocumentsQuery();
|
|
102
|
+
homepage.useGetKeyStatisticsQuery();
|
|
89
103
|
const [filteredWidgets, setFilteredWidgets] = React__namespace.useState([]);
|
|
90
|
-
const [
|
|
91
|
-
|
|
104
|
+
const [widgetPermissionStatus, setWidgetPermissionStatus] = React__namespace.useState(()=>allWidgets.reduce((acc, widget)=>{
|
|
105
|
+
acc[widget.uid] = !widget.permissions || widget.permissions.length === 0 ? 'allowed' : 'loading';
|
|
106
|
+
return acc;
|
|
107
|
+
}, {}));
|
|
92
108
|
const [isAddWidgetModalOpen, setIsAddWidgetModalOpen] = React__namespace.useState(false);
|
|
93
109
|
// Use custom hook for widget management
|
|
94
110
|
const { findWidget, deleteWidget, addWidget, moveWidget, columnWidths, setColumnWidths, handleWidgetResize, saveLayout, isDraggingWidget, draggedWidgetId, handleDragStart, handleDragEnd } = Widgets.useWidgets({
|
|
@@ -96,37 +112,102 @@ const DragPreviewWrapper = styled.styled.div`
|
|
|
96
112
|
setFilteredWidgets
|
|
97
113
|
});
|
|
98
114
|
React__namespace.useEffect(()=>{
|
|
115
|
+
const initialPermissionStatus = allWidgets.reduce((acc, widget)=>{
|
|
116
|
+
acc[widget.uid] = !widget.permissions || widget.permissions.length === 0 ? 'allowed' : 'loading';
|
|
117
|
+
return acc;
|
|
118
|
+
}, {});
|
|
119
|
+
setWidgetPermissionStatus(initialPermissionStatus);
|
|
120
|
+
const widgetsWithPermissions = allWidgets.filter((widget)=>widget.permissions && widget.permissions.length > 0);
|
|
121
|
+
if (widgetsWithPermissions.length === 0) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const groupedPermissions = widgetsWithPermissions.reduce((acc, widget)=>{
|
|
125
|
+
const permissions = widget.permissions ?? [];
|
|
126
|
+
const key = getWidgetPermissionsCacheKey(permissions);
|
|
127
|
+
const existingGroup = acc.get(key);
|
|
128
|
+
if (existingGroup) {
|
|
129
|
+
existingGroup.uids.push(widget.uid);
|
|
130
|
+
} else {
|
|
131
|
+
acc.set(key, {
|
|
132
|
+
permissions,
|
|
133
|
+
uids: [
|
|
134
|
+
widget.uid
|
|
135
|
+
]
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return acc;
|
|
139
|
+
}, new Map());
|
|
140
|
+
let isMounted = true;
|
|
99
141
|
const checkWidgetsPermissions = async ()=>{
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
142
|
+
try {
|
|
143
|
+
const permissionResults = await Promise.all(Array.from(groupedPermissions.values()).map(async ({ permissions, uids })=>{
|
|
144
|
+
const matchingPermissions = await checkUserHasPermissions(permissions);
|
|
145
|
+
const status = matchingPermissions.length >= permissions.length ? 'allowed' : 'denied';
|
|
146
|
+
return {
|
|
147
|
+
uids,
|
|
148
|
+
status
|
|
149
|
+
};
|
|
150
|
+
}));
|
|
151
|
+
if (!isMounted) return;
|
|
152
|
+
setWidgetPermissionStatus((prev)=>{
|
|
153
|
+
const next = {
|
|
154
|
+
...prev
|
|
155
|
+
};
|
|
156
|
+
permissionResults.forEach(({ uids, status })=>{
|
|
157
|
+
uids.forEach((uid)=>{
|
|
158
|
+
next[uid] = status;
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
return next;
|
|
162
|
+
});
|
|
163
|
+
} catch {
|
|
164
|
+
if (!isMounted) return;
|
|
165
|
+
// Keep the UI responsive even when permission checks fail.
|
|
166
|
+
setWidgetPermissionStatus((prev)=>{
|
|
167
|
+
const next = {
|
|
168
|
+
...prev
|
|
169
|
+
};
|
|
170
|
+
widgetsWithPermissions.forEach((widget)=>{
|
|
171
|
+
next[widget.uid] = 'denied';
|
|
172
|
+
});
|
|
173
|
+
return next;
|
|
174
|
+
});
|
|
175
|
+
}
|
|
109
176
|
};
|
|
110
177
|
checkWidgetsPermissions();
|
|
178
|
+
return ()=>{
|
|
179
|
+
isMounted = false;
|
|
180
|
+
};
|
|
111
181
|
}, [
|
|
112
|
-
|
|
113
|
-
|
|
182
|
+
allWidgets,
|
|
183
|
+
checkUserHasPermissions
|
|
184
|
+
]);
|
|
185
|
+
const allAvailableWidgets = React__namespace.useMemo(()=>{
|
|
186
|
+
return allWidgets.filter((widget)=>widgetPermissionStatus[widget.uid] === 'allowed');
|
|
187
|
+
}, [
|
|
188
|
+
allWidgets,
|
|
189
|
+
widgetPermissionStatus
|
|
190
|
+
]);
|
|
191
|
+
const renderableWidgets = React__namespace.useMemo(()=>{
|
|
192
|
+
return allWidgets.filter((widget)=>widgetPermissionStatus[widget.uid] !== 'denied');
|
|
193
|
+
}, [
|
|
194
|
+
allWidgets,
|
|
195
|
+
widgetPermissionStatus
|
|
114
196
|
]);
|
|
115
197
|
React__namespace.useEffect(()=>{
|
|
116
|
-
if (allAvailableWidgets.length === 0) return;
|
|
117
198
|
// If user has customized the homepage layout, apply it
|
|
118
199
|
if (homepageLayout && homepageLayout.widgets) {
|
|
119
|
-
const { filteredWidgets, widths: homepageWidths } = widgetLayout.applyHomepageLayout(
|
|
200
|
+
const { filteredWidgets, widths: homepageWidths } = widgetLayout.applyHomepageLayout(renderableWidgets, homepageLayout);
|
|
120
201
|
setFilteredWidgets(filteredWidgets);
|
|
121
202
|
setColumnWidths(homepageWidths);
|
|
122
203
|
} else {
|
|
123
204
|
// Set default layout when no custom layout exists
|
|
124
|
-
setFilteredWidgets(
|
|
125
|
-
setColumnWidths(widgetLayout.createDefaultWidgetWidths(
|
|
205
|
+
setFilteredWidgets(renderableWidgets);
|
|
206
|
+
setColumnWidths(widgetLayout.createDefaultWidgetWidths(renderableWidgets));
|
|
126
207
|
}
|
|
127
208
|
}, [
|
|
128
209
|
homepageLayout,
|
|
129
|
-
|
|
210
|
+
renderableWidgets,
|
|
130
211
|
setColumnWidths
|
|
131
212
|
]);
|
|
132
213
|
const widgetLayout$1 = React__namespace.useMemo(()=>{
|
|
@@ -197,14 +278,7 @@ const DragPreviewWrapper = styled.styled.div`
|
|
|
197
278
|
paddingBottom: 10,
|
|
198
279
|
children: [
|
|
199
280
|
/*#__PURE__*/ jsxRuntime.jsx(Overview.GuidedTourHomepageOverview, {}),
|
|
200
|
-
|
|
201
|
-
position: "absolute",
|
|
202
|
-
top: 0,
|
|
203
|
-
left: 0,
|
|
204
|
-
right: 0,
|
|
205
|
-
bottom: 0,
|
|
206
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(PageHelpers.Page.Loading, {})
|
|
207
|
-
}) : /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Box, {
|
|
281
|
+
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Box, {
|
|
208
282
|
position: "relative",
|
|
209
283
|
[widgetLayout.WIDGET_DATA_ATTRIBUTES.GRID_CONTAINER]: true,
|
|
210
284
|
children: [
|
|
@@ -225,7 +299,7 @@ const DragPreviewWrapper = styled.styled.div`
|
|
|
225
299
|
onDragStart: handleDragStart,
|
|
226
300
|
onDragEnd: handleDragEnd,
|
|
227
301
|
component: widget.component,
|
|
228
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(WidgetComponent, {
|
|
302
|
+
children: widgetPermissionStatus[widget.uid] === 'loading' ? /*#__PURE__*/ jsxRuntime.jsx(WidgetHelpers.Widget.Loading, {}) : /*#__PURE__*/ jsxRuntime.jsx(WidgetComponent, {
|
|
229
303
|
component: widget.component,
|
|
230
304
|
columnWidth: widgetWidth
|
|
231
305
|
})
|
|
@@ -255,7 +329,7 @@ const DragPreviewWrapper = styled.styled.div`
|
|
|
255
329
|
})
|
|
256
330
|
}),
|
|
257
331
|
/*#__PURE__*/ jsxRuntime.jsx(DragLayer.DragLayer, {
|
|
258
|
-
renderItem: ({ type, item })=>{
|
|
332
|
+
renderItem: ({ type: _type, item })=>{
|
|
259
333
|
if (!DragLayer.isWidgetDragItem(item)) {
|
|
260
334
|
return null;
|
|
261
335
|
}
|