Skip to content

Commit 1567692

Browse files
committed
feat: enhance filter functionality across identity components
- Refactored filter handling in edit-filters and pan-filters components to utilize a unified method for recognizing filter fields. - Introduced new props for default filter field paths and custom filter fields storage key to improve flexibility in filter management. - Updated identity export and table pages to incorporate the new filter props, enhancing the user experience with dynamic filtering capabilities.
1 parent 4a71fd3 commit 1567692

6 files changed

Lines changed: 327 additions & 33 deletions

File tree

apps/web/src/components/core/edit-filters.vue

Lines changed: 109 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ q-card.transparent(style='min-width: 45vw; max-width: 90vw')
33
q-toolbar.bg-secondary.text-white(dense flat style='height: 32px;')
44
q-toolbar-title
55
span {{ title }} 
6-
small(v-if='columnExists(initialFilter.field || "")')
6+
small(v-if='isRecognizedFilterField(initialFilter.field || "")')
77
i(v-if='initialFilter.label') <{{ initialFilter.label }}>
88
q-chip(
99
@click='copy(initialFilter.field || "")'
1010
v-if='initialFilter && initialFilter.field'
11-
:color='$q.dark.isActive ? "amber-9" : "amber-3"'
11+
:color='isRecognizedFilterField(initialFilter.field || "") ? ($q.dark.isActive ? "grey-9" : "grey-3") : ($q.dark.isActive ? "amber-9" : "amber-3")'
1212
text-color='black'
1313
size='xs'
1414
class='q-ml-sm'
@@ -48,11 +48,36 @@ q-card.transparent(style='min-width: 45vw; max-width: 90vw')
4848
//- pre(v-html='JSON.stringify(scope)')
4949
q-chip(
5050
style='overflow-x: hidden;'
51-
:class="[!columnExists(scope.opt.name || scope.opt) ? 'text-black' : '']"
52-
:color="!columnExists(scope.opt.name || scope.opt) ? ($q.dark.isActive ? 'amber-9' : 'amber-3') : ''"
51+
:class="[!isRecognizedFilterField(scope.opt.name || scope.opt) ? 'text-black' : '']"
52+
:color="!isRecognizedFilterField(scope.opt.name || scope.opt) ? ($q.dark.isActive ? 'amber-9' : 'amber-3') : ''"
5353
dense
5454
)
55-
| {{ scope.opt.label || scope.opt.name || scope.opt }}
55+
template(v-if='isCustomFilterFieldOption(scope.opt)')
56+
| {{ scope.opt.name || scope.opt }}
57+
template(v-else)
58+
| {{ scope.opt.label || scope.opt.name || scope.opt }}
59+
small.filter-field-path(v-if='scope.opt.name && scope.opt.label !== scope.opt.name') ({{ scope.opt.name }})
60+
template(v-slot:option="scope")
61+
q-item(v-bind="scope.itemProps")
62+
q-item-section
63+
template(v-if='isCustomFilterFieldOption(scope.opt)')
64+
q-item-label {{ scope.opt.name }}
65+
template(v-else)
66+
q-item-label
67+
| {{ scope.opt.label }}
68+
small.filter-field-path(v-if='scope.opt.name && scope.opt.label !== scope.opt.name') ({{ scope.opt.name }})
69+
q-item-section(v-if='isCustomFilterFieldOption(scope.opt) && customFilterFieldsStorageKey' side)
70+
q-btn(
71+
icon='mdi-delete-outline'
72+
flat
73+
dense
74+
round
75+
size='sm'
76+
color='negative'
77+
aria-label='Supprimer le champ personnalisé'
78+
@click.stop='removeCustomFilterFieldOption(scope.opt.name)'
79+
)
80+
q-tooltip Supprimer ce champ personnalisé
5681
template(#no-option="{ inputValue }")
5782
q-item(clickable @click="triggerEnter")
5883
q-item-section
@@ -61,12 +86,12 @@ q-card.transparent(style='min-width: 45vw; max-width: 90vw')
6186
| &nbsp;
6287
code <{{ inputValue }}>
6388
q-select.col-1(
64-
v-if='filter.key && !columnExists(filter.key || "")'
89+
v-if='filter.key && !isRecognizedFilterField(filter.key || "")'
6590
style='min-width: 120px'
6691
v-model='fieldType'
6792
label='Type'
6893
:options='["text", "number", "date", "boolean", "array"]'
69-
:readonly='!filter.key || !!columnExists(filter.key || "")'
94+
:readonly='!filter.key || !!isRecognizedFilterField(filter.key || "")'
7095
dense
7196
outlined
7297
options-dense
@@ -253,11 +278,21 @@ export default defineNuxtComponent({
253278
type: Object as () => InitialFilter,
254279
default: () => ({}),
255280
},
281+
defaultFilterFieldPaths: {
282+
type: Array as PropType<readonly string[]>,
283+
required: false,
284+
default: () => [],
285+
},
286+
customFilterFieldsStorageKey: {
287+
type: String,
288+
required: false,
289+
default: undefined,
290+
},
256291
},
257292
watch: {
258293
'filter.key': {
259294
handler() {
260-
this.fieldType = this.columnsType.find((col) => col.name === this.filter.key)?.type || 'text'
295+
this.fieldType = resolveFilterFieldType(this.filter.key || '', this.columnsType)
261296
this.filter.operator = ''
262297
},
263298
},
@@ -277,10 +312,10 @@ export default defineNuxtComponent({
277312
data() {
278313
return {
279314
filterOptions: [] as { name: string; label: string }[],
315+
allFilterOptions: [] as { name: string; label: string }[],
280316
}
281317
},
282318
setup({ columns, initialFilter, columnsType }) {
283-
console.log('initialFilter', initialFilter)
284319
const { fieldTypes, comparatorTypes, writeFilter } = useFiltersQuery(ref(columns), ref(columnsType))
285320
286321
const detectInitialOperator = () => {
@@ -395,7 +430,7 @@ export default defineNuxtComponent({
395430
return this.fieldType || 'text'
396431
},
397432
availableComparators(): { label: string; value: string; prefix?: string; suffix?: string; multiplefields?: boolean }[] {
398-
if (!this.columnExists(this.filter.key || '') && !this.fieldType) {
433+
if (!this.isRecognizedFilterField(this.filter.key || '') && !this.fieldType) {
399434
return this.comparatorTypes || []
400435
}
401436
@@ -418,33 +453,73 @@ export default defineNuxtComponent({
418453
},
419454
},
420455
methods: {
421-
columnExists(field: string) {
422-
return this.columns.find((col) => col.name === field)
456+
isRecognizedFilterField(field: string) {
457+
return isRecognizedFilterField(field, {
458+
columns: this.columns,
459+
columnsType: this.columnsType,
460+
defaultFilterFieldPaths: this.defaultFilterFieldPaths,
461+
})
462+
},
463+
isCustomFilterFieldOption(option: { name?: string; label?: string; isCustom?: boolean } | string) {
464+
if (typeof option === 'string') {
465+
return this.allFilterOptions.find((item) => item.name === option)?.isCustom === true
466+
}
467+
468+
if (option?.isCustom) return true
469+
470+
const name = option?.name
471+
if (!name) return false
472+
473+
return this.allFilterOptions.find((item) => item.name === name)?.isCustom === true
423474
},
424-
mapAssign(col: { name: string; label?: string }) {
425-
return { name: col.name, label: col.label || col.name }
475+
rebuildFilterOptions() {
476+
this.allFilterOptions = buildFilterFieldOptions(this.columns, {
477+
extraDefaultPaths: this.defaultFilterFieldPaths,
478+
customStorageKey: this.customFilterFieldsStorageKey,
479+
})
480+
this.filterOptions = [...this.allFilterOptions]
481+
},
482+
removeCustomFilterFieldOption(field: string) {
483+
if (!this.customFilterFieldsStorageKey || !field) return
484+
485+
removeCustomFilterField(this.customFilterFieldsStorageKey, field)
486+
487+
if (this.filter.key === field) {
488+
this.filter.key = undefined
489+
this.filter.operator = ''
490+
this.filter.value = undefined
491+
}
492+
493+
this.rebuildFilterOptions()
426494
},
427495
createValue(val: string, done: (newVal: string, mode: 'toggle' | 'add-unique' | 'add') => void) {
428496
if (val.length > 0) {
429-
if (this.filterOptions.find((opt) => opt.label === val)) {
430-
// If the value already exists in options, select it
431-
const existing = this.filterOptions.find((opt) => opt.label === val)!
497+
const existingByName = this.allFilterOptions.find((opt) => opt.name === val)
498+
const existingByLabel = this.allFilterOptions.find((opt) => opt.label === val)
499+
const existing = existingByName || existingByLabel
500+
501+
if (existing) {
432502
done(existing.name, 'toggle')
433-
} else {
434-
// Otherwise, add it to options and select it
435-
const newOption = { name: val, label: val }
436-
this.filterOptions.push(newOption)
437-
done(val, 'add-unique')
503+
return
504+
}
505+
506+
if (this.customFilterFieldsStorageKey) {
507+
saveCustomFilterField(this.customFilterFieldsStorageKey, val)
438508
}
509+
510+
this.rebuildFilterOptions()
511+
done(val, 'add-unique')
439512
}
440513
},
441514
filterFn(val, update) {
442515
update(() => {
443516
if (val === '') {
444-
this.filterOptions = this.columns.map(this.mapAssign)
517+
this.filterOptions = [...this.allFilterOptions]
445518
} else {
446519
const needle = val.toLowerCase()
447-
this.filterOptions = this.columns.map(this.mapAssign).filter((v) => v.label.toLowerCase().indexOf(needle) > -1)
520+
this.filterOptions = this.allFilterOptions.filter(
521+
(option) => option.label.toLowerCase().includes(needle) || option.name.toLowerCase().includes(needle),
522+
)
448523
}
449524
})
450525
},
@@ -484,12 +559,19 @@ export default defineNuxtComponent({
484559
},
485560
},
486561
mounted() {
487-
this.filterOptions = this.columns.map(this.mapAssign)
488-
this.fieldType = this.columnsType.find((col) => col.name === this.filter.key)?.type
562+
this.rebuildFilterOptions()
563+
this.fieldType = resolveFilterFieldType(this.filter.key || '', this.columnsType)
489564
490-
if (!this.fieldType && !this.columnExists(this.filter.key || '') && this.filter.key) {
565+
if (!this.fieldType && !this.isRecognizedFilterField(this.filter.key || '') && this.filter.key) {
491566
this.fieldType = this.comparator?.type ? this.comparator.type[0] : 'text'
492567
}
493568
},
494569
})
495570
</script>
571+
572+
<style lang="scss" scoped>
573+
.filter-field-path {
574+
font-size: 0.75em;
575+
opacity: 0.72;
576+
}
577+
</style>

apps/web/src/components/core/pan-filters.vue

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ q-toolbar(dense flat)
8585
title='Ajouter un filtre'
8686
:columns='columns'
8787
:columns-type='columnsType'
88+
:default-filter-field-paths='defaultFilterFieldPaths'
89+
:custom-filter-fields-storage-key='customFilterFieldsStorageKey'
8890
)
8991
q-separator(vertical)
9092
q-btn-dropdown.text-secondary(
@@ -112,7 +114,7 @@ q-toolbar(dense flat)
112114
template(v-for='(filter, i) in getFilters' :key='filter.field')
113115
//- pre(v-html='JSON.stringify(filter)')
114116
q-chip(
115-
:class="[!columnExists(filter.field) ? 'text-black' : '']"
117+
:class="[!isRecognizedFilterField(filter.field) ? 'text-black' : '']"
116118
@remove="removeFilter(filter)"
117119
:color="getFilterColor(filter)"
118120
removable
@@ -135,13 +137,15 @@ q-toolbar(dense flat)
135137
:initial-filter='filter'
136138
:columns='columns'
137139
:columns-type='columnsType'
140+
:default-filter-field-paths='defaultFilterFieldPaths'
141+
:custom-filter-fields-storage-key='customFilterFieldsStorageKey'
138142
)
139143
q-tooltip.text-body2(
140144
:class="getTooltipColor(filter)"
141145
anchor='top middle'
142146
self='bottom middle'
143147
)
144-
span(v-if='!columnExists(filter.field)')
148+
span(v-if='!isRecognizedFilterField(filter.field)')
145149
| Cliquer pour modifier le filtre&nbsp;
146150
small (Le champ "{{ filter.field }}" n'existe pas ou n'est pas reconnu)
147151
span(v-else) Cliquer pour modifier le filtre
@@ -182,6 +186,16 @@ export default defineComponent({
182186
required: false,
183187
default: undefined,
184188
},
189+
defaultFilterFieldPaths: {
190+
type: Array as PropType<readonly string[]>,
191+
required: false,
192+
default: () => [],
193+
},
194+
customFilterFieldsStorageKey: {
195+
type: String,
196+
required: false,
197+
default: undefined,
198+
},
185199
},
186200
setup({ columns, columnsType }) {
187201
const { countFilters, hasFilters, getFilters, removeFilter, removeAllFilters } = useFiltersQuery(ref(columns), ref(columnsType))
@@ -212,19 +226,23 @@ export default defineComponent({
212226
},
213227
},
214228
methods: {
215-
columnExists(field: string) {
216-
return this.columns.find((col) => col.name === field)
229+
isRecognizedFilterField(field: string) {
230+
return isRecognizedFilterField(field, {
231+
columns: this.columns,
232+
columnsType: this.columnsType,
233+
defaultFilterFieldPaths: this.defaultFilterFieldPaths,
234+
})
217235
},
218236
getFilterColor(filter: { comparator: string; label: string; field: string; search?: string; value?: unknown }) {
219-
if (this.columnExists(filter.field)) {
237+
if (this.isRecognizedFilterField(filter.field)) {
220238
return this.$q.dark.isActive ? 'grey-9' : 'grey-3'
221239
}
222240
223241
return this.$q.dark.isActive ? 'amber-9' : 'amber-3'
224242
},
225243
getTooltipColor(filter: { comparator: string; label: string; field: string; search?: string; value?: unknown }) {
226244
const colors = [] as string[]
227-
if (!this.columnExists(filter.field)) {
245+
if (!this.isRecognizedFilterField(filter.field)) {
228246
colors.push(this.$q.dark.isActive ? 'bg-amber-9' : 'bg-amber-3')
229247
colors.push('text-black')
230248
}

0 commit comments

Comments
 (0)