@budibase/frontend-core 3.8.0 → 3.8.2

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.8.0",
3
+ "version": "3.8.2",
4
4
  "description": "Budibase frontend core libraries used in builder and client",
5
5
  "author": "Budibase",
6
6
  "license": "MPL-2.0",
@@ -17,5 +17,5 @@
17
17
  "shortid": "2.2.15",
18
18
  "socket.io-client": "^4.7.5"
19
19
  },
20
- "gitHead": "9bf4efcee5ec5016aeafacbf1ea2bb32b08d922d"
20
+ "gitHead": "de9bbc8e465a6c939bf23c2fde11a4ce80cbc709"
21
21
  }
@@ -1,8 +1,5 @@
1
- <script context="module">
2
- const NumberFormatter = Intl.NumberFormat()
3
- </script>
4
-
5
1
  <script>
2
+ import { formatNumber } from "@budibase/frontend-core"
6
3
  import TextCell from "./TextCell.svelte"
7
4
 
8
5
  export let api
@@ -13,18 +10,6 @@
13
10
  const newValue = isNaN(float) ? null : float
14
11
  onChange(newValue)
15
12
  }
16
-
17
- const formatNumber = value => {
18
- const type = typeof value
19
- if (type !== "string" && type !== "number") {
20
- return ""
21
- }
22
- if (type === "string" && !value.trim().length) {
23
- return ""
24
- }
25
- const res = NumberFormatter.format(value)
26
- return res === "NaN" ? value : res
27
- }
28
13
  </script>
29
14
 
30
15
  <TextCell
