Skip to content

Commit a0ec8d8

Browse files
committed
Update filter query handling to support multiple v
alues for the same filter key Modified files: - apps/web/src/components/core/edit-filters.vue - apps/web/src/composables/useColumnsIdentities.ts - apps/web/src/composables/useFiltersQuery.ts - apps/web/src/pages/identities/table.vue
1 parent c57baca commit a0ec8d8

File tree

4 files changed

+147
-33
lines changed

4 files changed

+147
-33
lines changed

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

Lines changed: 81 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template lang="pug">
2-
q-card(style='min-width: 40vw;')
2+
q-card.transparent(style='min-width: 40vw; max-width: 80vw')
33
q-toolbar.bg-primary.text-white(dense flat style='height: 32px;')
44
q-toolbar-title(v-text='title')
55
q-btn(
@@ -49,7 +49,7 @@ q-card(style='min-width: 40vw;')
4949
span {{ scope.opt.label }}
5050
q-input.col(
5151
style='min-width: 300px'
52-
v-show="!comparator?.multiplefields"
52+
v-show="!comparator?.multiplefields && optionsMapping.length === 0"
5353
v-model='filter.value'
5454
label='Valeur'
5555
:prefix="comparator?.prefix"
@@ -59,9 +59,24 @@ q-card(style='min-width: 40vw;')
5959
dense
6060
outlined
6161
)
62+
q-select.col(
63+
style='min-width: 300px'
64+
v-show="!comparator?.multiplefields && optionsMapping.length > 0"
65+
v-model='filter.value'
66+
label='Valeur'
67+
:prefix="comparator?.prefix"
68+
:suffix="comparator?.suffix"
69+
:type='searchInputType'
70+
@keydown.enter.prevent="writeFilter(filter)"
71+
:options="optionsMapping"
72+
emit-value
73+
map-options
74+
dense
75+
outlined
76+
)
6277
q-input.col(
6378
style='min-width: 200px'
64-
v-show="comparator?.multiplefields"
79+
v-show="comparator?.multiplefields && comparator?.querySign === '<<'"
6580
v-model="filter.min"
6681
:type='searchInputType'
6782
label="Minimum"
@@ -71,19 +86,39 @@ q-card(style='min-width: 40vw;')
7186
)
7287
q-input.col(
7388
style='min-width: 200px'
74-
v-show="comparator?.multiplefields"
89+
v-show="comparator?.multiplefields && comparator?.querySign === '<<'"
7590
v-model="filter.max"
7691
:type='searchInputType'
7792
label="Maximum"
7893
clearable
7994
dense
8095
outlined
8196
)
97+
q-select.col(
98+
style='min-width: 300px'
99+
v-show="comparator?.multiplefields && comparator?.querySign === '@'"
100+
v-model="filter.items"
101+
label="Valeur"
102+
:prefix="comparator?.prefix"
103+
:suffix="comparator?.suffix"
104+
:type='searchInputType'
105+
:options="optionsMapping"
106+
input-debounce="100"
107+
new-value-mode="add-unique"
108+
emit-value
109+
map-options
110+
fill-input
111+
use-input
112+
use-chips
113+
multiple
114+
dense
115+
outlined
116+
)
82117
q-card-actions
83118
q-space
84119
q-btn(
85120
@click='writeFilter(filter)'
86-
:disabled='!filter.key || !filter.operator || !filter.value'
121+
:disabled='!filter.key || !filter.operator || (!filter.value && !filter.items?.length)'
87122
label='Valider'
88123
color='positive'
89124
icon-right='mdi-check'
@@ -100,8 +135,10 @@ type Filter = {
100135
operator: string
101136
value: string
102137
103-
min: string
104-
max: string
138+
min?: string
139+
max?: string
140+
141+
items?: (string | number)[]
105142
}
106143
107144
type InitialFilter = {
@@ -125,7 +162,7 @@ export default defineNuxtComponent({
125162
default: () => [],
126163
},
127164
columnsType: {
128-
type: Array as PropType<{ name: string; type: string }[]>,
165+
type: Array as PropType<{ name: string; type: string; valueMapping?: Record<string, string> }[]>,
129166
required: false,
130167
default: () => [],
131168
},
@@ -146,10 +183,12 @@ export default defineNuxtComponent({
146183
this.filter.value = ''
147184
this.filter.min = ''
148185
this.filter.max = ''
186+
this.filter.items = []
149187
},
150188
},
151189
},
152190
setup({ columns, initialFilter, columnsType }) {
191+
console.log('initialFilter', initialFilter)
153192
const { fieldTypes, comparatorTypes, writeFilter } = useFiltersQuery(ref(columns), ref(columnsType))
154193
155194
const detectInitialOperator = () => {
@@ -206,14 +245,31 @@ export default defineNuxtComponent({
206245
return val
207246
}
208247
248+
const items = ref<(string | number)[]>([])
249+
250+
if (initialFilter && initialFilter.querySign === '@' && initialFilter.value) {
251+
if (Array.isArray(initialFilter.value) || initialFilter.value.includes(',')) {
252+
items.value = Array.isArray(initialFilter.value)
253+
? initialFilter.value
254+
: initialFilter.value
255+
.split(',')
256+
.map((s) => s.trim())
257+
.filter((s) => s.length > 0)
258+
} else {
259+
items.value = [initialFilter.value]
260+
}
261+
}
262+
209263
const fieldType = ref<string>()
210264
const filter = ref<Filter>({
211-
key: initialFilter?.field || '',
265+
key: initialFilter?.field?.replace('[]', '') || '',
212266
operator: detectInitialOperator(),
213267
value: stripPrefixSuffix(initialFilter?.value) || '',
214268
215269
min: '',
216270
max: '',
271+
272+
items: items.value,
217273
})
218274
219275
return {
@@ -238,8 +294,24 @@ export default defineNuxtComponent({
238294
return comparator.type.includes(this.fieldType!)
239295
})
240296
},
297+
optionsMapping(): { label: string; value: string }[] {
298+
const mapping: { label: string; value: string }[] = []
299+
300+
this.columnsType.forEach((col) => {
301+
if (col.name === this.filter.key && col.valueMapping) {
302+
Object.entries(col.valueMapping).forEach(([key, val]) => {
303+
mapping.push({ label: val, value: key })
304+
})
305+
}
306+
})
307+
308+
return mapping
309+
},
241310
},
242311
mounted() {
312+
console.log('comparator', this.comparator)
313+
console.log('optionsMapping', this.optionsMapping)
314+
console.log('this.columnsType', this.columnsType)
243315
this.fieldType = this.columnsType.find((col) => col.name === this.filter.key)?.type || 'text'
244316
},
245317
})

apps/web/src/composables/useColumnsIdentities.ts

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,30 @@ import Sandbox from '@nyariv/sandboxjs'
44
type ColumnType = {
55
name: string
66
type: string
7+
8+
valueMapping?: Record<string | number | symbol, string>
9+
}
10+
11+
enum IdentityState {
12+
SYNCED = 99,
13+
PROCESSING = 50,
14+
TO_SYNC = 2,
15+
TO_VALIDATE = 1,
16+
TO_CREATE = -1,
17+
TO_COMPLETE = -2,
18+
ON_ERROR = -3,
19+
DONT_SYNC = -99,
20+
}
21+
22+
const IdentityStateLabels: Record<IdentityState, string> = {
23+
[IdentityState.SYNCED]: 'Synchronisé',
24+
[IdentityState.PROCESSING]: 'En cours de traitement',
25+
[IdentityState.TO_SYNC]: 'À synchroniser',
26+
[IdentityState.TO_VALIDATE]: 'À valider',
27+
[IdentityState.TO_CREATE]: 'À créer',
28+
[IdentityState.TO_COMPLETE]: 'À compléter',
29+
[IdentityState.ON_ERROR]: 'En erreur',
30+
[IdentityState.DONT_SYNC]: 'Ne pas synchroniser',
731
}
832

933
interface ColumnConfig {
@@ -58,27 +82,12 @@ export function useColumnsIdentites(): useColumnsIdentitesReturnType {
5882

5983
const columns = ref<QTableProps['columns'] & { type: string }[]>([
6084
{
61-
name: 'states',
85+
name: 'state',
6286
label: 'États',
63-
field: 'states',
87+
field: 'state',
6488
align: 'left',
6589
},
6690
...config?.identitiesColumns?.entries || [],
67-
// {
68-
// name: 'state',
69-
// label: 'Status',
70-
// hidden: true,
71-
// },
72-
// {
73-
// name: 'initState',
74-
// label: 'Etat initial',
75-
// hidden: true,
76-
// },
77-
// {
78-
// name: 'lifecycle',
79-
// label: 'Cycle de vie',
80-
// hidden: true,
81-
// },
8291
{
8392
name: 'metadata.lastUpdatedAt',
8493
label: 'Date de modification',
@@ -105,11 +114,12 @@ export function useColumnsIdentites(): useColumnsIdentitesReturnType {
105114
...config?.identitiesColumns?.entries.map((col: any) => col.name) || [],
106115
'metadata.lastUpdatedAt',
107116
'metadata.createdAt',
108-
'states',
117+
'state',
109118
])
110119

111120
const columnsType = ref<ColumnType[]>([
112121
...config?.identitiesColumns?.entries.map((col: any) => ({ name: col.name, type: col.type || 'text' })) || [],
122+
{ name: 'state', type: 'number', valueMapping: IdentityStateLabels },
113123
{ name: 'metadata.lastUpdatedAt', type: 'date' },
114124
{ name: 'metadata.createdAt', type: 'date' },
115125
])

apps/web/src/composables/useFiltersQuery.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export type ComparatorType = {
3131
export type ColumnType = {
3232
name: string
3333
type: string
34+
35+
valueMapping?: Record<string | number | symbol, string>
3436
}
3537

3638
const comparatorTypes = ref<ComparatorType[]>([
@@ -149,7 +151,7 @@ const comparatorTypes = ref<ComparatorType[]>([
149151
querySign: '@',
150152
value: '@',
151153
icon: 'mdi-format-letter-matches',
152-
type: ['array'],
154+
type: ['array', 'number', 'text'],
153155
multiplefields: true,
154156
prefix: '',
155157
suffix: '',
@@ -235,6 +237,7 @@ const getSearchString = (
235237
const field = columns.value?.find((f) => f.name === fieldLabel.replace('[]', ''))
236238
if (!field) return ''
237239
const fieldType = columnTypes?.value.find((col) => col.name === fieldLabel.replace('[]', ''))?.type || 'text'
240+
const columnType = columnTypes?.value.find((col) => col.name === fieldLabel.replace('[]', ''))
238241
// if (field.type === 'multiple') {
239242
// const searchArray = Array.isArray(search) ? search : [search]
240243
// return searchArray
@@ -248,10 +251,25 @@ const getSearchString = (
248251
// if (Array.isArray(search)) {
249252
// return search.join(' ou ')
250253
// }
251-
console.log('fieldType', fieldType, fieldLabel, search, columnTypes)
254+
252255
if (fieldType === 'date') {
253256
return dayjs(search!.toString()).format('DD/MM/YYYY')
254257
}
258+
259+
if (['number', 'array', 'text'].includes(fieldType) && columnType?.valueMapping) {
260+
if (Array.isArray(search)) {
261+
return search
262+
.map((s) => {
263+
if (columnType.valueMapping) {
264+
return columnType.valueMapping[s!.toString()] || sanitizeSearchString(s!.toString())
265+
}
266+
return sanitizeSearchString(s!.toString())
267+
})
268+
.join(', ')
269+
}
270+
return columnType.valueMapping[search!.toString()] || sanitizeSearchString(search!.toString())
271+
}
272+
255273
return sanitizeSearchString(search!.toString())
256274
}
257275

@@ -348,13 +366,14 @@ export function useFiltersQuery(columns: Ref<QTableProps['columns'] & { type: st
348366
const filterKey = `${FILTER_PREFIX}${filter.querySign}${filter.field}${FILTER_SUFFIX}`
349367

350368
delete query[filterKey]
369+
delete query[filterKey + '[]'] // In case of multiple values
351370

352371
router.replace({
353372
query,
354373
})
355374
}
356375

357-
const writeFilter = (filter: { key: string; operator: string; value: string, min?: string, max?: string }) => {
376+
const writeFilter = (filter: { key: string; operator: string; value: string, min?: string, max?: string, items?: (string | number)[] }) => {
358377
const router = useRouter()
359378
const query = { ...$route.query }
360379
const comparator = comparatorTypes.value.find((comp) => comp.value === filter.operator)
@@ -367,13 +386,26 @@ export function useFiltersQuery(columns: Ref<QTableProps['columns'] & { type: st
367386
const filteredKey = key.replace(FILTER_PREFIX, '').replace(FILTER_SUFFIX, '')
368387
const extract = extractComparator(filteredKey)
369388

370-
if (extract && extract.field === filter.key) {
389+
// console.log('query key', query)
390+
if (extract && extract.field.replace('[]', '') === filter.key) {
371391
delete query[`${FILTER_PREFIX}${extract.comparator}${extract.field}${FILTER_SUFFIX}`]
392+
delete query[`${FILTER_PREFIX}${extract.comparator}${extract.field.replace('[]', '')}${FILTER_SUFFIX}[]`] // In case of multiple values
393+
// console.log('deleted key', `${FILTER_PREFIX}${extract.comparator}${extract.field}${FILTER_SUFFIX}`)
372394
}
373395
}
374396
}
375397

376-
query[filterKey] = `${comparator?.prefix || ''}${value}${comparator?.suffix || ''}`
398+
switch (filter.operator) {
399+
case '@':
400+
if (filter.items && filter.items.length > 0) {
401+
query[filterKey] = filter.items.map((item) => `${comparator?.prefix || ''}${item}${comparator?.suffix || ''}`)
402+
}
403+
break
404+
405+
default:
406+
query[filterKey] = `${comparator?.prefix || ''}${value}${comparator?.suffix || ''}`
407+
break
408+
}
377409

378410
router.replace({
379411
query,

apps/web/src/pages/identities/table.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ q-page.grid
3636
q-separator(vertical v-if="selected.length !== 0")
3737
q-btn(flat icon="mdi-cancel" color="warning" rounded @click="clearSelection" size="md" v-show="selected.length !== 0" dense)
3838
q-tooltip.text-body2(transition-show="scale" transition-hide="scale") Nettoyer la selection
39-
template(#body-cell-states="props")
39+
template(#body-cell-state="props")
4040
q-td
4141
sesame-pages-identities-states-info(:identity='props.row')
4242
template(v-slot:row-actions='{ row }')

0 commit comments

Comments
 (0)