Merge pull request #15838 from Budibase/pdf-specific-components
PDF table component
This commit is contained in:
commit
9d7ba4edd4
|
@ -211,9 +211,12 @@ const localeDateFormat = new Intl.DateTimeFormat()
|
|||
|
||||
// Formats a dayjs date according to schema flags
|
||||
export const getDateDisplayValue = (
|
||||
value: dayjs.Dayjs | null,
|
||||
value: dayjs.Dayjs | string | null,
|
||||
{ enableTime = true, timeOnly = false } = {}
|
||||
): string => {
|
||||
if (typeof value === "string") {
|
||||
value = dayjs(value)
|
||||
}
|
||||
if (!value?.isValid()) {
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import ValidationEditor from "./controls/ValidationEditor/ValidationEditor.svelt
|
|||
import DrawerBindableInput from "@/components/common/bindings/DrawerBindableInput.svelte"
|
||||
import ColumnEditor from "./controls/ColumnEditor/ColumnEditor.svelte"
|
||||
import BasicColumnEditor from "./controls/ColumnEditor/BasicColumnEditor.svelte"
|
||||
import TopLevelColumnEditor from "./controls/ColumnEditor/TopLevelColumnEditor.svelte"
|
||||
import GridColumnEditor from "./controls/GridColumnConfiguration/GridColumnConfiguration.svelte"
|
||||
import BarButtonList from "./controls/BarButtonList.svelte"
|
||||
import FieldConfiguration from "./controls/FieldConfiguration/FieldConfiguration.svelte"
|
||||
|
@ -62,7 +63,10 @@ const componentMap = {
|
|||
stepConfiguration: FormStepConfiguration,
|
||||
formStepControls: FormStepControls,
|
||||
columns: ColumnEditor,
|
||||
// "Basic" actually includes nested JSON and relationship fields
|
||||
"columns/basic": BasicColumnEditor,
|
||||
// "Top level" is only the top level schema fields
|
||||
"columns/toplevel": TopLevelColumnEditor,
|
||||
"columns/grid": GridColumnEditor,
|
||||
tableConditions: TableConditionEditor,
|
||||
"field/sortable": SortableFieldSelect,
|
||||
|
|
|
@ -145,7 +145,7 @@
|
|||
<div class="column">
|
||||
<div class="wide">
|
||||
<Body size="S">
|
||||
By default, all columns will automatically be shown.
|
||||
The default column configuration will automatically be shown.
|
||||
<br />
|
||||
You can manually control which columns are included by adding them
|
||||
below.
|
||||
|
|
|
@ -10,10 +10,18 @@
|
|||
} from "@/dataBinding"
|
||||
import { selectedScreen, tables } from "@/stores/builder"
|
||||
|
||||
export let componentInstance
|
||||
const getSearchableFields = (schema, tableList) => {
|
||||
return search.getFields(tableList, Object.values(schema || {}), {
|
||||
allowLinks: true,
|
||||
})
|
||||
}
|
||||
|
||||
export let componentInstance = undefined
|
||||
export let value = []
|
||||
export let allowCellEditing = true
|
||||
export let allowReorder = true
|
||||
export let getSchemaFields = getSearchableFields
|
||||
export let placeholder = "All columns"
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
|
@ -28,13 +36,7 @@
|
|||
: enrichedSchemaFields?.map(field => field.name)
|
||||
$: sanitisedValue = getValidColumns(value, options)
|
||||
$: updateBoundValue(sanitisedValue)
|
||||
$: enrichedSchemaFields = search.getFields(
|
||||
$tables.list,
|
||||
Object.values(schema || {}),
|
||||
{
|
||||
allowLinks: true,
|
||||
}
|
||||
)
|
||||
$: enrichedSchemaFields = getSchemaFields(schema, $tables.list)
|
||||
|
||||
$: {
|
||||
value = (value || []).filter(
|
||||
|
@ -44,7 +46,7 @@
|
|||
|
||||
const getText = value => {
|
||||
if (!value?.length) {
|
||||
return "All columns"
|
||||
return placeholder
|
||||
}
|
||||
let text = `${value.length} column`
|
||||
if (value.length !== 1) {
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<script lang="ts">
|
||||
import ColumnEditor from "./ColumnEditor.svelte"
|
||||
import type { TableSchema } from "@budibase/types"
|
||||
|
||||
const getTopLevelSchemaFields = (schema: TableSchema) => {
|
||||
return Object.values(schema).filter(fieldSchema => !fieldSchema.nestedJSON)
|
||||
}
|
||||
</script>
|
||||
|
||||
<ColumnEditor
|
||||
{...$$props}
|
||||
on:change
|
||||
allowCellEditing={false}
|
||||
getSchemaFields={getTopLevelSchemaFields}
|
||||
/>
|
|
@ -26,7 +26,7 @@ import {
|
|||
getJsHelperList,
|
||||
} from "@budibase/string-templates"
|
||||
import { TableNames } from "./constants"
|
||||
import { JSONUtils, Constants } from "@budibase/frontend-core"
|
||||
import { JSONUtils, Constants, SchemaUtils } from "@budibase/frontend-core"
|
||||
import ActionDefinitions from "@/components/design/settings/controls/ButtonActionEditor/manifest.json"
|
||||
import { environment, licensing } from "@/stores/portal"
|
||||
import { convertOldFieldFormat } from "@/components/design/settings/controls/FieldConfiguration/utils"
|
||||
|
@ -1026,25 +1026,7 @@ export const getSchemaForDatasource = (asset, datasource, options) => {
|
|||
|
||||
// Check for any JSON fields so we can add any top level properties
|
||||
if (schema) {
|
||||
let jsonAdditions = {}
|
||||
Object.keys(schema).forEach(fieldKey => {
|
||||
const fieldSchema = schema[fieldKey]
|
||||
if (fieldSchema?.type === "json") {
|
||||
const jsonSchema = JSONUtils.convertJSONSchemaToTableSchema(
|
||||
fieldSchema,
|
||||
{
|
||||
squashObjects: true,
|
||||
}
|
||||
)
|
||||
Object.keys(jsonSchema).forEach(jsonKey => {
|
||||
jsonAdditions[`${fieldKey}.${jsonKey}`] = {
|
||||
type: jsonSchema[jsonKey].type,
|
||||
nestedJSON: true,
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
schema = { ...schema, ...jsonAdditions }
|
||||
schema = SchemaUtils.addNestedJSONSchemaFields(schema)
|
||||
}
|
||||
|
||||
// Determine if we should add ID and rev to the schema
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
"dataprovider",
|
||||
"repeater",
|
||||
"gridblock",
|
||||
"pdftable",
|
||||
"spreadsheet",
|
||||
"dynamicfilter",
|
||||
"daterangepicker"
|
||||
|
|
|
@ -8017,6 +8017,32 @@
|
|||
"key": "text",
|
||||
"wide": true
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Size",
|
||||
"key": "size",
|
||||
"defaultValue": "14px",
|
||||
"showInBar": true,
|
||||
"placeholder": "Default",
|
||||
"options": [
|
||||
{
|
||||
"label": "Small",
|
||||
"value": "12px"
|
||||
},
|
||||
{
|
||||
"label": "Medium",
|
||||
"value": "14px"
|
||||
},
|
||||
{
|
||||
"label": "Large",
|
||||
"value": "18px"
|
||||
},
|
||||
{
|
||||
"label": "Extra large",
|
||||
"value": "24px"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Alignment",
|
||||
|
@ -8088,5 +8114,71 @@
|
|||
"defaultValue": "Download PDF"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pdftable": {
|
||||
"name": "PDF Table",
|
||||
"icon": "Table",
|
||||
"styles": ["size"],
|
||||
"size": {
|
||||
"width": 600,
|
||||
"height": 304
|
||||
},
|
||||
"grid": {
|
||||
"hAlign": "stretch",
|
||||
"vAlign": "stretch"
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
"type": "dataSource",
|
||||
"label": "Data",
|
||||
"key": "datasource",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "filter",
|
||||
"label": "Filtering",
|
||||
"key": "filter",
|
||||
"resetOn": "datasource",
|
||||
"dependsOn": {
|
||||
"setting": "datasource.type",
|
||||
"value": "custom",
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "field/sortable",
|
||||
"label": "Sort column",
|
||||
"key": "sortColumn",
|
||||
"placeholder": "Default",
|
||||
"resetOn": "datasource",
|
||||
"dependsOn": {
|
||||
"setting": "datasource.type",
|
||||
"value": "custom",
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Sort order",
|
||||
"key": "sortOrder",
|
||||
"resetOn": "datasource",
|
||||
"options": ["Ascending", "Descending"],
|
||||
"defaultValue": "Ascending",
|
||||
"dependsOn": "sortColumn"
|
||||
},
|
||||
{
|
||||
"type": "columns/toplevel",
|
||||
"label": "Columns",
|
||||
"key": "columns",
|
||||
"resetOn": "datasource",
|
||||
"placeholder": "First 3 columns"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"label": "Limit",
|
||||
"key": "limit",
|
||||
"defaultValue": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
export let text: any = ""
|
||||
export let color: string | undefined = undefined
|
||||
export let align: "left" | "center" | "right" | "justify" = "left"
|
||||
export let size: string | undefined = "14px"
|
||||
|
||||
const component = getContext("component")
|
||||
const { styleable } = getContext("sdk")
|
||||
|
||||
// Add in certain settings to styles
|
||||
$: styles = enrichStyles($component.styles, color, align)
|
||||
$: styles = enrichStyles($component.styles, color, align, size)
|
||||
|
||||
// Ensure we're always passing in a string value to the markdown editor
|
||||
$: safeText = stringify(text)
|
||||
|
@ -18,10 +19,12 @@
|
|||
const enrichStyles = (
|
||||
styles: any,
|
||||
colorStyle: typeof color,
|
||||
alignStyle: typeof align
|
||||
alignStyle: typeof align,
|
||||
size: string | undefined
|
||||
) => {
|
||||
let additions: Record<string, string> = {
|
||||
"text-align": alignStyle,
|
||||
"font-size": size || "14px",
|
||||
}
|
||||
if (colorStyle) {
|
||||
additions.color = colorStyle
|
||||
|
|
|
@ -36,11 +36,11 @@ export { default as sidepanel } from "./SidePanel.svelte"
|
|||
export { default as modal } from "./Modal.svelte"
|
||||
export { default as gridblock } from "./GridBlock.svelte"
|
||||
export { default as textv2 } from "./Text.svelte"
|
||||
export { default as pdf } from "./pdf/PDF.svelte"
|
||||
export * from "./charts"
|
||||
export * from "./forms"
|
||||
export * from "./blocks"
|
||||
export * from "./dynamic-filter"
|
||||
export * from "./pdf"
|
||||
|
||||
// Deprecated component left for compatibility in old apps
|
||||
export * from "./deprecated/table"
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
<script lang="ts">
|
||||
import type {
|
||||
DataFetchDatasource,
|
||||
FieldSchema,
|
||||
GroupUserDatasource,
|
||||
SortOrder,
|
||||
TableSchema,
|
||||
UISearchFilter,
|
||||
UserDatasource,
|
||||
} from "@budibase/types"
|
||||
import { fetchData, QueryUtils, stringifyRow } from "@budibase/frontend-core"
|
||||
import { getContext } from "svelte"
|
||||
|
||||
type ProviderDatasource = Exclude<
|
||||
DataFetchDatasource,
|
||||
UserDatasource | GroupUserDatasource
|
||||
>
|
||||
type ChosenColumns = Array<{ name: string; displayName?: string }> | undefined
|
||||
type Schema = { [key: string]: FieldSchema & { displayName: string } }
|
||||
|
||||
export let datasource: ProviderDatasource
|
||||
export let filter: UISearchFilter | undefined = undefined
|
||||
export let sortColumn: string | undefined = undefined
|
||||
export let sortOrder: SortOrder | undefined = undefined
|
||||
export let columns: ChosenColumns = undefined
|
||||
export let limit: number = 20
|
||||
|
||||
const component = getContext("component")
|
||||
const { styleable, API } = getContext("sdk")
|
||||
|
||||
$: query = QueryUtils.buildQuery(filter)
|
||||
$: fetch = createFetch(datasource)
|
||||
$: fetch.update({
|
||||
query,
|
||||
sortColumn,
|
||||
sortOrder,
|
||||
limit,
|
||||
})
|
||||
$: schema = sanitizeSchema($fetch.schema, columns)
|
||||
$: columnCount = Object.keys(schema).length
|
||||
$: rowCount = $fetch.rows?.length || 0
|
||||
$: stringifiedRows = ($fetch?.rows || []).map(row =>
|
||||
stringifyRow(row, schema)
|
||||
)
|
||||
|
||||
const createFetch = (datasource: ProviderDatasource) => {
|
||||
return fetchData({
|
||||
API,
|
||||
datasource,
|
||||
options: {
|
||||
query,
|
||||
sortColumn,
|
||||
sortOrder,
|
||||
limit,
|
||||
paginate: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const sanitizeSchema = (
|
||||
schema: TableSchema | null,
|
||||
columns: ChosenColumns
|
||||
): Schema => {
|
||||
if (!schema) {
|
||||
return {}
|
||||
}
|
||||
let sanitized: Schema = {}
|
||||
|
||||
// Clean out hidden fields and ensure we have
|
||||
Object.entries(schema).forEach(([field, fieldSchema]) => {
|
||||
if (fieldSchema.visible !== false) {
|
||||
sanitized[field] = {
|
||||
...fieldSchema,
|
||||
displayName: field,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Clean out unselected columns.
|
||||
// Default to first 3 columns if none specified, as we are width contrained.
|
||||
if (!columns?.length) {
|
||||
columns = Object.values(sanitized).slice(0, 3)
|
||||
}
|
||||
let pruned: Schema = {}
|
||||
for (let col of columns) {
|
||||
if (sanitized[col.name]) {
|
||||
pruned[col.name] = {
|
||||
...sanitized[col.name],
|
||||
displayName: col.displayName || sanitized[col.name].displayName,
|
||||
}
|
||||
}
|
||||
}
|
||||
sanitized = pruned
|
||||
|
||||
return sanitized
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="vars" style="--cols:{columnCount}; --rows:{rowCount};">
|
||||
<div class="table" class:valid={!!schema} use:styleable={$component.styles}>
|
||||
{#if schema}
|
||||
{#each Object.keys(schema) as col}
|
||||
<div class="cell header">{schema[col].displayName}</div>
|
||||
{/each}
|
||||
{#each stringifiedRows as row}
|
||||
{#each Object.keys(schema) as col}
|
||||
<div class="cell">{row[col]}</div>
|
||||
{/each}
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.vars {
|
||||
display: contents;
|
||||
--border-color: var(--spectrum-global-color-gray-300);
|
||||
}
|
||||
.table {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--cols), minmax(40px, auto));
|
||||
grid-template-rows: repeat(var(--rows), max-content);
|
||||
overflow: hidden;
|
||||
background: var(--spectrum-global-color-gray-50);
|
||||
}
|
||||
.table.valid {
|
||||
border-left: 1px solid var(--border-color);
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
.cell {
|
||||
border-right: 1px solid var(--border-color);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
padding: var(--spacing-xs) var(--spacing-s);
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
}
|
||||
.cell.header {
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,2 @@
|
|||
export { default as pdf } from "./PDF.svelte"
|
||||
export { default as pdftable } from "./PDFTable.svelte"
|
|
@ -1,8 +1,5 @@
|
|||
<script context="module">
|
||||
const NumberFormatter = Intl.NumberFormat()
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { formatNumber } from "@budibase/frontend-core"
|
||||
import TextCell from "./TextCell.svelte"
|
||||
|
||||
export let api
|
||||
|
@ -13,18 +10,6 @@
|
|||
const newValue = isNaN(float) ? null : float
|
||||
onChange(newValue)
|
||||
}
|
||||
|
||||
const formatNumber = value => {
|
||||
const type = typeof value
|
||||
if (type !== "string" && type !== "number") {
|
||||
return ""
|
||||
}
|
||||
if (type === "string" && !value.trim().length) {
|
||||
return ""
|
||||
}
|
||||
const res = NumberFormatter.format(value)
|
||||
return res === "NaN" ? value : res
|
||||
}
|
||||
</script>
|
||||
|
||||
<TextCell
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
import {
|
||||
BBReferenceFieldSubType,
|
||||
FieldSchema,
|
||||
FieldType,
|
||||
Row,
|
||||
TableSchema,
|
||||
} from "@budibase/types"
|
||||
import { Helpers } from "@budibase/bbui"
|
||||
|
||||
// Singleton formatter to save us creating one every time
|
||||
const NumberFormatter = Intl.NumberFormat()
|
||||
|
||||
export type StringifiedRow = { [key: string]: string }
|
||||
|
||||
// Formats a number according to the locale
|
||||
export const formatNumber = (value: any): string => {
|
||||
const type = typeof value
|
||||
if (type !== "string" && type !== "number") {
|
||||
return ""
|
||||
}
|
||||
if (type === "string" && !value.trim().length) {
|
||||
return ""
|
||||
}
|
||||
const res = NumberFormatter.format(value)
|
||||
return res === "NaN" ? stringifyValue(value) : res
|
||||
}
|
||||
|
||||
// Attempts to stringify any type of value
|
||||
const stringifyValue = (value: any): string => {
|
||||
if (value == null) {
|
||||
return ""
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
return value
|
||||
}
|
||||
if (typeof value.toString === "function") {
|
||||
return stringifyValue(value.toString())
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(value)
|
||||
} catch (e) {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
const stringifyField = (value: any, schema: FieldSchema): string => {
|
||||
switch (schema.type) {
|
||||
// Auto should not exist as it should always be typed by its underlying
|
||||
// real type, like date or user
|
||||
case FieldType.AUTO:
|
||||
return ""
|
||||
|
||||
// Just state whether signatures exist or not
|
||||
case FieldType.SIGNATURE_SINGLE:
|
||||
return value ? "Yes" : "No"
|
||||
|
||||
// Extract attachment names
|
||||
case FieldType.ATTACHMENT_SINGLE:
|
||||
case FieldType.ATTACHMENTS: {
|
||||
if (!value) {
|
||||
return ""
|
||||
}
|
||||
const arrayValue = Array.isArray(value) ? value : [value]
|
||||
return arrayValue
|
||||
.map(x => x.name)
|
||||
.filter(x => !!x)
|
||||
.join(", ")
|
||||
}
|
||||
|
||||
// Extract primary displays from relationships
|
||||
case FieldType.LINK: {
|
||||
if (!value) {
|
||||
return ""
|
||||
}
|
||||
const arrayValue = Array.isArray(value) ? value : [value]
|
||||
return arrayValue
|
||||
.map(x => x.primaryDisplay)
|
||||
.filter(x => !!x)
|
||||
.join(", ")
|
||||
}
|
||||
|
||||
// Stringify JSON blobs
|
||||
case FieldType.JSON:
|
||||
return value ? JSON.stringify(value) : ""
|
||||
|
||||
// User is the only BB reference subtype right now
|
||||
case FieldType.BB_REFERENCE:
|
||||
case FieldType.BB_REFERENCE_SINGLE: {
|
||||
if (
|
||||
schema.subtype !== BBReferenceFieldSubType.USERS &&
|
||||
schema.subtype !== BBReferenceFieldSubType.USER
|
||||
) {
|
||||
return ""
|
||||
}
|
||||
if (!value) {
|
||||
return ""
|
||||
}
|
||||
const arrayVal = Array.isArray(value) ? value : [value]
|
||||
return arrayVal?.map((user: any) => user.primaryDisplay).join(", ") || ""
|
||||
}
|
||||
|
||||
// Join arrays with commas
|
||||
case FieldType.ARRAY:
|
||||
return value?.join(", ") || ""
|
||||
|
||||
// Just capitalise booleans
|
||||
case FieldType.BOOLEAN:
|
||||
return Helpers.capitalise(value?.toString() || "false")
|
||||
|
||||
// Format dates into something readable
|
||||
case FieldType.DATETIME: {
|
||||
return Helpers.getDateDisplayValue(value, {
|
||||
enableTime: !schema.dateOnly,
|
||||
timeOnly: schema.timeOnly,
|
||||
})
|
||||
}
|
||||
|
||||
// Format numbers using a locale string
|
||||
case FieldType.NUMBER:
|
||||
return formatNumber(value)
|
||||
|
||||
// Simple string types
|
||||
case FieldType.STRING:
|
||||
case FieldType.LONGFORM:
|
||||
case FieldType.BIGINT:
|
||||
case FieldType.OPTIONS:
|
||||
case FieldType.AI:
|
||||
case FieldType.BARCODEQR:
|
||||
return value || ""
|
||||
|
||||
// Fallback for unknown types or future column types that we forget to add
|
||||
case FieldType.FORMULA:
|
||||
default:
|
||||
return stringifyValue(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Stringifies every property of a row, ensuring they are all human-readable
|
||||
// strings for display
|
||||
export const stringifyRow = (row: Row, schema: TableSchema): StringifiedRow => {
|
||||
let stringified: StringifiedRow = {}
|
||||
Object.entries(schema).forEach(([field, fieldSchema]) => {
|
||||
stringified[field] = stringifyField(
|
||||
Helpers.deepGet(row, field),
|
||||
fieldSchema
|
||||
)
|
||||
})
|
||||
return stringified
|
||||
}
|
|
@ -15,3 +15,4 @@ export * from "./relatedColumns"
|
|||
export * from "./table"
|
||||
export * from "./components"
|
||||
export * from "./validation"
|
||||
export * from "./formatting"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { helpers } from "@budibase/shared-core"
|
||||
import { TypeIconMap } from "../constants"
|
||||
import { convertJSONSchemaToTableSchema } from "./json"
|
||||
|
||||
export const getColumnIcon = column => {
|
||||
// For some reason we have remix icons saved under this property sometimes,
|
||||
|
@ -24,3 +25,25 @@ export const getColumnIcon = column => {
|
|||
|
||||
return result || "Text"
|
||||
}
|
||||
|
||||
export const addNestedJSONSchemaFields = schema => {
|
||||
if (!schema) {
|
||||
return schema
|
||||
}
|
||||
let jsonAdditions = {}
|
||||
Object.keys(schema).forEach(fieldKey => {
|
||||
const fieldSchema = schema[fieldKey]
|
||||
if (fieldSchema?.type === "json") {
|
||||
const jsonSchema = convertJSONSchemaToTableSchema(fieldSchema, {
|
||||
squashObjects: true,
|
||||
})
|
||||
Object.keys(jsonSchema).forEach(jsonKey => {
|
||||
jsonAdditions[`${fieldKey}.${jsonKey}`] = {
|
||||
type: jsonSchema[jsonKey].type,
|
||||
nestedJSON: true,
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return { ...schema, ...jsonAdditions }
|
||||
}
|
||||
|
|
|
@ -207,6 +207,8 @@ export interface BaseFieldSchema extends UIFieldMetadata {
|
|||
autocolumn?: boolean
|
||||
autoReason?: AutoReason.FOREIGN_KEY
|
||||
subtype?: never
|
||||
// added when enriching nested JSON fields into schema
|
||||
nestedJSON?: boolean
|
||||
}
|
||||
|
||||
interface OtherFieldMetadata extends BaseFieldSchema {
|
||||
|
|
Loading…
Reference in New Issue