@budibase/frontend-core 2.33.13 → 3.0.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 (53) hide show
  1. package/package.json +5 -5
  2. package/src/api/automations.js +2 -7
  3. package/src/api/index.js +2 -0
  4. package/src/api/rowActions.js +90 -0
  5. package/src/api/tables.js +1 -1
  6. package/src/api/viewsV2.js +1 -0
  7. package/src/components/CoreFilterBuilder.svelte +532 -0
  8. package/src/components/FilterField.svelte +319 -0
  9. package/src/components/FilterUsers.svelte +2 -1
  10. package/src/components/grid/cells/AICell.svelte +99 -0
  11. package/src/components/grid/cells/DataCell.svelte +1 -1
  12. package/src/components/grid/cells/GridCell.svelte +6 -1
  13. package/src/components/grid/cells/HeaderCell.svelte +20 -11
  14. package/src/components/grid/cells/NumberCell.svelte +23 -1
  15. package/src/components/grid/cells/RelationshipCell.svelte +1 -3
  16. package/src/components/grid/cells/RoleCell.svelte +45 -0
  17. package/src/components/grid/cells/TextCell.svelte +3 -1
  18. package/src/components/grid/layout/ButtonColumn.svelte +67 -36
  19. package/src/components/grid/layout/Grid.svelte +22 -27
  20. package/src/components/grid/lib/constants.js +2 -0
  21. package/src/components/grid/lib/renderers.js +9 -0
  22. package/src/components/grid/lib/utils.js +13 -31
  23. package/src/components/grid/lib/websocket.js +9 -0
  24. package/src/components/grid/overlays/GridPopover.svelte +4 -2
  25. package/src/components/grid/overlays/MenuOverlay.svelte +19 -0
  26. package/src/components/grid/stores/columns.js +2 -1
  27. package/src/components/grid/stores/config.js +12 -3
  28. package/src/components/grid/stores/datasource.js +27 -10
  29. package/src/components/grid/stores/datasources/nonPlus.js +3 -2
  30. package/src/components/grid/stores/datasources/table.js +3 -2
  31. package/src/components/grid/stores/datasources/viewV2.js +58 -27
  32. package/src/components/grid/stores/filter.js +25 -7
  33. package/src/components/grid/stores/rows.js +11 -6
  34. package/src/components/grid/stores/sort.js +7 -3
  35. package/src/components/index.js +1 -1
  36. package/src/constants.js +17 -30
  37. package/src/fetch/DataFetch.js +17 -9
  38. package/src/fetch/TableFetch.js +2 -1
  39. package/src/fetch/UserFetch.js +7 -8
  40. package/src/fetch/ViewV2Fetch.js +18 -13
  41. package/src/utils/index.js +1 -1
  42. package/src/utils/relatedColumns.js +6 -10
  43. package/src/utils/roles.js +0 -13
  44. package/src/utils/schema.js +24 -0
  45. package/src/utils/table.js +6 -6
  46. package/src/utils/utils.js +1 -1
  47. package/src/components/FilterBuilder.svelte +0 -379
  48. package/src/components/grid/controls/ColumnsSettingButton.svelte +0 -41
  49. package/src/components/grid/controls/ColumnsSettingContent.svelte +0 -270
  50. package/src/components/grid/controls/SizeButton.svelte +0 -136
  51. package/src/components/grid/controls/SortButton.svelte +0 -96
  52. package/src/components/grid/controls/ToggleActionButtonGroup.svelte +0 -41
  53. package/src/utils/theme.js +0 -12
@@ -1,4 +1,5 @@
1
1
  import { get } from "svelte/store"
2
+ import { SortOrder } from "@budibase/types"
2
3
 
3
4
  const SuppressErrors = true
4
5
 
@@ -29,8 +30,18 @@ export const createActions = context => {
29
30
  })
30
31
  }
31
32
 
