Initial commit
This commit is contained in:
parent
088ed1139c
commit
b4a8f22b2e
|
@ -23,6 +23,7 @@ import BasicColumnEditor from "./controls/ColumnEditor/BasicColumnEditor.svelte"
|
|||
import GridColumnEditor from "./controls/ColumnEditor/GridColumnEditor.svelte"
|
||||
import BarButtonList from "./controls/BarButtonList.svelte"
|
||||
import FieldConfiguration from "./controls/FieldConfiguration/FieldConfiguration.svelte"
|
||||
import ButtonConfiguration from "./controls/ButtonConfiguration/ButtonConfiguration.svelte"
|
||||
import RelationshipFilterEditor from "./controls/RelationshipFilterEditor.svelte"
|
||||
|
||||
const componentMap = {
|
||||
|
@ -48,6 +49,7 @@ const componentMap = {
|
|||
"filter/relationship": RelationshipFilterEditor,
|
||||
url: URLSelect,
|
||||
fieldConfiguration: FieldConfiguration,
|
||||
buttonConfiguration: ButtonConfiguration,
|
||||
columns: ColumnEditor,
|
||||
"columns/basic": BasicColumnEditor,
|
||||
"columns/grid": GridColumnEditor,
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
<script>
|
||||
import DraggableList from "../DraggableList.svelte"
|
||||
import ButtonSetting from "./ButtonSetting.svelte"
|
||||
import {
|
||||
getBindableProperties,
|
||||
getComponentBindableProperties,
|
||||
} from "builderStore/dataBinding"
|
||||
import { createEventDispatcher, onMount } from "svelte"
|
||||
import { selectedScreen, store } from "builderStore"
|
||||
import { isEqual, cloneDeep } from "lodash"
|
||||
|
||||
export let componentInstance
|
||||
export let value
|
||||
|
||||
$: bindings = getBindableProperties($selectedScreen, componentInstance._id)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let buttonList
|
||||
let mounted
|
||||
let cachedValue
|
||||
let componentBindings = []
|
||||
|
||||
$: componentBindings = getComponentBindableProperties(
|
||||
$selectedScreen,
|
||||
componentInstance._id
|
||||
)
|
||||
|
||||
$: if (!isEqual(value, cachedValue) && mounted) {
|
||||
cachedValue = value
|
||||
? cloneDeep(value)
|
||||
: [
|
||||
buildPseudoInstance({ name: `Button 1`, type: "cta" }),
|
||||
buildPseudoInstance({ name: `Button 2` }),
|
||||
]
|
||||
}
|
||||
|
||||
const updateState = value => {
|
||||
buttonList = value
|
||||
}
|
||||
|
||||
$: updateState(cachedValue)
|
||||
|
||||
const processItemUpdate = e => {
|
||||
const updatedField = e.detail
|
||||
const parentButtonsUpdated = buttonList ? cloneDeep(buttonList) : []
|
||||
|
||||
let parentFieldIdx = parentButtonsUpdated.findIndex(pSetting => {
|
||||
return pSetting._id === updatedField?._id
|
||||
})
|
||||
|
||||
if (parentFieldIdx == -1) {
|
||||
parentButtonsUpdated.push(updatedField)
|
||||
} else {
|
||||
parentButtonsUpdated[parentFieldIdx] = updatedField
|
||||
}
|
||||
console.log("On value update ", parentButtonsUpdated)
|
||||
dispatch("change", parentButtonsUpdated)
|
||||
}
|
||||
|
||||
const listUpdated = e => {
|
||||
dispatch("change", [...e.detail])
|
||||
}
|
||||
|
||||
// May not be necessary without
|
||||
const buildPseudoInstance = cfg => {
|
||||
const pseudoComponentInstance = store.actions.components.createInstance(
|
||||
`@budibase/standard-components/button`,
|
||||
{
|
||||
_instanceName: cfg.name,
|
||||
text: cfg.name,
|
||||
type: cfg.type || "primary",
|
||||
},
|
||||
{}
|
||||
)
|
||||
|
||||
return pseudoComponentInstance
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
mounted = true
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="button-configuration">
|
||||
{#if buttonList?.length}
|
||||
<DraggableList
|
||||
on:change={listUpdated}
|
||||
on:itemChange={processItemUpdate}
|
||||
items={buttonList}
|
||||
listItemKey={"_id"}
|
||||
listType={ButtonSetting}
|
||||
listTypeProps={{
|
||||
componentBindings,
|
||||
bindings,
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.button-configuration :global(.spectrum-ActionButton) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,61 @@
|
|||
<script>
|
||||
import EditFieldPopover from "../FieldConfiguration/EditFieldPopover.svelte"
|
||||
import { Icon } from "@budibase/bbui"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
// import { cloneDeep } from "lodash/fp"
|
||||
|
||||
export let item
|
||||
export let componentBindings
|
||||
export let bindings
|
||||
export let anchor
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
// const onToggle = item => {
|
||||
// return e => {
|
||||
// item.active = e.detail
|
||||
// dispatch("change", { ...cloneDeep(item), active: e.detail })
|
||||
// }
|
||||
// }
|
||||
</script>
|
||||
|
||||
<div class="list-item-body">
|
||||
<div class="list-item-left">
|
||||
<EditFieldPopover
|
||||
{anchor}
|
||||
field={item}
|
||||
{componentBindings}
|
||||
{bindings}
|
||||
on:change
|
||||
/>
|
||||
<div class="field-label">{item.text}</div>
|
||||
</div>
|
||||
<div class="list-item-right">
|
||||
<Icon size="S" name="Close" hoverable on:click={() => {console.log("REMOVE ME")}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.field-label {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.list-item-body,
|
||||
.list-item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-m);
|
||||
min-width: 0;
|
||||
}
|
||||
.list-item-body {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.list-item-right :global(div.spectrum-Switch) {
|
||||
margin: 0px;
|
||||
}
|
||||
.list-item-body {
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
|
@ -1,91 +0,0 @@
|
|||
<script>
|
||||
import { Button, ActionButton, Drawer } from "@budibase/bbui"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import ColumnDrawer from "./ColumnEditor/ColumnDrawer.svelte"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import {
|
||||
getDatasourceForProvider,
|
||||
getSchemaForDatasource,
|
||||
} from "builderStore/dataBinding"
|
||||
import { currentAsset } from "builderStore"
|
||||
import { getFields } from "helpers/searchFields"
|
||||
|
||||
export let componentInstance
|
||||
export let value = []
|
||||
export let allowCellEditing = true
|
||||
export let subject = "Table"
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let drawer
|
||||
let boundValue
|
||||
|
||||
$: datasource = getDatasourceForProvider($currentAsset, componentInstance)
|
||||
$: schema = getSchema($currentAsset, datasource)
|
||||
$: options = allowCellEditing
|
||||
? Object.keys(schema || {})
|
||||
: enrichedSchemaFields?.map(field => field.name)
|
||||
$: sanitisedValue = getValidColumns(value, options)
|
||||
$: updateBoundValue(sanitisedValue)
|
||||
$: enrichedSchemaFields = getFields(Object.values(schema || {}), {
|
||||
allowLinks: true,
|
||||
})
|
||||
|
||||
const getSchema = (asset, datasource) => {
|
||||
const schema = getSchemaForDatasource(asset, datasource).schema
|
||||
|
||||
// Don't show ID and rev in tables
|
||||
if (schema) {
|
||||
delete schema._id
|
||||
delete schema._rev
|
||||
}
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
const updateBoundValue = value => {
|
||||
boundValue = cloneDeep(value)
|
||||
}
|
||||
|
||||
const getValidColumns = (columns, options) => {
|
||||
if (!Array.isArray(columns) || !columns.length) {
|
||||
return []
|
||||
}
|
||||
// We need to account for legacy configs which would just be an array
|
||||
// of strings
|
||||
if (typeof columns[0] === "string") {
|
||||
columns = columns.map(col => ({
|
||||
name: col,
|
||||
displayName: col,
|
||||
}))
|
||||
}
|
||||
return columns.filter(column => {
|
||||
return options.includes(column.name)
|
||||
})
|
||||
}
|
||||
|
||||
const open = () => {
|
||||
updateBoundValue(sanitisedValue)
|
||||
drawer.show()
|
||||
}
|
||||
|
||||
const save = () => {
|
||||
dispatch("change", getValidColumns(boundValue, options))
|
||||
drawer.hide()
|
||||
}
|
||||
</script>
|
||||
|
||||
<ActionButton on:click={open}>Configure columns</ActionButton>
|
||||
<Drawer bind:this={drawer} title="{subject} Columns">
|
||||
<svelte:fragment slot="description">
|
||||
Configure the columns in your {subject.toLowerCase()}.
|
||||
</svelte:fragment>
|
||||
<Button cta slot="buttons" on:click={save}>Save</Button>
|
||||
<ColumnDrawer
|
||||
slot="body"
|
||||
bind:columns={boundValue}
|
||||
{options}
|
||||
{schema}
|
||||
{allowCellEditing}
|
||||
/>
|
||||
</Drawer>
|
|
@ -61,6 +61,25 @@
|
|||
|
||||
dispatch("change", update)
|
||||
}
|
||||
|
||||
const customPositionHandler = (anchorBounds, eleBounds, cfg) => {
|
||||
let { left, top } = cfg
|
||||
let percentageOffset = 30
|
||||
// left-outside
|
||||
left = anchorBounds.left - eleBounds.width - 18
|
||||
|
||||
// shift up from the anchor, if space allows
|
||||
let offsetPos = Math.floor(eleBounds.height / 100) * percentageOffset
|
||||
let defaultTop = anchorBounds.top - offsetPos
|
||||
|
||||
if (window.innerHeight - defaultTop < eleBounds.height) {
|
||||
top = window.innerHeight - eleBounds.height - 5
|
||||
} else {
|
||||
top = anchorBounds.top - offsetPos
|
||||
}
|
||||
|
||||
return { ...cfg, left, top }
|
||||
}
|
||||
</script>
|
||||
|
||||
<Icon
|
||||
|
@ -92,24 +111,7 @@
|
|||
showPopover={drawers.length == 0}
|
||||
clickOutsideOverride={drawers.length > 0}
|
||||
maxHeight={600}
|
||||
handlePostionUpdate={(anchorBounds, eleBounds, cfg) => {
|
||||
let { left, top } = cfg
|
||||
let percentageOffset = 30
|
||||
// left-outside
|
||||
left = anchorBounds.left - eleBounds.width - 18
|
||||
|
||||
// shift up from the anchor, if space allows
|
||||
let offsetPos = Math.floor(eleBounds.height / 100) * percentageOffset
|
||||
let defaultTop = anchorBounds.top - offsetPos
|
||||
|
||||
if (window.innerHeight - defaultTop < eleBounds.height) {
|
||||
top = window.innerHeight - eleBounds.height - 5
|
||||
} else {
|
||||
top = anchorBounds.top - offsetPos
|
||||
}
|
||||
|
||||
return { ...cfg, left, top }
|
||||
}}
|
||||
handlePostionUpdate={customPositionHandler}
|
||||
>
|
||||
<span class="popover-wrap">
|
||||
<Layout noPadding noGap>
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
updateSanitsedFields(sanitisedValue)
|
||||
unconfigured = buildUnconfiguredOptions(schema, sanitisedFields)
|
||||
fieldList = [...sanitisedFields, ...unconfigured]
|
||||
.map(buildSudoInstance)
|
||||
.map(buildPseudoInstance)
|
||||
.filter(x => x != null)
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@
|
|||
})
|
||||
}
|
||||
|
||||
const buildSudoInstance = instance => {
|
||||
const buildPseudoInstance = instance => {
|
||||
if (instance._component) {
|
||||
return instance
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
"heading",
|
||||
"text",
|
||||
"button",
|
||||
"buttongroup",
|
||||
"tag",
|
||||
"spectrumcard",
|
||||
"cardstat",
|
||||
|
|
|
@ -258,6 +258,189 @@
|
|||
"description": "Contains your app screens",
|
||||
"static": true
|
||||
},
|
||||
|
||||
"buttongroup": {
|
||||
"name": "Button group",
|
||||
"icon": "Button",
|
||||
"hasChildren": false,
|
||||
"settings": [
|
||||
{
|
||||
"section": true,
|
||||
"name": "Buttons",
|
||||
"settings": [
|
||||
{
|
||||
"type": "buttonConfiguration",
|
||||
"key": "buttons",
|
||||
"nested": true,
|
||||
"defaultValue" : [{
|
||||
"component" : "button",
|
||||
"props" : {
|
||||
"type": "cta"
|
||||
}
|
||||
},{
|
||||
"component" : "button",
|
||||
"props" : {
|
||||
"type" : "primary"
|
||||
}
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"section": true,
|
||||
"name": "Layout",
|
||||
"settings": [
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Direction",
|
||||
"key": "direction",
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "Column",
|
||||
"value": "column",
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "Column layout"
|
||||
},
|
||||
{
|
||||
"label": "Row",
|
||||
"value": "row",
|
||||
"barIcon": "ViewRow",
|
||||
"barTitle": "Row layout"
|
||||
}
|
||||
],
|
||||
"defaultValue": "column"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Horiz. align",
|
||||
"key": "hAlign",
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "Left",
|
||||
"value": "left",
|
||||
"barIcon": "AlignLeft",
|
||||
"barTitle": "Align left"
|
||||
},
|
||||
{
|
||||
"label": "Center",
|
||||
"value": "center",
|
||||
"barIcon": "AlignCenter",
|
||||
"barTitle": "Align center"
|
||||
},
|
||||
{
|
||||
"label": "Right",
|
||||
"value": "right",
|
||||
"barIcon": "AlignRight",
|
||||
"barTitle": "Align right"
|
||||
},
|
||||
{
|
||||
"label": "Stretch",
|
||||
"value": "stretch",
|
||||
"barIcon": "MoveLeftRight",
|
||||
"barTitle": "Align stretched horizontally"
|
||||
}
|
||||
],
|
||||
"defaultValue": "left"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Vert. align",
|
||||
"key": "vAlign",
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "Top",
|
||||
"value": "top",
|
||||
"barIcon": "AlignTop",
|
||||
"barTitle": "Align top"
|
||||
},
|
||||
{
|
||||
"label": "Middle",
|
||||
"value": "middle",
|
||||
"barIcon": "AlignMiddle",
|
||||
"barTitle": "Align middle"
|
||||
},
|
||||
{
|
||||
"label": "Bottom",
|
||||
"value": "bottom",
|
||||
"barIcon": "AlignBottom",
|
||||
"barTitle": "Align bottom"
|
||||
},
|
||||
{
|
||||
"label": "Stretch",
|
||||
"value": "stretch",
|
||||
"barIcon": "MoveUpDown",
|
||||
"barTitle": "Align stretched vertically"
|
||||
}
|
||||
],
|
||||
"defaultValue": "top"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Size",
|
||||
"key": "size",
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "Shrink",
|
||||
"value": "shrink",
|
||||
"barIcon": "Minimize",
|
||||
"barTitle": "Shrink container"
|
||||
},
|
||||
{
|
||||
"label": "Grow",
|
||||
"value": "grow",
|
||||
"barIcon": "Maximize",
|
||||
"barTitle": "Grow container"
|
||||
}
|
||||
],
|
||||
"defaultValue": "shrink"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Gap",
|
||||
"key": "gap",
|
||||
"showInBar": true,
|
||||
"barStyle": "picker",
|
||||
"options": [
|
||||
{
|
||||
"label": "None",
|
||||
"value": "N"
|
||||
},
|
||||
{
|
||||
"label": "Small",
|
||||
"value": "S"
|
||||
},
|
||||
{
|
||||
"label": "Medium",
|
||||
"value": "M"
|
||||
},
|
||||
{
|
||||
"label": "Large",
|
||||
"value": "L"
|
||||
}
|
||||
],
|
||||
"defaultValue": "M"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Wrap",
|
||||
"key": "wrap",
|
||||
"showInBar": true,
|
||||
"barIcon": "ModernGridView",
|
||||
"barTitle": "Wrap"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"button": {
|
||||
"name": "Button",
|
||||
"description": "A basic html button that is ready for styling",
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import Container from "components/app/Container.svelte"
|
||||
import BlockComponent from "../../BlockComponent.svelte"
|
||||
import Block from "../../Block.svelte"
|
||||
|
||||
const { styleable } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
|
||||
export let buttons = []
|
||||
export let direction
|
||||
export let hAlign
|
||||
export let vAlign
|
||||
export let gap = "S"
|
||||
export let wrap
|
||||
|
||||
$: console.log("client buttons/wrap", buttons, wrap)
|
||||
</script>
|
||||
|
||||
<!-- <div use:styleable={$component.styles}> -->
|
||||
<Block>
|
||||
<Container {direction} {hAlign} {vAlign} {gap} {wrap}>
|
||||
{#each buttons as { text, type, quiet, disabled, onClick, size }}
|
||||
<BlockComponent
|
||||
type="button"
|
||||
props={{
|
||||
text,
|
||||
onClick,
|
||||
type,
|
||||
quiet,
|
||||
disabled,
|
||||
size
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
</Container>
|
||||
</Block>
|
||||
<!-- </div> -->
|
|
@ -16,3 +16,4 @@ export { default as jsonfield } from "./JSONField.svelte"
|
|||
export { default as s3upload } from "./S3Upload.svelte"
|
||||
export { default as codescanner } from "./CodeScannerField.svelte"
|
||||
export { default as bbreferencefield } from "./BBReferenceField.svelte"
|
||||
export { default as buttongroup } from "./ButtonGroup.svelte"
|
Loading…
Reference in New Issue