@budibase/frontend-core 2.9.38 → 2.9.39-alpha.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.
Files changed (45) hide show
  1. package/package.json +4 -4
  2. package/src/api/groups.js +22 -0
  3. package/src/api/index.js +2 -0
  4. package/src/api/permissions.js +23 -0
  5. package/src/api/rows.js +22 -3
  6. package/src/api/user.js +27 -4
  7. package/src/api/viewsV2.js +72 -0
  8. package/src/components/grid/cells/DataCell.svelte +8 -3
  9. package/src/components/grid/cells/GutterCell.svelte +4 -4
  10. package/src/components/grid/cells/HeaderCell.svelte +3 -3
  11. package/src/components/grid/controls/HideColumnsButton.svelte +10 -7
  12. package/src/components/grid/controls/SizeButton.svelte +10 -4
  13. package/src/components/grid/controls/SortButton.svelte +12 -34
  14. package/src/components/grid/layout/Grid.svelte +22 -17
  15. package/src/components/grid/layout/GridBody.svelte +2 -2
  16. package/src/components/grid/layout/HeaderRow.svelte +3 -4
  17. package/src/components/grid/layout/NewColumnButton.svelte +3 -2
  18. package/src/components/grid/layout/NewRow.svelte +6 -6
  19. package/src/components/grid/layout/StickyColumn.svelte +2 -2
  20. package/src/components/grid/lib/websocket.js +18 -12
  21. package/src/components/grid/overlays/KeyboardManager.svelte +12 -11
  22. package/src/components/grid/overlays/MenuOverlay.svelte +3 -6
  23. package/src/components/grid/stores/clipboard.js +1 -1
  24. package/src/components/grid/stores/columns.js +39 -99
  25. package/src/components/grid/stores/config.js +33 -6
  26. package/src/components/grid/stores/datasource.js +131 -0
  27. package/src/components/grid/stores/filter.js +2 -2
  28. package/src/components/grid/stores/index.js +14 -3
  29. package/src/components/grid/stores/menu.js +1 -1
  30. package/src/components/grid/stores/pagination.js +3 -4
  31. package/src/components/grid/stores/reorder.js +1 -1
  32. package/src/components/grid/stores/resize.js +1 -1
  33. package/src/components/grid/stores/rows.js +61 -101
  34. package/src/components/grid/stores/sort.js +29 -6
  35. package/src/components/grid/stores/table.js +129 -0
  36. package/src/components/grid/stores/ui.js +24 -36
  37. package/src/components/grid/stores/users.js +8 -1
  38. package/src/components/grid/stores/viewV2.js +212 -0
  39. package/src/components/grid/stores/viewport.js +4 -4
  40. package/src/constants.js +21 -13
  41. package/src/fetch/DataFetch.js +35 -24
  42. package/src/fetch/QueryFetch.js +4 -0
  43. package/src/fetch/ViewV2Fetch.js +65 -0
  44. package/src/fetch/fetchData.js +2 -0
  45. package/src/utils/roles.js +5 -3
@@ -7,6 +7,7 @@
7
7
 
8
8
  let anchor
9
9
  let open = false
10
+
10
11
  $: columnsWidth = $renderedColumns.reduce(
11
12
  (total, col) => (total += col.width),
12
13
  0
@@ -17,6 +18,7 @@
17
18
  const close = () => {
18
19
  open = false
19
20
  }
21
+
20
22
  onMount(() => subscribe("close-edit-column", close))
21
23
  </script>
22
24
 
@@ -32,10 +34,9 @@
32
34
  <Popover
33
35
  bind:open
34
36
  {anchor}
35
- align="right"
37
+ align={$renderedColumns.length ? "right" : "left"}
36
38
  offset={0}
37
39
  popoverTarget={document.getElementById(`add-column-button`)}
38
- animate={false}
39
40
  customZindex={100}
40
41
  >
41
42
  <div
@@ -17,7 +17,7 @@
17
17
  dispatch,
18
18
  rows,
19
19
  focusedCellAPI,
20
- tableId,
20
+ datasource,
21
21
  subscribe,
22
22
  renderedRows,
23
23
  renderedColumns,
@@ -28,7 +28,7 @@
28
28
  columnHorizontalInversionIndex,
29
29
  selectedRows,
30
30
  loading,
31
- canAddRows,
31
+ config,
32
32
  } = getContext("grid")