32
- const getRow = () => {
33
- throw "Views don't support fetching individual rows"
33
+ const getRow = async id => {
34
+ const res = await API.viewV2.fetch({
35
+ viewId: get(datasource).id,
36
+ limit: 1,
37
+ query: {
38
+ equal: {
39
+ _id: id,
40
+ },
41
+ },
42
+ paginate: false,
43
+ })
44
+ return res?.rows?.[0]
34
45
  }
35
46
 
36
47
  const isDatasourceValid = datasource => {
@@ -94,12 +105,15 @@ export const initialise = context => {
94
105
  inlineFilters.set([])
95
106
  sort.set({
96
107
  column: get(initialSortColumn),
97
- order: get(initialSortOrder) || "ascending",
108
+ order: get(initialSortOrder) || SortOrder.ASCENDING,
98
109
  })
99
110
 
100
- // Keep sort and filter state in line with the view definition
111
+ // Keep sort and filter state in line with the view definition when in builder
101
112
  unsubscribers.push(
102
113
  definition.subscribe($definition => {
114
+ if (!get(config).canSaveSchema) {
115
+ return
116
+ }
103
117
  if ($definition?.id !== $datasource.id) {
104
118
  return
105
119
  }
@@ -107,12 +121,12 @@ export const initialise = context => {
107
121
  if (!get(initialSortColumn)) {
108
122
  sort.set({
109
123
  column: $definition.sort?.field,
110
- order: $definition.sort?.order || "ascending",
124
+ order: $definition.sort?.order || SortOrder.ASCENDING,
111
125
  })
112
126
  }
113
127
  // Only override filter state if we don't have an initial filter
114
128
  if (!get(initialFilter)) {
115
- filter.set($definition.query)
129
+ filter.set($definition.queryUI)
116
130
  }
117
131
  })
118
132
  )
@@ -140,7 +154,7 @@ export const initialise = context => {
140
154
  ...$view,
141
155
  sort: {
142
156
  field: $sort.column,
143
- order: $sort.order || "ascending",
157
+ order: $sort.order || SortOrder.ASCENDING,
144
158
  },
145
159
  })
146
160
  }
@@ -148,7 +162,7 @@ export const initialise = context => {
148
162
  // Also update the fetch to ensure the new sort is respected.
149
163
  // Ensure we're updating the correct fetch.
150
164
  const $fetch = get(fetch)
151
- if ($fetch?.options?.datasource?.tableId !== $datasource.tableId) {
165
+ if ($fetch?.options?.datasource?.id !== $datasource.id) {
152
166
  return
153
167
  }
154
168
  $fetch.update({
@@ -161,32 +175,49 @@ export const initialise = context => {
161
175
  // When filters change, ensure view definition is kept up to date
162
176
  unsubscribers?.push(
163
177
  filter.subscribe(async $filter => {
164
- // If we can mutate schema then update the view definition
165
- if (get(config).canSaveSchema) {
166
- // Ensure we're updating the correct view
167
- const $view = get(definition)
168
- if ($view?.id !== $datasource.id) {
169
- return
170
- }
171
- if (JSON.stringify($filter) !== JSON.stringify($view.query)) {
172
- await datasource.actions.saveDefinition({
173
- ...$view,
174
- query: $filter,
175
- })
176
- }
178
+ if (!get(config).canSaveSchema) {
179
+ return
180
+ }
181
+ const $view = get(definition)
182
+ if ($view?.id !== $datasource.id) {
183
+ return
184
+ }
185
+ if (JSON.stringify($filter) !== JSON.stringify($view.queryUI)) {
186
+ await datasource.actions.saveDefinition({
187
+ ...$view,
188
+ queryUI: $filter,
189
+ })
190
+
191
+ // Refresh data since view definition changed
192
+ await rows.actions.refreshData()
177
193
  }
178
194
  })
179
195
  )
180
196
 
181
- // Keep fetch up to date with filters.
182
- // If we're able to save filters against the view then we only need to apply
183
- // inline filters to the fetch, as saved filters are applied server side.
184
- // If we can't save filters, then all filters must be applied to the fetch.
197
+ // Keep fetch up to date with inline filters when in the data section
198
+ unsubscribers.push(
199
+ inlineFilters.subscribe($inlineFilters => {
200
+ if (!get(config).canSaveSchema) {
201
+ return
202
+ }
203
+ const $fetch = get(fetch)
204
+ if ($fetch?.options?.datasource?.id !== $datasource.id) {
205
+ return
206
+ }
207
+ $fetch.update({
208
+ filter: $inlineFilters,
209
+ })
210
+ })
211
+ )
212
+
213
+ // Keep fetch up to date with all filters when not in the data section
185
214
  unsubscribers.push(
186
215
  allFilters.subscribe($allFilters => {
187
- // Ensure we're updating the correct fetch
216
+ if (get(config).canSaveSchema) {
217
+ return
218
+ }
188
219
  const $fetch = get(fetch)
189
- if ($fetch?.options?.datasource?.tableId !== $datasource.tableId) {
220
+ if ($fetch?.options?.datasource?.id !== $datasource.id) {
190
221
  return
191
222
  }
192
223
  $fetch.update({
@@ -1,12 +1,13 @@
1
- import { writable, get, derived } from "svelte/store"
2
- import { FieldType } from "@budibase/types"
1
+ import { get, derived } from "svelte/store"
2
+ import { FieldType, UILogicalOperator } from "@budibase/types"
3
+ import { memo } from "../../../utils/memo"
3
4
 
4
5
  export const createStores = context => {
5
6
  const { props } = context
6
7
 
7
8
  // Initialise to default props
8
- const filter = writable(get(props).initialFilter)
9
- const inlineFilters = writable([])
9
+ const filter = memo(get(props).initialFilter)
10
+ const inlineFilters = memo([])
10
11
 
11
12
  return {
12
13
  filter,
@@ -16,11 +17,29 @@ export const createStores = context => {
16
17
 
17
18
  export const deriveStores = context => {
18
19
  const { filter, inlineFilters } = context
19
-
20
20
  const allFilters = derived(
21
21
  [filter, inlineFilters],
22
22
  ([$filter, $inlineFilters]) => {
23
- return [...($filter || []), ...$inlineFilters]
23
+ // Just use filter prop if no inline filters
24
+ if (!$inlineFilters?.length) {
25
+ return $filter
26
+ }
27
+ let allFilters = {
28
+ logicalOperator: UILogicalOperator.ALL,
29
+ groups: [
30
+ {
31
+ logicalOperator: UILogicalOperator.ALL,
32
+ filters: $inlineFilters,
33
+ },
34
+ ],
35
+ }
36
+ // Just use inline if no filter
37
+ if (!$filter?.groups?.length) {
38
+ return allFilters
39
+ }
40
+ // Join them together if both
41
+ allFilters.groups = [...allFilters.groups, ...$filter.groups]
42
+ return allFilters
24
43
  }
25
44
  )
26
45
 
@@ -54,7 +73,6 @@ export const createActions = context => {
54
73
  inlineFilter.operator = "contains"
55
74
  }
56
75
 
57
- // Add this filter
58
76
  inlineFilters.update($inlineFilters => {
59
77
  // Remove any existing inline filter for this column
60
78
  $inlineFilters = $inlineFilters?.filter(x => x.id !== filterId)
@@ -1,7 +1,12 @@
1
1
  import { writable, derived, get } from "svelte/store"
2
2
  import { fetchData } from "../../../fetch"
3
3
  import { NewRowID, RowPageSize } from "../lib/constants"
4
- import { getCellID, parseCellID } from "../lib/utils"
4
+ import {
5
+ generateRowID,
6
+ getCellID,
7
+ isGeneratedRowID,
8
+ parseCellID,
9
+ } from "../lib/utils"
5
10
  import { tick } from "svelte"
6
11
  import { Helpers } from "@budibase/bbui"
7
12
  import { sleep } from "../../../utils/utils"
@@ -634,10 +639,10 @@ export const createActions = context => {
634
639
  newRow = newRows[i]
635
640
 
636
641
  // Ensure we have a unique _id.
637
- // This means generating one for non DS+, overwriting any that may already
638
- // exist as we cannot allow duplicates.
639
- if (!$hasBudibaseIdentifiers) {
640
- newRow._id = Helpers.uuid()
642
+ // We generate one for non DS+ where required, but trust that any existing
643
+ // _id values are unique (e.g. Mongo)
644
+ if (!$hasBudibaseIdentifiers && !newRow._id?.length) {
645
+ newRow._id = generateRowID()
641
646
  }
642
647
 
643
648
  if (!rowCacheMap[newRow._id]) {
@@ -674,7 +679,7 @@ export const createActions = context => {
674
679
  let clone = { ...row }
675
680
  delete clone.__idx
676
681
  delete clone.__metadata
677
- if (!get(hasBudibaseIdentifiers)) {
682
+ if (!get(hasBudibaseIdentifiers) && isGeneratedRowID(clone._id)) {
678
683
  delete clone._id
679
684
  }
680
685
  return clone
@@ -1,5 +1,6 @@
1
1
  import { derived, get } from "svelte/store"
2
2
  import { memo } from "../../../utils"
3
+ import { SortOrder } from "@budibase/types"
3
4
 
4
5
  export const createStores = context => {
5
6
  const { props } = context
@@ -8,7 +9,7 @@ export const createStores = context => {
8
9
  // Initialise to default props
9
10
  const sort = memo({
10
11
  column: $props.initialSortColumn,
11
- order: $props.initialSortOrder || "ascending",
12
+ order: $props.initialSortOrder || SortOrder.ASCENDING,
12
13
  })
13
14
 
14
15
  return {
@@ -24,7 +25,10 @@ export const initialise = context => {
24
25
  sort.update(state => ({ ...state, column: newSortColumn }))
25
26
  })
26
27
  initialSortOrder.subscribe(newSortOrder => {
27
- sort.update(state => ({ ...state, order: newSortOrder || "ascending" }))
28
+ sort.update(state => ({
29
+ ...state,
30
+ order: newSortOrder || SortOrder.ASCENDING,
31
+ }))
28
32
  })
29
33
 
30
34
  // Derive if the current sort column exists in the schema
@@ -40,7 +44,7 @@ export const initialise = context => {
40
44
  if (!exists) {
41
45
  sort.set({
42
46
  column: null,
43
- order: "ascending",
47
+ order: SortOrder.ASCENDING,
44
48
  })
45
49
  }
46
50
  })
@@ -7,5 +7,5 @@ export { default as UserAvatars } from "./UserAvatars.svelte"
7
7
  export { default as Updating } from "./Updating.svelte"
8
8
  export { Grid } from "./grid"
9
9
  export { default as ClientAppSkeleton } from "./ClientAppSkeleton.svelte"
10
- export { default as FilterBuilder } from "./FilterBuilder.svelte"
10
+ export { default as CoreFilterBuilder } from "./CoreFilterBuilder.svelte"
11
11
  export { default as FilterUsers } from "./FilterUsers.svelte"
package/src/constants.js CHANGED
@@ -108,35 +108,6 @@ export const Roles = {
108
108
  CREATOR: "CREATOR",
109
109
  }
110
110
 
111
- export const Themes = [
112
- {
113
- class: "lightest",
114
- name: "Lightest",
115
- },
116
- {
117
- class: "light",
118
- name: "Light",
119
- },
120
- {
121
- class: "dark",
122
- name: "Dark",
123
- },
124
- {
125
- class: "darkest",
126
- name: "Darkest",
127
- },
128
- {
129
- class: "nord",
130
- name: "Nord",
131
- base: "darkest",
132
- },
133
- {
134
- class: "midnight",
135
- name: "Midnight",
136
- base: "darkest",
137
- },
138
- ]
139
-
140
111
  export const EventPublishType = {
141
112
  ENV_VAR_UPGRADE_PANEL_OPENED: "environment_variable_upgrade_panel_opened",
142
113
  }
@@ -160,9 +131,10 @@ export const TypeIconMap = {
160
131
  [FieldType.ATTACHMENT_SINGLE]: "DocumentFragment",
161
132
  [FieldType.LINK]: "DataCorrelated",
162
133
  [FieldType.FORMULA]: "Calculator",
134
+ [FieldType.AI]: "MagicWand",
163
135
  [FieldType.JSON]: "Brackets",
164
136
  [FieldType.BIGINT]: "TagBold",
165
- [FieldType.AUTO]: "MagicWand",
137
+ [FieldType.AUTO]: "Shapes",
166
138
  [FieldType.BB_REFERENCE]: {
167
139
  [BBReferenceFieldSubType.USER]: "UserGroup",
168
140
  [BBReferenceFieldSubType.USERS]: "UserGroup",
@@ -176,6 +148,21 @@ export const OptionColours = [...new Array(12).keys()].map(idx => {
176
148
  return `hsla(${((idx + 1) * 222) % 360}, 90%, 75%, 0.3)`
177
149
  })
178
150
 
151
+ export const FilterOperator = {
152
+ ANY: "any",
153
+ ALL: "all",
154
+ }
155
+
156
+ export const OnEmptyFilter = {
157
+ RETURN_ALL: "all",
158
+ RETURN_NONE: "none",
159
+ }
160
+
161
+ export const FilterValueType = {
162
+ BINDING: "Binding",
163
+ VALUE: "Value",
164
+ }
165
+
179
166
  export const FieldPermissions = {
180
167
  WRITABLE: "writable",
181
168
  READONLY: "readonly",
@@ -2,6 +2,7 @@ import { writable, derived, get } from "svelte/store"
2
2
  import { cloneDeep } from "lodash/fp"
3
3
  import { QueryUtils } from "../utils"
4
4
  import { convertJSONSchemaToTableSchema } from "../utils/json"
5
+ import { FieldType, SortOrder, SortType } from "@budibase/types"
5
6
 
6
7
  const { buildQuery, limit: queryLimit, runQuery, sort } = QueryUtils
7
8
 
@@ -37,7 +38,7 @@ export default class DataFetch {
37
38
 
38
39
  // Sorting config
39
40
  sortColumn: null,
40
- sortOrder: "ascending",
41
+ sortOrder: SortOrder.ASCENDING,
41
42
  sortType: null,
42
43
 
43
44
  // Pagination config
@@ -162,17 +163,22 @@ export default class DataFetch {
162
163
  // If we don't have a sort column specified then just ensure we don't set
163
164
  // any sorting params
164
165
  if (!this.options.sortColumn) {
165
- this.options.sortOrder = "ascending"
166
+ this.options.sortOrder = SortOrder.ASCENDING
166
167
  this.options.sortType = null
167
168
  } else {
168
169
  // Otherwise determine what sort type to use base on sort column
169
- const type = schema?.[this.options.sortColumn]?.type
170
- this.options.sortType =
171
- type === "number" || type === "bigint" ? "number" : "string"
172
-
170
+ this.options.sortType = SortType.STRING
171
+ const fieldSchema = schema?.[this.options.sortColumn]
172
+ if (
173
+ fieldSchema?.type === FieldType.NUMBER ||
174
+ fieldSchema?.type === FieldType.BIGINT ||
175
+ fieldSchema?.calculationType
176
+ ) {
177
+ this.options.sortType = SortType.NUMBER
178
+ }
173
179
  // If no sort order, default to ascending
174
180
  if (!this.options.sortOrder) {
175
- this.options.sortOrder = "ascending"
181
+ this.options.sortOrder = SortOrder.ASCENDING
176
182
  }
177
183
  }
178
184
 
@@ -310,7 +316,7 @@ export default class DataFetch {
310
316
  let jsonAdditions = {}
311
317
  Object.keys(schema).forEach(fieldKey => {
312
318
  const fieldSchema = schema[fieldKey]
313
- if (fieldSchema?.type === "json") {
319
+ if (fieldSchema?.type === FieldType.JSON) {
314
320
  const jsonSchema = convertJSONSchemaToTableSchema(fieldSchema, {
315
321
  squashObjects: true,
316
322
  })
@@ -364,7 +370,9 @@ export default class DataFetch {
364
370
  let refresh = false
365
371
  const entries = Object.entries(newOptions || {})
366
372
  for (let [key, value] of entries) {
367
- if (JSON.stringify(value) !== JSON.stringify(this.options[key])) {
373
+ const oldVal = this.options[key] == null ? null : this.options[key]
374
+ const newVal = value == null ? null : value
375
+ if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
368
376
  refresh = true
369
377
  break
370
378
  }
@@ -1,5 +1,6 @@
1
1
  import { get } from "svelte/store"
2
2
  import DataFetch from "./DataFetch.js"
3
+ import { SortOrder } from "@budibase/types"
3
4
 
4
5
  export default class TableFetch extends DataFetch {
5
6
  determineFeatureFlags() {
@@ -23,7 +24,7 @@ export default class TableFetch extends DataFetch {
23
24
  query,
24
25
  limit,
25
26
  sort: sortColumn,
26
- sortOrder: sortOrder?.toLowerCase() ?? "ascending",
27
+ sortOrder: sortOrder?.toLowerCase() ?? SortOrder.ASCENDING,
27
28
  sortType,
28
29
  paginate,
29
30
  bookmark: cursor,
@@ -1,7 +1,7 @@
1
1
  import { get } from "svelte/store"
2
2
  import DataFetch from "./DataFetch.js"
3
3
  import { TableNames } from "../constants"
4
- import { QueryUtils } from "../utils"
4
+ import { utils } from "@budibase/shared-core"
5
5
 
6
6
  export default class UserFetch extends DataFetch {
7
7
  constructor(opts) {
@@ -30,14 +30,13 @@ export default class UserFetch extends DataFetch {
30
30
  async getData() {
31
31
  const { limit, paginate } = this.options
32
32
  const { cursor, query } = get(this.store)
33
- let finalQuery
34
- // convert old format to new one - we now allow use of the lucene format
33
+
34
+ // Convert old format to new one - we now allow use of the lucene format
35
35
  const { appId, paginated, ...rest } = query || {}
36
- if (!QueryUtils.hasFilters(query) && rest.email != null) {
37
- finalQuery = { string: { email: rest.email } }
38
- } else {
39
- finalQuery = rest
40
- }
36
+ const finalQuery = utils.isSupportedUserSearch(rest)
37
+ ? query
38
+ : { string: { email: null } }
39
+
41
40
  try {
42
41
  const opts = {
43
42
  bookmark: cursor,
@@ -1,3 +1,4 @@
1
+ import { ViewV2Type } from "@budibase/types"
1
2
  import DataFetch from "./DataFetch.js"
2
3
  import { get } from "svelte/store"
3
4
 
@@ -35,17 +36,23 @@ export default class ViewV2Fetch extends DataFetch {
35
36
  }
36
37
 
37
38
  async getData() {
38
- const {
39
- datasource,
40
- limit,
41
- sortColumn,
42
- sortOrder,
43
- sortType,
44
- paginate,
45
- filter,
46
- } = this.options
39
+ const { datasource, limit, sortColumn, sortOrder, sortType, paginate } =
40
+ this.options
47
41
  const { cursor, query, definition } = get(this.store)
48
42
 
43
+ // If this is a calculation view and we have no calculations, return nothing
44
+ if (
45
+ definition.type === ViewV2Type.CALCULATION &&
46
+ !Object.values(definition.schema || {}).some(x => x.calculationType)
47
+ ) {
48
+ return {
49
+ rows: [],
50
+ hasNextPage: false,
51
+ cursor: null,
52
+ error: null,
53
+ }
54
+ }
55
+
49
56
  // If sort/filter params are not defined, update options to store the
50
57
  // params built in to this view. This ensures that we can accurately
51
58
  // compare old and new params and skip a redundant API call.
@@ -53,14 +60,11 @@ export default class ViewV2Fetch extends DataFetch {
53
60
  this.options.sortColumn = definition.sort.field
54
61
  this.options.sortOrder = definition.sort.order
55
62
  }
56
- if (!filter?.length && definition.query?.length) {
57
- this.options.filter = definition.query
58
- }
59
63
 
60
64
  try {
61
65
  const res = await this.API.viewV2.fetch({
62
66
  viewId: datasource.id,
63
- query,
67
+ ...(query ? { query } : {}),
64
68
  paginate,
65
69
  limit,
66
70
  bookmark: cursor,
@@ -77,6 +81,7 @@ export default class ViewV2Fetch extends DataFetch {
77
81
  return {
78
82
  rows: [],
79
83
  hasNextPage: false,
84
+ cursor: null,
80
85
  error,
81
86
  }
82
87
  }
@@ -5,10 +5,10 @@ export * as RoleUtils from "./roles"
5
5
  export * as Utils from "./utils"
6
6
  export * as RowUtils from "./rows"
7
7
  export * as search from "./searchFields"
8
+ export * as SchemaUtils from "./schema"
8
9
  export { memo, derivedMemo } from "./memo"
9
10
  export { createWebsocket } from "./websocket"
10
11
  export * from "./download"
11
- export * from "./theme"
12
12
  export * from "./settings"
13
13
  export * from "./relatedColumns"
14
14
  export * from "./table"
@@ -24,9 +24,9 @@ const columnTypeManyParser = {
24
24
  return parsed
25
25
  }
26
26
 
27
- return value?.map(v => parseDate(v))
27
+ return value.map(v => parseDate(v))
28
28
  },
29
- [FieldType.BOOLEAN]: value => value?.map(v => !!v),
29
+ [FieldType.BOOLEAN]: value => value.map(v => !!v),
30
30
  [FieldType.BB_REFERENCE_SINGLE]: value => [
31
31
  ...new Map(value.map(i => [i._id, i])).values(),
32
32
  ],
@@ -80,14 +80,10 @@ export function getRelatedTableValues(row, field, fromField) {
80
80
  result = row[field.related.field]?.[0]?.[field.related.subField]
81
81
  } else {
82
82
  const parser = columnTypeManyParser[field.type] || (value => value)
83
-
84
- result = parser(
85
- row[field.related.field]
86
- ?.flatMap(r => r[field.related.subField])
87
- ?.filter(i => i !== undefined && i !== null),
88
- field
89
- )
90
-
83
+ const value = row[field.related.field]
84
+ ?.flatMap(r => r[field.related.subField])
85
+ ?.filter(i => i !== undefined && i !== null)
86
+ result = parser(value || [], field)
91
87
  if (
92
88
  [
93
89
  FieldType.STRING,
@@ -7,20 +7,7 @@ const RolePriorities = {
7
7
  [Roles.BASIC]: 2,
8
8
  [Roles.PUBLIC]: 1,
9
9
  }
10
- const RoleColours = {
11
- [Roles.ADMIN]: "var(--spectrum-global-color-static-red-400)",
12
- [Roles.CREATOR]: "var(--spectrum-global-color-static-magenta-600)",
13
- [Roles.POWER]: "var(--spectrum-global-color-static-orange-400)",
14
- [Roles.BASIC]: "var(--spectrum-global-color-static-green-400)",
15
- [Roles.PUBLIC]: "var(--spectrum-global-color-static-blue-400)",
16
- }
17
10
 
18
11
  export const getRolePriority = role => {
19
12
  return RolePriorities[role] ?? 0
20
13
  }
21
-
22
- export const getRoleColour = roleId => {
23
- return (
24
- RoleColours[roleId] ?? "var(--spectrum-global-color-static-magenta-400)"
25
- )
26
- }
@@ -0,0 +1,24 @@
1
+ import { helpers } from "@budibase/shared-core"
2
+ import { TypeIconMap } from "../constants"
3
+
4
+ export const getColumnIcon = column => {
5
+ if (column.schema.icon) {
6
+ return column.schema.icon
7
+ }
8
+ if (column.calculationType) {
9
+ return "Calculator"
10
+ }
11
+ if (column.schema.autocolumn) {
12
+ return "MagicWand"
13
+ }
14
+ if (helpers.schema.isDeprecatedSingleUserColumn(column.schema)) {
15
+ return "User"
16
+ }
17
+ const { type, subtype } = column.schema
18
+ const result =
19
+ typeof TypeIconMap[type] === "object" && subtype
20
+ ? TypeIconMap[type][subtype]
21
+ : TypeIconMap[type]
22
+
23
+ return result || "Text"
24
+ }
@@ -4,24 +4,24 @@ export function canBeDisplayColumn(column) {
4
4
  if (!sharedCore.canBeDisplayColumn(column.type)) {
5
5
  return false
6
6
  }
7
-
7
+ // If it's a related column (only available in the frontend), don't allow using it as display column
8
8
  if (column.related) {
9
- // If it's a related column (only available in the frontend), don't allow using it as display column
10
9
  return false
11
10
  }
12
-
13
11
  return true
14
12
  }
15
13
 
16
14
  export function canBeSortColumn(column) {
15
+ // Allow sorting by calculation columns
16
+ if (column.calculationType) {
17
+ return true
18
+ }
17
19
  if (!sharedCore.canBeSortColumn(column.type)) {
18
20
  return false
19
21
  }
20
-
22
+ // If it's a related column (only available in the frontend), don't allow using it as display column
21
23
  if (column.related) {
22
- // If it's a related column (only available in the frontend), don't allow using it as display column
23
24
  return false
24
25
  }
25
-
26
26
  return true
27
27
  }
@@ -240,7 +240,7 @@ export const buildFormBlockButtonConfig = props => {
240
240
  _component: "@budibase/standard-components/button",
241
241
  onClick: onDelete,
242
242
  quiet: true,
243
- type: "secondary",
243
+ type: "warning",
244
244
  })
245
245
  }
246
246