Add initial work on merging settings and design panels, improve code structure, improve styles
This commit is contained in:
parent
0f691e5484
commit
aee876a681
|
@ -2,12 +2,10 @@
|
||||||
import Icon from "../Icon/Icon.svelte"
|
import Icon from "../Icon/Icon.svelte"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let name
|
||||||
|
export let show = false
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let thin = false
|
|
||||||
export let name,
|
|
||||||
show = false
|
|
||||||
|
|
||||||
const onHeaderClick = () => {
|
const onHeaderClick = () => {
|
||||||
show = !show
|
show = !show
|
||||||
if (show) {
|
if (show) {
|
||||||
|
@ -16,12 +14,10 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="property-group-container" class:thin>
|
<div class="property-group-container">
|
||||||
<div class="property-group-name" on:click={onHeaderClick}>
|
<div class="property-group-name" on:click={onHeaderClick}>
|
||||||
<div class:thin class="name">{name}</div>
|
<div class="name">{name}</div>
|
||||||
<div class="icon">
|
<Icon size="S" name={show ? "Remove" : "Add"} />
|
||||||
<Icon size="S" name={show ? "Remove" : "Add"} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="property-panel" class:show>
|
<div class="property-panel" class:show>
|
||||||
<slot />
|
<slot />
|
||||||
|
@ -32,10 +28,9 @@
|
||||||
.property-group-container {
|
.property-group-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: auto;
|
justify-content: flex-start;
|
||||||
justify-content: center;
|
align-items: stretch;
|
||||||
border-radius: var(--border-radius-m);
|
border-bottom: var(--border-light);
|
||||||
font-family: var(--font-sans);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.property-group-name {
|
.property-group-name {
|
||||||
|
@ -45,42 +40,38 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: var(--spacing-m) var(--spacing-xl);
|
||||||
|
color: var(--spectrum-global-color-gray-600);
|
||||||
|
transition: color 130ms ease-in-out;
|
||||||
|
}
|
||||||
|
.property-group-name:hover {
|
||||||
|
color: var(--spectrum-global-color-gray-900);
|
||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: 14px;
|
font-size: var(--font-size-s);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
letter-spacing: 0.14px;
|
letter-spacing: 0.14px;
|
||||||
color: var(--ink);
|
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
text-transform: capitalize;
|
text-transform: uppercase;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
.name.thin {
|
|
||||||
font-size: var(--spectrum-global-dimension-font-size-75);
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
flex: 0 0 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.property-panel {
|
.property-panel {
|
||||||
/* height: 0px;
|
|
||||||
overflow: hidden; */
|
|
||||||
display: none;
|
display: none;
|
||||||
|
padding: var(--spacing-s) var(--spacing-xl) var(--spacing-xl)
|
||||||
|
var(--spacing-xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
.show {
|
.show {
|
||||||
/* overflow: auto;
|
|
||||||
height: auto; */
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
justify-content: flex-start;
|
||||||
margin-top: var(--spacing-m);
|
align-items: stretch;
|
||||||
|
gap: var(--spacing-m);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
export let selected
|
export let selected
|
||||||
export let vertical = false
|
export let vertical = false
|
||||||
|
export let noPadding = false
|
||||||
|
|
||||||
let _id = id()
|
let _id = id()
|
||||||
const tab = writable({ title: selected, id: _id })
|
const tab = writable({ title: selected, id: _id })
|
||||||
setContext("tab", tab)
|
setContext("tab", tab)
|
||||||
|
@ -63,14 +65,17 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="spectrum-Tabs-content spectrum-Tabs-content-{_id}" />
|
<div
|
||||||
|
class="spectrum-Tabs-content spectrum-Tabs-content-{_id}"
|
||||||
|
class:noPadding
|
||||||
|
/>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.spectrum-Tabs {
|
.spectrum-Tabs {
|
||||||
padding-left: var(--spacing-xl);
|
padding-left: var(--spacing-xl);
|
||||||
padding-right: var(--spacing-xl);
|
padding-right: var(--spacing-xl);
|
||||||
position: relative;
|
position: relative;
|
||||||
border-width: 1px !important;
|
border-bottom: var(--border-light);
|
||||||
}
|
}
|
||||||
.spectrum-Tabs-content {
|
.spectrum-Tabs-content {
|
||||||
margin-top: var(--spectrum-global-dimension-static-size-150);
|
margin-top: var(--spectrum-global-dimension-static-size-150);
|
||||||
|
@ -81,4 +86,7 @@
|
||||||
.spectrum-Tabs--horizontal .spectrum-Tabs-selectionIndicator {
|
.spectrum-Tabs--horizontal .spectrum-Tabs-selectionIndicator {
|
||||||
bottom: 0 !important;
|
bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
.noPadding {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -488,12 +488,12 @@ export const getFrontendStore = () => {
|
||||||
})
|
})
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
},
|
},
|
||||||
updateStyle: async (type, name, value) => {
|
updateStyle: async (name, value) => {
|
||||||
const selected = get(selectedComponent)
|
const selected = get(selectedComponent)
|
||||||
if (value == null || value === "") {
|
if (value == null || value === "") {
|
||||||
delete selected._styles[type][name]
|
delete selected._styles.normal[name]
|
||||||
} else {
|
} else {
|
||||||
selected._styles[type][name] = value
|
selected._styles.normal[name] = value
|
||||||
}
|
}
|
||||||
await store.actions.preview.saveSelected()
|
await store.actions.preview.saveSelected()
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
<script>
|
||||||
|
import { DetailSummary, ActionButton } from "@budibase/bbui"
|
||||||
|
import { currentAsset, store } from "builderStore"
|
||||||
|
import { findClosestMatchingComponent } from "builderStore/storeUtils"
|
||||||
|
import { makeDatasourceFormComponents } from "builderStore/store/screenTemplates/utils/commonComponents"
|
||||||
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
|
|
||||||
|
export let openSection
|
||||||
|
export let componentDefinition
|
||||||
|
export let componentInstance
|
||||||
|
|
||||||
|
let confirmResetFieldsDialog
|
||||||
|
|
||||||
|
const resetFormFields = () => {
|
||||||
|
const form = findClosestMatchingComponent(
|
||||||
|
$currentAsset.props,
|
||||||
|
componentInstance._id,
|
||||||
|
component => component._component.endsWith("/form")
|
||||||
|
)
|
||||||
|
const dataSource = form?.dataSource
|
||||||
|
const fields = makeDatasourceFormComponents(dataSource)
|
||||||
|
store.actions.components.updateProp(
|
||||||
|
"_children",
|
||||||
|
fields.map(field => field.json())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DetailSummary name="Actions" on:open show={openSection === "actions"}>
|
||||||
|
<ActionButton secondary wide on:click={store.actions.components.resetStyles}>
|
||||||
|
Reset styles
|
||||||
|
</ActionButton>
|
||||||
|
{#if componentDefinition?.component?.endsWith("/fieldgroup")}
|
||||||
|
<ActionButton
|
||||||
|
secondary
|
||||||
|
wide
|
||||||
|
on:click={() => confirmResetFieldsDialog?.show()}
|
||||||
|
>
|
||||||
|
Update form fields
|
||||||
|
</ActionButton>
|
||||||
|
{/if}
|
||||||
|
</DetailSummary>
|
||||||
|
|
||||||
|
<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"
|
||||||
|
/>
|
|
@ -1,40 +0,0 @@
|
||||||
<script>
|
|
||||||
export let categories = []
|
|
||||||
export let selectedCategory = {}
|
|
||||||
export let onClick = () => {}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="tabs">
|
|
||||||
{#each categories as category}
|
|
||||||
<li
|
|
||||||
data-cy={category.name}
|
|
||||||
on:click={() => onClick(category)}
|
|
||||||
class:active={selectedCategory === category}
|
|
||||||
>
|
|
||||||
{category.name}
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.tabs {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
list-style: none;
|
|
||||||
font-size: var(--font-size-m);
|
|
||||||
font-weight: 600;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
color: var(--grey-5);
|
|
||||||
cursor: pointer;
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.active {
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<script>
|
||||||
|
import { TextArea, DetailSummary } from "@budibase/bbui"
|
||||||
|
import { store } from "builderStore"
|
||||||
|
|
||||||
|
export let componentInstance
|
||||||
|
export let openSection
|
||||||
|
|
||||||
|
function onChange(css) {
|
||||||
|
store.actions.components.updateCustomStyle(css)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DetailSummary
|
||||||
|
name={`Custom Styles${componentInstance?._styles?.custom ? " *" : ""}`}
|
||||||
|
on:open
|
||||||
|
show={openSection === "custom"}
|
||||||
|
>
|
||||||
|
<div class="custom-styles">
|
||||||
|
<TextArea
|
||||||
|
value={componentInstance?._styles?.custom}
|
||||||
|
on:change={event => onChange(event.detail)}
|
||||||
|
placeholder="Enter some CSS..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</DetailSummary>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.custom-styles :global(textarea) {
|
||||||
|
font-family: monospace;
|
||||||
|
min-height: 120px;
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,42 @@
|
||||||
|
<script>
|
||||||
|
import { DetailSummary } from "@budibase/bbui"
|
||||||
|
import PropertyGroup from "./PropertyControls/PropertyGroup.svelte"
|
||||||
|
import { allStyles } from "./componentStyles"
|
||||||
|
import { store } from "builderStore"
|
||||||
|
|
||||||
|
export let componentDefinition
|
||||||
|
export let componentInstance
|
||||||
|
export let openSection
|
||||||
|
|
||||||
|
let selectedCategory = "normal"
|
||||||
|
let currentGroup
|
||||||
|
|
||||||
|
$: groups = componentDefinition?.styleable ? Object.keys(allStyles) : []
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DetailSummary name="Design" show={openSection === "design"} on:open>
|
||||||
|
{#if groups.length > 0}
|
||||||
|
{#each groups as groupName}
|
||||||
|
<PropertyGroup
|
||||||
|
name={groupName}
|
||||||
|
properties={allStyles[groupName]}
|
||||||
|
styleCategory={selectedCategory}
|
||||||
|
onStyleChanged={store.actions.components.updateStyle}
|
||||||
|
{componentInstance}
|
||||||
|
open={currentGroup === groupName}
|
||||||
|
on:open={() => (currentGroup = groupName)}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
{:else}
|
||||||
|
<div class="no-design">
|
||||||
|
This component doesn't have any design properties.
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</DetailSummary>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.no-design {
|
||||||
|
font-size: var(--spectrum-global-dimension-font-size-75);
|
||||||
|
color: var(--grey-6);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,111 +0,0 @@
|
||||||
<script>
|
|
||||||
import { TextArea, DetailSummary, Button } from "@budibase/bbui"
|
|
||||||
import PropertyGroup from "./PropertyControls/PropertyGroup.svelte"
|
|
||||||
import FlatButtonGroup from "./PropertyControls/FlatButtonGroup"
|
|
||||||
import { allStyles } from "./componentStyles"
|
|
||||||
|
|
||||||
export let componentDefinition = {}
|
|
||||||
export let componentInstance = {}
|
|
||||||
export let onStyleChanged = () => {}
|
|
||||||
export let onCustomStyleChanged = () => {}
|
|
||||||
export let onResetStyles = () => {}
|
|
||||||
|
|
||||||
let selectedCategory = "normal"
|
|
||||||
let currentGroup
|
|
||||||
|
|
||||||
function onChange(category) {
|
|
||||||
selectedCategory = category
|
|
||||||
}
|
|
||||||
|
|
||||||
const buttonProps = [
|
|
||||||
{ value: "normal", text: "Normal" },
|
|
||||||
{ value: "hover", text: "Hover" },
|
|
||||||
{ value: "active", text: "Active" },
|
|
||||||
]
|
|
||||||
|
|
||||||
$: groups = componentDefinition?.styleable ? Object.keys(allStyles) : []
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<div class="state-categories">
|
|
||||||
<FlatButtonGroup value={selectedCategory} {buttonProps} {onChange} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="positioned-wrapper">
|
|
||||||
<div class="property-groups">
|
|
||||||
{#if groups.length > 0}
|
|
||||||
{#each groups as groupName}
|
|
||||||
<PropertyGroup
|
|
||||||
name={groupName}
|
|
||||||
properties={allStyles[groupName]}
|
|
||||||
styleCategory={selectedCategory}
|
|
||||||
{onStyleChanged}
|
|
||||||
{componentInstance}
|
|
||||||
open={currentGroup === groupName}
|
|
||||||
on:open={() => (currentGroup = groupName)}
|
|
||||||
/>
|
|
||||||
{/each}
|
|
||||||
<DetailSummary
|
|
||||||
name={`Custom Styles${componentInstance._styles.custom ? " *" : ""}`}
|
|
||||||
on:open={() => (currentGroup = "custom")}
|
|
||||||
show={currentGroup === "custom"}
|
|
||||||
thin
|
|
||||||
>
|
|
||||||
<div class="custom-styles">
|
|
||||||
<TextArea
|
|
||||||
value={componentInstance._styles.custom}
|
|
||||||
on:change={event => onCustomStyleChanged(event.detail)}
|
|
||||||
placeholder="Enter some CSS..."
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</DetailSummary>
|
|
||||||
<Button secondary wide on:click={onResetStyles}>Reset Styles</Button>
|
|
||||||
{:else}
|
|
||||||
<div class="no-design">
|
|
||||||
This component doesn't have any design properties.
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
gap: var(--spacing-l);
|
|
||||||
}
|
|
||||||
|
|
||||||
.positioned-wrapper {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
min-height: 0;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.property-groups {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
min-height: 0;
|
|
||||||
margin: 0 -20px;
|
|
||||||
padding: 0 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: stretch;
|
|
||||||
gap: var(--spacing-m);
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-design {
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
color: var(--grey-5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-styles :global(textarea) {
|
|
||||||
font-family: monospace;
|
|
||||||
min-height: 120px;
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -3,11 +3,16 @@
|
||||||
import { store, selectedComponent, currentAsset } from "builderStore"
|
import { store, selectedComponent, currentAsset } from "builderStore"
|
||||||
import { Tabs, Tab } from "@budibase/bbui"
|
import { Tabs, Tab } from "@budibase/bbui"
|
||||||
import { FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
import DesignView from "./DesignView.svelte"
|
import SettingsSection from "./SettingsSection.svelte"
|
||||||
import SettingsView from "./SettingsView.svelte"
|
import DesignSection from "./DesignSection.svelte"
|
||||||
|
import CustomStylesSection from "./CustomStylesSection.svelte"
|
||||||
|
import ActionsSection from "./ActionsSection.svelte"
|
||||||
import { setWith } from "lodash"
|
import { setWith } from "lodash"
|
||||||
|
|
||||||
$: definition = store.actions.components.getDefinition(
|
let openSection = "settings"
|
||||||
|
|
||||||
|
$: componentInstance = $selectedComponent
|
||||||
|
$: componentDefinition = store.actions.components.getDefinition(
|
||||||
$selectedComponent?._component
|
$selectedComponent?._component
|
||||||
)
|
)
|
||||||
$: isComponentOrScreen =
|
$: isComponentOrScreen =
|
||||||
|
@ -16,10 +21,6 @@
|
||||||
$: isNotScreenslot = !$selectedComponent._component.endsWith("screenslot")
|
$: isNotScreenslot = !$selectedComponent._component.endsWith("screenslot")
|
||||||
$: showDisplayName = isComponentOrScreen && isNotScreenslot
|
$: showDisplayName = isComponentOrScreen && isNotScreenslot
|
||||||
|
|
||||||
const onStyleChanged = store.actions.components.updateStyle
|
|
||||||
const onCustomStyleChanged = store.actions.components.updateCustomStyle
|
|
||||||
const onResetStyles = store.actions.components.resetStyles
|
|
||||||
|
|
||||||
function setAssetProps(name, value) {
|
function setAssetProps(name, value) {
|
||||||
const selectedAsset = get(currentAsset)
|
const selectedAsset = get(currentAsset)
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
|
@ -37,48 +38,34 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Tabs selected="Settings">
|
<Tabs selected="Settings" noPadding>
|
||||||
<Tab title="Settings">
|
<Tab title="Settings">
|
||||||
<div class="tab-content-padding">
|
<SettingsSection
|
||||||
{#if definition && definition.name}
|
{componentInstance}
|
||||||
<div class="instance-name">{definition.name}</div>
|
{componentDefinition}
|
||||||
{/if}
|
{showDisplayName}
|
||||||
<SettingsView
|
onScreenPropChange={setAssetProps}
|
||||||
componentInstance={$selectedComponent}
|
assetInstance={$store.currentView !== "component" && $currentAsset}
|
||||||
componentDefinition={definition}
|
{openSection}
|
||||||
{showDisplayName}
|
on:open={() => (openSection = "settings")}
|
||||||
onChange={store.actions.components.updateProp}
|
/>
|
||||||
onScreenPropChange={setAssetProps}
|
<DesignSection
|
||||||
assetInstance={$store.currentView !== "component" && $currentAsset}
|
{componentInstance}
|
||||||
/>
|
{componentDefinition}
|
||||||
</div>
|
{openSection}
|
||||||
</Tab>
|
on:open={() => (openSection = "design")}
|
||||||
<Tab title="Design">
|
/>
|
||||||
<div class="tab-content-padding">
|
<CustomStylesSection
|
||||||
{#if definition && definition.name}
|
{componentInstance}
|
||||||
<div class="instance-name">{definition.name}</div>
|
{componentDefinition}
|
||||||
{/if}
|
{openSection}
|
||||||
<DesignView
|
on:open={() => (openSection = "custom")}
|
||||||
componentInstance={$selectedComponent}
|
/>
|
||||||
componentDefinition={definition}
|
<ActionsSection
|
||||||
{onStyleChanged}
|
{componentInstance}
|
||||||
{onCustomStyleChanged}
|
{componentDefinition}
|
||||||
{onResetStyles}
|
{openSection}
|
||||||
/>
|
on:open={() => (openSection = "actions")}
|
||||||
</div>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
<style>
|
|
||||||
.tab-content-padding {
|
|
||||||
padding: 0 var(--spacing-xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
.instance-name {
|
|
||||||
font-size: var(--spectrum-global-dimension-font-size-75);
|
|
||||||
margin-bottom: var(--spacing-m);
|
|
||||||
margin-top: var(--spacing-xs);
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--grey-7);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { Button, Icon, Drawer } from "@budibase/bbui"
|
import { Button, Icon, Drawer, Label } from "@budibase/bbui"
|
||||||
import { store, currentAsset } from "builderStore"
|
import { store, currentAsset } from "builderStore"
|
||||||
import {
|
import {
|
||||||
getBindableProperties,
|
getBindableProperties,
|
||||||
|
@ -70,7 +70,11 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="property-control" bind:this={anchor} data-cy={`setting-${key}`}>
|
<div class="property-control" bind:this={anchor} data-cy={`setting-${key}`}>
|
||||||
<div class="label">{label}</div>
|
{#if type !== "boolean"}
|
||||||
|
<div class="label">
|
||||||
|
<Label>{label}</Label>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div data-cy={`${key}-prop-control`} class="control">
|
<div data-cy={`${key}-prop-control`} class="control">
|
||||||
<svelte:component
|
<svelte:component
|
||||||
this={control}
|
this={control}
|
||||||
|
@ -79,63 +83,56 @@
|
||||||
updateOnChange={false}
|
updateOnChange={false}
|
||||||
on:change={handleChange}
|
on:change={handleChange}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
name={key}
|
||||||
|
text={label}
|
||||||
{type}
|
{type}
|
||||||
{...props}
|
{...props}
|
||||||
name={key}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
{#if bindable && !key.startsWith("_") && type === "text"}
|
||||||
{#if bindable && !key.startsWith("_") && type === "text"}
|
<div
|
||||||
<div
|
class="icon"
|
||||||
class="icon"
|
data-cy={`${key}-binding-button`}
|
||||||
data-cy={`${key}-binding-button`}
|
on:click={bindingDrawer.show}
|
||||||
on:click={bindingDrawer.show}
|
|
||||||
>
|
|
||||||
<Icon size="S" name="FlashOn" />
|
|
||||||
</div>
|
|
||||||
<Drawer bind:this={bindingDrawer} title={capitalise(key)}>
|
|
||||||
<svelte:fragment slot="description">
|
|
||||||
Add the objects on the left to enrich your text.
|
|
||||||
</svelte:fragment>
|
|
||||||
<Button cta slot="buttons" disabled={!valid} on:click={handleClose}
|
|
||||||
>Save</Button
|
|
||||||
>
|
>
|
||||||
<BindingPanel
|
<Icon size="S" name="FlashOn" />
|
||||||
slot="body"
|
</div>
|
||||||
bind:valid
|
<Drawer bind:this={bindingDrawer} title={capitalise(key)}>
|
||||||
value={safeValue}
|
<svelte:fragment slot="description">
|
||||||
close={handleClose}
|
Add the objects on the left to enrich your text.
|
||||||
on:update={e => (temporaryBindableValue = e.detail)}
|
</svelte:fragment>
|
||||||
{bindableProperties}
|
<Button cta slot="buttons" disabled={!valid} on:click={handleClose}>
|
||||||
/>
|
Save
|
||||||
</Drawer>
|
</Button>
|
||||||
{/if}
|
<BindingPanel
|
||||||
|
slot="body"
|
||||||
|
bind:valid
|
||||||
|
value={safeValue}
|
||||||
|
close={handleClose}
|
||||||
|
on:update={e => (temporaryBindableValue = e.detail)}
|
||||||
|
{bindableProperties}
|
||||||
|
/>
|
||||||
|
</Drawer>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.property-control {
|
.property-control {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row;
|
flex-direction: column;
|
||||||
align-items: center;
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 400;
|
|
||||||
flex: 0 0 80px;
|
|
||||||
text-align: left;
|
|
||||||
color: var(--ink);
|
|
||||||
margin-right: auto;
|
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
|
padding-top: var(--spectrum-global-dimension-size-50);
|
||||||
|
padding-bottom: var(--spectrum-global-dimension-size-65);
|
||||||
}
|
}
|
||||||
|
|
||||||
.control {
|
.control {
|
||||||
flex: 1;
|
position: relative;
|
||||||
display: inline-block;
|
|
||||||
padding-left: 2px;
|
|
||||||
width: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { get } from "lodash"
|
import { get } from "lodash"
|
||||||
import { isEmpty } from "lodash/fp"
|
import { isEmpty } from "lodash/fp"
|
||||||
import { Button, Checkbox, Input, Select } from "@budibase/bbui"
|
import { Checkbox, Input, Select, DetailSummary } from "@budibase/bbui"
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
import { store } from "builderStore"
|
||||||
import { currentAsset } from "builderStore"
|
|
||||||
import { findClosestMatchingComponent } from "builderStore/storeUtils"
|
|
||||||
import { makeDatasourceFormComponents } from "builderStore/store/screenTemplates/utils/commonComponents"
|
|
||||||
import PropertyControl from "./PropertyControls/PropertyControl.svelte"
|
import PropertyControl from "./PropertyControls/PropertyControl.svelte"
|
||||||
import LayoutSelect from "./PropertyControls/LayoutSelect.svelte"
|
import LayoutSelect from "./PropertyControls/LayoutSelect.svelte"
|
||||||
import RoleSelect from "./PropertyControls/RoleSelect.svelte"
|
import RoleSelect from "./PropertyControls/RoleSelect.svelte"
|
||||||
|
@ -33,9 +30,9 @@
|
||||||
export let componentDefinition = {}
|
export let componentDefinition = {}
|
||||||
export let componentInstance = {}
|
export let componentInstance = {}
|
||||||
export let assetInstance
|
export let assetInstance
|
||||||
export let onChange = () => {}
|
|
||||||
export let onScreenPropChange = () => {}
|
export let onScreenPropChange = () => {}
|
||||||
export let showDisplayName = false
|
export let showDisplayName = false
|
||||||
|
export let openSection
|
||||||
|
|
||||||
const layoutDefinition = []
|
const layoutDefinition = []
|
||||||
const screenDefinition = [
|
const screenDefinition = [
|
||||||
|
@ -44,12 +41,12 @@
|
||||||
{ key: "routing.roleId", label: "Access", control: RoleSelect },
|
{ key: "routing.roleId", label: "Access", control: RoleSelect },
|
||||||
{ key: "layoutId", label: "Layout", control: LayoutSelect },
|
{ key: "layoutId", label: "Layout", control: LayoutSelect },
|
||||||
]
|
]
|
||||||
let confirmResetFieldsDialog
|
|
||||||
|
|
||||||
$: settings = componentDefinition?.settings ?? []
|
$: settings = componentDefinition?.settings ?? []
|
||||||
$: isLayout = assetInstance && assetInstance.favicon
|
$: isLayout = assetInstance && assetInstance.favicon
|
||||||
$: assetDefinition = isLayout ? layoutDefinition : screenDefinition
|
$: assetDefinition = isLayout ? layoutDefinition : screenDefinition
|
||||||
|
|
||||||
|
const updateProp = store.actions.components.updateProp
|
||||||
const controlMap = {
|
const controlMap = {
|
||||||
text: Input,
|
text: Input,
|
||||||
select: Select,
|
select: Select,
|
||||||
|
@ -91,27 +88,13 @@
|
||||||
}
|
}
|
||||||
return true
|
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>
|
</script>
|
||||||
|
|
||||||
<div class="settings-view-container">
|
<DetailSummary
|
||||||
|
name={componentDefinition.name}
|
||||||
|
on:open
|
||||||
|
show={openSection === "settings"}
|
||||||
|
>
|
||||||
{#if assetInstance}
|
{#if assetInstance}
|
||||||
{#each assetDefinition as def (`${componentInstance._id}-${def.key}`)}
|
{#each assetDefinition as def (`${componentInstance._id}-${def.key}`)}
|
||||||
<PropertyControl
|
<PropertyControl
|
||||||
|
@ -124,7 +107,6 @@
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if showDisplayName}
|
{#if showDisplayName}
|
||||||
<PropertyControl
|
<PropertyControl
|
||||||
bindable={false}
|
bindable={false}
|
||||||
|
@ -132,10 +114,9 @@
|
||||||
label="Name"
|
label="Name"
|
||||||
key="_instanceName"
|
key="_instanceName"
|
||||||
value={componentInstance._instanceName}
|
value={componentInstance._instanceName}
|
||||||
onChange={onInstanceNameChange}
|
onChange={val => updateProp("_instanceName", val)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if settings && settings.length > 0}
|
{#if settings && settings.length > 0}
|
||||||
{#each settings as setting (`${componentInstance._id}-${setting.key}`)}
|
{#each settings as setting (`${componentInstance._id}-${setting.key}`)}
|
||||||
{#if canRenderControl(setting)}
|
{#if canRenderControl(setting)}
|
||||||
|
@ -147,8 +128,11 @@
|
||||||
value={componentInstance[setting.key] ??
|
value={componentInstance[setting.key] ??
|
||||||
componentInstance[setting.key]?.defaultValue}
|
componentInstance[setting.key]?.defaultValue}
|
||||||
{componentInstance}
|
{componentInstance}
|
||||||
onChange={val => onChange(setting.key, val)}
|
onChange={val => updateProp(setting.key, val)}
|
||||||
props={{ options: setting.options, placeholder: setting.placeholder }}
|
props={{
|
||||||
|
options: setting.options,
|
||||||
|
placeholder: setting.placeholder,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -160,39 +144,11 @@
|
||||||
{@html componentDefinition?.info}
|
{@html componentDefinition?.info}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
</DetailSummary>
|
||||||
{#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>
|
<style>
|
||||||
.settings-view-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
gap: var(--spacing-s);
|
|
||||||
}
|
|
||||||
.text {
|
.text {
|
||||||
font-size: var(--spectrum-global-dimension-font-size-75);
|
font-size: var(--spectrum-global-dimension-font-size-75);
|
||||||
margin-top: var(--spacing-m);
|
|
||||||
color: var(--grey-6);
|
color: var(--grey-6);
|
||||||
}
|
}
|
||||||
.buttonWrapper {
|
|
||||||
margin-top: 10px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
const setUpChart = provider => {
|
const setUpChart = provider => {
|
||||||
const allCols = [labelColumn, ...(valueColumns || [null])]
|
const allCols = [labelColumn, ...(valueColumns || [null])]
|
||||||
if (!provider || allCols.find(x => x == null)) {
|
if (!provider || !provider.rows?.length || allCols.find(x => x == null)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
// Fetch data on mount
|
// Fetch data on mount
|
||||||
const setUpChart = provider => {
|
const setUpChart = provider => {
|
||||||
const allCols = [dateColumn, openColumn, highColumn, lowColumn, closeColumn]
|
const allCols = [dateColumn, openColumn, highColumn, lowColumn, closeColumn]
|
||||||
if (!provider || allCols.find(x => x == null)) {
|
if (!provider || !provider.rows?.length || allCols.find(x => x == null)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
// Fetch data on mount
|
// Fetch data on mount
|
||||||
const setUpChart = provider => {
|
const setUpChart = provider => {
|
||||||
const allCols = [labelColumn, ...(valueColumns || [null])]
|
const allCols = [labelColumn, ...(valueColumns || [null])]
|
||||||
if (!provider || allCols.find(x => x == null)) {
|
if (!provider || !provider.rows?.length || allCols.find(x => x == null)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
// Fetch data on mount
|
// Fetch data on mount
|
||||||
const setUpChart = provider => {
|
const setUpChart = provider => {
|
||||||
if (!provider || !labelColumn || !valueColumn) {
|
if (!provider || !provider.rows?.length || !labelColumn || !valueColumn) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue