@budibase/frontend-core 3.2.44 → 3.2.46

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.44",
3
+ "version": "3.2.46",
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": "6f26dc6e757f321d7b3568e8a36c7b806475f5d3"
23
+ "gitHead": "a42b9757de845189ea0c0617440936e3d67f62c3"
24
24
  }
@@ -1,7 +1,11 @@
1
1
  // TODO: datasource and defitions are unions of the different implementations. At this point, the datasource does not know what type is being used, and the assignations will cause TS exceptions. Casting it "as any" for now. This should be fixed improving the type usages.
2
2
 
3
3
  import { derived, get, Readable, Writable } from "svelte/store"
4
- import { getDatasourceDefinition, getDatasourceSchema } from "../../../fetch"
4
+ import {
5
+ DataFetchDefinition,
6
+ getDatasourceDefinition,
7
+ getDatasourceSchema,
8
+ } from "../../../fetch"
5
9
  import { enrichSchemaWithRelColumns, memo } from "../../../utils"
6
10
  import { cloneDeep } from "lodash"
7
11
  import {
@@ -18,7 +22,7 @@ import { Store as StoreContext, BaseStoreProps } from "."
18
22
  import { DatasourceActions } from "./datasources"
19
23
 
20
24
  interface DatasourceStore {
21
- definition: Writable<UIDatasource | null>
25
+ definition: Writable<DataFetchDefinition | null>
22
26
  schemaMutations: Writable<Record<string, UIFieldMutation>>
23
27
  subSchemaMutations: Writable<Record<string, Record<string, UIFieldMutation>>>
24
28
  }
@@ -131,11 +135,17 @@ export const deriveStores = (context: StoreContext): DerivedDatasourceStore => {
131
135
  [datasource, definition],
132
136
  ([$datasource, $definition]) => {
133
137
  let type = $datasource?.type
138
+ // @ts-expect-error
134
139
  if (type === "provider") {
135
140
  type = ($datasource as any).value?.datasource?.type // TODO: see line 1
136
141
  }
137
142
  // Handle calculation views
138
- if (type === "viewV2" && $definition?.type === ViewV2Type.CALCULATION) {
143
+ if (
144
+ type === "viewV2" &&
145
+ $definition &&
146
+ "type" in $definition &&
147
+ $definition.type === ViewV2Type.CALCULATION
148
+ ) {
139
149
  return false
140
150
  }
141
151
  return !!type && ["table", "viewV2", "link"].includes(type)
@@ -197,7 +207,7 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => {
197
207
  ) => {
198
208
  // Update local state
199
209
  const originalDefinition = get(definition)
200
- definition.set(newDefinition as UIDatasource)
210
+ definition.set(newDefinition)
201
211
 
202
212
  // Update server
203
213
  if (get(config).canSaveSchema) {
@@ -225,13 +235,15 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => {
225
235
  // Update primary display
226
236
  newDefinition.primaryDisplay = column
227
237
 
228
- // Sanitise schema to ensure field is required and has no default value
229
- if (!newDefinition.schema[column].constraints) {
230
- newDefinition.schema[column].constraints = {}
231
- }
232
- newDefinition.schema[column].constraints.presence = { allowEmpty: false }
233
- if ("default" in newDefinition.schema[column]) {
234
- delete newDefinition.schema[column].default
238
+ if (newDefinition.schema) {
239
+ // Sanitise schema to ensure field is required and has no default value
240
+ if (!newDefinition.schema[column].constraints) {
241
+ newDefinition.schema[column].constraints = {}
242
+ }
243
+ newDefinition.schema[column].constraints.presence = { allowEmpty: false }
244
+ if ("default" in newDefinition.schema[column]) {
245
+ delete newDefinition.schema[column].default
246
+ }
235
247
  }
236
248
  return await saveDefinition(newDefinition as any) // TODO: see line 1
237
249
  }
@@ -8,6 +8,7 @@ import {
8
8
  import { get } from "svelte/store"
9
9
  import { Store as StoreContext } from ".."
10
10
  import { DatasourceTableActions } from "."
11
+ import TableFetch from "../../../../fetch/TableFetch"
11
12
 
12
13
  const SuppressErrors = true
13
14
 
@@ -119,7 +120,7 @@ export const initialise = (context: StoreContext) => {
119
120
  unsubscribers.push(
120
121
  allFilters.subscribe($allFilters => {
121
122
  // Ensure we're updating the correct fetch
122
- const $fetch = get(fetch)
123
+ const $fetch = get(fetch) as TableFetch | null
123
124
  if ($fetch?.options?.datasource?.tableId !== $datasource.tableId) {
124
125
  return
125
126
  }
@@ -133,7 +134,7 @@ export const initialise = (context: StoreContext) => {
133
134
  unsubscribers.push(
134
135
  sort.subscribe($sort => {
135
136
  // Ensure we're updating the correct fetch
136
- const $fetch = get(fetch)
137
+ const $fetch = get(fetch) as TableFetch | null
137
138
  if ($fetch?.options?.datasource?.tableId !== $datasource.tableId) {
138
139
  return
139
140
  }
@@ -4,11 +4,11 @@ import {
4
4
  SaveRowRequest,
5
5
  SortOrder,
6
6
  UIDatasource,
7
- UIView,
8
7
  UpdateViewRequest,
9
8
  } from "@budibase/types"
10
9
  import { Store as StoreContext } from ".."
11
10
  import { DatasourceViewActions } from "."
11
+ import ViewV2Fetch from "../../../../fetch/ViewV2Fetch"
12
12
 
13
13
  const SuppressErrors = true
14
14
 
@@ -134,6 +134,9 @@ export const initialise = (context: StoreContext) => {
134
134
  if (!get(config).canSaveSchema) {
135
135
  return
136
136
  }
137
+ if (!$definition || !("id" in $definition)) {
138
+ return
139
+ }
137
140
  if ($definition?.id !== $datasource.id) {
138
141
  return
139
142
  }
@@ -184,7 +187,10 @@ export const initialise = (context: StoreContext) => {
184
187
  unsubscribers.push(
185
188
  sort.subscribe(async $sort => {
186
189
  // Ensure we're updating the correct view
187
- const $view = get(definition) as UIView
190
+ const $view = get(definition)
191
+ if (!$view || !("id" in $view)) {
192
+ return
193
+ }
188
194
  if ($view?.id !== $datasource.id) {
189
195
  return
190
196
  }
@@ -207,7 +213,7 @@ export const initialise = (context: StoreContext) => {
207
213
 
208
214
  // Also update the fetch to ensure the new sort is respected.
209
215
  // Ensure we're updating the correct fetch.
210
- const $fetch = get(fetch)
216
+ const $fetch = get(fetch) as ViewV2Fetch | null
211
217
  if ($fetch?.options?.datasource?.id !== $datasource.id) {
212
218
  return
213
219
  }
@@ -225,6 +231,9 @@ export const initialise = (context: StoreContext) => {
225
231
  return
226
232
  }
227
233
  const $view = get(definition)
234
+ if (!$view || !("id" in $view)) {
235
+ return
236
+ }
228
237
  if ($view?.id !== $datasource.id) {
229
238
  return
230
239
  }
@@ -246,7 +255,7 @@ export const initialise = (context: StoreContext) => {
246
255
  if (!get(config).canSaveSchema) {
247
256
  return
248
257
  }
249
- const $fetch = get(fetch)
258
+ const $fetch = get(fetch) as ViewV2Fetch | null
250
259
  if ($fetch?.options?.datasource?.id !== $datasource.id) {
251
260
  return
252
261
  }
@@ -262,7 +271,7 @@ export const initialise = (context: StoreContext) => {
262
271
  if (get(config).canSaveSchema) {
263
272
  return
264
273
  }
265
- const $fetch = get(fetch)
274
+ const $fetch = get(fetch) as ViewV2Fetch | null
266
275
  if ($fetch?.options?.datasource?.id !== $datasource.id) {
267
276
  return
268
277
  }
@@ -1,5 +1,5 @@
1
1
  import { writable, derived, get, Writable, Readable } from "svelte/store"
2
- import { fetchData } from "../../../fetch"
2
+ import { DataFetch, fetchData } from "../../../fetch"
3
3
  import { NewRowID, RowPageSize } from "../lib/constants"
4
4
  import {
5
5
  generateRowID,
@@ -13,7 +13,6 @@ import { sleep } from "../../../utils/utils"
13
13
  import { FieldType, Row, UIRow } from "@budibase/types"
14
14
  import { getRelatedTableValues } from "../../../utils"
15
15
  import { Store as StoreContext } from "."
16
- import DataFetch from "../../../fetch/DataFetch"
17
16
 
18
17
  interface IndexedUIRow extends UIRow {
19
18
  __idx: number
@@ -21,7 +20,7 @@ interface IndexedUIRow extends UIRow {
21
20
 
22
21
  interface RowStore {
23
22
  rows: Writable<UIRow[]>
24
- fetch: Writable<DataFetch<any, any, any> | null> // TODO: type this properly, having a union of all the possible options
23
+ fetch: Writable<DataFetch | null>
25
24
  loaded: Writable<boolean>
26
25
  refreshing: Writable<boolean>
27
26
  loading: Writable<boolean>
@@ -254,7 +253,7 @@ export const createActions = (context: StoreContext): RowActionStore => {
254
253
 
255
254
  // Reset state properties when dataset changes
256
255
  if (!$instanceLoaded || resetRows) {
257
- definition.set($fetch.definition as any) // TODO: datasource and defitions are unions of the different implementations. At this point, the datasource does not know what type is being used, and the assignations will cause TS exceptions. Casting it "as any" for now. This should be fixed improving the type usages.
256
+ definition.set($fetch.definition ?? null)
258
257
  }
259
258
 
260
259
  // Reset scroll state when data changes
@@ -1,13 +1,9 @@
1
- import DataFetch from "./DataFetch"
2
-
3
- interface CustomDatasource {
4
- type: "custom"
5
- data: any
6
- }
1
+ import { CustomDatasource } from "@budibase/types"
2
+ import BaseDataFetch from "./DataFetch"
7
3
 
8
4
  type CustomDefinition = Record<string, any>
9
5
 
10
- export default class CustomFetch extends DataFetch<
6
+ export default class CustomFetch extends BaseDataFetch<
11
7
  CustomDatasource,
12
8
  CustomDefinition
13
9
  > {
@@ -3,14 +3,13 @@ import { cloneDeep } from "lodash/fp"
3
3
  import { QueryUtils } from "../utils"
4
4
  import { convertJSONSchemaToTableSchema } from "../utils/json"
5
5
  import {
6
+ DataFetchOptions,
6
7
  FieldType,
7
- LegacyFilter,
8
8
  Row,
9
9
  SearchFilters,
10
10
  SortOrder,
11
11
  SortType,
12
12
  TableSchema,
13
- UISearchFilter,
14
13
  } from "@budibase/types"
15
14
  import { APIClient } from "../api/types"
16
15
  import { DataFetchType } from "."
@@ -44,14 +43,11 @@ interface DataFetchDerivedStore<TDefinition, TQuery>
44
43
  supportsPagination: boolean
45
44
  }
46
45
 
47
- export interface DataFetchParams<
48
- TDatasource,
49
- TQuery = SearchFilters | undefined
50
- > {
46
+ export interface DataFetchParams<TDatasource, TQuery = SearchFilters> {
51
47
  API: APIClient
52
48
  datasource: TDatasource
53
49
  query: TQuery
54
- options?: {}
50
+ options?: Partial<DataFetchOptions<TQuery>>
55
51
  }
56
52
 
57
53
  /**
@@ -59,7 +55,7 @@ export interface DataFetchParams<
59
55
  * internal table or datasource plus.
60
56
  * For other types of datasource, this class is overridden and extended.
61
57
  */
62
- export default abstract class DataFetch<
58
+ export default abstract class BaseDataFetch<
63
59
  TDatasource extends { type: DataFetchType },
64
60
  TDefinition extends {
65
61
  schema?: Record<string, any> | null
@@ -73,18 +69,11 @@ export default abstract class DataFetch<
73
69
  supportsSort: boolean
74
70
  supportsPagination: boolean
75
71
  }
76
- options: {
72
+ options: DataFetchOptions<TQuery> & {
77
73
  datasource: TDatasource
78
- limit: number
79
- // Search config
80
- filter: UISearchFilter | LegacyFilter[] | null
81
- query: TQuery
82
- // Sorting config
83
- sortColumn: string | null
84
- sortOrder: SortOrder
74
+
85
75
  sortType: SortType | null
86
- // Pagination config
87
- paginate: boolean
76
+
88
77
  // Client side feature customisation
89
78
  clientSideSearching: boolean
90
79
  clientSideSorting: boolean
@@ -267,6 +256,7 @@ export default abstract class DataFetch<
267
256
 
268
257
  // Build the query
269
258
  let query = this.options.query
259
+
270
260
  if (!query) {
271
261
  query = buildQuery(filter ?? undefined) as TQuery
272
262
  }
@@ -430,7 +420,7 @@ export default abstract class DataFetch<
430
420
  * Resets the data set and updates options
431
421
  * @param newOptions any new options
432
422
  */
433
- async update(newOptions: any) {
423
+ async update(newOptions: Partial<DataFetchOptions<TQuery>>) {
434
424
  // Check if any settings have actually changed
435
425
  let refresh = false
436
426
  for (const [key, value] of Object.entries(newOptions || {})) {
@@ -1,14 +1,10 @@
1
- import { Row } from "@budibase/types"
2
- import DataFetch from "./DataFetch"
3
-
4
- type Types = "field" | "queryarray" | "jsonarray"
5
-
6
- export interface FieldDatasource<TType extends Types> {
7
- type: TType
8
- tableId: string
9
- fieldType: "attachment" | "array"
10
- value: string[] | Row[]
11
- }
1
+ import {
2
+ FieldDatasource,
3
+ JSONArrayFieldDatasource,
4
+ QueryArrayFieldDatasource,
5
+ Row,
6
+ } from "@budibase/types"
7
+ import BaseDataFetch from "./DataFetch"
12
8
 
13
9
  export interface FieldDefinition {
14
10
  schema?: Record<string, { type: string }> | null
@@ -18,10 +14,12 @@ function isArrayOfStrings(value: string[] | Row[]): value is string[] {
18
14
  return Array.isArray(value) && !!value[0] && typeof value[0] !== "object"
19
15
  }
20
16
 
21
- export default class FieldFetch<TType extends Types> extends DataFetch<
22
- FieldDatasource<TType>,
23
- FieldDefinition
24
- > {
17
+ export default class FieldFetch<
18
+ TDatasource extends
19
+ | FieldDatasource
20
+ | QueryArrayFieldDatasource
21
+ | JSONArrayFieldDatasource = FieldDatasource
22
+ > extends BaseDataFetch<TDatasource, FieldDefinition> {
25
23
  async getDefinition(): Promise<FieldDefinition | null> {
26
24
  const { datasource } = this.options
27
25
 
@@ -1,20 +1,20 @@
1
1
  import { get } from "svelte/store"
2
- import DataFetch, { DataFetchParams } from "./DataFetch"
3
- import { TableNames } from "../constants"
2
+ import BaseDataFetch, { DataFetchParams } from "./DataFetch"
3
+ import { GroupUserDatasource, InternalTable } from "@budibase/types"
4
4
 
5
5
  interface GroupUserQuery {
6
6
  groupId: string
7
7
  emailSearch: string
8
8
  }
9
9
 
10
- interface GroupUserDatasource {
11
- type: "groupUser"
12
- tableId: TableNames.USERS
10
+ interface GroupUserDefinition {
11
+ schema?: Record<string, any> | null
12
+ primaryDisplay?: string
13
13
  }
14
14
 
15
- export default class GroupUserFetch extends DataFetch<
15
+ export default class GroupUserFetch extends BaseDataFetch<
16
16
  GroupUserDatasource,
17
- {},
17
+ GroupUserDefinition,
18
18
  GroupUserQuery
19
19
  > {
20
20
  constructor(opts: DataFetchParams<GroupUserDatasource, GroupUserQuery>) {
@@ -22,7 +22,7 @@ export default class GroupUserFetch extends DataFetch<
22
22
  ...opts,
23
23
  datasource: {
24
24
  type: "groupUser",
25
- tableId: TableNames.USERS,
25
+ tableId: InternalTable.USER_METADATA,
26
26
  },
27
27
  })
28
28
  }
@@ -1,7 +1,8 @@
1
1
  import FieldFetch from "./FieldFetch"
2
2
  import { getJSONArrayDatasourceSchema } from "../utils/json"
3
+ import { JSONArrayFieldDatasource } from "@budibase/types"
3
4
 
4
- export default class JSONArrayFetch extends FieldFetch<"jsonarray"> {
5
+ export default class JSONArrayFetch extends FieldFetch<JSONArrayFieldDatasource> {
5
6
  async getDefinition() {
6
7
  const { datasource } = this.options
7
8
 
@@ -1,20 +1,11 @@
1
- import { Row, TableSchema } from "@budibase/types"
2
- import DataFetch from "./DataFetch"
3
-
4
- interface NestedProviderDatasource {
5
- type: "provider"
6
- value?: {
7
- schema: TableSchema
8
- primaryDisplay: string
9
- rows: Row[]
10
- }
11
- }
1
+ import { NestedProviderDatasource, TableSchema } from "@budibase/types"
2
+ import BaseDataFetch from "./DataFetch"
12
3
 
13
4
  interface NestedProviderDefinition {
14
5
  schema?: TableSchema
15
6
  primaryDisplay?: string
16
7
  }
17
- export default class NestedProviderFetch extends DataFetch<
8
+ export default class NestedProviderFetch extends BaseDataFetch<
18
9
  NestedProviderDatasource,
19
10
  NestedProviderDefinition
20
11
  > {
@@ -3,8 +3,9 @@ import {
3
3
  getJSONArrayDatasourceSchema,
4
4
  generateQueryArraySchemas,
5
5
  } from "../utils/json"
6
+ import { QueryArrayFieldDatasource } from "@budibase/types"
6
7
 
7
- export default class QueryArrayFetch extends FieldFetch<"queryarray"> {
8
+ export default class QueryArrayFetch extends FieldFetch<QueryArrayFieldDatasource> {
8
9
  async getDefinition() {
9
10
  const { datasource } = this.options
10
11
 
@@ -1,23 +1,9 @@
1
- import DataFetch from "./DataFetch"
1
+ import BaseDataFetch from "./DataFetch"
2
2
  import { Helpers } from "@budibase/bbui"
3
- import { ExecuteQueryRequest, Query } from "@budibase/types"
3
+ import { ExecuteQueryRequest, Query, QueryDatasource } from "@budibase/types"
4
4
  import { get } from "svelte/store"
5
5
 
6
- interface QueryDatasource {
7
- type: "query"
8
- _id: string
9
- fields: Record<string, any> & {
10
- pagination?: {
11
- type: string
12
- location: string
13
- pageParam: string
14
- }
15
- }
16
- queryParams?: Record<string, string>
17
- parameters: { name: string; default: string }[]
18
- }
19
-
20
- export default class QueryFetch extends DataFetch<QueryDatasource, Query> {
6
+ export default class QueryFetch extends BaseDataFetch<QueryDatasource, Query> {
21
7
  async determineFeatureFlags() {
22
8
  const definition = await this.getDefinition()
23
9
  const supportsPagination =
@@ -1,15 +1,7 @@
1
- import { Table } from "@budibase/types"
2
- import DataFetch from "./DataFetch"
1
+ import { RelationshipDatasource, Table } from "@budibase/types"
2
+ import BaseDataFetch from "./DataFetch"
3
3
 
4
- interface RelationshipDatasource {
5
- type: "link"
6
- tableId: string
7
- rowId: string
8
- rowTableId: string
9
- fieldName: string
10
- }
11
-
12
- export default class RelationshipFetch extends DataFetch<
4
+ export default class RelationshipFetch extends BaseDataFetch<
13
5
  RelationshipDatasource,
14
6
  Table
15
7
  > {
@@ -1,13 +1,8 @@
1
1
  import { get } from "svelte/store"
2
- import DataFetch from "./DataFetch"
3
- import { SortOrder, Table } from "@budibase/types"
2
+ import BaseDataFetch from "./DataFetch"
3
+ import { SortOrder, Table, TableDatasource } from "@budibase/types"
4
4
 
5
- interface TableDatasource {
6
- type: "table"
7
- tableId: string
8
- }
9
-
10
- export default class TableFetch extends DataFetch<TableDatasource, Table> {
5
+ export default class TableFetch extends BaseDataFetch<TableDatasource, Table> {
11
6
  async determineFeatureFlags() {
12
7
  return {
13
8
  supportsSearch: true,
@@ -1,22 +1,24 @@
1
1
  import { get } from "svelte/store"
2
- import DataFetch, { DataFetchParams } from "./DataFetch"
3
- import { TableNames } from "../constants"
2
+ import BaseDataFetch, { DataFetchParams } from "./DataFetch"
4
3
  import { utils } from "@budibase/shared-core"
5
- import { SearchFilters, SearchUsersRequest } from "@budibase/types"
4
+ import {
5
+ InternalTable,
6
+ SearchFilters,
7
+ SearchUsersRequest,
8
+ UserDatasource,
9
+ } from "@budibase/types"
6
10
 
7
11
  interface UserFetchQuery {
8
12
  appId: string
9
13
  paginated: boolean
10
14
  }
11
15
 
12
- interface UserDatasource {
13
- type: "user"
14
- tableId: TableNames.USERS
16
+ interface UserDefinition {
17
+ schema?: Record<string, any> | null
18
+ primaryDisplay?: string
15
19
  }
16
20
 
17
- interface UserDefinition {}
18
-
19
- export default class UserFetch extends DataFetch<
21
+ export default class UserFetch extends BaseDataFetch<
20
22
  UserDatasource,
21
23
  UserDefinition,
22
24
  UserFetchQuery
@@ -26,7 +28,7 @@ export default class UserFetch extends DataFetch<
26
28
  ...opts,
27
29
  datasource: {
28
30
  type: "user",
29
- tableId: TableNames.USERS,
31
+ tableId: InternalTable.USER_METADATA,
30
32
  },
31
33
  })
32
34
  }
@@ -1,16 +1,7 @@
1
- import { Table } from "@budibase/types"
2
- import DataFetch from "./DataFetch"
1
+ import { Table, ViewV1Datasource } from "@budibase/types"
2
+ import BaseDataFetch from "./DataFetch"
3
3
 
4
- type ViewV1Datasource = {
5
- type: "view"
6
- name: string
7
- tableId: string
8
- calculation: string
9
- field: string
10
- groupBy: string
11
- }
12
-
13
- export default class ViewFetch extends DataFetch<ViewV1Datasource, Table> {
4
+ export default class ViewFetch extends BaseDataFetch<ViewV1Datasource, Table> {
14
5
  async getDefinition() {
15
6
  const { datasource } = this.options
16
7
 
@@ -1,14 +1,14 @@
1
- import { SortOrder, ViewV2Enriched, ViewV2Type } from "@budibase/types"
2
- import DataFetch from "./DataFetch"
1
+ import {
2
+ SortOrder,
3
+ ViewDatasource,
4
+ ViewV2Enriched,
5
+ ViewV2Type,
6
+ } from "@budibase/types"
7
+ import BaseDataFetch from "./DataFetch"
3
8
  import { get } from "svelte/store"
4
9
  import { helpers } from "@budibase/shared-core"
5
10
 
6
- interface ViewDatasource {
7
- type: "viewV2"
8
- id: string
9
- }
10
-
11
- export default class ViewV2Fetch extends DataFetch<
11
+ export default class ViewV2Fetch extends BaseDataFetch<
12
12
  ViewDatasource,
13
13
  ViewV2Enriched
14
14
  > {
@@ -11,6 +11,7 @@ import GroupUserFetch from "./GroupUserFetch"
11
11
  import CustomFetch from "./CustomFetch"
12
12
  import QueryArrayFetch from "./QueryArrayFetch"
13
13
  import { APIClient } from "../api/types"
14
+ import { DataFetchDatasource, Table, ViewV2Enriched } from "@budibase/types"
14
15
 
15
16
  export type DataFetchType = keyof typeof DataFetchMap
16
17
 
@@ -26,32 +27,88 @@ export const DataFetchMap = {
26
27
 
27
28
  // Client specific datasource types
28
29
  provider: NestedProviderFetch,
29
- field: FieldFetch<"field">,
30
+ field: FieldFetch,
30
31
  jsonarray: JSONArrayFetch,
31
32
  queryarray: QueryArrayFetch,
32
33
  }
33
34
 
35
+ export interface DataFetchClassMap {
36
+ table: TableFetch
37
+ view: ViewFetch
38
+ viewV2: ViewV2Fetch
39
+ query: QueryFetch
40
+ link: RelationshipFetch
41
+ user: UserFetch
42
+ groupUser: GroupUserFetch
43
+ custom: CustomFetch
44
+
45
+ // Client specific datasource types
46
+ provider: NestedProviderFetch
47
+ field: FieldFetch
48
+ jsonarray: JSONArrayFetch
49
+ queryarray: QueryArrayFetch
50
+ }
51
+
52
+ export type DataFetch =
53
+ | TableFetch
54
+ | ViewFetch
55
+ | ViewV2Fetch
56
+ | QueryFetch
57
+ | RelationshipFetch
58
+ | UserFetch
59
+ | GroupUserFetch
60
+ | CustomFetch
61
+ | NestedProviderFetch
62
+ | FieldFetch
63
+ | JSONArrayFetch
64
+ | QueryArrayFetch
65
+
66
+ export type DataFetchDefinition =
67
+ | Table
68
+ | ViewV2Enriched
69
+ | {
70
+ // These fields are added to allow checking these fields on definition usages without requiring constant castings
71
+ schema?: Record<string, any> | null
72
+ primaryDisplay?: string
73
+ rowHeight?: number
74
+ type?: string
75
+ name?: string
76
+ }
77
+
34
78
  // Constructs a new fetch model for a certain datasource
35
- export const fetchData = ({ API, datasource, options }: any) => {
36
- const Fetch = DataFetchMap[datasource?.type as DataFetchType] || TableFetch
79
+ export const fetchData = <
80
+ T extends DataFetchDatasource,
81
+ Type extends T["type"] = T["type"]
82
+ >({
83
+ API,
84
+ datasource,
85
+ options,
86
+ }: {
87
+ API: APIClient
88
+ datasource: T
89
+ options: any
90
+ }): Type extends keyof DataFetchClassMap
91
+ ? DataFetchClassMap[Type]
92
+ : TableFetch => {
93
+ const Fetch = DataFetchMap[datasource?.type] || TableFetch
37
94
  const fetch = new Fetch({ API, datasource, ...options })
38
95
 
39
96
  // Initially fetch data but don't bother waiting for the result
40
97
  fetch.getInitialData()
41
98
 
42
- return fetch
99
+ return fetch as any
43
100
  }
44
101
 
45
102
  // Creates an empty fetch instance with no datasource configured, so no data
46
103
  // will initially be loaded
47
- const createEmptyFetchInstance = <TDatasource extends { type: DataFetchType }>({
104
+ const createEmptyFetchInstance = ({
48
105
  API,
49
106
  datasource,
50
107
  }: {
51
108
  API: APIClient
52
- datasource: TDatasource
109
+ datasource: DataFetchDatasource
53
110
  }) => {
54
- const handler = DataFetchMap[datasource?.type as DataFetchType]
111
+ const handler = DataFetchMap[datasource?.type]
55
112
  if (!handler) {
56
113
  return null
57
114
  }
@@ -63,29 +120,25 @@ const createEmptyFetchInstance = <TDatasource extends { type: DataFetchType }>({
63
120
  }
64
121
 
65
122
  // Fetches the definition of any type of datasource
66
- export const getDatasourceDefinition = async <
67
- TDatasource extends { type: DataFetchType }
68
- >({
123
+ export const getDatasourceDefinition = async ({
69
124
  API,
70
125
  datasource,
71
126
  }: {
72
127
  API: APIClient
73
- datasource: TDatasource
128
+ datasource: DataFetchDatasource
74
129
  }) => {
75
130
  const instance = createEmptyFetchInstance({ API, datasource })
76
131
  return await instance?.getDefinition()
77
132
  }
78
133
 
79
134
  // Fetches the schema of any type of datasource
80
- export const getDatasourceSchema = <
81
- TDatasource extends { type: DataFetchType }
82
- >({
135
+ export const getDatasourceSchema = ({
83
136
  API,
84
137
  datasource,
85
138
  definition,
86
139
  }: {
87
140
  API: APIClient
88
- datasource: TDatasource
141
+ datasource: DataFetchDatasource
89
142
  definition?: any
90
143
  }) => {
91
144
  const instance = createEmptyFetchInstance({ API, datasource })
package/src/index.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  export { createAPIClient } from "./api"
2
2
  export type { APIClient } from "./api"
3
3
  export { fetchData, DataFetchMap } from "./fetch"
4
- export type { DataFetchType } from "./fetch"
5
4
  export * as Constants from "./constants"
6
5
  export * from "./stores"
7
6
  export * from "./utils"
@@ -8,6 +8,7 @@ export * as search from "./searchFields"
8
8
  export * as SchemaUtils from "./schema"
9
9
  export { memo, derivedMemo } from "./memo"
10
10
  export { createWebsocket } from "./websocket"
11
+ export * as JsonFormatter from "./jsonFormatter"
11
12
  export * from "./download"
12
13
  export * from "./settings"
13
14
  export * from "./relatedColumns"
@@ -0,0 +1,71 @@
1
+ import { JSONValue } from "@budibase/types"
2
+
3
+ export type ColorsOptions = {
4
+ keyColor?: string
5
+ numberColor?: string
6
+ stringColor?: string
7
+ trueColor?: string
8
+ falseColor?: string
9
+ nullColor?: string
10
+ }
11
+
12
+ const defaultColors: ColorsOptions = {
13
+ keyColor: "dimgray",
14
+ numberColor: "lightskyblue",
15
+ stringColor: "lightcoral",
16
+ trueColor: "lightseagreen",
17
+ falseColor: "#f66578",
18
+ nullColor: "cornflowerblue",
19
+ }
20
+
21
+ const entityMap = {
22
+ "&": "&amp;",
23
+ "<": "&lt;",
24
+ ">": "&gt;",
25
+ '"': "&quot;",
26
+ "'": "&#39;",
27
+ "`": "&#x60;",
28
+ "=": "&#x3D;",
29
+ }
30
+
31
+ function escapeHtml(html: string) {
32
+ return String(html).replace(/[&<>"'`=]/g, function (s) {
33
+ return entityMap[s as keyof typeof entityMap]
34
+ })
35
+ }
36
+
37
+ export function format(json: JSONValue, colorOptions: ColorsOptions = {}) {
38
+ const valueType = typeof json
39
+ let jsonString =
40
+ typeof json === "string" ? json : JSON.stringify(json, null, 2) || valueType
41
+ let colors = Object.assign({}, defaultColors, colorOptions)
42
+ jsonString = jsonString
43
+ .replace(/&/g, "&")
44
+ .replace(/</g, "<")
45
+ .replace(/>/g, ">")
46
+ return jsonString.replace(
47
+ /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+]?\d+)?)/g,
48
+ (match: string) => {
49
+ let color = colors.numberColor
50
+ let style = ""
51
+ if (/^"/.test(match)) {
52
+ if (/:$/.test(match)) {
53
+ color = colors.keyColor
54
+ } else {
55
+ color = colors.stringColor
56
+ match = '"' + escapeHtml(match.substr(1, match.length - 2)) + '"'
57
+ style = "word-wrap:break-word;white-space:pre-wrap;"
58
+ }
59
+ } else {
60
+ color = /true/.test(match)
61
+ ? colors.trueColor
62
+ : /false/.test(match)
63
+ ? colors.falseColor
64
+ : /null/.test(match)
65
+ ? colors.nullColor
66
+ : color
67
+ }
68
+ return `<span style="${style}color:${color}">${match}</span>`
69
+ }
70
+ )
71
+ }
@@ -43,7 +43,7 @@ export const sequential = fn => {
43
43
  * invocations is enforced.
44
44
  * @param callback an async function to run
45
45
  * @param minDelay the minimum delay between invocations
46
- * @returns {Promise} a debounced version of the callback
46
+ * @returns a debounced version of the callback
47
47
  */
48
48
  export const debounce = (callback, minDelay = 1000) => {
49
49
  let timeout