164 lines
4.4 KiB
Svelte
164 lines
4.4 KiB
Svelte
<script>
|
|
import { get } from "lodash"
|
|
import { isEmpty } from "lodash/fp"
|
|
import { FrontendTypes } from "constants"
|
|
import PropertyControl from "./PropertyControl.svelte"
|
|
import LayoutSelect from "./LayoutSelect.svelte"
|
|
import RoleSelect from "./RoleSelect.svelte"
|
|
import Input from "./PropertyPanelControls/Input.svelte"
|
|
import { excludeProps } from "./propertyCategories.js"
|
|
import { store, allScreens, currentAsset } from "builderStore"
|
|
import { walkProps } from "builderStore/storeUtils"
|
|
|
|
export let panelDefinition = []
|
|
export let componentDefinition = {}
|
|
export let componentInstance = {}
|
|
export let onChange = () => {}
|
|
export let onScreenPropChange = () => {}
|
|
export let displayNameField = false
|
|
export let assetInstance
|
|
|
|
let assetProps = [
|
|
"title",
|
|
"description",
|
|
"routing.route",
|
|
"layoutId",
|
|
"routing.roleId",
|
|
]
|
|
let duplicateName = false
|
|
|
|
const propExistsOnComponentDef = prop =>
|
|
assetProps.includes(prop) || prop in componentDefinition.props
|
|
|
|
function handleChange(key, data) {
|
|
data.target ? onChange(key, data.target.value) : onChange(key, data)
|
|
}
|
|
|
|
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 },
|
|
]
|
|
|
|
const layoutDefinition = []
|
|
|
|
const canRenderControl = (key, dependsOn) => {
|
|
let test = !isEmpty(componentInstance[dependsOn])
|
|
|
|
return (
|
|
propExistsOnComponentDef(key) &&
|
|
(!dependsOn || !isEmpty(componentInstance[dependsOn]))
|
|
)
|
|
}
|
|
|
|
$: isLayout = assetInstance && assetInstance.favicon
|
|
$: assetDefinition = isLayout ? layoutDefinition : screenDefinition
|
|
|
|
const isDuplicateName = name => {
|
|
let duplicate = false
|
|
|
|
const lookForDuplicate = rootProps => {
|
|
walkProps(rootProps, (inst, cancel) => {
|
|
if (inst._instanceName === name && inst._id !== componentInstance._id) {
|
|
duplicate = true
|
|
cancel()
|
|
}
|
|
})
|
|
}
|
|
// check against layouts
|
|
for (let layout of $store.layouts) {
|
|
lookForDuplicate(layout.props)
|
|
}
|
|
// if viewing screen, check current screen for duplicate
|
|
if ($store.currentFrontEndType === FrontendTypes.SCREEN) {
|
|
lookForDuplicate($currentAsset.props)
|
|
} else {
|
|
// need to dedupe against all screens
|
|
for (let screen of $allScreens) {
|
|
lookForDuplicate(screen.props)
|
|
}
|
|
}
|
|
|
|
return duplicate
|
|
}
|
|
|
|
const onInstanceNameChange = (_, name) => {
|
|
if (isDuplicateName(name)) {
|
|
duplicateName = true
|
|
} else {
|
|
duplicateName = false
|
|
onChange("_instanceName", name)
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<div class="settings-view-container">
|
|
{#if assetInstance}
|
|
{#each assetDefinition as def}
|
|
<PropertyControl
|
|
bindable={false}
|
|
control={def.control}
|
|
label={def.label}
|
|
key={def.key}
|
|
value={get(assetInstance, def.key)}
|
|
onChange={onScreenPropChange}
|
|
props={{ ...excludeProps(def, ['control', 'label']) }} />
|
|
{/each}
|
|
{/if}
|
|
|
|
{#if displayNameField}
|
|
<PropertyControl
|
|
control={Input}
|
|
label="Name"
|
|
key="_instanceName"
|
|
value={componentInstance._instanceName}
|
|
onChange={onInstanceNameChange} />
|
|
{#if duplicateName}
|
|
<span class="duplicate-name">Name must be unique</span>
|
|
{/if}
|
|
{/if}
|
|
|
|
{#if !isLayout && panelDefinition && panelDefinition.length > 0}
|
|
{#each panelDefinition as definition}
|
|
{#if canRenderControl(definition.key, definition.dependsOn)}
|
|
<PropertyControl
|
|
control={definition.control}
|
|
label={definition.label}
|
|
key={definition.key}
|
|
value={componentInstance[definition.key] ?? componentInstance[definition.key]?.defaultValue}
|
|
{componentInstance}
|
|
{onChange}
|
|
props={{ ...excludeProps(definition, ['control', 'label']) }} />
|
|
{/if}
|
|
{/each}
|
|
{:else}
|
|
<div class="empty">
|
|
This component doesn't have any additional settings.
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<style>
|
|
.settings-view-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
height: 100%;
|
|
gap: var(--spacing-s);
|
|
}
|
|
|
|
.empty {
|
|
font-size: var(--font-size-xs);
|
|
margin-top: var(--spacing-m);
|
|
color: var(--grey-5);
|
|
}
|
|
|
|
.duplicate-name {
|
|
color: var(--red);
|
|
font-size: var(--font-size-xs);
|
|
position: relative;
|
|
top: -10px;
|
|
}
|
|
</style>
|