@bexis2/bexis2-core-ui 0.4.14 → 0.4.15
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 +5 -0
- package/dist/components/Facets/Facets.svelte +101 -41
- package/dist/components/Facets/Facets.svelte.d.ts +3 -5
- package/dist/components/Facets/ShowMore.svelte +20 -30
- package/dist/components/Facets/ShowMore.svelte.d.ts +3 -5
- package/dist/models/Models.d.ts +19 -6
- package/dist/models/Models.js +3 -4
- package/package.json +1 -1
- package/src/lib/components/Facets/Facets.svelte +120 -42
- package/src/lib/components/Facets/ShowMore.svelte +20 -32
- package/src/lib/models/Models.ts +28 -14
package/README.md
CHANGED
|
@@ -1,102 +1,162 @@
|
|
|
1
|
-
<script>import {
|
|
1
|
+
<script>import { createEventDispatcher } from "svelte";
|
|
2
|
+
import { getModalStore, Modal, TreeView, TreeViewItem } from "@skeletonlabs/skeleton";
|
|
2
3
|
import ShowMore from "./ShowMore.svelte";
|
|
3
4
|
export let groupSelection = false;
|
|
4
5
|
export let groups;
|
|
5
|
-
export let selected;
|
|
6
|
-
export let selectedGroups = {};
|
|
7
6
|
export let showAll = false;
|
|
8
7
|
export let open = false;
|
|
8
|
+
let displayedGroups = structuredClone(groups);
|
|
9
|
+
let selected = groups.reduce((acc, g) => {
|
|
10
|
+
const children = g.children.reduce((acc2, c) => {
|
|
11
|
+
acc2[c.name] = {
|
|
12
|
+
...c,
|
|
13
|
+
selected: false
|
|
14
|
+
};
|
|
15
|
+
return acc2;
|
|
16
|
+
}, {});
|
|
17
|
+
acc[g.name] = {
|
|
18
|
+
...g,
|
|
19
|
+
children,
|
|
20
|
+
selected: false
|
|
21
|
+
};
|
|
22
|
+
return acc;
|
|
23
|
+
}, {});
|
|
24
|
+
let selectedItems = {};
|
|
25
|
+
let selectedGroups = {};
|
|
26
|
+
Object.keys(selected).forEach((groupName) => {
|
|
27
|
+
selectedItems[groupName] = {};
|
|
28
|
+
Object.keys(selected[groupName].children).forEach((itemName) => {
|
|
29
|
+
selectedItems[groupName][itemName] = false;
|
|
30
|
+
});
|
|
31
|
+
selectedGroups[groupName] = false;
|
|
32
|
+
});
|
|
33
|
+
const dispatch = createEventDispatcher();
|
|
9
34
|
const modalStore = getModalStore();
|
|
10
35
|
const showMore = (group) => {
|
|
11
36
|
modalStore.trigger({
|
|
12
37
|
type: "component",
|
|
13
|
-
title: `${group}`,
|
|
38
|
+
title: `${group.displayName}`,
|
|
14
39
|
component: {
|
|
15
40
|
ref: ShowMore,
|
|
16
41
|
props: {
|
|
17
42
|
group,
|
|
18
43
|
handleSave,
|
|
19
|
-
handleCancel
|
|
20
|
-
selected: selected[group],
|
|
21
|
-
items: groups[group].sort((a, b) => a.value.localeCompare(b.value))
|
|
44
|
+
handleCancel
|
|
22
45
|
}
|
|
23
46
|
}
|
|
24
47
|
});
|
|
25
48
|
};
|
|
26
|
-
const handleSave = (group
|
|
27
|
-
|
|
49
|
+
const handleSave = (group) => {
|
|
50
|
+
Object.keys(group.children).forEach((key) => {
|
|
51
|
+
selectedItems[group.name][key] = group.children[key].selected;
|
|
52
|
+
});
|
|
28
53
|
modalStore.close();
|
|
29
54
|
};
|
|
30
55
|
const handleCancel = () => {
|
|
31
56
|
modalStore.close();
|
|
32
57
|
};
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return b.count - a.count;
|
|
58
|
+
const mapSelected = (type) => {
|
|
59
|
+
const changed = [];
|
|
60
|
+
if (type === "items") {
|
|
61
|
+
Object.keys(selectedItems).forEach((group) => {
|
|
62
|
+
Object.keys(selectedItems[group]).forEach((item) => {
|
|
63
|
+
if (selectedItems[group][item] !== selected[group].children[item].selected) {
|
|
64
|
+
changed.push({
|
|
65
|
+
parent: group,
|
|
66
|
+
selectedItem: item
|
|
67
|
+
});
|
|
68
|
+
selected[group].children[item].selected = selectedItems[group][item];
|
|
45
69
|
}
|
|
46
|
-
|
|
47
|
-
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
} else {
|
|
73
|
+
Object.keys(selectedGroups).forEach((group) => {
|
|
74
|
+
if (selectedGroups[group] !== selected[group].selected) {
|
|
75
|
+
changed.push({
|
|
76
|
+
parent: null,
|
|
77
|
+
selectedItem: group
|
|
78
|
+
});
|
|
79
|
+
selected[group].selected = selectedGroups[group];
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
dispatch("change", changed);
|
|
84
|
+
};
|
|
85
|
+
const sortOptions = () => {
|
|
86
|
+
Object.keys(selected).forEach((group) => {
|
|
87
|
+
const checked = Object.keys(selected[group].children).filter((item) => selected[group].children[item].selected).map((item) => selected[group].children[item]).sort((a, b) => {
|
|
88
|
+
if (a.count != void 0 && b.count != void 0) {
|
|
89
|
+
return b.count - a.count;
|
|
90
|
+
}
|
|
91
|
+
return a.displayName.localeCompare(b.displayName);
|
|
92
|
+
}).map((item) => item.name);
|
|
93
|
+
const unchecked = Object.keys(selected[group].children).filter(
|
|
94
|
+
(item) => !checked.includes(item)
|
|
95
|
+
);
|
|
96
|
+
const groupIndex = displayedGroups.findIndex((g) => g.name === group);
|
|
97
|
+
displayedGroups[groupIndex].children = [
|
|
98
|
+
...checked.map(
|
|
99
|
+
(item) => displayedGroups[groupIndex].children.find((i) => i.name === item)
|
|
100
|
+
),
|
|
101
|
+
...unchecked.map(
|
|
102
|
+
(item) => displayedGroups[groupIndex].children.find((i) => i.name === item)
|
|
103
|
+
)
|
|
48
104
|
];
|
|
49
105
|
});
|
|
50
106
|
};
|
|
51
|
-
$:
|
|
107
|
+
$: selectedItems, mapSelected("items"), sortOptions();
|
|
108
|
+
$: selectedGroups, mapSelected("groups");
|
|
52
109
|
</script>
|
|
53
110
|
|
|
54
111
|
<TreeView selection={groupSelection} multiple={groupSelection} padding="p-1" hover="">
|
|
55
|
-
{#each
|
|
112
|
+
{#each displayedGroups as group}
|
|
56
113
|
<TreeViewItem
|
|
57
|
-
name=
|
|
58
|
-
value={group}
|
|
114
|
+
name={group.name}
|
|
115
|
+
value={group.name}
|
|
59
116
|
{open}
|
|
60
117
|
hyphenOpacity="opacity-0"
|
|
118
|
+
bind:checked={selectedGroups[group.name]}
|
|
61
119
|
bind:group={selectedGroups}
|
|
62
|
-
bind:checked={selectedGroups[group]}
|
|
63
120
|
>
|
|
64
|
-
<p class="font-semibold">{group}</p>
|
|
121
|
+
<p class="font-semibold">{group.displayName}</p>
|
|
65
122
|
|
|
66
123
|
<svelte:fragment slot="children">
|
|
67
124
|
<!-- If more than 5 choices, show the remaining in the Modal -->
|
|
68
125
|
{#if !showAll}
|
|
69
|
-
{#each
|
|
126
|
+
{#each group.children.slice(0, 5) as item}
|
|
70
127
|
<TreeViewItem
|
|
71
|
-
bind:group={
|
|
72
|
-
name={
|
|
73
|
-
value={item}
|
|
128
|
+
bind:group={selectedItems[group.name]}
|
|
129
|
+
name={item.name}
|
|
130
|
+
value={item.displayName}
|
|
74
131
|
hyphenOpacity="opacity-0"
|
|
132
|
+
bind:checked={selectedItems[group.name][item.name]}
|
|
75
133
|
spacing="space-x-3"
|
|
76
134
|
selection
|
|
77
135
|
multiple
|
|
78
136
|
>
|
|
79
|
-
<p>{item.
|
|
137
|
+
<p>{item.displayName} ({item.count})</p>
|
|
80
138
|
</TreeViewItem>
|
|
81
139
|
{/each}
|
|
82
140
|
<!-- Trigger for the Modal to view all options -->
|
|
83
|
-
{#if
|
|
141
|
+
{#if group.children.length > 5}
|
|
84
142
|
<TreeViewItem hyphenOpacity="opacity-0">
|
|
85
|
-
<button class="anchor" on:click={() => showMore(group)}>more</button
|
|
143
|
+
<button class="anchor" on:click={() => showMore(selected[group.name])}>more</button
|
|
144
|
+
></TreeViewItem
|
|
86
145
|
>
|
|
87
146
|
{/if}
|
|
88
147
|
{:else}
|
|
89
|
-
{#each
|
|
148
|
+
{#each group.children as item}
|
|
90
149
|
<TreeViewItem
|
|
91
|
-
bind:group={
|
|
92
|
-
|
|
93
|
-
|
|
150
|
+
bind:group={selectedItems[group.name]}
|
|
151
|
+
bind:checked={selectedItems[group.name][item.name]}
|
|
152
|
+
name={item.name}
|
|
153
|
+
value={item.displayName}
|
|
94
154
|
hyphenOpacity="opacity-0"
|
|
95
155
|
spacing="space-x-3"
|
|
96
156
|
selection
|
|
97
157
|
multiple
|
|
98
158
|
>
|
|
99
|
-
<p>{item.
|
|
159
|
+
<p>{item.displayName} ({item.count})</p>
|
|
100
160
|
</TreeViewItem>
|
|
101
161
|
{/each}
|
|
102
162
|
{/if}
|
|
@@ -3,15 +3,13 @@ import type { FacetGroup } from '../../models/Models';
|
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: {
|
|
5
5
|
groupSelection?: boolean;
|
|
6
|
-
groups: FacetGroup;
|
|
7
|
-
selected: FacetGroup;
|
|
8
|
-
selectedGroups?: {
|
|
9
|
-
[key: string]: boolean;
|
|
10
|
-
};
|
|
6
|
+
groups: FacetGroup[];
|
|
11
7
|
showAll?: boolean;
|
|
12
8
|
open?: boolean;
|
|
13
9
|
};
|
|
14
10
|
events: {
|
|
11
|
+
change: CustomEvent<any>;
|
|
12
|
+
} & {
|
|
15
13
|
[evt: string]: CustomEvent<any>;
|
|
16
14
|
};
|
|
17
15
|
slots: {};
|
|
@@ -1,36 +1,30 @@
|
|
|
1
1
|
<script>export let group;
|
|
2
|
-
export let items;
|
|
3
|
-
export let selected;
|
|
4
2
|
export let handleSave;
|
|
5
3
|
export let handleCancel;
|
|
6
|
-
let
|
|
7
|
-
const handleCheck = (e, index) => {
|
|
8
|
-
const target = e.target;
|
|
9
|
-
if (target.checked) {
|
|
10
|
-
selectedItems = [...selectedItems, items[index]];
|
|
11
|
-
} else {
|
|
12
|
-
selectedItems = selectedItems.filter((item) => item !== items[index]);
|
|
13
|
-
}
|
|
14
|
-
};
|
|
4
|
+
let selected = structuredClone(group.children);
|
|
15
5
|
const selectAll = () => {
|
|
16
|
-
|
|
6
|
+
Object.keys(selected).forEach((key) => selected[key].selected = true);
|
|
17
7
|
};
|
|
18
8
|
const selectNone = () => {
|
|
19
|
-
|
|
9
|
+
Object.keys(selected).forEach((key) => selected[key].selected = false);
|
|
20
10
|
};
|
|
21
11
|
const onSave = () => {
|
|
22
|
-
handleSave(
|
|
12
|
+
handleSave({
|
|
13
|
+
...group,
|
|
14
|
+
children: selected
|
|
15
|
+
});
|
|
23
16
|
};
|
|
24
17
|
const onCancel = () => {
|
|
25
|
-
|
|
18
|
+
console.log(selected, group.children);
|
|
19
|
+
selected = structuredClone(group.children);
|
|
26
20
|
handleCancel();
|
|
27
21
|
};
|
|
28
|
-
const gridClass = (
|
|
29
|
-
if (
|
|
22
|
+
const gridClass = (items) => {
|
|
23
|
+
if (items.length >= 50) {
|
|
30
24
|
return "grid-cols-5";
|
|
31
|
-
} else if (
|
|
25
|
+
} else if (items.length >= 30) {
|
|
32
26
|
return "grid-cols-4";
|
|
33
|
-
} else if (
|
|
27
|
+
} else if (items.length >= 20) {
|
|
34
28
|
return "grid-cols-3";
|
|
35
29
|
}
|
|
36
30
|
return "grid-cols-2";
|
|
@@ -39,24 +33,20 @@ const gridClass = (items2) => {
|
|
|
39
33
|
|
|
40
34
|
<div class="p-5 rounded-md bg-surface-50 dark:bg-surface-800 border-primary-500 border-2">
|
|
41
35
|
<!-- Header -->
|
|
42
|
-
<h2 class="text-xl font-semibold">{group}</h2>
|
|
36
|
+
<h2 class="text-xl font-semibold">{group.displayName}</h2>
|
|
43
37
|
|
|
44
38
|
<!-- Items -->
|
|
45
39
|
<div
|
|
46
40
|
class="grid {gridClass(
|
|
47
|
-
|
|
41
|
+
Object.keys(selected)
|
|
48
42
|
)} !gap-x-20 gap-y-2 py-10 px-2 max-h-[1000px] overflow-x-auto max-w-6xl"
|
|
49
43
|
>
|
|
50
|
-
{#each
|
|
44
|
+
{#each Object.keys(selected) as key}
|
|
51
45
|
<label class="flex gap-3 items-center">
|
|
52
|
-
<input
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
on:click={(e) => handleCheck(e, index)}
|
|
57
|
-
checked={selectedItems.includes(item)}
|
|
58
|
-
/>
|
|
59
|
-
<span class="whitespace-nowrap break-before-avoid break-after-avoid">{item.value}</span>
|
|
46
|
+
<input type="checkbox" class="checkbox" bind:checked={selected[key].selected} />
|
|
47
|
+
<span class="whitespace-nowrap break-before-avoid break-after-avoid"
|
|
48
|
+
>{selected[key].displayName}</span
|
|
49
|
+
>
|
|
60
50
|
</label>
|
|
61
51
|
{/each}
|
|
62
52
|
</div>
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
-
import type {
|
|
2
|
+
import type { SelectedFacetGroup } from '../../models/Models';
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: {
|
|
5
|
-
group:
|
|
6
|
-
|
|
7
|
-
selected: FacetOption[];
|
|
8
|
-
handleSave: (group: string, selectedItems: FacetOption[]) => {};
|
|
5
|
+
group: SelectedFacetGroup;
|
|
6
|
+
handleSave: (group: SelectedFacetGroup) => {};
|
|
9
7
|
handleCancel: () => {};
|
|
10
8
|
};
|
|
11
9
|
events: {
|
package/dist/models/Models.d.ts
CHANGED
|
@@ -151,13 +151,26 @@ export type Filter = {
|
|
|
151
151
|
filterBy: FilterOptionsEnum;
|
|
152
152
|
value: string | number | Date | boolean;
|
|
153
153
|
};
|
|
154
|
-
export
|
|
155
|
-
|
|
154
|
+
export interface FacetOption {
|
|
155
|
+
name: string;
|
|
156
|
+
displayName: string;
|
|
156
157
|
count?: number;
|
|
157
|
-
}
|
|
158
|
-
export
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
}
|
|
159
|
+
export interface FacetGroup {
|
|
160
|
+
name: string;
|
|
161
|
+
displayName: string;
|
|
162
|
+
children: FacetOption[];
|
|
163
|
+
count?: number;
|
|
164
|
+
}
|
|
165
|
+
export interface SelectedFacetOption extends FacetOption {
|
|
166
|
+
selected: boolean;
|
|
167
|
+
}
|
|
168
|
+
export interface SelectedFacetGroup extends Omit<FacetGroup, 'children'> {
|
|
169
|
+
selected: boolean;
|
|
170
|
+
children: {
|
|
171
|
+
[key: string]: SelectedFacetOption;
|
|
172
|
+
};
|
|
173
|
+
}
|
|
161
174
|
export declare class Send {
|
|
162
175
|
id: number;
|
|
163
176
|
limit: number;
|
package/dist/models/Models.js
CHANGED
package/package.json
CHANGED
|
@@ -1,36 +1,71 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { createEventDispatcher } from 'svelte';
|
|
2
3
|
import { getModalStore, Modal, TreeView, TreeViewItem } from '@skeletonlabs/skeleton';
|
|
3
4
|
|
|
4
5
|
import ShowMore from './ShowMore.svelte';
|
|
5
|
-
import type {
|
|
6
|
+
import type { FacetGroup, SelectedFacetGroup } from '$models/Models';
|
|
6
7
|
|
|
7
8
|
export let groupSelection = false;
|
|
8
|
-
export let groups: FacetGroup;
|
|
9
|
-
export let selected: FacetGroup;
|
|
10
|
-
export let selectedGroups: { [key: string]: boolean } = {};
|
|
9
|
+
export let groups: FacetGroup[];
|
|
11
10
|
export let showAll = false;
|
|
12
11
|
export let open = false;
|
|
13
12
|
|
|
13
|
+
let displayedGroups = structuredClone(groups);
|
|
14
|
+
|
|
15
|
+
let selected: { [key: string]: SelectedFacetGroup } = groups.reduce((acc, g) => {
|
|
16
|
+
const children = g.children.reduce((acc, c) => {
|
|
17
|
+
acc[c.name] = {
|
|
18
|
+
...c,
|
|
19
|
+
selected: false
|
|
20
|
+
};
|
|
21
|
+
return acc;
|
|
22
|
+
}, {});
|
|
23
|
+
|
|
24
|
+
acc[g.name] = {
|
|
25
|
+
...g,
|
|
26
|
+
children,
|
|
27
|
+
selected: false
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return acc;
|
|
31
|
+
}, {});
|
|
32
|
+
let selectedItems: {
|
|
33
|
+
[key: string]: {
|
|
34
|
+
[key: string]: boolean;
|
|
35
|
+
};
|
|
36
|
+
} = {};
|
|
37
|
+
let selectedGroups: { [key: string]: boolean } = {};
|
|
38
|
+
|
|
39
|
+
Object.keys(selected).forEach((groupName) => {
|
|
40
|
+
selectedItems[groupName] = {};
|
|
41
|
+
Object.keys(selected[groupName].children).forEach((itemName) => {
|
|
42
|
+
selectedItems[groupName][itemName] = false;
|
|
43
|
+
});
|
|
44
|
+
selectedGroups[groupName] = false;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const dispatch = createEventDispatcher();
|
|
48
|
+
|
|
14
49
|
const modalStore = getModalStore();
|
|
15
|
-
const showMore = (group:
|
|
50
|
+
const showMore = (group: SelectedFacetGroup) => {
|
|
16
51
|
modalStore.trigger({
|
|
17
52
|
type: 'component',
|
|
18
|
-
title: `${group}`,
|
|
53
|
+
title: `${group.displayName}`,
|
|
19
54
|
component: {
|
|
20
55
|
ref: ShowMore,
|
|
21
56
|
props: {
|
|
22
57
|
group,
|
|
23
58
|
handleSave,
|
|
24
|
-
handleCancel
|
|
25
|
-
selected: selected[group],
|
|
26
|
-
items: groups[group].sort((a, b) => a.value.localeCompare(b.value))
|
|
59
|
+
handleCancel
|
|
27
60
|
}
|
|
28
61
|
}
|
|
29
62
|
});
|
|
30
63
|
};
|
|
31
64
|
|
|
32
|
-
const handleSave = (group:
|
|
33
|
-
|
|
65
|
+
const handleSave = (group: SelectedFacetGroup) => {
|
|
66
|
+
Object.keys(group.children).forEach((key) => {
|
|
67
|
+
selectedItems[group.name][key] = group.children[key].selected;
|
|
68
|
+
});
|
|
34
69
|
modalStore.close();
|
|
35
70
|
};
|
|
36
71
|
|
|
@@ -38,77 +73,120 @@
|
|
|
38
73
|
modalStore.close();
|
|
39
74
|
};
|
|
40
75
|
|
|
76
|
+
const mapSelected = (type: 'items' | 'groups') => {
|
|
77
|
+
const changed: any = [];
|
|
78
|
+
|
|
79
|
+
if (type === 'items') {
|
|
80
|
+
Object.keys(selectedItems).forEach((group) => {
|
|
81
|
+
Object.keys(selectedItems[group]).forEach((item) => {
|
|
82
|
+
if (selectedItems[group][item] !== selected[group].children[item].selected) {
|
|
83
|
+
changed.push({
|
|
84
|
+
parent: group,
|
|
85
|
+
selectedItem: item
|
|
86
|
+
});
|
|
87
|
+
selected[group].children[item].selected = selectedItems[group][item];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
} else {
|
|
92
|
+
Object.keys(selectedGroups).forEach((group) => {
|
|
93
|
+
if (selectedGroups[group] !== selected[group].selected) {
|
|
94
|
+
changed.push({
|
|
95
|
+
parent: null,
|
|
96
|
+
selectedItem: group
|
|
97
|
+
});
|
|
98
|
+
selected[group].selected = selectedGroups[group];
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
dispatch('change', changed);
|
|
104
|
+
};
|
|
105
|
+
|
|
41
106
|
const sortOptions = () => {
|
|
42
107
|
// Sort facets in a descending order if count exits, or sort alphabetically
|
|
43
|
-
Object.keys(
|
|
44
|
-
|
|
45
|
-
|
|
108
|
+
Object.keys(selected).forEach((group) => {
|
|
109
|
+
const checked = Object.keys(selected[group].children)
|
|
110
|
+
.filter((item) => selected[group].children[item].selected)
|
|
111
|
+
.map((item) => selected[group].children[item])
|
|
112
|
+
.sort((a, b) => {
|
|
46
113
|
if (a.count != undefined && b.count != undefined) {
|
|
47
114
|
return b.count - a.count;
|
|
48
115
|
}
|
|
49
|
-
return a.
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
116
|
+
return a.displayName.localeCompare(b.displayName);
|
|
117
|
+
})
|
|
118
|
+
.map((item) => item.name);
|
|
119
|
+
|
|
120
|
+
const unchecked = Object.keys(selected[group].children).filter(
|
|
121
|
+
(item) => !checked.includes(item)
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const groupIndex = displayedGroups.findIndex((g) => g.name === group);
|
|
125
|
+
|
|
126
|
+
displayedGroups[groupIndex].children = [
|
|
127
|
+
...checked.map(
|
|
128
|
+
(item) => displayedGroups[groupIndex].children.find((i) => i.name === item)!
|
|
129
|
+
),
|
|
130
|
+
...unchecked.map(
|
|
131
|
+
(item) => displayedGroups[groupIndex].children.find((i) => i.name === item)!
|
|
132
|
+
)
|
|
59
133
|
];
|
|
60
134
|
});
|
|
61
135
|
};
|
|
62
136
|
|
|
63
|
-
$:
|
|
137
|
+
$: selectedItems, mapSelected('items'), sortOptions();
|
|
138
|
+
$: selectedGroups, mapSelected('groups');
|
|
64
139
|
</script>
|
|
65
140
|
|
|
66
141
|
<TreeView selection={groupSelection} multiple={groupSelection} padding="p-1" hover="">
|
|
67
|
-
{#each
|
|
142
|
+
{#each displayedGroups as group}
|
|
68
143
|
<TreeViewItem
|
|
69
|
-
name=
|
|
70
|
-
value={group}
|
|
144
|
+
name={group.name}
|
|
145
|
+
value={group.name}
|
|
71
146
|
{open}
|
|
72
147
|
hyphenOpacity="opacity-0"
|
|
148
|
+
bind:checked={selectedGroups[group.name]}
|
|
73
149
|
bind:group={selectedGroups}
|
|
74
|
-
bind:checked={selectedGroups[group]}
|
|
75
150
|
>
|
|
76
|
-
<p class="font-semibold">{group}</p>
|
|
151
|
+
<p class="font-semibold">{group.displayName}</p>
|
|
77
152
|
|
|
78
153
|
<svelte:fragment slot="children">
|
|
79
154
|
<!-- If more than 5 choices, show the remaining in the Modal -->
|
|
80
155
|
{#if !showAll}
|
|
81
|
-
{#each
|
|
156
|
+
{#each group.children.slice(0, 5) as item}
|
|
82
157
|
<TreeViewItem
|
|
83
|
-
bind:group={
|
|
84
|
-
name={
|
|
85
|
-
value={item}
|
|
158
|
+
bind:group={selectedItems[group.name]}
|
|
159
|
+
name={item.name}
|
|
160
|
+
value={item.displayName}
|
|
86
161
|
hyphenOpacity="opacity-0"
|
|
162
|
+
bind:checked={selectedItems[group.name][item.name]}
|
|
87
163
|
spacing="space-x-3"
|
|
88
164
|
selection
|
|
89
165
|
multiple
|
|
90
166
|
>
|
|
91
|
-
<p>{item.
|
|
167
|
+
<p>{item.displayName} ({item.count})</p>
|
|
92
168
|
</TreeViewItem>
|
|
93
169
|
{/each}
|
|
94
170
|
<!-- Trigger for the Modal to view all options -->
|
|
95
|
-
{#if
|
|
171
|
+
{#if group.children.length > 5}
|
|
96
172
|
<TreeViewItem hyphenOpacity="opacity-0">
|
|
97
|
-
<button class="anchor" on:click={() => showMore(group)}>more</button
|
|
173
|
+
<button class="anchor" on:click={() => showMore(selected[group.name])}>more</button
|
|
174
|
+
></TreeViewItem
|
|
98
175
|
>
|
|
99
176
|
{/if}
|
|
100
177
|
{:else}
|
|
101
|
-
{#each
|
|
178
|
+
{#each group.children as item}
|
|
102
179
|
<TreeViewItem
|
|
103
|
-
bind:group={
|
|
104
|
-
|
|
105
|
-
|
|
180
|
+
bind:group={selectedItems[group.name]}
|
|
181
|
+
bind:checked={selectedItems[group.name][item.name]}
|
|
182
|
+
name={item.name}
|
|
183
|
+
value={item.displayName}
|
|
106
184
|
hyphenOpacity="opacity-0"
|
|
107
185
|
spacing="space-x-3"
|
|
108
186
|
selection
|
|
109
187
|
multiple
|
|
110
188
|
>
|
|
111
|
-
<p>{item.
|
|
189
|
+
<p>{item.displayName} ({item.count})</p>
|
|
112
190
|
</TreeViewItem>
|
|
113
191
|
{/each}
|
|
114
192
|
{/if}
|
|
@@ -1,42 +1,34 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type {
|
|
2
|
+
import type { SelectedFacetGroup } from '$models/Models';
|
|
3
3
|
|
|
4
|
-
export let group:
|
|
5
|
-
export let
|
|
6
|
-
export let selected: FacetOption[]; // Initially selected items
|
|
7
|
-
export let handleSave: (group: string, selectedItems: FacetOption[]) => {};
|
|
4
|
+
export let group: SelectedFacetGroup;
|
|
5
|
+
export let handleSave: (group: SelectedFacetGroup) => {};
|
|
8
6
|
export let handleCancel: () => {};
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
let selectedItems = selected; // Selected items in the Modal.
|
|
12
|
-
|
|
13
|
-
const handleCheck = (e, index: number) => {
|
|
14
|
-
const target = e.target as HTMLInputElement;
|
|
15
|
-
if (target.checked) {
|
|
16
|
-
selectedItems = [...selectedItems, items[index]];
|
|
17
|
-
} else {
|
|
18
|
-
selectedItems = selectedItems.filter((item) => item !== items[index]);
|
|
19
|
-
}
|
|
20
|
-
};
|
|
8
|
+
let selected = structuredClone(group.children);
|
|
21
9
|
|
|
22
10
|
const selectAll = () => {
|
|
23
|
-
|
|
11
|
+
Object.keys(selected).forEach((key) => (selected[key].selected = true));
|
|
24
12
|
};
|
|
25
13
|
|
|
26
14
|
const selectNone = () => {
|
|
27
|
-
|
|
15
|
+
Object.keys(selected).forEach((key) => (selected[key].selected = false));
|
|
28
16
|
};
|
|
29
17
|
|
|
30
18
|
const onSave = () => {
|
|
31
|
-
handleSave(
|
|
19
|
+
handleSave({
|
|
20
|
+
...group,
|
|
21
|
+
children: selected
|
|
22
|
+
});
|
|
32
23
|
};
|
|
33
24
|
|
|
34
25
|
const onCancel = () => {
|
|
35
|
-
|
|
26
|
+
console.log(selected, group.children);
|
|
27
|
+
selected = structuredClone(group.children);
|
|
36
28
|
handleCancel();
|
|
37
29
|
};
|
|
38
30
|
|
|
39
|
-
const gridClass = (items:
|
|
31
|
+
const gridClass = (items: any[]) => {
|
|
40
32
|
if (items.length >= 50) {
|
|
41
33
|
return 'grid-cols-5';
|
|
42
34
|
} else if (items.length >= 30) {
|
|
@@ -51,24 +43,20 @@
|
|
|
51
43
|
|
|
52
44
|
<div class="p-5 rounded-md bg-surface-50 dark:bg-surface-800 border-primary-500 border-2">
|
|
53
45
|
<!-- Header -->
|
|
54
|
-
<h2 class="text-xl font-semibold">{group}</h2>
|
|
46
|
+
<h2 class="text-xl font-semibold">{group.displayName}</h2>
|
|
55
47
|
|
|
56
48
|
<!-- Items -->
|
|
57
49
|
<div
|
|
58
50
|
class="grid {gridClass(
|
|
59
|
-
|
|
51
|
+
Object.keys(selected)
|
|
60
52
|
)} !gap-x-20 gap-y-2 py-10 px-2 max-h-[1000px] overflow-x-auto max-w-6xl"
|
|
61
53
|
>
|
|
62
|
-
{#each
|
|
54
|
+
{#each Object.keys(selected) as key}
|
|
63
55
|
<label class="flex gap-3 items-center">
|
|
64
|
-
<input
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
on:click={(e) => handleCheck(e, index)}
|
|
69
|
-
checked={selectedItems.includes(item)}
|
|
70
|
-
/>
|
|
71
|
-
<span class="whitespace-nowrap break-before-avoid break-after-avoid">{item.value}</span>
|
|
56
|
+
<input type="checkbox" class="checkbox" bind:checked={selected[key].selected} />
|
|
57
|
+
<span class="whitespace-nowrap break-before-avoid break-after-avoid"
|
|
58
|
+
>{selected[key].displayName}</span
|
|
59
|
+
>
|
|
72
60
|
</label>
|
|
73
61
|
{/each}
|
|
74
62
|
</div>
|
package/src/lib/models/Models.ts
CHANGED
|
@@ -104,7 +104,7 @@ export interface Columns {
|
|
|
104
104
|
[key: string]: Column;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
// Server config type for the table
|
|
107
|
+
// Server config type for the table
|
|
108
108
|
export type ServerConfig = {
|
|
109
109
|
baseUrl?: string; // Base URL for server-side table
|
|
110
110
|
sendModel?: Send; // Send model for server-side table
|
|
@@ -191,14 +191,29 @@ export type Filter = {
|
|
|
191
191
|
value: string | number | Date | boolean;
|
|
192
192
|
};
|
|
193
193
|
|
|
194
|
-
export
|
|
195
|
-
|
|
194
|
+
export interface FacetOption {
|
|
195
|
+
name: string;
|
|
196
|
+
displayName: string;
|
|
196
197
|
count?: number;
|
|
197
|
-
}
|
|
198
|
+
}
|
|
198
199
|
|
|
199
|
-
export
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
export interface FacetGroup {
|
|
201
|
+
name: string;
|
|
202
|
+
displayName: string;
|
|
203
|
+
children: FacetOption[];
|
|
204
|
+
count?: number;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface SelectedFacetOption extends FacetOption {
|
|
208
|
+
selected: boolean;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export interface SelectedFacetGroup extends Omit<FacetGroup, 'children'> {
|
|
212
|
+
selected: boolean;
|
|
213
|
+
children: {
|
|
214
|
+
[key: string]: SelectedFacetOption;
|
|
215
|
+
};
|
|
216
|
+
}
|
|
202
217
|
|
|
203
218
|
export class Send {
|
|
204
219
|
id: number;
|
|
@@ -237,14 +252,13 @@ export class Receive {
|
|
|
237
252
|
export class errorType {
|
|
238
253
|
statusText: string;
|
|
239
254
|
status: number;
|
|
240
|
-
error:string;
|
|
241
|
-
stackTrace:string
|
|
255
|
+
error: string;
|
|
256
|
+
stackTrace: string;
|
|
242
257
|
|
|
243
258
|
constructor() {
|
|
244
|
-
this.statusText =
|
|
259
|
+
this.statusText = '';
|
|
245
260
|
this.status = 0;
|
|
246
|
-
this.error =
|
|
247
|
-
this.stackTrace =
|
|
261
|
+
this.error = '';
|
|
262
|
+
this.stackTrace = '';
|
|
248
263
|
}
|
|
249
|
-
|
|
250
|
-
};
|
|
264
|
+
}
|