budibase/packages/builder/src/components/design/PropertiesPanel/SettingsView.svelte

199 lines
6.7 KiB
Svelte

<script>
import { get } from "lodash"
import { isEmpty } from "lodash/fp"
import { Button, Checkbox, Input, Select } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { currentAsset } from "builderStore"
import { findClosestMatchingComponent } from "builderStore/storeUtils"
import { makeDatasourceFormComponents } from "builderStore/store/screenTemplates/utils/commonComponents"
import PropertyControl from "./PropertyControls/PropertyControl.svelte"
import LayoutSelect from "./PropertyControls/LayoutSelect.svelte"
import RoleSelect from "./PropertyControls/RoleSelect.svelte"
import TableSelect from "./PropertyControls/TableSelect.svelte"
import DataSourceSelect from "./PropertyControls/DataSourceSelect.svelte"
import DataProviderSelect from "./PropertyControls/DataProviderSelect.svelte"
import FieldSelect from "./PropertyControls/FieldSelect.svelte"
import MultiFieldSelect from "./PropertyControls/MultiFieldSelect.svelte"
import SchemaSelect from "./PropertyControls/SchemaSelect.svelte"
import SectionSelect from "./PropertyControls/SectionSelect.svelte"
import NavigationEditor from "./PropertyControls/NavigationEditor/NavigationEditor.svelte"
import EventsEditor from "./PropertyControls/EventsEditor"
import FilterEditor from "./PropertyControls/FilterEditor/FilterEditor.svelte"
import { IconSelect } from "./PropertyControls/IconSelect"
import ColorPicker from "./PropertyControls/ColorPicker.svelte"
import StringFieldSelect from "./PropertyControls/StringFieldSelect.svelte"
import NumberFieldSelect from "./PropertyControls/NumberFieldSelect.svelte"
import OptionsFieldSelect from "./PropertyControls/OptionsFieldSelect.svelte"
import BooleanFieldSelect from "./PropertyControls/BooleanFieldSelect.svelte"
import LongFormFieldSelect from "./PropertyControls/LongFormFieldSelect.svelte"
import DateTimeFieldSelect from "./PropertyControls/DateTimeFieldSelect.svelte"
import AttachmentFieldSelect from "./PropertyControls/AttachmentFieldSelect.svelte"
import RelationshipFieldSelect from "./PropertyControls/RelationshipFieldSelect.svelte"
export let componentDefinition = {}
export let componentInstance = {}
export let assetInstance
export let onChange = () => {}
export let onScreenPropChange = () => {}
export let showDisplayName = false
const layoutDefinition = []
const screenDefinition = [
{ key: "description", label: "Description", control: Input },
{ key: "routing.route", label: "Route", control: Input },
{ key: "routing.roleId", label: "Access", control: RoleSelect },
{ key: "layoutId", label: "Layout", control: LayoutSelect },
]
let confirmResetFieldsDialog
$: settings = componentDefinition?.settings ?? []
$: isLayout = assetInstance && assetInstance.favicon
$: assetDefinition = isLayout ? layoutDefinition : screenDefinition
const controlMap = {
text: Input,
select: Select,
dataSource: DataSourceSelect,
dataProvider: DataProviderSelect,
boolean: Checkbox,
number: Input,
event: EventsEditor,
table: TableSelect,
color: ColorPicker,
icon: IconSelect,
field: FieldSelect,
multifield: MultiFieldSelect,
schema: SchemaSelect,
section: SectionSelect,
navigation: NavigationEditor,
filter: FilterEditor,
"field/string": StringFieldSelect,
"field/number": NumberFieldSelect,
"field/options": OptionsFieldSelect,
"field/boolean": BooleanFieldSelect,
"field/longform": LongFormFieldSelect,
"field/datetime": DateTimeFieldSelect,
"field/attachment": AttachmentFieldSelect,
"field/link": RelationshipFieldSelect,
}
const getControl = type => {
return controlMap[type]
}
const canRenderControl = setting => {
const control = getControl(setting?.type)
if (!control) {
return false
}
if (setting.dependsOn && isEmpty(componentInstance[setting.dependsOn])) {
return false
}
return true
}
const onInstanceNameChange = name => {
onChange("_instanceName", name)
}
const resetFormFields = () => {
const form = findClosestMatchingComponent(
$currentAsset.props,
componentInstance._id,
component => component._component.endsWith("/form")
)
const dataSource = form?.dataSource
const fields = makeDatasourceFormComponents(dataSource)
onChange(
"_children",
fields.map(field => field.json())
)
}
</script>
<div class="settings-view-container">
{#if assetInstance}
{#each assetDefinition as def (`${componentInstance._id}-${def.key}`)}
<PropertyControl
bindable={false}
control={def.control}
label={def.label}
key={def.key}
value={get(assetInstance, def.key)}
onChange={val => onScreenPropChange(def.key, val)}
/>
{/each}
{/if}
{#if showDisplayName}
<PropertyControl
bindable={false}
control={Input}
label="Name"
key="_instanceName"
value={componentInstance._instanceName}
onChange={onInstanceNameChange}
/>
{/if}
{#if settings && settings.length > 0}
{#each settings as setting (`${componentInstance._id}-${setting.key}`)}
{#if canRenderControl(setting)}
<PropertyControl
type={setting.type}
control={getControl(setting.type)}
label={setting.label}
key={setting.key}
value={componentInstance[setting.key] ??
componentInstance[setting.key]?.defaultValue}
{componentInstance}
onChange={val => onChange(setting.key, val)}
props={{ options: setting.options, placeholder: setting.placeholder }}
/>
{/if}
{/each}
{:else}
<div class="text">This component doesn't have any additional settings.</div>
{/if}
{#if componentDefinition?.info}
<div class="text">
{@html componentDefinition?.info}
</div>
{/if}
{#if componentDefinition?.component?.endsWith("/fieldgroup")}
<div class="buttonWrapper">
<Button secondary wide on:click={() => confirmResetFieldsDialog?.show()}>
Update Form Fields
</Button>
</div>
{/if}
</div>
<ConfirmDialog
bind:this={confirmResetFieldsDialog}
body={`All components inside this group will be deleted and replaced with fields to match the schema. Are you sure you want to update this Field Group?`}
okText="Update"
onOk={resetFormFields}
title="Confirm Form Field Update"
/>
<style>
.settings-view-container {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
gap: var(--spacing-s);
}
.text {
font-size: var(--spectrum-global-dimension-font-size-75);
margin-top: var(--spacing-m);
color: var(--grey-6);
}
.buttonWrapper {
margin-top: 10px;
display: flex;
flex-direction: column;
}
</style>