@budibase/frontend-core 2.11.44 → 2.12.0
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/package.json +4 -4
- package/src/components/grid/cells/DataCell.svelte +2 -0
- package/src/components/grid/cells/GridCell.svelte +5 -0
- package/src/components/grid/cells/HeaderCell.svelte +185 -39
- package/src/components/grid/layout/GridBody.svelte +3 -3
- package/src/components/grid/layout/GridRow.svelte +4 -2
- package/src/components/grid/layout/GridScrollWrapper.svelte +3 -4
- package/src/components/grid/layout/HeaderRow.svelte +2 -2
- package/src/components/grid/layout/NewColumnButton.svelte +4 -5
- package/src/components/grid/layout/NewRow.svelte +28 -26
- package/src/components/grid/overlays/KeyboardManager.svelte +1 -0
- package/src/components/grid/overlays/ResizeOverlay.svelte +2 -2
- package/src/components/grid/stores/datasource.js +11 -5
- package/src/components/grid/stores/datasources/nonPlus.js +5 -2
- package/src/components/grid/stores/datasources/table.js +5 -2
- package/src/components/grid/stores/datasources/viewV2.js +29 -23
- package/src/components/grid/stores/filter.js +67 -1
- package/src/components/grid/stores/rows.js +9 -3
- package/src/components/grid/stores/viewport.js +19 -39
- package/src/fetch/ViewV2Fetch.js +22 -3
- package/src/fetch/index.js +16 -4
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/frontend-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"description": "Budibase frontend core libraries used in builder and client",
|
|
5
5
|
"author": "Budibase",
|
|
6
6
|
"license": "MPL-2.0",
|
|
7
7
|
"svelte": "src/index.js",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@budibase/bbui": "2.
|
|
10
|
-
"@budibase/shared-core": "2.
|
|
9
|
+
"@budibase/bbui": "2.12.0",
|
|
10
|
+
"@budibase/shared-core": "2.12.0",
|
|
11
11
|
"dayjs": "^1.10.8",
|
|
12
12
|
"lodash": "^4.17.21",
|
|
13
13
|
"socket.io-client": "^4.6.1",
|
|
14
14
|
"svelte": "^3.46.2"
|
|
15
15
|
},
|
|
16
|
-
"gitHead": "
|
|
16
|
+
"gitHead": "b1ed21810000332da296d8fe556a166851626ae2"
|
|
17
17
|
}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
export let invertX = false
|
|
22
22
|
export let invertY = false
|
|
23
23
|
export let contentLines = 1
|
|
24
|
+
export let hidden = false
|
|
24
25
|
|
|
25
26
|
const emptyError = writable(null)
|
|
26
27
|
|
|
@@ -78,6 +79,7 @@
|
|
|
78
79
|
{focused}
|
|
79
80
|
{selectedUser}
|
|
80
81
|
{readonly}
|
|
82
|
+
{hidden}
|
|
81
83
|
error={$error}
|
|
82
84
|
on:click={() => focusedCellId.set(cellId)}
|
|
83
85
|
on:contextmenu={e => menu.actions.open(cellId, e)}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
export let defaultHeight = false
|
|
11
11
|
export let center = false
|
|
12
12
|
export let readonly = false
|
|
13
|
+
export let hidden = false
|
|
13
14
|
|
|
14
15
|
$: style = getStyle(width, selectedUser)
|
|
15
16
|
|
|
@@ -30,6 +31,7 @@
|
|
|
30
31
|
class:error
|
|
31
32
|
class:center
|
|
32
33
|
class:readonly
|
|
34
|
+
class:hidden
|
|
33
35
|
class:default-height={defaultHeight}
|
|
34
36
|
class:selected-other={selectedUser != null}
|
|
35
37
|
class:alt={rowIdx % 2 === 1}
|
|
@@ -81,6 +83,9 @@
|
|
|
81
83
|
.cell.center {
|
|
82
84
|
align-items: center;
|
|
83
85
|
}
|
|
86
|
+
.cell.hidden {
|
|
87
|
+
content-visibility: hidden;
|
|
88
|
+
}
|
|
84
89
|
|
|
85
90
|
/* Cell border */
|
|
86
91
|
.cell.focused:after,
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
import { Icon, Popover, Menu, MenuItem, clickOutside } from "@budibase/bbui"
|
|
5
5
|
import GridCell from "./GridCell.svelte"
|
|
6
6
|
import { getColumnIcon } from "../lib/utils"
|
|
7
|
+
import { debounce } from "../../../utils/utils"
|
|
8
|
+
import { FieldType, FormulaTypes } from "@budibase/types"
|
|
7
9
|
|
|
8
10
|
export let column
|
|
9
11
|
export let idx
|
|
@@ -15,7 +17,7 @@
|
|
|
15
17
|
isResizing,
|
|
16
18
|
rand,
|
|
17
19
|
sort,
|
|
18
|
-
|
|
20
|
+
visibleColumns,
|
|
19
21
|
dispatch,
|
|
20
22
|
subscribe,
|
|
21
23
|
config,
|
|
@@ -24,23 +26,69 @@
|
|
|
24
26
|
definition,
|
|
25
27
|
datasource,
|
|
26
28
|
schema,
|
|
29
|
+
focusedCellId,
|
|
30
|
+
filter,
|
|
31
|
+
inlineFilters,
|
|
27
32
|
} = getContext("grid")
|
|
28
33
|
|
|
34
|
+
const searchableTypes = [
|
|
35
|
+
FieldType.STRING,
|
|
36
|
+
FieldType.OPTIONS,
|
|
37
|
+
FieldType.NUMBER,
|
|
38
|
+
FieldType.BIGINT,
|
|
39
|
+
FieldType.ARRAY,
|
|
40
|
+
FieldType.LONGFORM,
|
|
41
|
+
]
|
|
42
|
+
|
|
29
43
|
let anchor
|
|
30
44
|
let open = false
|
|
31
45
|
let editIsOpen = false
|
|
32
46
|
let timeout
|
|
33
47
|
let popover
|
|
48
|
+
let searchValue
|
|
49
|
+
let input
|
|
34
50
|
|
|
35
51
|
$: sortedBy = column.name === $sort.column
|
|
36
52
|
$: canMoveLeft = orderable && idx > 0
|
|
37
|
-
$: canMoveRight = orderable && idx < $
|
|
38
|
-
$:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
$:
|
|
42
|
-
|
|
43
|
-
|
|
53
|
+
$: canMoveRight = orderable && idx < $visibleColumns.length - 1
|
|
54
|
+
$: sortingLabels = getSortingLabels(column.schema?.type)
|
|
55
|
+
$: searchable = isColumnSearchable(column)
|
|
56
|
+
$: resetSearchValue(column.name)
|
|
57
|
+
$: searching = searchValue != null
|
|
58
|
+
$: debouncedUpdateFilter(searchValue)
|
|
59
|
+
|
|
60
|
+
const getSortingLabels = type => {
|
|
61
|
+
switch (type) {
|
|
62
|
+
case FieldType.NUMBER:
|
|
63
|
+
case FieldType.BIGINT:
|
|
64
|
+
return {
|
|
65
|
+
ascending: "low-high",
|
|
66
|
+
descending: "high-low",
|
|
67
|
+
}
|
|
68
|
+
case FieldType.DATETIME:
|
|
69
|
+
return {
|
|
70
|
+
ascending: "old-new",
|
|
71
|
+
descending: "new-old",
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
return {
|
|
75
|
+
ascending: "A-Z",
|
|
76
|
+
descending: "Z-A",
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const resetSearchValue = name => {
|
|
82
|
+
searchValue = $inlineFilters?.find(x => x.id === `inline-${name}`)?.value
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const isColumnSearchable = col => {
|
|
86
|
+
const { type, formulaType } = col.schema
|
|
87
|
+
return (
|
|
88
|
+
searchableTypes.includes(type) ||
|
|
89
|
+
(type === FieldType.FORMULA && formulaType === FormulaTypes.STATIC)
|
|
90
|
+
)
|
|
91
|
+
}
|
|
44
92
|
|
|
45
93
|
const editColumn = async () => {
|
|
46
94
|
editIsOpen = true
|
|
@@ -141,12 +189,46 @@
|
|
|
141
189
|
})
|
|
142
190
|
}
|
|
143
191
|
|
|
192
|
+
const startSearching = async () => {
|
|
193
|
+
$focusedCellId = null
|
|
194
|
+
searchValue = ""
|
|
195
|
+
await tick()
|
|
196
|
+
input?.focus()
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const onInputKeyDown = e => {
|
|
200
|
+
if (e.key === "Enter") {
|
|
201
|
+
updateFilter()
|
|
202
|
+
} else if (e.key === "Escape") {
|
|
203
|
+
input?.blur()
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const stopSearching = () => {
|
|
208
|
+
searchValue = null
|
|
209
|
+
updateFilter()
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const onBlurInput = () => {
|
|
213
|
+
if (searchValue === "") {
|
|
214
|
+
searchValue = null
|
|
215
|
+
}
|
|
216
|
+
updateFilter()
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const updateFilter = () => {
|
|
220
|
+
filter.actions.addInlineFilter(column, searchValue)
|
|
221
|
+
}
|
|
222
|
+
const debouncedUpdateFilter = debounce(updateFilter, 250)
|
|
223
|
+
|
|
144
224
|
onMount(() => subscribe("close-edit-column", cancelEdit))
|
|
145
225
|
</script>
|
|
146
226
|
|
|
147
227
|
<div
|
|
148
228
|
class="header-cell"
|
|
149
229
|
class:open
|
|
230
|
+
class:searchable
|
|
231
|
+
class:searching
|
|
150
232
|
style="flex: 0 0 {column.width}px;"
|
|
151
233
|
bind:this={anchor}
|
|
152
234
|
class:disabled={$isReordering || $isResizing}
|
|
@@ -161,30 +243,49 @@
|
|
|
161
243
|
defaultHeight
|
|
162
244
|
center
|
|
163
245
|
>
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
246
|
+
{#if searching}
|
|
247
|
+
<input
|
|
248
|
+
bind:this={input}
|
|
249
|
+
type="text"
|
|
250
|
+
bind:value={searchValue}
|
|
251
|
+
on:blur={onBlurInput}
|
|
252
|
+
on:click={() => focusedCellId.set(null)}
|
|
253
|
+
on:keydown={onInputKeyDown}
|
|
254
|
+
data-grid-ignore
|
|
255
|
+
/>
|
|
256
|
+
{/if}
|
|
257
|
+
|
|
258
|
+
<div class="column-icon">
|
|
259
|
+
<Icon size="S" name={getColumnIcon(column)} />
|
|
260
|
+
</div>
|
|
261
|
+
<div class="search-icon" on:click={startSearching}>
|
|
262
|
+
<Icon hoverable size="S" name="Search" />
|
|
263
|
+
</div>
|
|
264
|
+
|
|
169
265
|
<div class="name">
|
|
170
266
|
{column.label}
|
|
171
267
|
</div>
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
268
|
+
|
|
269
|
+
{#if searching}
|
|
270
|
+
<div class="clear-icon" on:click={stopSearching}>
|
|
271
|
+
<Icon hoverable size="S" name="Close" />
|
|
272
|
+
</div>
|
|
273
|
+
{:else}
|
|
274
|
+
{#if sortedBy}
|
|
275
|
+
<div class="sort-indicator">
|
|
276
|
+
<Icon
|
|
277
|
+
hoverable
|
|
278
|
+
size="S"
|
|
279
|
+
name={$sort.order === "descending"
|
|
280
|
+
? "SortOrderDown"
|
|
281
|
+
: "SortOrderUp"}
|
|
282
|
+
/>
|
|
283
|
+
</div>
|
|
284
|
+
{/if}
|
|
285
|
+
<div class="more-icon" on:click={() => (open = true)}>
|
|
286
|
+
<Icon hoverable size="S" name="MoreVertical" />
|
|
179
287
|
</div>
|
|
180
288
|
{/if}
|
|
181
|
-
<div class="more" on:click={() => (open = true)}>
|
|
182
|
-
<Icon
|
|
183
|
-
size="S"
|
|
184
|
-
name="MoreVertical"
|
|
185
|
-
color="var(--spectrum-global-color-gray-600)"
|
|
186
|
-
/>
|
|
187
|
-
</div>
|
|
188
289
|
</GridCell>
|
|
189
290
|
</div>
|
|
190
291
|
|
|
@@ -235,7 +336,7 @@
|
|
|
235
336
|
disabled={!canBeSortColumn(column.schema.type) ||
|
|
236
337
|
(column.name === $sort.column && $sort.order === "ascending")}
|
|
237
338
|
>
|
|
238
|
-
Sort {
|
|
339
|
+
Sort {sortingLabels.ascending}
|
|
239
340
|
</MenuItem>
|
|
240
341
|
<MenuItem
|
|
241
342
|
icon="SortOrderDown"
|
|
@@ -243,7 +344,7 @@
|
|
|
243
344
|
disabled={!canBeSortColumn(column.schema.type) ||
|
|
244
345
|
(column.name === $sort.column && $sort.order === "descending")}
|
|
245
346
|
>
|
|
246
|
-
Sort {
|
|
347
|
+
Sort {sortingLabels.descending}
|
|
247
348
|
</MenuItem>
|
|
248
349
|
<MenuItem disabled={!canMoveLeft} icon="ChevronLeft" on:click={moveLeft}>
|
|
249
350
|
Move left
|
|
@@ -283,6 +384,29 @@
|
|
|
283
384
|
background: var(--grid-background-alt);
|
|
284
385
|
}
|
|
285
386
|
|
|
387
|
+
/* Icon colors */
|
|
388
|
+
.header-cell :global(.spectrum-Icon) {
|
|
389
|
+
color: var(--spectrum-global-color-gray-600);
|
|
390
|
+
}
|
|
391
|
+
.header-cell :global(.spectrum-Icon.hoverable:hover) {
|
|
392
|
+
color: var(--spectrum-global-color-gray-800) !important;
|
|
393
|
+
cursor: pointer;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/* Search icon */
|
|
397
|
+
.search-icon {
|
|
398
|
+
display: none;
|
|
399
|
+
}
|
|
400
|
+
.header-cell.searchable:not(.open):hover .search-icon,
|
|
401
|
+
.header-cell.searchable.searching .search-icon {
|
|
402
|
+
display: block;
|
|
403
|
+
}
|
|
404
|
+
.header-cell.searchable:not(.open):hover .column-icon,
|
|
405
|
+
.header-cell.searchable.searching .column-icon {
|
|
406
|
+
display: none;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/* Main center content */
|
|
286
410
|
.name {
|
|
287
411
|
flex: 1 1 auto;
|
|
288
412
|
width: 0;
|
|
@@ -290,23 +414,45 @@
|
|
|
290
414
|
text-overflow: ellipsis;
|
|
291
415
|
overflow: hidden;
|
|
292
416
|
}
|
|
417
|
+
.header-cell.searching .name {
|
|
418
|
+
opacity: 0;
|
|
419
|
+
pointer-events: none;
|
|
420
|
+
}
|
|
421
|
+
input {
|
|
422
|
+
display: none;
|
|
423
|
+
font-family: var(--font-sans);
|
|
424
|
+
outline: none;
|
|
425
|
+
border: 1px solid transparent;
|
|
426
|
+
background: transparent;
|
|
427
|
+
color: var(--spectrum-global-color-gray-800);
|
|
428
|
+
position: absolute;
|
|
429
|
+
top: 0;
|
|
430
|
+
left: 0;
|
|
431
|
+
width: 100%;
|
|
432
|
+
height: 100%;
|
|
433
|
+
padding: 0 30px;
|
|
434
|
+
border-radius: 2px;
|
|
435
|
+
}
|
|
436
|
+
input:focus {
|
|
437
|
+
border: 1px solid var(--accent-color);
|
|
438
|
+
}
|
|
439
|
+
input:not(:focus) {
|
|
440
|
+
background: var(--spectrum-global-color-gray-200);
|
|
441
|
+
}
|
|
442
|
+
.header-cell.searching input {
|
|
443
|
+
display: block;
|
|
444
|
+
}
|
|
293
445
|
|
|
294
|
-
|
|
446
|
+
/* Right icons */
|
|
447
|
+
.more-icon {
|
|
295
448
|
display: none;
|
|
296
449
|
padding: 4px;
|
|
297
450
|
margin: 0 -4px;
|
|
298
451
|
}
|
|
299
|
-
.header-cell.open .more,
|
|
300
|
-
.header-cell:hover .more {
|
|
452
|
+
.header-cell.open .more-icon,
|
|
453
|
+
.header-cell:hover .more-icon {
|
|
301
454
|
display: block;
|
|
302
455
|
}
|
|
303
|
-
.more:hover {
|
|
304
|
-
cursor: pointer;
|
|
305
|
-
}
|
|
306
|
-
.more:hover :global(.spectrum-Icon) {
|
|
307
|
-
color: var(--spectrum-global-color-gray-800) !important;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
456
|
.header-cell.open .sort-indicator,
|
|
311
457
|
.header-cell:hover .sort-indicator {
|
|
312
458
|
display: none;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
const {
|
|
8
8
|
bounds,
|
|
9
9
|
renderedRows,
|
|
10
|
-
|
|
10
|
+
visibleColumns,
|
|
11
11
|
rowVerticalInversionIndex,
|
|
12
12
|
hoveredRowId,
|
|
13
13
|
dispatch,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
let body
|
|
19
19
|
|
|
20
|
-
$:
|
|
20
|
+
$: columnsWidth = $visibleColumns.reduce(
|
|
21
21
|
(total, col) => (total += col.width),
|
|
22
22
|
0
|
|
23
23
|
)
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
<div
|
|
48
48
|
class="blank"
|
|
49
49
|
class:highlighted={$hoveredRowId === BlankRowID}
|
|
50
|
-
style="width:{
|
|
50
|
+
style="width:{columnsWidth}px"
|
|
51
51
|
on:mouseenter={$isDragging ? null : () => ($hoveredRowId = BlankRowID)}
|
|
52
52
|
on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)}
|
|
53
53
|
on:click={() => dispatch("add-row-inline")}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
focusedCellId,
|
|
11
11
|
reorder,
|
|
12
12
|
selectedRows,
|
|
13
|
-
|
|
13
|
+
visibleColumns,
|
|
14
14
|
hoveredRowId,
|
|
15
15
|
selectedCellMap,
|
|
16
16
|
focusedRow,
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
isDragging,
|
|
20
20
|
dispatch,
|
|
21
21
|
rows,
|
|
22
|
+
columnRenderMap,
|
|
22
23
|
} = getContext("grid")
|
|
23
24
|
|
|
24
25
|
$: rowSelected = !!$selectedRows[row._id]
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)}
|
|
35
36
|
on:click={() => dispatch("rowclick", rows.actions.cleanRow(row))}
|
|
36
37
|
>
|
|
37
|
-
{#each $
|
|
38
|
+
{#each $visibleColumns as column, columnIdx}
|
|
38
39
|
{@const cellId = `${row._id}-${column.name}`}
|
|
39
40
|
<DataCell
|
|
40
41
|
{cellId}
|
|
@@ -51,6 +52,7 @@
|
|
|
51
52
|
selectedUser={$selectedCellMap[cellId]}
|
|
52
53
|
width={column.width}
|
|
53
54
|
contentLines={$contentLines}
|
|
55
|
+
hidden={!$columnRenderMap[column.name]}
|
|
54
56
|
/>
|
|
55
57
|
{/each}
|
|
56
58
|
</div>
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
maxScrollLeft,
|
|
12
12
|
bounds,
|
|
13
13
|
hoveredRowId,
|
|
14
|
-
hiddenColumnsWidth,
|
|
15
14
|
menu,
|
|
16
15
|
} = getContext("grid")
|
|
17
16
|
|
|
@@ -23,10 +22,10 @@
|
|
|
23
22
|
let initialTouchX
|
|
24
23
|
let initialTouchY
|
|
25
24
|
|
|
26
|
-
$: style = generateStyle($scroll, $rowHeight
|
|
25
|
+
$: style = generateStyle($scroll, $rowHeight)
|
|
27
26
|
|
|
28
|
-
const generateStyle = (scroll, rowHeight
|
|
29
|
-
const offsetX = scrollHorizontally ? -1 * scroll.left
|
|
27
|
+
const generateStyle = (scroll, rowHeight) => {
|
|
28
|
+
const offsetX = scrollHorizontally ? -1 * scroll.left : 0
|
|
30
29
|
const offsetY = scrollVertically ? -1 * (scroll.top % rowHeight) : 0
|
|
31
30
|
return `transform: translate3d(${offsetX}px, ${offsetY}px, 0);`
|
|
32
31
|
}
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
import HeaderCell from "../cells/HeaderCell.svelte"
|
|
6
6
|
import { TempTooltip, TooltipType } from "@budibase/bbui"
|
|
7
7
|
|
|
8
|
-
const {
|
|
8
|
+
const { visibleColumns, config, hasNonAutoColumn, datasource, loading } =
|
|
9
9
|
getContext("grid")
|
|
10
10
|
</script>
|
|
11
11
|
|
|
12
12
|
<div class="header">
|
|
13
13
|
<GridScrollWrapper scrollHorizontally>
|
|
14
14
|
<div class="row">
|
|
15
|
-
{#each $
|
|
15
|
+
{#each $visibleColumns as column, idx}
|
|
16
16
|
<HeaderCell {column} {idx}>
|
|
17
17
|
<slot name="edit-column" />
|
|
18
18
|
</HeaderCell>
|
|
@@ -2,17 +2,16 @@
|
|
|
2
2
|
import { getContext, onMount } from "svelte"
|
|
3
3
|
import { Icon, Popover, clickOutside } from "@budibase/bbui"
|
|
4
4
|
|
|
5
|
-
const {
|
|
6
|
-
getContext("grid")
|
|
5
|
+
const { visibleColumns, scroll, width, subscribe } = getContext("grid")
|
|
7
6
|
|
|
8
7
|
let anchor
|
|
9
8
|
let open = false
|
|
10
9
|
|
|
11
|
-
$: columnsWidth = $
|
|
10
|
+
$: columnsWidth = $visibleColumns.reduce(
|
|
12
11
|
(total, col) => (total += col.width),
|
|
13
12
|
0
|
|
14
13
|
)
|
|
15
|
-
$: end =
|
|
14
|
+
$: end = columnsWidth - 1 - $scroll.left
|
|
16
15
|
$: left = Math.min($width - 40, end)
|
|
17
16
|
|
|
18
17
|
const close = () => {
|
|
@@ -34,7 +33,7 @@
|
|
|
34
33
|
<Popover
|
|
35
34
|
bind:open
|
|
36
35
|
{anchor}
|
|
37
|
-
align={$
|
|
36
|
+
align={$visibleColumns.length ? "right" : "left"}
|
|
38
37
|
offset={0}
|
|
39
38
|
popoverTarget={document.getElementById(`add-column-button`)}
|
|
40
39
|
customZindex={100}
|
|
@@ -20,15 +20,18 @@
|
|
|
20
20
|
datasource,
|
|
21
21
|
subscribe,
|
|
22
22
|
renderedRows,
|
|
23
|
-
|
|
23
|
+
visibleColumns,
|
|
24
24
|
rowHeight,
|
|
25
25
|
hasNextPage,
|
|
26
26
|
maxScrollTop,
|
|
27
27
|
rowVerticalInversionIndex,
|
|
28
28
|
columnHorizontalInversionIndex,
|
|
29
29
|
selectedRows,
|
|
30
|
-
|
|
30
|
+
loaded,
|
|
31
|
+
refreshing,
|
|
31
32
|
config,
|
|
33
|
+
filter,
|
|
34
|
+
columnRenderMap,
|
|
32
35
|
} = getContext("grid")
|
|
33
36
|
|
|
34
37
|
let visible = false
|
|
@@ -36,7 +39,7 @@
|
|
|
36
39
|
let newRow
|
|
37
40
|
let offset = 0
|
|
38
41
|
|
|
39
|
-
$: firstColumn = $stickyColumn || $
|
|
42
|
+
$: firstColumn = $stickyColumn || $visibleColumns[0]
|
|
40
43
|
$: width = GutterWidth + ($stickyColumn?.width || 0)
|
|
41
44
|
$: $datasource, (visible = false)
|
|
42
45
|
$: invertY = shouldInvertY(offset, $rowVerticalInversionIndex, $renderedRows)
|
|
@@ -153,7 +156,7 @@
|
|
|
153
156
|
<!-- New row FAB -->
|
|
154
157
|
<TempTooltip
|
|
155
158
|
text="Click here to create your first row"
|
|
156
|
-
condition={hasNoRows && !$
|
|
159
|
+
condition={hasNoRows && $loaded && !$filter?.length && !$refreshing}
|
|
157
160
|
type={TooltipType.Info}
|
|
158
161
|
>
|
|
159
162
|
{#if !visible && !selectedRowCount && $config.canAddRows}
|
|
@@ -209,29 +212,28 @@
|
|
|
209
212
|
<div class="normal-columns" transition:fade|local={{ duration: 130 }}>
|
|
210
213
|
<GridScrollWrapper scrollHorizontally attachHandlers>
|
|
211
214
|
<div class="row">
|
|
212
|
-
{#each $
|
|
215
|
+
{#each $visibleColumns as column, columnIdx}
|
|
213
216
|
{@const cellId = `new-${column.name}`}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
{/key}
|
|
217
|
+
<DataCell
|
|
218
|
+
{cellId}
|
|
219
|
+
{column}
|
|
220
|
+
{updateValue}
|
|
221
|
+
rowFocused
|
|
222
|
+
row={newRow}
|
|
223
|
+
focused={$focusedCellId === cellId}
|
|
224
|
+
width={column.width}
|
|
225
|
+
topRow={offset === 0}
|
|
226
|
+
invertX={columnIdx >= $columnHorizontalInversionIndex}
|
|
227
|
+
{invertY}
|
|
228
|
+
hidden={!$columnRenderMap[column.name]}
|
|
229
|
+
>
|
|
230
|
+
{#if column?.schema?.autocolumn}
|
|
231
|
+
<div class="readonly-overlay">Can't edit auto column</div>
|
|
232
|
+
{/if}
|
|
233
|
+
{#if isAdding}
|
|
234
|
+
<div in:fade={{ duration: 130 }} class="loading-overlay" />
|
|
235
|
+
{/if}
|
|
236
|
+
</DataCell>
|
|
235
237
|
{/each}
|
|
236
238
|
</div>
|
|
237
239
|
</GridScrollWrapper>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { getContext } from "svelte"
|
|
3
3
|
import { GutterWidth } from "../lib/constants"
|
|
4
4
|
|
|
5
|
-
const { resize,
|
|
5
|
+
const { resize, visibleColumns, stickyColumn, isReordering, scrollLeft } =
|
|
6
6
|
getContext("grid")
|
|
7
7
|
|
|
8
8
|
$: offset = GutterWidth + ($stickyColumn?.width || 0)
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<div class="resize-indicator" />
|
|
27
27
|
</div>
|
|
28
28
|
{/if}
|
|
29
|
-
{#each $
|
|
29
|
+
{#each $visibleColumns as column}
|
|
30
30
|
<div
|
|
31
31
|
class="resize-slider"
|
|
32
32
|
class:visible={activeColumn === column.name}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { derived, get
|
|
2
|
-
import { getDatasourceDefinition } from "../../../fetch"
|
|
1
|
+
import { derived, get } from "svelte/store"
|
|
2
|
+
import { getDatasourceDefinition, getDatasourceSchema } from "../../../fetch"
|
|
3
|
+
import { memo } from "../../../utils"
|
|
3
4
|
|
|
4
5
|
export const createStores = () => {
|
|
5
|
-
const definition =
|
|
6
|
+
const definition = memo(null)
|
|
6
7
|
|
|
7
8
|
return {
|
|
8
9
|
definition,
|
|
@@ -10,10 +11,15 @@ export const createStores = () => {
|
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export const deriveStores = context => {
|
|
13
|
-
const { definition, schemaOverrides, columnWhitelist, datasource } =
|
|
14
|
+
const { API, definition, schemaOverrides, columnWhitelist, datasource } =
|
|
15
|
+
context
|
|
14
16
|
|
|
15
17
|
const schema = derived(definition, $definition => {
|
|
16
|
-
let schema =
|
|
18
|
+
let schema = getDatasourceSchema({
|
|
19
|
+
API,
|
|
20
|
+
datasource: get(datasource),
|
|
21
|
+
definition: $definition,
|
|
22
|
+
})
|
|
17
23
|
if (!schema) {
|
|
18
24
|
return null
|
|
19
25
|
}
|
|
@@ -66,6 +66,8 @@ export const initialise = context => {
|
|
|
66
66
|
datasource,
|
|
67
67
|
sort,
|
|
68
68
|
filter,
|
|
69
|
+
inlineFilters,
|
|
70
|
+
allFilters,
|
|
69
71
|
nonPlus,
|
|
70
72
|
initialFilter,
|
|
71
73
|
initialSortColumn,
|
|
@@ -87,6 +89,7 @@ export const initialise = context => {
|
|
|
87
89
|
|
|
88
90
|
// Wipe state
|
|
89
91
|
filter.set(get(initialFilter))
|
|
92
|
+
inlineFilters.set([])
|
|
90
93
|
sort.set({
|
|
91
94
|
column: get(initialSortColumn),
|
|
92
95
|
order: get(initialSortOrder) || "ascending",
|
|
@@ -94,14 +97,14 @@ export const initialise = context => {
|
|
|
94
97
|
|
|
95
98
|
// Update fetch when filter changes
|
|
96
99
|
unsubscribers.push(
|
|
97
|
-
|
|
100
|
+
allFilters.subscribe($allFilters => {
|
|
98
101
|
// Ensure we're updating the correct fetch
|
|
99
102
|
const $fetch = get(fetch)
|
|
100
103
|
if (!isSameDatasource($fetch?.options?.datasource, $datasource)) {
|
|
101
104
|
return
|
|
102
105
|
}
|
|
103
106
|
$fetch.update({
|
|
104
|
-
filter: $
|
|
107
|
+
filter: $allFilters,
|
|
105
108
|
})
|
|
106
109
|
})
|
|
107
110
|
)
|
|
@@ -71,6 +71,8 @@ export const initialise = context => {
|
|
|
71
71
|
datasource,
|
|
72
72
|
fetch,
|
|
73
73
|
filter,
|
|
74
|
+
inlineFilters,
|
|
75
|
+
allFilters,
|
|
74
76
|
sort,
|
|
75
77
|
table,
|
|
76
78
|
initialFilter,
|
|
@@ -93,6 +95,7 @@ export const initialise = context => {
|
|
|
93
95
|
|
|
94
96
|
// Wipe state
|
|
95
97
|
filter.set(get(initialFilter))
|
|
98
|
+
inlineFilters.set([])
|
|
96
99
|
sort.set({
|
|
97
100
|
column: get(initialSortColumn),
|
|
98
101
|
order: get(initialSortOrder) || "ascending",
|
|
@@ -100,14 +103,14 @@ export const initialise = context => {
|
|
|
100
103
|
|
|
101
104
|
// Update fetch when filter changes
|
|
102
105
|
unsubscribers.push(
|
|
103
|
-
|
|
106
|
+
allFilters.subscribe($allFilters => {
|
|
104
107
|
// Ensure we're updating the correct fetch
|
|
105
108
|
const $fetch = get(fetch)
|
|
106
109
|
if ($fetch?.options?.datasource?.tableId !== $datasource.tableId) {
|
|
107
110
|
return
|
|
108
111
|
}
|
|
109
112
|
$fetch.update({
|
|
110
|
-
filter: $
|
|
113
|
+
filter: $allFilters,
|
|
111
114
|
})
|
|
112
115
|
})
|
|
113
116
|
)
|
|
@@ -73,6 +73,8 @@ export const initialise = context => {
|
|
|
73
73
|
sort,
|
|
74
74
|
rows,
|
|
75
75
|
filter,
|
|
76
|
+
inlineFilters,
|
|
77
|
+
allFilters,
|
|
76
78
|
subscribe,
|
|
77
79
|
viewV2,
|
|
78
80
|
initialFilter,
|
|
@@ -97,6 +99,7 @@ export const initialise = context => {
|
|
|
97
99
|
|
|
98
100
|
// Reset state for new view
|
|
99
101
|
filter.set(get(initialFilter))
|
|
102
|
+
inlineFilters.set([])
|
|
100
103
|
sort.set({
|
|
101
104
|
column: get(initialSortColumn),
|
|
102
105
|
order: get(initialSortOrder) || "ascending",
|
|
@@ -143,21 +146,19 @@ export const initialise = context => {
|
|
|
143
146
|
order: $sort.order || "ascending",
|
|
144
147
|
},
|
|
145
148
|
})
|
|
146
|
-
await rows.actions.refreshData()
|
|
147
149
|
}
|
|
148
150
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
$fetch.update({
|
|
157
|
-
sortOrder: $sort.order || "ascending",
|
|
158
|
-
sortColumn: $sort.column,
|
|
159
|
-
})
|
|
151
|
+
|
|
152
|
+
// Also update the fetch to ensure the new sort is respected.
|
|
153
|
+
// Ensure we're updating the correct fetch.
|
|
154
|
+
const $fetch = get(fetch)
|
|
155
|
+
if ($fetch?.options?.datasource?.tableId !== $datasource.tableId) {
|
|
156
|
+
return
|
|
160
157
|
}
|
|
158
|
+
$fetch.update({
|
|
159
|
+
sortOrder: $sort.order,
|
|
160
|
+
sortColumn: $sort.column,
|
|
161
|
+
})
|
|
161
162
|
})
|
|
162
163
|
)
|
|
163
164
|
|
|
@@ -176,20 +177,25 @@ export const initialise = context => {
|
|
|
176
177
|
...$view,
|
|
177
178
|
query: $filter,
|
|
178
179
|
})
|
|
179
|
-
await rows.actions.refreshData()
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
182
|
+
})
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
// Keep fetch up to date with filters.
|
|
186
|
+
// If we're able to save filters against the view then we only need to apply
|
|
187
|
+
// inline filters to the fetch, as saved filters are applied server side.
|
|
188
|
+
// If we can't save filters, then all filters must be applied to the fetch.
|
|
189
|
+
unsubscribers.push(
|
|
190
|
+
allFilters.subscribe($allFilters => {
|
|
191
|
+
// Ensure we're updating the correct fetch
|
|
192
|
+
const $fetch = get(fetch)
|
|
193
|
+
if ($fetch?.options?.datasource?.tableId !== $datasource.tableId) {
|
|
194
|
+
return
|
|
192
195
|
}
|
|
196
|
+
$fetch.update({
|
|
197
|
+
filter: $allFilters,
|
|
198
|
+
})
|
|
193
199
|
})
|
|
194
200
|
)
|
|
195
201
|
|
|
@@ -1,13 +1,79 @@
|
|
|
1
|
-
import { writable, get } from "svelte/store"
|
|
1
|
+
import { writable, get, derived } from "svelte/store"
|
|
2
|
+
import { FieldType } from "@budibase/types"
|
|
2
3
|
|
|
3
4
|
export const createStores = context => {
|
|
4
5
|
const { props } = context
|
|
5
6
|
|
|
6
7
|
// Initialise to default props
|
|
7
8
|
const filter = writable(get(props).initialFilter)
|
|
9
|
+
const inlineFilters = writable([])
|
|
8
10
|
|
|
9
11
|
return {
|
|
10
12
|
filter,
|
|
13
|
+
inlineFilters,
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const deriveStores = context => {
|
|
18
|
+
const { filter, inlineFilters } = context
|
|
19
|
+
|
|
20
|
+
const allFilters = derived(
|
|
21
|
+
[filter, inlineFilters],
|
|
22
|
+
([$filter, $inlineFilters]) => {
|
|
23
|
+
return [...($filter || []), ...$inlineFilters]
|
|
24
|
+
}
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
allFilters,
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const createActions = context => {
|
|
33
|
+
const { filter, inlineFilters } = context
|
|
34
|
+
|
|
35
|
+
const addInlineFilter = (column, value) => {
|
|
36
|
+
const filterId = `inline-${column.name}`
|
|
37
|
+
const type = column.schema.type
|
|
38
|
+
let inlineFilter = {
|
|
39
|
+
field: column.name,
|
|
40
|
+
id: filterId,
|
|
41
|
+
operator: "string",
|
|
42
|
+
valueType: "value",
|
|
43
|
+
type,
|
|
44
|
+
value,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Add overrides specific so the certain column type
|
|
48
|
+
if (type === FieldType.NUMBER) {
|
|
49
|
+
inlineFilter.value = parseFloat(value)
|
|
50
|
+
inlineFilter.operator = "equal"
|
|
51
|
+
} else if (type === FieldType.BIGINT) {
|
|
52
|
+
inlineFilter.operator = "equal"
|
|
53
|
+
} else if (type === FieldType.ARRAY) {
|
|
54
|
+
inlineFilter.operator = "contains"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Add this filter
|
|
58
|
+
inlineFilters.update($inlineFilters => {
|
|
59
|
+
// Remove any existing inline filter for this column
|
|
60
|
+
$inlineFilters = $inlineFilters?.filter(x => x.id !== filterId)
|
|
61
|
+
|
|
62
|
+
// Add new one if a value exists
|
|
63
|
+
if (value) {
|
|
64
|
+
$inlineFilters.push(inlineFilter)
|
|
65
|
+
}
|
|
66
|
+
return $inlineFilters
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
filter: {
|
|
72
|
+
...filter,
|
|
73
|
+
actions: {
|
|
74
|
+
addInlineFilter,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
11
77
|
}
|
|
12
78
|
}
|
|
13
79
|
|
|
@@ -8,6 +8,7 @@ export const createStores = () => {
|
|
|
8
8
|
const rows = writable([])
|
|
9
9
|
const loading = writable(false)
|
|
10
10
|
const loaded = writable(false)
|
|
11
|
+
const refreshing = writable(false)
|
|
11
12
|
const rowChangeCache = writable({})
|
|
12
13
|
const inProgressChanges = writable({})
|
|
13
14
|
const hasNextPage = writable(false)
|
|
@@ -53,6 +54,7 @@ export const createStores = () => {
|
|
|
53
54
|
fetch,
|
|
54
55
|
rowLookupMap,
|
|
55
56
|
loaded,
|
|
57
|
+
refreshing,
|
|
56
58
|
loading,
|
|
57
59
|
rowChangeCache,
|
|
58
60
|
inProgressChanges,
|
|
@@ -66,7 +68,7 @@ export const createActions = context => {
|
|
|
66
68
|
rows,
|
|
67
69
|
rowLookupMap,
|
|
68
70
|
definition,
|
|
69
|
-
|
|
71
|
+
allFilters,
|
|
70
72
|
loading,
|
|
71
73
|
sort,
|
|
72
74
|
datasource,
|
|
@@ -82,6 +84,7 @@ export const createActions = context => {
|
|
|
82
84
|
notifications,
|
|
83
85
|
fetch,
|
|
84
86
|
isDatasourcePlus,
|
|
87
|
+
refreshing,
|
|
85
88
|
} = context
|
|
86
89
|
const instanceLoaded = writable(false)
|
|
87
90
|
|
|
@@ -108,7 +111,7 @@ export const createActions = context => {
|
|
|
108
111
|
// Tick to allow other reactive logic to update stores when datasource changes
|
|
109
112
|
// before proceeding. This allows us to wipe filters etc if needed.
|
|
110
113
|
await tick()
|
|
111
|
-
const $
|
|
114
|
+
const $allFilters = get(allFilters)
|
|
112
115
|
const $sort = get(sort)
|
|
113
116
|
|
|
114
117
|
// Determine how many rows to fetch per page
|
|
@@ -120,7 +123,7 @@ export const createActions = context => {
|
|
|
120
123
|
API,
|
|
121
124
|
datasource: $datasource,
|
|
122
125
|
options: {
|
|
123
|
-
filter: $
|
|
126
|
+
filter: $allFilters,
|
|
124
127
|
sortColumn: $sort.column,
|
|
125
128
|
sortOrder: $sort.order,
|
|
126
129
|
limit,
|
|
@@ -176,6 +179,9 @@ export const createActions = context => {
|
|
|
176
179
|
// Notify that we're loaded
|
|
177
180
|
loading.set(false)
|
|
178
181
|
}
|
|
182
|
+
|
|
183
|
+
// Update refreshing state
|
|
184
|
+
refreshing.set($fetch.loading)
|
|
179
185
|
})
|
|
180
186
|
|
|
181
187
|
fetch.set(newFetch)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { derived
|
|
1
|
+
import { derived } from "svelte/store"
|
|
2
2
|
import {
|
|
3
3
|
MaxCellRenderHeight,
|
|
4
4
|
MaxCellRenderWidthOverflow,
|
|
@@ -50,12 +50,11 @@ export const deriveStores = context => {
|
|
|
50
50
|
const interval = MinColumnWidth
|
|
51
51
|
return Math.round($scrollLeft / interval) * interval
|
|
52
52
|
})
|
|
53
|
-
const
|
|
53
|
+
const columnRenderMap = derived(
|
|
54
54
|
[visibleColumns, scrollLeftRounded, width],
|
|
55
|
-
([$visibleColumns, $scrollLeft, $width]
|
|
55
|
+
([$visibleColumns, $scrollLeft, $width]) => {
|
|
56
56
|
if (!$visibleColumns.length) {
|
|
57
|
-
|
|
58
|
-
return
|
|
57
|
+
return {}
|
|
59
58
|
}
|
|
60
59
|
let startColIdx = 0
|
|
61
60
|
let rightEdge = $visibleColumns[0].width
|
|
@@ -75,34 +74,16 @@ export const deriveStores = context => {
|
|
|
75
74
|
leftEdge += $visibleColumns[endColIdx].width
|
|
76
75
|
endColIdx++
|
|
77
76
|
}
|
|
78
|
-
// Render an additional column on either side to account for
|
|
79
|
-
// debounce column updates based on scroll position
|
|
80
|
-
const next = $visibleColumns.slice(
|
|
81
|
-
Math.max(0, startColIdx - 1),
|
|
82
|
-
endColIdx + 1
|
|
83
|
-
)
|
|
84
|
-
const current = get(renderedColumns)
|
|
85
|
-
if (JSON.stringify(next) !== JSON.stringify(current)) {
|
|
86
|
-
set(next)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
)
|
|
90
77
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
col =>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
width += $visibleColumns[i].width
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return width
|
|
104
|
-
},
|
|
105
|
-
0
|
|
78
|
+
// Only update the store if different
|
|
79
|
+
let next = {}
|
|
80
|
+
$visibleColumns
|
|
81
|
+
.slice(Math.max(0, startColIdx), endColIdx)
|
|
82
|
+
.forEach(col => {
|
|
83
|
+
next[col.name] = true
|
|
84
|
+
})
|
|
85
|
+
return next
|
|
86
|
+
}
|
|
106
87
|
)
|
|
107
88
|
|
|
108
89
|
// Determine the row index at which we should start vertically inverting cell
|
|
@@ -130,12 +111,12 @@ export const deriveStores = context => {
|
|
|
130
111
|
// Determine the column index at which we should start horizontally inverting
|
|
131
112
|
// cell dropdowns
|
|
132
113
|
const columnHorizontalInversionIndex = derived(
|
|
133
|
-
[
|
|
134
|
-
([$
|
|
114
|
+
[visibleColumns, scrollLeft, width],
|
|
115
|
+
([$visibleColumns, $scrollLeft, $width]) => {
|
|
135
116
|
const cutoff = $width + $scrollLeft - ScrollBarSize * 3
|
|
136
|
-
let inversionIdx = $
|
|
137
|
-
for (let i = $
|
|
138
|
-
const rightEdge = $
|
|
117
|
+
let inversionIdx = $visibleColumns.length
|
|
118
|
+
for (let i = $visibleColumns.length - 1; i >= 0; i--, inversionIdx--) {
|
|
119
|
+
const rightEdge = $visibleColumns[i].left + $visibleColumns[i].width
|
|
139
120
|
if (rightEdge + MaxCellRenderWidthOverflow <= cutoff) {
|
|
140
121
|
break
|
|
141
122
|
}
|
|
@@ -148,8 +129,7 @@ export const deriveStores = context => {
|
|
|
148
129
|
scrolledRowCount,
|
|
149
130
|
visualRowCapacity,
|
|
150
131
|
renderedRows,
|
|
151
|
-
|
|
152
|
-
hiddenColumnsWidth,
|
|
132
|
+
columnRenderMap,
|
|
153
133
|
rowVerticalInversionIndex,
|
|
154
134
|
columnHorizontalInversionIndex,
|
|
155
135
|
}
|
package/src/fetch/ViewV2Fetch.js
CHANGED
|
@@ -35,9 +35,28 @@ export default class ViewV2Fetch extends DataFetch {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
async getData() {
|
|
38
|
-
const {
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
const {
|
|
39
|
+
datasource,
|
|
40
|
+
limit,
|
|
41
|
+
sortColumn,
|
|
42
|
+
sortOrder,
|
|
43
|
+
sortType,
|
|
44
|
+
paginate,
|
|
45
|
+
filter,
|
|
46
|
+
} = this.options
|
|
47
|
+
const { cursor, query, definition } = get(this.store)
|
|
48
|
+
|
|
49
|
+
// If sort/filter params are not defined, update options to store the
|
|
50
|
+
// params built in to this view. This ensures that we can accurately
|
|
51
|
+
// compare old and new params and skip a redundant API call.
|
|
52
|
+
if (!sortColumn && definition.sort?.field) {
|
|
53
|
+
this.options.sortColumn = definition.sort.field
|
|
54
|
+
this.options.sortOrder = definition.sort.order
|
|
55
|
+
}
|
|
56
|
+
if (!filter?.length && definition.query?.length) {
|
|
57
|
+
this.options.filter = definition.query
|
|
58
|
+
}
|
|
59
|
+
|
|
41
60
|
try {
|
|
42
61
|
const res = await this.API.viewV2.fetch({
|
|
43
62
|
viewId: datasource.id,
|
package/src/fetch/index.js
CHANGED
|
@@ -32,12 +32,24 @@ export const fetchData = ({ API, datasource, options }) => {
|
|
|
32
32
|
return new Fetch({ API, datasource, ...options })
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
//
|
|
36
|
-
|
|
35
|
+
// Creates an empty fetch instance with no datasource configured, so no data
|
|
36
|
+
// will initially be loaded
|
|
37
|
+
const createEmptyFetchInstance = ({ API, datasource }) => {
|
|
37
38
|
const handler = DataFetchMap[datasource?.type]
|
|
38
39
|
if (!handler) {
|
|
39
40
|
return null
|
|
40
41
|
}
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
return new handler({ API })
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Fetches the definition of any type of datasource
|
|
46
|
+
export const getDatasourceDefinition = async ({ API, datasource }) => {
|
|
47
|
+
const instance = createEmptyFetchInstance({ API, datasource })
|
|
48
|
+
return await instance?.getDefinition(datasource)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Fetches the schema of any type of datasource
|
|
52
|
+
export const getDatasourceSchema = ({ API, datasource, definition }) => {
|
|
53
|
+
const instance = createEmptyFetchInstance({ API, datasource })
|
|
54
|
+
return instance?.getSchema(datasource, definition)
|
|
43
55
|
}
|