@budibase/frontend-core 3.2.38 → 3.2.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@budibase/frontend-core",
3
- "version": "3.2.38",
3
+ "version": "3.2.40",
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": "f6424d1f4a4b524be41d8ab389053cc1287cfe9f"
24
24
  }
package/src/api/index.ts CHANGED
@@ -46,6 +46,8 @@ import { buildLogsEndpoints } from "./logs"
46
46
  import { buildMigrationEndpoints } from "./migrations"
47
47
  import { buildRowActionEndpoints } from "./rowActions"
48
48
 
49
+ export type { APIClient } from "./types"
50
+
49
51
  /**
50
52
  * Random identifier to uniquely identify a session in a tab. This is
51
53
  * used to determine the originator of calls to the API, which is in
@@ -68,13 +70,13 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
68
70
  ): Promise<APIError> => {
69
71
  // Try to read a message from the error
70
72
  let message = response.statusText
71
- let json: any = null
73
+ let json = null
72
74
  try {
73
75
  json = await response.json()
74
76
  if (json?.message) {
75
77
  message = json.message
76
78
  } else if (json?.error) {
77
- message = json.error
79
+ message = JSON.stringify(json.error)
78
80
  }
79
81
  } catch (error) {
80
82
  // Do nothing
@@ -93,7 +95,7 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
93
95
  // Generates an error object from a string
94
96
  const makeError = (
95
97
  message: string,
96
- url?: string,
98
+ url: string,
97
99
  method?: HTTPMethod
98
100
  ): APIError => {
99
101
  return {
@@ -226,7 +228,7 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
226
228
  return await handler(callConfig)
227
229
  } catch (error) {
228
230
  if (config?.onError) {
229
- config.onError(error)
231
+ config.onError(error as APIError)
230
232
  }
231
233
  throw error
232
234
  }
@@ -239,13 +241,9 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
239
241
  patch: requestApiCall(HTTPMethod.PATCH),
240
242
  delete: requestApiCall(HTTPMethod.DELETE),
241
243
  put: requestApiCall(HTTPMethod.PUT),
242
- error: (message: string) => {
243
- throw makeError(message)
244
- },
245
244
  invalidateCache: () => {
246
245
  cache = {}
247
246
  },
248
-
249
247
  // Generic utility to extract the current app ID. Assumes that any client
250
248
  // that exists in an app context will be attaching our app ID header.
251
249
  getAppID: (): string => {
package/src/api/self.ts CHANGED
@@ -13,7 +13,7 @@ export interface SelfEndpoints {
13
13
  generateAPIKey: () => Promise<string | undefined>
14
14
  fetchDeveloperInfo: () => Promise<FetchAPIKeyResponse>
15
15
  fetchBuilderSelf: () => Promise<GetGlobalSelfResponse>
16
- fetchSelf: () => Promise<AppSelfResponse>
16
+ fetchSelf: () => Promise<AppSelfResponse | null>
17
17
  }
18
18
 
19
19
  export const buildSelfEndpoints = (API: BaseAPIClient): SelfEndpoints => ({
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
package/src/api/user.ts CHANGED
@@ -21,11 +21,12 @@ import {
21
21
  SaveUserResponse,
22
22
  SearchUsersRequest,
23
23
  SearchUsersResponse,
24
+ UnsavedUser,
24
25
  UpdateInviteRequest,
25
26
  UpdateInviteResponse,
26
27
  UpdateSelfMetadataRequest,
27
28
  UpdateSelfMetadataResponse,
28
- User,
29
+ UserIdentifier,
29
30
  } from "@budibase/types"
30
31
  import { BaseAPIClient } from "./types"
31
32
 
@@ -38,14 +39,9 @@ export interface UserEndpoints {
38
39
  createAdminUser: (
39
40
  user: CreateAdminUserRequest
40
41
  ) => Promise<CreateAdminUserResponse>
41
- saveUser: (user: User) => Promise<SaveUserResponse>
42
+ saveUser: (user: UnsavedUser) => Promise<SaveUserResponse>
42
43
  deleteUser: (userId: string) => Promise<DeleteUserResponse>
43
- deleteUsers: (
44
- users: Array<{
45
- userId: string
46
- email: string
47
- }>
48
- ) => Promise<BulkUserDeleted | undefined>
44
+ deleteUsers: (users: UserIdentifier[]) => Promise<BulkUserDeleted | undefined>
49
45
  onboardUsers: (data: InviteUsersRequest) => Promise<InviteUsersResponse>
50
46
  getUserInvite: (code: string) => Promise<CheckInviteResponse>
51
47
  getUserInvites: () => Promise<GetUserInvitesResponse>
@@ -60,7 +56,7 @@ export interface UserEndpoints {
60
56
  getAccountHolder: () => Promise<LookupAccountHolderResponse>
61
57
  searchUsers: (data: SearchUsersRequest) => Promise<SearchUsersResponse>
62
58
  createUsers: (
63
- users: User[],
59
+ users: UnsavedUser[],
64
60
  groups: any[]
65
61
  ) => Promise<BulkUserCreated | undefined>
66
62
  updateUserInvite: (
@@ -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,7 @@
1
1
  export { createAPIClient } from "./api"
2
- export { fetchData } from "./fetch"
2
+ export type { APIClient } from "./api"
3
+ export { fetchData, DataFetchMap } from "./fetch"
4
+ export type { DataFetchType } from "./fetch"
3
5
  export * as Constants from "./constants"
4
6
  export * from "./stores"
5
7
  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
- }