@bexis2/bexis2-core-ui 0.4.9 → 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 -3
- 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/Table/ColumnsMenu.svelte +33 -0
- package/dist/components/Table/ColumnsMenu.svelte.d.ts +21 -0
- package/dist/components/Table/TableContent.svelte +46 -30
- package/dist/components/Table/TableFilter.svelte +15 -7
- package/dist/components/Table/TableFilterServer.svelte +4 -2
- package/dist/components/Table/TablePagination.svelte +31 -5
- package/dist/components/Table/TablePaginationServer.svelte +1 -1
- package/dist/models/Models.d.ts +14 -6
- 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,7 +1,16 @@
|
|
|
1
|
-
#
|
|
2
|
-
## 0.4.
|
|
3
|
-
-
|
|
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.
|
|
4
10
|
|
|
11
|
+
- Facets:
|
|
12
|
+
- Adds Facets component.
|
|
13
|
+
|
|
5
14
|
## 0.4.8
|
|
6
15
|
- page
|
|
7
16
|
- add notification if api call to backend faild
|
|
@@ -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 {};
|
|
@@ -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 {};
|
|
@@ -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 {
|
|
@@ -304,16 +310,19 @@ const sortServer = (order, id) => {
|
|
|
304
310
|
$: sortKeys = pluginStates.sort.sortKeys;
|
|
305
311
|
$: serverSide && updateTable();
|
|
306
312
|
$: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
|
|
313
|
+
$: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => col.id);
|
|
307
314
|
</script>
|
|
308
315
|
|
|
309
316
|
<div class="grid gap-2 overflow-auto" class:w-fit={!fitToScreen} class:w-full={fitToScreen}>
|
|
310
317
|
{#if $data.length > 0 || (columns && Object.keys(columns).length > 0)}
|
|
311
318
|
<div class="table-container">
|
|
312
319
|
<!-- Enable the search filter if table is not empty -->
|
|
313
|
-
{#if
|
|
320
|
+
{#if search}
|
|
314
321
|
<form
|
|
315
322
|
class="flex gap-2"
|
|
316
323
|
on:submit|preventDefault={() => {
|
|
324
|
+
if (!sendModel) throw new Error('Server-side configuration is missing');
|
|
325
|
+
|
|
317
326
|
sendModel.q = searchValue;
|
|
318
327
|
$filterValue = searchValue;
|
|
319
328
|
}}
|
|
@@ -330,6 +339,8 @@ $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
|
|
|
330
339
|
id="{tableId}-searchReset"
|
|
331
340
|
class="absolute right-3 items-center"
|
|
332
341
|
on:click|preventDefault={() => {
|
|
342
|
+
if (!sendModel) throw new Error('Server-side configuration is missing');
|
|
343
|
+
|
|
333
344
|
searchValue = '';
|
|
334
345
|
sendModel.q = '';
|
|
335
346
|
$filterValue = '';
|
|
@@ -341,6 +352,8 @@ $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
|
|
|
341
352
|
id="{tableId}-searchSubmit"
|
|
342
353
|
class="btn variant-filled-primary"
|
|
343
354
|
on:click|preventDefault={() => {
|
|
355
|
+
if (!sendModel) throw new Error('Server-side configuration is missing');
|
|
356
|
+
|
|
344
357
|
$filterValue = searchValue;
|
|
345
358
|
sendModel.q = searchValue;
|
|
346
359
|
}}>Search</button
|
|
@@ -381,6 +394,9 @@ $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
|
|
|
381
394
|
>Export as CSV</button
|
|
382
395
|
>
|
|
383
396
|
{/if}
|
|
397
|
+
{#if shownColumns.length > 0}
|
|
398
|
+
<ColumnsMenu bind:columns={shownColumns} {tableId} />
|
|
399
|
+
{/if}
|
|
384
400
|
</div>
|
|
385
401
|
</div>
|
|
386
402
|
|
|
@@ -433,9 +449,7 @@ $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
|
|
|
433
449
|
<!-- Adding column filter config -->
|
|
434
450
|
{#if cell.isData()}
|
|
435
451
|
{#if props.colFilter?.render}
|
|
436
|
-
<
|
|
437
|
-
<Render of={props.colFilter.render} />
|
|
438
|
-
</div>
|
|
452
|
+
<Render of={props.colFilter.render} />
|
|
439
453
|
{/if}
|
|
440
454
|
{/if}
|
|
441
455
|
</div>
|
|
@@ -506,3 +520,5 @@ $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
|
|
|
506
520
|
{/if}
|
|
507
521
|
{/if}
|
|
508
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
|
};
|
|
@@ -184,9 +187,14 @@ $: remainingFilters = options[type].filter(
|
|
|
184
187
|
(option) => !Object.keys($filters[id]).includes(option.value)
|
|
185
188
|
);
|
|
186
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
|
+
});
|
|
187
195
|
</script>
|
|
188
196
|
|
|
189
|
-
<
|
|
197
|
+
<div id="parent-{popupId}">
|
|
190
198
|
<button
|
|
191
199
|
class:variant-filled-primary={active}
|
|
192
200
|
class="btn w-max p-2"
|
|
@@ -197,7 +205,7 @@ $: addFilter(options[type][0].value, void 0);
|
|
|
197
205
|
<Fa icon={faFilter} size="12" />
|
|
198
206
|
</button>
|
|
199
207
|
|
|
200
|
-
<div data-popup={
|
|
208
|
+
<div data-popup={popupId} id={popupId} class="">
|
|
201
209
|
<div class="card p-3 grid gap-2 shadow-lg w-max bg-base-100">
|
|
202
210
|
<button
|
|
203
211
|
class="btn variant-filled-primary btn-sm"
|
|
@@ -255,7 +263,7 @@ $: addFilter(options[type][0].value, void 0);
|
|
|
255
263
|
type="date"
|
|
256
264
|
class="input p-1 border border-primary-500"
|
|
257
265
|
on:input={(e) => valueChangeHandler(e, index)}
|
|
258
|
-
bind:value={dropdown.
|
|
266
|
+
bind:value={dropdown.formValue}
|
|
259
267
|
/>
|
|
260
268
|
{/if}
|
|
261
269
|
</div>
|
|
@@ -289,4 +297,4 @@ $: addFilter(options[type][0].value, void 0);
|
|
|
289
297
|
>
|
|
290
298
|
</div>
|
|
291
299
|
</div>
|
|
292
|
-
</
|
|
300
|
+
</div>
|
|
@@ -134,7 +134,8 @@ const optionChangeHandler = (e, index) => {
|
|
|
134
134
|
const valueChangeHandler = (e, index) => {
|
|
135
135
|
dropdowns[index] = {
|
|
136
136
|
...dropdowns[index],
|
|
137
|
-
value: type === "date" ? new Date(e.target.value) : e.target.value
|
|
137
|
+
value: type === "date" ? new Date(e.target.value) : e.target.value,
|
|
138
|
+
formValue: e.target.value
|
|
138
139
|
};
|
|
139
140
|
$filters = {
|
|
140
141
|
...$filters,
|
|
@@ -150,7 +151,8 @@ const addFilter = (option, value) => {
|
|
|
150
151
|
...dropdowns,
|
|
151
152
|
{
|
|
152
153
|
option,
|
|
153
|
-
value: void 0
|
|
154
|
+
value: void 0,
|
|
155
|
+
formValue: void 0
|
|
154
156
|
}
|
|
155
157
|
];
|
|
156
158
|
};
|
|
@@ -3,8 +3,10 @@ import {
|
|
|
3
3
|
faAnglesRight,
|
|
4
4
|
faAngleRight,
|
|
5
5
|
faAnglesLeft,
|
|
6
|
-
faAngleLeft
|
|
6
|
+
faAngleLeft,
|
|
7
|
+
faChevronDown
|
|
7
8
|
} from "@fortawesome/free-solid-svg-icons";
|
|
9
|
+
import { ListBox, ListBoxItem, popup } from "@skeletonlabs/skeleton";
|
|
8
10
|
export let pageConfig;
|
|
9
11
|
export let pageSizes;
|
|
10
12
|
export let id;
|
|
@@ -23,24 +25,48 @@ const handleChange = (e) => {
|
|
|
23
25
|
$pageIndex = value - 1;
|
|
24
26
|
}
|
|
25
27
|
};
|
|
28
|
+
let pageSizeDropdownValue = $pageSize;
|
|
29
|
+
const pageSizePopup = {
|
|
30
|
+
event: "click",
|
|
31
|
+
target: `#${id}-pageSizeDropdown`,
|
|
32
|
+
placement: "bottom",
|
|
33
|
+
closeQuery: ".listbox-item"
|
|
34
|
+
};
|
|
26
35
|
$: goToFirstPageDisabled = !$pageIndex;
|
|
27
36
|
$: goToLastPageDisabled = $pageIndex == $pageCount - 1;
|
|
28
37
|
$: goToNextPageDisabled = !$hasNextPage;
|
|
29
38
|
$: goToPreviousPageDisabled = !$hasPreviousPage;
|
|
39
|
+
$: $pageSize = pageSizeDropdownValue;
|
|
30
40
|
</script>
|
|
31
41
|
|
|
32
|
-
<div class="flex justify-between w-full items-stretch gap-10">
|
|
42
|
+
<div class="flex justify-between w-full items-stretch gap-10 z-50">
|
|
33
43
|
<div class="flex justify-start">
|
|
34
|
-
<select
|
|
44
|
+
<!-- <select
|
|
35
45
|
name="pageSize"
|
|
36
46
|
id="{id}-pageSize"
|
|
37
47
|
class="select variant-filled-primary w-min font-bold"
|
|
38
48
|
bind:value={$pageSize}
|
|
39
49
|
>
|
|
40
50
|
{#each pageSizes as size}
|
|
41
|
-
<option value={size}>{size}</option>
|
|
51
|
+
<option value={size} class="">{size}</option>
|
|
42
52
|
{/each}
|
|
43
|
-
</select>
|
|
53
|
+
</select> -->
|
|
54
|
+
|
|
55
|
+
<button class="btn variant-filled-primary w-20 justify-between" use:popup={pageSizePopup}>
|
|
56
|
+
<span class="capitalize font-semibold">{pageSizeDropdownValue}</span>
|
|
57
|
+
<Fa icon={faChevronDown} size="xs" />
|
|
58
|
+
</button>
|
|
59
|
+
|
|
60
|
+
<div class="card w-20 shadow-xl py-2" data-popup={`#${id}-pageSizeDropdown`}>
|
|
61
|
+
<ListBox rounded="rounded-none">
|
|
62
|
+
{#each pageSizes as size}
|
|
63
|
+
<ListBoxItem bind:group={pageSizeDropdownValue} name="medium" value={size}
|
|
64
|
+
>{size}</ListBoxItem
|
|
65
|
+
>
|
|
66
|
+
{/each}
|
|
67
|
+
</ListBox>
|
|
68
|
+
<div class="arrow bg-surface-100-800-token" />
|
|
69
|
+
</div>
|
|
44
70
|
</div>
|
|
45
71
|
<div class="flex justify-center gap-1">
|
|
46
72
|
<button
|