@budibase/frontend-core 3.2.38 → 3.2.39

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@budibase/frontend-core",
3
- "version": "3.2.38",
3
+ "version": "3.2.39",
4
4
  "description": "Budibase frontend core libraries used in builder and client",
5
5
  "author": "Budibase",
6
6
  "license": "MPL-2.0",
@@ -20,5 +20,5 @@
20
20
  "devDependencies": {
21
21
  "svelte-check": "^4.1.0"
22
22
  },
23
- "gitHead": "e3eabe9c968e531a30fe8848141f536d2b8a0b65"
23
+ "gitHead": "a334d5aac9f0ca11e718772afd0b93813852f6c6"
24
24
  }
package/src/api/index.ts CHANGED
@@ -68,13 +68,13 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
68
68
  ): Promise<APIError> => {
69
69
  // Try to read a message from the error
70
70
  let message = response.statusText
71
- let json: any = null
71
+ let json = null
72
72
  try {
73
73
  json = await response.json()
74
74
  if (json?.message) {
75
75
  message = json.message
76
76
  } else if (json?.error) {
77
- message = json.error
77
+ message = JSON.stringify(json.error)
78
78
  }
79
79
  } catch (error) {
80
80
  // Do nothing
@@ -93,7 +93,7 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
93
93
  // Generates an error object from a string
94
94
  const makeError = (
95
95
  message: string,
96
- url?: string,
96
+ url: string,
97
97
  method?: HTTPMethod
98
98
  ): APIError => {
99
99
  return {
@@ -226,7 +226,7 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
226
226
  return await handler(callConfig)
227
227
  } catch (error) {
228
228
  if (config?.onError) {
229
- config.onError(error)
229
+ config.onError(error as APIError)
230
230
  }
231
231
  throw error
232
232
  }
@@ -239,13 +239,9 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
239
239
  patch: requestApiCall(HTTPMethod.PATCH),
240
240
  delete: requestApiCall(HTTPMethod.DELETE),
241
241
  put: requestApiCall(HTTPMethod.PUT),
242
- error: (message: string) => {
243
- throw makeError(message)
244
- },
245
242
  invalidateCache: () => {
246
243
  cache = {}
247
244
  },
248
-
249
245
  // Generic utility to extract the current app ID. Assumes that any client
250
246
  // that exists in an app context will be attaching our app ID header.
251
247
  getAppID: (): string => {
package/src/api/types.ts CHANGED
@@ -46,7 +46,7 @@ export type Headers = Record<string, string>
46
46
  export type APIClientConfig = {
47
47
  enableCaching?: boolean
48
48
  attachHeaders?: (headers: Headers) => void
49
- onError?: (error: any) => void
49
+ onError?: (error: APIError) => void
50
50
  onMigrationDetected?: (migration: string) => void
51
51
  }
52
52
 
@@ -86,14 +86,13 @@ export type BaseAPIClient = {
86
86
  patch: <RequestT = null, ResponseT = void>(
87
87
  params: APICallParams<RequestT, ResponseT>
88
88
  ) => Promise<ResponseT>
89
- error: (message: string) => void
90
89
  invalidateCache: () => void
91
90
  getAppID: () => string
92
91
  }
93
92
 
94
93
  export type APIError = {
95
94
  message?: string
96
- url?: string
95
+ url: string
97
96
  method?: HTTPMethod
98
97
  json: any
99
98
  status: number
@@ -1,4 +1,4 @@
1
- import { FieldType } from "@budibase/types"
1
+ import { FieldType, UIColumn } from "@budibase/types"
2
2
 
3
3
  import OptionsCell from "../cells/OptionsCell.svelte"
4
4
  import DateCell from "../cells/DateCell.svelte"
@@ -40,13 +40,23 @@ const TypeComponentMap = {
40
40
  // Custom types for UI only
41
41
  role: RoleCell,
42
42
  }
43
- export const getCellRenderer = column => {
43
+
44
+ function getCellRendererByType(type: FieldType | "role" | undefined) {
45
+ if (!type) {
46
+ return
47
+ }
48
+
49
+ return TypeComponentMap[type as keyof typeof TypeComponentMap]
50
+ }
51
+
52
+ export const getCellRenderer = (column: UIColumn) => {
44
53
  if (column.calculationType) {
45
54
  return NumberCell
46
55
  }
56
+
47
57
  return (
48
- TypeComponentMap[column?.schema?.cellRenderType] ||
49
- TypeComponentMap[column?.schema?.type] ||
58
+ getCellRendererByType(column.schema?.cellRenderType) ||
59
+ getCellRendererByType(column.schema?.type) ||
50
60
  TextCell
51
61
  )
52
62
  }
@@ -1,12 +1,14 @@
1
1
  import { get } from "svelte/store"
2
2
  import { createWebsocket } from "../../../utils"
3
3
  import { SocketEvent, GridSocketEvent } from "@budibase/shared-core"
4
+ import { Store } from "../stores"
5
+ import { UIDatasource, UIUser } from "@budibase/types"
4
6
 
5
- export const createGridWebsocket = context => {
7
+ export const createGridWebsocket = (context: Store) => {
6
8
  const { rows, datasource, users, focusedCellId, definition, API } = context
7
9
  const socket = createWebsocket("/socket/grid")
8
10
 
9
- const connectToDatasource = datasource => {
11
+ const connectToDatasource = (datasource: UIDatasource) => {
10
12
  if (!socket.connected) {
11
13
  return
12
14
  }
@@ -18,7 +20,7 @@ export const createGridWebsocket = context => {
18
20
  datasource,
19
21
  appId,
20
22
  },
21
- ({ users: gridUsers }) => {
23
+ ({ users: gridUsers }: { users: UIUser[] }) => {
22
24
  users.set(gridUsers)
23
25
  }
24
26
  )
@@ -65,7 +67,7 @@ export const createGridWebsocket = context => {
65
67
  GridSocketEvent.DatasourceChange,
66
68
  ({ datasource: newDatasource }) => {
67
69
  // Listen builder renames, as these aren't handled otherwise
68
- if (newDatasource?.name !== get(definition).name) {
70
+ if (newDatasource?.name !== get(definition)?.name) {
69
71
  definition.set(newDatasource)
70
72
  }
71
73
  }
@@ -1,6 +1,7 @@
1
1
  import DataFetch from "./DataFetch"
2
2
 
3
3
  interface CustomDatasource {
4
+ type: "custom"
4
5
  data: any
5
6
  }
6
7
 
@@ -13,6 +13,7 @@ import {
13
13
  UISearchFilter,
14
14
  } from "@budibase/types"
15
15
  import { APIClient } from "../api/types"
16
+ import { DataFetchType } from "."
16
17
 
17
18
  const { buildQuery, limit: queryLimit, runQuery, sort } = QueryUtils
18
19
 
@@ -59,7 +60,7 @@ export interface DataFetchParams<
59
60
  * For other types of datasource, this class is overridden and extended.
60
61
  */
61
62
  export default abstract class DataFetch<
62
- TDatasource extends {},
63
+ TDatasource extends { type: DataFetchType },
63
64
  TDefinition extends {
64
65
  schema?: Record<string, any> | null
65
66
  primaryDisplay?: string
@@ -368,7 +369,7 @@ export default abstract class DataFetch<
368
369
  * @param schema the datasource schema
369
370
  * @return {object} the enriched datasource schema
370
371
  */
371
- private enrichSchema(schema: TableSchema): TableSchema {
372
+ enrichSchema(schema: TableSchema): TableSchema {
372
373
  // Check for any JSON fields so we can add any top level properties
373
374
  let jsonAdditions: Record<string, { type: string; nestedJSON: true }> = {}
374
375
  for (const fieldKey of Object.keys(schema)) {
@@ -1,7 +1,10 @@
1
1
  import { Row } from "@budibase/types"
2
2
  import DataFetch from "./DataFetch"
3
3
 
4
- export interface FieldDatasource {
4
+ type Types = "field" | "queryarray" | "jsonarray"
5
+
6
+ export interface FieldDatasource<TType extends Types> {
7
+ type: TType
5
8
  tableId: string
6
9
  fieldType: "attachment" | "array"
7
10
  value: string[] | Row[]
@@ -15,8 +18,8 @@ function isArrayOfStrings(value: string[] | Row[]): value is string[] {
15
18
  return Array.isArray(value) && !!value[0] && typeof value[0] !== "object"
16
19
  }
17
20
 
18
- export default class FieldFetch extends DataFetch<
19
- FieldDatasource,
21
+ export default class FieldFetch<TType extends Types> extends DataFetch<
22
+ FieldDatasource<TType>,
20
23
  FieldDefinition
21
24
  > {
22
25
  async getDefinition(): Promise<FieldDefinition | null> {
@@ -8,6 +8,7 @@ interface GroupUserQuery {
8
8
  }
9
9
 
10
10
  interface GroupUserDatasource {
11
+ type: "groupUser"
11
12
  tableId: TableNames.USERS
12
13
  }
13
14
 
@@ -20,6 +21,7 @@ export default class GroupUserFetch extends DataFetch<
20
21
  super({
21
22
  ...opts,
22
23
  datasource: {
24
+ type: "groupUser",
23
25
  tableId: TableNames.USERS,
24
26
  },
25
27
  })
@@ -1,7 +1,7 @@
1
1
  import FieldFetch from "./FieldFetch"
2
2
  import { getJSONArrayDatasourceSchema } from "../utils/json"
3
3
 
4
- export default class JSONArrayFetch extends FieldFetch {
4
+ export default class JSONArrayFetch extends FieldFetch<"jsonarray"> {
5
5
  async getDefinition() {
6
6
  const { datasource } = this.options
7
7
 
@@ -2,6 +2,7 @@ import { Row, TableSchema } from "@budibase/types"
2
2
  import DataFetch from "./DataFetch"
3
3
 
4
4
  interface NestedProviderDatasource {
5
+ type: "provider"
5
6
  value?: {
6
7
  schema: TableSchema
7
8
  primaryDisplay: string
@@ -4,7 +4,7 @@ import {
4
4
  generateQueryArraySchemas,
5
5
  } from "../utils/json"
6
6
 
7
- export default class QueryArrayFetch extends FieldFetch {
7
+ export default class QueryArrayFetch extends FieldFetch<"queryarray"> {
8
8
  async getDefinition() {
9
9
  const { datasource } = this.options
10
10
 
@@ -4,6 +4,7 @@ import { ExecuteQueryRequest, Query } from "@budibase/types"
4
4
  import { get } from "svelte/store"
5
5
 
6
6
  interface QueryDatasource {
7
+ type: "query"
7
8
  _id: string
8
9
  fields: Record<string, any> & {
9
10
  pagination?: {
@@ -2,6 +2,7 @@ import { Table } from "@budibase/types"
2
2
  import DataFetch from "./DataFetch"
3
3
 
4
4
  interface RelationshipDatasource {
5
+ type: "link"
5
6
  tableId: string
6
7
  rowId: string
7
8
  rowTableId: string
@@ -1,8 +1,13 @@
1
1
  import { get } from "svelte/store"
2
2
  import DataFetch from "./DataFetch"
3
- import { SortOrder, Table, UITable } from "@budibase/types"
3
+ import { SortOrder, Table } from "@budibase/types"
4
4
 
5
- export default class TableFetch extends DataFetch<UITable, Table> {
5
+ interface TableDatasource {
6
+ type: "table"
7
+ tableId: string
8
+ }
9
+
10
+ export default class TableFetch extends DataFetch<TableDatasource, Table> {
6
11
  async determineFeatureFlags() {
7
12
  return {
8
13
  supportsSearch: true,
@@ -2,11 +2,7 @@ import { get } from "svelte/store"
2
2
  import DataFetch, { DataFetchParams } from "./DataFetch"
3
3
  import { TableNames } from "../constants"
4
4
  import { utils } from "@budibase/shared-core"
5
- import {
6
- BasicOperator,
7
- SearchFilters,
8
- SearchUsersRequest,
9
- } from "@budibase/types"
5
+ import { SearchFilters, SearchUsersRequest } from "@budibase/types"
10
6
 
11
7
  interface UserFetchQuery {
12
8
  appId: string
@@ -14,18 +10,22 @@ interface UserFetchQuery {
14
10
  }
15
11
 
16
12
  interface UserDatasource {
17
- tableId: string
13
+ type: "user"
14
+ tableId: TableNames.USERS
18
15
  }
19
16
 
17
+ interface UserDefinition {}
18
+
20
19
  export default class UserFetch extends DataFetch<
21
20
  UserDatasource,
22
- {},
21
+ UserDefinition,
23
22
  UserFetchQuery
24
23
  > {
25
24
  constructor(opts: DataFetchParams<UserDatasource, UserFetchQuery>) {
26
25
  super({
27
26
  ...opts,
28
27
  datasource: {
28
+ type: "user",
29
29
  tableId: TableNames.USERS,
30
30
  },
31
31
  })
@@ -52,7 +52,7 @@ export default class UserFetch extends DataFetch<
52
52
 
53
53
  const finalQuery: SearchFilters = utils.isSupportedUserSearch(rest)
54
54
  ? rest
55
- : { [BasicOperator.EMPTY]: { email: null } }
55
+ : {}
56
56
 
57
57
  try {
58
58
  const opts: SearchUsersRequest = {
@@ -1,9 +1,16 @@
1
- import { Table, View } from "@budibase/types"
1
+ import { Table } from "@budibase/types"
2
2
  import DataFetch from "./DataFetch"
3
3
 
4
- type ViewV1 = View & { name: string }
4
+ type ViewV1Datasource = {
5
+ type: "view"
6
+ name: string
7
+ tableId: string
8
+ calculation: string
9
+ field: string
10
+ groupBy: string
11
+ }
5
12
 
6
- export default class ViewFetch extends DataFetch<ViewV1, Table> {
13
+ export default class ViewFetch extends DataFetch<ViewV1Datasource, Table> {
7
14
  async getDefinition() {
8
15
  const { datasource } = this.options
9
16
 
@@ -1,9 +1,17 @@
1
- import { SortOrder, UIView, ViewV2, ViewV2Type } from "@budibase/types"
1
+ import { SortOrder, ViewV2Enriched, ViewV2Type } from "@budibase/types"
2
2
  import DataFetch from "./DataFetch"
3
3
  import { get } from "svelte/store"
4
4
  import { helpers } from "@budibase/shared-core"
5
5
 
6
- export default class ViewV2Fetch extends DataFetch<UIView, ViewV2> {
6
+ interface ViewDatasource {
7
+ type: "viewV2"
8
+ id: string
9
+ }
10
+
11
+ export default class ViewV2Fetch extends DataFetch<
12
+ ViewDatasource,
13
+ ViewV2Enriched
14
+ > {
7
15
  async determineFeatureFlags() {
8
16
  return {
9
17
  supportsSearch: true,
@@ -1,18 +1,20 @@
1
- import TableFetch from "./TableFetch.js"
2
- import ViewFetch from "./ViewFetch.js"
3
- import ViewV2Fetch from "./ViewV2Fetch.js"
1
+ import TableFetch from "./TableFetch"
2
+ import ViewFetch from "./ViewFetch"
3
+ import ViewV2Fetch from "./ViewV2Fetch"
4
4
  import QueryFetch from "./QueryFetch"
5
5
  import RelationshipFetch from "./RelationshipFetch"
6
6
  import NestedProviderFetch from "./NestedProviderFetch"
7
7
  import FieldFetch from "./FieldFetch"
8
8
  import JSONArrayFetch from "./JSONArrayFetch"
9
- import UserFetch from "./UserFetch.js"
9
+ import UserFetch from "./UserFetch"
10
10
  import GroupUserFetch from "./GroupUserFetch"
11
11
  import CustomFetch from "./CustomFetch"
12
- import QueryArrayFetch from "./QueryArrayFetch.js"
13
- import { APIClient } from "../api/types.js"
12
+ import QueryArrayFetch from "./QueryArrayFetch"
13
+ import { APIClient } from "../api/types"
14
14
 
15
- const DataFetchMap = {
15
+ export type DataFetchType = keyof typeof DataFetchMap
16
+
17
+ export const DataFetchMap = {
16
18
  table: TableFetch,
17
19
  view: ViewFetch,
18
20
  viewV2: ViewV2Fetch,
@@ -24,15 +26,14 @@ const DataFetchMap = {
24
26
 
25
27
  // Client specific datasource types
26
28
  provider: NestedProviderFetch,
27
- field: FieldFetch,
29
+ field: FieldFetch<"field">,
28
30
  jsonarray: JSONArrayFetch,
29
31
  queryarray: QueryArrayFetch,
30
32
  }
31
33
 
32
34
  // Constructs a new fetch model for a certain datasource
33
35
  export const fetchData = ({ API, datasource, options }: any) => {
34
- const Fetch =
35
- DataFetchMap[datasource?.type as keyof typeof DataFetchMap] || TableFetch
36
+ const Fetch = DataFetchMap[datasource?.type as DataFetchType] || TableFetch
36
37
  const fetch = new Fetch({ API, datasource, ...options })
37
38
 
38
39
  // Initially fetch data but don't bother waiting for the result
@@ -43,29 +44,27 @@ export const fetchData = ({ API, datasource, options }: any) => {
43
44
 
44
45
  // Creates an empty fetch instance with no datasource configured, so no data
45
46
  // will initially be loaded
46
- const createEmptyFetchInstance = <
47
- TDatasource extends {
48
- type: keyof typeof DataFetchMap
49
- }
50
- >({
47
+ const createEmptyFetchInstance = <TDatasource extends { type: DataFetchType }>({
51
48
  API,
52
49
  datasource,
53
50
  }: {
54
51
  API: APIClient
55
52
  datasource: TDatasource
56
53
  }) => {
57
- const handler = DataFetchMap[datasource?.type as keyof typeof DataFetchMap]
54
+ const handler = DataFetchMap[datasource?.type as DataFetchType]
58
55
  if (!handler) {
59
56
  return null
60
57
  }
61
- return new handler({ API, datasource: null as any, query: null as any })
58
+ return new handler({
59
+ API,
60
+ datasource: null as never,
61
+ query: null as any,
62
+ })
62
63
  }
63
64
 
64
65
  // Fetches the definition of any type of datasource
65
66
  export const getDatasourceDefinition = async <
66
- TDatasource extends {
67
- type: keyof typeof DataFetchMap
68
- }
67
+ TDatasource extends { type: DataFetchType }
69
68
  >({
70
69
  API,
71
70
  datasource,
@@ -79,9 +78,7 @@ export const getDatasourceDefinition = async <
79
78
 
80
79
  // Fetches the schema of any type of datasource
81
80
  export const getDatasourceSchema = <
82
- TDatasource extends {
83
- type: keyof typeof DataFetchMap
84
- }
81
+ TDatasource extends { type: DataFetchType }
85
82
  >({
86
83
  API,
87
84
  datasource,
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { createAPIClient } from "./api"
2
- export { fetchData } from "./fetch"
2
+ export { fetchData, DataFetchMap } from "./fetch"
3
+ export type { DataFetchType } from "./fetch"
3
4
  export * as Constants from "./constants"
4
5
  export * from "./stores"
5
6
  export * from "./utils"
@@ -209,6 +209,9 @@ export const buildFormBlockButtonConfig = props => {
209
209
  {
210
210
  "##eventHandlerType": "Close Side Panel",
211
211
  },
212
+ {
213
+ "##eventHandlerType": "Close Modal",
214
+ },
212
215
 
213
216
  ...(actionUrl
214
217
  ? [
@@ -1,32 +0,0 @@
1
- // TODO: remove when all stores are typed
2
-
3
- import { GeneratedIDPrefix, CellIDSeparator } from "./constants"
4
- import { Helpers } from "@budibase/bbui"
5
-
6
- export const parseCellID = cellId => {
7
- if (!cellId) {
8
- return { rowId: undefined, field: undefined }
9
- }
10
- const parts = cellId.split(CellIDSeparator)
11
- const field = parts.pop()
12
- return { rowId: parts.join(CellIDSeparator), field }
13
- }
14
-
15
- export const getCellID = (rowId, fieldName) => {
16
- return `${rowId}${CellIDSeparator}${fieldName}`
17
- }
18
-
19
- export const parseEventLocation = e => {
20
- return {
21
- x: e.clientX ?? e.touches?.[0]?.clientX,
22
- y: e.clientY ?? e.touches?.[0]?.clientY,
23
- }
24
- }
25
-
26
- export const generateRowID = () => {
27
- return `${GeneratedIDPrefix}${Helpers.uuid()}`
28
- }
29
-
30
- export const isGeneratedRowID = id => {
31
- return id?.startsWith(GeneratedIDPrefix)
32
- }