@bexis2/bexis2-core-ui 0.3.12 → 0.3.13
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/README.md +1 -0
- package/dist/components/File/FileUploader.svelte +3 -3
- package/dist/components/Table/TableContent.svelte +202 -119
- package/dist/components/Table/TableFilter.svelte +146 -102
- package/dist/components/Table/TableFilter.svelte.d.ts +2 -3
- package/dist/components/Table/TableFilterServer.svelte +274 -0
- package/dist/components/Table/TableFilterServer.svelte.d.ts +22 -0
- package/dist/components/Table/TablePagination.svelte +72 -39
- package/dist/components/Table/TablePaginationServer.svelte +125 -0
- package/dist/components/Table/TablePaginationServer.svelte.d.ts +21 -0
- package/dist/components/Table/filter.js +40 -78
- package/dist/components/Table/shared.d.ts +32 -0
- package/dist/components/Table/shared.js +117 -0
- package/dist/components/form/DropdownKvP.svelte.d.ts +4 -4
- package/dist/components/form/MultiSelect.svelte.d.ts +6 -6
- package/dist/models/Enums.d.ts +18 -0
- package/dist/models/Enums.js +20 -0
- package/dist/models/Models.d.ts +43 -2
- package/dist/models/Models.js +28 -1
- package/package.json +2 -2
- package/src/lib/components/Table/TableContent.svelte +227 -151
- package/src/lib/components/Table/TableFilter.svelte +166 -102
- package/src/lib/components/Table/TableFilterServer.svelte +310 -0
- package/src/lib/components/Table/TablePagination.svelte +75 -39
- package/src/lib/components/Table/TablePaginationServer.svelte +133 -0
- package/src/lib/components/Table/filter.ts +42 -86
- package/src/lib/components/Table/shared.ts +141 -0
- package/src/lib/components/file/FileUploader.svelte +3 -3
- package/src/lib/models/Enums.ts +22 -0
- package/src/lib/models/Models.ts +63 -2
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import Fa from 'svelte-fa/src/fa.svelte';
|
|
3
|
-
import { faFilter } from '@fortawesome/free-solid-svg-icons';
|
|
3
|
+
import { faFilter, faPlus, faXmark } from '@fortawesome/free-solid-svg-icons';
|
|
4
4
|
import { popup } from '@skeletonlabs/skeleton';
|
|
5
5
|
import type { PopupSettings } from '@skeletonlabs/skeleton';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import { FilterOptionsEnum } from '$models/Enums';
|
|
8
|
+
|
|
8
9
|
export let values;
|
|
9
10
|
export let id;
|
|
10
11
|
export let tableId;
|
|
11
12
|
export let toFilterableValueFn: undefined | ((value: any) => any) = undefined;
|
|
13
|
+
export let filterValue;
|
|
14
|
+
export let filters;
|
|
12
15
|
|
|
13
|
-
let firstOption;
|
|
14
|
-
let firstValue;
|
|
15
|
-
let secondOption;
|
|
16
|
-
let secondValue;
|
|
17
16
|
// If the filter is applied and the displayed values are filtered
|
|
18
17
|
let active = false;
|
|
19
18
|
|
|
@@ -21,84 +20,89 @@
|
|
|
21
20
|
const options = {
|
|
22
21
|
number: [
|
|
23
22
|
{
|
|
24
|
-
value:
|
|
23
|
+
value: FilterOptionsEnum.e,
|
|
25
24
|
label: 'Is equal to'
|
|
26
25
|
},
|
|
27
26
|
{
|
|
28
|
-
value:
|
|
27
|
+
value: FilterOptionsEnum.gte,
|
|
29
28
|
label: 'Is greater than or equal to'
|
|
30
29
|
},
|
|
31
30
|
{
|
|
32
|
-
value:
|
|
31
|
+
value: FilterOptionsEnum.gt,
|
|
33
32
|
label: 'Is greater than'
|
|
34
33
|
},
|
|
35
34
|
{
|
|
36
|
-
value:
|
|
35
|
+
value: FilterOptionsEnum.lte,
|
|
37
36
|
label: 'Is less than or equal to'
|
|
38
37
|
},
|
|
39
38
|
{
|
|
40
|
-
value:
|
|
39
|
+
value: FilterOptionsEnum.lt,
|
|
41
40
|
label: 'Is less than'
|
|
42
41
|
},
|
|
43
42
|
{
|
|
44
|
-
value:
|
|
43
|
+
value: FilterOptionsEnum.ne,
|
|
45
44
|
label: 'Is not equal to'
|
|
46
45
|
}
|
|
47
46
|
],
|
|
48
47
|
string: [
|
|
49
48
|
{
|
|
50
|
-
value:
|
|
49
|
+
value: FilterOptionsEnum.c,
|
|
51
50
|
label: 'Contains'
|
|
52
51
|
},
|
|
53
52
|
{
|
|
54
|
-
value:
|
|
53
|
+
value: FilterOptionsEnum.nc,
|
|
55
54
|
label: 'Does not contain'
|
|
56
55
|
},
|
|
57
56
|
{
|
|
58
|
-
value:
|
|
57
|
+
value: FilterOptionsEnum.e,
|
|
59
58
|
label: 'Is equal to'
|
|
60
59
|
},
|
|
61
60
|
{
|
|
62
|
-
value:
|
|
61
|
+
value: FilterOptionsEnum.ne,
|
|
63
62
|
label: 'Is not equal to'
|
|
64
63
|
},
|
|
65
64
|
{
|
|
66
|
-
value:
|
|
65
|
+
value: FilterOptionsEnum.sw,
|
|
67
66
|
label: 'Starts with'
|
|
68
67
|
},
|
|
69
68
|
{
|
|
70
|
-
value:
|
|
69
|
+
value: FilterOptionsEnum.ew,
|
|
71
70
|
label: 'Ends with'
|
|
72
71
|
}
|
|
73
72
|
],
|
|
74
73
|
date: [
|
|
75
74
|
{
|
|
76
|
-
value:
|
|
75
|
+
value: FilterOptionsEnum.o,
|
|
77
76
|
label: 'Is on'
|
|
78
77
|
},
|
|
79
78
|
{
|
|
80
|
-
value:
|
|
79
|
+
value: FilterOptionsEnum.sf,
|
|
81
80
|
label: 'Is starting from'
|
|
82
81
|
},
|
|
83
82
|
{
|
|
84
|
-
value:
|
|
83
|
+
value: FilterOptionsEnum.a,
|
|
85
84
|
label: 'Is after'
|
|
86
85
|
},
|
|
87
86
|
{
|
|
88
|
-
value:
|
|
87
|
+
value: FilterOptionsEnum.u,
|
|
89
88
|
label: 'Is until'
|
|
90
89
|
},
|
|
91
90
|
{
|
|
92
|
-
value:
|
|
91
|
+
value: FilterOptionsEnum.b,
|
|
93
92
|
label: 'Is before'
|
|
94
93
|
},
|
|
95
94
|
{
|
|
96
|
-
value:
|
|
95
|
+
value: FilterOptionsEnum.no,
|
|
97
96
|
label: 'Is not on'
|
|
98
97
|
}
|
|
99
98
|
]
|
|
100
99
|
};
|
|
101
100
|
|
|
101
|
+
let dropdowns: {
|
|
102
|
+
option: FilterOptionsEnum;
|
|
103
|
+
value: string | number | Date | undefined;
|
|
104
|
+
}[] = [];
|
|
105
|
+
|
|
102
106
|
// Unique ID for the column filter popup
|
|
103
107
|
const popupId = `${tableId}-${id}`;
|
|
104
108
|
// Popup config
|
|
@@ -122,8 +126,68 @@
|
|
|
122
126
|
}
|
|
123
127
|
}
|
|
124
128
|
});
|
|
129
|
+
|
|
130
|
+
const optionChangeHandler = (e, index) => {
|
|
131
|
+
delete $filters[id][dropdowns[index].option];
|
|
132
|
+
$filters[id] = { ...$filters[id], [e.target.value]: dropdowns[index].value };
|
|
133
|
+
$filters = $filters;
|
|
134
|
+
|
|
135
|
+
dropdowns[index] = {
|
|
136
|
+
...dropdowns[index],
|
|
137
|
+
option: e.target.value
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const valueChangeHandler = (e, index) => {
|
|
142
|
+
dropdowns[index] = {
|
|
143
|
+
...dropdowns[index],
|
|
144
|
+
value:
|
|
145
|
+
type === 'number'
|
|
146
|
+
? +e.target.value
|
|
147
|
+
: type === 'date'
|
|
148
|
+
? new Date(e.target.value)
|
|
149
|
+
: e.target.value
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
$filters = {
|
|
153
|
+
...$filters,
|
|
154
|
+
[id]: { ...$filters[id], [dropdowns[index].option]: dropdowns[index].value }
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const addFilter = (option, value) => {
|
|
159
|
+
$filters = { ...$filters, [id]: { ...$filters[id], [option]: value } };
|
|
160
|
+
|
|
161
|
+
dropdowns = [
|
|
162
|
+
...dropdowns,
|
|
163
|
+
{
|
|
164
|
+
option: option,
|
|
165
|
+
value: undefined
|
|
166
|
+
}
|
|
167
|
+
];
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const removeFilter = (option) => {
|
|
171
|
+
dropdowns = dropdowns.filter((dropdown) => dropdown.option !== option);
|
|
172
|
+
delete $filters[id][option];
|
|
173
|
+
$filters = $filters;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const clearFilters = () => {
|
|
177
|
+
dropdowns = [];
|
|
178
|
+
$filters[id] = {};
|
|
179
|
+
};
|
|
180
|
+
|
|
125
181
|
// Determine if the type is date
|
|
126
|
-
type = isDate ? 'date' : type;
|
|
182
|
+
$: type = isDate ? 'date' : type;
|
|
183
|
+
|
|
184
|
+
// Filter the unapplied filters
|
|
185
|
+
$: remainingFilters = options[type].filter(
|
|
186
|
+
(option) => !Object.keys($filters[id]).includes(option.value)
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
// Start by adding the default filter
|
|
190
|
+
$: addFilter(options[type][0].value, undefined);
|
|
127
191
|
</script>
|
|
128
192
|
|
|
129
193
|
<form class="">
|
|
@@ -138,98 +202,98 @@
|
|
|
138
202
|
</button>
|
|
139
203
|
|
|
140
204
|
<div data-popup={`${popupId}`} id={popupId} class="z-50">
|
|
141
|
-
<div class="card p-3 grid gap-2 shadow-lg w-
|
|
205
|
+
<div class="card p-3 grid gap-2 shadow-lg w-max bg-base-100">
|
|
142
206
|
<button
|
|
143
207
|
class="btn variant-filled-primary btn-sm"
|
|
144
208
|
type="button"
|
|
145
209
|
on:click|preventDefault={() => {
|
|
146
210
|
// Set the defaults when cleared
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
secondValue = undefined;
|
|
151
|
-
|
|
152
|
-
$filterValue = [firstOption, firstValue, secondOption, secondValue];
|
|
211
|
+
clearFilters();
|
|
212
|
+
addFilter(options[type][0].value, undefined);
|
|
213
|
+
$filterValue = $filters[id];
|
|
153
214
|
active = false;
|
|
154
|
-
}}>Clear
|
|
215
|
+
}}>Clear Filters</button
|
|
155
216
|
>
|
|
156
217
|
|
|
157
218
|
<label for="" class="label normal-case text-sm">Show rows with value that</label>
|
|
158
|
-
<div class="grid gap-2
|
|
159
|
-
|
|
160
|
-
class="
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
219
|
+
<div class="grid gap-2 overflow-auto">
|
|
220
|
+
{#each dropdowns as dropdown, index (index)}
|
|
221
|
+
<div class="grid gap-2 w-full">
|
|
222
|
+
<div class="flex gap-1 items-center">
|
|
223
|
+
<select
|
|
224
|
+
class="select border border-primary-500 text-sm p-1"
|
|
225
|
+
aria-label="Show rows with value that"
|
|
226
|
+
on:change={(e) => optionChangeHandler(e, index)}
|
|
227
|
+
bind:value={dropdown.option}
|
|
228
|
+
>
|
|
229
|
+
{#each options[type] as option (option)}
|
|
230
|
+
<option
|
|
231
|
+
value={option.value}
|
|
232
|
+
selected={dropdown.option === option.value}
|
|
233
|
+
disabled={Object.keys($filters[id]).includes(option.value) &&
|
|
234
|
+
dropdown.option !== option.value}>{option.label}</option
|
|
235
|
+
>
|
|
236
|
+
{/each}
|
|
237
|
+
</select>
|
|
238
|
+
{#if dropdowns.length > 1}
|
|
239
|
+
<div
|
|
240
|
+
class="btn variant-filled-warning btn-sm h-full"
|
|
241
|
+
on:click|preventDefault={() => removeFilter(dropdown.option)}
|
|
242
|
+
on:keydown|preventDefault={() => removeFilter(dropdown.option)}
|
|
243
|
+
>
|
|
244
|
+
<Fa icon={faXmark} />
|
|
245
|
+
</div>
|
|
246
|
+
{/if}
|
|
247
|
+
</div>
|
|
248
|
+
|
|
249
|
+
{#if type === 'number'}
|
|
250
|
+
<input
|
|
251
|
+
type="number"
|
|
252
|
+
class="input p-1 border border-primary-500"
|
|
253
|
+
on:input={(e) => valueChangeHandler(e, index)}
|
|
254
|
+
bind:value={dropdown.value}
|
|
255
|
+
/>
|
|
256
|
+
{:else if type === 'string'}
|
|
257
|
+
<input
|
|
258
|
+
type="text"
|
|
259
|
+
class="input p-1 border border-primary-500"
|
|
260
|
+
on:input={(e) => valueChangeHandler(e, index)}
|
|
261
|
+
bind:value={dropdown.value}
|
|
262
|
+
/>
|
|
263
|
+
{:else}
|
|
264
|
+
<input
|
|
265
|
+
type="date"
|
|
266
|
+
class="input p-1 border border-primary-500"
|
|
267
|
+
on:input={(e) => valueChangeHandler(e, index)}
|
|
268
|
+
bind:value={dropdown.value}
|
|
269
|
+
/>
|
|
270
|
+
{/if}
|
|
271
|
+
</div>
|
|
272
|
+
{#if index !== dropdowns.length - 1 && dropdowns.length > 1}
|
|
273
|
+
<label for="" class="label normal-case">And</label>
|
|
274
|
+
{/if}
|
|
275
|
+
{/each}
|
|
191
276
|
</div>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
<
|
|
195
|
-
class="
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
277
|
+
|
|
278
|
+
{#if remainingFilters.length}
|
|
279
|
+
<div
|
|
280
|
+
class="btn variant-filled-secondary btn-sm cursor-pointer"
|
|
281
|
+
on:click|stopPropagation={() => {
|
|
282
|
+
addFilter(remainingFilters[0].value, undefined);
|
|
283
|
+
}}
|
|
284
|
+
on:keydown|stopPropagation={() => {
|
|
285
|
+
addFilter(remainingFilters[0].value, undefined);
|
|
286
|
+
}}
|
|
199
287
|
>
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
</select>
|
|
204
|
-
{#if type === 'number'}
|
|
205
|
-
<input
|
|
206
|
-
type="number"
|
|
207
|
-
class="input p-1 border border-primary-500"
|
|
208
|
-
bind:value={secondValue}
|
|
209
|
-
on:click|stopPropagation
|
|
210
|
-
/>
|
|
211
|
-
{:else if type === 'string'}
|
|
212
|
-
<input
|
|
213
|
-
type="text"
|
|
214
|
-
class="input p-1 border border-primary-500"
|
|
215
|
-
bind:value={secondValue}
|
|
216
|
-
on:click|stopPropagation
|
|
217
|
-
/>
|
|
218
|
-
{:else}
|
|
219
|
-
<input
|
|
220
|
-
type="date"
|
|
221
|
-
class="input p-1 border border-primary-500"
|
|
222
|
-
bind:value={secondValue}
|
|
223
|
-
on:click|stopPropagation
|
|
224
|
-
/>
|
|
225
|
-
{/if}
|
|
226
|
-
</div>
|
|
288
|
+
<div class="flex gap-1 items-center"><Fa icon={faPlus} />Add Filter</div>
|
|
289
|
+
</div>
|
|
290
|
+
{/if}
|
|
227
291
|
<button
|
|
228
292
|
class="btn variant-filled-primary btn-sm"
|
|
229
293
|
type="button"
|
|
230
294
|
on:click|preventDefault={() => {
|
|
231
|
-
|
|
232
|
-
|
|
295
|
+
$filterValue = $filters[id];
|
|
296
|
+
active = true;
|
|
233
297
|
}}>Apply</button
|
|
234
298
|
>
|
|
235
299
|
</div>
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Fa from 'svelte-fa/src/fa.svelte';
|
|
3
|
+
import { faFilter, faPlus, faXmark } from '@fortawesome/free-solid-svg-icons';
|
|
4
|
+
import { popup } from '@skeletonlabs/skeleton';
|
|
5
|
+
import type { PopupSettings } from '@skeletonlabs/skeleton';
|
|
6
|
+
|
|
7
|
+
import { FilterOptionsEnum } from '$models/Enums';
|
|
8
|
+
|
|
9
|
+
export let values;
|
|
10
|
+
export let id;
|
|
11
|
+
export let tableId;
|
|
12
|
+
export let toFilterableValueFn: undefined | ((value: any) => any) = undefined;
|
|
13
|
+
export let filters;
|
|
14
|
+
export let updateTable;
|
|
15
|
+
export let pageIndex;
|
|
16
|
+
|
|
17
|
+
// If the filter is applied and the displayed values are filtered
|
|
18
|
+
let active = false;
|
|
19
|
+
|
|
20
|
+
// Options for different types of values
|
|
21
|
+
const options = {
|
|
22
|
+
number: [
|
|
23
|
+
{
|
|
24
|
+
value: FilterOptionsEnum.e,
|
|
25
|
+
label: 'Is equal to'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
value: FilterOptionsEnum.gte,
|
|
29
|
+
label: 'Is greater than or equal to'
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
value: FilterOptionsEnum.gt,
|
|
33
|
+
label: 'Is greater than'
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
value: FilterOptionsEnum.lte,
|
|
37
|
+
label: 'Is less than or equal to'
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
value: FilterOptionsEnum.lt,
|
|
41
|
+
label: 'Is less than'
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
value: FilterOptionsEnum.ne,
|
|
45
|
+
label: 'Is not equal to'
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
string: [
|
|
49
|
+
{
|
|
50
|
+
value: FilterOptionsEnum.c,
|
|
51
|
+
label: 'Contains'
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
value: FilterOptionsEnum.nc,
|
|
55
|
+
label: 'Does not contain'
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
value: FilterOptionsEnum.e,
|
|
59
|
+
label: 'Is equal to'
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
value: FilterOptionsEnum.ne,
|
|
63
|
+
label: 'Is not equal to'
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
value: FilterOptionsEnum.sw,
|
|
67
|
+
label: 'Starts with'
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
value: FilterOptionsEnum.ew,
|
|
71
|
+
label: 'Ends with'
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
date: [
|
|
75
|
+
{
|
|
76
|
+
value: FilterOptionsEnum.o,
|
|
77
|
+
label: 'Is on'
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
value: FilterOptionsEnum.sf,
|
|
81
|
+
label: 'Is starting from'
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
value: FilterOptionsEnum.a,
|
|
85
|
+
label: 'Is after'
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
value: FilterOptionsEnum.u,
|
|
89
|
+
label: 'Is until'
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
value: FilterOptionsEnum.b,
|
|
93
|
+
label: 'Is before'
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
value: FilterOptionsEnum.no,
|
|
97
|
+
label: 'Is not on'
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
let dropdowns: {
|
|
103
|
+
option: FilterOptionsEnum;
|
|
104
|
+
value: string | number | Date | undefined;
|
|
105
|
+
}[] = [];
|
|
106
|
+
|
|
107
|
+
// Unique ID for the column filter popup
|
|
108
|
+
const popupId = `${tableId}-${id}`;
|
|
109
|
+
// Popup config
|
|
110
|
+
const popupFeatured: PopupSettings = {
|
|
111
|
+
event: 'click',
|
|
112
|
+
target: popupId,
|
|
113
|
+
placement: 'bottom-start'
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
let type: string = 'string';
|
|
117
|
+
let isDate = false;
|
|
118
|
+
// Check the type of the column
|
|
119
|
+
$values.forEach((item) => {
|
|
120
|
+
if (item) {
|
|
121
|
+
type = typeof (toFilterableValueFn ? toFilterableValueFn(item) : item);
|
|
122
|
+
|
|
123
|
+
if (type === 'object') {
|
|
124
|
+
if (item instanceof Date) {
|
|
125
|
+
isDate = true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const optionChangeHandler = (e, index) => {
|
|
132
|
+
delete $filters[id][dropdowns[index].option];
|
|
133
|
+
$filters[id] = { ...$filters[id], [e.target.value]: dropdowns[index].value };
|
|
134
|
+
$filters = $filters;
|
|
135
|
+
|
|
136
|
+
dropdowns[index] = {
|
|
137
|
+
...dropdowns[index],
|
|
138
|
+
option: e.target.value
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const valueChangeHandler = (e, index) => {
|
|
143
|
+
dropdowns[index] = {
|
|
144
|
+
...dropdowns[index],
|
|
145
|
+
value:
|
|
146
|
+
type === 'number'
|
|
147
|
+
? +e.target.value
|
|
148
|
+
: type === 'date'
|
|
149
|
+
? new Date(e.target.value)
|
|
150
|
+
: e.target.value
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
$filters = {
|
|
154
|
+
...$filters,
|
|
155
|
+
[id]: { ...$filters[id], [dropdowns[index].option]: dropdowns[index].value }
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const addFilter = (option, value) => {
|
|
160
|
+
$filters = { ...$filters, [id]: { ...$filters[id], [option]: value } };
|
|
161
|
+
|
|
162
|
+
dropdowns = [
|
|
163
|
+
...dropdowns,
|
|
164
|
+
{
|
|
165
|
+
option: option,
|
|
166
|
+
value: undefined
|
|
167
|
+
}
|
|
168
|
+
];
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const removeFilter = (option) => {
|
|
172
|
+
dropdowns = dropdowns.filter((dropdown) => dropdown.option !== option);
|
|
173
|
+
delete $filters[id][option];
|
|
174
|
+
$filters = $filters;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const clearFilters = () => {
|
|
178
|
+
dropdowns = [];
|
|
179
|
+
$filters[id] = {};
|
|
180
|
+
|
|
181
|
+
$pageIndex = 0;
|
|
182
|
+
updateTable().then(() => {
|
|
183
|
+
active = false;
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const applyFilters = () => {
|
|
188
|
+
$pageIndex = 0;
|
|
189
|
+
updateTable().then(() => {
|
|
190
|
+
active = true;
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// Determine if the type is date
|
|
195
|
+
$: type = isDate ? 'date' : type;
|
|
196
|
+
|
|
197
|
+
// Filter the unapplied filters
|
|
198
|
+
$: remainingFilters = options[type].filter(
|
|
199
|
+
(option) => !Object.keys($filters[id]).includes(option.value)
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
// Start by adding the default filter
|
|
203
|
+
$: addFilter(options[type][0].value, undefined);
|
|
204
|
+
</script>
|
|
205
|
+
|
|
206
|
+
<form class="">
|
|
207
|
+
<button
|
|
208
|
+
class:variant-filled-primary={active}
|
|
209
|
+
class="btn w-max p-2"
|
|
210
|
+
type="button"
|
|
211
|
+
use:popup={popupFeatured}
|
|
212
|
+
id="{popupId}-button"
|
|
213
|
+
>
|
|
214
|
+
<Fa icon={faFilter} size="12" />
|
|
215
|
+
</button>
|
|
216
|
+
|
|
217
|
+
<div data-popup={`${popupId}`} id={popupId} class="z-50">
|
|
218
|
+
<div class="card p-3 grid gap-2 shadow-lg w-max bg-base-100">
|
|
219
|
+
<button
|
|
220
|
+
class="btn variant-filled-primary btn-sm"
|
|
221
|
+
type="button"
|
|
222
|
+
on:click|preventDefault={() => {
|
|
223
|
+
// Set the defaults when cleared
|
|
224
|
+
clearFilters();
|
|
225
|
+
addFilter(options[type][0].value, undefined);
|
|
226
|
+
active = false;
|
|
227
|
+
}}>Clear Filters</button
|
|
228
|
+
>
|
|
229
|
+
|
|
230
|
+
<label for="" class="label normal-case text-sm">Show rows with value that</label>
|
|
231
|
+
<div class="grid gap-2 overflow-auto">
|
|
232
|
+
{#each dropdowns as dropdown, index (index)}
|
|
233
|
+
<div class="grid gap-2 w-full">
|
|
234
|
+
<div class="flex gap-1 items-center">
|
|
235
|
+
<select
|
|
236
|
+
class="select border border-primary-500 text-sm p-1"
|
|
237
|
+
aria-label="Show rows with value that"
|
|
238
|
+
on:change={(e) => optionChangeHandler(e, index)}
|
|
239
|
+
bind:value={dropdown.option}
|
|
240
|
+
>
|
|
241
|
+
{#each options[type] as option (option)}
|
|
242
|
+
<option
|
|
243
|
+
value={option.value}
|
|
244
|
+
selected={dropdown.option === option.value}
|
|
245
|
+
disabled={Object.keys($filters[id]).includes(option.value) &&
|
|
246
|
+
dropdown.option !== option.value}>{option.label}</option
|
|
247
|
+
>
|
|
248
|
+
{/each}
|
|
249
|
+
</select>
|
|
250
|
+
{#if dropdowns.length > 1}
|
|
251
|
+
<div
|
|
252
|
+
class="btn variant-filled-warning btn-sm h-full"
|
|
253
|
+
on:click|preventDefault={() => removeFilter(dropdown.option)}
|
|
254
|
+
on:keydown|preventDefault={() => removeFilter(dropdown.option)}
|
|
255
|
+
>
|
|
256
|
+
<Fa icon={faXmark} />
|
|
257
|
+
</div>
|
|
258
|
+
{/if}
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
{#if type === 'number'}
|
|
262
|
+
<input
|
|
263
|
+
type="number"
|
|
264
|
+
class="input p-1 border border-primary-500"
|
|
265
|
+
on:input={(e) => valueChangeHandler(e, index)}
|
|
266
|
+
bind:value={dropdown.value}
|
|
267
|
+
/>
|
|
268
|
+
{:else if type === 'string'}
|
|
269
|
+
<input
|
|
270
|
+
type="text"
|
|
271
|
+
class="input p-1 border border-primary-500"
|
|
272
|
+
on:input={(e) => valueChangeHandler(e, index)}
|
|
273
|
+
bind:value={dropdown.value}
|
|
274
|
+
/>
|
|
275
|
+
{:else}
|
|
276
|
+
<input
|
|
277
|
+
type="date"
|
|
278
|
+
class="input p-1 border border-primary-500"
|
|
279
|
+
on:input={(e) => valueChangeHandler(e, index)}
|
|
280
|
+
bind:value={dropdown.value}
|
|
281
|
+
/>
|
|
282
|
+
{/if}
|
|
283
|
+
</div>
|
|
284
|
+
{#if index !== dropdowns.length - 1 && dropdowns.length > 1}
|
|
285
|
+
<label for="" class="label normal-case">And</label>
|
|
286
|
+
{/if}
|
|
287
|
+
{/each}
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
{#if remainingFilters.length}
|
|
291
|
+
<div
|
|
292
|
+
class="btn variant-filled-secondary btn-sm cursor-pointer"
|
|
293
|
+
on:click|stopPropagation={() => {
|
|
294
|
+
addFilter(remainingFilters[0].value, undefined);
|
|
295
|
+
}}
|
|
296
|
+
on:keydown|stopPropagation={() => {
|
|
297
|
+
addFilter(remainingFilters[0].value, undefined);
|
|
298
|
+
}}
|
|
299
|
+
>
|
|
300
|
+
<div class="flex gap-1 items-center"><Fa icon={faPlus} />Add Filter</div>
|
|
301
|
+
</div>
|
|
302
|
+
{/if}
|
|
303
|
+
<button
|
|
304
|
+
class="btn variant-filled-primary btn-sm"
|
|
305
|
+
type="button"
|
|
306
|
+
on:click|preventDefault={applyFilters}>Apply</button
|
|
307
|
+
>
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
</form>
|