@bexis2/bexis2-core-ui 0.4.13 → 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 +12 -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/components/Table/TableContent.svelte +6 -2
- package/dist/components/Table/TableFilter.svelte +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/models/Models.d.ts +20 -7
- 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/components/Table/TableContent.svelte +6 -2
- package/src/lib/components/Table/TableFilter.svelte +1 -1
- package/src/lib/index.ts +6 -0
- package/src/lib/models/Models.ts +30 -16
package/README.md
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
# bexis-core-ui
|
|
2
|
+
## 0.4.15
|
|
3
|
+
- Update Facets with new params and add onChange action
|
|
4
|
+
- Changes structure of Facets data
|
|
5
|
+
- Adds on:change action
|
|
6
|
+
|
|
7
|
+
## 0.4.14
|
|
8
|
+
- Table
|
|
9
|
+
- fixes rendering issues with Table filters and different components
|
|
10
|
+
|
|
11
|
+
- Facets
|
|
12
|
+
- Exports Facets component
|
|
13
|
+
|
|
2
14
|
## 0.4.13
|
|
3
15
|
- menu
|
|
4
16
|
- fix code isses
|
|
@@ -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: {
|
|
@@ -64,7 +64,7 @@ let {
|
|
|
64
64
|
let searchValue = "";
|
|
65
65
|
let isFetching = false;
|
|
66
66
|
const serverSide = server !== void 0;
|
|
67
|
-
const { baseUrl,
|
|
67
|
+
const { baseUrl, entityId, versionId, sendModel = new Send() } = server ?? {};
|
|
68
68
|
const filters = writable({});
|
|
69
69
|
const dispatch = createEventDispatcher();
|
|
70
70
|
const actionDispatcher = (obj) => dispatch("action", obj);
|
|
@@ -361,7 +361,11 @@ $: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => co
|
|
|
361
361
|
</form>
|
|
362
362
|
{/if}
|
|
363
363
|
|
|
364
|
-
<div
|
|
364
|
+
<div
|
|
365
|
+
class="flex justify-between items-center w-full {search && 'py-2'} {!search &&
|
|
366
|
+
(shownColumns.length > 0 || toggle || resizable !== 'none' || exportable) &&
|
|
367
|
+
'pb-2'}"
|
|
368
|
+
>
|
|
365
369
|
<div>
|
|
366
370
|
<!-- Enable the fitToScreen toggle if toggle === true -->
|
|
367
371
|
{#if toggle}
|
|
@@ -205,7 +205,7 @@ onMount(() => {
|
|
|
205
205
|
<Fa icon={faFilter} size="12" />
|
|
206
206
|
</button>
|
|
207
207
|
|
|
208
|
-
<div data-popup={popupId} id={popupId} class="">
|
|
208
|
+
<div data-popup={popupId} id={popupId} class="z-50">
|
|
209
209
|
<div class="card p-3 grid gap-2 shadow-lg w-max bg-base-100">
|
|
210
210
|
<button
|
|
211
211
|
class="btn variant-filled-primary btn-sm"
|
package/dist/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ import Table from './components/Table/Table.svelte';
|
|
|
19
19
|
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
|
+
import Facets from './components/Facets/Facets.svelte';
|
|
22
23
|
import CodeEditor from './components/CodeEditor/CodeEditor.svelte';
|
|
23
24
|
import Notification from './components/page/Notification.svelte';
|
|
24
25
|
import TablePlaceholder from './components/page/TablePlaceholder.svelte';
|
|
@@ -38,6 +39,7 @@ export { Notification };
|
|
|
38
39
|
export { TablePlaceholder };
|
|
39
40
|
export { positionType, pageContentLayoutType, decimalCharacterType, orientationType, textMarkerType, textSeperatorType } from './models/Enums';
|
|
40
41
|
export { Table, TableFilter, columnFilter, searchFilter };
|
|
42
|
+
export { Facets };
|
|
41
43
|
export { CodeEditor };
|
|
42
44
|
export type { TableConfig, Columns, Column };
|
|
43
45
|
export { bexis2theme };
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,8 @@ import TextArea from './components/form/TextArea.svelte';
|
|
|
24
24
|
import Table from './components/Table/Table.svelte';
|
|
25
25
|
import TableFilter from './components/Table/TableFilter.svelte';
|
|
26
26
|
import { columnFilter, searchFilter } from './components/Table/filter';
|
|
27
|
+
//Facets
|
|
28
|
+
import Facets from './components/Facets/Facets.svelte';
|
|
27
29
|
// CodeEditor
|
|
28
30
|
import CodeEditor from './components/CodeEditor/CodeEditor.svelte';
|
|
29
31
|
//notification
|
|
@@ -53,6 +55,8 @@ export { TablePlaceholder };
|
|
|
53
55
|
export { positionType, pageContentLayoutType, decimalCharacterType, orientationType, textMarkerType, textSeperatorType } from './models/Enums';
|
|
54
56
|
// Table
|
|
55
57
|
export { Table, TableFilter, columnFilter, searchFilter };
|
|
58
|
+
// Facets
|
|
59
|
+
export { Facets };
|
|
56
60
|
// CodeEditor
|
|
57
61
|
export { CodeEditor };
|
|
58
62
|
// theme
|
package/dist/models/Models.d.ts
CHANGED
|
@@ -82,7 +82,7 @@ export interface Columns {
|
|
|
82
82
|
}
|
|
83
83
|
export type ServerConfig = {
|
|
84
84
|
baseUrl?: string;
|
|
85
|
-
sendModel
|
|
85
|
+
sendModel?: Send;
|
|
86
86
|
entityId?: number;
|
|
87
87
|
versionId?: number;
|
|
88
88
|
};
|
|
@@ -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>
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
let searchValue = '';
|
|
63
63
|
let isFetching = false;
|
|
64
64
|
const serverSide = server !== undefined;
|
|
65
|
-
const { baseUrl,
|
|
65
|
+
const { baseUrl, entityId, versionId, sendModel = new Send() } = server ?? {};
|
|
66
66
|
|
|
67
67
|
const filters = writable<{
|
|
68
68
|
[key: string]: { [key in FilterOptionsEnum]?: number | string | Date };
|
|
@@ -429,7 +429,11 @@
|
|
|
429
429
|
</form>
|
|
430
430
|
{/if}
|
|
431
431
|
|
|
432
|
-
<div
|
|
432
|
+
<div
|
|
433
|
+
class="flex justify-between items-center w-full {search && 'py-2'} {!search &&
|
|
434
|
+
(shownColumns.length > 0 || toggle || resizable !== 'none' || exportable) &&
|
|
435
|
+
'pb-2'}"
|
|
436
|
+
>
|
|
433
437
|
<div>
|
|
434
438
|
<!-- Enable the fitToScreen toggle if toggle === true -->
|
|
435
439
|
{#if toggle}
|
|
@@ -244,7 +244,7 @@
|
|
|
244
244
|
<Fa icon={faFilter} size="12" />
|
|
245
245
|
</button>
|
|
246
246
|
|
|
247
|
-
<div data-popup={popupId} id={popupId} class="">
|
|
247
|
+
<div data-popup={popupId} id={popupId} class="z-50">
|
|
248
248
|
<div class="card p-3 grid gap-2 shadow-lg w-max bg-base-100">
|
|
249
249
|
<button
|
|
250
250
|
class="btn variant-filled-primary btn-sm"
|
package/src/lib/index.ts
CHANGED
|
@@ -30,6 +30,9 @@ import TableFilter from './components/Table/TableFilter.svelte';
|
|
|
30
30
|
import { columnFilter, searchFilter } from './components/Table/filter';
|
|
31
31
|
import type { TableConfig, Columns, Column } from './models/Models';
|
|
32
32
|
|
|
33
|
+
//Facets
|
|
34
|
+
import Facets from './components/Facets/Facets.svelte';
|
|
35
|
+
|
|
33
36
|
// CodeEditor
|
|
34
37
|
import CodeEditor from './components/CodeEditor/CodeEditor.svelte';
|
|
35
38
|
|
|
@@ -103,6 +106,9 @@ export {
|
|
|
103
106
|
// Table
|
|
104
107
|
export { Table, TableFilter, columnFilter, searchFilter };
|
|
105
108
|
|
|
109
|
+
// Facets
|
|
110
|
+
export { Facets };
|
|
111
|
+
|
|
106
112
|
// CodeEditor
|
|
107
113
|
export { CodeEditor };
|
|
108
114
|
|
package/src/lib/models/Models.ts
CHANGED
|
@@ -104,10 +104,10 @@ 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
|
-
sendModel
|
|
110
|
+
sendModel?: Send; // Send model for server-side table
|
|
111
111
|
entityId?: number; // Entity ID for server-side table
|
|
112
112
|
versionId?: number; // Version ID for server-side table
|
|
113
113
|
};
|
|
@@ -124,7 +124,7 @@ export interface TableConfig<T> {
|
|
|
124
124
|
rowHeight?: number; // auto by default
|
|
125
125
|
columns?: Columns;
|
|
126
126
|
exportable?: boolean; // false by default
|
|
127
|
-
pageSizes?: number[]; // [5, 10,
|
|
127
|
+
pageSizes?: number[]; // [5, 10, 20, 50, 100] by default
|
|
128
128
|
defaultPageSize?: number; // 10 by default
|
|
129
129
|
optionsComponent?: typeof SvelteComponent;
|
|
130
130
|
|
|
@@ -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
|
+
}
|