@poirazis/supercomponents-shared 0.0.1
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/LICENSE +21 -0
- package/README.md +66 -0
- package/dist/index.js +30635 -0
- package/dist/index.umd.cjs +12 -0
- package/dist/style.css +1 -0
- package/package.json +117 -0
- package/src/index.js +29 -0
- package/src/index.ts +31 -0
- package/src/lib/Actions/autoresize_textarea.js +14 -0
- package/src/lib/Actions/click_outside.js +80 -0
- package/src/lib/Actions/index.js +4 -0
- package/src/lib/Actions/position_dropdown.js +129 -0
- package/src/lib/SuperButton/SuperButton.svelte +341 -0
- package/src/lib/SuperFieldLabel/SuperFieldLabel.svelte +91 -0
- package/src/lib/SuperFieldsCommon.css +54 -0
- package/src/lib/SuperList/SuperList.svelte +308 -0
- package/src/lib/SuperList/drag-handle.svelte +31 -0
- package/src/lib/SuperPopover/SuperPopover.svelte +134 -0
- package/src/lib/SuperTable/SuperTable.css +410 -0
- package/src/lib/SuperTable/SuperTable.svelte +1332 -0
- package/src/lib/SuperTable/constants.js +85 -0
- package/src/lib/SuperTable/controls/ColumnsSection.svelte +34 -0
- package/src/lib/SuperTable/controls/ControlSection.svelte +3 -0
- package/src/lib/SuperTable/controls/RowButtonsColumn.svelte +169 -0
- package/src/lib/SuperTable/controls/SelectionColumn.svelte +174 -0
- package/src/lib/SuperTable/controls/SuperTableWelcome.svelte +58 -0
- package/src/lib/SuperTable/overlays/AddNewRowOverlay.svelte +52 -0
- package/src/lib/SuperTable/overlays/EmptyResultSetOverlay.svelte +13 -0
- package/src/lib/SuperTable/overlays/LoadingOverlay.svelte +3 -0
- package/src/lib/SuperTable/overlays/RowContextMenu copy.svelte +57 -0
- package/src/lib/SuperTable/overlays/RowContextMenu.svelte +58 -0
- package/src/lib/SuperTable/overlays/ScrollbarsOverlay.svelte +184 -0
- package/src/lib/SuperTable/overlays/SelectedActionsOverlay.svelte +64 -0
- package/src/lib/SuperTable/state/API.js +0 -0
- package/src/lib/SuperTable/state/SuperTableStateMachine.js +0 -0
- package/src/lib/SuperTable/types.js +0 -0
- package/src/lib/SuperTableCells/CellAttachment.svelte +288 -0
- package/src/lib/SuperTableCells/CellBoolean.svelte +158 -0
- package/src/lib/SuperTableCells/CellColor.svelte +460 -0
- package/src/lib/SuperTableCells/CellCommon.css +319 -0
- package/src/lib/SuperTableCells/CellDatetime.svelte +180 -0
- package/src/lib/SuperTableCells/CellIcon.svelte +627 -0
- package/src/lib/SuperTableCells/CellJSON.svelte +297 -0
- package/src/lib/SuperTableCells/CellLink.svelte +274 -0
- package/src/lib/SuperTableCells/CellLinkAdvanced.svelte +298 -0
- package/src/lib/SuperTableCells/CellLinkPickerSelect.svelte +355 -0
- package/src/lib/SuperTableCells/CellLinkPickerTable.svelte +91 -0
- package/src/lib/SuperTableCells/CellLinkPickerTree.svelte +226 -0
- package/src/lib/SuperTableCells/CellNumber.svelte +179 -0
- package/src/lib/SuperTableCells/CellNumberSimple.svelte +56 -0
- package/src/lib/SuperTableCells/CellOptions.svelte +631 -0
- package/src/lib/SuperTableCells/CellOptionsAdvanced.svelte +684 -0
- package/src/lib/SuperTableCells/CellSkeleton.svelte +59 -0
- package/src/lib/SuperTableCells/CellString.svelte +178 -0
- package/src/lib/SuperTableCells/CellStringSimple.svelte +55 -0
- package/src/lib/SuperTableCells/index.js +21 -0
- package/src/lib/SuperTableCells/remixIcons.js +6772 -0
- package/src/lib/SuperTableColumn/SuperTableColumn.svelte +392 -0
- package/src/lib/SuperTableColumn/index.js +9 -0
- package/src/lib/SuperTableColumn/parts/SuperColumnBody.svelte +57 -0
- package/src/lib/SuperTableColumn/parts/SuperColumnFooter.svelte +14 -0
- package/src/lib/SuperTableColumn/parts/SuperColumnHeader.svelte +228 -0
- package/src/lib/SuperTableColumn/parts/SuperColumnRow.svelte +142 -0
- package/src/lib/SuperTableColumn/parts/SuperColumnRowNew.svelte +34 -0
- package/src/lib/SuperTree/SuperTree.svelte +117 -0
- package/src/types/svelte-portal.d.ts +1 -0
@@ -0,0 +1,1332 @@
|
|
1
|
+
<script>
|
2
|
+
import { getContext, setContext, onDestroy, tick } from "svelte";
|
3
|
+
import fsm from "svelte-fsm";
|
4
|
+
import { writable } from "svelte/store";
|
5
|
+
|
6
|
+
import {
|
7
|
+
sizingMap,
|
8
|
+
defaultOperatorMap,
|
9
|
+
supportFilteringMap,
|
10
|
+
supportSortingMap,
|
11
|
+
supportEditingMap,
|
12
|
+
} from "./constants.js";
|
13
|
+
|
14
|
+
// Overlays
|
15
|
+
import ScrollbarsOverlay from "./overlays/ScrollbarsOverlay.svelte";
|
16
|
+
import EmptyResultSetOverlay from "./overlays/EmptyResultSetOverlay.svelte";
|
17
|
+
import AddNewRowOverlay from "./overlays/AddNewRowOverlay.svelte";
|
18
|
+
import SelectedActionsOverlay from "./overlays/SelectedActionsOverlay.svelte";
|
19
|
+
import LoadingOverlay from "./overlays/LoadingOverlay.svelte";
|
20
|
+
|
21
|
+
// Components
|
22
|
+
import SuperTableColumn from "../SuperTableColumn/SuperTableColumn.svelte";
|
23
|
+
import CellSkeleton from "../SuperTableCells/CellSkeleton.svelte";
|
24
|
+
import RowButtonsColumn from "./controls/RowButtonsColumn.svelte";
|
25
|
+
import SelectionColumn from "./controls/SelectionColumn.svelte";
|
26
|
+
import RowContextMenu from "./overlays/RowContextMenu.svelte";
|
27
|
+
|
28
|
+
// Sections
|
29
|
+
import ControlSection from "./controls/ControlSection.svelte";
|
30
|
+
import ColumnsSection from "./controls/ColumnsSection.svelte";
|
31
|
+
|
32
|
+
const {
|
33
|
+
API,
|
34
|
+
processStringSync,
|
35
|
+
notificationStore,
|
36
|
+
enrichButtonActions,
|
37
|
+
getAction,
|
38
|
+
ActionTypes,
|
39
|
+
Provider,
|
40
|
+
fetchData,
|
41
|
+
QueryUtils,
|
42
|
+
memo,
|
43
|
+
derivedMemo,
|
44
|
+
builderStore,
|
45
|
+
} = getContext("sdk");
|
46
|
+
|
47
|
+
const context = getContext("context");
|
48
|
+
|
49
|
+
// Internally used to appropriately enrich context
|
50
|
+
// this is component.id of the wrapper component seen by budibase
|
51
|
+
export let comp_id;
|
52
|
+
export let inBuilder;
|
53
|
+
|
54
|
+
// Properties
|
55
|
+
export let datasource;
|
56
|
+
export let idColumn = "_id";
|
57
|
+
export let sortColumn;
|
58
|
+
export let sortOrder;
|
59
|
+
export let limit = 50;
|
60
|
+
export let fetchOnScroll = true;
|
61
|
+
export let autoRefresh;
|
62
|
+
export let autoRefreshRate;
|
63
|
+
export let paginate;
|
64
|
+
export let filter;
|
65
|
+
export let emptyMessage;
|
66
|
+
|
67
|
+
export let columnList = [];
|
68
|
+
export let autocolumns;
|
69
|
+
|
70
|
+
export let tableActions;
|
71
|
+
|
72
|
+
export let showFooter;
|
73
|
+
export let showHeader = true;
|
74
|
+
export let size = "M";
|
75
|
+
export let canInsert, canDelete, canEdit, canResize, canFilter, canSelect;
|
76
|
+
export let superColumnsPos;
|
77
|
+
|
78
|
+
export let debounce = 750;
|
79
|
+
export let rowMenu;
|
80
|
+
export let rowMenuItems;
|
81
|
+
export let rowMenuIcon = "ri-more-fill";
|
82
|
+
export let menuItemsVisible = 0;
|
83
|
+
export let rowContextMenuItems;
|
84
|
+
|
85
|
+
export let preselectedIds;
|
86
|
+
export let hideSelectionColumn;
|
87
|
+
export let numberingColumn;
|
88
|
+
export let stickFirstColumn = false;
|
89
|
+
export let maxSelected = 0;
|
90
|
+
export let selectedActions;
|
91
|
+
|
92
|
+
export let beautifyLabels;
|
93
|
+
export let columnSizing = "flex";
|
94
|
+
export let columnMinWidth = "7rem";
|
95
|
+
export let columnMaxWidth = "auto";
|
96
|
+
export let columnFixedWidth = "7rem";
|
97
|
+
export let dividers = "horizontal";
|
98
|
+
export let dividersColor;
|
99
|
+
|
100
|
+
export let rowColorTemplate, rowBGColorTemplate;
|
101
|
+
export let rowHeight;
|
102
|
+
|
103
|
+
export let footerColorTemplate, footerBGColorTemplate;
|
104
|
+
|
105
|
+
export let useOptionColors = true;
|
106
|
+
export let optionsViewMode = "colorText";
|
107
|
+
export let relViewMode = "pills";
|
108
|
+
export let zebraColors = false;
|
109
|
+
export let quiet;
|
110
|
+
export let highlighters;
|
111
|
+
export let entitySingular = "Row";
|
112
|
+
export let entityPlural = "Rows";
|
113
|
+
|
114
|
+
// Events
|
115
|
+
export let onRowSelect;
|
116
|
+
export let onCellChange;
|
117
|
+
export let onRowClick;
|
118
|
+
export let onCellClick;
|
119
|
+
export let onLinkClick;
|
120
|
+
export let onRowDblClick;
|
121
|
+
export let onInsert;
|
122
|
+
export let afterInsert;
|
123
|
+
export let onDelete;
|
124
|
+
export let afterDelete;
|
125
|
+
export let afterEdit;
|
126
|
+
export let onRefresh;
|
127
|
+
|
128
|
+
const dataSourceStore = memo(datasource);
|
129
|
+
const columnsStore = memo(columnList);
|
130
|
+
const filterStore = memo(filter);
|
131
|
+
$: dataSourceStore.set(datasource);
|
132
|
+
$: filterStore.set(filter);
|
133
|
+
$: columnsStore.set(columnList);
|
134
|
+
$: stbData = createFetch($dataSourceStore);
|
135
|
+
$: _rowHeight = rowHeight
|
136
|
+
? toNumber(
|
137
|
+
processStringSync(rowHeight, {
|
138
|
+
[comp_id]: { row: {} },
|
139
|
+
})
|
140
|
+
) || sizingMap[size].rowHeight
|
141
|
+
: sizingMap[size].rowHeight;
|
142
|
+
|
143
|
+
// Internal Variables
|
144
|
+
let timer;
|
145
|
+
|
146
|
+
let stbColumnFilters = [];
|
147
|
+
let highlighted;
|
148
|
+
let scrollHeight;
|
149
|
+
let clientHeight;
|
150
|
+
let columnStates = [];
|
151
|
+
let canScroll;
|
152
|
+
let horizontalVisible;
|
153
|
+
let maxBodyHeight;
|
154
|
+
let viewport;
|
155
|
+
let columnsViewport;
|
156
|
+
let start = 0;
|
157
|
+
let end = 0;
|
158
|
+
let touchStartY = 0;
|
159
|
+
let touchStartX = 0;
|
160
|
+
let overflow;
|
161
|
+
let isEmpty;
|
162
|
+
let _limit = limit;
|
163
|
+
|
164
|
+
// Inserting New Record
|
165
|
+
let temp_scroll_pos;
|
166
|
+
let new_row;
|
167
|
+
|
168
|
+
// Turm non primitive props into reactive stores to limit refreshes
|
169
|
+
|
170
|
+
const stbSettings = memo({});
|
171
|
+
const stbSchema = writable(0);
|
172
|
+
// Create Stores
|
173
|
+
const stbScrollPos = memo(0);
|
174
|
+
const stbScrollOffset = memo(0);
|
175
|
+
const stbScrollPercent = memo(0);
|
176
|
+
const stbHorizontalScrollPos = memo(0);
|
177
|
+
const stbHorizontalScrollPercent = memo(0);
|
178
|
+
|
179
|
+
const stbVisibleRows = memo([]);
|
180
|
+
|
181
|
+
const stbMenuID = memo(-1);
|
182
|
+
const stbMenuAnchor = memo(-1);
|
183
|
+
const stbSelected = memo([]);
|
184
|
+
const stbHovered = memo(-1);
|
185
|
+
const stbEditing = memo(-1);
|
186
|
+
const stbSortColumn = memo({});
|
187
|
+
const stbSortOrder = memo({});
|
188
|
+
|
189
|
+
// Update Settings Reactively so children can react to changes
|
190
|
+
$: stbSettings.set({
|
191
|
+
inBuilder: $builderStore?.inBuilder,
|
192
|
+
autocolumns,
|
193
|
+
superColumnsPos,
|
194
|
+
columnSizing: columnSizing || "flexible",
|
195
|
+
columnMaxWidth: columnMaxWidth || "auto",
|
196
|
+
columnMinWidth: columnMinWidth || "7rem",
|
197
|
+
columnFixedWidth: columnFixedWidth || "7rem",
|
198
|
+
debounce,
|
199
|
+
hideSelectionColumn,
|
200
|
+
dividers,
|
201
|
+
dividersColor,
|
202
|
+
showFooter,
|
203
|
+
showHeader,
|
204
|
+
rowMenuIcon,
|
205
|
+
features: {
|
206
|
+
canSelect,
|
207
|
+
maxSelected,
|
208
|
+
canFilter,
|
209
|
+
canEdit,
|
210
|
+
canDelete,
|
211
|
+
canInsert,
|
212
|
+
canResize,
|
213
|
+
},
|
214
|
+
data: {
|
215
|
+
datasource,
|
216
|
+
idColumn,
|
217
|
+
filter,
|
218
|
+
sortColumn,
|
219
|
+
sortOrder,
|
220
|
+
limit,
|
221
|
+
emptyMessage:
|
222
|
+
emptyMessage || entityPlural
|
223
|
+
? "No " + entityPlural + " found"
|
224
|
+
: "No Rows Found",
|
225
|
+
paginate,
|
226
|
+
autoRefresh,
|
227
|
+
autoRefreshRate,
|
228
|
+
fetchOnScroll,
|
229
|
+
schema: $stbSchema,
|
230
|
+
},
|
231
|
+
appearance: {
|
232
|
+
size,
|
233
|
+
headerHeight: showHeader ? sizingMap[size].headerHeight : 0,
|
234
|
+
footerHeight: showFooter ? sizingMap[size].headerHeight : 0,
|
235
|
+
rowHeight: _rowHeight,
|
236
|
+
numberingColumn,
|
237
|
+
hideSelectionColumn,
|
238
|
+
quiet,
|
239
|
+
useOptionColors,
|
240
|
+
optionsViewMode,
|
241
|
+
relViewMode,
|
242
|
+
zebraColors,
|
243
|
+
dynamicColors: true,
|
244
|
+
highlighters,
|
245
|
+
rowColorTemplate,
|
246
|
+
rowBGColorTemplate,
|
247
|
+
footerColorTemplate,
|
248
|
+
footerBGColorTemplate,
|
249
|
+
cellPadding: sizingMap[size].cellPadding,
|
250
|
+
beautifyLabels,
|
251
|
+
},
|
252
|
+
events: {
|
253
|
+
onRowClick,
|
254
|
+
onRowDblClick,
|
255
|
+
onCellChange,
|
256
|
+
onRowSelect,
|
257
|
+
onDelete,
|
258
|
+
afterDelete,
|
259
|
+
},
|
260
|
+
});
|
261
|
+
|
262
|
+
$: stbRowMetadata = derivedMemo(
|
263
|
+
[stbData, stbSettings],
|
264
|
+
([$stbData, $stbSettings]) => {
|
265
|
+
if (!$stbData?.loaded) return [];
|
266
|
+
return (
|
267
|
+
$stbData?.rows?.map((row) => ({
|
268
|
+
height: rowHeight
|
269
|
+
? toNumber(
|
270
|
+
processStringSync(rowHeight, {
|
271
|
+
[comp_id]: { row },
|
272
|
+
})
|
273
|
+
) || $stbSettings.appearance.rowHeight
|
274
|
+
: $stbSettings.appearance.rowHeight,
|
275
|
+
bgcolor: rowBGColorTemplate
|
276
|
+
? processStringSync(rowBGColorTemplate, {
|
277
|
+
[comp_id]: { row },
|
278
|
+
})
|
279
|
+
: undefined,
|
280
|
+
color: rowColorTemplate
|
281
|
+
? processStringSync(rowColorTemplate, {
|
282
|
+
[comp_id]: { row },
|
283
|
+
})
|
284
|
+
: undefined,
|
285
|
+
})) || [{}]
|
286
|
+
);
|
287
|
+
}
|
288
|
+
);
|
289
|
+
|
290
|
+
$: cumulativeHeights = derivedMemo(
|
291
|
+
[stbRowMetadata, stbSettings],
|
292
|
+
([$meta, $settings]) => {
|
293
|
+
const defaultRowHeight = $settings.appearance?.rowHeight || 36; // Fallback if undefined
|
294
|
+
return $meta.map((_, i) =>
|
295
|
+
$meta
|
296
|
+
.slice(0, i + 1)
|
297
|
+
.reduce((sum, meta) => sum + (meta.height || defaultRowHeight), 0)
|
298
|
+
);
|
299
|
+
}
|
300
|
+
);
|
301
|
+
|
302
|
+
// The Super Table API
|
303
|
+
const tableAPI = {
|
304
|
+
unflattenObject: (obj, delimiter = ".") => {
|
305
|
+
if (!obj) return {};
|
306
|
+
|
307
|
+
return Object.keys(obj).reduce((res, k) => {
|
308
|
+
const keys = k.split(delimiter);
|
309
|
+
keys.reduce((acc, e, i) => {
|
310
|
+
// Check if this is the last key in the path
|
311
|
+
if (i === keys.length - 1) {
|
312
|
+
acc[e] = obj[k]; // Assign the original value (including booleans)
|
313
|
+
return acc;
|
314
|
+
}
|
315
|
+
|
316
|
+
// Determine the type for the next level
|
317
|
+
const nextKey = keys[i + 1];
|
318
|
+
if (!acc[e]) {
|
319
|
+
acc[e] = isNaN(Number(nextKey)) ? {} : [];
|
320
|
+
}
|
321
|
+
return acc[e];
|
322
|
+
}, res);
|
323
|
+
return res;
|
324
|
+
}, {});
|
325
|
+
},
|
326
|
+
populateColumns: (schema, list, auto) => {
|
327
|
+
let jsoncolumnslist = [];
|
328
|
+
let autocolumnsList = [];
|
329
|
+
let columns = [];
|
330
|
+
|
331
|
+
if (schema) {
|
332
|
+
if (auto) {
|
333
|
+
autocolumnsList = Object.keys(schema)
|
334
|
+
.filter((v) => schema[v].autocolumn)
|
335
|
+
.map((v) => tableAPI.enrichColumn(schema, schema[v]));
|
336
|
+
}
|
337
|
+
|
338
|
+
if (list?.length) {
|
339
|
+
columns = list.map((column) =>
|
340
|
+
tableAPI.enrichColumn(schema, { ...column, field: column.name })
|
341
|
+
);
|
342
|
+
} else {
|
343
|
+
jsoncolumnslist = Object.keys(schema)
|
344
|
+
.filter((v) => schema[v].nestedJSON)
|
345
|
+
.map((v) => tableAPI.enrichColumn(schema, schema[v]));
|
346
|
+
|
347
|
+
columns = Object.keys(schema)
|
348
|
+
.filter(
|
349
|
+
(v) =>
|
350
|
+
!schema[v].autocolumn &&
|
351
|
+
!schema[v].nestedJSON &&
|
352
|
+
schema[v]?.visible != false &&
|
353
|
+
v != idColumn
|
354
|
+
)
|
355
|
+
.map((v) => {
|
356
|
+
return tableAPI.enrichColumn(schema, {
|
357
|
+
...schema[v],
|
358
|
+
field: v ?? schema[v].field ?? schema[v].name,
|
359
|
+
});
|
360
|
+
});
|
361
|
+
}
|
362
|
+
|
363
|
+
return [...columns, ...jsoncolumnslist, ...autocolumnsList].sort(
|
364
|
+
(a, b) => a.order - b.order
|
365
|
+
);
|
366
|
+
}
|
367
|
+
},
|
368
|
+
enrichColumn: (schema, bbcolumn) => {
|
369
|
+
let type;
|
370
|
+
let columnSchema;
|
371
|
+
|
372
|
+
if (bbcolumn.field.includes(".")) {
|
373
|
+
let words = bbcolumn.field.split(".");
|
374
|
+
let outerSchema = schema[words[0]].schema;
|
375
|
+
columnSchema = outerSchema[words[1]];
|
376
|
+
type = columnSchema.type;
|
377
|
+
} else {
|
378
|
+
type = schema[bbcolumn.field]?.type;
|
379
|
+
columnSchema = schema[bbcolumn.field];
|
380
|
+
|
381
|
+
// TODO : Let the ST handle self relationships inline
|
382
|
+
/**
|
383
|
+
if (bbcolumn.field.startsWith("fk_self_")) {
|
384
|
+
(type = "link"),
|
385
|
+
(columnSchema = {
|
386
|
+
...columnSchema,
|
387
|
+
tableId: $dataSourceStore.tableId,
|
388
|
+
relationshipType: "self",
|
389
|
+
type: "link",
|
390
|
+
});
|
391
|
+
}
|
392
|
+
*/
|
393
|
+
}
|
394
|
+
|
395
|
+
return {
|
396
|
+
...bbcolumn,
|
397
|
+
name: bbcolumn.field,
|
398
|
+
widthOverride: bbcolumn.width,
|
399
|
+
readonly: schema[bbcolumn.field]?.readonly,
|
400
|
+
canEdit:
|
401
|
+
supportEditingMap[type] &&
|
402
|
+
canEdit &&
|
403
|
+
!schema[bbcolumn.name]?.readonly,
|
404
|
+
canFilter: supportFilteringMap[type] ? canFilter : false,
|
405
|
+
canSort: supportSortingMap[type],
|
406
|
+
filteringOperators: QueryUtils.getValidOperatorsForType({ type }),
|
407
|
+
defaultFilteringOperator: defaultOperatorMap[type],
|
408
|
+
headerAlign: bbcolumn.align ? bbcolumn.align : "flex-start",
|
409
|
+
type,
|
410
|
+
displayName: beautifyLabel(bbcolumn.displayName ?? bbcolumn.field),
|
411
|
+
schema: columnSchema,
|
412
|
+
};
|
413
|
+
},
|
414
|
+
enrichContext: (row) => {
|
415
|
+
return {
|
416
|
+
...$context,
|
417
|
+
[comp_id]: {
|
418
|
+
...$context[comp_id],
|
419
|
+
row,
|
420
|
+
},
|
421
|
+
};
|
422
|
+
},
|
423
|
+
registerSuperColumn: (id, state) => {
|
424
|
+
columnStates = [...columnStates, { id, state }];
|
425
|
+
},
|
426
|
+
unregisterSuperColumn: (id) => {
|
427
|
+
let pos = columnStates.findIndex((col) => col.id == id);
|
428
|
+
if (pos > -1) {
|
429
|
+
columnStates.splice(pos, 1);
|
430
|
+
columnStates = columnStates;
|
431
|
+
}
|
432
|
+
},
|
433
|
+
executeRowButtonAction: async (index, action) => {
|
434
|
+
let cmd = enrichButtonActions(
|
435
|
+
action,
|
436
|
+
tableAPI.enrichContext($stbData.rows[index])
|
437
|
+
);
|
438
|
+
await cmd?.();
|
439
|
+
},
|
440
|
+
executeRowOnClickAction: async (index) => {
|
441
|
+
await tableAPI.executeRowButtonAction(index, onRowClick);
|
442
|
+
},
|
443
|
+
executeCellOnClickAction: async (index, column, value, id) => {
|
444
|
+
let cmd = enrichButtonActions(
|
445
|
+
onCellClick,
|
446
|
+
tableAPI.enrichContext($stbData.rows[index])
|
447
|
+
);
|
448
|
+
await cmd?.({ column, value, id });
|
449
|
+
},
|
450
|
+
executeOnLinkClickAction: async (column, linkItem) => {
|
451
|
+
let cmd = enrichButtonActions(onLinkClick, {
|
452
|
+
column,
|
453
|
+
id: linkItem._id,
|
454
|
+
primaryDisplay: linkItem.primaryDisplay,
|
455
|
+
});
|
456
|
+
await cmd?.({
|
457
|
+
column,
|
458
|
+
id: linkItem._id,
|
459
|
+
primaryDisplay: linkItem.primaryDisplay,
|
460
|
+
});
|
461
|
+
},
|
462
|
+
executeRowOnDblClickAction: async (id) => {
|
463
|
+
await tableAPI.executeRowButtonAction(id, onRowDblClick);
|
464
|
+
},
|
465
|
+
executeRowOnSelectAction: async (index) => {
|
466
|
+
await tick();
|
467
|
+
let cmd = enrichButtonActions(
|
468
|
+
onRowSelect,
|
469
|
+
tableAPI.enrichContext($stbData.rows[index])
|
470
|
+
);
|
471
|
+
await cmd?.();
|
472
|
+
},
|
473
|
+
showContextMenu: (id, anchor) => {
|
474
|
+
if (rowContextMenuItems?.length && $stbMenuID != id) {
|
475
|
+
$stbMenuID = id;
|
476
|
+
$stbMenuAnchor = anchor;
|
477
|
+
} else {
|
478
|
+
$stbMenuID = -1;
|
479
|
+
$stbMenuAnchor = -1;
|
480
|
+
}
|
481
|
+
},
|
482
|
+
executeRowContextMenuAction: async (id, action) => {
|
483
|
+
await tableAPI.executeRowButtonAction(id, action);
|
484
|
+
$stbMenuID = -1;
|
485
|
+
$stbMenuAnchor = -1;
|
486
|
+
},
|
487
|
+
executeSelectedRowsAction: async (action) => {
|
488
|
+
tableAPI.executeRowButtonAction(null, action);
|
489
|
+
},
|
490
|
+
selectRow: (index) => {
|
491
|
+
let id = $stbData.rows[index][idColumn] ?? index;
|
492
|
+
|
493
|
+
if (maxSelected != 1) {
|
494
|
+
if ($stbSelected.includes(id)) {
|
495
|
+
$stbSelected.splice($stbSelected.indexOf(id), 1);
|
496
|
+
$stbSelected = $stbSelected;
|
497
|
+
} else {
|
498
|
+
if (maxSelected == 0 || $stbSelected.length < maxSelected)
|
499
|
+
$stbSelected = [...$stbSelected, id];
|
500
|
+
else
|
501
|
+
notificationStore.actions.warning(
|
502
|
+
"Cannot select more than " +
|
503
|
+
maxSelected +
|
504
|
+
" " +
|
505
|
+
(entityPlural || "Rows")
|
506
|
+
);
|
507
|
+
}
|
508
|
+
} else {
|
509
|
+
if ($stbSelected.includes(id)) {
|
510
|
+
$stbSelected = [];
|
511
|
+
} else {
|
512
|
+
$stbSelected = [id];
|
513
|
+
}
|
514
|
+
}
|
515
|
+
|
516
|
+
// Fire Assigned Events
|
517
|
+
if ($stbSelected.length) tableAPI.executeRowOnSelectAction(index);
|
518
|
+
},
|
519
|
+
selectAllRows: () => {
|
520
|
+
if ($stbSelected.length != $stbData.rows.length)
|
521
|
+
$stbSelected = $stbData.rows.map((x) => x[idColumn]);
|
522
|
+
else $stbSelected = [];
|
523
|
+
|
524
|
+
tableAPI.executeRowOnSelectAction();
|
525
|
+
},
|
526
|
+
insertRow: async (row) => {
|
527
|
+
let cmd_after = enrichButtonActions(afterInsert, $context);
|
528
|
+
let saved_row;
|
529
|
+
if (onInsert && onInsert.length) {
|
530
|
+
let cmd = enrichButtonActions(onInsert, $context);
|
531
|
+
await cmd?.();
|
532
|
+
} else {
|
533
|
+
stbState.startSave();
|
534
|
+
try {
|
535
|
+
saved_row = await API.saveRow({ ...new_row, tableId });
|
536
|
+
} catch (e) {
|
537
|
+
console.log(e);
|
538
|
+
} finally {
|
539
|
+
await cmd_after?.({ newRow: saved_row });
|
540
|
+
stbState.endSave();
|
541
|
+
}
|
542
|
+
}
|
543
|
+
},
|
544
|
+
deleteRow: async (index) => {
|
545
|
+
let id = $stbData.rows[index][idColumn];
|
546
|
+
let row = $stbData.rows[index];
|
547
|
+
|
548
|
+
let autoDelete = [
|
549
|
+
{
|
550
|
+
parameters: {
|
551
|
+
confirm: true,
|
552
|
+
notificationOverride: true,
|
553
|
+
customTitleText: "Delete " + (entitySingular || "Row") + " ?",
|
554
|
+
confirmText:
|
555
|
+
"Are you sure you want to delete this " +
|
556
|
+
(entitySingular || "Row") +
|
557
|
+
" ?",
|
558
|
+
tableId: tableId,
|
559
|
+
rowId: id,
|
560
|
+
},
|
561
|
+
"##eventHandlerType": "Delete Row",
|
562
|
+
},
|
563
|
+
];
|
564
|
+
|
565
|
+
let cmd;
|
566
|
+
let cmd_after = enrichButtonActions(
|
567
|
+
afterDelete,
|
568
|
+
tableAPI.enrichContext($stbData.rows[index])
|
569
|
+
);
|
570
|
+
|
571
|
+
if (onDelete?.length) {
|
572
|
+
cmd = enrichButtonActions(
|
573
|
+
onDelete,
|
574
|
+
tableAPI.enrichContext($stbData.rows[index])
|
575
|
+
);
|
576
|
+
} else {
|
577
|
+
cmd = enrichButtonActions(autoDelete, {});
|
578
|
+
}
|
579
|
+
|
580
|
+
await cmd?.({ row });
|
581
|
+
await cmd_after?.({ row });
|
582
|
+
|
583
|
+
// Remove row from the selected list if selected
|
584
|
+
if ($stbSelected.includes(id)) {
|
585
|
+
$stbSelected.splice($stbSelected.indexOf(id), 1);
|
586
|
+
$stbSelected = $stbSelected;
|
587
|
+
}
|
588
|
+
|
589
|
+
// Refresh the dataset
|
590
|
+
stbData.refresh();
|
591
|
+
},
|
592
|
+
deleteSelectedRows: async () => {
|
593
|
+
let autoDelete = [
|
594
|
+
{
|
595
|
+
parameters: {
|
596
|
+
confirm: true,
|
597
|
+
notificationOverride: true,
|
598
|
+
customTitleText:
|
599
|
+
"Delete " +
|
600
|
+
$stbSelected.length +
|
601
|
+
" " +
|
602
|
+
(entityPlural || "Rows") +
|
603
|
+
" ?",
|
604
|
+
confirmText:
|
605
|
+
"Are you sure you want to delete these " +
|
606
|
+
(entityPlural || "Rows") +
|
607
|
+
" ?",
|
608
|
+
tableId: tableId,
|
609
|
+
rowId: $stbSelected,
|
610
|
+
},
|
611
|
+
"##eventHandlerType": "Delete Row",
|
612
|
+
},
|
613
|
+
];
|
614
|
+
let cmd = enrichButtonActions(autoDelete, {});
|
615
|
+
let cmd_after = enrichButtonActions(afterDelete, $context);
|
616
|
+
await cmd?.();
|
617
|
+
await cmd_after?.();
|
618
|
+
stbData.refresh();
|
619
|
+
},
|
620
|
+
patchRow: async (patch) => {
|
621
|
+
patch = tableAPI.unflattenObject(patch);
|
622
|
+
if (tableId) {
|
623
|
+
try {
|
624
|
+
let row = await API.patchRow({
|
625
|
+
tableId,
|
626
|
+
...patch,
|
627
|
+
});
|
628
|
+
|
629
|
+
stbState.refresh();
|
630
|
+
let richContext = {
|
631
|
+
...$context,
|
632
|
+
[comp_id]: { row },
|
633
|
+
};
|
634
|
+
let cmd_after = enrichButtonActions(afterEdit, richContext);
|
635
|
+
await cmd_after?.({ row });
|
636
|
+
return row;
|
637
|
+
} catch (ex) {
|
638
|
+
console.log(ex);
|
639
|
+
}
|
640
|
+
}
|
641
|
+
},
|
642
|
+
};
|
643
|
+
|
644
|
+
// Super Table State Machine
|
645
|
+
const stbState = fsm("Init", {
|
646
|
+
"*": {
|
647
|
+
init() {
|
648
|
+
return "Init";
|
649
|
+
},
|
650
|
+
async refresh() {
|
651
|
+
if (stbData.loaded) await stbData?.refresh();
|
652
|
+
this.enrichRows();
|
653
|
+
this.calculateRowBoundaries();
|
654
|
+
},
|
655
|
+
enrichRows() {},
|
656
|
+
scrollToTop() {
|
657
|
+
$stbScrollPos = 0;
|
658
|
+
$stbScrollOffset = 0;
|
659
|
+
this.calculateRowBoundaries();
|
660
|
+
},
|
661
|
+
scrollTo(position) {
|
662
|
+
$stbScrollPos = position;
|
663
|
+
this.calculateRowBoundaries();
|
664
|
+
},
|
665
|
+
scrollToEnd() {
|
666
|
+
$stbScrollPos = scrollHeight - maxBodyHeight;
|
667
|
+
this.calculateRowBoundaries();
|
668
|
+
},
|
669
|
+
calculateBoundaries() {
|
670
|
+
let rows = $stbData?.rows;
|
671
|
+
if (!rows || !viewport) return;
|
672
|
+
|
673
|
+
const defaultRowHeight = $stbSettings.appearance.rowHeight;
|
674
|
+
|
675
|
+
// Calculate scrollHeight as sum of row heights from stbRowMetadata
|
676
|
+
scrollHeight =
|
677
|
+
($cumulativeHeights[$cumulativeHeights.length - 1] || 0) +
|
678
|
+
(canInsert ? 4 * defaultRowHeight : 2 * defaultRowHeight);
|
679
|
+
|
680
|
+
// Calculate maxBodyHeight, adding one row height for extra space
|
681
|
+
|
682
|
+
maxBodyHeight =
|
683
|
+
viewport.clientHeight -
|
684
|
+
$stbSettings.appearance.headerHeight -
|
685
|
+
$stbSettings.appearance.footerHeight +
|
686
|
+
defaultRowHeight; // Add extra row height for negative margin
|
687
|
+
|
688
|
+
// Determine if scrolling is needed
|
689
|
+
canScroll = scrollHeight > maxBodyHeight;
|
690
|
+
overflow = canScroll;
|
691
|
+
|
692
|
+
// Update scroll percentage
|
693
|
+
$stbScrollPercent =
|
694
|
+
scrollHeight > maxBodyHeight
|
695
|
+
? $stbScrollPos / (scrollHeight - maxBodyHeight)
|
696
|
+
: 0;
|
697
|
+
|
698
|
+
// Recalculate visible row boundaries
|
699
|
+
this.calculateRowBoundaries();
|
700
|
+
},
|
701
|
+
calculateRowBoundaries() {
|
702
|
+
let rows = $stbData?.rows;
|
703
|
+
if (!rows?.length || !viewport || !$cumulativeHeights.length) return;
|
704
|
+
|
705
|
+
const defaultRowHeight = $stbSettings.appearance.rowHeight;
|
706
|
+
let start = $stbVisibleRows?.length ? $stbVisibleRows[0] - 1 : 0;
|
707
|
+
start = Math.max(0, start); // Ensure start doesn't go negative
|
708
|
+
let end = 0;
|
709
|
+
|
710
|
+
// Find start index using cumulativeHeights
|
711
|
+
for (let i = 0; i < rows.length; i++) {
|
712
|
+
if ($cumulativeHeights[i] > $stbScrollPos) {
|
713
|
+
start = i;
|
714
|
+
break;
|
715
|
+
}
|
716
|
+
}
|
717
|
+
|
718
|
+
// Find end index using cumulativeHeights
|
719
|
+
for (let i = start; i < rows.length; i++) {
|
720
|
+
if (
|
721
|
+
$cumulativeHeights[i] >=
|
722
|
+
$stbScrollPos + maxBodyHeight - defaultRowHeight
|
723
|
+
) {
|
724
|
+
end = i + 1;
|
725
|
+
break;
|
726
|
+
}
|
727
|
+
}
|
728
|
+
|
729
|
+
// Ensure all rows are included when at the bottom
|
730
|
+
end = end || rows.length;
|
731
|
+
|
732
|
+
// Update visible rows
|
733
|
+
$stbVisibleRows = $stbData?.rows
|
734
|
+
?.slice(start, end)
|
735
|
+
.map((_, i) => i + start);
|
736
|
+
|
737
|
+
// Calculate scroll offset for rendering
|
738
|
+
const startHeight = start > 0 ? $cumulativeHeights[start - 1] : 0;
|
739
|
+
$stbScrollOffset = $stbScrollPos - startHeight;
|
740
|
+
|
741
|
+
// Ensure offset doesn't exceed bounds at the end
|
742
|
+
if ($stbScrollPos >= scrollHeight - maxBodyHeight) {
|
743
|
+
$stbScrollPos = Math.max(0, scrollHeight - maxBodyHeight);
|
744
|
+
$stbScrollOffset = Math.min(
|
745
|
+
$stbScrollOffset,
|
746
|
+
maxBodyHeight - defaultRowHeight
|
747
|
+
);
|
748
|
+
}
|
749
|
+
|
750
|
+
// Fetch more rows if nearing the end of loaded data
|
751
|
+
if (fetchOnScroll && rows.length > 0) {
|
752
|
+
const loadedHeight = $cumulativeHeights[rows.length - 1];
|
753
|
+
const remainingHeight =
|
754
|
+
loadedHeight - ($stbScrollPos + maxBodyHeight);
|
755
|
+
if (remainingHeight < maxBodyHeight && rows.length == _limit) {
|
756
|
+
stbState.fetchMoreRows.debounce(200, 100); // Debounced fetch call
|
757
|
+
}
|
758
|
+
}
|
759
|
+
},
|
760
|
+
handleVerticalScroll(delta) {
|
761
|
+
$stbScrollPos = Math.max(
|
762
|
+
Math.min(
|
763
|
+
$stbScrollPos + delta,
|
764
|
+
Math.max(0, scrollHeight - maxBodyHeight)
|
765
|
+
),
|
766
|
+
0
|
767
|
+
);
|
768
|
+
$stbScrollPercent =
|
769
|
+
scrollHeight > maxBodyHeight
|
770
|
+
? $stbScrollPos / (scrollHeight - maxBodyHeight)
|
771
|
+
: 0;
|
772
|
+
$stbScrollOffset = Math.floor(
|
773
|
+
$stbScrollPos % $stbSettings.appearance.rowHeight
|
774
|
+
);
|
775
|
+
|
776
|
+
this.calculateRowBoundaries.debounce(1);
|
777
|
+
},
|
778
|
+
handleWheel(e) {
|
779
|
+
if ($stbState == "Inserting") {
|
780
|
+
e.preventDefault();
|
781
|
+
e.stopPropagation();
|
782
|
+
return;
|
783
|
+
}
|
784
|
+
|
785
|
+
if (e.deltaY && canScroll) {
|
786
|
+
e.preventDefault();
|
787
|
+
e.stopPropagation();
|
788
|
+
this.handleVerticalScroll(e.deltaY);
|
789
|
+
} else if (e.deltaX) {
|
790
|
+
if ($stbHorizontalScrollPos + e.deltaX < 0) {
|
791
|
+
$stbHorizontalScrollPos = 0;
|
792
|
+
$stbHorizontalScrollPercent = 0;
|
793
|
+
return;
|
794
|
+
}
|
795
|
+
if (
|
796
|
+
$stbHorizontalScrollPos + e.deltaX >
|
797
|
+
columnsViewport?.scrollWidth - columnsViewport.clientWidth
|
798
|
+
) {
|
799
|
+
$stbHorizontalScrollPos =
|
800
|
+
columnsViewport?.scrollWidth - columnsViewport.clientWidth;
|
801
|
+
$stbHorizontalScrollPercent = 1;
|
802
|
+
return;
|
803
|
+
}
|
804
|
+
|
805
|
+
$stbHorizontalScrollPos += e.deltaX;
|
806
|
+
$stbHorizontalScrollPercent =
|
807
|
+
$stbHorizontalScrollPos / columnsViewport.scrollWidth;
|
808
|
+
}
|
809
|
+
},
|
810
|
+
handleKeyboard(e) {
|
811
|
+
// TODO : Table Keyboard Handler
|
812
|
+
},
|
813
|
+
handleTouch(e, type) {
|
814
|
+
if ($stbData.loading || $stbState === "Inserting") {
|
815
|
+
e.preventDefault();
|
816
|
+
return;
|
817
|
+
}
|
818
|
+
|
819
|
+
if (type === "start") {
|
820
|
+
touchStartY = e.touches[0].clientY;
|
821
|
+
touchStartX = e.touches[0].clientX;
|
822
|
+
} else if (type === "move" && canScroll) {
|
823
|
+
const touchY = e.touches[0].clientY;
|
824
|
+
const touchX = e.touches[0].clientX;
|
825
|
+
const deltaY = touchStartY - touchY; // Positive for swipe up, negative for swipe down
|
826
|
+
const deltaX = touchStartX - touchX;
|
827
|
+
|
828
|
+
// Prioritize vertical scrolling if swipe is mostly vertical
|
829
|
+
if (Math.abs(deltaY) > Math.abs(deltaX)) {
|
830
|
+
e.preventDefault(); // Prevent native vertical scroll
|
831
|
+
this.handleVerticalScroll(deltaY * 0.5); // Adjust sensitivity (0.5 for smoother scrolling)
|
832
|
+
touchStartY = touchY; // Update start position for continuous scrolling
|
833
|
+
}
|
834
|
+
}
|
835
|
+
},
|
836
|
+
sortBy(column, order) {
|
837
|
+
sortColumn = column;
|
838
|
+
sortOrder = order;
|
839
|
+
$stbSortColumn = column;
|
840
|
+
$stbSortOrder = order;
|
841
|
+
},
|
842
|
+
resizeRow(index, size) {
|
843
|
+
$stbRowMetadata[index].height =
|
844
|
+
size || $stbSettings.appearance.rowHeight;
|
845
|
+
this.calculateBoundaries.debounce(20);
|
846
|
+
},
|
847
|
+
handleRowClick(index, column, value, id) {
|
848
|
+
if (canSelect && !canEdit) tableAPI.selectRow(index);
|
849
|
+
if (onCellClick) {
|
850
|
+
tableAPI.executeCellOnClickAction(index, column, value, id);
|
851
|
+
tableAPI.executeRowOnClickAction(index);
|
852
|
+
} else {
|
853
|
+
tableAPI.executeRowOnClickAction(index);
|
854
|
+
}
|
855
|
+
},
|
856
|
+
addRow() {
|
857
|
+
if (!onInsert || onInsert?.length == 0) {
|
858
|
+
return "Inserting";
|
859
|
+
} else {
|
860
|
+
tableAPI.insertRow();
|
861
|
+
}
|
862
|
+
},
|
863
|
+
edit() {
|
864
|
+
return "Editing";
|
865
|
+
},
|
866
|
+
},
|
867
|
+
Init: {
|
868
|
+
_enter() {
|
869
|
+
if (timer) clearInterval(timer);
|
870
|
+
start = 0;
|
871
|
+
end = 0;
|
872
|
+
$stbScrollPos = 0;
|
873
|
+
$stbScrollOffset = 0;
|
874
|
+
$stbHorizontalScrollPos = 0;
|
875
|
+
$stbSelected = [];
|
876
|
+
if (_limit != limit) _limit = limit;
|
877
|
+
},
|
878
|
+
synch(fetchState) {
|
879
|
+
if (fetchState.loaded) {
|
880
|
+
this.enrichRows();
|
881
|
+
this.calculateBoundaries();
|
882
|
+
if (autoRefresh && !inBuilder) {
|
883
|
+
timer = setInterval(() => {
|
884
|
+
stbData?.refresh();
|
885
|
+
onRefresh?.();
|
886
|
+
}, autoRefreshRate * 1000);
|
887
|
+
}
|
888
|
+
return "Idle";
|
889
|
+
}
|
890
|
+
},
|
891
|
+
},
|
892
|
+
Idle: {
|
893
|
+
_enter() {
|
894
|
+
isEmpty = $stbData.rows.length < 1;
|
895
|
+
},
|
896
|
+
_exit() {},
|
897
|
+
synch(fetchState) {
|
898
|
+
if (fetchState.loading) return;
|
899
|
+
this.enrichRows();
|
900
|
+
this.calculateBoundaries();
|
901
|
+
isEmpty = !$stbData?.rows.length;
|
902
|
+
},
|
903
|
+
addFilter(filterObj) {
|
904
|
+
stbColumnFilters = [...stbColumnFilters, filterObj];
|
905
|
+
return "Filtered";
|
906
|
+
},
|
907
|
+
fetchMoreRows(size) {
|
908
|
+
_limit = _limit + size;
|
909
|
+
stbData.update({ limit: _limit });
|
910
|
+
},
|
911
|
+
},
|
912
|
+
Filtered: {
|
913
|
+
_enter() {},
|
914
|
+
_exit() {},
|
915
|
+
addFilter(filterObj) {
|
916
|
+
this.removeFilter(filterObj.id);
|
917
|
+
stbColumnFilters = [...stbColumnFilters, filterObj];
|
918
|
+
},
|
919
|
+
removeFilter(id) {
|
920
|
+
let pos = stbColumnFilters.find((x) => x.id == id);
|
921
|
+
if (pos) {
|
922
|
+
stbColumnFilters = stbColumnFilters.toSpliced(pos, 1);
|
923
|
+
}
|
924
|
+
},
|
925
|
+
clearFilter(id) {
|
926
|
+
let pos = stbColumnFilters.find((x) => x.id == id);
|
927
|
+
if (pos) {
|
928
|
+
stbColumnFilters = stbColumnFilters.toSpliced(pos, 1);
|
929
|
+
}
|
930
|
+
if (!stbColumnFilters.length) return "Idle";
|
931
|
+
},
|
932
|
+
clear() {
|
933
|
+
stbColumnFilters = [];
|
934
|
+
columnStates.forEach(({ state }) => state.reset());
|
935
|
+
return "Idle";
|
936
|
+
},
|
937
|
+
synch(fetchState) {
|
938
|
+
if (fetchState.loaded) {
|
939
|
+
this.enrichRows();
|
940
|
+
this.calculateBoundaries();
|
941
|
+
this.calculateRowBoundaries();
|
942
|
+
|
943
|
+
isEmpty = fetchState.rows.length < 1;
|
944
|
+
}
|
945
|
+
},
|
946
|
+
},
|
947
|
+
Editing: {
|
948
|
+
async patchRow(index, id, rev, field, change) {
|
949
|
+
let patch = { _id: id, _rev: rev, [field]: change };
|
950
|
+
await tableAPI.patchRow(index, patch);
|
951
|
+
stbState.refresh();
|
952
|
+
return "Idle";
|
953
|
+
},
|
954
|
+
endEdit() {
|
955
|
+
return "Idle";
|
956
|
+
},
|
957
|
+
},
|
958
|
+
Inserting: {
|
959
|
+
_enter() {
|
960
|
+
isEmpty = false;
|
961
|
+
columnStates.forEach(({ state }) => state.addRow());
|
962
|
+
new_row = {};
|
963
|
+
temp_scroll_pos = $stbScrollPos;
|
964
|
+
this.scrollToEnd();
|
965
|
+
},
|
966
|
+
_exit() {
|
967
|
+
columnStates.forEach(({ state }) => state.cancelAddRow());
|
968
|
+
this.scrollTo(temp_scroll_pos);
|
969
|
+
},
|
970
|
+
cancelAddRow() {
|
971
|
+
return "Idle";
|
972
|
+
},
|
973
|
+
endSave() {
|
974
|
+
this.refresh();
|
975
|
+
return "Idle";
|
976
|
+
},
|
977
|
+
setValue(field, value) {
|
978
|
+
new_row[field] = value;
|
979
|
+
},
|
980
|
+
},
|
981
|
+
});
|
982
|
+
|
983
|
+
$: stbSchema.set($stbData?.definition?.schema);
|
984
|
+
|
985
|
+
// Virtual List Capabilities reacting to viewport change
|
986
|
+
$: stbState.calculateBoundaries(
|
987
|
+
clientHeight,
|
988
|
+
canInsert,
|
989
|
+
$stbSortColumn,
|
990
|
+
fetchOnScroll,
|
991
|
+
rowHeight
|
992
|
+
);
|
993
|
+
|
994
|
+
// Scroll to Top when filter changes
|
995
|
+
$: stbState.scrollToTop(query);
|
996
|
+
|
997
|
+
$: if (canSelect) stbSelected.set(preselectedIds ?? []);
|
998
|
+
else stbSelected.set([]);
|
999
|
+
|
1000
|
+
$: idColumn = $stbData?.definition?.primary?.[0]
|
1001
|
+
? $stbData?.definition?.primary?.[0]
|
1002
|
+
: $stbSchema?.id
|
1003
|
+
? "id"
|
1004
|
+
: "_id";
|
1005
|
+
|
1006
|
+
// Reactively set the Table Settings store
|
1007
|
+
|
1008
|
+
$: if (datasource.type == "provider") {
|
1009
|
+
let dataProviderId = datasource.providerId;
|
1010
|
+
let addExtension = getAction(
|
1011
|
+
dataProviderId,
|
1012
|
+
ActionTypes.AddDataProviderQueryExtension
|
1013
|
+
);
|
1014
|
+
|
1015
|
+
let removeExtension = getAction(
|
1016
|
+
dataProviderId,
|
1017
|
+
ActionTypes.RemoveDataProviderQueryExtension
|
1018
|
+
);
|
1019
|
+
}
|
1020
|
+
|
1021
|
+
// Data Related
|
1022
|
+
$: defaultQuery = QueryUtils.buildQuery($filterStore);
|
1023
|
+
$: queryExtension = QueryUtils.buildQuery(stbColumnFilters);
|
1024
|
+
$: query = extendQuery(defaultQuery, [queryExtension]);
|
1025
|
+
|
1026
|
+
$: stbData?.update({
|
1027
|
+
query,
|
1028
|
+
sortColumn,
|
1029
|
+
sortOrder,
|
1030
|
+
});
|
1031
|
+
$: stbState.synch($stbData);
|
1032
|
+
$: tableId = $stbData?.definition?.tableId || $stbData?.definition?._id;
|
1033
|
+
|
1034
|
+
// Derived Store with the columns to be rendered
|
1035
|
+
$: superColumns = derivedMemo(
|
1036
|
+
[stbSchema, columnsStore, stbSettings],
|
1037
|
+
([$stbSchema, $columnsStore, $stbSettings]) => {
|
1038
|
+
if ($stbSchema)
|
1039
|
+
return tableAPI.populateColumns($stbSchema, $columnsStore, autocolumns);
|
1040
|
+
}
|
1041
|
+
);
|
1042
|
+
|
1043
|
+
// Derived Store with common column settings
|
1044
|
+
const commonColumnOptions = derivedMemo(stbSettings, ($stbSettings) => {
|
1045
|
+
return {
|
1046
|
+
hasChildren: false,
|
1047
|
+
maxWidth: columnMaxWidth || "auto",
|
1048
|
+
minWidth: columnMinWidth || "7rem",
|
1049
|
+
fixedWidth: columnFixedWidth || "7rem",
|
1050
|
+
sizing: columnSizing,
|
1051
|
+
canResize,
|
1052
|
+
canEdit: inBuilder ? false : canEdit,
|
1053
|
+
showFooter,
|
1054
|
+
showHeader,
|
1055
|
+
cellPadding: sizingMap[size].cellPadding,
|
1056
|
+
headerHeight: sizingMap[size].headerHeight,
|
1057
|
+
rowHeight: sizingMap[size].rowHeight,
|
1058
|
+
highlighters,
|
1059
|
+
useOptionColors: $stbSettings?.appearance?.useOptionColors || false,
|
1060
|
+
optionsViewMode,
|
1061
|
+
relViewMode,
|
1062
|
+
zebraColors,
|
1063
|
+
quiet,
|
1064
|
+
};
|
1065
|
+
});
|
1066
|
+
|
1067
|
+
$: dividersStyles = {
|
1068
|
+
color:
|
1069
|
+
$stbSettings.dividersColor ?? "var(--spectrum-global-color-gray-200)",
|
1070
|
+
horizontal:
|
1071
|
+
$stbSettings.dividers == "both" || $stbSettings.dividers == "horizontal"
|
1072
|
+
? "1px solid var(--super-table-devider-color)"
|
1073
|
+
: "1px solid transparent",
|
1074
|
+
vertical:
|
1075
|
+
$stbSettings.dividers == "both" || $stbSettings.dividers == "vertical"
|
1076
|
+
? "1px solid var(--super-table-devider-color)"
|
1077
|
+
: "none",
|
1078
|
+
};
|
1079
|
+
|
1080
|
+
// Build our data and actions ontext
|
1081
|
+
$: actions = [
|
1082
|
+
{
|
1083
|
+
type: ActionTypes.ClearRowSelection,
|
1084
|
+
callback: () => {
|
1085
|
+
$stbSelected = [];
|
1086
|
+
},
|
1087
|
+
},
|
1088
|
+
{
|
1089
|
+
type: ActionTypes.RefreshDatasource,
|
1090
|
+
callback: () => stbData?.refresh(),
|
1091
|
+
},
|
1092
|
+
];
|
1093
|
+
|
1094
|
+
// The "row" is dynamically enriched, but show the first one in the builder for preview
|
1095
|
+
$: dataContext = {
|
1096
|
+
row: inBuilder ? $stbData?.rows[0] : {},
|
1097
|
+
hoveredRow: $stbData?.rows[$stbHovered],
|
1098
|
+
rows: $stbData?.rows,
|
1099
|
+
selectedRows: $stbData?.rows.filter((x) =>
|
1100
|
+
$stbSelected.includes(x[idColumn])
|
1101
|
+
),
|
1102
|
+
selectedIds: $stbSelected,
|
1103
|
+
info: $stbData?.info,
|
1104
|
+
datasource: datasource || {},
|
1105
|
+
schema: $stbSchema,
|
1106
|
+
rowsLength: $stbData?.rows.length,
|
1107
|
+
pageNumber: $stbData?.pageNumber + 1,
|
1108
|
+
entitySingular,
|
1109
|
+
entityPlural,
|
1110
|
+
offset: 0,
|
1111
|
+
limit: 100,
|
1112
|
+
};
|
1113
|
+
|
1114
|
+
// Show Action Buttons Column
|
1115
|
+
$: showButtonColumnRight = rowMenu == "columnRight" && rowMenuItems?.length;
|
1116
|
+
$: showButtonColumnLeft = rowMenu == "columnLeft" && rowMenuItems?.length;
|
1117
|
+
|
1118
|
+
const createFetch = (datasource) => {
|
1119
|
+
stbState.init();
|
1120
|
+
return fetchData({
|
1121
|
+
API,
|
1122
|
+
datasource,
|
1123
|
+
options: {
|
1124
|
+
query,
|
1125
|
+
sortColumn,
|
1126
|
+
sortOrder,
|
1127
|
+
limit,
|
1128
|
+
paginate: true,
|
1129
|
+
},
|
1130
|
+
});
|
1131
|
+
};
|
1132
|
+
|
1133
|
+
const extendQuery = (defaultQuery, extensions) => {
|
1134
|
+
const extensionValues = Object.values(extensions || {});
|
1135
|
+
let extendedQuery = { ...defaultQuery };
|
1136
|
+
extensionValues.forEach((extension) => {
|
1137
|
+
Object.entries(extension || {}).forEach(([operator, fields]) => {
|
1138
|
+
extendedQuery[operator] =
|
1139
|
+
operator != "onEmptyFilter"
|
1140
|
+
? {
|
1141
|
+
...extendedQuery[operator],
|
1142
|
+
...fields,
|
1143
|
+
}
|
1144
|
+
: "none";
|
1145
|
+
});
|
1146
|
+
});
|
1147
|
+
return extendedQuery;
|
1148
|
+
};
|
1149
|
+
|
1150
|
+
const beautifyLabel = (label) => {
|
1151
|
+
if (!beautifyLabels || !label) return label;
|
1152
|
+
|
1153
|
+
let fields = label.split(".");
|
1154
|
+
fields.forEach((field, index) => {
|
1155
|
+
let words = field.split("_");
|
1156
|
+
words.forEach((word, index) => {
|
1157
|
+
if (word) words[index] = word[0]?.toUpperCase() + word?.slice(1);
|
1158
|
+
});
|
1159
|
+
fields[index] = words.join(" ");
|
1160
|
+
});
|
1161
|
+
return fields.join(" - ");
|
1162
|
+
};
|
1163
|
+
|
1164
|
+
// Expose Context
|
1165
|
+
setContext("stbScrollPos", stbScrollPos);
|
1166
|
+
setContext("stbScrollOffset", stbScrollOffset);
|
1167
|
+
setContext("stbHorizontalScrollPos", stbHorizontalScrollPos);
|
1168
|
+
setContext("stbHovered", stbHovered);
|
1169
|
+
setContext("stbSelected", stbSelected);
|
1170
|
+
setContext("stbEditing", stbEditing);
|
1171
|
+
setContext("stbState", stbState);
|
1172
|
+
setContext("stbSettings", stbSettings);
|
1173
|
+
setContext("stbSortColumn", stbSortColumn);
|
1174
|
+
setContext("stbSortOrder", stbSortOrder);
|
1175
|
+
setContext("stbMenuID", stbMenuID);
|
1176
|
+
setContext("stbMenuAnchor", stbMenuAnchor);
|
1177
|
+
setContext("stbAPI", tableAPI);
|
1178
|
+
setContext("stbVisibleRows", stbVisibleRows);
|
1179
|
+
$: setContext("stbRowMetadata", stbRowMetadata);
|
1180
|
+
$: setContext("stbData", stbData);
|
1181
|
+
$: setContext("stbSchema", stbSchema);
|
1182
|
+
|
1183
|
+
function toNumber(input) {
|
1184
|
+
const num = Number(input);
|
1185
|
+
return isNaN(num) ? null : num;
|
1186
|
+
}
|
1187
|
+
|
1188
|
+
onDestroy(() => {
|
1189
|
+
if (timer) clearInterval(timer);
|
1190
|
+
});
|
1191
|
+
|
1192
|
+
/**
|
1193
|
+
$: console.log("Table State : " + $stbState);
|
1194
|
+
$: console.log("Table Filters : ", stbColumnFilters);
|
1195
|
+
$: console.log("Table Settings : ", $stbSettings);
|
1196
|
+
*/
|
1197
|
+
|
1198
|
+
$: console.log($stbSchema);
|
1199
|
+
</script>
|
1200
|
+
|
1201
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
1202
|
+
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
1203
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
1204
|
+
<div
|
1205
|
+
class="super-table"
|
1206
|
+
class:quiet
|
1207
|
+
bind:this={viewport}
|
1208
|
+
bind:clientHeight
|
1209
|
+
style:font-size={sizingMap[size].rowFontSize}
|
1210
|
+
style:--super-table-devider-color={dividersStyles.color}
|
1211
|
+
style:--super-table-body-height={maxBodyHeight}
|
1212
|
+
style:--super-table-header-height={$stbSettings.appearance.headerHeight}
|
1213
|
+
style:--super-table-footer-height={$stbSettings.appearance.footerHeight}
|
1214
|
+
style:--super-table-horizontal-dividers={dividersStyles.horizontal}
|
1215
|
+
style:--super-table-vertical-dividers={dividersStyles.vertical}
|
1216
|
+
style:--super-table-cell-padding={sizingMap[size].cellPadding}
|
1217
|
+
style:--super-column-top-offset={$stbScrollOffset * -1}
|
1218
|
+
on:mouseenter={() => (highlighted = true)}
|
1219
|
+
on:mouseleave={() => {
|
1220
|
+
highlighted = false;
|
1221
|
+
$stbHovered = null;
|
1222
|
+
}}
|
1223
|
+
on:keydown={stbState.handleKeyboard}
|
1224
|
+
on:wheel={stbState.handleWheel}
|
1225
|
+
on:touchstart={(e) => stbState.handleTouch(e, "start")}
|
1226
|
+
on:touchmove={(e) => stbState.handleTouch(e, "move")}
|
1227
|
+
on:touchend={(e) => stbState.handleTouch(e, "end")}
|
1228
|
+
>
|
1229
|
+
<Provider {actions} data={dataContext} />
|
1230
|
+
{#key columnSizing}
|
1231
|
+
{#if $stbState != "Init"}
|
1232
|
+
{#if !isEmpty}
|
1233
|
+
<ControlSection>
|
1234
|
+
<SelectionColumn {hideSelectionColumn} />
|
1235
|
+
|
1236
|
+
{#if showButtonColumnLeft}
|
1237
|
+
<RowButtonsColumn {rowMenuItems} {menuItemsVisible} {rowMenu} />
|
1238
|
+
{/if}
|
1239
|
+
|
1240
|
+
{#if stickFirstColumn && $superColumns.length > 1}
|
1241
|
+
<SuperTableColumn
|
1242
|
+
sticky={true}
|
1243
|
+
scrollPos={$stbHorizontalScrollPos}
|
1244
|
+
columnOptions={{
|
1245
|
+
...$superColumns[0],
|
1246
|
+
...$commonColumnOptions,
|
1247
|
+
overflow,
|
1248
|
+
isFirst: true,
|
1249
|
+
isLast:
|
1250
|
+
$superColumns?.length == 1 &&
|
1251
|
+
!showButtonColumnRight &&
|
1252
|
+
canScroll,
|
1253
|
+
}}
|
1254
|
+
/>
|
1255
|
+
{/if}
|
1256
|
+
</ControlSection>
|
1257
|
+
{/if}
|
1258
|
+
|
1259
|
+
<ColumnsSection
|
1260
|
+
{stbSettings}
|
1261
|
+
{superColumns}
|
1262
|
+
{commonColumnOptions}
|
1263
|
+
{canScroll}
|
1264
|
+
bind:columnsViewport
|
1265
|
+
>
|
1266
|
+
<slot />
|
1267
|
+
</ColumnsSection>
|
1268
|
+
|
1269
|
+
{#if showButtonColumnRight && !isEmpty}
|
1270
|
+
<ControlSection>
|
1271
|
+
<RowButtonsColumn
|
1272
|
+
{rowMenuItems}
|
1273
|
+
{menuItemsVisible}
|
1274
|
+
{rowMenu}
|
1275
|
+
{canScroll}
|
1276
|
+
right={true}
|
1277
|
+
/>
|
1278
|
+
</ControlSection>
|
1279
|
+
{/if}
|
1280
|
+
|
1281
|
+
<ScrollbarsOverlay
|
1282
|
+
anchor={columnsViewport}
|
1283
|
+
clientHeight={maxBodyHeight}
|
1284
|
+
{scrollHeight}
|
1285
|
+
{highlighted}
|
1286
|
+
{isEmpty}
|
1287
|
+
bind:horizontalVisible
|
1288
|
+
on:positionChange={stbState.calculateRowBoundaries}
|
1289
|
+
/>
|
1290
|
+
|
1291
|
+
<EmptyResultSetOverlay
|
1292
|
+
{isEmpty}
|
1293
|
+
message={$stbSettings.data.emptyMessage}
|
1294
|
+
top={$superColumns?.length
|
1295
|
+
? $stbSettings.appearance.headerHeight + 16
|
1296
|
+
: 16}
|
1297
|
+
bottom={horizontalVisible ? 24 : 16}
|
1298
|
+
/>
|
1299
|
+
|
1300
|
+
<RowContextMenu {rowContextMenuItems} />
|
1301
|
+
|
1302
|
+
{#if $stbSettings.features.canInsert || $stbState == "Filtered"}
|
1303
|
+
<AddNewRowOverlay
|
1304
|
+
{stbState}
|
1305
|
+
{tableAPI}
|
1306
|
+
{highlighted}
|
1307
|
+
{tableActions}
|
1308
|
+
footer={$stbSettings.showFooter}
|
1309
|
+
/>
|
1310
|
+
{/if}
|
1311
|
+
|
1312
|
+
{#if $stbSettings.features.canSelect && selectedActions?.length}
|
1313
|
+
<SelectedActionsOverlay
|
1314
|
+
{stbSettings}
|
1315
|
+
{selectedActions}
|
1316
|
+
{stbSelected}
|
1317
|
+
{tableAPI}
|
1318
|
+
{stbState}
|
1319
|
+
{highlighted}
|
1320
|
+
{entitySingular}
|
1321
|
+
{entityPlural}
|
1322
|
+
/>
|
1323
|
+
{/if}
|
1324
|
+
|
1325
|
+
{#if $stbData.loading}
|
1326
|
+
<LoadingOverlay />
|
1327
|
+
{/if}
|
1328
|
+
{:else}
|
1329
|
+
<CellSkeleton />
|
1330
|
+
{/if}
|
1331
|
+
{/key}
|
1332
|
+
</div>
|