@@ -0,0 +1,149 @@
1
+ import {
2
+ BBReferenceFieldSubType,
3
+ FieldSchema,
4
+ FieldType,
5
+ Row,
6
+ TableSchema,
7
+ } from "@budibase/types"
8
+ import { Helpers } from "@budibase/bbui"
9
+
10
+ // Singleton formatter to save us creating one every time
11
+ const NumberFormatter = Intl.NumberFormat()
12
+
13
+ export type StringifiedRow = { [key: string]: string }
14
+
15
+ // Formats a number according to the locale
16
+ export const formatNumber = (value: any): string => {
17
+ const type = typeof value
18
+ if (type !== "string" && type !== "number") {
19
+ return ""
20
+ }
21
+ if (type === "string" && !value.trim().length) {
22
+ return ""
23
+ }
24
+ const res = NumberFormatter.format(value)
25
+ return res === "NaN" ? stringifyValue(value) : res
26
+ }
27
+
28
+ // Attempts to stringify any type of value
29
+ const stringifyValue = (value: any): string => {
30
+ if (value == null) {
31
+ return ""
32
+ }
33
+ if (typeof value === "string") {
34
+ return value
35
+ }
36
+ if (typeof value.toString === "function") {
37
+ return stringifyValue(value.toString())
38
+ }
39
+ try {
40
+ return JSON.stringify(value)
41
+ } catch (e) {
42
+ return ""
43
+ }
44
+ }
45
+
46
+ const stringifyField = (value: any, schema: FieldSchema): string => {
47
+ switch (schema.type) {
48
+ // Auto should not exist as it should always be typed by its underlying
49
+ // real type, like date or user
50
+ case FieldType.AUTO:
51
+ return ""
52
+
53
+ // Just state whether signatures exist or not
54
+ case FieldType.SIGNATURE_SINGLE:
55
+ return value ? "Yes" : "No"
56
+
57
+ // Extract attachment names
58
+ case FieldType.ATTACHMENT_SINGLE:
59
+ case FieldType.ATTACHMENTS: {
60
+ if (!value) {
61
+ return ""
62
+ }
63
+ const arrayValue = Array.isArray(value) ? value : [value]
64
+ return arrayValue
65
+ .map(x => x.name)
66
+ .filter(x => !!x)
67
+ .join(", ")
68
+ }
69
+
70
+ // Extract primary displays from relationships
71
+ case FieldType.LINK: {
72
+ if (!value) {
73
+ return ""
74
+ }
75
+ const arrayValue = Array.isArray(value) ? value : [value]
76
+ return arrayValue
77
+ .map(x => x.primaryDisplay)
78
+ .filter(x => !!x)
79
+ .join(", ")
80
+ }
81
+
82
+ // Stringify JSON blobs
83
+ case FieldType.JSON:
84
+ return value ? JSON.stringify(value) : ""
85
+
86
+ // User is the only BB reference subtype right now
87
+ case FieldType.BB_REFERENCE:
88
+ case FieldType.BB_REFERENCE_SINGLE: {
89
+ if (
90
+ schema.subtype !== BBReferenceFieldSubType.USERS &&
91
+ schema.subtype !== BBReferenceFieldSubType.USER
92
+ ) {
93
+ return ""
94
+ }
95
+ if (!value) {
96
+ return ""
97
+ }
98
+ const arrayVal = Array.isArray(value) ? value : [value]
99
+ return arrayVal?.map((user: any) => user.primaryDisplay).join(", ") || ""
100
+ }
101
+
102
+ // Join arrays with commas
103
+ case FieldType.ARRAY:
104
+ return value?.join(", ") || ""
105
+
106
+ // Just capitalise booleans
107
+ case FieldType.BOOLEAN:
108
+ return Helpers.capitalise(value?.toString() || "false")
109
+
110
+ // Format dates into something readable
111
+ case FieldType.DATETIME: {
112
+ return Helpers.getDateDisplayValue(value, {
113
+ enableTime: !schema.dateOnly,
114
+ timeOnly: schema.timeOnly,
115
+ })
116
+ }
117
+
118
+ // Format numbers using a locale string
119
+ case FieldType.NUMBER:
120
+ return formatNumber(value)
121
+
122
+ // Simple string types
123
+ case FieldType.STRING:
124
+ case FieldType.LONGFORM:
125
+ case FieldType.BIGINT:
126
+ case FieldType.OPTIONS:
127
+ case FieldType.AI:
128
+ case FieldType.BARCODEQR:
129
+ return value || ""
130
+
131
+ // Fallback for unknown types or future column types that we forget to add
132
+ case FieldType.FORMULA:
133
+ default:
134
+ return stringifyValue(value)
135
+ }
136
+ }
137
+
138
+ // Stringifies every property of a row, ensuring they are all human-readable
139
+ // strings for display
140
+ export const stringifyRow = (row: Row, schema: TableSchema): StringifiedRow => {
141
+ let stringified: StringifiedRow = {}
142
+ Object.entries(schema).forEach(([field, fieldSchema]) => {
143
+ stringified[field] = stringifyField(
144
+ Helpers.deepGet(row, field),
145
+ fieldSchema
146
+ )
147
+ })
148
+ return stringified
149
+ }
@@ -15,3 +15,4 @@ export * from "./relatedColumns"
15
15
  export * from "./table"
16
16
  export * from "./components"
17
17
  export * from "./validation"
18
+ export * from "./formatting"
@@ -1,5 +1,6 @@
1
1
  import { helpers } from "@budibase/shared-core"
2
2
  import { TypeIconMap } from "../constants"
3
+ import { convertJSONSchemaToTableSchema } from "./json"
3
4
 
4
5
  export const getColumnIcon = column => {
5
6
  // For some reason we have remix icons saved under this property sometimes,
@@ -24,3 +25,25 @@ export const getColumnIcon = column => {
24
25
 
25
26
  return result || "Text"
26
27
  }
28
+
29
+ export const addNestedJSONSchemaFields = schema => {
30
+ if (!schema) {
31
+ return schema
32
+ }
33
+ let jsonAdditions = {}
34
+ Object.keys(schema).forEach(fieldKey => {
35
+ const fieldSchema = schema[fieldKey]
36
+ if (fieldSchema?.type === "json") {
37
+ const jsonSchema = convertJSONSchemaToTableSchema(fieldSchema, {
38
+ squashObjects: true,
39
+ })
40
+ Object.keys(jsonSchema).forEach(jsonKey => {
41
+ jsonAdditions[`${fieldKey}.${jsonKey}`] = {
42
+ type: jsonSchema[jsonKey].type,
43
+ nestedJSON: true,
44
+ }
45
+ })
46
+ }
47
+ })
48
+ return { ...schema, ...jsonAdditions }
49
+ }