Validate required settings messages from builder

This commit is contained in:
Adria Navarro 2025-01-27 13:13:11 +01:00
parent c90296d552
commit 2537ee6980
4 changed files with 114 additions and 38 deletions

View File

@ -38,7 +38,7 @@ export function findComponentsBySettingsType(
return result return result
} }
function getManifestDefinition(component: Component) { export function getManifestDefinition(component: Component) {
const componentType = component._component.split("/").slice(-1)[0] const componentType = component._component.split("/").slice(-1)[0]
const definition = const definition =
clientManifest[componentType as keyof typeof clientManifest] clientManifest[componentType as keyof typeof clientManifest]

View File

@ -2,11 +2,15 @@ import { derived } from "svelte/store"
import { tables } from "./tables" import { tables } from "./tables"
import { selectedScreen } from "./screens" import { selectedScreen } from "./screens"
import { viewsV2 } from "./viewsV2" import { viewsV2 } from "./viewsV2"
import { findComponentsBySettingsType } from "@/helpers/screen" import {
import { UIDatasourceType, Screen } from "@budibase/types" findComponentsBySettingsType,
getManifestDefinition,
} from "@/helpers/screen"
import { UIDatasourceType, Screen, Component } from "@budibase/types"
import { queries } from "./queries" import { queries } from "./queries"
import { views } from "./views" import { views } from "./views"
import { featureFlag } from "@/helpers" import { featureFlag } from "@/helpers"
import { findAllComponents } from "@/helpers/components"
function reduceBy<TItem extends {}, TKey extends keyof TItem>( function reduceBy<TItem extends {}, TKey extends keyof TItem>(
key: TKey, key: TKey,
@ -42,16 +46,36 @@ export const screenComponentErrors = derived(
if (!featureFlag.isEnabled("CHECK_SCREEN_COMPONENT_SETTINGS_ERRORS")) { if (!featureFlag.isEnabled("CHECK_SCREEN_COMPONENT_SETTINGS_ERRORS")) {
return {} return {}
} }
const datasources = {
...reduceBy("_id", $tables.list),
...reduceBy("name", $views.list),
...reduceBy("id", $viewsV2.list),
...reduceBy("_id", $queries.list),
}
const errors = {
...getInvalidDatasources($selectedScreen, datasources),
...getMissingRequiredSettings($selectedScreen),
}
return errors
}
)
function getInvalidDatasources( function getInvalidDatasources(
screen: Screen, screen: Screen,
datasources: Record<string, any> datasources: Record<string, any>
) { ) {
const result: Record<string, string[]> = {} const result: Record<string, string[]> = {}
for (const { component, setting } of findComponentsBySettingsType( for (const { component, setting } of findComponentsBySettingsType(screen, [
screen, "table",
["table", "dataSource"] "dataSource",
)) { ])) {
const componentSettings = component[setting.key] const componentSettings = component[setting.key]
if (!componentSettings) {
continue
}
const { label } = componentSettings const { label } = componentSettings
const type = componentSettings.type as UIDatasourceType const type = componentSettings.type as UIDatasourceType
@ -71,13 +95,69 @@ export const screenComponentErrors = derived(
return result return result
} }
const datasources = { function getAllComponentsInScreen(screen: Screen) {
...reduceBy("_id", $tables.list), const result: Component[] = []
...reduceBy("name", $views.list), function recursiveCheck(component: Component) {
...reduceBy("id", $viewsV2.list), result.push(...findAllComponents(component))
...reduceBy("_id", $queries.list), component._children?.forEach(recursiveCheck)
}
recursiveCheck(screen.props)
return result
} }
return getInvalidDatasources($selectedScreen, datasources) function getMissingRequiredSettings(screen: Screen) {
const allComponents = getAllComponentsInScreen(screen)
const result: Record<string, string[]> = {}
for (const component of allComponents) {
const definition = getManifestDefinition(component)
if (!("settings" in definition)) {
continue
}
const missingRequiredSettings = definition.settings.filter(
(setting: any) => {
let empty =
component[setting.key] == null || component[setting.key] === ""
let missing = setting.required && empty
// Check if this setting depends on another, as it may not be required
if (setting.dependsOn) {
const dependsOnKey = setting.dependsOn.setting || setting.dependsOn
const dependsOnValue = setting.dependsOn.value
const realDependentValue = component[dependsOnKey]
const sectionDependsOnKey =
setting.sectionDependsOn?.setting || setting.sectionDependsOn
const sectionDependsOnValue = setting.sectionDependsOn?.value
const sectionRealDependentValue = component[sectionDependsOnKey]
if (dependsOnValue == null && realDependentValue == null) {
return false
}
if (dependsOnValue != null && dependsOnValue !== realDependentValue) {
return false
}
if (
sectionDependsOnValue != null &&
sectionDependsOnValue !== sectionRealDependentValue
) {
return false
}
}
return missing
} }
) )
if (missingRequiredSettings.length) {
result[component._id!] = missingRequiredSettings.map(
(s: any) =>
`Add the <mark>${s.label}</mark> setting to start using your component`
)
}
}
return result
}

View File

@ -695,11 +695,7 @@
use:gridLayout={gridMetadata} use:gridLayout={gridMetadata}
> >
{#if errorState} {#if errorState}
<ComponentErrorState <ComponentErrorState {componentErrors} />
{missingRequiredSettings}
{missingRequiredAncestors}
{componentErrors}
/>
{:else} {:else}
<svelte:component this={constructor} bind:this={ref} {...initialSettings}> <svelte:component this={constructor} bind:this={ref} {...initialSettings}>
{#if children.length} {#if children.length}

View File

@ -26,7 +26,7 @@
{#if requiredAncestor} {#if requiredAncestor}
<MissingRequiredAncestor {requiredAncestor} /> <MissingRequiredAncestor {requiredAncestor} />
{:else if errorMessage} {:else if errorMessage}
{errorMessage} {@html errorMessage}
{:else if requiredSetting} {:else if requiredSetting}
<MissingRequiredSetting {requiredSetting} /> <MissingRequiredSetting {requiredSetting} />
{/if} {/if}