33
33
 
34
34
  let visible = false
@@ -38,7 +38,7 @@
38
38
 
39
39
  $: firstColumn = $stickyColumn || $renderedColumns[0]
40
40
  $: width = GutterWidth + ($stickyColumn?.width || 0)
41
- $: $tableId, (visible = false)
41
+ $: $datasource, (visible = false)
42
42
  $: invertY = shouldInvertY(offset, $rowVerticalInversionIndex, $renderedRows)
43
43
  $: selectedRowCount = Object.values($selectedRows).length
44
44
  $: hasNoRows = !$rows.length
@@ -120,8 +120,8 @@
120
120
  document.addEventListener("keydown", handleKeyPress)
121
121
  }
122
122
 
123
- const updateValue = (rowId, columnName, val) => {
124
- newRow[columnName] = val
123
+ const updateValue = ({ column, value }) => {
124
+ newRow[column] = value
125
125
  }
126
126
 
127
127
  const addViaModal = () => {
@@ -154,7 +154,7 @@
154
154
  condition={hasNoRows && !$loading}
155
155
  type={TooltipType.Info}
156
156
  >
157
- {#if !visible && !selectedRowCount && $canAddRows}
157
+ {#if !visible && !selectedRowCount && $config.canAddRows}
158
158
  <div
159
159
  class="new-row-fab"
160
160
  on:click={() => dispatch("add-row-inline")}
@@ -16,7 +16,7 @@
16
16
  renderedRows,
17
17
  focusedCellId,
18
18
  hoveredRowId,
19
- canAddRows,
19
+ config,
20
20
  selectedCellMap,
21
21
  focusedRow,
22
22
  scrollLeft,
@@ -94,7 +94,7 @@
94
94
  {/if}
95
95
  </div>
96
96
  {/each}
97
- {#if $canAddRows}
97
+ {#if $config.canAddRows}
98
98
  <div
99
99
  class="row new"
100
100
  on:mouseenter={$isDragging
@@ -3,18 +3,21 @@ import { createWebsocket } from "../../../utils"
3
3
  import { SocketEvent, GridSocketEvent } from "@budibase/shared-core"
4
4
 
5
5
  export const createGridWebsocket = context => {
6
- const { rows, tableId, users, focusedCellId, table, API } = context
6
+ const { rows, datasource, users, focusedCellId, definition, API } = context
7
7
  const socket = createWebsocket("/socket/grid")
8
8
 
9
- const connectToTable = tableId => {
9
+ const connectToDatasource = datasource => {
10
10
  if (!socket.connected) {
11
11
  return
12
12
  }
13
13
  // Identify which table we are editing
14
14
  const appId = API.getAppID()
15
15
  socket.emit(
16
- GridSocketEvent.SelectTable,
17
- { tableId, appId },
16
+ GridSocketEvent.SelectDatasource,
17
+ {
18
+ datasource,
19
+ appId,
20
+ },
18
21
  ({ users: gridUsers }) => {
19
22
  users.set(gridUsers)
20
23
  }
@@ -23,7 +26,7 @@ export const createGridWebsocket = context => {
23
26
 
24
27
  // Built-in events
25
28
  socket.on("connect", () => {
26
- connectToTable(get(tableId))
29
+ connectToDatasource(get(datasource))
27
30
  })
28
31
  socket.on("connect_error", err => {
29
32
  console.log("Failed to connect to grid websocket:", err.message)
@@ -48,16 +51,19 @@ export const createGridWebsocket = context => {
48
51
  })
49
52
 
50
53
  // Table events
51
- socket.onOther(GridSocketEvent.TableChange, ({ table: newTable }) => {
52
- // Only update table if one exists. If the table was deleted then we don't
53
- // want to know - let the builder navigate away
54
- if (newTable) {
55
- table.set(newTable)
54
+ socket.onOther(
55
+ GridSocketEvent.DatasourceChange,
56
+ ({ datasource: newDatasource }) => {
57
+ // Only update definition if one exists. If the datasource was deleted
58
+ // then we don't want to know - let the builder navigate away
59
+ if (newDatasource) {
60
+ definition.set(newDatasource)
61
+ }
56
62
  }
57
- })
63
+ )
58
64
 
59
65
  // Change websocket connection when table changes
60
- tableId.subscribe(connectToTable)
66
+ datasource.subscribe(connectToDatasource)
61
67
 
62
68
  // Notify selected cell changes
63
69
  focusedCellId.subscribe($focusedCellId => {
@@ -4,7 +4,7 @@
4
4
  import { NewRowID } from "../lib/constants"
5
5
 
6
6
  const {
7
- enrichedRows,
7
+ rows,
8
8
  focusedCellId,
9
9
  visibleColumns,
10
10
  focusedRow,
@@ -16,7 +16,6 @@
16
16
  config,
17
17
  menu,
18
18
  gridFocused,
19
- canAddRows,
20
19
  } = getContext("grid")
21
20
 
22
21
  const ignoredOriginSelectors = [
@@ -46,12 +45,12 @@
46
45
  e.preventDefault()
47
46
  focusFirstCell()
48
47
  } else if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
49
- if ($canAddRows) {
48
+ if ($config.canAddRows) {
50
49
  e.preventDefault()
51
50
  dispatch("add-row-inline")
52
51
  }
53
52
  } else if (e.key === "Delete" || e.key === "Backspace") {
54
- if (Object.keys($selectedRows).length && $config.allowDeleteRows) {
53
+ if (Object.keys($selectedRows).length && $config.canDeleteRows) {
55
54
  dispatch("request-bulk-delete")
56
55
  }
57
56
  }
@@ -100,7 +99,7 @@
100
99
  }
101
100
  break
102
101
  case "Enter":
103
- if ($canAddRows) {
102
+ if ($config.canAddRows) {
104
103
  dispatch("add-row-inline")
105
104
  }
106
105
  }
@@ -120,7 +119,7 @@
120
119
  break
121
120
  case "Delete":
122
121
  case "Backspace":
123
- if (Object.keys($selectedRows).length && $config.allowDeleteRows) {
122
+ if (Object.keys($selectedRows).length && $config.canDeleteRows) {
124
123
  dispatch("request-bulk-delete")
125
124
  } else {
126
125
  deleteSelectedCell()
@@ -131,7 +130,7 @@
131
130
  break
132
131
  case " ":
133
132
  case "Space":
134
- if ($config.allowDeleteRows) {
133
+ if ($config.canDeleteRows) {
135
134
  toggleSelectRow()
136
135
  }
137
136
  break
@@ -143,7 +142,7 @@
143
142
 
144
143
  // Focuses the first cell in the grid
145
144
  const focusFirstCell = () => {
146
- const firstRow = $enrichedRows[0]
145
+ const firstRow = $rows[0]
147
146
  if (!firstRow) {
148
147
  return
149
148
  }
@@ -184,7 +183,7 @@
184
183
  if (!$focusedRow) {
185
184
  return
186
185
  }
187
- const newRow = $enrichedRows[$focusedRow.__idx + delta]
186
+ const newRow = $rows[$focusedRow.__idx + delta]
188
187
  if (newRow) {
189
188
  const split = $focusedCellId.split("-")
190
189
  $focusedCellId = `${newRow._id}-${split[1]}`
@@ -216,13 +215,15 @@
216
215
  if ($focusedCellAPI && !$focusedCellAPI.isReadonly()) {
217
216
  const type = $focusedCellAPI.getType()
218
217
  if (type === "number" && keyCodeIsNumber(keyCode)) {
219
- $focusedCellAPI.setValue(parseInt(key))
218
+ // Update the value locally but don't save it yet
219
+ $focusedCellAPI.setValue(parseInt(key), { save: false })
220
220
  $focusedCellAPI.focus()
221
221
  } else if (
222
222
  ["string", "barcodeqr", "longform"].includes(type) &&
223
223
  (keyCodeIsLetter(keyCode) || keyCodeIsNumber(keyCode))
224
224
  ) {
225
- $focusedCellAPI.setValue(key)
225
+ // Update the value locally but don't save it yet
226
+ $focusedCellAPI.setValue(key, { save: false })
226
227
  $focusedCellAPI.focus()
227
228
  }
228
229
  }
@@ -17,7 +17,6 @@
17
17
  focusedCellAPI,
18
18
  focusedRowId,
19
19
  notifications,
20
- canAddRows,
21
20
  } = getContext("grid")
22
21
 
23
22
  $: style = makeStyle($menu)
@@ -68,9 +67,7 @@
68
67
  </MenuItem>
69
68
  <MenuItem
70
69
  icon="Maximize"
71
- disabled={isNewRow ||
72
- !$config.allowEditRows ||
73
- !$config.allowExpandRows}
70
+ disabled={isNewRow || !$config.canEditRows || !$config.canExpandRows}
74
71
  on:click={() => dispatch("edit-row", $focusedRow)}
75
72
  on:click={menu.actions.close}
76
73
  >
@@ -94,14 +91,14 @@
94
91
  </MenuItem>
95
92
  <MenuItem
96
93
  icon="Duplicate"
97
- disabled={isNewRow || !$canAddRows}
94
+ disabled={isNewRow || !$config.canAddRows}
98
95
  on:click={duplicate}
99
96
  >
100
97
  Duplicate row
101
98
  </MenuItem>
102
99
  <MenuItem
103
100
  icon="Delete"
104
- disabled={isNewRow || !$config.allowDeleteRows}
101
+ disabled={isNewRow || !$config.canDeleteRows}
105
102
  on:click={deleteRow}
106
103
  >
107
104
  Delete row
@@ -8,7 +8,7 @@ export const createStores = () => {
8
8
  }
9
9
  }
10
10
 
11
- export const deriveStores = context => {
11
+ export const createActions = context => {
12
12
  const { copiedCell, focusedCellAPI } = context
13
13
 
14
14
  const copy = () => {
@@ -35,20 +35,10 @@ export const createStores = () => {
35
35
  []
36
36
  )
37
37
 
38
- // Checks if we have a certain column by name
39
- const hasColumn = column => {
40
- const $columns = get(columns)
41
- const $sticky = get(stickyColumn)
42
- return $columns.some(col => col.name === column) || $sticky?.name === column
43
- }
44
-
45
38
  return {
46
39
  columns: {
47
40
  ...columns,
48
41
  subscribe: enrichedColumns.subscribe,
49
- actions: {
50
- hasColumn,
51
- },
52
42
  },
53
43
  stickyColumn,
54
44
  visibleColumns,
@@ -56,12 +46,35 @@ export const createStores = () => {
56
46
  }
57
47
 
58
48
  export const deriveStores = context => {
59
- const { table, columns, stickyColumn, API, dispatch, config } = context
49
+ const { columns, stickyColumn } = context
50
+
51
+ // Derive if we have any normal columns
52
+ const hasNonAutoColumn = derived(
53
+ [columns, stickyColumn],
54
+ ([$columns, $stickyColumn]) => {
55
+ let allCols = $columns || []
56
+ if ($stickyColumn) {
57
+ allCols = [...allCols, $stickyColumn]
58
+ }
59
+ const normalCols = allCols.filter(column => {
60
+ return !column.schema?.autocolumn
61
+ })
62
+ return normalCols.length > 0
63
+ }
64
+ )
65
+
66
+ return {
67
+ hasNonAutoColumn,
68
+ }
69
+ }
70
+
71
+ export const createActions = context => {
72
+ const { columns, stickyColumn, datasource, definition } = context
60
73
 
61
- // Updates the tables primary display column
74
+ // Updates the datasources primary display column
62
75
  const changePrimaryDisplay = async column => {
63
- return await saveTable({
64
- ...get(table),
76
+ return await datasource.actions.saveDefinition({
77
+ ...get(definition),
65
78
  primaryDisplay: column,
66
79
  })
67
80
  }
@@ -83,29 +96,14 @@ export const deriveStores = context => {
83
96
  await saveChanges()
84
97
  }
85
98
 
86
- // Derive if we have any normal columns
87
- const hasNonAutoColumn = derived(
88
- [columns, stickyColumn],
89
- ([$columns, $stickyColumn]) => {
90
- let allCols = $columns || []
91
- if ($stickyColumn) {
92
- allCols = [...allCols, $stickyColumn]
93
- }
94
- const normalCols = allCols.filter(column => {
95
- return !column.schema?.autocolumn
96
- })
97
- return normalCols.length > 0
98
- }
99
- )
100
-
101
- // Persists column changes by saving metadata against table schema
99
+ // Persists column changes by saving metadata against datasource schema
102
100
  const saveChanges = async () => {
103
101
  const $columns = get(columns)
104
- const $table = get(table)
102
+ const $definition = get(definition)
105
103
  const $stickyColumn = get(stickyColumn)
106
- const newSchema = cloneDeep($table.schema)
104
+ const newSchema = cloneDeep($definition.schema)
107
105
 
108
- // Build new updated table schema
106
+ // Build new updated datasource schema
109
107
  Object.keys(newSchema).forEach(column => {
110
108
  // Respect order specified by columns
111
109
  const index = $columns.findIndex(x => x.name === column)
@@ -125,31 +123,17 @@ export const deriveStores = context => {
125
123
  }
126
124
  })
127
125
 
128
- await saveTable({ ...$table, schema: newSchema })
129
- }
130
-
131
- const saveTable = async newTable => {
132
- // Update local state
133
- table.set(newTable)
134
-
135
- // Update server
136
- if (get(config).allowSchemaChanges) {
137
- await API.saveTable(newTable)
138
- }
139
-
140
- // Broadcast change to external state can be updated, as this change
141
- // will not be received by the builder websocket because we caused it ourselves
142
- dispatch("updatetable", newTable)
126
+ await datasource.actions.saveDefinition({
127
+ ...$definition,
128
+ schema: newSchema,
129
+ })
143
130
  }
144
131
 
145
132
  return {
146
- hasNonAutoColumn,
147
133
  columns: {
148
134
  ...columns,
149
135
  actions: {
150
- ...columns.actions,
151
136
  saveChanges,
152
- saveTable,
153
137
  changePrimaryDisplay,
154
138
  changeAllColumnWidths,
155
139
  },
@@ -158,51 +142,7 @@ export const deriveStores = context => {
158
142
  }
159
143
 
160
144
  export const initialise = context => {
161
- const { table, columns, stickyColumn, schemaOverrides, columnWhitelist } =
162
- context
163
-
164
- const schema = derived(
165
- [table, schemaOverrides, columnWhitelist],
166
- ([$table, $schemaOverrides, $columnWhitelist]) => {
167
- if (!$table?.schema) {
168
- return null
169
- }
170
- let newSchema = { ...$table?.schema }
171
-
172
- // Edge case to temporarily allow deletion of duplicated user
173
- // fields that were saved with the "disabled" flag set.
174
- // By overriding the saved schema we ensure only overrides can
175
- // set the disabled flag.
176
- // TODO: remove in future
177
- Object.keys(newSchema).forEach(field => {
178
- newSchema[field] = {
179
- ...newSchema[field],
180
- disabled: false,
181
- }
182
- })
183
-
184
- // Apply schema overrides
185
- Object.keys($schemaOverrides || {}).forEach(field => {
186
- if (newSchema[field]) {
187
- newSchema[field] = {
188
- ...newSchema[field],
189
- ...$schemaOverrides[field],
190
- }
191
- }
192
- })
193
-
194
- // Apply whitelist if specified
195
- if ($columnWhitelist?.length) {
196
- Object.keys(newSchema).forEach(key => {
197
- if (!$columnWhitelist.includes(key)) {
198
- delete newSchema[key]
199
- }
200
- })
201
- }
202
-
203
- return newSchema
204
- }
205
- )
145
+ const { definition, columns, stickyColumn, schema } = context
206
146
 
207
147
  // Merge new schema fields with existing schema in order to preserve widths
208
148
  schema.subscribe($schema => {
@@ -211,12 +151,12 @@ export const initialise = context => {
211
151
  stickyColumn.set(null)
212
152
  return
213
153
  }
214
- const $table = get(table)
154
+ const $definition = get(definition)
215
155
 
216
156
  // Find primary display
217
157
  let primaryDisplay
218
- if ($table.primaryDisplay && $schema[$table.primaryDisplay]) {
219
- primaryDisplay = $table.primaryDisplay
158
+ if ($definition.primaryDisplay && $schema[$definition.primaryDisplay]) {
159
+ primaryDisplay = $definition.primaryDisplay
220
160
  }
221
161
 
222
162
  // Get field list
@@ -1,12 +1,12 @@
1
- import { writable } from "svelte/store"
2
1
  import { derivedMemo } from "../../../utils"
2
+ import { derived } from "svelte/store"
3
3
 
4
4
  export const createStores = context => {
5
- const config = writable(context.props)
6
- const getProp = prop => derivedMemo(config, $config => $config[prop])
5
+ const { props } = context
6
+ const getProp = prop => derivedMemo(props, $props => $props[prop])
7
7
 
8
8
  // Derive and memoize some props so that we can react to them in isolation
9
- const tableId = getProp("tableId")
9
+ const datasource = getProp("datasource")
10
10
  const initialSortColumn = getProp("initialSortColumn")
11
11
  const initialSortOrder = getProp("initialSortOrder")
12
12
  const initialFilter = getProp("initialFilter")
@@ -17,8 +17,7 @@ export const createStores = context => {
17
17
  const notifyError = getProp("notifyError")
18
18
 
19
19
  return {
20
- config,
21
- tableId,
20
+ datasource,
22
21
  initialSortColumn,
23
22
  initialSortOrder,
24
23
  initialFilter,
@@ -29,3 +28,31 @@ export const createStores = context => {
29
28
  notifyError,
30
29
  }
31
30
  }
31
+
32
+ export const deriveStores = context => {
33
+ const { props, hasNonAutoColumn } = context
34
+
35
+ // Derive features
36
+ const config = derived(
37
+ [props, hasNonAutoColumn],
38
+ ([$props, $hasNonAutoColumn]) => {
39
+ let config = { ...$props }
40
+
41
+ // Disable some features if we're editing a view
42
+ if ($props.datasource?.type === "viewV2") {
43
+ config.canEditColumns = false
44
+ }
45
+
46
+ // Disable adding rows if we don't have any valid columns
47
+ if (!$hasNonAutoColumn) {
48
+ config.canAddRows = false
49
+ }
50
+
51
+ return config
52
+ }
53
+ )
54
+
55
+ return {
56
+ config,
57
+ }
58
+ }
@@ -0,0 +1,131 @@
1
+ import { derived, get, writable } from "svelte/store"
2
+
3
+ export const createStores = () => {
4
+ const definition = writable(null)
5
+
6
+ return {
7
+ definition,
8
+ }
9
+ }
10
+
11
+ export const deriveStores = context => {
12
+ const { definition, schemaOverrides, columnWhitelist } = context
13
+
14
+ const schema = derived(
15
+ [definition, schemaOverrides, columnWhitelist],
16
+ ([$definition, $schemaOverrides, $columnWhitelist]) => {
17
+ if (!$definition?.schema) {
18
+ return null
19
+ }
20
+ let newSchema = { ...$definition?.schema }
21
+
22
+ // Apply schema overrides
23
+ Object.keys($schemaOverrides || {}).forEach(field => {
24
+ if (newSchema[field]) {
25
+ newSchema[field] = {
26
+ ...newSchema[field],
27
+ ...$schemaOverrides[field],
28
+ }
29
+ }
30
+ })
31
+
32
+ // Apply whitelist if specified
33
+ if ($columnWhitelist?.length) {
34
+ Object.keys(newSchema).forEach(key => {
35
+ if (!$columnWhitelist.includes(key)) {
36
+ delete newSchema[key]
37
+ }
38
+ })
39
+ }
40
+
41
+ return newSchema
42
+ }
43
+ )
44
+
45
+ return {
46
+ schema,
47
+ }
48
+ }
49
+
50
+ export const createActions = context => {
51
+ const { datasource, definition, config, dispatch, table, viewV2 } = context
52
+
53
+ // Gets the appropriate API for the configured datasource type
54
+ const getAPI = () => {
55
+ const $datasource = get(datasource)
56
+ switch ($datasource?.type) {
57
+ case "table":
58
+ return table
59
+ case "viewV2":
60
+ return viewV2
61
+ default:
62
+ return null
63
+ }
64
+ }
65
+
66
+ // Refreshes the datasource definition
67
+ const refreshDefinition = async () => {
68
+ return await getAPI()?.actions.refreshDefinition()
69
+ }
70
+
71
+ // Saves the datasource definition
72
+ const saveDefinition = async newDefinition => {
73
+ // Update local state
74
+ definition.set(newDefinition)
75
+
76
+ // Update server
77
+ if (get(config).canSaveSchema) {
78
+ await getAPI()?.actions.saveDefinition(newDefinition)
79
+ }
80
+
81
+ // Broadcast change to external state can be updated, as this change
82
+ // will not be received by the builder websocket because we caused it ourselves
83
+ dispatch("updatedatasource", newDefinition)
84
+ }
85
+
86
+ // Adds a row to the datasource
87
+ const addRow = async row => {
88
+ return await getAPI()?.actions.addRow(row)
89
+ }
90
+
91
+ // Updates an existing row in the datasource
92
+ const updateRow = async row => {
93
+ return await getAPI()?.actions.updateRow(row)
94
+ }
95
+
96
+ // Deletes rows from the datasource
97
+ const deleteRows = async rows => {
98
+ return await getAPI()?.actions.deleteRows(rows)
99
+ }
100
+
101
+ // Gets a single row from a datasource
102
+ const getRow = async id => {
103
+ return await getAPI()?.actions.getRow(id)
104
+ }
105
+
106
+ // Checks if a certain datasource config is valid
107
+ const isDatasourceValid = datasource => {
108
+ return getAPI()?.actions.isDatasourceValid(datasource)
109
+ }
110
+
111
+ // Checks if this datasource can use a specific column by name
112
+ const canUseColumn = name => {
113
+ return getAPI()?.actions.canUseColumn(name)
114
+ }
115
+
116
+ return {
117
+ datasource: {
118
+ ...datasource,
119
+ actions: {
120
+ refreshDefinition,
121
+ saveDefinition,
122
+ addRow,
123
+ updateRow,
124
+ deleteRows,
125
+ getRow,
126
+ isDatasourceValid,
127
+ canUseColumn,
128
+ },
129
+ },
130
+ }
131
+ }
@@ -1,10 +1,10 @@
1
- import { writable } from "svelte/store"
1
+ import { writable, get } from "svelte/store"
2
2
 
3
3
  export const createStores = context => {
4
4
  const { props } = context
5
5
 
6
6
  // Initialise to default props
7
- const filter = writable(props.initialFilter)
7
+ const filter = writable(get(props).initialFilter)
8
8
 
9
9
  return {
10
10
  filter,