refactor and allow for condition and style settings
This commit is contained in:
parent
56018b1375
commit
3ac7c90fb8
|
@ -60,8 +60,12 @@
|
|||
$: highlightedSettings = $builderStore.highlightedSettings
|
||||
$: if (highlightedSettings?.length) {
|
||||
const settings = highlightedSettings.map(s => s.key)
|
||||
if (settings.length === 1 && settings[0] === "_conditions") {
|
||||
if (settings.includes("_conditions")) {
|
||||
section = "conditions"
|
||||
} else if (settings.includes("_styles")) {
|
||||
section = "styles"
|
||||
} else if (settings.includes("_settings")) {
|
||||
section = "settings"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
let tempValue
|
||||
let drawer
|
||||
|
||||
$: highlightCondition = $builderStore.highlightedSettings?.find(
|
||||
$: highlighted = $builderStore.highlightedSettings?.find(
|
||||
setting => setting.key === "_conditions"
|
||||
)
|
||||
|
||||
|
@ -57,7 +57,7 @@
|
|||
/>
|
||||
|
||||
<DetailSummary name={"Conditions"} collapsible={false}>
|
||||
<div class:highlighted={highlightCondition}>
|
||||
<div class:highlighted>
|
||||
<ActionButton fullWidth on:click={openDrawer}>{conditionText}</ActionButton>
|
||||
</div>
|
||||
</DetailSummary>
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
readableToRuntimeBinding,
|
||||
runtimeToReadableBinding,
|
||||
} from "@/dataBinding"
|
||||
import { builderStore } from "@/stores/builder"
|
||||
|
||||
export let componentInstance
|
||||
export let componentDefinition
|
||||
|
@ -32,6 +33,10 @@
|
|||
|
||||
$: icon = componentDefinition?.icon
|
||||
|
||||
$: highlighted = $builderStore.highlightedSettings?.find(
|
||||
setting => setting.key === "_styles"
|
||||
)
|
||||
|
||||
const openDrawer = () => {
|
||||
tempValue = runtimeToReadableBinding(
|
||||
bindings,
|
||||
|
@ -55,7 +60,7 @@
|
|||
name={`Custom CSS${componentInstance?._styles?.custom ? " *" : ""}`}
|
||||
collapsible={false}
|
||||
>
|
||||
<div>
|
||||
<div class:highlighted>
|
||||
<ActionButton on:click={openDrawer}>Edit custom CSS</ActionButton>
|
||||
</div>
|
||||
</DetailSummary>
|
||||
|
@ -97,4 +102,16 @@
|
|||
align-items: center;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
|
||||
.highlighted {
|
||||
background: var(--spectrum-global-color-gray-300);
|
||||
border-left: 4px solid var(--spectrum-semantic-informative-color-background);
|
||||
transition: background 130ms ease-out, border-color 130ms ease-out;
|
||||
margin-top: -3.5px;
|
||||
margin-bottom: -3.5px;
|
||||
padding-bottom: 3.5px;
|
||||
padding-top: 3.5px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from "svelte"
|
||||
import { Select, Link } from "@budibase/bbui"
|
||||
import type { Component } from "@budibase/types"
|
||||
import { getAllStateVariables } from "@/dataBinding"
|
||||
import {
|
||||
componentStore,
|
||||
|
@ -12,7 +14,6 @@
|
|||
findHBSBlocks,
|
||||
isJSBinding,
|
||||
} from "@budibase/string-templates"
|
||||
import { onMount } from "svelte"
|
||||
import DrawerBindableInput from "@/components/common/bindings/DrawerBindableInput.svelte"
|
||||
|
||||
type ComponentUsingState = {
|
||||
|
@ -30,15 +31,12 @@
|
|||
let editorError: string | null = null
|
||||
|
||||
onMount(() => {
|
||||
if (selectedKey) {
|
||||
searchComponents(selectedKey)
|
||||
}
|
||||
previewStore.requestComponentContext()
|
||||
})
|
||||
|
||||
$: $selectedScreen, selectedKey && searchComponents(selectedKey)
|
||||
$: {
|
||||
const previewContext = $previewStore.selectedComponentContext || {}
|
||||
|
||||
if (selectedKey && previewContext.state) {
|
||||
// It's unlikely value will ever be populated immediately as preview never has state values on load
|
||||
editorValue = previewContext.state[selectedKey] ?? null
|
||||
|
@ -50,7 +48,7 @@
|
|||
}
|
||||
|
||||
const findComponentsUpdatingState = (
|
||||
component: any,
|
||||
component: Component,
|
||||
stateKey: string
|
||||
): ComponentUsingState[] => {
|
||||
let foundComponents: ComponentUsingState[] = []
|
||||
|
@ -66,7 +64,7 @@
|
|||
handler.parameters?.key === stateKey
|
||||
) {
|
||||
foundComponents.push({
|
||||
id: component._id,
|
||||
id: component._id!,
|
||||
name: component._instanceName,
|
||||
settings: [eventType],
|
||||
})
|
||||
|
@ -86,76 +84,71 @@
|
|||
return foundComponents
|
||||
}
|
||||
|
||||
const hasStateBinding = (value: string, stateKey: string): boolean => {
|
||||
const bindings = findHBSBlocks(value).map(binding => {
|
||||
const sanitizedBinding = binding.replace(/\\"/g, '"')
|
||||
return isJSBinding(sanitizedBinding)
|
||||
? decodeJSBinding(sanitizedBinding)
|
||||
: sanitizedBinding
|
||||
})
|
||||
return bindings.join(" ").includes(stateKey)
|
||||
}
|
||||
|
||||
const getSettingsWithState = (component: any, stateKey: string): string[] => {
|
||||
const settingsWithState: string[] = []
|
||||
for (const [setting, value] of Object.entries(component)) {
|
||||
if (typeof value === "string" && hasStateBinding(value, stateKey)) {
|
||||
settingsWithState.push(setting)
|
||||
}
|
||||
}
|
||||
return settingsWithState
|
||||
}
|
||||
|
||||
const checkConditions = (conditions: any[], stateKey: string): boolean => {
|
||||
return conditions.some(condition =>
|
||||
[condition.referenceValue, condition.newValue].some(
|
||||
value => typeof value === "string" && hasStateBinding(value, stateKey)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
const checkStyles = (styles: any, stateKey: string): boolean => {
|
||||
return (
|
||||
typeof styles?.custom === "string" &&
|
||||
hasStateBinding(styles.custom, stateKey)
|
||||
)
|
||||
}
|
||||
|
||||
const findComponentsUsingState = (
|
||||
component: any,
|
||||
stateKey: string
|
||||
): ComponentUsingState[] => {
|
||||
let componentsUsingState: ComponentUsingState[] = []
|
||||
const { _children, _styles, _conditions, ...componentSettings } = component
|
||||
|
||||
const processValue = (value: string): boolean => {
|
||||
const bindings = findHBSBlocks(value).map(binding => {
|
||||
const sanitizedBinding = binding.replace(/\\"/g, '"')
|
||||
return isJSBinding(sanitizedBinding)
|
||||
? decodeJSBinding(sanitizedBinding)
|
||||
: sanitizedBinding
|
||||
const settingsWithState = getSettingsWithState(componentSettings, stateKey)
|
||||
settingsWithState.forEach(setting => {
|
||||
componentsUsingState.push({
|
||||
id: component._id,
|
||||
name: `${component._instanceName} (${setting})`,
|
||||
settings: [setting],
|
||||
})
|
||||
})
|
||||
|
||||
if (_conditions?.length > 0 && checkConditions(_conditions, stateKey)) {
|
||||
componentsUsingState.push({
|
||||
id: component._id,
|
||||
name: `${component._instanceName} (conditions)`,
|
||||
settings: ["_conditions"],
|
||||
})
|
||||
return bindings.join(" ").includes(stateKey)
|
||||
}
|
||||
|
||||
const { _children, ...componentSettings } = component
|
||||
|
||||
// Check normal settings
|
||||
for (const [setting, value] of Object.entries(componentSettings)) {
|
||||
if (typeof value === "string" && processValue(value)) {
|
||||
componentsUsingState.push({
|
||||
id: component._id,
|
||||
name: `${component._instanceName} (${setting})`,
|
||||
settings: [setting],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Check conditions
|
||||
if (component._conditions?.length > 0) {
|
||||
for (const condition of component._conditions) {
|
||||
const conditionValues = [condition.referenceValue, condition.newValue]
|
||||
if (
|
||||
conditionValues.some(
|
||||
value => typeof value === "string" && processValue(value)
|
||||
)
|
||||
) {
|
||||
componentsUsingState.push({
|
||||
id: component._id,
|
||||
name: `${component._instanceName} (conditions)`,
|
||||
settings: ["_conditions"],
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check styles
|
||||
if (component._styles) {
|
||||
const checkStyleObject = (obj: any) => {
|
||||
for (const [, value] of Object.entries(obj)) {
|
||||
if (typeof value === "string" && processValue(value)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const hasStateInStyles = Object.values(component._styles).some(styleObj =>
|
||||
checkStyleObject(styleObj)
|
||||
)
|
||||
|
||||
if (hasStateInStyles) {
|
||||
componentsUsingState.push({
|
||||
id: component._id,
|
||||
name: `${component._instanceName} (styles)`,
|
||||
settings: ["_styles"],
|
||||
})
|
||||
}
|
||||
if (_styles && checkStyles(_styles, stateKey)) {
|
||||
componentsUsingState.push({
|
||||
id: component._id,
|
||||
name: `${component._instanceName} (styles)`,
|
||||
settings: ["_styles"],
|
||||
})
|
||||
}
|
||||
|
||||
if (_children) {
|
||||
|
@ -170,7 +163,7 @@
|
|||
return componentsUsingState
|
||||
}
|
||||
|
||||
const searchComponents = (stateKey: string) => {
|
||||
const searchComponents = (stateKey: string | undefined) => {
|
||||
if (!stateKey || !$selectedScreen?.props) {
|
||||
return
|
||||
}
|
||||
|
@ -223,7 +216,7 @@
|
|||
<div class="section">
|
||||
<Select
|
||||
label="State variables"
|
||||
value={selectedKey}
|
||||
bind:value={selectedKey}
|
||||
placeholder="Type here..."
|
||||
options={keyOptions}
|
||||
on:change={handleStateKeySelect}
|
||||
|
@ -245,29 +238,31 @@
|
|||
{#if componentsUsingState.length > 0}
|
||||
<div class="section">
|
||||
<span class="text">Updates:</span>
|
||||
{#each componentsUsingState as component, i}
|
||||
{#if i > 0}{", "}{/if}
|
||||
<button
|
||||
class="component-link updates-colour"
|
||||
on:click={() => onClickComponentLink(component)}
|
||||
>
|
||||
{component.name}
|
||||
</button>
|
||||
{/each}
|
||||
<div class="updates-section">
|
||||
{#each componentsUsingState as component}
|
||||
<button
|
||||
class="component-link updates-colour"
|
||||
on:click={() => onClickComponentLink(component)}
|
||||
>
|
||||
{component.name}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if componentsUpdatingState.length > 0}
|
||||
<div class="section">
|
||||
<span class="text">Controlled by:</span>
|
||||
{#each componentsUpdatingState as component, i}
|
||||
{#if i > 0}{", "}{/if}
|
||||
<button
|
||||
class="component-link controlled-by-colour"
|
||||
on:click={() => onClickComponentLink(component)}
|
||||
>
|
||||
{component.name}
|
||||
</button>
|
||||
{/each}
|
||||
<div class="updates-section">
|
||||
{#each componentsUpdatingState as component}
|
||||
<button
|
||||
class="component-link controlled-by-colour"
|
||||
on:click={() => onClickComponentLink(component)}
|
||||
>
|
||||
{component.name}
|
||||
</button>
|
||||
{/each}git
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div style="opacity: 0.5; ">
|
||||
|
@ -291,6 +286,8 @@
|
|||
gap: var(--spacing-m);
|
||||
}
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-s);
|
||||
}
|
||||
.text {
|
||||
|
@ -313,16 +310,23 @@
|
|||
color: #e87400;
|
||||
}
|
||||
.component-link {
|
||||
display: inline;
|
||||
display: inline-block;
|
||||
border: none;
|
||||
background: none;
|
||||
text-decoration: underline;
|
||||
color: var(--spectrum-global-color-white);
|
||||
cursor: pointer;
|
||||
font-size: var(--spectrum-global-dimension-font-size-50);
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.component-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.updates-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue