@bexis2/bexis2-core-ui 0.4.8 → 0.4.10
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/CodeEditor/CodeEditor.svelte +1 -2
- package/dist/components/CodeEditor/CodeEditor.svelte.d.ts +8 -8
- package/dist/components/Facets/Facets.svelte +108 -0
- package/dist/components/Facets/Facets.svelte.d.ts +24 -0
- package/dist/components/Facets/ShowMore.svelte +75 -0
- package/dist/components/Facets/ShowMore.svelte.d.ts +21 -0
- package/dist/components/File/FileUploader.svelte +3 -6
- package/dist/components/File/FileUploader.svelte.d.ts +5 -5
- package/dist/components/Table/ColumnsMenu.svelte +33 -0
- package/dist/components/Table/ColumnsMenu.svelte.d.ts +21 -0
- package/dist/components/Table/Table.svelte +1 -3
- package/dist/components/Table/Table.svelte.d.ts +12 -1
- package/dist/components/Table/TableContent.svelte +49 -36
- package/dist/components/Table/TableFilter.svelte +20 -15
- package/dist/components/Table/TableFilterServer.svelte +10 -12
- package/dist/components/Table/TablePagination.svelte +35 -13
- package/dist/components/Table/TablePaginationServer.svelte +7 -13
- package/dist/components/Table/shared.d.ts +2 -19
- package/dist/components/form/Checkbox.svelte.d.ts +3 -3
- package/dist/components/form/CheckboxKvPList.svelte.d.ts +2 -2
- package/dist/components/form/CheckboxList.svelte.d.ts +1 -1
- package/dist/components/form/DateInput.svelte.d.ts +9 -9
- package/dist/components/form/InputContainer.svelte.d.ts +3 -3
- package/dist/components/form/NumberInput.svelte.d.ts +10 -10
- package/dist/components/form/TextArea.svelte.d.ts +10 -10
- package/dist/components/form/TextInput.svelte.d.ts +10 -10
- package/dist/components/page/Alert.svelte +1 -2
- package/dist/components/page/Alert.svelte.d.ts +4 -4
- package/dist/components/page/Docs.svelte.d.ts +1 -1
- package/dist/components/page/Footer.svelte +1 -2
- package/dist/components/page/Header.svelte +1 -2
- package/dist/components/page/HelpPopUp.svelte +4 -6
- package/dist/components/page/HelpPopUp.svelte.d.ts +1 -1
- package/dist/components/page/Notification.svelte +2 -4
- package/dist/components/page/Page.svelte.d.ts +8 -8
- package/dist/components/page/Spinner.svelte.d.ts +3 -3
- package/dist/components/page/TablePlaceholder.svelte.d.ts +2 -2
- package/dist/components/page/breadcrumb/Breadcrumb.svelte +5 -8
- package/dist/components/toggle/Toggle.svelte +7 -14
- package/dist/components/toggle/Toggle.svelte.d.ts +9 -8
- package/dist/models/Models.d.ts +14 -6
- package/dist/stores/apiStores.d.ts +0 -1
- package/dist/stores/pageStores.d.ts +0 -1
- package/package.json +114 -114
- package/src/lib/components/Facets/Facets.svelte +120 -0
- package/src/lib/components/Facets/ShowMore.svelte +87 -0
- package/src/lib/components/Table/ColumnsMenu.svelte +37 -0
- package/src/lib/components/Table/TableContent.svelte +167 -141
- package/src/lib/components/Table/TableFilter.svelte +17 -7
- package/src/lib/components/Table/TableFilterServer.svelte +6 -3
- package/src/lib/components/Table/TablePagination.svelte +33 -5
- package/src/lib/components/Table/TablePaginationServer.svelte +1 -1
- package/src/lib/models/Models.ts +18 -7
- /package/src/lib/components/{file → File}/FileIcon.svelte +0 -0
- /package/src/lib/components/{file → File}/FileInfo.svelte +0 -0
- /package/src/lib/components/{file → File}/FileUploader.svelte +0 -0
package/README.md
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
# bexis-core-ui
|
|
2
|
+
## 0.4.10
|
|
3
|
+
- Table:
|
|
4
|
+
- Fixes issue with sticky Tables not rendering the filters correctly.
|
|
5
|
+
- Fixes issues related to date picker in Tables with date filters.
|
|
6
|
+
- Updates default Table page sizes to [5, 10, 20, 50, 100].
|
|
7
|
+
- Updates the structure of server-side configuration for Tables.
|
|
8
|
+
- Adds new page size dropdown in Table for to fix contrast issues in the component.
|
|
9
|
+
- Adds showing/hiding Table columns.
|
|
10
|
+
|
|
11
|
+
- Facets:
|
|
12
|
+
- Adds Facets component.
|
|
13
|
+
|
|
2
14
|
## 0.4.8
|
|
3
15
|
- page
|
|
4
16
|
- add notification if api call to backend faild
|
|
@@ -53,8 +53,7 @@ const isValidJS = (str) => {
|
|
|
53
53
|
}
|
|
54
54
|
return true;
|
|
55
55
|
};
|
|
56
|
-
$:
|
|
57
|
-
isValid = language === "json" ? isValidJSON(value) : language === "js" ? isValidJS(value) : true;
|
|
56
|
+
$: isValid = language === "json" ? isValidJSON(value) : language === "js" ? isValidJS(value) : true;
|
|
58
57
|
</script>
|
|
59
58
|
|
|
60
59
|
<div class="grid items-stretch justify-stretch gap-1">
|
|
@@ -2,14 +2,14 @@ import { SvelteComponent } from "svelte";
|
|
|
2
2
|
declare const __propDef: {
|
|
3
3
|
props: {
|
|
4
4
|
id: string;
|
|
5
|
-
title?: string
|
|
6
|
-
initialValue?: string
|
|
7
|
-
value?: string
|
|
8
|
-
language?: string
|
|
9
|
-
dark?: boolean
|
|
10
|
-
toggle?: boolean
|
|
11
|
-
actions?: boolean
|
|
12
|
-
isValid?: boolean
|
|
5
|
+
title?: string;
|
|
6
|
+
initialValue?: string;
|
|
7
|
+
value?: string;
|
|
8
|
+
language?: string;
|
|
9
|
+
dark?: boolean;
|
|
10
|
+
toggle?: boolean;
|
|
11
|
+
actions?: boolean;
|
|
12
|
+
isValid?: boolean;
|
|
13
13
|
styles?: any;
|
|
14
14
|
};
|
|
15
15
|
events: {
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<script>import { getModalStore, Modal, TreeView, TreeViewItem } from "@skeletonlabs/skeleton";
|
|
2
|
+
import ShowMore from "./ShowMore.svelte";
|
|
3
|
+
export let groupSelection = false;
|
|
4
|
+
export let groups;
|
|
5
|
+
export let selected;
|
|
6
|
+
export let selectedGroups = {};
|
|
7
|
+
export let showAll = false;
|
|
8
|
+
export let open = false;
|
|
9
|
+
const modalStore = getModalStore();
|
|
10
|
+
const showMore = (group) => {
|
|
11
|
+
modalStore.trigger({
|
|
12
|
+
type: "component",
|
|
13
|
+
title: `${group}`,
|
|
14
|
+
component: {
|
|
15
|
+
ref: ShowMore,
|
|
16
|
+
props: {
|
|
17
|
+
group,
|
|
18
|
+
handleSave,
|
|
19
|
+
handleCancel,
|
|
20
|
+
selected: selected[group],
|
|
21
|
+
items: groups[group].sort((a, b) => a.value.localeCompare(b.value))
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
const handleSave = (group, selectedItems) => {
|
|
27
|
+
selected[group] = selectedItems;
|
|
28
|
+
modalStore.close();
|
|
29
|
+
};
|
|
30
|
+
const handleCancel = () => {
|
|
31
|
+
modalStore.close();
|
|
32
|
+
};
|
|
33
|
+
const sortOptions = () => {
|
|
34
|
+
Object.keys(groups).forEach((group) => {
|
|
35
|
+
groups[group] = [
|
|
36
|
+
...selected[group].sort((a, b) => {
|
|
37
|
+
if (a.count != void 0 && b.count != void 0) {
|
|
38
|
+
return b.count - a.count;
|
|
39
|
+
}
|
|
40
|
+
return a.value.localeCompare(b.value);
|
|
41
|
+
}),
|
|
42
|
+
...groups[group].filter((item) => !selected[group].includes(item)).sort((a, b) => {
|
|
43
|
+
if (a.count != void 0 && b.count != void 0) {
|
|
44
|
+
return b.count - a.count;
|
|
45
|
+
}
|
|
46
|
+
return a.value.localeCompare(b.value);
|
|
47
|
+
})
|
|
48
|
+
];
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
$: selected, sortOptions();
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<TreeView selection={groupSelection} multiple={groupSelection} padding="p-1" hover="">
|
|
55
|
+
{#each Object.keys(groups) as group}
|
|
56
|
+
<TreeViewItem
|
|
57
|
+
name="groups"
|
|
58
|
+
value={group}
|
|
59
|
+
{open}
|
|
60
|
+
hyphenOpacity="opacity-0"
|
|
61
|
+
bind:group={selectedGroups}
|
|
62
|
+
bind:checked={selectedGroups[group]}
|
|
63
|
+
>
|
|
64
|
+
<p class="font-semibold">{group}</p>
|
|
65
|
+
|
|
66
|
+
<svelte:fragment slot="children">
|
|
67
|
+
<!-- If more than 5 choices, show the remaining in the Modal -->
|
|
68
|
+
{#if !showAll}
|
|
69
|
+
{#each groups[group].slice(0, 5) as item}
|
|
70
|
+
<TreeViewItem
|
|
71
|
+
bind:group={selected[group]}
|
|
72
|
+
name={group}
|
|
73
|
+
value={item}
|
|
74
|
+
hyphenOpacity="opacity-0"
|
|
75
|
+
spacing="space-x-3"
|
|
76
|
+
selection
|
|
77
|
+
multiple
|
|
78
|
+
>
|
|
79
|
+
<p>{item.value} ({item.count})</p>
|
|
80
|
+
</TreeViewItem>
|
|
81
|
+
{/each}
|
|
82
|
+
<!-- Trigger for the Modal to view all options -->
|
|
83
|
+
{#if groups[group].length > 5}
|
|
84
|
+
<TreeViewItem hyphenOpacity="opacity-0">
|
|
85
|
+
<button class="anchor" on:click={() => showMore(group)}>more</button></TreeViewItem
|
|
86
|
+
>
|
|
87
|
+
{/if}
|
|
88
|
+
{:else}
|
|
89
|
+
{#each groups[group] as item}
|
|
90
|
+
<TreeViewItem
|
|
91
|
+
bind:group={selected[group]}
|
|
92
|
+
name={group}
|
|
93
|
+
value={item}
|
|
94
|
+
hyphenOpacity="opacity-0"
|
|
95
|
+
spacing="space-x-3"
|
|
96
|
+
selection
|
|
97
|
+
multiple
|
|
98
|
+
>
|
|
99
|
+
<p>{item.value} ({item.count})</p>
|
|
100
|
+
</TreeViewItem>
|
|
101
|
+
{/each}
|
|
102
|
+
{/if}
|
|
103
|
+
</svelte:fragment>
|
|
104
|
+
</TreeViewItem>
|
|
105
|
+
{/each}
|
|
106
|
+
</TreeView>
|
|
107
|
+
|
|
108
|
+
<Modal />
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { FacetGroup } from '../../models/Models';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
groupSelection?: boolean;
|
|
6
|
+
groups: FacetGroup;
|
|
7
|
+
selected: FacetGroup;
|
|
8
|
+
selectedGroups?: {
|
|
9
|
+
[key: string]: boolean;
|
|
10
|
+
};
|
|
11
|
+
showAll?: boolean;
|
|
12
|
+
open?: boolean;
|
|
13
|
+
};
|
|
14
|
+
events: {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
};
|
|
17
|
+
slots: {};
|
|
18
|
+
};
|
|
19
|
+
export type FacetsProps = typeof __propDef.props;
|
|
20
|
+
export type FacetsEvents = typeof __propDef.events;
|
|
21
|
+
export type FacetsSlots = typeof __propDef.slots;
|
|
22
|
+
export default class Facets extends SvelteComponent<FacetsProps, FacetsEvents, FacetsSlots> {
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<script>export let group;
|
|
2
|
+
export let items;
|
|
3
|
+
export let selected;
|
|
4
|
+
export let handleSave;
|
|
5
|
+
export let handleCancel;
|
|
6
|
+
let selectedItems = selected;
|
|
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
|
+
};
|
|
15
|
+
const selectAll = () => {
|
|
16
|
+
selectedItems = items;
|
|
17
|
+
};
|
|
18
|
+
const selectNone = () => {
|
|
19
|
+
selectedItems = [];
|
|
20
|
+
};
|
|
21
|
+
const onSave = () => {
|
|
22
|
+
handleSave(group, selectedItems);
|
|
23
|
+
};
|
|
24
|
+
const onCancel = () => {
|
|
25
|
+
selectedItems = selected;
|
|
26
|
+
handleCancel();
|
|
27
|
+
};
|
|
28
|
+
const gridClass = (items2) => {
|
|
29
|
+
if (items2.length >= 50) {
|
|
30
|
+
return "grid-cols-5";
|
|
31
|
+
} else if (items2.length >= 30) {
|
|
32
|
+
return "grid-cols-4";
|
|
33
|
+
} else if (items2.length >= 20) {
|
|
34
|
+
return "grid-cols-3";
|
|
35
|
+
}
|
|
36
|
+
return "grid-cols-2";
|
|
37
|
+
};
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<div class="p-5 rounded-md bg-surface-50 dark:bg-surface-800 border-primary-500 border-2">
|
|
41
|
+
<!-- Header -->
|
|
42
|
+
<h2 class="text-xl font-semibold">{group}</h2>
|
|
43
|
+
|
|
44
|
+
<!-- Items -->
|
|
45
|
+
<div
|
|
46
|
+
class="grid {gridClass(
|
|
47
|
+
items
|
|
48
|
+
)} !gap-x-20 gap-y-2 py-10 px-2 max-h-[1000px] overflow-x-auto max-w-6xl"
|
|
49
|
+
>
|
|
50
|
+
{#each items as item, index}
|
|
51
|
+
<label class="flex gap-3 items-center">
|
|
52
|
+
<input
|
|
53
|
+
type="checkbox"
|
|
54
|
+
class="checkbox"
|
|
55
|
+
value={item.value}
|
|
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>
|
|
60
|
+
</label>
|
|
61
|
+
{/each}
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<!-- Footer -->
|
|
65
|
+
<div class="flex w-full justify-between gap-5">
|
|
66
|
+
<div class="flex gap-3">
|
|
67
|
+
<button class="btn btn-sm variant-filled-tertiary" on:click={selectNone}>None</button>
|
|
68
|
+
<button class="btn btn-sm variant-filled-tertiary" on:click={selectAll}>All</button>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="flex gap-3">
|
|
71
|
+
<button class="btn btn-sm variant-filled-primary" on:click={onSave}>Save</button>
|
|
72
|
+
<button class="btn btn-sm variant-filled-secondary" on:click={onCancel}>Cancel</button>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { FacetOption } from '../../models/Models';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
group: string;
|
|
6
|
+
items: FacetOption[];
|
|
7
|
+
selected: FacetOption[];
|
|
8
|
+
handleSave: (group: string, selectedItems: FacetOption[]) => {};
|
|
9
|
+
handleCancel: () => {};
|
|
10
|
+
};
|
|
11
|
+
events: {
|
|
12
|
+
[evt: string]: CustomEvent<any>;
|
|
13
|
+
};
|
|
14
|
+
slots: {};
|
|
15
|
+
};
|
|
16
|
+
export type ShowMoreProps = typeof __propDef.props;
|
|
17
|
+
export type ShowMoreEvents = typeof __propDef.events;
|
|
18
|
+
export type ShowMoreSlots = typeof __propDef.slots;
|
|
19
|
+
export default class ShowMore extends SvelteComponent<ShowMoreProps, ShowMoreEvents, ShowMoreSlots> {
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
@@ -15,16 +15,13 @@ export let submit = "";
|
|
|
15
15
|
export let context = "";
|
|
16
16
|
export let data;
|
|
17
17
|
let isUploading = false;
|
|
18
|
-
$:
|
|
19
|
-
|
|
20
|
-
$:
|
|
21
|
-
submitBt = "submit";
|
|
18
|
+
$: model = data;
|
|
19
|
+
$: submitBt = "submit";
|
|
22
20
|
let maxSize = 0;
|
|
23
21
|
const dispatch = createEventDispatcher();
|
|
24
22
|
let fx;
|
|
25
23
|
let files = { accepted: [], rejected: [] };
|
|
26
|
-
$:
|
|
27
|
-
files;
|
|
24
|
+
$: files;
|
|
28
25
|
onMount(async () => {
|
|
29
26
|
if (!data) {
|
|
30
27
|
load();
|
|
@@ -2,11 +2,11 @@ import { SvelteComponent } from "svelte";
|
|
|
2
2
|
import type { fileUploaderType } from '../../models/Models.js';
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: {
|
|
5
|
-
id?: number
|
|
6
|
-
version?: number
|
|
7
|
-
start?: string
|
|
8
|
-
submit?: string
|
|
9
|
-
context?: string
|
|
5
|
+
id?: number;
|
|
6
|
+
version?: number;
|
|
7
|
+
start?: string;
|
|
8
|
+
submit?: string;
|
|
9
|
+
context?: string;
|
|
10
10
|
data: fileUploaderType | undefined;
|
|
11
11
|
};
|
|
12
12
|
events: {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script>import { popup } from "@skeletonlabs/skeleton";
|
|
2
|
+
export let columns = [];
|
|
3
|
+
export let tableId;
|
|
4
|
+
const popupCombobox = {
|
|
5
|
+
event: "click",
|
|
6
|
+
target: `${tableId}-columns-menu`,
|
|
7
|
+
placement: "bottom"
|
|
8
|
+
};
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<button
|
|
12
|
+
type="button"
|
|
13
|
+
class="btn btn-sm variant-filled-primary rounded-full order-last"
|
|
14
|
+
use:popup={popupCombobox}>Columns</button
|
|
15
|
+
>
|
|
16
|
+
|
|
17
|
+
<div
|
|
18
|
+
class="bg-white dark:bg-surface-500 p-4 rounded-md shadow-md z-10"
|
|
19
|
+
data-popup="{tableId}-columns-menu"
|
|
20
|
+
>
|
|
21
|
+
{#each columns as column}
|
|
22
|
+
<div class="flex gap-3 items-center">
|
|
23
|
+
<input
|
|
24
|
+
type="checkbox"
|
|
25
|
+
bind:checked={column.visible}
|
|
26
|
+
disabled={columns.filter((c) => c.visible).length === 1 && column.visible}
|
|
27
|
+
/>
|
|
28
|
+
<span>{column.label}</span>
|
|
29
|
+
</div>
|
|
30
|
+
{/each}
|
|
31
|
+
|
|
32
|
+
<div class="arrow bg-white dark:bg-surface-500" />
|
|
33
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
columns?: {
|
|
5
|
+
id: string;
|
|
6
|
+
label: string;
|
|
7
|
+
visible: boolean;
|
|
8
|
+
}[];
|
|
9
|
+
tableId: string;
|
|
10
|
+
};
|
|
11
|
+
events: {
|
|
12
|
+
[evt: string]: CustomEvent<any>;
|
|
13
|
+
};
|
|
14
|
+
slots: {};
|
|
15
|
+
};
|
|
16
|
+
export type ColumnsMenuProps = typeof __propDef.props;
|
|
17
|
+
export type ColumnsMenuEvents = typeof __propDef.events;
|
|
18
|
+
export type ColumnsMenuSlots = typeof __propDef.slots;
|
|
19
|
+
export default class ColumnsMenu extends SvelteComponent<ColumnsMenuProps, ColumnsMenuEvents, ColumnsMenuSlots> {
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
-
|
|
2
|
+
import type { TableConfig } from '../../models/Models';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
config: TableConfig<any>;
|
|
6
|
+
};
|
|
7
|
+
events: {
|
|
8
|
+
action: any;
|
|
9
|
+
} & {
|
|
10
|
+
[evt: string]: CustomEvent<any>;
|
|
11
|
+
};
|
|
12
|
+
slots: {};
|
|
13
|
+
};
|
|
3
14
|
export type TableProps = typeof __propDef.props;
|
|
4
15
|
export type TableEvents = typeof __propDef.events;
|
|
5
16
|
export type TableSlots = typeof __propDef.slots;
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
addExpandedRows,
|
|
10
10
|
addColumnFilters,
|
|
11
11
|
addTableFilter,
|
|
12
|
-
addDataExport
|
|
12
|
+
addDataExport,
|
|
13
|
+
addHiddenColumns
|
|
13
14
|
} from "svelte-headless-table/plugins";
|
|
14
15
|
import { computePosition, autoUpdate, offset, shift, flip, arrow } from "@floating-ui/dom";
|
|
15
16
|
import { SlideToggle, storePopup } from "@skeletonlabs/skeleton";
|
|
@@ -19,6 +20,7 @@ import TableFilter from "./TableFilter.svelte";
|
|
|
19
20
|
import TableFilterServer from "./TableFilterServer.svelte";
|
|
20
21
|
import TablePagination from "./TablePagination.svelte";
|
|
21
22
|
import TablePaginationServer from "./TablePaginationServer.svelte";
|
|
23
|
+
import ColumnsMenu from "./ColumnsMenu.svelte";
|
|
22
24
|
import { columnFilter, searchFilter } from "./filter";
|
|
23
25
|
import {
|
|
24
26
|
cellStyle,
|
|
@@ -51,27 +53,18 @@ let {
|
|
|
51
53
|
// Whether to display the fitToScreen toggle
|
|
52
54
|
search = true,
|
|
53
55
|
// Whether to display the search input
|
|
54
|
-
pageSizes = [5, 10,
|
|
56
|
+
pageSizes = [5, 10, 20, 50, 100],
|
|
55
57
|
// Page sizes to display in the pagination component
|
|
56
58
|
fitToScreen = true,
|
|
57
59
|
// Whether to fit the table to the screen,
|
|
58
60
|
exportable = false,
|
|
59
61
|
// Whether to display the export button and enable export functionality
|
|
60
|
-
|
|
61
|
-
// Whether the table is client or server-side
|
|
62
|
-
URL = "",
|
|
63
|
-
// URL to fetch data from
|
|
64
|
-
token = "",
|
|
65
|
-
// Bearer token to authenticate the request
|
|
66
|
-
sendModel = new Send(),
|
|
67
|
-
// Model to send requests
|
|
68
|
-
entityId = 0,
|
|
69
|
-
// Entity ID to send with the request
|
|
70
|
-
versionId = 0
|
|
71
|
-
// Version ID to send with the request,
|
|
62
|
+
server
|
|
72
63
|
} = config;
|
|
73
64
|
let searchValue = "";
|
|
74
65
|
let isFetching = false;
|
|
66
|
+
const serverSide = server !== void 0;
|
|
67
|
+
const { baseUrl, sendModel, entityId, versionId } = server ?? {};
|
|
75
68
|
const filters = writable({});
|
|
76
69
|
const dispatch = createEventDispatcher();
|
|
77
70
|
const actionDispatcher = (obj) => dispatch("action", obj);
|
|
@@ -85,6 +78,7 @@ const table = createTable(data, {
|
|
|
85
78
|
fn: searchFilter,
|
|
86
79
|
serverSide
|
|
87
80
|
}),
|
|
81
|
+
hideColumns: addHiddenColumns(),
|
|
88
82
|
sort: addSortBy({
|
|
89
83
|
disableMultiSort: true,
|
|
90
84
|
serverSide
|
|
@@ -109,14 +103,24 @@ Object.keys(allCols).forEach((key) => {
|
|
|
109
103
|
$filters = { ...$filters, [key]: {} };
|
|
110
104
|
});
|
|
111
105
|
const accessors = Object.keys(allCols);
|
|
106
|
+
const unexcludedColumns = accessors.filter((accessor) => {
|
|
107
|
+
const key = accessor;
|
|
108
|
+
if (columns !== void 0 && key in columns && columns[key].exclude === true) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
});
|
|
113
|
+
let shownColumns = unexcludedColumns.map((c) => {
|
|
114
|
+
const key = c;
|
|
115
|
+
const label = key.charAt(0).toUpperCase() + key.slice(1);
|
|
116
|
+
return {
|
|
117
|
+
id: c,
|
|
118
|
+
label: columns && columns[key] && columns[key].header ? columns[key].header : label,
|
|
119
|
+
visible: true
|
|
120
|
+
};
|
|
121
|
+
});
|
|
112
122
|
const tableColumns = [
|
|
113
|
-
...
|
|
114
|
-
const key = accessor;
|
|
115
|
-
if (columns !== void 0 && key in columns && columns[key].exclude === true) {
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
return true;
|
|
119
|
-
}).map((accessor) => {
|
|
123
|
+
...unexcludedColumns.map((accessor) => {
|
|
120
124
|
const key = accessor;
|
|
121
125
|
if (columns !== void 0 && key in columns) {
|
|
122
126
|
const {
|
|
@@ -246,19 +250,20 @@ const { headerRows, pageRows, tableAttrs, tableBodyAttrs, pluginStates } = table
|
|
|
246
250
|
const { filterValue } = pluginStates.tableFilter;
|
|
247
251
|
const { exportedData } = pluginStates.export;
|
|
248
252
|
const { pageIndex, pageSize } = pluginStates.page;
|
|
253
|
+
const { hiddenColumnIds } = pluginStates.hideColumns;
|
|
249
254
|
const updateTable = async () => {
|
|
255
|
+
if (!sendModel) throw new Error("Server-side configuration is missing");
|
|
250
256
|
sendModel.limit = $pageSize;
|
|
251
257
|
sendModel.offset = $pageSize * $pageIndex;
|
|
252
|
-
sendModel.version = versionId;
|
|
253
|
-
sendModel.id = entityId;
|
|
258
|
+
sendModel.version = versionId || -1;
|
|
259
|
+
sendModel.id = entityId || -1;
|
|
254
260
|
sendModel.filter = normalizeFilters($filters);
|
|
255
261
|
let fetchData;
|
|
256
262
|
try {
|
|
257
263
|
isFetching = true;
|
|
258
|
-
fetchData = await fetch(
|
|
264
|
+
fetchData = await fetch(baseUrl || "", {
|
|
259
265
|
headers: {
|
|
260
|
-
"Content-Type": "application/json"
|
|
261
|
-
Authorization: `Bearer ${token}`
|
|
266
|
+
"Content-Type": "application/json"
|
|
262
267
|
},
|
|
263
268
|
method: "POST",
|
|
264
269
|
body: JSON.stringify(sendModel)
|
|
@@ -293,6 +298,7 @@ const updateTable = async () => {
|
|
|
293
298
|
return response;
|
|
294
299
|
};
|
|
295
300
|
const sortServer = (order, id) => {
|
|
301
|
+
if (!sendModel) throw new Error("Server-side configuration is missing");
|
|
296
302
|
if (order === void 0) {
|
|
297
303
|
sendModel.order = [];
|
|
298
304
|
} else {
|
|
@@ -301,22 +307,22 @@ const sortServer = (order, id) => {
|
|
|
301
307
|
$pageIndex = 0;
|
|
302
308
|
updateTable();
|
|
303
309
|
};
|
|
304
|
-
$:
|
|
305
|
-
|
|
306
|
-
$:
|
|
307
|
-
|
|
308
|
-
$:
|
|
309
|
-
serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
|
|
310
|
+
$: sortKeys = pluginStates.sort.sortKeys;
|
|
311
|
+
$: serverSide && updateTable();
|
|
312
|
+
$: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
|
|
313
|
+
$: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => col.id);
|
|
310
314
|
</script>
|
|
311
315
|
|
|
312
316
|
<div class="grid gap-2 overflow-auto" class:w-fit={!fitToScreen} class:w-full={fitToScreen}>
|
|
313
317
|
{#if $data.length > 0 || (columns && Object.keys(columns).length > 0)}
|
|
314
318
|
<div class="table-container">
|
|
315
319
|
<!-- Enable the search filter if table is not empty -->
|
|
316
|
-
{#if
|
|
320
|
+
{#if search}
|
|
317
321
|
<form
|
|
318
322
|
class="flex gap-2"
|
|
319
323
|
on:submit|preventDefault={() => {
|
|
324
|
+
if (!sendModel) throw new Error('Server-side configuration is missing');
|
|
325
|
+
|
|
320
326
|
sendModel.q = searchValue;
|
|
321
327
|
$filterValue = searchValue;
|
|
322
328
|
}}
|
|
@@ -333,6 +339,8 @@ $:
|
|
|
333
339
|
id="{tableId}-searchReset"
|
|
334
340
|
class="absolute right-3 items-center"
|
|
335
341
|
on:click|preventDefault={() => {
|
|
342
|
+
if (!sendModel) throw new Error('Server-side configuration is missing');
|
|
343
|
+
|
|
336
344
|
searchValue = '';
|
|
337
345
|
sendModel.q = '';
|
|
338
346
|
$filterValue = '';
|
|
@@ -344,6 +352,8 @@ $:
|
|
|
344
352
|
id="{tableId}-searchSubmit"
|
|
345
353
|
class="btn variant-filled-primary"
|
|
346
354
|
on:click|preventDefault={() => {
|
|
355
|
+
if (!sendModel) throw new Error('Server-side configuration is missing');
|
|
356
|
+
|
|
347
357
|
$filterValue = searchValue;
|
|
348
358
|
sendModel.q = searchValue;
|
|
349
359
|
}}>Search</button
|
|
@@ -384,6 +394,9 @@ $:
|
|
|
384
394
|
>Export as CSV</button
|
|
385
395
|
>
|
|
386
396
|
{/if}
|
|
397
|
+
{#if shownColumns.length > 0}
|
|
398
|
+
<ColumnsMenu bind:columns={shownColumns} {tableId} />
|
|
399
|
+
{/if}
|
|
387
400
|
</div>
|
|
388
401
|
</div>
|
|
389
402
|
|
|
@@ -436,9 +449,7 @@ $:
|
|
|
436
449
|
<!-- Adding column filter config -->
|
|
437
450
|
{#if cell.isData()}
|
|
438
451
|
{#if props.colFilter?.render}
|
|
439
|
-
<
|
|
440
|
-
<Render of={props.colFilter.render} />
|
|
441
|
-
</div>
|
|
452
|
+
<Render of={props.colFilter.render} />
|
|
442
453
|
{/if}
|
|
443
454
|
{/if}
|
|
444
455
|
</div>
|
|
@@ -509,3 +520,5 @@ $:
|
|
|
509
520
|
{/if}
|
|
510
521
|
{/if}
|
|
511
522
|
</div>
|
|
523
|
+
|
|
524
|
+
<div id="{tableId}-popups" />
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
<script>import Fa from "svelte-fa";
|
|
1
|
+
<script>import Fa from "svelte-fa/src/fa.svelte";
|
|
2
|
+
import { onMount } from "svelte";
|
|
2
3
|
import { faFilter, faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
|
3
4
|
import { popup } from "@skeletonlabs/skeleton";
|
|
4
5
|
import { FilterOptionsEnum } from "../../models/Enums";
|
|
@@ -146,7 +147,8 @@ const optionChangeHandler = (e, index) => {
|
|
|
146
147
|
const valueChangeHandler = (e, index) => {
|
|
147
148
|
dropdowns[index] = {
|
|
148
149
|
...dropdowns[index],
|
|
149
|
-
value: type === "date" ? new Date(e.target.value) : e.target.value
|
|
150
|
+
value: type === "date" ? new Date(e.target.value) : e.target.value,
|
|
151
|
+
formValue: e.target.value
|
|
150
152
|
};
|
|
151
153
|
$filters = {
|
|
152
154
|
...$filters,
|
|
@@ -166,7 +168,8 @@ const addFilter = (option, value) => {
|
|
|
166
168
|
...dropdowns,
|
|
167
169
|
{
|
|
168
170
|
option,
|
|
169
|
-
value: void 0
|
|
171
|
+
value: void 0,
|
|
172
|
+
formValue: void 0
|
|
170
173
|
}
|
|
171
174
|
];
|
|
172
175
|
};
|
|
@@ -179,17 +182,19 @@ const clearFilters = () => {
|
|
|
179
182
|
dropdowns = [];
|
|
180
183
|
$filters[id] = {};
|
|
181
184
|
};
|
|
182
|
-
$:
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
185
|
+
$: type = isDate ? "date" : type;
|
|
186
|
+
$: remainingFilters = options[type].filter(
|
|
187
|
+
(option) => !Object.keys($filters[id]).includes(option.value)
|
|
188
|
+
);
|
|
189
|
+
$: addFilter(options[type][0].value, void 0);
|
|
190
|
+
onMount(() => {
|
|
191
|
+
const element = document.getElementById(popupId);
|
|
192
|
+
element?.parentElement?.removeChild(element);
|
|
193
|
+
element && document.getElementById(`${tableId}-popups`)?.appendChild(element);
|
|
194
|
+
});
|
|
190
195
|
</script>
|
|
191
196
|
|
|
192
|
-
<
|
|
197
|
+
<div id="parent-{popupId}">
|
|
193
198
|
<button
|
|
194
199
|
class:variant-filled-primary={active}
|
|
195
200
|
class="btn w-max p-2"
|
|
@@ -200,7 +205,7 @@ $:
|
|
|
200
205
|
<Fa icon={faFilter} size="12" />
|
|
201
206
|
</button>
|
|
202
207
|
|
|
203
|
-
<div data-popup={
|
|
208
|
+
<div data-popup={popupId} id={popupId} class="">
|
|
204
209
|
<div class="card p-3 grid gap-2 shadow-lg w-max bg-base-100">
|
|
205
210
|
<button
|
|
206
211
|
class="btn variant-filled-primary btn-sm"
|
|
@@ -258,7 +263,7 @@ $:
|
|
|
258
263
|
type="date"
|
|
259
264
|
class="input p-1 border border-primary-500"
|
|
260
265
|
on:input={(e) => valueChangeHandler(e, index)}
|
|
261
|
-
bind:value={dropdown.
|
|
266
|
+
bind:value={dropdown.formValue}
|
|
262
267
|
/>
|
|
263
268
|
{/if}
|
|
264
269
|
</div>
|
|
@@ -292,4 +297,4 @@ $:
|
|
|
292
297
|
>
|
|
293
298
|
</div>
|
|
294
299
|
</div>
|
|
295
|
-
</
|
|
300
|
+
</div>
|