Fix component navigation, fix settings editing, fix design editing
This commit is contained in:
parent
af73139a87
commit
6b9e61e7e6
|
@ -11,12 +11,13 @@ import {
|
||||||
} from "builderStore"
|
} from "builderStore"
|
||||||
import { fetchComponentLibDefinitions } from "../loadComponentLibraries"
|
import { fetchComponentLibDefinitions } from "../loadComponentLibraries"
|
||||||
import api from "../api"
|
import api from "../api"
|
||||||
import { FrontendTypes } from "../../constants"
|
import { FrontendTypes } from "constants"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
import {
|
import {
|
||||||
findComponentType,
|
findComponentType,
|
||||||
findComponentParent,
|
findComponentParent,
|
||||||
findComponentPath,
|
findComponentPath,
|
||||||
|
findComponent,
|
||||||
} from "../storeUtils"
|
} from "../storeUtils"
|
||||||
import { uuid } from "../uuid"
|
import { uuid } from "../uuid"
|
||||||
|
|
||||||
|
@ -44,21 +45,21 @@ export const getFrontendStore = () => {
|
||||||
store.actions = {
|
store.actions = {
|
||||||
initialise: async pkg => {
|
initialise: async pkg => {
|
||||||
const { layouts, screens, application } = pkg
|
const { layouts, screens, application } = pkg
|
||||||
const components = await fetchComponentLibDefinitions(pkg.application._id)
|
const components = await fetchComponentLibDefinitions(application._id)
|
||||||
store.update(state => ({
|
store.update(state => ({
|
||||||
...state,
|
...state,
|
||||||
libraries: pkg.application.componentLibraries,
|
libraries: application.componentLibraries,
|
||||||
components,
|
components,
|
||||||
name: pkg.application.name,
|
name: application.name,
|
||||||
description: pkg.application.description,
|
description: application.description,
|
||||||
appId: pkg.application._id,
|
appId: application._id,
|
||||||
layouts,
|
layouts,
|
||||||
screens,
|
screens,
|
||||||
hasAppPackage: true,
|
hasAppPackage: true,
|
||||||
appInstance: pkg.application.instance,
|
appInstance: application.instance,
|
||||||
}))
|
}))
|
||||||
await hostingStore.actions.fetch()
|
await hostingStore.actions.fetch()
|
||||||
await backendUiStore.actions.database.select(pkg.application.instance)
|
await backendUiStore.actions.database.select(application.instance)
|
||||||
},
|
},
|
||||||
routing: {
|
routing: {
|
||||||
fetch: async () => {
|
fetch: async () => {
|
||||||
|
@ -226,6 +227,25 @@ export const getFrontendStore = () => {
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
select: component => {
|
select: component => {
|
||||||
|
if (!component) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is the root component, select the asset instead
|
||||||
|
const asset = get(currentAsset)
|
||||||
|
const parent = findComponentParent(asset.props, component._id)
|
||||||
|
if (parent == null) {
|
||||||
|
const state = get(store)
|
||||||
|
const isLayout = state.currentFrontEndType === FrontendTypes.LAYOUT
|
||||||
|
if (isLayout) {
|
||||||
|
store.actions.layouts.select(asset._id)
|
||||||
|
} else {
|
||||||
|
store.actions.screens.select(asset._id)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise select the component
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.selectedComponentId = component._id
|
state.selectedComponentId = component._id
|
||||||
state.currentView = "component"
|
state.currentView = "component"
|
||||||
|
@ -236,10 +256,10 @@ export const getFrontendStore = () => {
|
||||||
if (!componentName) {
|
if (!componentName) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const name = componentName.startsWith("@budibase")
|
if (!componentName.startsWith("@budibase")) {
|
||||||
? componentName
|
componentName = `@budibase/standard-components/${componentName}`
|
||||||
: `@budibase/standard-components/${componentName}`
|
}
|
||||||
return get(store).components[name]
|
return get(store).components[componentName]
|
||||||
},
|
},
|
||||||
createInstance: (componentName, presetProps) => {
|
createInstance: (componentName, presetProps) => {
|
||||||
const definition = store.actions.components.getDefinition(componentName)
|
const definition = store.actions.components.getDefinition(componentName)
|
||||||
|
@ -273,6 +293,19 @@ export const getFrontendStore = () => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
create: (componentName, presetProps) => {
|
create: (componentName, presetProps) => {
|
||||||
|
const selected = get(selectedComponent)
|
||||||
|
const asset = get(currentAsset)
|
||||||
|
const state = get(store)
|
||||||
|
|
||||||
|
// Only allow one screen slot, and in the layout
|
||||||
|
if (componentName.endsWith("screenslot")) {
|
||||||
|
const isLayout = state.currentFrontEndType === FrontendTypes.LAYOUT
|
||||||
|
const slot = findComponentType(asset.props, componentName)
|
||||||
|
if (!isLayout || slot != null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create new component
|
// Create new component
|
||||||
const componentInstance = store.actions.components.createInstance(
|
const componentInstance = store.actions.components.createInstance(
|
||||||
componentName,
|
componentName,
|
||||||
|
@ -284,8 +317,7 @@ export const getFrontendStore = () => {
|
||||||
|
|
||||||
// Find parent node to attach this component to
|
// Find parent node to attach this component to
|
||||||
let parentComponent
|
let parentComponent
|
||||||
const selected = get(selectedComponent)
|
|
||||||
const asset = get(currentAsset)
|
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,43 +32,35 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const moveUpComponent = () => {
|
const moveUpComponent = () => {
|
||||||
store.update(state => {
|
|
||||||
const asset = get(currentAsset)
|
const asset = get(currentAsset)
|
||||||
const parent = findComponentParent(asset.props, component)
|
const parent = findComponentParent(asset.props, component._id)
|
||||||
|
if (!parent) {
|
||||||
if (parent) {
|
return
|
||||||
|
}
|
||||||
const currentIndex = parent._children.indexOf(component)
|
const currentIndex = parent._children.indexOf(component)
|
||||||
if (currentIndex === 0) return state
|
if (currentIndex === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const newChildren = parent._children.filter(c => c !== component)
|
const newChildren = parent._children.filter(c => c !== component)
|
||||||
newChildren.splice(currentIndex - 1, 0, component)
|
newChildren.splice(currentIndex - 1, 0, component)
|
||||||
parent._children = newChildren
|
parent._children = newChildren
|
||||||
}
|
|
||||||
state.selectedComponentId = component._id
|
|
||||||
store.actions.preview.saveSelected()
|
store.actions.preview.saveSelected()
|
||||||
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const moveDownComponent = () => {
|
const moveDownComponent = () => {
|
||||||
store.update(state => {
|
|
||||||
const asset = get(currentAsset)
|
const asset = get(currentAsset)
|
||||||
const parent = findComponentParent(asset.props, component)
|
const parent = findComponentParent(asset.props, component._id)
|
||||||
|
if (!parent) {
|
||||||
if (parent) {
|
return
|
||||||
|
}
|
||||||
const currentIndex = parent._children.indexOf(component)
|
const currentIndex = parent._children.indexOf(component)
|
||||||
if (currentIndex === parent._children.length - 1) return state
|
if (currentIndex === parent._children.length - 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const newChildren = parent._children.filter(c => c !== component)
|
const newChildren = parent._children.filter(c => c !== component)
|
||||||
newChildren.splice(currentIndex + 1, 0, component)
|
newChildren.splice(currentIndex + 1, 0, component)
|
||||||
parent._children = newChildren
|
parent._children = newChildren
|
||||||
}
|
|
||||||
state.selectedComponentId = component._id
|
|
||||||
store.actions.preview.saveSelected()
|
store.actions.preview.saveSelected()
|
||||||
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const duplicateComponent = () => {
|
const duplicateComponent = () => {
|
||||||
|
|
|
@ -2,48 +2,30 @@
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { store, selectedComponent, currentAsset } from "builderStore"
|
import { store, selectedComponent, currentAsset } from "builderStore"
|
||||||
import { FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
import panelStructure from "./temporaryPanelStructure.js"
|
|
||||||
import CategoryTab from "./CategoryTab.svelte"
|
import CategoryTab from "./CategoryTab.svelte"
|
||||||
import DesignView from "./DesignView.svelte"
|
import DesignView from "./DesignView.svelte"
|
||||||
import SettingsView from "./SettingsView.svelte"
|
import SettingsView from "./SettingsView.svelte"
|
||||||
import { setWith } from "lodash"
|
import { setWith } from "lodash"
|
||||||
|
|
||||||
let flattenedPanel = flattenComponents(panelStructure.categories)
|
const categories = [
|
||||||
let categories = [
|
|
||||||
{ value: "settings", name: "Settings" },
|
{ value: "settings", name: "Settings" },
|
||||||
{ value: "design", name: "Design" },
|
{ value: "design", name: "Design" },
|
||||||
]
|
]
|
||||||
let selectedCategory = categories[0]
|
let selectedCategory = categories[0]
|
||||||
|
|
||||||
$: componentInstance =
|
$: definition = store.actions.components.getDefinition(
|
||||||
$store.currentView !== "component"
|
$selectedComponent._component
|
||||||
? { ...$currentAsset, ...$selectedComponent }
|
|
||||||
: $selectedComponent
|
|
||||||
$: componentDefinition = store.actions.components.getDefinition(
|
|
||||||
componentInstance._component
|
|
||||||
)
|
)
|
||||||
$: componentPropDefinition =
|
$: isComponentOrScreen =
|
||||||
flattenedPanel.find(
|
$store.currentView === "component" ||
|
||||||
// use for getting controls for each component property
|
$store.currentFrontEndType === FrontendTypes.SCREEN
|
||||||
c => c._component === componentInstance._component
|
$: isNotScreenslot = !$selectedComponent._component.endsWith("screenslot")
|
||||||
) || {}
|
$: showDisplayName = isComponentOrScreen && isNotScreenslot
|
||||||
|
|
||||||
$: panelDefinition =
|
|
||||||
componentPropDefinition.properties &&
|
|
||||||
componentPropDefinition.properties[selectedCategory.value]
|
|
||||||
|
|
||||||
const onStyleChanged = store.actions.components.updateStyle
|
const onStyleChanged = store.actions.components.updateStyle
|
||||||
const onCustomStyleChanged = store.actions.components.updateCustomStyle
|
const onCustomStyleChanged = store.actions.components.updateCustomStyle
|
||||||
const onResetStyles = store.actions.components.resetStyles
|
const onResetStyles = store.actions.components.resetStyles
|
||||||
|
|
||||||
$: isComponentOrScreen =
|
|
||||||
$store.currentView === "component" ||
|
|
||||||
$store.currentFrontEndType === FrontendTypes.SCREEN
|
|
||||||
$: isNotScreenslot = !componentInstance._component.endsWith("screenslot")
|
|
||||||
|
|
||||||
$: displayName =
|
|
||||||
isComponentOrScreen && componentInstance._instanceName && isNotScreenslot
|
|
||||||
|
|
||||||
function walkProps(component, action) {
|
function walkProps(component, action) {
|
||||||
action(component)
|
action(component)
|
||||||
if (component.children) {
|
if (component.children) {
|
||||||
|
@ -91,24 +73,23 @@
|
||||||
{categories}
|
{categories}
|
||||||
{selectedCategory} />
|
{selectedCategory} />
|
||||||
|
|
||||||
{#if displayName}
|
{#if showDisplayName}
|
||||||
<div class="instance-name">{componentInstance._instanceName}</div>
|
<div class="instance-name">{$selectedComponent._instanceName}</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="component-props-container">
|
<div class="component-props-container">
|
||||||
{#if selectedCategory.value === 'design'}
|
{#if selectedCategory.value === 'design'}
|
||||||
<DesignView
|
<DesignView
|
||||||
{panelDefinition}
|
componentInstance={$selectedComponent}
|
||||||
{componentInstance}
|
componentDefinition={definition}
|
||||||
{onStyleChanged}
|
{onStyleChanged}
|
||||||
{onCustomStyleChanged}
|
{onCustomStyleChanged}
|
||||||
{onResetStyles} />
|
{onResetStyles} />
|
||||||
{:else if selectedCategory.value === 'settings'}
|
{:else if selectedCategory.value === 'settings'}
|
||||||
<SettingsView
|
<SettingsView
|
||||||
{componentInstance}
|
componentInstance={$selectedComponent}
|
||||||
{componentDefinition}
|
componentDefinition={definition}
|
||||||
{panelDefinition}
|
{showDisplayName}
|
||||||
displayNameField={displayName}
|
|
||||||
onChange={store.actions.components.updateProp}
|
onChange={store.actions.components.updateProp}
|
||||||
onScreenPropChange={setAssetProps}
|
onScreenPropChange={setAssetProps}
|
||||||
assetInstance={$store.currentView !== 'component' && $currentAsset} />
|
assetInstance={$store.currentView !== 'component' && $currentAsset} />
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
<script>
|
<script>
|
||||||
import { TextArea, DetailSummary, Button } from "@budibase/bbui"
|
import { TextArea, DetailSummary, Button } from "@budibase/bbui"
|
||||||
import PropertyGroup from "./PropertyGroup.svelte"
|
import PropertyGroup from "./PropertyGroup.svelte"
|
||||||
import FlatButtonGroup from "./FlatButtonGroup.svelte"
|
import FlatButtonGroup from "./PropertyPanelControls/FlatButtonGroup"
|
||||||
|
import { allStyles } from "./componentStyles"
|
||||||
|
|
||||||
export let panelDefinition = {}
|
export let componentDefinition = {}
|
||||||
export let componentInstance = {}
|
export let componentInstance = {}
|
||||||
export let onStyleChanged = () => {}
|
export let onStyleChanged = () => {}
|
||||||
export let onCustomStyleChanged = () => {}
|
export let onCustomStyleChanged = () => {}
|
||||||
export let onResetStyles = () => {}
|
export let onResetStyles = () => {}
|
||||||
|
|
||||||
let selectedCategory = "normal"
|
let selectedCategory = "normal"
|
||||||
let propGroup = null
|
|
||||||
let currentGroup
|
let currentGroup
|
||||||
|
|
||||||
function onChange(category) {
|
function onChange(category) {
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
{ value: "active", text: "Active" },
|
{ value: "active", text: "Active" },
|
||||||
]
|
]
|
||||||
|
|
||||||
$: propertyGroupNames = panelDefinition ? Object.keys(panelDefinition) : []
|
$: groups = componentDefinition?.styleable ? Object.keys(allStyles) : []
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="design-view-container">
|
<div class="design-view-container">
|
||||||
|
@ -32,12 +32,12 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="positioned-wrapper">
|
<div class="positioned-wrapper">
|
||||||
<div bind:this={propGroup} class="design-view-property-groups">
|
<div class="design-view-property-groups">
|
||||||
{#if propertyGroupNames.length > 0}
|
{#if groups.length > 0}
|
||||||
{#each propertyGroupNames as groupName}
|
{#each groups as groupName}
|
||||||
<PropertyGroup
|
<PropertyGroup
|
||||||
name={groupName}
|
name={groupName}
|
||||||
properties={panelDefinition[groupName]}
|
properties={allStyles[groupName]}
|
||||||
styleCategory={selectedCategory}
|
styleCategory={selectedCategory}
|
||||||
{onStyleChanged}
|
{onStyleChanged}
|
||||||
{componentInstance}
|
{componentInstance}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
import "@fortawesome/fontawesome-free/js/all.js"
|
|
||||||
|
|
||||||
export { default as IconSelect } from "./IconSelect.svelte"
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import TableViewFieldSelect from "./TableViewFieldSelect.svelte"
|
import TableViewFieldSelect from "./PropertyPanelControls/TableViewFieldSelect.svelte"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<TableViewFieldSelect {...$$props} multiselect />
|
<TableViewFieldSelect {...$$props} multiselect />
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { excludeProps } from "./propertyCategories.js"
|
import PropertyControl from "./PropertyPanelControls/PropertyControl.svelte"
|
||||||
import PropertyControl from "./PropertyControl.svelte"
|
|
||||||
import { DetailSummary } from "@budibase/bbui"
|
import { DetailSummary } from "@budibase/bbui"
|
||||||
|
|
||||||
export let name = ""
|
export let name = ""
|
||||||
|
@ -36,7 +35,7 @@
|
||||||
key={prop.key}
|
key={prop.key}
|
||||||
value={style[prop.key]}
|
value={style[prop.key]}
|
||||||
onChange={(key, value) => onStyleChanged(styleCategory, key, value)}
|
onChange={(key, value) => onStyleChanged(styleCategory, key, value)}
|
||||||
props={{ ...excludeProps(prop, ['control', 'label']) }} />
|
props={{ options: prop.options, placeholder: prop.placeholder }} />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
import EventsEditor from "./EventPropertyControl.svelte"
|
||||||
|
export default EventsEditor
|
|
@ -0,0 +1,2 @@
|
||||||
|
import FlatButtonGroup from "./FlatButtonGroup.svelte"
|
||||||
|
export default FlatButtonGroup
|
|
@ -0,0 +1,4 @@
|
||||||
|
import "@fortawesome/fontawesome-free/js/all.js"
|
||||||
|
import IconSelect from "./IconSelect.svelte"
|
||||||
|
|
||||||
|
export default IconSelect
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { store, currentAsset } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import { Select } from "@budibase/bbui"
|
import { Select } from "@budibase/bbui"
|
||||||
|
|
||||||
export let value
|
export let value
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import Portal from "svelte-portal"
|
import Portal from "svelte-portal"
|
||||||
import { buildStyle } from "../../helpers.js"
|
import { buildStyle } from "../../../helpers.js"
|
||||||
|
|
||||||
export let options = []
|
export let options = []
|
||||||
export let value = ""
|
export let value = ""
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { Icon } from "@budibase/bbui"
|
import { Icon } from "@budibase/bbui"
|
||||||
import Input from "./PropertyPanelControls/Input.svelte"
|
import Input from "./Input.svelte"
|
||||||
import { store, backendUiStore, currentAsset } from "builderStore"
|
import { store, backendUiStore, currentAsset } from "builderStore"
|
||||||
import fetchBindableProperties from "builderStore/fetchBindableProperties"
|
import fetchBindableProperties from "builderStore/fetchBindableProperties"
|
||||||
import {
|
import {
|
|
@ -2,7 +2,7 @@
|
||||||
import { Button, Icon, DropdownMenu, Spacer, Heading } from "@budibase/bbui"
|
import { Button, Icon, DropdownMenu, Spacer, Heading } from "@budibase/bbui"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import { store, backendUiStore, currentAsset } from "builderStore"
|
import { store, backendUiStore, currentAsset } from "builderStore"
|
||||||
import fetchBindableProperties from "../../builderStore/fetchBindableProperties"
|
import fetchBindableProperties from "../../../builderStore/fetchBindableProperties"
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
let anchorRight, dropdownRight
|
let anchorRight, dropdownRight
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
class="dropdownbutton"
|
class="dropdownbutton"
|
||||||
bind:this={anchorRight}
|
bind:this={anchorRight}
|
||||||
on:click={dropdownRight.show}>
|
on:click={dropdownRight.show}>
|
||||||
<span>{value.label ? value.label : 'Table / View'}</span>
|
<span>{value && value.label ? value.label : 'Table / View'}</span>
|
||||||
<Icon name="arrowdown" />
|
<Icon name="arrowdown" />
|
||||||
</div>
|
</div>
|
||||||
<DropdownMenu bind:this={dropdownRight} anchor={anchorRight}>
|
<DropdownMenu bind:this={dropdownRight} anchor={anchorRight}>
|
|
@ -1,32 +1,57 @@
|
||||||
<script>
|
<script>
|
||||||
import { get } from "lodash"
|
import { get } from "lodash"
|
||||||
import { isEmpty } from "lodash/fp"
|
import { isEmpty } from "lodash/fp"
|
||||||
import PropertyControl from "./PropertyControl.svelte"
|
import PropertyControl from "./PropertyPanelControls/PropertyControl.svelte"
|
||||||
import LayoutSelect from "./LayoutSelect.svelte"
|
|
||||||
import RoleSelect from "./RoleSelect.svelte"
|
import Input from "./PropertyPanelControls/Input.svelte"
|
||||||
import Input from "./PropertyPanelControls/Input.svelte"
|
|
||||||
import { excludeProps } from "./propertyCategories.js"
|
import LayoutSelect from "./PropertyPanelControls/LayoutSelect.svelte"
|
||||||
|
import RoleSelect from "./PropertyPanelControls/RoleSelect.svelte"
|
||||||
|
import OptionSelect from "./PropertyPanelControls/OptionSelect.svelte"
|
||||||
|
import MultiTableViewFieldSelect from "./MultiTableViewFieldSelect.svelte"
|
||||||
|
import Checkbox from "../common/Checkbox.svelte"
|
||||||
|
import TableSelect from "components/userInterface/PropertyPanelControls/TableSelect.svelte"
|
||||||
|
import TableViewSelect from "components/userInterface/PropertyPanelControls/TableViewSelect.svelte"
|
||||||
|
import TableViewFieldSelect from "components/userInterface/PropertyPanelControls/TableViewFieldSelect.svelte"
|
||||||
|
import EventsEditor from "components/userInterface/PropertyPanelControls/EventsEditor"
|
||||||
|
import ScreenSelect from "components/userInterface/PropertyPanelControls/ScreenSelect.svelte"
|
||||||
|
import DetailScreenSelect from "components/userInterface/DetailScreenSelect.svelte"
|
||||||
|
import IconSelect from "components/userInterface/PropertyPanelControls/IconSelect"
|
||||||
|
import Colorpicker from "@budibase/colorpicker"
|
||||||
|
|
||||||
export let panelDefinition = []
|
|
||||||
export let componentDefinition = {}
|
export let componentDefinition = {}
|
||||||
export let componentInstance = {}
|
export let componentInstance = {}
|
||||||
|
export let assetInstance
|
||||||
export let onChange = () => {}
|
export let onChange = () => {}
|
||||||
export let onScreenPropChange = () => {}
|
export let onScreenPropChange = () => {}
|
||||||
export let displayNameField = false
|
export let showDisplayName = false
|
||||||
export let assetInstance
|
|
||||||
|
|
||||||
let assetProps = [
|
const assetProps = [
|
||||||
"title",
|
"title",
|
||||||
"description",
|
"description",
|
||||||
"routing.route",
|
"routing.route",
|
||||||
"layoutId",
|
"layoutId",
|
||||||
"routing.roleId",
|
"routing.roleId",
|
||||||
]
|
]
|
||||||
let duplicateName = false
|
|
||||||
|
$: settings = componentDefinition?.settings ?? []
|
||||||
|
|
||||||
|
const controlMap = {
|
||||||
|
text: Input,
|
||||||
|
select: OptionSelect,
|
||||||
|
datasource: TableViewSelect,
|
||||||
|
detailURL: DetailScreenSelect,
|
||||||
|
boolean: Checkbox,
|
||||||
|
number: Input,
|
||||||
|
}
|
||||||
|
const getControl = type => {
|
||||||
|
return controlMap[type]
|
||||||
|
}
|
||||||
|
|
||||||
const propExistsOnComponentDef = prop =>
|
const propExistsOnComponentDef = prop =>
|
||||||
assetProps.includes(prop) || prop in (componentDefinition?.props ?? {})
|
assetProps.includes(prop) || prop in (componentDefinition?.props ?? {})
|
||||||
|
|
||||||
|
const layoutDefinition = []
|
||||||
const screenDefinition = [
|
const screenDefinition = [
|
||||||
{ key: "description", label: "Description", control: Input },
|
{ key: "description", label: "Description", control: Input },
|
||||||
{ key: "routing.route", label: "Route", control: Input },
|
{ key: "routing.route", label: "Route", control: Input },
|
||||||
|
@ -34,13 +59,15 @@
|
||||||
{ key: "layoutId", label: "Layout", control: LayoutSelect },
|
{ key: "layoutId", label: "Layout", control: LayoutSelect },
|
||||||
]
|
]
|
||||||
|
|
||||||
const layoutDefinition = []
|
const canRenderControl = setting => {
|
||||||
|
const control = getControl(setting?.type)
|
||||||
const canRenderControl = (key, dependsOn) => {
|
if (!control) {
|
||||||
return (
|
return false
|
||||||
propExistsOnComponentDef(key) &&
|
}
|
||||||
(!dependsOn || !isEmpty(componentInstance[dependsOn]))
|
if (setting.dependsOn && isEmpty(componentInstance[setting.dependsOn])) {
|
||||||
)
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
$: isLayout = assetInstance && assetInstance.favicon
|
$: isLayout = assetInstance && assetInstance.favicon
|
||||||
|
@ -60,34 +87,30 @@
|
||||||
label={def.label}
|
label={def.label}
|
||||||
key={def.key}
|
key={def.key}
|
||||||
value={get(assetInstance, def.key)}
|
value={get(assetInstance, def.key)}
|
||||||
onChange={onScreenPropChange}
|
onChange={onScreenPropChange} />
|
||||||
props={{ ...excludeProps(def, ['control', 'label']) }} />
|
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if displayNameField}
|
{#if showDisplayName}
|
||||||
<PropertyControl
|
<PropertyControl
|
||||||
control={Input}
|
control={Input}
|
||||||
label="Name"
|
label="Name"
|
||||||
key="_instanceName"
|
key="_instanceName"
|
||||||
value={componentInstance._instanceName}
|
value={componentInstance._instanceName}
|
||||||
onChange={onInstanceNameChange} />
|
onChange={onInstanceNameChange} />
|
||||||
{#if duplicateName}
|
|
||||||
<span class="duplicate-name">Name must be unique</span>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if !isLayout && panelDefinition && panelDefinition.length > 0}
|
{#if settings && settings.length > 0}
|
||||||
{#each panelDefinition as definition}
|
{#each settings as setting}
|
||||||
{#if canRenderControl(definition.key, definition.dependsOn)}
|
{#if canRenderControl(setting)}
|
||||||
<PropertyControl
|
<PropertyControl
|
||||||
control={definition.control}
|
control={getControl(setting.type)}
|
||||||
label={definition.label}
|
label={setting.label}
|
||||||
key={definition.key}
|
key={setting.key}
|
||||||
value={componentInstance[definition.key] ?? componentInstance[definition.key]?.defaultValue}
|
value={componentInstance[setting.key] ?? componentInstance[setting.key]?.defaultValue}
|
||||||
{componentInstance}
|
{componentInstance}
|
||||||
{onChange}
|
{onChange}
|
||||||
props={{ ...excludeProps(definition, ['control', 'label']) }} />
|
props={{ options: setting.options }} />
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -105,17 +128,9 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
gap: var(--spacing-s);
|
gap: var(--spacing-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty {
|
.empty {
|
||||||
font-size: var(--font-size-xs);
|
font-size: var(--font-size-xs);
|
||||||
margin-top: var(--spacing-m);
|
margin-top: var(--spacing-m);
|
||||||
color: var(--grey-5);
|
color: var(--grey-5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.duplicate-name {
|
|
||||||
color: var(--red);
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
position: relative;
|
|
||||||
top: -10px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
import { isRootComponent } from "./searchComponents"
|
|
||||||
import { find } from "lodash/fp"
|
|
||||||
|
|
||||||
export const getRootComponent = (componentName, components) => {
|
|
||||||
const component = find(c => c.name === componentName)(components)
|
|
||||||
|
|
||||||
if (isRootComponent(component)) return component
|
|
||||||
|
|
||||||
return getRootComponent(component.props._component, components)
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
import { isUndefined, filter, some, includes } from "lodash/fp"
|
|
||||||
import { pipe } from "../../../helpers"
|
|
||||||
|
|
||||||
const normalString = s => (s || "").trim().toLowerCase()
|
|
||||||
|
|
||||||
export const isRootComponent = c =>
|
|
||||||
isComponent(c) && isUndefined(c.props._component)
|
|
||||||
|
|
||||||
export const isComponent = c => {
|
|
||||||
const hasProp = n => !isUndefined(c[n])
|
|
||||||
return hasProp("name") && hasProp("props")
|
|
||||||
}
|
|
||||||
|
|
||||||
export const searchAllComponents = (components, phrase) => {
|
|
||||||
const hasPhrase = (...vals) =>
|
|
||||||
pipe(vals, [some(v => includes(normalString(phrase))(normalString(v)))])
|
|
||||||
|
|
||||||
const componentMatches = c => {
|
|
||||||
if (hasPhrase(c._instanceName, ...(c.tags || []))) return true
|
|
||||||
|
|
||||||
if (isRootComponent(c)) return false
|
|
||||||
|
|
||||||
const parent = getExactComponent(components, c.props._component)
|
|
||||||
|
|
||||||
return componentMatches(parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
return filter(componentMatches)(components)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getExactComponent = (components, name, isScreen = false) => {
|
|
||||||
return components.find(comp =>
|
|
||||||
isScreen ? comp.props._instanceName === name : comp._instanceName === name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getAncestorProps = (components, name, found = []) => {
|
|
||||||
const thisComponent = getExactComponent(components, name)
|
|
||||||
|
|
||||||
if (isRootComponent(thisComponent)) return [thisComponent.props, ...found]
|
|
||||||
|
|
||||||
return getAncestorProps(components, thisComponent.props._component, [
|
|
||||||
{ ...thisComponent.props },
|
|
||||||
...found,
|
|
||||||
])
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { split, last } from "lodash/fp"
|
|
||||||
import { pipe } from "../../../helpers"
|
|
||||||
|
|
||||||
export const splitName = fullname => {
|
|
||||||
const componentName = pipe(fullname, [split("/"), last])
|
|
||||||
|
|
||||||
const libName = fullname.substring(
|
|
||||||
0,
|
|
||||||
fullname.length - componentName.length - 1
|
|
||||||
)
|
|
||||||
|
|
||||||
return { libName, componentName }
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
export const TYPE_MAP = {
|
|
||||||
string: {
|
|
||||||
default: "",
|
|
||||||
},
|
|
||||||
bool: {
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
number: {
|
|
||||||
default: 0,
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
default: [],
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
default: [],
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
default: {
|
|
||||||
"##bbstate": "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tables: {
|
|
||||||
default: {},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Input from "./PropertyPanelControls/Input.svelte"
|
import Input from "./PropertyPanelControls/Input.svelte"
|
||||||
import OptionSelect from "./OptionSelect.svelte"
|
import OptionSelect from "./PropertyPanelControls/OptionSelect.svelte"
|
||||||
import FlatButtonGroup from "./FlatButtonGroup.svelte"
|
import FlatButtonGroup from "./PropertyPanelControls/FlatButtonGroup"
|
||||||
import Colorpicker from "@budibase/colorpicker"
|
import Colorpicker from "@budibase/colorpicker"
|
||||||
|
|
||||||
export const layout = [
|
export const layout = [
|
||||||
|
@ -299,42 +299,36 @@ export const size = [
|
||||||
key: "width",
|
key: "width",
|
||||||
control: Input,
|
control: Input,
|
||||||
placeholder: "px",
|
placeholder: "px",
|
||||||
textAlign: "center",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Height",
|
label: "Height",
|
||||||
key: "height",
|
key: "height",
|
||||||
control: Input,
|
control: Input,
|
||||||
placeholder: "px",
|
placeholder: "px",
|
||||||
textAlign: "center",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Min Width",
|
label: "Min Width",
|
||||||
key: "min-width",
|
key: "min-width",
|
||||||
control: Input,
|
control: Input,
|
||||||
placeholder: "px",
|
placeholder: "px",
|
||||||
textAlign: "center",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Max Width",
|
label: "Max Width",
|
||||||
key: "max-width",
|
key: "max-width",
|
||||||
control: Input,
|
control: Input,
|
||||||
placeholder: "px",
|
placeholder: "px",
|
||||||
textAlign: "center",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Min Height",
|
label: "Min Height",
|
||||||
key: "min-height",
|
key: "min-height",
|
||||||
control: Input,
|
control: Input,
|
||||||
placeholder: "px",
|
placeholder: "px",
|
||||||
textAlign: "center",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Max Height",
|
label: "Max Height",
|
||||||
key: "max-height",
|
key: "max-height",
|
||||||
control: Input,
|
control: Input,
|
||||||
placeholder: "px",
|
placeholder: "px",
|
||||||
textAlign: "center",
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -357,28 +351,24 @@ export const position = [
|
||||||
key: "top",
|
key: "top",
|
||||||
control: Input,
|
control: Input,
|
||||||
placeholder: "px",
|
placeholder: "px",
|
||||||
textAlign: "center",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Right",
|
label: "Right",
|
||||||
key: "right",
|
key: "right",
|
||||||
control: Input,
|
control: Input,
|
||||||
placeholder: "px",
|
placeholder: "px",
|
||||||
textAlign: "center",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Bottom",
|
label: "Bottom",
|
||||||
key: "bottom",
|
key: "bottom",
|
||||||
control: Input,
|
control: Input,
|
||||||
placeholder: "px",
|
placeholder: "px",
|
||||||
textAlign: "center",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Left",
|
label: "Left",
|
||||||
key: "left",
|
key: "left",
|
||||||
control: Input,
|
control: Input,
|
||||||
placeholder: "px",
|
placeholder: "px",
|
||||||
textAlign: "center",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Z-index",
|
label: "Z-index",
|
||||||
|
@ -458,7 +448,6 @@ export const typography = [
|
||||||
{ label: "60px", value: "60px" },
|
{ label: "60px", value: "60px" },
|
||||||
{ label: "72px", value: "72px" },
|
{ label: "72px", value: "72px" },
|
||||||
],
|
],
|
||||||
textAlign: "center",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Line H",
|
label: "Line H",
|
||||||
|
@ -672,7 +661,6 @@ export const effects = [
|
||||||
label: "Opacity",
|
label: "Opacity",
|
||||||
key: "opacity",
|
key: "opacity",
|
||||||
control: OptionSelect,
|
control: OptionSelect,
|
||||||
textAlign: "center",
|
|
||||||
options: [
|
options: [
|
||||||
{ label: "Choose option", value: "" },
|
{ label: "Choose option", value: "" },
|
||||||
{ label: "0", value: "0" },
|
{ label: "0", value: "0" },
|
||||||
|
@ -758,7 +746,6 @@ export const transitions = [
|
||||||
label: "Duration",
|
label: "Duration",
|
||||||
key: "transition-duration",
|
key: "transition-duration",
|
||||||
control: OptionSelect,
|
control: OptionSelect,
|
||||||
textAlign: "center",
|
|
||||||
placeholder: "sec",
|
placeholder: "sec",
|
||||||
options: [
|
options: [
|
||||||
{ label: "Choose option", value: "" },
|
{ label: "Choose option", value: "" },
|
||||||
|
@ -785,7 +772,7 @@ export const transitions = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const all = {
|
export const allStyles = {
|
||||||
layout,
|
layout,
|
||||||
margin,
|
margin,
|
||||||
padding,
|
padding,
|
||||||
|
@ -797,13 +784,3 @@ export const all = {
|
||||||
effects,
|
effects,
|
||||||
transitions,
|
transitions,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function excludeProps(props, propsToExclude) {
|
|
||||||
const modifiedProps = {}
|
|
||||||
for (const prop in props) {
|
|
||||||
if (!propsToExclude.includes(prop)) {
|
|
||||||
modifiedProps[prop] = props[prop]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return modifiedProps
|
|
||||||
}
|
|
|
@ -1,14 +1,14 @@
|
||||||
import Input from "./PropertyPanelControls/Input.svelte"
|
import Input from "./PropertyPanelControls/Input.svelte"
|
||||||
import OptionSelect from "./OptionSelect.svelte"
|
import OptionSelect from "./PropertyPanelControls/OptionSelect.svelte"
|
||||||
import MultiTableViewFieldSelect from "./MultiTableViewFieldSelect.svelte"
|
import MultiTableViewFieldSelect from "./MultiTableViewFieldSelect.svelte"
|
||||||
import Checkbox from "../common/Checkbox.svelte"
|
import Checkbox from "../common/Checkbox.svelte"
|
||||||
import TableSelect from "components/userInterface/TableSelect.svelte"
|
import TableSelect from "components/userInterface/PropertyPanelControls/TableSelect.svelte"
|
||||||
import TableViewSelect from "components/userInterface/TableViewSelect.svelte"
|
import TableViewSelect from "components/userInterface/PropertyPanelControls/TableViewSelect.svelte"
|
||||||
import TableViewFieldSelect from "components/userInterface/TableViewFieldSelect.svelte"
|
import TableViewFieldSelect from "components/userInterface/PropertyPanelControls/TableViewFieldSelect.svelte"
|
||||||
import Event from "components/userInterface/EventsEditor/EventPropertyControl.svelte"
|
import Event from "components/userInterface/PropertyPanelControls/EventsEditor/EventPropertyControl.svelte"
|
||||||
import ScreenSelect from "components/userInterface/ScreenSelect.svelte"
|
import ScreenSelect from "components/userInterface/PropertyPanelControls/ScreenSelect.svelte"
|
||||||
import DetailScreenSelect from "components/userInterface/DetailScreenSelect.svelte"
|
import DetailScreenSelect from "components/userInterface/DetailScreenSelect.svelte"
|
||||||
import { IconSelect } from "components/userInterface/IconSelect"
|
import { IconSelect } from "components/userInterface/PropertyPanelControls/IconSelect"
|
||||||
import Colorpicker from "@budibase/colorpicker"
|
import Colorpicker from "@budibase/colorpicker"
|
||||||
|
|
||||||
import { all } from "./propertyCategories.js"
|
import { all } from "./propertyCategories.js"
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
<script>
|
<script>
|
||||||
// This component is overridden when running in a real app.
|
// This component is overridden when running in a real app.
|
||||||
// This simply serves as a placeholder component for the real screen router.
|
// This simply serves as a placeholder component for the real screen router
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
|
||||||
|
const { styleable } = getContext("sdk")
|
||||||
|
const component = getContext("component")
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div use:styleable={$component.styles}>
|
||||||
<h1>Screen Slot</h1>
|
<h1>Screen Slot</h1>
|
||||||
<span>
|
<span>
|
||||||
The screens that you create will be displayed inside this box.
|
The screens that you create will be displayed inside this box.
|
||||||
|
@ -14,16 +18,15 @@
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div {
|
div {
|
||||||
display: flex;
|
display: flex !important;
|
||||||
flex-direction: column;
|
flex-direction: column !important;
|
||||||
align-items: center;
|
align-items: center !important;
|
||||||
justify-content: center;
|
justify-content: center !important;
|
||||||
padding: 20px;
|
padding: 20px !important;
|
||||||
text-align: center;
|
text-align: center !important;
|
||||||
border-style: dashed !important;
|
border-style: dashed !important;
|
||||||
border-width: 1px;
|
border-width: 1px !important;
|
||||||
color: #000000;
|
color: #000000 !important;
|
||||||
background-color: rgba(0, 0, 0, 0.05);
|
background-color: rgba(0, 0, 0, 0.05) !important;
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue