@bexis2/bexis2-core-ui 0.4.14 → 0.4.16
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 +11 -0
- package/dist/components/Facets/Facets.svelte +106 -41
- package/dist/components/Facets/Facets.svelte.d.ts +4 -5
- package/dist/components/Facets/ShowMore.svelte +20 -30
- package/dist/components/Facets/ShowMore.svelte.d.ts +3 -5
- package/dist/index.d.ts +2 -0
- package/dist/models/Models.d.ts +17 -6
- package/dist/models/Models.js +3 -4
- package/package.json +1 -1
- package/src/lib/components/Facets/Facets.svelte +127 -42
- package/src/lib/components/Facets/ShowMore.svelte +20 -32
- package/src/lib/index.ts +2 -0
- package/src/lib/models/Models.ts +25 -14
package/README.md
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
# bexis-core-ui
|
|
2
|
+
|
|
3
|
+
## 0.4.16
|
|
4
|
+
- Facets
|
|
5
|
+
- Replaces groups array with a writable store to re-render component on data manipulation.
|
|
6
|
+
- Adds selected attribute to the type so that Facets can be initialized with some selected values.
|
|
7
|
+
|
|
8
|
+
## 0.4.15
|
|
9
|
+
- Update Facets with new params and add onChange action
|
|
10
|
+
- Changes structure of Facets data
|
|
11
|
+
- Adds on:change action
|
|
12
|
+
|
|
2
13
|
## 0.4.14
|
|
3
14
|
- Table
|
|
4
15
|
- fixes rendering issues with Table filters and different components
|
|
@@ -1,102 +1,167 @@
|
|
|
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 selected;
|
|
9
|
+
let selectedItems = {};
|
|
10
|
+
let selectedGroups = {};
|
|
11
|
+
const dispatch = createEventDispatcher();
|
|
9
12
|
const modalStore = getModalStore();
|
|
10
13
|
const showMore = (group) => {
|
|
11
14
|
modalStore.trigger({
|
|
12
15
|
type: "component",
|
|
13
|
-
title: `${group}`,
|
|
16
|
+
title: `${group.displayName}`,
|
|
14
17
|
component: {
|
|
15
18
|
ref: ShowMore,
|
|
16
19
|
props: {
|
|
17
20
|
group,
|
|
18
21
|
handleSave,
|
|
19
|
-
handleCancel
|
|
20
|
-
selected: selected[group],
|
|
21
|
-
items: groups[group].sort((a, b) => a.value.localeCompare(b.value))
|
|
22
|
+
handleCancel
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
});
|
|
25
26
|
};
|
|
26
|
-
const handleSave = (group
|
|
27
|
-
|
|
27
|
+
const handleSave = (group) => {
|
|
28
|
+
Object.keys(group.children).forEach((key) => {
|
|
29
|
+
selectedItems[group.name][key] = group.children[key].selected || false;
|
|
30
|
+
});
|
|
28
31
|
modalStore.close();
|
|
29
32
|
};
|
|
30
33
|
const handleCancel = () => {
|
|
31
34
|
modalStore.close();
|
|
32
35
|
};
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
const mapSelected = (type) => {
|
|
37
|
+
const changed = [];
|
|
38
|
+
if (type === "items") {
|
|
39
|
+
Object.keys(selectedItems).forEach((group) => {
|
|
40
|
+
Object.keys(selectedItems[group]).forEach((item) => {
|
|
41
|
+
if (selectedItems[group][item] !== selected[group].children[item].selected) {
|
|
42
|
+
changed.push({
|
|
43
|
+
parent: group,
|
|
44
|
+
selectedItem: item
|
|
45
|
+
});
|
|
46
|
+
selected[group].children[item].selected = selectedItems[group][item];
|
|
39
47
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
} else {
|
|
51
|
+
Object.keys(selectedGroups).forEach((group) => {
|
|
52
|
+
if (selectedGroups[group] !== selected[group].selected) {
|
|
53
|
+
changed.push({
|
|
54
|
+
parent: null,
|
|
55
|
+
selectedItem: group
|
|
56
|
+
});
|
|
57
|
+
selected[group].selected = selectedGroups[group];
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
changed.length && dispatch("change", changed);
|
|
62
|
+
};
|
|
63
|
+
const sortOptions = () => {
|
|
64
|
+
Object.keys(selected).forEach((group) => {
|
|
65
|
+
const checked = Object.keys(selected[group].children).filter((item) => selected[group].children[item].selected).map((item) => selected[group].children[item]).sort((a, b) => {
|
|
66
|
+
if (a.count != void 0 && b.count != void 0) {
|
|
67
|
+
return b.count - a.count;
|
|
68
|
+
}
|
|
69
|
+
return a.displayName.localeCompare(b.displayName);
|
|
70
|
+
}).map((item) => item.name);
|
|
71
|
+
const unchecked = Object.keys(selected[group].children).filter(
|
|
72
|
+
(item) => !checked.includes(item)
|
|
73
|
+
);
|
|
74
|
+
const groupIndex = displayedGroups.findIndex((g) => g.name === group);
|
|
75
|
+
displayedGroups[groupIndex].children = [
|
|
76
|
+
...checked.map(
|
|
77
|
+
(item) => displayedGroups[groupIndex].children.find((i) => i.name === item)
|
|
78
|
+
),
|
|
79
|
+
...unchecked.map(
|
|
80
|
+
(item) => displayedGroups[groupIndex].children.find((i) => i.name === item)
|
|
81
|
+
)
|
|
48
82
|
];
|
|
49
83
|
});
|
|
50
84
|
};
|
|
51
|
-
|
|
85
|
+
groups.subscribe((data) => {
|
|
86
|
+
selected = data.reduce((acc, g) => {
|
|
87
|
+
const children = g.children.reduce((acc2, c) => {
|
|
88
|
+
acc2[c.name] = {
|
|
89
|
+
...c,
|
|
90
|
+
selected: c.selected || false
|
|
91
|
+
};
|
|
92
|
+
return acc2;
|
|
93
|
+
}, {});
|
|
94
|
+
acc[g.name] = {
|
|
95
|
+
...g,
|
|
96
|
+
children,
|
|
97
|
+
selected: g.selected || false
|
|
98
|
+
};
|
|
99
|
+
return acc;
|
|
100
|
+
}, {});
|
|
101
|
+
Object.keys(selected).forEach((groupName) => {
|
|
102
|
+
selectedItems[groupName] = {};
|
|
103
|
+
Object.keys(selected[groupName].children).forEach((itemName) => {
|
|
104
|
+
selectedItems[groupName][itemName] = selected[groupName].children[itemName].selected || false;
|
|
105
|
+
});
|
|
106
|
+
selectedGroups[groupName] = selected[groupName].selected || false;
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
$: displayedGroups = structuredClone($groups);
|
|
110
|
+
$: selectedItems, mapSelected("items"), sortOptions();
|
|
111
|
+
$: selectedGroups, mapSelected("groups");
|
|
52
112
|
</script>
|
|
53
113
|
|
|
54
114
|
<TreeView selection={groupSelection} multiple={groupSelection} padding="p-1" hover="">
|
|
55
|
-
{#each
|
|
115
|
+
{#each displayedGroups as group}
|
|
56
116
|
<TreeViewItem
|
|
57
|
-
name=
|
|
58
|
-
value={group}
|
|
117
|
+
name={group.name}
|
|
118
|
+
value={group.name}
|
|
59
119
|
{open}
|
|
60
120
|
hyphenOpacity="opacity-0"
|
|
121
|
+
bind:checked={selectedGroups[group.name]}
|
|
61
122
|
bind:group={selectedGroups}
|
|
62
|
-
bind:checked={selectedGroups[group]}
|
|
63
123
|
>
|
|
64
|
-
<p class="font-semibold">
|
|
124
|
+
<p class="font-semibold">
|
|
125
|
+
{group.displayName}{group.count !== undefined ? ` (${group.count})` : ''}
|
|
126
|
+
</p>
|
|
65
127
|
|
|
66
128
|
<svelte:fragment slot="children">
|
|
67
129
|
<!-- If more than 5 choices, show the remaining in the Modal -->
|
|
68
130
|
{#if !showAll}
|
|
69
|
-
{#each
|
|
131
|
+
{#each group.children.slice(0, 5) as item}
|
|
70
132
|
<TreeViewItem
|
|
71
|
-
bind:group={
|
|
72
|
-
name={
|
|
73
|
-
value={item}
|
|
133
|
+
bind:group={selectedItems[group.name]}
|
|
134
|
+
name={item.name}
|
|
135
|
+
value={item.displayName}
|
|
74
136
|
hyphenOpacity="opacity-0"
|
|
137
|
+
bind:checked={selectedItems[group.name][item.name]}
|
|
75
138
|
spacing="space-x-3"
|
|
76
139
|
selection
|
|
77
140
|
multiple
|
|
78
141
|
>
|
|
79
|
-
<p>{item.
|
|
142
|
+
<p>{item.displayName} ({item.count})</p>
|
|
80
143
|
</TreeViewItem>
|
|
81
144
|
{/each}
|
|
82
145
|
<!-- Trigger for the Modal to view all options -->
|
|
83
|
-
{#if
|
|
146
|
+
{#if group.children.length > 5}
|
|
84
147
|
<TreeViewItem hyphenOpacity="opacity-0">
|
|
85
|
-
<button class="anchor" on:click={() => showMore(group)}>more</button
|
|
148
|
+
<button class="anchor" on:click={() => showMore(selected[group.name])}>more</button
|
|
149
|
+
></TreeViewItem
|
|
86
150
|
>
|
|
87
151
|
{/if}
|
|
88
152
|
{:else}
|
|
89
|
-
{#each
|
|
153
|
+
{#each group.children as item}
|
|
90
154
|
<TreeViewItem
|
|
91
|
-
bind:group={
|
|
92
|
-
|
|
93
|
-
|
|
155
|
+
bind:group={selectedItems[group.name]}
|
|
156
|
+
bind:checked={selectedItems[group.name][item.name]}
|
|
157
|
+
name={item.name}
|
|
158
|
+
value={item.displayName}
|
|
94
159
|
hyphenOpacity="opacity-0"
|
|
95
160
|
spacing="space-x-3"
|
|
96
161
|
selection
|
|
97
162
|
multiple
|
|
98
163
|
>
|
|
99
|
-
<p>{item.
|
|
164
|
+
<p>{item.displayName} ({item.count})</p>
|
|
100
165
|
</TreeViewItem>
|
|
101
166
|
{/each}
|
|
102
167
|
{/if}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { Writable } from 'svelte/store';
|
|
2
3
|
import type { FacetGroup } from '../../models/Models';
|
|
3
4
|
declare const __propDef: {
|
|
4
5
|
props: {
|
|
5
6
|
groupSelection?: boolean;
|
|
6
|
-
groups: FacetGroup
|
|
7
|
-
selected: FacetGroup;
|
|
8
|
-
selectedGroups?: {
|
|
9
|
-
[key: string]: boolean;
|
|
10
|
-
};
|
|
7
|
+
groups: Writable<FacetGroup[]>;
|
|
11
8
|
showAll?: boolean;
|
|
12
9
|
open?: boolean;
|
|
13
10
|
};
|
|
14
11
|
events: {
|
|
12
|
+
change: CustomEvent<any>;
|
|
13
|
+
} & {
|
|
15
14
|
[evt: string]: CustomEvent<any>;
|
|
16
15
|
};
|
|
17
16
|
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/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ import TableFilter from './components/Table/TableFilter.svelte';
|
|
|
20
20
|
import { columnFilter, searchFilter } from './components/Table/filter';
|
|
21
21
|
import type { TableConfig, Columns, Column } from './models/Models';
|
|
22
22
|
import Facets from './components/Facets/Facets.svelte';
|
|
23
|
+
import type { FacetGroup, FacetOption, SelectedFacetGroup } from './models/Models';
|
|
23
24
|
import CodeEditor from './components/CodeEditor/CodeEditor.svelte';
|
|
24
25
|
import Notification from './components/page/Notification.svelte';
|
|
25
26
|
import TablePlaceholder from './components/page/TablePlaceholder.svelte';
|
|
@@ -40,6 +41,7 @@ export { TablePlaceholder };
|
|
|
40
41
|
export { positionType, pageContentLayoutType, decimalCharacterType, orientationType, textMarkerType, textSeperatorType } from './models/Enums';
|
|
41
42
|
export { Table, TableFilter, columnFilter, searchFilter };
|
|
42
43
|
export { Facets };
|
|
44
|
+
export type { FacetGroup, FacetOption, SelectedFacetGroup };
|
|
43
45
|
export { CodeEditor };
|
|
44
46
|
export type { TableConfig, Columns, Column };
|
|
45
47
|
export { bexis2theme };
|
package/dist/models/Models.d.ts
CHANGED
|
@@ -151,13 +151,24 @@ 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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
selected?: boolean;
|
|
159
|
+
}
|
|
160
|
+
export interface FacetGroup {
|
|
161
|
+
name: string;
|
|
162
|
+
displayName: string;
|
|
163
|
+
selected?: boolean;
|
|
164
|
+
children: FacetOption[];
|
|
165
|
+
count?: number;
|
|
166
|
+
}
|
|
167
|
+
export interface SelectedFacetGroup extends Omit<FacetGroup, 'children'> {
|
|
168
|
+
children: {
|
|
169
|
+
[key: string]: FacetOption;
|
|
170
|
+
};
|
|
171
|
+
}
|
|
161
172
|
export declare class Send {
|
|
162
173
|
id: number;
|
|
163
174
|
limit: number;
|
package/dist/models/Models.js
CHANGED
package/package.json
CHANGED
|
@@ -1,36 +1,46 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { createEventDispatcher } from 'svelte';
|
|
2
3
|
import { getModalStore, Modal, TreeView, TreeViewItem } from '@skeletonlabs/skeleton';
|
|
4
|
+
import type { Writable } from 'svelte/store';
|
|
3
5
|
|
|
4
6
|
import ShowMore from './ShowMore.svelte';
|
|
5
|
-
import type {
|
|
7
|
+
import type { FacetGroup, SelectedFacetGroup } from '$models/Models';
|
|
6
8
|
|
|
7
9
|
export let groupSelection = false;
|
|
8
|
-
export let groups: FacetGroup
|
|
9
|
-
export let selected: FacetGroup;
|
|
10
|
-
export let selectedGroups: { [key: string]: boolean } = {};
|
|
10
|
+
export let groups: Writable<FacetGroup[]>;
|
|
11
11
|
export let showAll = false;
|
|
12
12
|
export let open = false;
|
|
13
13
|
|
|
14
|
+
let selected: { [key: string]: SelectedFacetGroup };
|
|
15
|
+
let selectedItems: {
|
|
16
|
+
[key: string]: {
|
|
17
|
+
[key: string]: boolean;
|
|
18
|
+
};
|
|
19
|
+
} = {};
|
|
20
|
+
let selectedGroups: { [key: string]: boolean } = {};
|
|
21
|
+
|
|
22
|
+
const dispatch = createEventDispatcher();
|
|
23
|
+
|
|
14
24
|
const modalStore = getModalStore();
|
|
15
|
-
const showMore = (group:
|
|
25
|
+
const showMore = (group: SelectedFacetGroup) => {
|
|
16
26
|
modalStore.trigger({
|
|
17
27
|
type: 'component',
|
|
18
|
-
title: `${group}`,
|
|
28
|
+
title: `${group.displayName}`,
|
|
19
29
|
component: {
|
|
20
30
|
ref: ShowMore,
|
|
21
31
|
props: {
|
|
22
32
|
group,
|
|
23
33
|
handleSave,
|
|
24
|
-
handleCancel
|
|
25
|
-
selected: selected[group],
|
|
26
|
-
items: groups[group].sort((a, b) => a.value.localeCompare(b.value))
|
|
34
|
+
handleCancel
|
|
27
35
|
}
|
|
28
36
|
}
|
|
29
37
|
});
|
|
30
38
|
};
|
|
31
39
|
|
|
32
|
-
const handleSave = (group:
|
|
33
|
-
|
|
40
|
+
const handleSave = (group: SelectedFacetGroup) => {
|
|
41
|
+
Object.keys(group.children).forEach((key) => {
|
|
42
|
+
selectedItems[group.name][key] = group.children[key].selected || false;
|
|
43
|
+
});
|
|
34
44
|
modalStore.close();
|
|
35
45
|
};
|
|
36
46
|
|
|
@@ -38,77 +48,152 @@
|
|
|
38
48
|
modalStore.close();
|
|
39
49
|
};
|
|
40
50
|
|
|
51
|
+
const mapSelected = (type: 'items' | 'groups') => {
|
|
52
|
+
const changed: any = [];
|
|
53
|
+
|
|
54
|
+
if (type === 'items') {
|
|
55
|
+
Object.keys(selectedItems).forEach((group) => {
|
|
56
|
+
Object.keys(selectedItems[group]).forEach((item) => {
|
|
57
|
+
if (selectedItems[group][item] !== selected[group].children[item].selected) {
|
|
58
|
+
changed.push({
|
|
59
|
+
parent: group,
|
|
60
|
+
selectedItem: item
|
|
61
|
+
});
|
|
62
|
+
selected[group].children[item].selected = selectedItems[group][item];
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
} else {
|
|
67
|
+
Object.keys(selectedGroups).forEach((group) => {
|
|
68
|
+
if (selectedGroups[group] !== selected[group].selected) {
|
|
69
|
+
changed.push({
|
|
70
|
+
parent: null,
|
|
71
|
+
selectedItem: group
|
|
72
|
+
});
|
|
73
|
+
selected[group].selected = selectedGroups[group];
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
changed.length && dispatch('change', changed);
|
|
79
|
+
};
|
|
80
|
+
|
|
41
81
|
const sortOptions = () => {
|
|
42
82
|
// Sort facets in a descending order if count exits, or sort alphabetically
|
|
43
|
-
Object.keys(
|
|
44
|
-
|
|
45
|
-
|
|
83
|
+
Object.keys(selected).forEach((group) => {
|
|
84
|
+
const checked = Object.keys(selected[group].children)
|
|
85
|
+
.filter((item) => selected[group].children[item].selected)
|
|
86
|
+
.map((item) => selected[group].children[item])
|
|
87
|
+
.sort((a, b) => {
|
|
46
88
|
if (a.count != undefined && b.count != undefined) {
|
|
47
89
|
return b.count - a.count;
|
|
48
90
|
}
|
|
49
|
-
return a.
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
91
|
+
return a.displayName.localeCompare(b.displayName);
|
|
92
|
+
})
|
|
93
|
+
.map((item) => item.name);
|
|
94
|
+
|
|
95
|
+
const unchecked = Object.keys(selected[group].children).filter(
|
|
96
|
+
(item) => !checked.includes(item)
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const groupIndex = displayedGroups.findIndex((g) => g.name === group);
|
|
100
|
+
|
|
101
|
+
displayedGroups[groupIndex].children = [
|
|
102
|
+
...checked.map(
|
|
103
|
+
(item) => displayedGroups[groupIndex].children.find((i) => i.name === item)!
|
|
104
|
+
),
|
|
105
|
+
...unchecked.map(
|
|
106
|
+
(item) => displayedGroups[groupIndex].children.find((i) => i.name === item)!
|
|
107
|
+
)
|
|
59
108
|
];
|
|
60
109
|
});
|
|
61
110
|
};
|
|
62
111
|
|
|
63
|
-
|
|
112
|
+
groups.subscribe((data) => {
|
|
113
|
+
selected = data.reduce((acc, g) => {
|
|
114
|
+
const children = g.children.reduce((acc, c) => {
|
|
115
|
+
acc[c.name] = {
|
|
116
|
+
...c,
|
|
117
|
+
selected: c.selected || false
|
|
118
|
+
};
|
|
119
|
+
return acc;
|
|
120
|
+
}, {});
|
|
121
|
+
|
|
122
|
+
acc[g.name] = {
|
|
123
|
+
...g,
|
|
124
|
+
children,
|
|
125
|
+
selected: g.selected || false
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
return acc;
|
|
129
|
+
}, {});
|
|
130
|
+
|
|
131
|
+
Object.keys(selected).forEach((groupName) => {
|
|
132
|
+
selectedItems[groupName] = {};
|
|
133
|
+
Object.keys(selected[groupName].children).forEach((itemName) => {
|
|
134
|
+
selectedItems[groupName][itemName] =
|
|
135
|
+
selected[groupName].children[itemName].selected || false;
|
|
136
|
+
});
|
|
137
|
+
selectedGroups[groupName] = selected[groupName].selected || false;
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
$: displayedGroups = structuredClone($groups);
|
|
142
|
+
$: selectedItems, mapSelected('items'), sortOptions();
|
|
143
|
+
$: selectedGroups, mapSelected('groups');
|
|
64
144
|
</script>
|
|
65
145
|
|
|
66
146
|
<TreeView selection={groupSelection} multiple={groupSelection} padding="p-1" hover="">
|
|
67
|
-
{#each
|
|
147
|
+
{#each displayedGroups as group}
|
|
68
148
|
<TreeViewItem
|
|
69
|
-
name=
|
|
70
|
-
value={group}
|
|
149
|
+
name={group.name}
|
|
150
|
+
value={group.name}
|
|
71
151
|
{open}
|
|
72
152
|
hyphenOpacity="opacity-0"
|
|
153
|
+
bind:checked={selectedGroups[group.name]}
|
|
73
154
|
bind:group={selectedGroups}
|
|
74
|
-
bind:checked={selectedGroups[group]}
|
|
75
155
|
>
|
|
76
|
-
<p class="font-semibold">
|
|
156
|
+
<p class="font-semibold">
|
|
157
|
+
{group.displayName}{group.count !== undefined ? ` (${group.count})` : ''}
|
|
158
|
+
</p>
|
|
77
159
|
|
|
78
160
|
<svelte:fragment slot="children">
|
|
79
161
|
<!-- If more than 5 choices, show the remaining in the Modal -->
|
|
80
162
|
{#if !showAll}
|
|
81
|
-
{#each
|
|
163
|
+
{#each group.children.slice(0, 5) as item}
|
|
82
164
|
<TreeViewItem
|
|
83
|
-
bind:group={
|
|
84
|
-
name={
|
|
85
|
-
value={item}
|
|
165
|
+
bind:group={selectedItems[group.name]}
|
|
166
|
+
name={item.name}
|
|
167
|
+
value={item.displayName}
|
|
86
168
|
hyphenOpacity="opacity-0"
|
|
169
|
+
bind:checked={selectedItems[group.name][item.name]}
|
|
87
170
|
spacing="space-x-3"
|
|
88
171
|
selection
|
|
89
172
|
multiple
|
|
90
173
|
>
|
|
91
|
-
<p>{item.
|
|
174
|
+
<p>{item.displayName} ({item.count})</p>
|
|
92
175
|
</TreeViewItem>
|
|
93
176
|
{/each}
|
|
94
177
|
<!-- Trigger for the Modal to view all options -->
|
|
95
|
-
{#if
|
|
178
|
+
{#if group.children.length > 5}
|
|
96
179
|
<TreeViewItem hyphenOpacity="opacity-0">
|
|
97
|
-
<button class="anchor" on:click={() => showMore(group)}>more</button
|
|
180
|
+
<button class="anchor" on:click={() => showMore(selected[group.name])}>more</button
|
|
181
|
+
></TreeViewItem
|
|
98
182
|
>
|
|
99
183
|
{/if}
|
|
100
184
|
{:else}
|
|
101
|
-
{#each
|
|
185
|
+
{#each group.children as item}
|
|
102
186
|
<TreeViewItem
|
|
103
|
-
bind:group={
|
|
104
|
-
|
|
105
|
-
|
|
187
|
+
bind:group={selectedItems[group.name]}
|
|
188
|
+
bind:checked={selectedItems[group.name][item.name]}
|
|
189
|
+
name={item.name}
|
|
190
|
+
value={item.displayName}
|
|
106
191
|
hyphenOpacity="opacity-0"
|
|
107
192
|
spacing="space-x-3"
|
|
108
193
|
selection
|
|
109
194
|
multiple
|
|
110
195
|
>
|
|
111
|
-
<p>{item.
|
|
196
|
+
<p>{item.displayName} ({item.count})</p>
|
|
112
197
|
</TreeViewItem>
|
|
113
198
|
{/each}
|
|
114
199
|
{/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/index.ts
CHANGED
|
@@ -32,6 +32,7 @@ import type { TableConfig, Columns, Column } from './models/Models';
|
|
|
32
32
|
|
|
33
33
|
//Facets
|
|
34
34
|
import Facets from './components/Facets/Facets.svelte';
|
|
35
|
+
import type { FacetGroup, FacetOption, SelectedFacetGroup } from './models/Models';
|
|
35
36
|
|
|
36
37
|
// CodeEditor
|
|
37
38
|
import CodeEditor from './components/CodeEditor/CodeEditor.svelte';
|
|
@@ -108,6 +109,7 @@ export { Table, TableFilter, columnFilter, searchFilter };
|
|
|
108
109
|
|
|
109
110
|
// Facets
|
|
110
111
|
export { Facets };
|
|
112
|
+
export type { FacetGroup, FacetOption, SelectedFacetGroup };
|
|
111
113
|
|
|
112
114
|
// CodeEditor
|
|
113
115
|
export { CodeEditor };
|
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,26 @@ 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
|
+
selected?: boolean;
|
|
199
|
+
}
|
|
198
200
|
|
|
199
|
-
export
|
|
200
|
-
|
|
201
|
-
|
|
201
|
+
export interface FacetGroup {
|
|
202
|
+
name: string;
|
|
203
|
+
displayName: string;
|
|
204
|
+
selected?: boolean;
|
|
205
|
+
children: FacetOption[];
|
|
206
|
+
count?: number;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface SelectedFacetGroup extends Omit<FacetGroup, 'children'> {
|
|
210
|
+
children: {
|
|
211
|
+
[key: string]: FacetOption;
|
|
212
|
+
};
|
|
213
|
+
}
|
|
202
214
|
|
|
203
215
|
export class Send {
|
|
204
216
|
id: number;
|
|
@@ -237,14 +249,13 @@ export class Receive {
|
|
|
237
249
|
export class errorType {
|
|
238
250
|
statusText: string;
|
|
239
251
|
status: number;
|
|
240
|
-
error:string;
|
|
241
|
-
stackTrace:string
|
|
252
|
+
error: string;
|
|
253
|
+
stackTrace: string;
|
|
242
254
|
|
|
243
255
|
constructor() {
|
|
244
|
-
this.statusText =
|
|
256
|
+
this.statusText = '';
|
|
245
257
|
this.status = 0;
|
|
246
|
-
this.error =
|
|
247
|
-
this.stackTrace =
|
|
258
|
+
this.error = '';
|
|
259
|
+
this.stackTrace = '';
|
|
248
260
|
}
|
|
249
|
-
|
|
250
|
-
};
|
|
261
|
+
}
|