@budibase/frontend-core 3.2.28 → 3.2.30

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 (106) hide show
  1. package/package.json +9 -3
  2. package/src/api/ai.ts +17 -0
  3. package/src/api/analytics.ts +39 -0
  4. package/src/api/{app.js → app.ts} +84 -5
  5. package/src/api/attachments.ts +121 -0
  6. package/src/api/auditLogs.ts +35 -0
  7. package/src/api/{auth.js → auth.ts} +44 -7
  8. package/src/api/automations.ts +158 -0
  9. package/src/api/backups.ts +50 -0
  10. package/src/api/{configs.js → configs.ts} +31 -3
  11. package/src/api/datasources.ts +132 -0
  12. package/src/api/environmentVariables.ts +58 -0
  13. package/src/api/events.ts +21 -0
  14. package/src/api/flags.ts +48 -0
  15. package/src/api/{groups.js → groups.ts} +73 -17
  16. package/src/api/{index.js → index.ts} +89 -102
  17. package/src/api/layouts.ts +35 -0
  18. package/src/api/licensing.ts +107 -0
  19. package/src/api/{logs.js → logs.ts} +7 -1
  20. package/src/api/migrations.ts +19 -0
  21. package/src/api/{other.js → other.ts} +19 -12
  22. package/src/api/{permissions.js → permissions.ts} +31 -5
  23. package/src/api/{plugins.js → plugins.ts} +18 -1
  24. package/src/api/{queries.js → queries.ts} +39 -14
  25. package/src/api/relationships.ts +31 -0
  26. package/src/api/{roles.js → roles.ts} +22 -5
  27. package/src/api/routes.ts +30 -0
  28. package/src/api/{rowActions.js → rowActions.ts} +45 -27
  29. package/src/api/rows.ts +120 -0
  30. package/src/api/screens.ts +35 -0
  31. package/src/api/{self.js → self.ts} +20 -4
  32. package/src/api/tables.ts +192 -0
  33. package/src/api/templates.ts +57 -0
  34. package/src/api/types.ts +136 -0
  35. package/src/api/{user.js → user.ts} +111 -119
  36. package/src/api/{views.js → views.ts} +18 -7
  37. package/src/api/{viewsV2.js → viewsV2.ts} +30 -27
  38. package/src/components/grid/cells/AICell.svelte +1 -0
  39. package/src/components/grid/cells/LongFormCell.svelte +1 -0
  40. package/src/components/grid/cells/RelationshipCell.svelte +1 -2
  41. package/src/components/grid/cells/TextCell.svelte +3 -0
  42. package/src/components/grid/controls/MigrationModal.svelte +5 -5
  43. package/src/components/grid/layout/Grid.svelte +5 -8
  44. package/src/components/grid/lib/constants.js +1 -1
  45. package/src/components/grid/lib/{events.js → events.ts} +3 -3
  46. package/src/components/grid/lib/utils.js +2 -0
  47. package/src/components/grid/lib/utils.ts +32 -0
  48. package/src/components/grid/stores/bounds.ts +29 -0
  49. package/src/components/grid/stores/{cache.js → cache.ts} +21 -6
  50. package/src/components/grid/stores/{clipboard.js → clipboard.ts} +55 -19
  51. package/src/components/grid/stores/{columns.js → columns.ts} +47 -19
  52. package/src/components/grid/stores/{conditions.js → conditions.ts} +32 -12
  53. package/src/components/grid/stores/{config.js → config.ts} +16 -6
  54. package/src/components/grid/stores/{datasource.js → datasource.ts} +86 -36
  55. package/src/components/grid/stores/datasources/index.ts +31 -0
  56. package/src/components/grid/stores/datasources/{nonPlus.js → nonPlus.ts} +21 -11
  57. package/src/components/grid/stores/datasources/{table.js → table.ts} +39 -21
  58. package/src/components/grid/stores/datasources/{viewV2.js → viewV2.ts} +74 -28
  59. package/src/components/grid/stores/{filter.js → filter.ts} +39 -16
  60. package/src/components/grid/stores/index.ts +143 -0
  61. package/src/components/grid/stores/{menu.js → menu.ts} +31 -6
  62. package/src/components/grid/stores/{notifications.js → notifications.ts} +12 -2
  63. package/src/components/grid/stores/{pagination.js → pagination.ts} +2 -1
  64. package/src/components/grid/stores/{reorder.js → reorder.ts} +47 -15
  65. package/src/components/grid/stores/{resize.js → resize.ts} +28 -10
  66. package/src/components/grid/stores/{rows.js → rows.ts} +167 -53
  67. package/src/components/grid/stores/{scroll.js → scroll.ts} +28 -5
  68. package/src/components/grid/stores/{sort.js → sort.ts} +13 -3
  69. package/src/components/grid/stores/{ui.js → ui.ts} +77 -20
  70. package/src/components/grid/stores/{users.js → users.ts} +36 -9
  71. package/src/components/grid/stores/{validation.js → validation.ts} +35 -12
  72. package/src/components/grid/stores/{viewport.js → viewport.ts} +14 -3
  73. package/src/{constants.js → constants.ts} +2 -2
  74. package/src/fetch/QueryFetch.js +2 -2
  75. package/src/fetch/RelationshipFetch.js +9 -6
  76. package/src/fetch/TableFetch.js +1 -2
  77. package/src/fetch/ViewFetch.js +1 -1
  78. package/src/fetch/ViewV2Fetch.js +1 -2
  79. package/src/utils/memo.d.ts +10 -0
  80. package/src/utils/relatedColumns.ts +126 -0
  81. package/tsconfig.json +14 -0
  82. package/src/api/ai.js +0 -11
  83. package/src/api/analytics.js +0 -17
  84. package/src/api/attachments.js +0 -78
  85. package/src/api/auditLogs.js +0 -63
  86. package/src/api/automations.js +0 -111
  87. package/src/api/backups.js +0 -46
  88. package/src/api/datasources.js +0 -92
  89. package/src/api/environmentVariables.js +0 -36
  90. package/src/api/events.js +0 -13
  91. package/src/api/flags.js +0 -34
  92. package/src/api/hosting.js +0 -19
  93. package/src/api/layouts.js +0 -23
  94. package/src/api/licensing.js +0 -75
  95. package/src/api/migrations.js +0 -10
  96. package/src/api/relationships.js +0 -21
  97. package/src/api/routes.js +0 -19
  98. package/src/api/rows.js +0 -117
  99. package/src/api/screens.js +0 -23
  100. package/src/api/tables.js +0 -152
  101. package/src/api/templates.js +0 -35
  102. package/src/components/grid/stores/bounds.js +0 -16
  103. package/src/components/grid/stores/index.js +0 -73
  104. package/src/utils/relatedColumns.js +0 -103
  105. /package/src/{index.js → index.ts} +0 -0
  106. /package/src/utils/{index.js → index.ts} +0 -0
@@ -1,10 +1,54 @@
1
- import { derived, get } from "svelte/store"
1
+ import { derived, get, Readable, Writable } from "svelte/store"
2
2
  import { getDatasourceDefinition, getDatasourceSchema } from "../../../fetch"
3
3
  import { enrichSchemaWithRelColumns, memo } from "../../../utils"
4
4
  import { cloneDeep } from "lodash"
5
- import { ViewV2Type } from "@budibase/types"
5
+ import {
6
+ SaveRowRequest,
7
+ SaveTableRequest,
8
+ UIDatasource,
9
+ UIFieldMutation,
10
+ UIFieldSchema,
11
+ UIRow,
12
+ UpdateViewRequest,
13
+ ViewV2Type,
14
+ } from "@budibase/types"
15
+ import { Store as StoreContext, BaseStoreProps } from "."
16
+ import { DatasourceActions } from "./datasources"
17
+
18
+ interface DatasourceStore {
19
+ definition: Writable<UIDatasource | null>
20
+ schemaMutations: Writable<Record<string, UIFieldMutation>>
21
+ subSchemaMutations: Writable<Record<string, Record<string, UIFieldMutation>>>
22
+ }
23
+
24
+ interface DerivedDatasourceStore {
25
+ schema: Readable<Record<string, UIFieldSchema> | null>
26
+ enrichedSchema: Readable<Record<string, UIFieldSchema> | null>
27
+ hasBudibaseIdentifiers: Readable<boolean>
28
+ }
29
+
30
+ interface ActionDatasourceStore {
31
+ datasource: BaseStoreProps["datasource"] & {
32
+ actions: DatasourceActions & {
33
+ refreshDefinition: () => Promise<void>
34
+ changePrimaryDisplay: (column: string) => Promise<void>
35
+ addSchemaMutation: (field: string, mutation: UIFieldMutation) => void
36
+ addSubSchemaMutation: (
37
+ field: string,
38
+ fromField: string,
39
+ mutation: UIFieldMutation
40
+ ) => void
41
+ saveSchemaMutations: () => Promise<void>
42
+ resetSchemaMutations: () => void
43
+ }
44
+ }
45
+ }
46
+
47
+ export type Store = DatasourceStore &
48
+ DerivedDatasourceStore &
49
+ ActionDatasourceStore
6
50
 
