@budibase/frontend-core 2.11.39 → 2.11.40
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 +1 -1
- package/src/components/grid/cells/HeaderCell.svelte +9 -6
- package/src/components/grid/controls/SortButton.svelte +3 -1
- package/src/components/grid/layout/Grid.svelte +8 -8
- package/src/components/grid/layout/GridRow.svelte +2 -1
- package/src/components/grid/layout/NewRow.svelte +5 -3
- package/src/components/grid/layout/StickyColumn.svelte +1 -1
- package/src/components/grid/lib/utils.js +1 -1
- package/src/components/grid/overlays/MenuOverlay.svelte +2 -1
- package/src/components/grid/stores/columns.js +34 -19
- package/src/components/grid/stores/config.js +12 -1
- package/src/components/grid/stores/datasource.js +63 -16
- package/src/components/grid/stores/datasources/nonPlus.js +124 -0
- package/src/components/grid/stores/{table.js → datasources/table.js} +7 -6
- package/src/components/grid/stores/{viewV2.js → datasources/viewV2.js} +7 -15
- package/src/components/grid/stores/index.js +4 -2
- package/src/components/grid/stores/rows.js +44 -12
- package/src/components/grid/stores/sort.js +6 -9
- package/src/fetch/CustomFetch.js +145 -0
- package/src/fetch/{fetchData.js → index.js} +13 -0
- package/src/index.js +1 -1
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/frontend-core",
|
|
3
|
-
"version": "2.11.
|
|
3
|
+
"version": "2.11.40",
|
|
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.11.
|
|
10
|
-
"@budibase/shared-core": "2.11.
|
|
9
|
+
"@budibase/bbui": "2.11.40",
|
|
10
|
+
"@budibase/shared-core": "2.11.40",
|
|
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": "386e2b81ef2ca25ee891f07be477723987dd9306"
|
|
17
17
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { getContext, onMount, tick } from "svelte"
|
|
3
|
-
import { canBeDisplayColumn } from "@budibase/shared-core"
|
|
3
|
+
import { canBeDisplayColumn, canBeSortColumn } from "@budibase/shared-core"
|
|
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"
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
columns,
|
|
24
24
|
definition,
|
|
25
25
|
datasource,
|
|
26
|
+
schema,
|
|
26
27
|
} = getContext("grid")
|
|
27
28
|
|
|
28
29
|
let anchor
|
|
@@ -119,16 +120,16 @@
|
|
|
119
120
|
// Generate new name
|
|
120
121
|
let newName = `${column.name} copy`
|
|
121
122
|
let attempts = 2
|
|
122
|
-
while ($
|
|
123
|
+
while ($schema[newName]) {
|
|
123
124
|
newName = `${column.name} copy ${attempts++}`
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
// Save schema with new column
|
|
127
|
-
const existingColumnDefinition = $
|
|
128
|
+
const existingColumnDefinition = $schema[column.name]
|
|
128
129
|
await datasource.actions.saveDefinition({
|
|
129
130
|
...$definition,
|
|
130
131
|
schema: {
|
|
131
|
-
...$
|
|
132
|
+
...$schema,
|
|
132
133
|
[newName]: {
|
|
133
134
|
...existingColumnDefinition,
|
|
134
135
|
name: newName,
|
|
@@ -231,14 +232,16 @@
|
|
|
231
232
|
<MenuItem
|
|
232
233
|
icon="SortOrderUp"
|
|
233
234
|
on:click={sortAscending}
|
|
234
|
-
disabled={column.
|
|
235
|
+
disabled={!canBeSortColumn(column.schema.type) ||
|
|
236
|
+
(column.name === $sort.column && $sort.order === "ascending")}
|
|
235
237
|
>
|
|
236
238
|
Sort {ascendingLabel}
|
|
237
239
|
</MenuItem>
|
|
238
240
|
<MenuItem
|
|
239
241
|
icon="SortOrderDown"
|
|
240
242
|
on:click={sortDescending}
|
|
241
|
-
disabled={column.
|
|
243
|
+
disabled={!canBeSortColumn(column.schema.type) ||
|
|
244
|
+
(column.name === $sort.column && $sort.order === "descending")}
|
|
242
245
|
>
|
|
243
246
|
Sort {descendingLabel}
|
|
244
247
|
</MenuItem>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { getContext } from "svelte"
|
|
3
3
|
import { ActionButton, Popover, Select } from "@budibase/bbui"
|
|
4
|
+
import { canBeSortColumn } from "@budibase/shared-core"
|
|
4
5
|
|
|
5
6
|
const { sort, columns, stickyColumn } = getContext("grid")
|
|
6
7
|
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
type: stickyColumn.schema?.type,
|
|
20
21
|
})
|
|
21
22
|
}
|
|
22
|
-
|
|
23
|
+
options = [
|
|
23
24
|
...options,
|
|
24
25
|
...columns.map(col => ({
|
|
25
26
|
label: col.label || col.name,
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
type: col.schema?.type,
|
|
28
29
|
})),
|
|
29
30
|
]
|
|
31
|
+
return options.filter(col => canBeSortColumn(col.type))
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
const getOrderOptions = (column, columnOptions) => {
|
|
@@ -141,7 +141,14 @@
|
|
|
141
141
|
</div>
|
|
142
142
|
</div>
|
|
143
143
|
{/if}
|
|
144
|
-
{#if $
|
|
144
|
+
{#if $error}
|
|
145
|
+
<div class="grid-error">
|
|
146
|
+
<div class="grid-error-title">There was a problem loading your grid</div>
|
|
147
|
+
<div class="grid-error-subtitle">
|
|
148
|
+
{$error}
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
{:else if $loaded}
|
|
145
152
|
<div class="grid-data-outer" use:clickOutside={ui.actions.blur}>
|
|
146
153
|
<div class="grid-data-inner">
|
|
147
154
|
<StickyColumn>
|
|
@@ -171,13 +178,6 @@
|
|
|
171
178
|
</div>
|
|
172
179
|
</div>
|
|
173
180
|
</div>
|
|
174
|
-
{:else if $error}
|
|
175
|
-
<div class="grid-error">
|
|
176
|
-
<div class="grid-error-title">There was a problem loading your grid</div>
|
|
177
|
-
<div class="grid-error-subtitle">
|
|
178
|
-
{$error}
|
|
179
|
-
</div>
|
|
180
|
-
</div>
|
|
181
181
|
{/if}
|
|
182
182
|
{#if $loading && !$error}
|
|
183
183
|
<div in:fade|local={{ duration: 130 }} class="grid-loading">
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
contentLines,
|
|
19
19
|
isDragging,
|
|
20
20
|
dispatch,
|
|
21
|
+
rows,
|
|
21
22
|
} = getContext("grid")
|
|
22
23
|
|
|
23
24
|
$: rowSelected = !!$selectedRows[row._id]
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
on:focus
|
|
32
33
|
on:mouseenter={$isDragging ? null : () => ($hoveredRowId = row._id)}
|
|
33
34
|
on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)}
|
|
34
|
-
on:click={() => dispatch("rowclick", row)}
|
|
35
|
+
on:click={() => dispatch("rowclick", rows.actions.cleanRow(row))}
|
|
35
36
|
>
|
|
36
37
|
{#each $renderedColumns as column, columnIdx (column.name)}
|
|
37
38
|
{@const cellId = `${row._id}-${column.name}`}
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
|
|
34
34
|
let visible = false
|
|
35
35
|
let isAdding = false
|
|
36
|
-
let newRow
|
|
36
|
+
let newRow
|
|
37
37
|
let offset = 0
|
|
38
38
|
|
|
39
39
|
$: firstColumn = $stickyColumn || $renderedColumns[0]
|
|
@@ -58,7 +58,9 @@
|
|
|
58
58
|
|
|
59
59
|
// Create row
|
|
60
60
|
const newRowIndex = offset ? undefined : 0
|
|
61
|
-
|
|
61
|
+
let rowToCreate = { ...newRow }
|
|
62
|
+
delete rowToCreate._isNewRow
|
|
63
|
+
const savedRow = await rows.actions.addRow(rowToCreate, newRowIndex)
|
|
62
64
|
if (savedRow) {
|
|
63
65
|
// Reset state
|
|
64
66
|
clear()
|
|
@@ -109,7 +111,7 @@
|
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
// Update state and select initial cell
|
|
112
|
-
newRow = {}
|
|
114
|
+
newRow = { _isNewRow: true }
|
|
113
115
|
visible = true
|
|
114
116
|
$hoveredRowId = NewRowID
|
|
115
117
|
if (firstColumn) {
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
class="row"
|
|
75
75
|
on:mouseenter={$isDragging ? null : () => ($hoveredRowId = row._id)}
|
|
76
76
|
on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)}
|
|
77
|
-
on:click={() => dispatch("rowclick", row)}
|
|
77
|
+
on:click={() => dispatch("rowclick", rows.actions.cleanRow(row))}
|
|
78
78
|
>
|
|
79
79
|
<GutterCell {row} {rowFocused} {rowHovered} {rowSelected} />
|
|
80
80
|
{#if $stickyColumn}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
focusedCellAPI,
|
|
18
18
|
focusedRowId,
|
|
19
19
|
notifications,
|
|
20
|
+
isDatasourcePlus,
|
|
20
21
|
} = getContext("grid")
|
|
21
22
|
|
|
22
23
|
$: style = makeStyle($menu)
|
|
@@ -75,7 +76,7 @@
|
|
|
75
76
|
</MenuItem>
|
|
76
77
|
<MenuItem
|
|
77
78
|
icon="Copy"
|
|
78
|
-
disabled={isNewRow || !$focusedRow?._id}
|
|
79
|
+
disabled={isNewRow || !$focusedRow?._id || !$isDatasourcePlus}
|
|
79
80
|
on:click={() => copyToClipboard($focusedRow?._id)}
|
|
80
81
|
on:click={menu.actions.close}
|
|
81
82
|
>
|
|
@@ -69,7 +69,7 @@ export const deriveStores = context => {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
export const createActions = context => {
|
|
72
|
-
const { columns, stickyColumn, datasource, definition } = context
|
|
72
|
+
const { columns, stickyColumn, datasource, definition, schema } = context
|
|
73
73
|
|
|
74
74
|
// Updates the datasources primary display column
|
|
75
75
|
const changePrimaryDisplay = async column => {
|
|
@@ -101,7 +101,7 @@ export const createActions = context => {
|
|
|
101
101
|
const $columns = get(columns)
|
|
102
102
|
const $definition = get(definition)
|
|
103
103
|
const $stickyColumn = get(stickyColumn)
|
|
104
|
-
|
|
104
|
+
let newSchema = cloneDeep(get(schema)) || {}
|
|
105
105
|
|
|
106
106
|
// Build new updated datasource schema
|
|
107
107
|
Object.keys(newSchema).forEach(column => {
|
|
@@ -142,26 +142,35 @@ export const createActions = context => {
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
export const initialise = context => {
|
|
145
|
-
const { definition, columns, stickyColumn,
|
|
145
|
+
const { definition, columns, stickyColumn, enrichedSchema } = context
|
|
146
146
|
|
|
147
147
|
// Merge new schema fields with existing schema in order to preserve widths
|
|
148
|
-
|
|
149
|
-
if (!$
|
|
148
|
+
enrichedSchema.subscribe($enrichedSchema => {
|
|
149
|
+
if (!$enrichedSchema) {
|
|
150
150
|
columns.set([])
|
|
151
151
|
stickyColumn.set(null)
|
|
152
152
|
return
|
|
153
153
|
}
|
|
154
154
|
const $definition = get(definition)
|
|
155
|
+
const $columns = get(columns)
|
|
156
|
+
const $stickyColumn = get(stickyColumn)
|
|
157
|
+
|
|
158
|
+
// Generate array of all columns to easily find pre-existing columns
|
|
159
|
+
let allColumns = $columns || []
|
|
160
|
+
if ($stickyColumn) {
|
|
161
|
+
allColumns.push($stickyColumn)
|
|
162
|
+
}
|
|
155
163
|
|
|
156
164
|
// Find primary display
|
|
157
165
|
let primaryDisplay
|
|
158
|
-
|
|
159
|
-
|
|
166
|
+
const candidatePD = $definition.primaryDisplay || $stickyColumn?.name
|
|
167
|
+
if (candidatePD && $enrichedSchema[candidatePD]) {
|
|
168
|
+
primaryDisplay = candidatePD
|
|
160
169
|
}
|
|
161
170
|
|
|
162
171
|
// Get field list
|
|
163
172
|
let fields = []
|
|
164
|
-
Object.keys($
|
|
173
|
+
Object.keys($enrichedSchema).forEach(field => {
|
|
165
174
|
if (field !== primaryDisplay) {
|
|
166
175
|
fields.push(field)
|
|
167
176
|
}
|
|
@@ -170,14 +179,18 @@ export const initialise = context => {
|
|
|
170
179
|
// Update columns, removing extraneous columns and adding missing ones
|
|
171
180
|
columns.set(
|
|
172
181
|
fields
|
|
173
|
-
.map(field =>
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
182
|
+
.map(field => {
|
|
183
|
+
const fieldSchema = $enrichedSchema[field]
|
|
184
|
+
const oldColumn = allColumns?.find(x => x.name === field)
|
|
185
|
+
return {
|
|
186
|
+
name: field,
|
|
187
|
+
label: fieldSchema.displayName || field,
|
|
188
|
+
schema: fieldSchema,
|
|
189
|
+
width: fieldSchema.width || oldColumn?.width || DefaultColumnWidth,
|
|
190
|
+
visible: fieldSchema.visible ?? true,
|
|
191
|
+
order: fieldSchema.order ?? oldColumn?.order,
|
|
192
|
+
}
|
|
193
|
+
})
|
|
181
194
|
.sort((a, b) => {
|
|
182
195
|
// Sort by order first
|
|
183
196
|
const orderA = a.order
|
|
@@ -205,11 +218,13 @@ export const initialise = context => {
|
|
|
205
218
|
stickyColumn.set(null)
|
|
206
219
|
return
|
|
207
220
|
}
|
|
221
|
+
const stickySchema = $enrichedSchema[primaryDisplay]
|
|
222
|
+
const oldStickyColumn = allColumns?.find(x => x.name === primaryDisplay)
|
|
208
223
|
stickyColumn.set({
|
|
209
224
|
name: primaryDisplay,
|
|
210
|
-
label:
|
|
211
|
-
schema:
|
|
212
|
-
width:
|
|
225
|
+
label: stickySchema.displayName || primaryDisplay,
|
|
226
|
+
schema: stickySchema,
|
|
227
|
+
width: stickySchema.width || oldStickyColumn?.width || DefaultColumnWidth,
|
|
213
228
|
visible: true,
|
|
214
229
|
order: 0,
|
|
215
230
|
left: GutterWidth,
|
|
@@ -37,9 +37,10 @@ export const deriveStores = context => {
|
|
|
37
37
|
[props, hasNonAutoColumn],
|
|
38
38
|
([$props, $hasNonAutoColumn]) => {
|
|
39
39
|
let config = { ...$props }
|
|
40
|
+
const type = $props.datasource?.type
|
|
40
41
|
|
|
41
42
|
// Disable some features if we're editing a view
|
|
42
|
-
if (
|
|
43
|
+
if (type === "viewV2") {
|
|
43
44
|
config.canEditColumns = false
|
|
44
45
|
}
|
|
45
46
|
|
|
@@ -48,6 +49,16 @@ export const deriveStores = context => {
|
|
|
48
49
|
config.canAddRows = false
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
// Disable features for non DS+
|
|
53
|
+
if (!["table", "viewV2"].includes(type)) {
|
|
54
|
+
config.canAddRows = false
|
|
55
|
+
config.canEditRows = false
|
|
56
|
+
config.canDeleteRows = false
|
|
57
|
+
config.canExpandRows = false
|
|
58
|
+
config.canSaveSchema = false
|
|
59
|
+
config.canEditColumns = false
|
|
60
|
+
}
|
|
61
|
+
|
|
51
62
|
return config
|
|
52
63
|
}
|
|
53
64
|
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { derived, get, writable } from "svelte/store"
|
|
2
|
+
import { getDatasourceDefinition } from "../../../fetch"
|
|
2
3
|
|
|
3
4
|
export const createStores = () => {
|
|
4
5
|
const definition = writable(null)
|
|
@@ -9,21 +10,38 @@ export const createStores = () => {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export const deriveStores = context => {
|
|
12
|
-
const { definition, schemaOverrides, columnWhitelist } = context
|
|
13
|
+
const { definition, schemaOverrides, columnWhitelist, datasource } = context
|
|
13
14
|
|
|
14
|
-
const schema = derived(
|
|
15
|
-
|
|
16
|
-
(
|
|
17
|
-
|
|
15
|
+
const schema = derived(definition, $definition => {
|
|
16
|
+
let schema = $definition?.schema
|
|
17
|
+
if (!schema) {
|
|
18
|
+
return null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Ensure schema is configured as objects.
|
|
22
|
+
// Certain datasources like queries use primitives.
|
|
23
|
+
Object.keys(schema || {}).forEach(key => {
|
|
24
|
+
if (typeof schema[key] !== "object") {
|
|
25
|
+
schema[key] = { type: schema[key] }
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
return schema
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const enrichedSchema = derived(
|
|
33
|
+
[schema, schemaOverrides, columnWhitelist],
|
|
34
|
+
([$schema, $schemaOverrides, $columnWhitelist]) => {
|
|
35
|
+
if (!$schema) {
|
|
18
36
|
return null
|
|
19
37
|
}
|
|
20
|
-
let
|
|
38
|
+
let enrichedSchema = { ...$schema }
|
|
21
39
|
|
|
22
40
|
// Apply schema overrides
|
|
23
41
|
Object.keys($schemaOverrides || {}).forEach(field => {
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
...
|
|
42
|
+
if (enrichedSchema[field]) {
|
|
43
|
+
enrichedSchema[field] = {
|
|
44
|
+
...enrichedSchema[field],
|
|
27
45
|
...$schemaOverrides[field],
|
|
28
46
|
}
|
|
29
47
|
}
|
|
@@ -31,41 +49,64 @@ export const deriveStores = context => {
|
|
|
31
49
|
|
|
32
50
|
// Apply whitelist if specified
|
|
33
51
|
if ($columnWhitelist?.length) {
|
|
34
|
-
Object.keys(
|
|
52
|
+
Object.keys(enrichedSchema).forEach(key => {
|
|
35
53
|
if (!$columnWhitelist.includes(key)) {
|
|
36
|
-
delete
|
|
54
|
+
delete enrichedSchema[key]
|
|
37
55
|
}
|
|
38
56
|
})
|
|
39
57
|
}
|
|
40
58
|
|
|
41
|
-
return
|
|
59
|
+
return enrichedSchema
|
|
42
60
|
}
|
|
43
61
|
)
|
|
44
62
|
|
|
63
|
+
const isDatasourcePlus = derived(datasource, $datasource => {
|
|
64
|
+
return ["table", "viewV2"].includes($datasource?.type)
|
|
65
|
+
})
|
|
66
|
+
|
|
45
67
|
return {
|
|
46
68
|
schema,
|
|
69
|
+
enrichedSchema,
|
|
70
|
+
isDatasourcePlus,
|
|
47
71
|
}
|
|
48
72
|
}
|
|
49
73
|
|
|
50
74
|
export const createActions = context => {
|
|
51
|
-
const {
|
|
75
|
+
const {
|
|
76
|
+
API,
|
|
77
|
+
datasource,
|
|
78
|
+
definition,
|
|
79
|
+
config,
|
|
80
|
+
dispatch,
|
|
81
|
+
table,
|
|
82
|
+
viewV2,
|
|
83
|
+
nonPlus,
|
|
84
|
+
} = context
|
|
52
85
|
|
|
53
86
|
// Gets the appropriate API for the configured datasource type
|
|
54
87
|
const getAPI = () => {
|
|
55
88
|
const $datasource = get(datasource)
|
|
56
|
-
|
|
89
|
+
const type = $datasource?.type
|
|
90
|
+
if (!type) {
|
|
91
|
+
return null
|
|
92
|
+
}
|
|
93
|
+
switch (type) {
|
|
57
94
|
case "table":
|
|
58
95
|
return table
|
|
59
96
|
case "viewV2":
|
|
60
97
|
return viewV2
|
|
61
98
|
default:
|
|
62
|
-
return
|
|
99
|
+
return nonPlus
|
|
63
100
|
}
|
|
64
101
|
}
|
|
65
102
|
|
|
66
103
|
// Refreshes the datasource definition
|
|
67
104
|
const refreshDefinition = async () => {
|
|
68
|
-
|
|
105
|
+
const def = await getDatasourceDefinition({
|
|
106
|
+
API,
|
|
107
|
+
datasource: get(datasource),
|
|
108
|
+
})
|
|
109
|
+
definition.set(def)
|
|
69
110
|
}
|
|
70
111
|
|
|
71
112
|
// Saves the datasource definition
|
|
@@ -113,6 +154,11 @@ export const createActions = context => {
|
|
|
113
154
|
return getAPI()?.actions.canUseColumn(name)
|
|
114
155
|
}
|
|
115
156
|
|
|
157
|
+
// Gets the default number of rows for a single page
|
|
158
|
+
const getFeatures = () => {
|
|
159
|
+
return getAPI()?.actions.getFeatures()
|
|
160
|
+
}
|
|
161
|
+
|
|
116
162
|
return {
|
|
117
163
|
datasource: {
|
|
118
164
|
...datasource,
|
|
@@ -125,6 +171,7 @@ export const createActions = context => {
|
|
|
125
171
|
getRow,
|
|
126
172
|
isDatasourceValid,
|
|
127
173
|
canUseColumn,
|
|
174
|
+
getFeatures,
|
|
128
175
|
},
|
|
129
176
|
},
|
|
130
177
|
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { get } from "svelte/store"
|
|
2
|
+
|
|
3
|
+
export const createActions = context => {
|
|
4
|
+
const { columns, stickyColumn, table, viewV2 } = context
|
|
5
|
+
|
|
6
|
+
const saveDefinition = async () => {
|
|
7
|
+
throw "This datasource does not support updating the definition"
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const saveRow = async () => {
|
|
11
|
+
throw "This datasource does not support saving rows"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const deleteRows = async () => {
|
|
15
|
+
throw "This datasource does not support deleting rows"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const getRow = () => {
|
|
19
|
+
throw "This datasource does not support fetching individual rows"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const isDatasourceValid = datasource => {
|
|
23
|
+
// There are many different types and shapes of datasource, so we only
|
|
24
|
+
// check that we aren't null
|
|
25
|
+
return (
|
|
26
|
+
!table.actions.isDatasourceValid(datasource) &&
|
|
27
|
+
!viewV2.actions.isDatasourceValid(datasource) &&
|
|
28
|
+
datasource?.type != null
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const canUseColumn = name => {
|
|
33
|
+
const $columns = get(columns)
|
|
34
|
+
const $sticky = get(stickyColumn)
|
|
35
|
+
return $columns.some(col => col.name === name) || $sticky?.name === name
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const getFeatures = () => {
|
|
39
|
+
// We don't support any features
|
|
40
|
+
return {}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
nonPlus: {
|
|
45
|
+
actions: {
|
|
46
|
+
saveDefinition,
|
|
47
|
+
addRow: saveRow,
|
|
48
|
+
updateRow: saveRow,
|
|
49
|
+
deleteRows,
|
|
50
|
+
getRow,
|
|
51
|
+
isDatasourceValid,
|
|
52
|
+
canUseColumn,
|
|
53
|
+
getFeatures,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Small util to compare datasource definitions
|
|
60
|
+
const isSameDatasource = (a, b) => {
|
|
61
|
+
return JSON.stringify(a) === JSON.stringify(b)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const initialise = context => {
|
|
65
|
+
const {
|
|
66
|
+
datasource,
|
|
67
|
+
sort,
|
|
68
|
+
filter,
|
|
69
|
+
nonPlus,
|
|
70
|
+
initialFilter,
|
|
71
|
+
initialSortColumn,
|
|
72
|
+
initialSortOrder,
|
|
73
|
+
fetch,
|
|
74
|
+
} = context
|
|
75
|
+
// Keep a list of subscriptions so that we can clear them when the datasource
|
|
76
|
+
// config changes
|
|
77
|
+
let unsubscribers = []
|
|
78
|
+
|
|
79
|
+
// Observe datasource changes and apply logic for view V2 datasources
|
|
80
|
+
datasource.subscribe($datasource => {
|
|
81
|
+
// Clear previous subscriptions
|
|
82
|
+
unsubscribers?.forEach(unsubscribe => unsubscribe())
|
|
83
|
+
unsubscribers = []
|
|
84
|
+
if (!nonPlus.actions.isDatasourceValid($datasource)) {
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Wipe state
|
|
89
|
+
filter.set(get(initialFilter))
|
|
90
|
+
sort.set({
|
|
91
|
+
column: get(initialSortColumn),
|
|
92
|
+
order: get(initialSortOrder) || "ascending",
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// Update fetch when filter changes
|
|
96
|
+
unsubscribers.push(
|
|
97
|
+
filter.subscribe($filter => {
|
|
98
|
+
// Ensure we're updating the correct fetch
|
|
99
|
+
const $fetch = get(fetch)
|
|
100
|
+
if (!isSameDatasource($fetch?.options?.datasource, $datasource)) {
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
$fetch.update({
|
|
104
|
+
filter: $filter,
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
// Update fetch when sorting changes
|
|
110
|
+
unsubscribers.push(
|
|
111
|
+
sort.subscribe($sort => {
|
|
112
|
+
// Ensure we're updating the correct fetch
|
|
113
|
+
const $fetch = get(fetch)
|
|
114
|
+
if (!isSameDatasource($fetch?.options?.datasource, $datasource)) {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
$fetch.update({
|
|
118
|
+
sortOrder: $sort.order || "ascending",
|
|
119
|
+
sortColumn: $sort.column,
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
)
|
|
123
|
+
})
|
|
124
|
+
}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { get } from "svelte/store"
|
|
2
|
+
import TableFetch from "../../../../fetch/TableFetch"
|
|
2
3
|
|
|
3
4
|
const SuppressErrors = true
|
|
4
5
|
|
|
5
6
|
export const createActions = context => {
|
|
6
|
-
const {
|
|
7
|
-
|
|
8
|
-
const refreshDefinition = async () => {
|
|
9
|
-
definition.set(await API.fetchTableDefinition(get(datasource).tableId))
|
|
10
|
-
}
|
|
7
|
+
const { API, datasource, columns, stickyColumn } = context
|
|
11
8
|
|
|
12
9
|
const saveDefinition = async newDefinition => {
|
|
13
10
|
await API.saveTable(newDefinition)
|
|
@@ -49,10 +46,13 @@ export const createActions = context => {
|
|
|
49
46
|
return $columns.some(col => col.name === name) || $sticky?.name === name
|
|
50
47
|
}
|
|
51
48
|
|
|
49
|
+
const getFeatures = () => {
|
|
50
|
+
return new TableFetch({ API }).determineFeatureFlags()
|
|
51
|
+
}
|
|
52
|
+
|
|
52
53
|
return {
|
|
53
54
|
table: {
|
|
54
55
|
actions: {
|
|
55
|
-
refreshDefinition,
|
|
56
56
|
saveDefinition,
|
|
57
57
|
addRow: saveRow,
|
|
58
58
|
updateRow: saveRow,
|
|
@@ -60,6 +60,7 @@ export const createActions = context => {
|
|
|
60
60
|
getRow,
|
|
61
61
|
isDatasourceValid,
|
|
62
62
|
canUseColumn,
|
|
63
|
+
getFeatures,
|
|
63
64
|
},
|
|
64
65
|
},
|
|
65
66
|
}
|
|
@@ -1,22 +1,10 @@
|
|
|
1
1
|
import { get } from "svelte/store"
|
|
2
|
+
import ViewV2Fetch from "../../../../fetch/ViewV2Fetch"
|
|
2
3
|
|
|
3
4
|
const SuppressErrors = true
|
|
4
5
|
|
|
5
6
|
export const createActions = context => {
|
|
6
|
-
const {
|
|
7
|
-
|
|
8
|
-
const refreshDefinition = async () => {
|
|
9
|
-
const $datasource = get(datasource)
|
|
10
|
-
if (!$datasource) {
|
|
11
|
-
definition.set(null)
|
|
12
|
-
return
|
|
13
|
-
}
|
|
14
|
-
const table = await API.fetchTableDefinition($datasource.tableId)
|
|
15
|
-
const view = Object.values(table?.views || {}).find(
|
|
16
|
-
view => view.id === $datasource.id
|
|
17
|
-
)
|
|
18
|
-
definition.set(view)
|
|
19
|
-
}
|
|
7
|
+
const { API, datasource, columns, stickyColumn } = context
|
|
20
8
|
|
|
21
9
|
const saveDefinition = async newDefinition => {
|
|
22
10
|
await API.viewV2.update(newDefinition)
|
|
@@ -58,10 +46,13 @@ export const createActions = context => {
|
|
|
58
46
|
)
|
|
59
47
|
}
|
|
60
48
|
|
|
49
|
+
const getFeatures = () => {
|
|
50
|
+
return new ViewV2Fetch({ API }).determineFeatureFlags()
|
|
51
|
+
}
|
|
52
|
+
|
|
61
53
|
return {
|
|
62
54
|
viewV2: {
|
|
63
55
|
actions: {
|
|
64
|
-
refreshDefinition,
|
|
65
56
|
saveDefinition,
|
|
66
57
|
addRow: saveRow,
|
|
67
58
|
updateRow: saveRow,
|
|
@@ -69,6 +60,7 @@ export const createActions = context => {
|
|
|
69
60
|
getRow,
|
|
70
61
|
isDatasourceValid,
|
|
71
62
|
canUseColumn,
|
|
63
|
+
getFeatures,
|
|
72
64
|
},
|
|
73
65
|
},
|
|
74
66
|
}
|
|
@@ -15,9 +15,10 @@ import * as Config from "./config"
|
|
|
15
15
|
import * as Sort from "./sort"
|
|
16
16
|
import * as Filter from "./filter"
|
|
17
17
|
import * as Notifications from "./notifications"
|
|
18
|
-
import * as Table from "./table"
|
|
19
|
-
import * as ViewV2 from "./viewV2"
|
|
20
18
|
import * as Datasource from "./datasource"
|
|
19
|
+
import * as Table from "./datasources/table"
|
|
20
|
+
import * as ViewV2 from "./datasources/viewV2"
|
|
21
|
+
import * as NonPlus from "./datasources/nonPlus"
|
|
21
22
|
|
|
22
23
|
const DependencyOrderedStores = [
|
|
23
24
|
Sort,
|
|
@@ -26,6 +27,7 @@ const DependencyOrderedStores = [
|
|
|
26
27
|
Scroll,
|
|
27
28
|
Table,
|
|
28
29
|
ViewV2,
|
|
30
|
+
NonPlus,
|
|
29
31
|
Datasource,
|
|
30
32
|
Columns,
|
|
31
33
|
Rows,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { writable, derived, get } from "svelte/store"
|
|
2
|
-
import { fetchData } from "../../../fetch
|
|
2
|
+
import { fetchData } from "../../../fetch"
|
|
3
3
|
import { NewRowID, RowPageSize } from "../lib/constants"
|
|
4
4
|
import { tick } from "svelte"
|
|
5
|
+
import { Helpers } from "@budibase/bbui"
|
|
5
6
|
|
|
6
7
|
export const createStores = () => {
|
|
7
8
|
const rows = writable([])
|
|
@@ -76,11 +77,11 @@ export const createActions = context => {
|
|
|
76
77
|
columns,
|
|
77
78
|
rowChangeCache,
|
|
78
79
|
inProgressChanges,
|
|
79
|
-
previousFocusedRowId,
|
|
80
80
|
hasNextPage,
|
|
81
81
|
error,
|
|
82
82
|
notifications,
|
|
83
83
|
fetch,
|
|
84
|
+
isDatasourcePlus,
|
|
84
85
|
} = context
|
|
85
86
|
const instanceLoaded = writable(false)
|
|
86
87
|
|
|
@@ -93,12 +94,14 @@ export const createActions = context => {
|
|
|
93
94
|
datasource.subscribe(async $datasource => {
|
|
94
95
|
// Unsub from previous fetch if one exists
|
|
95
96
|
unsubscribe?.()
|
|
97
|
+
unsubscribe = null
|
|
96
98
|
fetch.set(null)
|
|
97
99
|
instanceLoaded.set(false)
|
|
98
100
|
loading.set(true)
|
|
99
101
|
|
|
100
102
|
// Abandon if we don't have a valid datasource
|
|
101
103
|
if (!datasource.actions.isDatasourceValid($datasource)) {
|
|
104
|
+
error.set("Datasource is invalid")
|
|
102
105
|
return
|
|
103
106
|
}
|
|
104
107
|
|
|
@@ -108,6 +111,10 @@ export const createActions = context => {
|
|
|
108
111
|
const $filter = get(filter)
|
|
109
112
|
const $sort = get(sort)
|
|
110
113
|
|
|
114
|
+
// Determine how many rows to fetch per page
|
|
115
|
+
const features = datasource.actions.getFeatures()
|
|
116
|
+
const limit = features?.supportsPagination ? RowPageSize : null
|
|
117
|
+
|
|
111
118
|
// Create new fetch model
|
|
112
119
|
const newFetch = fetchData({
|
|
113
120
|
API,
|
|
@@ -116,7 +123,7 @@ export const createActions = context => {
|
|
|
116
123
|
filter: $filter,
|
|
117
124
|
sortColumn: $sort.column,
|
|
118
125
|
sortOrder: $sort.order,
|
|
119
|
-
limit
|
|
126
|
+
limit,
|
|
120
127
|
paginate: true,
|
|
121
128
|
},
|
|
122
129
|
})
|
|
@@ -355,7 +362,7 @@ export const createActions = context => {
|
|
|
355
362
|
|
|
356
363
|
// Update row
|
|
357
364
|
const saved = await datasource.actions.updateRow({
|
|
358
|
-
...row,
|
|
365
|
+
...cleanRow(row),
|
|
359
366
|
...get(rowChangeCache)[rowId],
|
|
360
367
|
})
|
|
361
368
|
|
|
@@ -411,8 +418,17 @@ export const createActions = context => {
|
|
|
411
418
|
}
|
|
412
419
|
let rowsToAppend = []
|
|
413
420
|
let newRow
|
|
421
|
+
const $isDatasourcePlus = get(isDatasourcePlus)
|
|
414
422
|
for (let i = 0; i < newRows.length; i++) {
|
|
415
423
|
newRow = newRows[i]
|
|
424
|
+
|
|
425
|
+
// Ensure we have a unique _id.
|
|
426
|
+
// This means generating one for non DS+, overriting any that may already
|
|
427
|
+
// exist as we cannot allow duplicates.
|
|
428
|
+
if (!$isDatasourcePlus) {
|
|
429
|
+
newRow._id = Helpers.uuid()
|
|
430
|
+
}
|
|
431
|
+
|
|
416
432
|
if (!rowCacheMap[newRow._id]) {
|
|
417
433
|
rowCacheMap[newRow._id] = true
|
|
418
434
|
rowsToAppend.push(newRow)
|
|
@@ -449,15 +465,16 @@ export const createActions = context => {
|
|
|
449
465
|
return get(rowLookupMap)[id] != null
|
|
450
466
|
}
|
|
451
467
|
|
|
452
|
-
//
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
468
|
+
// Cleans a row by removing any internal grid metadata from it.
|
|
469
|
+
// Call this before passing a row to any sort of external flow.
|
|
470
|
+
const cleanRow = row => {
|
|
471
|
+
let clone = { ...row }
|
|
472
|
+
delete clone.__idx
|
|
473
|
+
if (!get(isDatasourcePlus)) {
|
|
474
|
+
delete clone._id
|
|
459
475
|
}
|
|
460
|
-
|
|
476
|
+
return clone
|
|
477
|
+
}
|
|
461
478
|
|
|
462
479
|
return {
|
|
463
480
|
rows: {
|
|
@@ -474,7 +491,22 @@ export const createActions = context => {
|
|
|
474
491
|
refreshRow,
|
|
475
492
|
replaceRow,
|
|
476
493
|
refreshData,
|
|
494
|
+
cleanRow,
|
|
477
495
|
},
|
|
478
496
|
},
|
|
479
497
|
}
|
|
480
498
|
}
|
|
499
|
+
|
|
500
|
+
export const initialise = context => {
|
|
501
|
+
const { rowChangeCache, inProgressChanges, previousFocusedRowId } = context
|
|
502
|
+
|
|
503
|
+
// Wipe the row change cache when changing row
|
|
504
|
+
previousFocusedRowId.subscribe(id => {
|
|
505
|
+
if (id && !get(inProgressChanges)[id]) {
|
|
506
|
+
rowChangeCache.update(state => {
|
|
507
|
+
delete state[id]
|
|
508
|
+
return state
|
|
509
|
+
})
|
|
510
|
+
}
|
|
511
|
+
})
|
|
512
|
+
}
|
|
@@ -17,7 +17,7 @@ export const createStores = context => {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const initialise = context => {
|
|
20
|
-
const { sort, initialSortColumn, initialSortOrder,
|
|
20
|
+
const { sort, initialSortColumn, initialSortOrder, schema } = context
|
|
21
21
|
|
|
22
22
|
// Reset sort when initial sort props change
|
|
23
23
|
initialSortColumn.subscribe(newSortColumn => {
|
|
@@ -28,15 +28,12 @@ export const initialise = context => {
|
|
|
28
28
|
})
|
|
29
29
|
|
|
30
30
|
// Derive if the current sort column exists in the schema
|
|
31
|
-
const sortColumnExists = derived(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (!$sort?.column || !$definition) {
|
|
35
|
-
return true
|
|
36
|
-
}
|
|
37
|
-
return $definition.schema?.[$sort.column] != null
|
|
31
|
+
const sortColumnExists = derived([sort, schema], ([$sort, $schema]) => {
|
|
32
|
+
if (!$sort?.column || !$schema) {
|
|
33
|
+
return true
|
|
38
34
|
}
|
|
39
|
-
|
|
35
|
+
return $schema[$sort.column] != null
|
|
36
|
+
})
|
|
40
37
|
|
|
41
38
|
// Clear sort state if our sort column does not exist
|
|
42
39
|
sortColumnExists.subscribe(exists => {
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import DataFetch from "./DataFetch.js"
|
|
2
|
+
|
|
3
|
+
export default class CustomFetch extends DataFetch {
|
|
4
|
+
// Gets the correct Budibase type for a JS value
|
|
5
|
+
getType(value) {
|
|
6
|
+
if (value == null) {
|
|
7
|
+
return "string"
|
|
8
|
+
}
|
|
9
|
+
const type = typeof value
|
|
10
|
+
if (type === "object") {
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
// Use our custom array type to render badges
|
|
13
|
+
return "array"
|
|
14
|
+
}
|
|
15
|
+
// Use JSON for objects to ensure they are stringified
|
|
16
|
+
return "json"
|
|
17
|
+
} else if (!isNaN(value)) {
|
|
18
|
+
return "number"
|
|
19
|
+
} else {
|
|
20
|
+
return "string"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Parses the custom data into an array format
|
|
25
|
+
parseCustomData(data) {
|
|
26
|
+
if (!data) {
|
|
27
|
+
return []
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Happy path - already an array
|
|
31
|
+
if (Array.isArray(data)) {
|
|
32
|
+
return data
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// For strings, try JSON then fall back to attempting a CSV
|
|
36
|
+
if (typeof data === "string") {
|
|
37
|
+
try {
|
|
38
|
+
const js = JSON.parse(data)
|
|
39
|
+
return Array.isArray(js) ? js : [js]
|
|
40
|
+
} catch (error) {
|
|
41
|
+
// Ignore
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Try splitting by newlines first
|
|
45
|
+
if (data.includes("\n")) {
|
|
46
|
+
return data.split("\n").map(x => x.trim())
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Split by commas next
|
|
50
|
+
return data.split(",").map(x => x.trim())
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Other cases we just assume it's a single object and wrap it
|
|
54
|
+
return [data]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Enriches the custom data to ensure the structure and format is usable
|
|
58
|
+
enrichCustomData(data) {
|
|
59
|
+
if (!data?.length) {
|
|
60
|
+
return []
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Filter out any invalid values
|
|
64
|
+
data = data.filter(x => x != null && x !== "" && !Array.isArray(x))
|
|
65
|
+
|
|
66
|
+
// Ensure all values are packed into objects
|
|
67
|
+
return data.map(value => {
|
|
68
|
+
if (typeof value === "object") {
|
|
69
|
+
return value
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Try parsing strings
|
|
73
|
+
if (typeof value === "string") {
|
|
74
|
+
const split = value.split(",").map(x => x.trim())
|
|
75
|
+
let obj = {}
|
|
76
|
+
for (let i = 0; i < split.length; i++) {
|
|
77
|
+
const suffix = i === 0 ? "" : ` ${i + 1}`
|
|
78
|
+
const key = `Value${suffix}`
|
|
79
|
+
obj[key] = split[i]
|
|
80
|
+
}
|
|
81
|
+
return obj
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// For anything else, wrap in an object
|
|
85
|
+
return { Value: value }
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Extracts and parses the custom data from the datasource definition
|
|
90
|
+
getCustomData(datasource) {
|
|
91
|
+
return this.enrichCustomData(this.parseCustomData(datasource?.data))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async getDefinition(datasource) {
|
|
95
|
+
// Try and work out the schema from the array provided
|
|
96
|
+
let schema = {}
|
|
97
|
+
const data = this.getCustomData(datasource)
|
|
98
|
+
if (!data?.length) {
|
|
99
|
+
return { schema }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Go through every object and extract all valid keys
|
|
103
|
+
for (let datum of data) {
|
|
104
|
+
for (let key of Object.keys(datum)) {
|
|
105
|
+
if (key === "_id") {
|
|
106
|
+
continue
|
|
107
|
+
}
|
|
108
|
+
if (!schema[key]) {
|
|
109
|
+
let type = this.getType(datum[key])
|
|
110
|
+
let constraints = {}
|
|
111
|
+
|
|
112
|
+
// Determine whether we should render text columns as options instead
|
|
113
|
+
if (type === "string") {
|
|
114
|
+
const uniqueValues = [...new Set(data.map(x => x[key]))]
|
|
115
|
+
const uniqueness = uniqueValues.length / data.length
|
|
116
|
+
if (uniqueness <= 0.8 && uniqueValues.length > 1) {
|
|
117
|
+
type = "options"
|
|
118
|
+
constraints.inclusion = uniqueValues
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Generate options for array columns
|
|
123
|
+
else if (type === "array") {
|
|
124
|
+
constraints.inclusion = [...new Set(data.map(x => x[key]).flat())]
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
schema[key] = {
|
|
128
|
+
type,
|
|
129
|
+
constraints,
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return { schema }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async getData() {
|
|
138
|
+
const { datasource } = this.options
|
|
139
|
+
return {
|
|
140
|
+
rows: this.getCustomData(datasource),
|
|
141
|
+
hasNextPage: false,
|
|
142
|
+
cursor: null,
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -8,6 +8,7 @@ import FieldFetch from "./FieldFetch.js"
|
|
|
8
8
|
import JSONArrayFetch from "./JSONArrayFetch.js"
|
|
9
9
|
import UserFetch from "./UserFetch.js"
|
|
10
10
|
import GroupUserFetch from "./GroupUserFetch.js"
|
|
11
|
+
import CustomFetch from "./CustomFetch.js"
|
|
11
12
|
|
|
12
13
|
const DataFetchMap = {
|
|
13
14
|
table: TableFetch,
|
|
@@ -17,6 +18,7 @@ const DataFetchMap = {
|
|
|
17
18
|
link: RelationshipFetch,
|
|
18
19
|
user: UserFetch,
|
|
19
20
|
groupUser: GroupUserFetch,
|
|
21
|
+
custom: CustomFetch,
|
|
20
22
|
|
|
21
23
|
// Client specific datasource types
|
|
22
24
|
provider: NestedProviderFetch,
|
|
@@ -24,7 +26,18 @@ const DataFetchMap = {
|
|
|
24
26
|
jsonarray: JSONArrayFetch,
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
// Constructs a new fetch model for a certain datasource
|
|
27
30
|
export const fetchData = ({ API, datasource, options }) => {
|
|
28
31
|
const Fetch = DataFetchMap[datasource?.type] || TableFetch
|
|
29
32
|
return new Fetch({ API, datasource, ...options })
|
|
30
33
|
}
|
|
34
|
+
|
|
35
|
+
// Fetches the definition of any type of datasource
|
|
36
|
+
export const getDatasourceDefinition = async ({ API, datasource }) => {
|
|
37
|
+
const handler = DataFetchMap[datasource?.type]
|
|
38
|
+
if (!handler) {
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
41
|
+
const instance = new handler({ API })
|
|
42
|
+
return await instance.getDefinition(datasource)
|
|
43
|
+
}
|
package/src/index.js
CHANGED