@bagelink/vue 1.7.88 → 1.7.92
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/components/Filter.vue.d.ts +5 -5
- package/dist/components/Filter.vue.d.ts.map +1 -1
- package/dist/components/Spreadsheet/SpreadsheetTable.vue.d.ts +21 -5
- package/dist/components/Spreadsheet/SpreadsheetTable.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/composables/useEditor.d.ts +1 -0
- package/dist/components/form/inputs/RichText/composables/useEditor.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts +1 -0
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/Upload/UploadInput.vue.d.ts +4 -4
- package/dist/components/form/inputs/Upload/useFileUpload.d.ts +4 -4
- package/dist/index.cjs +23 -23
- package/dist/index.mjs +4426 -4329
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Filter.vue +330 -173
package/package.json
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
|
2
|
-
import type { ComparisonOperator
|
|
3
|
-
import { Btn, DateInput, Dropdown, SelectInput, TextInput, type Option } from '@bagelink/vue'
|
|
2
|
+
import type { ComparisonOperator } from '../utils/queryFilter'
|
|
3
|
+
import { Btn, DateInput, Dropdown, Icon, SelectInput, TextInput, type Option } from '@bagelink/vue'
|
|
4
4
|
import { computed } from 'vue'
|
|
5
5
|
|
|
6
6
|
type OptionsSource = Option[] | ((query: string) => Promise<Option[]>)
|
|
7
|
+
type Language = 'he' | 'en'
|
|
8
|
+
|
|
9
|
+
// Define missing types locally
|
|
10
|
+
type QueryObject<T = Record<string, any>> = Record<string, any> & T
|
|
11
|
+
interface Condition {
|
|
12
|
+
pr?: boolean
|
|
13
|
+
[operator: string]: any
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface FilterCondition {
|
|
17
|
+
id: string
|
|
18
|
+
field: string
|
|
19
|
+
operator: ComparisonOperator
|
|
20
|
+
value: string
|
|
21
|
+
connector: 'and' | 'or' | ''
|
|
22
|
+
}
|
|
7
23
|
|
|
8
24
|
const props = defineProps<{
|
|
9
25
|
fields: Array<{
|
|
@@ -12,44 +28,156 @@ const props = defineProps<{
|
|
|
12
28
|
type?: 'string' | 'number' | 'boolean' | 'date'
|
|
13
29
|
options?: OptionsSource
|
|
14
30
|
}>
|
|
31
|
+
language?: Language
|
|
15
32
|
}>()
|
|
16
33
|
|
|
17
34
|
const emit = defineEmits<{
|
|
18
|
-
change: [value:
|
|
35
|
+
change: [value: QueryObject<T>]
|
|
19
36
|
}>()
|
|
20
37
|
|
|
21
|
-
const model = defineModel<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const model = defineModel<QueryObject<T>>({ default: () => ({}) })
|
|
39
|
+
|
|
40
|
+
// Localization data
|
|
41
|
+
const texts = {
|
|
42
|
+
he: {
|
|
43
|
+
filter: 'פילטר',
|
|
44
|
+
noActiveFilters: 'אין פילטרים פעילים',
|
|
45
|
+
connectors: {
|
|
46
|
+
and: 'וגם',
|
|
47
|
+
or: 'או'
|
|
48
|
+
},
|
|
49
|
+
operators: {
|
|
50
|
+
eq: 'שווה ל',
|
|
51
|
+
ne: 'לא שווה ל',
|
|
52
|
+
gt: 'גדול מ',
|
|
53
|
+
ge: 'גדול או שווה ל',
|
|
54
|
+
lt: 'קטן מ',
|
|
55
|
+
le: 'קטן או שווה ל',
|
|
56
|
+
co: 'מכיל',
|
|
57
|
+
sw: 'מתחיל ב',
|
|
58
|
+
ew: 'מסתיים ב',
|
|
59
|
+
pr: 'קיים'
|
|
60
|
+
},
|
|
61
|
+
placeholders: {
|
|
62
|
+
selectField: 'בחר שדה',
|
|
63
|
+
selectOption: 'בחירה',
|
|
64
|
+
selectDate: 'בחירת תאריך',
|
|
65
|
+
enterValue: 'ערך'
|
|
66
|
+
},
|
|
67
|
+
buttons: {
|
|
68
|
+
addCondition: 'הוספת תנאי',
|
|
69
|
+
clearAll: 'נקה הכל'
|
|
70
|
+
},
|
|
71
|
+
boolean: {
|
|
72
|
+
true: 'כן',
|
|
73
|
+
false: 'לא'
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
en: {
|
|
77
|
+
filter: 'Filter',
|
|
78
|
+
noActiveFilters: 'No active filters',
|
|
79
|
+
connectors: {
|
|
80
|
+
and: 'And',
|
|
81
|
+
or: 'Or'
|
|
82
|
+
},
|
|
83
|
+
operators: {
|
|
84
|
+
eq: 'Equals',
|
|
85
|
+
ne: 'Not equals',
|
|
86
|
+
gt: 'Greater than',
|
|
87
|
+
ge: 'Greater or equal',
|
|
88
|
+
lt: 'Less than',
|
|
89
|
+
le: 'Less or equal',
|
|
90
|
+
co: 'Contains',
|
|
91
|
+
sw: 'Starts with',
|
|
92
|
+
ew: 'Ends with',
|
|
93
|
+
pr: 'Present'
|
|
94
|
+
},
|
|
95
|
+
placeholders: {
|
|
96
|
+
selectField: 'Select field',
|
|
97
|
+
selectOption: 'Select option',
|
|
98
|
+
selectDate: 'Select date',
|
|
99
|
+
enterValue: 'Value'
|
|
100
|
+
},
|
|
101
|
+
buttons: {
|
|
102
|
+
addCondition: 'Add condition',
|
|
103
|
+
clearAll: 'Clear all'
|
|
104
|
+
},
|
|
105
|
+
boolean: {
|
|
106
|
+
true: 'Yes',
|
|
107
|
+
false: 'No'
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Get current language texts
|
|
113
|
+
const currentTexts = computed(() => texts[props.language || 'en'])
|
|
114
|
+
|
|
115
|
+
// Derive conditions directly from model (read-only view)
|
|
116
|
+
const conditions = computed(() => {
|
|
117
|
+
const obj = model.value
|
|
118
|
+
if (Object.keys(obj).filter(k => !k.startsWith('_')).length === 0) {
|
|
119
|
+
return [] as FilterCondition[]
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const result: FilterCondition[] = []
|
|
123
|
+
const useOr = (obj as any)._or === true
|
|
124
|
+
|
|
125
|
+
for (const [field, value] of Object.entries(obj)) {
|
|
126
|
+
if (field.startsWith('_')) continue
|
|
127
|
+
|
|
128
|
+
const condition: FilterCondition = {
|
|
129
|
+
id: field, // use field as id for stability
|
|
130
|
+
field,
|
|
131
|
+
operator: 'eq',
|
|
132
|
+
value: '',
|
|
133
|
+
connector: result.length > 0 ? (useOr ? 'or' : 'and') : '',
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value)) {
|
|
137
|
+
const cond = value as Condition
|
|
138
|
+
if (cond.pr === true) {
|
|
139
|
+
condition.operator = 'pr'
|
|
140
|
+
} else {
|
|
141
|
+
const op = Object.keys(cond)[0] as ComparisonOperator
|
|
142
|
+
condition.operator = op
|
|
143
|
+
const val = (cond as any)[op]
|
|
144
|
+
condition.value = val === null ? 'null' : String(val)
|
|
145
|
+
}
|
|
146
|
+
} else if (value !== undefined) {
|
|
147
|
+
condition.value = value === null ? 'null' : String(value)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
result.push(condition)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return result
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
const allOperatorOptions = computed(() => [
|
|
157
|
+
{ label: currentTexts.value.operators.eq, value: 'eq' as ComparisonOperator },
|
|
158
|
+
{ label: currentTexts.value.operators.ne, value: 'ne' as ComparisonOperator },
|
|
159
|
+
{ label: currentTexts.value.operators.gt, value: 'gt' as ComparisonOperator },
|
|
160
|
+
{ label: currentTexts.value.operators.ge, value: 'ge' as ComparisonOperator },
|
|
161
|
+
{ label: currentTexts.value.operators.lt, value: 'lt' as ComparisonOperator },
|
|
162
|
+
{ label: currentTexts.value.operators.le, value: 'le' as ComparisonOperator },
|
|
163
|
+
{ label: currentTexts.value.operators.co, value: 'co' as ComparisonOperator },
|
|
164
|
+
{ label: currentTexts.value.operators.sw, value: 'sw' as ComparisonOperator },
|
|
165
|
+
{ label: currentTexts.value.operators.ew, value: 'ew' as ComparisonOperator },
|
|
166
|
+
{ label: currentTexts.value.operators.pr, value: 'pr' as ComparisonOperator },
|
|
167
|
+
])
|
|
40
168
|
|
|
41
169
|
function getOperatorsForType(fieldType: string, hasOptions: boolean) {
|
|
42
170
|
if (hasOptions) {
|
|
43
|
-
return allOperatorOptions.filter(o => ['eq', 'ne', 'pr'].includes(o.value))
|
|
171
|
+
return allOperatorOptions.value.filter(o => ['eq', 'ne', 'pr'].includes(o.value))
|
|
44
172
|
}
|
|
45
173
|
switch (fieldType) {
|
|
46
174
|
case 'boolean':
|
|
47
|
-
return allOperatorOptions.filter(o => ['eq', 'ne', 'pr'].includes(o.value))
|
|
175
|
+
return allOperatorOptions.value.filter(o => ['eq', 'ne', 'pr'].includes(o.value))
|
|
48
176
|
case 'number':
|
|
49
177
|
case 'date':
|
|
50
|
-
return allOperatorOptions.filter(o => ['eq', 'ne', 'gt', 'ge', 'lt', 'le', 'pr'].includes(o.value))
|
|
178
|
+
return allOperatorOptions.value.filter(o => ['eq', 'ne', 'gt', 'ge', 'lt', 'le', 'pr'].includes(o.value))
|
|
51
179
|
default:
|
|
52
|
-
return allOperatorOptions.filter(o => ['eq', 'ne', 'co', 'sw', 'ew', 'pr'].includes(o.value))
|
|
180
|
+
return allOperatorOptions.value.filter(o => ['eq', 'ne', 'co', 'sw', 'ew', 'pr'].includes(o.value))
|
|
53
181
|
}
|
|
54
182
|
}
|
|
55
183
|
|
|
@@ -57,191 +185,205 @@ function getFieldOptions(fieldValue: string): OptionsSource | undefined {
|
|
|
57
185
|
return props.fields.find(f => f.value === fieldValue)?.options
|
|
58
186
|
}
|
|
59
187
|
|
|
60
|
-
const booleanOptions = [
|
|
61
|
-
{ label:
|
|
62
|
-
{ label:
|
|
63
|
-
]
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
188
|
+
const booleanOptions = computed(() => [
|
|
189
|
+
{ label: currentTexts.value.boolean.true, value: 'true' },
|
|
190
|
+
{ label: currentTexts.value.boolean.false, value: 'false' },
|
|
191
|
+
])
|
|
192
|
+
|
|
193
|
+
// Update a single field in model
|
|
194
|
+
function updateCondition(field: string, operator: ComparisonOperator, value: string) {
|
|
195
|
+
const newModel = { ...model.value }
|
|
196
|
+
|
|
197
|
+
let parsedValue: any = value
|
|
198
|
+
if (value === 'true') parsedValue = true
|
|
199
|
+
else if (value === 'false') parsedValue = false
|
|
200
|
+
else if (value === 'null') parsedValue = null
|
|
201
|
+
else if (!Number.isNaN(Number(value)) && value.trim() !== '') parsedValue = Number(value)
|
|
202
|
+
|
|
203
|
+
if (operator === 'eq') {
|
|
204
|
+
(newModel as any)[field] = parsedValue
|
|
205
|
+
} else if (operator === 'pr') {
|
|
206
|
+
(newModel as any)[field] = { pr: true }
|
|
207
|
+
} else {
|
|
208
|
+
(newModel as any)[field] = { [operator]: parsedValue }
|
|
81
209
|
}
|
|
82
210
|
|
|
83
|
-
model.value =
|
|
84
|
-
emit('change',
|
|
211
|
+
model.value = newModel
|
|
212
|
+
emit('change', newModel)
|
|
85
213
|
}
|
|
86
214
|
|
|
87
215
|
function addCondition() {
|
|
88
|
-
const field = props.fields[0]?.value || ''
|
|
89
|
-
|
|
90
|
-
field,
|
|
91
|
-
op: 'eq',
|
|
92
|
-
value: '',
|
|
93
|
-
connector: model.value.length > 0 ? 'and' : undefined,
|
|
94
|
-
}
|
|
95
|
-
const newConditions = [...model.value, newCondition]
|
|
96
|
-
model.value = newConditions
|
|
97
|
-
emit('change', newConditions)
|
|
216
|
+
const field = props.fields[0]?.value || 'new_field'
|
|
217
|
+
updateCondition(field, 'eq', '')
|
|
98
218
|
}
|
|
99
219
|
|
|
100
|
-
function removeCondition(
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
model.value = newConditions
|
|
107
|
-
emit('change', newConditions)
|
|
220
|
+
function removeCondition(field: string) {
|
|
221
|
+
const newModel = { ...model.value }
|
|
222
|
+
Reflect.deleteProperty(newModel, field)
|
|
223
|
+
model.value = newModel
|
|
224
|
+
emit('change', newModel)
|
|
108
225
|
}
|
|
109
226
|
|
|
110
227
|
function clearAll() {
|
|
111
|
-
model.value =
|
|
112
|
-
emit('change',
|
|
228
|
+
model.value = {} as QueryObject<T>
|
|
229
|
+
emit('change', {} as QueryObject<T>)
|
|
113
230
|
}
|
|
114
231
|
|
|
115
232
|
function getFieldType(fieldValue: string): string {
|
|
116
233
|
return props.fields.find(f => f.value === fieldValue)?.type || 'string'
|
|
117
234
|
}
|
|
118
235
|
|
|
119
|
-
function needsValue(
|
|
120
|
-
return
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function displayValue(value: any): string {
|
|
124
|
-
if (value === null) return 'null'
|
|
125
|
-
if (value === true) return 'true'
|
|
126
|
-
if (value === false) return 'false'
|
|
127
|
-
return String(value ?? '')
|
|
236
|
+
function needsValue(operator: ComparisonOperator): boolean {
|
|
237
|
+
return operator !== 'pr'
|
|
128
238
|
}
|
|
129
239
|
|
|
130
240
|
const activeFiltersCount = computed(() => {
|
|
131
|
-
return
|
|
241
|
+
return conditions.value.filter(c => Boolean(c.field) && (c.operator === 'pr' || Boolean(c.value))).length
|
|
132
242
|
})
|
|
243
|
+
|
|
244
|
+
// Handle field change - need to rename the key in model
|
|
245
|
+
function onFieldChange(oldField: string, newField: string, condition: FilterCondition) {
|
|
246
|
+
const newModel = { ...model.value }
|
|
247
|
+
Reflect.deleteProperty(newModel, oldField)
|
|
248
|
+
|
|
249
|
+
let parsedValue: any = condition.value
|
|
250
|
+
if (condition.value === 'true') parsedValue = true
|
|
251
|
+
else if (condition.value === 'false') parsedValue = false
|
|
252
|
+
else if (condition.value === 'null') parsedValue = null
|
|
253
|
+
else if (!Number.isNaN(Number(condition.value)) && condition.value.trim() !== '') parsedValue = Number(condition.value)
|
|
254
|
+
|
|
255
|
+
if (condition.operator === 'eq') {
|
|
256
|
+
(newModel as any)[newField] = parsedValue
|
|
257
|
+
} else if (condition.operator === 'pr') {
|
|
258
|
+
(newModel as any)[newField] = { pr: true }
|
|
259
|
+
} else {
|
|
260
|
+
(newModel as any)[newField] = { [condition.operator]: parsedValue }
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
model.value = newModel
|
|
264
|
+
emit('change', newModel)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function onOperatorChange(field: string, operator: ComparisonOperator, value: string) {
|
|
268
|
+
updateCondition(field, operator, value)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function onValueChange(field: string, operator: ComparisonOperator, value: string) {
|
|
272
|
+
updateCondition(field, operator, value)
|
|
273
|
+
}
|
|
133
274
|
</script>
|
|
134
275
|
|
|
135
276
|
<template>
|
|
136
277
|
<Dropdown
|
|
137
|
-
flat
|
|
138
|
-
|
|
278
|
+
flat
|
|
279
|
+
placement="bottom-end"
|
|
280
|
+
icon="filter_alt"
|
|
281
|
+
:value="activeFiltersCount > 0 ? `${currentTexts.filter} (${activeFiltersCount})` : currentTexts.filter"
|
|
282
|
+
thin
|
|
283
|
+
:auto-hide="false"
|
|
139
284
|
>
|
|
140
|
-
<div class="
|
|
141
|
-
<
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
:options="getOperatorsForType(getFieldType(condition.field as string), !!getFieldOptions(condition.field as string))"
|
|
164
|
-
class="operator-select"
|
|
165
|
-
@update:model-value="(v: ComparisonOperator) => updateCondition(index, { op: v })"
|
|
166
|
-
/>
|
|
167
|
-
|
|
168
|
-
<!-- Value input - type-specific -->
|
|
169
|
-
<template v-if="needsValue(condition.op)">
|
|
285
|
+
<div class="p-1 m_p-05">
|
|
286
|
+
<div class="p-025 bg-bg radius-1 mb-05">
|
|
287
|
+
<!-- Empty state -->
|
|
288
|
+
<div v-if="conditions.length === 0" class="opacity-3 flex gap-05 p-025 min-w-450px m_min-0">
|
|
289
|
+
<Icon name="info" />
|
|
290
|
+
<div class="">
|
|
291
|
+
{{ currentTexts.noActiveFilters }}
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
|
|
295
|
+
<TransitionGroup name="condition">
|
|
296
|
+
<div
|
|
297
|
+
v-for="(condition, index) in conditions"
|
|
298
|
+
:key="condition.id"
|
|
299
|
+
class="grid filter-row gap-025 align-items-center p-025"
|
|
300
|
+
>
|
|
301
|
+
<!-- Connector (AND/OR) - display only for now -->
|
|
302
|
+
<div v-if="index > 0" class="min-w-20px">
|
|
303
|
+
<span class="txt12 opacity-6">{{ condition.connector === 'or' ? currentTexts.connectors.or : currentTexts.connectors.and }}</span>
|
|
304
|
+
</div>
|
|
305
|
+
<div v-else class="min-w-20px" />
|
|
306
|
+
|
|
307
|
+
<!-- Field selector -->
|
|
170
308
|
<SelectInput
|
|
171
|
-
|
|
172
|
-
:options="
|
|
173
|
-
|
|
309
|
+
:model-value="condition.field"
|
|
310
|
+
:options="fields"
|
|
311
|
+
:placeholder="currentTexts.placeholders.selectField"
|
|
312
|
+
class="m-0 light-input borderHover"
|
|
313
|
+
@update:model-value="(v: string) => onFieldChange(condition.field, v, condition)"
|
|
174
314
|
/>
|
|
315
|
+
|
|
316
|
+
<!-- Operator selector -->
|
|
175
317
|
<SelectInput
|
|
176
|
-
|
|
177
|
-
:
|
|
178
|
-
class="
|
|
179
|
-
|
|
180
|
-
<DateInput
|
|
181
|
-
v-else-if="getFieldType(condition.field as string) === 'date'"
|
|
182
|
-
:model-value="displayValue(condition.value)" placeholder="בחר תאריך" class="value-input"
|
|
183
|
-
@update:model-value="(v: any) => updateCondition(index, { value: String(v) })"
|
|
184
|
-
/>
|
|
185
|
-
<TextInput
|
|
186
|
-
v-else-if="getFieldType(condition.field as string) === 'number'"
|
|
187
|
-
:model-value="displayValue(condition.value)" placeholder="0" type="number" class="value-input"
|
|
188
|
-
@update:model-value="(v: string) => updateCondition(index, { value: v })"
|
|
318
|
+
:model-value="condition.operator"
|
|
319
|
+
:options="getOperatorsForType(getFieldType(condition.field), !!getFieldOptions(condition.field))"
|
|
320
|
+
class="m-0 light-input borderHover"
|
|
321
|
+
@update:model-value="(v: ComparisonOperator) => onOperatorChange(condition.field, v, condition.value)"
|
|
189
322
|
/>
|
|
190
|
-
<TextInput
|
|
191
|
-
v-else :model-value="displayValue(condition.value)" placeholder="ערך" class="value-input"
|
|
192
|
-
@update:model-value="(v: string) => updateCondition(index, { value: v })"
|
|
193
|
-
/>
|
|
194
|
-
</template>
|
|
195
|
-
<div v-else class="value-placeholder" />
|
|
196
323
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
324
|
+
<!-- Value input - type-specific -->
|
|
325
|
+
<template v-if="needsValue(condition.operator)">
|
|
326
|
+
<SelectInput
|
|
327
|
+
v-if="getFieldOptions(condition.field)"
|
|
328
|
+
:model-value="condition.value"
|
|
329
|
+
:options="getFieldOptions(condition.field)!"
|
|
330
|
+
:placeholder="currentTexts.placeholders.selectOption"
|
|
331
|
+
class="m-0 light-input borderHover"
|
|
332
|
+
searchable
|
|
333
|
+
@update:model-value="(v: string) => onValueChange(condition.field, condition.operator, v)"
|
|
334
|
+
/>
|
|
335
|
+
<SelectInput
|
|
336
|
+
v-else-if="getFieldType(condition.field) === 'boolean'"
|
|
337
|
+
:model-value="condition.value"
|
|
338
|
+
:options="booleanOptions"
|
|
339
|
+
:placeholder="currentTexts.placeholders.selectOption"
|
|
340
|
+
class="m-0 light-input borderHover"
|
|
341
|
+
@update:model-value="(v: string) => onValueChange(condition.field, condition.operator, v)"
|
|
342
|
+
/>
|
|
343
|
+
<DateInput
|
|
344
|
+
v-else-if="getFieldType(condition.field) === 'date'"
|
|
345
|
+
:model-value="condition.value"
|
|
346
|
+
:placeholder="currentTexts.placeholders.selectDate"
|
|
347
|
+
class="m-0 light-input borderHover"
|
|
348
|
+
@update:model-value="(v: any) => onValueChange(condition.field, condition.operator, String(v))"
|
|
349
|
+
/>
|
|
350
|
+
<TextInput
|
|
351
|
+
v-else-if="getFieldType(condition.field) === 'number'"
|
|
352
|
+
:model-value="condition.value"
|
|
353
|
+
placeholder="0"
|
|
354
|
+
type="number"
|
|
355
|
+
class="m-0 light-input borderHover"
|
|
356
|
+
@update:model-value="(v: string) => onValueChange(condition.field, condition.operator, v)"
|
|
357
|
+
/>
|
|
358
|
+
<TextInput
|
|
359
|
+
v-else
|
|
360
|
+
:model-value="condition.value"
|
|
361
|
+
:placeholder="currentTexts.placeholders.enterValue"
|
|
362
|
+
class="m-0 light-input borderHover"
|
|
363
|
+
@update:model-value="(v: string) => onValueChange(condition.field, condition.operator, v)"
|
|
364
|
+
/>
|
|
365
|
+
</template>
|
|
366
|
+
<div v-else />
|
|
367
|
+
|
|
368
|
+
<!-- Remove button -->
|
|
369
|
+
<Btn icon="close" thin flat size="small" class="m_bg-gray-40 m_px-3 m_mx-auto" @click="removeCondition(condition.field)" />
|
|
370
|
+
</div>
|
|
371
|
+
</TransitionGroup>
|
|
372
|
+
</div>
|
|
201
373
|
|
|
202
|
-
<div class="flex gap-
|
|
203
|
-
<Btn icon="add" flat thin value="
|
|
204
|
-
<Btn v-if="
|
|
374
|
+
<div class="flex gap-1 space-between">
|
|
375
|
+
<Btn icon="add" flat thin :value="currentTexts.buttons.addCondition" @click="addCondition" />
|
|
376
|
+
<Btn v-if="conditions.length > 0" icon="delete_sweep" flat thin color="gray" :value="currentTexts.buttons.clearAll" @click="clearAll" />
|
|
205
377
|
</div>
|
|
206
378
|
</div>
|
|
207
379
|
</Dropdown>
|
|
208
380
|
</template>
|
|
209
381
|
|
|
210
382
|
<style scoped>
|
|
211
|
-
.filter-
|
|
212
|
-
|
|
213
|
-
--input-height: 30px;
|
|
214
|
-
/* --input-border-radius: 100px; */
|
|
215
|
-
/* --input-bg: var(--bgl-primary-light); */
|
|
216
|
-
/* --input-color: var(--bgl-primary); */
|
|
217
|
-
min-width: 520px;
|
|
218
|
-
max-width: 90vw;
|
|
219
|
-
padding: 0.5rem;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.field-select {
|
|
223
|
-
flex: 1;
|
|
224
|
-
min-width: 120px;
|
|
225
|
-
margin: 0;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
.operator-select {
|
|
229
|
-
min-width: 120px;
|
|
230
|
-
margin: 0;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
.value-input {
|
|
234
|
-
flex: 1;
|
|
235
|
-
min-width: 100px;
|
|
236
|
-
margin: 0;
|
|
383
|
+
.filter-row {
|
|
384
|
+
grid-template-columns: auto minmax(90px, 0.5fr) minmax(170px, 0.75fr) minmax(120px, 0.5fr) auto;
|
|
237
385
|
}
|
|
238
|
-
|
|
239
|
-
.value-placeholder {
|
|
240
|
-
flex: 1;
|
|
241
|
-
min-width: 100px;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/* Transition animations */
|
|
386
|
+
/* Transition animations */
|
|
245
387
|
.condition-enter-active,
|
|
246
388
|
.condition-leave-active {
|
|
247
389
|
transition: all 0.25s ease;
|
|
@@ -264,4 +406,19 @@ const activeFiltersCount = computed(() => {
|
|
|
264
406
|
:dir(rtl) .condition-leave-to {
|
|
265
407
|
transform: translateX(-10px);
|
|
266
408
|
}
|
|
409
|
+
@media (max-width: 910px) {
|
|
410
|
+
.filter-row {
|
|
411
|
+
grid-template-columns: auto;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
</style>
|
|
415
|
+
|
|
416
|
+
<style>
|
|
417
|
+
.borderHover * {
|
|
418
|
+
transition: all 0.2s ease-in-out !important;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.borderHover:hover {
|
|
422
|
+
--border-color: var(--bgl-primary);
|
|
423
|
+
}
|
|
267
424
|
</style>
|