Merge branch 'master' into BUDI-9016/extract-componenterrors-from-client

This commit is contained in:
Adria Navarro 2025-01-27 13:27:25 +01:00
commit a3e69b752d
6 changed files with 123 additions and 69 deletions

View File

@ -31,6 +31,11 @@
import IntegrationQueryEditor from "@/components/integration/index.svelte"
import { makePropSafe as safe } from "@budibase/string-templates"
import { findAllComponents } from "@/helpers/components"
import {
extractFields,
extractJSONArrayFields,
extractRelationships,
} from "@/helpers/bindings"
import ClientBindingPanel from "@/components/common/bindings/ClientBindingPanel.svelte"
import DataSourceCategory from "@/components/design/settings/controls/DataSourceSelect/DataSourceCategory.svelte"
import { API } from "@/api"
@ -81,67 +86,9 @@
value: `{{ literal ${safe(provider._id)} }}`,
type: "provider",
}))
$: links = bindings
// Get only link bindings
.filter(x => x.fieldSchema?.type === "link")
// Filter out bindings provided by forms
.filter(x => !x.component?.endsWith("/form"))
.map(binding => {
const { providerId, readableBinding, fieldSchema } = binding || {}
const { name, tableId } = fieldSchema || {}
const safeProviderId = safe(providerId)
return {
providerId,
label: readableBinding,
fieldName: name,
tableId,
type: "link",
// These properties will be enriched by the client library and provide
// details of the parent row of the relationship field, from context
rowId: `{{ ${safeProviderId}.${safe("_id")} }}`,
rowTableId: `{{ ${safeProviderId}.${safe("tableId")} }}`,
}
})
$: fields = bindings
.filter(
x =>
x.fieldSchema?.type === "attachment" ||
(x.fieldSchema?.type === "array" && x.tableId)
)
.map(binding => {
const { providerId, readableBinding, runtimeBinding } = binding
const { name, type, tableId } = binding.fieldSchema
return {
providerId,
label: readableBinding,
fieldName: name,
fieldType: type,
tableId,
type: "field",
value: `{{ literal ${runtimeBinding} }}`,
}
})
$: jsonArrays = bindings
.filter(
x =>
x.fieldSchema?.type === "jsonarray" ||
(x.fieldSchema?.type === "json" && x.fieldSchema?.subtype === "array")
)
.map(binding => {
const { providerId, readableBinding, runtimeBinding, tableId } = binding
const { name, type, prefixKeys, subtype } = binding.fieldSchema
return {
providerId,
label: readableBinding,
fieldName: name,
fieldType: type,
tableId,
prefixKeys,
type: type === "jsonarray" ? "jsonarray" : "queryarray",
subtype,
value: `{{ literal ${runtimeBinding} }}`,
}
})
$: links = extractRelationships(bindings)
$: fields = extractFields(bindings)
$: jsonArrays = extractJSONArrayFields(bindings)
$: custom = {
type: "custom",
label: "JSON / CSV",

View File

@ -0,0 +1,74 @@
import { makePropSafe } from "@budibase/string-templates"
import { UIBinding } from "@budibase/types"
export function extractRelationships(bindings: UIBinding[]) {
return (
bindings
// Get only link bindings
.filter(x => x.fieldSchema?.type === "link")
// Filter out bindings provided by forms
.filter(x => !x.component?.endsWith("/form"))
.map(binding => {
const { providerId, readableBinding, fieldSchema } = binding || {}
const { name, tableId } = fieldSchema || {}
const safeProviderId = makePropSafe(providerId)
return {
providerId,
label: readableBinding,
fieldName: name,
tableId,
type: "link",
// These properties will be enriched by the client library and provide
// details of the parent row of the relationship field, from context
rowId: `{{ ${safeProviderId}.${makePropSafe("_id")} }}`,
rowTableId: `{{ ${safeProviderId}.${makePropSafe("tableId")} }}`,
}
})
)
}
export function extractFields(bindings: UIBinding[]) {
return bindings
.filter(
x =>
x.fieldSchema?.type === "attachment" ||
(x.fieldSchema?.type === "array" && x.tableId)
)
.map(binding => {
const { providerId, readableBinding, runtimeBinding } = binding
const { name, type, tableId } = binding.fieldSchema!
return {
providerId,
label: readableBinding,
fieldName: name,
fieldType: type,
tableId,
type: "field",
value: `{{ literal ${runtimeBinding} }}`,
}
})
}
export function extractJSONArrayFields(bindings: UIBinding[]) {
return bindings
.filter(
x =>
x.fieldSchema?.type === "jsonarray" ||
(x.fieldSchema?.type === "json" && x.fieldSchema?.subtype === "array")
)
.map(binding => {
const { providerId, readableBinding, runtimeBinding, tableId } = binding
const { name, type, prefixKeys, subtype } = binding.fieldSchema!
return {
providerId,
label: readableBinding,
fieldName: name,
fieldType: type,
tableId,
prefixKeys,
type: type === "jsonarray" ? "jsonarray" : "queryarray",
subtype,
value: `{{ literal ${runtimeBinding} }}`,
}
})
}

View File

@ -10,3 +10,4 @@ export {
isBuilderInputFocused,
} from "./helpers"
export * as featureFlag from "./featureFlags"
export * as bindings from "./bindings"

View File

@ -14,13 +14,14 @@ import {
} from "@budibase/types"
import { queries } from "./queries"
import { views } from "./views"
import { featureFlag } from "@/helpers"
import { findAllComponents } from "@/helpers/components"
import { bindings, featureFlag } from "@/helpers"
import { getBindableProperties } from "@/dataBinding"
function reduceBy<TItem extends {}, TKey extends keyof TItem>(
key: TKey,
list: TItem[]
) {
): Record<string, any> {
return list.reduce(
(result, item) => ({
...result,
@ -40,6 +41,9 @@ const validationKeyByType: Record<UIDatasourceType, string | null> = {
viewV2: "id",
query: "_id",
custom: null,
link: "rowId",
field: "value",
jsonarray: "value",
}
export const screenComponentErrors = derived(
@ -77,10 +81,6 @@ function getInvalidDatasources(
"dataSource",
])) {
const componentSettings = component[setting.key]
if (!componentSettings) {
continue
}
const { label } = componentSettings
const type = componentSettings.type as UIDatasourceType
@ -88,8 +88,17 @@ function getInvalidDatasources(
if (!validationKey) {
continue
}
const componentBindings = getBindableProperties(screen, component._id)
const componentDatasources = {
...reduceBy("rowId", bindings.extractRelationships(componentBindings)),
...reduceBy("value", bindings.extractFields(componentBindings)),
...reduceBy("value", bindings.extractJSONArrayFields(componentBindings)),
}
const resourceId = componentSettings[validationKey]
if (!datasources[resourceId]) {
if (!{ ...datasources, ...componentDatasources }[resourceId]) {
const friendlyTypeName = friendlyNameByType[type] ?? type
result[component._id!] = [
{

View File

@ -24,3 +24,18 @@ export type InsertAtPositionFn = (_: {
value: string
cursor?: { anchor: number }
}) => void
export interface UIBinding {
tableId?: string
fieldSchema?: {
name: string
tableId: string
type: string
subtype?: string
prefixKeys?: string
}
component?: string
providerId: string
readableBinding?: string
runtimeBinding?: string
}

View File

@ -1 +1,9 @@
export type UIDatasourceType = "table" | "view" | "viewV2" | "query" | "custom"
export type UIDatasourceType =
| "table"
| "view"
| "viewV2"
| "query"
| "custom"
| "link"
| "field"
| "jsonarray"