7
- export const createStores = () => {
51
+ export const createStores = (): DatasourceStore => {
8
52
  const definition = memo(null)
9
53
  const schemaMutations = memo({})
10
54
  const subSchemaMutations = memo({})
@@ -16,7 +60,7 @@ export const createStores = () => {
16
60
  }
17
61
  }
18
62
 
19
- export const deriveStores = context => {
63
+ export const deriveStores = (context: StoreContext): DerivedDatasourceStore => {
20
64
  const {
21
65
  API,
22
66
  definition,
@@ -27,7 +71,7 @@ export const deriveStores = context => {
27
71
  } = context
28
72
 
29
73
  const schema = derived(definition, $definition => {
30
- let schema = getDatasourceSchema({
74
+ let schema: Record<string, UIFieldSchema> = getDatasourceSchema({
31
75
  API,
32
76
  datasource: get(datasource),
33
77
  definition: $definition,
@@ -40,7 +84,7 @@ export const deriveStores = context => {
40
84
  // Certain datasources like queries use primitives.
41
85
  Object.keys(schema || {}).forEach(key => {
42
86
  if (typeof schema[key] !== "object") {
43
- schema[key] = { type: schema[key] }
87
+ schema[key] = { name: key, type: schema[key] }
44
88
  }
45
89
  })
46
90
 
@@ -58,19 +102,18 @@ export const deriveStores = context => {
58
102
 
59
103
  const schemaWithRelatedColumns = enrichSchemaWithRelColumns($schema)
60
104
 
61
- const enrichedSchema = {}
62
- Object.keys(schemaWithRelatedColumns).forEach(field => {
105
+ const enrichedSchema: Record<string, UIFieldSchema> = {}
106
+ Object.keys(schemaWithRelatedColumns || {}).forEach(field => {
63
107
  enrichedSchema[field] = {
64
- ...schemaWithRelatedColumns[field],
108
+ ...schemaWithRelatedColumns?.[field],
65
109
  ...$schemaOverrides?.[field],
66
110
  ...$schemaMutations[field],
67
111
  }
68
112
 
69
113
  if ($subSchemaMutations[field]) {
70
114
  enrichedSchema[field].columns ??= {}
71
- for (const [fieldName, mutation] of Object.entries(
72
- $subSchemaMutations[field]
73
- )) {
115
+ for (const fieldName of Object.keys($subSchemaMutations[field])) {
116
+ const mutation = $subSchemaMutations[field][fieldName]
74
117
  enrichedSchema[field].columns[fieldName] = {
75
118
  ...enrichedSchema[field].columns[fieldName],
76
119
  ...mutation,
@@ -87,7 +130,7 @@ export const deriveStores = context => {
87
130
  ([$datasource, $definition]) => {
88
131
  let type = $datasource?.type
89
132
  if (type === "provider") {
90
- type = $datasource.value?.datasource?.type
133
+ type = ($datasource as any).value?.datasource?.type
91
134
  }
92
135
  // Handle calculation views
93
136
  if (type === "viewV2" && $definition?.type === ViewV2Type.CALCULATION) {
@@ -104,7 +147,7 @@ export const deriveStores = context => {
104
147
  }
105
148
  }
106
149
 
107
- export const createActions = context => {
150
+ export const createActions = (context: StoreContext): ActionDatasourceStore => {
108
151
  const {
109
152
  API,
110
153
  datasource,
@@ -147,21 +190,23 @@ export const createActions = context => {
147
190
  }
148
191
 
149
192
  // Saves the datasource definition
150
- const saveDefinition = async newDefinition => {
193
+ const saveDefinition = async (
194
+ newDefinition: SaveTableRequest | UpdateViewRequest
195
+ ) => {
151
196
  // Update local state
152
197
  const originalDefinition = get(definition)
153
- definition.set(newDefinition)
198
+ definition.set(newDefinition as UIDatasource)
154
199
 
155
200
  // Update server
156
201
  if (get(config).canSaveSchema) {
157
202
  try {
158
- await getAPI()?.actions.saveDefinition(newDefinition)
203
+ await getAPI()?.actions.saveDefinition(newDefinition as never)
159
204
 
160
205
  // Broadcast change so external state can be updated, as this change
161
206
  // will not be received by the builder websocket because we caused it
162
207
  // ourselves
163
208
  dispatch("updatedatasource", newDefinition)
164
- } catch (error) {
209
+ } catch (error: any) {
165
210
  const msg = error?.message || error || "Unknown error"
166
211
  get(notifications).error(`Error saving schema: ${msg}`)
167
212
 
@@ -172,8 +217,8 @@ export const createActions = context => {
172
217
  }
173
218
 
174
219
  // Updates the datasources primary display column
175
- const changePrimaryDisplay = async column => {
176
- let newDefinition = cloneDeep(get(definition))
220
+ const changePrimaryDisplay = async (column: string) => {
221
+ let newDefinition = cloneDeep(get(definition)!)
177
222
 
178
223
  // Update primary display
179
224
  newDefinition.primaryDisplay = column
@@ -183,12 +228,14 @@ export const createActions = context => {
183
228
  newDefinition.schema[column].constraints = {}
184
229
  }
185
230
  newDefinition.schema[column].constraints.presence = { allowEmpty: false }
186
- delete newDefinition.schema[column].default
187
- return await saveDefinition(newDefinition)
231
+ if ("default" in newDefinition.schema[column]) {
232
+ delete newDefinition.schema[column].default
233
+ }
234
+ return await saveDefinition(newDefinition as any)
188
235
  }
189
236
 
190
237
  // Adds a schema mutation for a single field
191
- const addSchemaMutation = (field, mutation) => {
238
+ const addSchemaMutation = (field: string, mutation: UIFieldMutation) => {
192
239
  if (!field || !mutation) {
193
240
  return
194
241
  }
@@ -204,7 +251,11 @@ export const createActions = context => {
204
251
  }
205
252
 
206
253
  // Adds a nested schema mutation for a single field
207
- const addSubSchemaMutation = (field, fromField, mutation) => {
254
+ const addSubSchemaMutation = (
255
+ field: string,
256
+ fromField: string,
257
+ mutation: UIFieldMutation
258
+ ) => {
208
259
  if (!field || !fromField || !mutation) {
209
260
  return
210
261
  }
@@ -231,8 +282,8 @@ export const createActions = context => {
231
282
  const $definition = get(definition)
232
283
  const $schemaMutations = get(schemaMutations)
233
284
  const $subSchemaMutations = get(subSchemaMutations)
234
- const $schema = get(schema)
235
- let newSchema = {}
285
+ const $schema = get(schema) || {}
286
+ let newSchema: Record<string, UIFieldSchema> = {}
236
287
 
237
288
  // Build new updated datasource schema
238
289
  Object.keys($schema).forEach(column => {
@@ -242,9 +293,8 @@ export const createActions = context => {
242
293
  }
243
294
  if ($subSchemaMutations[column]) {
244
295
  newSchema[column].columns ??= {}
245
- for (const [fieldName, mutation] of Object.entries(
246
- $subSchemaMutations[column]
247
- )) {
296
+ for (const fieldName of Object.keys($subSchemaMutations[column])) {
297
+ const mutation = $subSchemaMutations[column][fieldName]
248
298
  newSchema[column].columns[fieldName] = {
249
299
  ...newSchema[column].columns[fieldName],
250
300
  ...mutation,
@@ -257,7 +307,7 @@ export const createActions = context => {
257
307
  await saveDefinition({
258
308
  ...$definition,
259
309
  schema: newSchema,
260
- })
310
+ } as any)
261
311
  resetSchemaMutations()
262
312
  }
263
313
 
@@ -267,32 +317,32 @@ export const createActions = context => {
267
317
  }
268
318
 
269
319
  // Adds a row to the datasource
270
- const addRow = async row => {
320
+ const addRow = async (row: SaveRowRequest) => {
271
321
  return await getAPI()?.actions.addRow(row)
272
322
  }
273
323
 
274
324
  // Updates an existing row in the datasource
275
- const updateRow = async row => {
325
+ const updateRow = async (row: SaveRowRequest) => {
276
326
  return await getAPI()?.actions.updateRow(row)
277
327
  }
278
328
 
279
329
  // Deletes rows from the datasource
280
- const deleteRows = async rows => {
330
+ const deleteRows = async (rows: UIRow[]) => {
281
331
  return await getAPI()?.actions.deleteRows(rows)
282
332
  }
283
333
 
284
334
  // Gets a single row from a datasource
285
- const getRow = async id => {
335
+ const getRow = async (id: string) => {
286
336
  return await getAPI()?.actions.getRow(id)
287
337
  }
288
338
 
289
339
  // Checks if a certain datasource config is valid
290
- const isDatasourceValid = datasource => {
340
+ const isDatasourceValid = (datasource: UIDatasource) => {
291
341
  return getAPI()?.actions.isDatasourceValid(datasource)
292
342
  }
293
343
 
294
344
  // Checks if this datasource can use a specific column by name
295
- const canUseColumn = name => {
345
+ const canUseColumn = (name: string) => {
296
346
  return getAPI()?.actions.canUseColumn(name)
297
347
  }
298
348
 
@@ -0,0 +1,31 @@
1
+ import {
2
+ SaveRowRequest,
3
+ SaveTableRequest,
4
+ UIDatasource,
5
+ UIRow,
6
+ UpdateViewRequest,
7
+ } from "@budibase/types"
8
+
9
+ interface DatasourceBaseActions<
10
+ TSaveDefinitionRequest = UpdateViewRequest | SaveTableRequest
11
+ > {
12
+ saveDefinition: (newDefinition: TSaveDefinitionRequest) => Promise<void>
13
+ addRow: (row: SaveRowRequest) => Promise<UIRow | undefined>
14
+ updateRow: (row: SaveRowRequest) => Promise<UIRow | undefined>
15
+ deleteRows: (rows: UIRow[]) => Promise<void>
16
+ getRow: (id: string) => Promise<UIRow | void>
17
+ isDatasourceValid: (datasource: UIDatasource) => boolean | void
18
+ canUseColumn: (name: string) => boolean | void
19
+ }
20
+
21
+ export interface DatasourceTableActions
22
+ extends DatasourceBaseActions<SaveTableRequest> {}
23
+
24
+ export interface DatasourceViewActions
25
+ extends DatasourceBaseActions<UpdateViewRequest> {}
26
+
27
+ export interface DatasourceNonPlusActions
28
+ extends DatasourceBaseActions<never> {}
29
+
30
+ export type DatasourceActions =
31
+ | DatasourceTableActions & DatasourceViewActions & DatasourceNonPlusActions
@@ -1,7 +1,17 @@
1
- import { SortOrder } from "@budibase/types"
1
+ import { SortOrder, UIDatasource } from "@budibase/types"
2
2
  import { get } from "svelte/store"
3
+ import { Store as StoreContext } from ".."
4
+ import { DatasourceNonPlusActions } from "."
3
5
 
4
- export const createActions = context => {
6
+ interface NonPlusActions {
7
+ nonPlus: {
8
+ actions: DatasourceNonPlusActions
9
+ }
10
+ }
11
+
12
+ export type Store = NonPlusActions
13
+
14
+ export const createActions = (context: StoreContext): NonPlusActions => {
5
15
  const { columns, table, viewV2 } = context
6
16
 
7
17
  const saveDefinition = async () => {
@@ -20,7 +30,7 @@ export const createActions = context => {
20
30
  throw "This datasource does not support fetching individual rows"
21
31
  }
22
32
 
23
- const isDatasourceValid = datasource => {
33
+ const isDatasourceValid = (datasource: UIDatasource) => {
24
34
  // There are many different types and shapes of datasource, so we only
25
35
  // check that we aren't null
26
36
  return (
@@ -30,7 +40,7 @@ export const createActions = context => {
30
40
  )
31
41
  }
32
42
 
33
- const canUseColumn = name => {
43
+ const canUseColumn = (name: string) => {
34
44
  return get(columns).some(col => col.name === name)
35
45
  }
36
46
 
@@ -50,11 +60,11 @@ export const createActions = context => {
50
60
  }
51
61
 
52
62
  // Small util to compare datasource definitions
53
- const isSameDatasource = (a, b) => {
63
+ const isSameDatasource = (a: any, b: any) => {
54
64
  return JSON.stringify(a) === JSON.stringify(b)
55
65
  }
56
66
 
57
- export const initialise = context => {
67
+ export const initialise = (context: StoreContext) => {
58
68
  const {
59
69
  datasource,
60
70
  sort,
@@ -69,7 +79,7 @@ export const initialise = context => {
69
79
  } = context
70
80
  // Keep a list of subscriptions so that we can clear them when the datasource
71
81
  // config changes
72
- let unsubscribers = []
82
+ let unsubscribers: any[] = []
73
83
 
74
84
  // Observe datasource changes and apply logic for view V2 datasources
75
85
  datasource.subscribe($datasource => {
@@ -81,7 +91,7 @@ export const initialise = context => {
81
91
  }
82
92
 
83
93
  // Wipe state
84
- filter.set(get(initialFilter))
94
+ filter.set(get(initialFilter) ?? undefined)
85
95
  inlineFilters.set([])
86
96
  sort.set({
87
97
  column: get(initialSortColumn),
@@ -96,7 +106,7 @@ export const initialise = context => {
96
106
  if (!isSameDatasource($fetch?.options?.datasource, $datasource)) {
97
107
  return
98
108
  }
99
- $fetch.update({
109
+ $fetch?.update({
100
110
  filter: $allFilters,
101
111
  })
102
112
  })
@@ -110,9 +120,9 @@ export const initialise = context => {
110
120
  if (!isSameDatasource($fetch?.options?.datasource, $datasource)) {
111
121
  return
112
122
  }
113
- $fetch.update({
123
+ $fetch?.update({
114
124
  sortOrder: $sort.order || SortOrder.ASCENDING,
115
- sortColumn: $sort.column,
125
+ sortColumn: $sort.column ?? undefined,
116
126
  })
117
127
  })
118
128
  )
@@ -1,37 +1,50 @@
1
- import { SortOrder } from "@budibase/types"
1
+ import {
2
+ Row,
3
+ SaveRowRequest,
4
+ SaveTableRequest,
5
+ SortOrder,
6
+ UIDatasource,
7
+ } from "@budibase/types"
2
8
  import { get } from "svelte/store"
9
+ import { Store as StoreContext } from ".."
10
+ import { DatasourceTableActions } from "."
3
11
 
4
12
  const SuppressErrors = true
5
13
 
6
- export const createActions = context => {
14
+ interface TableActions {
15
+ table: {
16
+ actions: DatasourceTableActions
17
+ }
18
+ }
19
+
20
+ export type Store = TableActions
21
+
22
+ export const createActions = (context: StoreContext): TableActions => {
7
23
  const { API, datasource, columns } = context
8
24
 
9
- const saveDefinition = async newDefinition => {
25
+ const saveDefinition = async (newDefinition: SaveTableRequest) => {
10
26
  await API.saveTable(newDefinition)
11
27
  }
12
28
 
13
- const saveRow = async row => {
29
+ const saveRow = async (row: SaveRowRequest) => {
14
30
  row = {
15
31
  ...row,
16
32
  tableId: get(datasource)?.tableId,
17
33
  }
18
- return await API.saveRow(row, SuppressErrors)
34
+ const newRow = await API.saveRow(row, SuppressErrors)
35
+ return { ...newRow, _id: newRow._id! }
19
36
  }
20
37
 
21
- const deleteRows = async rows => {
22
- await API.deleteRows({
23
- tableId: get(datasource).tableId,
24
- rows,
25
- })
38
+ const deleteRows = async (rows: Row[]) => {
39
+ await API.deleteRows(get(datasource).tableId, rows)
26
40
  }
27
41
 
28
- const isDatasourceValid = datasource => {
29
- return datasource?.type === "table" && datasource?.tableId
42
+ const isDatasourceValid = (datasource: UIDatasource) => {
43
+ return datasource?.type === "table" && !!datasource?.tableId
30
44
  }
31
45
 
32
- const getRow = async id => {
33
- const res = await API.searchTable({
34
- tableId: get(datasource).tableId,
46
+ const getRow = async (id: any) => {
47
+ const res = await API.searchTable(get(datasource).tableId, {
35
48
  limit: 1,
36
49
  query: {
37
50
  equal: {
@@ -40,10 +53,15 @@ export const createActions = context => {
40
53
  },
41
54
  paginate: false,
42
55
  })
43
- return res?.rows?.[0]
56
+ const row = res?.rows?.[0]
57
+ if (!row) {
58
+ return
59
+ }
60
+
61
+ return { ...row, _id: row._id! }
44
62
  }
45
63
 
46
- const canUseColumn = name => {
64
+ const canUseColumn = (name: string) => {
47
65
  return get(columns).some(col => col.name === name)
48
66
  }
49
67
 
@@ -62,7 +80,7 @@ export const createActions = context => {
62
80
  }
63
81
  }
64
82
 
65
- export const initialise = context => {
83
+ export const initialise = (context: StoreContext) => {
66
84
  const {
67
85
  datasource,
68
86
  fetch,
@@ -78,7 +96,7 @@ export const initialise = context => {
78
96
 
79
97
  // Keep a list of subscriptions so that we can clear them when the datasource
80
98
  // config changes
81
- let unsubscribers = []
99
+ let unsubscribers: any[] = []
82
100
 
83
101
  // Observe datasource changes and apply logic for table datasources
84
102
  datasource.subscribe($datasource => {
@@ -90,7 +108,7 @@ export const initialise = context => {
90
108
  }
91
109
 
92
110
  // Wipe state
93
- filter.set(get(initialFilter))
111
+ filter.set(get(initialFilter) ?? undefined)
94
112
  inlineFilters.set([])
95
113
  sort.set({
96
114
  column: get(initialSortColumn),
@@ -121,7 +139,7 @@ export const initialise = context => {
121
139
  }
122
140
  $fetch.update({
123
141
  sortOrder: $sort.order || SortOrder.ASCENDING,
124
- sortColumn: $sort.column,
142
+ sortColumn: $sort.column ?? undefined,
125
143
  })
126
144
  })
127
145
  )
@@ -1,38 +1,53 @@
1
1
  import { get } from "svelte/store"
2
- import { SortOrder } from "@budibase/types"
2
+ import {
3
+ Row,
4
+ SaveRowRequest,
5
+ SortOrder,
6
+ UIDatasource,
7
+ UIView,
8
+ UpdateViewRequest,
9
+ } from "@budibase/types"
10
+ import { Store as StoreContext } from ".."
11
+ import { DatasourceViewActions } from "."
3
12
 
4
13
  const SuppressErrors = true
5
14
 
6
- export const createActions = context => {
15
+ interface ViewActions {
16
+ viewV2: {
17
+ actions: DatasourceViewActions
18
+ }
19
+ }
20
+
21
+ export type Store = ViewActions
22
+
23
+ export const createActions = (context: StoreContext): ViewActions => {
7
24
  const { API, datasource, columns } = context
8
25
 
9
- const saveDefinition = async newDefinition => {
26
+ const saveDefinition = async (newDefinition: UpdateViewRequest) => {
10
27
  await API.viewV2.update(newDefinition)
11
28
  }
12
29
 
13
- const saveRow = async row => {
30
+ const saveRow = async (row: SaveRowRequest) => {
14
31
  const $datasource = get(datasource)
15
32
  row = {
16
33
  ...row,
17
34
  tableId: $datasource?.tableId,
18
35
  _viewId: $datasource?.id,
19
36
  }
37
+ const newRow = await API.saveRow(row, SuppressErrors)
20
38
  return {
21
- ...(await API.saveRow(row, SuppressErrors)),
39
+ ...newRow,
40
+ _id: newRow._id!,
22
41
  _viewId: row._viewId,
23
42
  }
24
43
  }
25
44
 
26
- const deleteRows = async rows => {
27
- await API.deleteRows({
28
- tableId: get(datasource).id,
29
- rows,
30
- })
45
+ const deleteRows = async (rows: Row[]) => {
46
+ await API.deleteRows(get(datasource).id, rows)
31
47
  }
32
48
 
33
- const getRow = async id => {
34
- const res = await API.viewV2.fetch({
35
- viewId: get(datasource).id,
49
+ const getRow = async (id: string) => {
50
+ const res = await API.viewV2.fetch(get(datasource).id, {
36
51
  limit: 1,
37
52
  query: {
38
53
  equal: {
@@ -41,16 +56,21 @@ export const createActions = context => {
41
56
  },
42
57
  paginate: false,
43
58
  })
44
- return res?.rows?.[0]
59
+ const row = res?.rows?.[0]
60
+ if (!row) {
61
+ return
62
+ }
63
+
64
+ return { ...row, _id: row._id! }
45
65
  }
46
66
 
47
- const isDatasourceValid = datasource => {
67
+ const isDatasourceValid = (datasource: UIDatasource) => {
48
68
  return (
49
- datasource?.type === "viewV2" && datasource?.id && datasource?.tableId
69
+ datasource?.type === "viewV2" && !!datasource?.id && !!datasource?.tableId
50
70
  )
51
71
  }
52
72
 
53
- const canUseColumn = name => {
73
+ const canUseColumn = (name: string) => {
54
74
  return get(columns).some(col => col.name === name && col.visible)
55
75
  }
56
76
 
@@ -69,7 +89,7 @@ export const createActions = context => {
69
89
  }
70
90
  }
71
91
 
72
- export const initialise = context => {
92
+ export const initialise = (context: StoreContext) => {
73
93
  const {
74
94
  definition,
75
95
  datasource,
@@ -89,7 +109,7 @@ export const initialise = context => {
89
109
 
90
110
  // Keep a list of subscriptions so that we can clear them when the datasource
91
111
  // config changes
92
- let unsubscribers = []
112
+ let unsubscribers: any[] = []
93
113
 
94
114
  // Observe datasource changes and apply logic for view V2 datasources
95
115
  datasource.subscribe($datasource => {
@@ -101,7 +121,7 @@ export const initialise = context => {
101
121
  }
102
122
 
103
123
  // Reset state for new view
104
- filter.set(get(initialFilter))
124
+ filter.set(get(initialFilter) ?? undefined)
105
125
  inlineFilters.set([])
106
126
  sort.set({
107
127
  column: get(initialSortColumn),
@@ -131,20 +151,46 @@ export const initialise = context => {
131
151
  })
132
152
  )
133
153
 
154
+ function sortHasChanged(
155
+ newSort: {
156
+ column: string | null | undefined
157
+ order: SortOrder
158
+ },
159
+ existingSort?: {
160
+ field: string
161
+ order?: SortOrder
162
+ }
163
+ ) {
164
+ const newColumn = newSort.column ?? null
165
+ const existingColumn = existingSort?.field ?? null
166
+ if (newColumn !== existingColumn) {
167
+ return true
168
+ }
169
+
170
+ if (!newColumn) {
171
+ return false
172
+ }
173
+
174
+ const newOrder = newSort.order ?? null
175
+ const existingOrder = existingSort?.order ?? null
176
+ if (newOrder !== existingOrder) {
177
+ return true
178
+ }
179
+
180
+ return false
181
+ }
182
+
134
183
  // When sorting changes, ensure view definition is kept up to date
135
184
  unsubscribers.push(
136
185
  sort.subscribe(async $sort => {
137
186
  // Ensure we're updating the correct view
138
- const $view = get(definition)
187
+ const $view = get(definition) as UIView
139
188
  if ($view?.id !== $datasource.id) {
140
189
  return
141
190
  }
142
191
 
143
192
  // Skip if nothing actually changed
144
- if (
145
- $sort?.column === $view.sort?.field &&
146
- $sort?.order === $view.sort?.order
147
- ) {
193
+ if (!sortHasChanged($sort, $view.sort)) {
148
194
  return
149
195
  }
150
196
 
@@ -153,7 +199,7 @@ export const initialise = context => {
153
199
  await datasource.actions.saveDefinition({
154
200
  ...$view,
155
201
  sort: {
156
- field: $sort.column,
202
+ field: $sort.column!,
157
203
  order: $sort.order || SortOrder.ASCENDING,
158
204
  },
159
205
  })
@@ -167,7 +213,7 @@ export const initialise = context => {
167
213
  }
168
214
  $fetch.update({
169
215
  sortOrder: $sort.order,
170
- sortColumn: $sort.column,
216
+ sortColumn: $sort.column ?? undefined,
171
217
  })
172
218
  })
173
219
  )
@@ -186,7 +232,7 @@ export const initialise = context => {
186
232
  await datasource.actions.saveDefinition({
187
233
  ...$view,
188
234
  queryUI: $filter,
189
- })
235
+ } as never as UpdateViewRequest)
190
236
 
191
237
  // Refresh data since view definition changed
192
238
  await rows.actions.refreshData()