Merge branch 'spectrum-bbui' of github.com:Budibase/budibase into spectrum-bbui

This commit is contained in:
Andrew Kingston 2021-04-27 15:50:59 +01:00
commit 11fa09ae8b
20 changed files with 337 additions and 418 deletions

View File

@ -3,8 +3,6 @@
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
/** @type {('S', 'M', 'L', 'XL')} Size of button */
export let size = "M"
export let quiet = false export let quiet = false
export let emphasized = false export let emphasized = false
export let selected = false export let selected = false
@ -12,6 +10,12 @@
export let disabled = false export let disabled = false
export let icon = "" export let icon = ""
export let xl = false
export let l = false
export let m = false
export let s = false
$: useDefault = ![xl, l, m, s].includes(true)
function longPress(element) { function longPress(element) {
if (!longPressable) return if (!longPressable) return
let timer let timer
@ -38,7 +42,11 @@
class:spectrum-ActionButton--quiet={quiet} class:spectrum-ActionButton--quiet={quiet}
class:spectrum-ActionButton--emphasized={emphasized} class:spectrum-ActionButton--emphasized={emphasized}
class:is-selected={selected} class:is-selected={selected}
class="spectrum-ActionButton spectrum-ActionButton--size{size.toUpperCase()}" class:spectrum-ActionButton--sizeS={s}
class:spectrum-ActionButton--sizeM={m || useDefault}
class:spectrum-ActionButton--sizeL={l}
class:spectrum-ActionButton--sizeXL={xl}
class="spectrum-ActionButton"
{disabled} {disabled}
on:longPress on:longPress
on:click|preventDefault on:click|preventDefault
@ -54,7 +62,11 @@
{/if} {/if}
{#if icon} {#if icon}
<svg <svg
class="spectrum-Icon spectrum-Icon--size{size.toUpperCase()}" class:spectrum-Icon--sizeS={s}
class:spectrum-Icon--sizeM={m || useDefault}
class:spectrum-Icon--sizeL={l}
class:spectrum-Icon--sizeXL={xl}
class="spectrum-Icon"
focusable="false" focusable="false"
aria-hidden="true" aria-hidden="true"
aria-label={icon} aria-label={icon}

View File

@ -1,6 +1,10 @@
<script> <script>
import { setContext } from "svelte"
import Popover from "../Popover/Popover.svelte" import Popover from "../Popover/Popover.svelte"
import Menu from "../Menu/Menu.svelte" import Menu from "../Menu/Menu.svelte"
export let disabled = false
let anchor let anchor
let dropdown let dropdown
@ -16,10 +20,16 @@
export const show = () => { export const show = () => {
dropdown.show() dropdown.show()
} }
const openMenu = () => {
if (!disabled) show()
}
setContext("actionMenu", { show, hide })
</script> </script>
<div class="contents" use:getAnchor on:click={dropdown.show}> <div class="contents" use:getAnchor on:click={openMenu}>
<slot name="button" /> <slot name="control" />
</div> </div>
<Popover bind:this={dropdown} {anchor} align="left"> <Popover bind:this={dropdown} {anchor} align="left">
<Menu> <Menu>

View File

@ -42,7 +42,7 @@
</div> </div>
<div class="buttons"> <div class="buttons">
<slot name="buttons" /> <slot name="buttons" />
<ActionButton selected quiet icon="Close" on:click={hide} /> <ActionButton quiet icon="Close" on:click={hide} />
</div> </div>
</header> </header>
<slot name="body" /> <slot name="body" />

View File

@ -0,0 +1,65 @@
<script>
export let horizontal = false
export let paddingX = "M"
export let paddingY = "M"
export let noPadding = false
export let gap = "M"
export let noGap = false
</script>
<div
class:horizontal
class="container paddingX-{!noPadding && paddingX} paddingY-{!noPadding &&
paddingY} gap-{!noGap && gap}"
>
<slot />
</div>
<style>
.container {
display: grid;
grid-template-columns: 1fr;
}
.paddingX-S {
padding-left: var(--spacing-s);
padding-right: var(--spacing-s);
}
.paddingX-M {
padding-left: var(--spacing-m);
padding-right: var(--spacing-m);
}
.paddingX-L {
padding-left: var(--spacing-l);
padding-right: var(--spacing-l);
}
.paddingY-S {
padding-top: var(--spacing-s);
padding-bottom: var(--spacing-s);
}
.paddingY-M {
padding-top: var(--spacing-m);
padding-bottom: var(--spacing-m);
}
.paddingY-L {
padding-top: var(--spacing-l);
padding-bottom: var(--spacing-l);
}
.gap-S {
grid-gap: var(--spectrum-alias-grid-gutter-xsmall);
}
.gap-M {
grid-gap: var(--spectrum-alias-grid-gutter-small);
}
.gap-L {
grid-gap: var(--spectrum-alias-grid-gutter-medium);
}
.horizontal.gap-S :global(*) + :global(*) {
margin-left: var(--spectrum-alias-grid-gutter-xsmall);
}
.horizontal.gap-M :global(*) + :global(*) {
margin-left: var(--spectrum-alias-grid-gutter-small);
}
.horizontal.gap-L :global(*) + :global(*) {
margin-left: var(--spectrum-alias-grid-gutter-medium);
}
</style>

View File

@ -1,13 +1,39 @@
<script> <script>
export let icon = undefined; import { createEventDispatcher, getContext } from "svelte"
export let disabled = undefined;
const dispatch = createEventDispatcher()
const actionMenu = getContext("actionMenu")
export let dataCy
export let icon = undefined
export let disabled = undefined
export let noClose = false
const onClick = () => {
if (actionMenu && !noClose) {
actionMenu.hide()
}
dispatch("click")
}
</script> </script>
<li on:click|preventDefault class="spectrum-Menu-item" class:is-disabled={disabled} role="menuitem" tabindex="0"> <li
{#if icon} data-cy={dataCy}
<svg class="spectrum-Icon spectrum-Icon--sizeM spectrum-Menu-itemIcon" focusable="false" aria-hidden="true" aria-label={icon}> on:click|preventDefault={onClick}
<use xlink:href="#spectrum-icon-18-{icon}"></use> class="spectrum-Menu-item"
</svg> class:is-disabled={disabled}
{/if} role="menuitem"
<span class="spectrum-Menu-itemLabel"><slot /></span> tabindex="0"
</li> >
{#if icon}
<svg
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Menu-itemIcon"
focusable="false"
aria-hidden="true"
aria-label={icon}
>
<use xlink:href="#spectrum-icon-18-{icon}" />
</svg>
{/if}
<span class="spectrum-Menu-itemLabel"><slot /></span>
</li>

View File

@ -13,5 +13,5 @@
<Checkbox value={selected} /> <Checkbox value={selected} />
{/if} {/if}
{#if allowEditRows} {#if allowEditRows}
<ActionButton size="s" on:click={onEdit}>Edit</ActionButton> <ActionButton s on:click={onEdit}>Edit</ActionButton>
{/if} {/if}

View File

@ -27,6 +27,7 @@ export { default as Popover } from "./Popover/Popover.svelte"
export { default as ProgressBar } from "./ProgressBar/ProgressBar.svelte" export { default as ProgressBar } from "./ProgressBar/ProgressBar.svelte"
export { default as ProgressCircle } from "./ProgressCircle/ProgressCircle.svelte" export { default as ProgressCircle } from "./ProgressCircle/ProgressCircle.svelte"
export { default as Label } from "./Styleguide/Label.svelte" export { default as Label } from "./Styleguide/Label.svelte"
export { default as Layout } from "./Layout/Layout.svelte"
export { default as Link } from "./Link/Link.svelte" export { default as Link } from "./Link/Link.svelte"
export { default as Close } from "./Button/Close.svelte" export { default as Close } from "./Button/Close.svelte"
export { default as Menu } from "./Menu/Menu.svelte" export { default as Menu } from "./Menu/Menu.svelte"

View File

@ -65,8 +65,8 @@
{#each tabs as tab, idx} {#each tabs as tab, idx}
<div bind:this={anchors[idx]}> <div bind:this={anchors[idx]}>
<ActionButton <ActionButton
size="S"
quiet quiet
s
icon={tab.icon} icon={tab.icon}
disabled={tab.disabled} disabled={tab.disabled}
on:click={tab.disabled ? null : () => onChangeTab(idx)}> on:click={tab.disabled ? null : () => onChangeTab(idx)}>

View File

@ -2,26 +2,14 @@
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { automationStore } from "builderStore" import { automationStore } from "builderStore"
import { database } from "stores/backend" import { database } from "stores/backend"
import { notifications } from "@budibase/bbui" import { ActionMenu, MenuItem, notifications, Icon } from "@budibase/bbui"
import { Icon, Popover } from "@budibase/bbui"
import {
DropdownContainer,
DropdownItem,
} from "components/common/Dropdowns"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
export let automation export let automation
let anchor
let dropdown
let confirmDeleteDialog let confirmDeleteDialog
$: instanceId = $database._id $: instanceId = $database._id
function showModal() {
dropdown.hide()
confirmDeleteDialog.show()
}
async function deleteAutomation() { async function deleteAutomation() {
await automationStore.actions.delete({ await automationStore.actions.delete({
instanceId, instanceId,
@ -32,20 +20,15 @@
} }
</script> </script>
<div on:click|stopPropagation> <ActionMenu>
<div bind:this={anchor} class="icon" on:click={dropdown.show}> <div slot="control" class="icon">
<Icon s hoverable name="MoreSmallList" /> <Icon s hoverable name="MoreSmallList" />
</div> </div>
<Popover align="left" {anchor} bind:this={dropdown}> <MenuItem noClose icon="Delete" on:click={confirmDeleteDialog.show}
<DropdownContainer> >Delete</MenuItem
<DropdownItem >
icon="ri-delete-bin-line" </ActionMenu>
title="Delete"
on:click={showModal}
/>
</DropdownContainer>
</Popover>
</div>
<ConfirmDialog <ConfirmDialog
bind:this={confirmDeleteDialog} bind:this={confirmDeleteDialog}
okText="Delete Automation" okText="Delete Automation"

View File

@ -2,54 +2,31 @@
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { datasources } from "stores/backend" import { datasources } from "stores/backend"
import { notifications } from "@budibase/bbui" import { notifications } from "@budibase/bbui"
import { Icon, Popover } from "@budibase/bbui" import { ActionMenu, MenuItem, Icon, Popover } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
export let datasource export let datasource
let anchor
let dropdown
let confirmDeleteDialog let confirmDeleteDialog
function hideEditor() {
dropdown?.hide()
}
function showModal() {
hideEditor()
confirmDeleteDialog.show()
}
async function deleteDatasource() { async function deleteDatasource() {
const wasSelectedSource = $datasources.selected const wasSelectedSource = $datasources.selected
console.log(wasSelectedSource)
console.log(datasource)
await datasources.delete(datasource) await datasources.delete(datasource)
notifications.success("Datasource deleted") notifications.success("Datasource deleted")
// navigate to first index page if the source you are deleting is selected // navigate to first index page if the source you are deleting is selected
if (wasSelectedSource === datasource._id) { if (wasSelectedSource === datasource._id) {
$goto("./datasource") $goto("./datasource")
} }
hideEditor()
} }
</script> </script>
<div on:click|stopPropagation> <ActionMenu>
<div bind:this={anchor} class="icon" on:click={dropdown.show}> <div slot="control" class="icon">
<Icon s hoverable name="MoreSmallList" /> <Icon s hoverable name="MoreSmallList" />
</div> </div>
<Popover align="left" {anchor} bind:this={dropdown}> <MenuItem icon="Delete" on:click={confirmDeleteDialog.show}>Delete</MenuItem>
<DropdownContainer> </ActionMenu>
<DropdownItem
icon="ri-delete-bin-line"
title="Delete"
on:click={showModal}
data-cy="delete-datasource"
/>
</DropdownContainer>
</Popover>
</div>
<ConfirmDialog <ConfirmDialog
bind:this={confirmDeleteDialog} bind:this={confirmDeleteDialog}
okText="Delete Datasource" okText="Delete Datasource"

View File

@ -1,46 +1,25 @@
<script> <script>
import { notifications } from "@budibase/bbui" import { ActionMenu, MenuItem, Icon, notifications } from "@budibase/bbui"
import { Icon, Popover } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" import { queries } from "stores/backend"
export let query export let query
let anchor
let dropdown
let confirmDeleteDialog let confirmDeleteDialog
function hideEditor() {
dropdown?.hide()
}
function showModal() {
hideEditor()
confirmDeleteDialog.show()
}
async function deleteQuery() { async function deleteQuery() {
await queries.delete(query) await queries.delete(query)
notifications.success("Query deleted") notifications.success("Query deleted")
hideEditor()
} }
</script> </script>
<div on:click|stopPropagation> <ActionMenu>
<div bind:this={anchor} class="icon" on:click={dropdown.show}> <div slot="control" class="icon">
<Icon s hoverable name="MoreSmallList" /> <Icon s hoverable name="MoreSmallList" />
</div> </div>
<Popover align="left" {anchor} bind:this={dropdown}> <MenuItem icon="Delete" on:click={confirmDeleteDialog.show}>Delete</MenuItem>
<DropdownContainer> </ActionMenu>
<DropdownItem
icon="ri-delete-bin-line"
title="Delete"
on:click={showModal}
data-cy="delete-datasource"
/>
</DropdownContainer>
</Popover>
</div>
<ConfirmDialog <ConfirmDialog
bind:this={confirmDeleteDialog} bind:this={confirmDeleteDialog}
okText="Delete Query" okText="Delete Query"

View File

@ -3,31 +3,26 @@
import { store, allScreens } from "builderStore" import { store, allScreens } from "builderStore"
import { tables } from "stores/backend" import { tables } from "stores/backend"
import { notifications } from "@budibase/bbui" import { notifications } from "@budibase/bbui"
import { Icon, Popover, Button, Input } from "@budibase/bbui" import {
ActionMenu,
MenuItem,
Icon,
Modal,
ModalContent,
Input,
} from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
export let table export let table
let anchor let editorModal
let dropdown
let editing
let confirmDeleteDialog let confirmDeleteDialog
let error = "" let error = ""
let originalName = table.name let originalName = table.name
let templateScreens let templateScreens
let willBeDeleted let willBeDeleted
function showEditor() { function showDeleteModal() {
editing = true
}
function hideEditor() {
dropdown?.hide()
editing = false
}
function showModal() {
const screens = $allScreens const screens = $allScreens
templateScreens = screens.filter( templateScreens = screens.filter(
(screen) => screen.autoTableId === table._id (screen) => screen.autoTableId === table._id
@ -35,7 +30,6 @@
willBeDeleted = ["All table data"].concat( willBeDeleted = ["All table data"].concat(
templateScreens.map((screen) => `Screen ${screen.props._instanceName}`) templateScreens.map((screen) => `Screen ${screen.props._instanceName}`)
) )
hideEditor()
confirmDeleteDialog.show() confirmDeleteDialog.show()
} }
@ -48,62 +42,48 @@
if (wasSelectedTable._id === table._id) { if (wasSelectedTable._id === table._id) {
$goto("./table") $goto("./table")
} }
hideEditor() editorModal.hide()
} }
async function save() { async function save() {
await tables.save(table) await tables.save(table)
notifications.success("Table renamed successfully") notifications.success("Table renamed successfully")
hideEditor() editorModal.hide()
} }
function checkValid(evt) { function checkValid(evt) {
const tableName = evt.target.value const tableName = evt.target.value
error = error =
originalName !== tableName originalName === tableName
? `Table with name ${tableName} already exists. Please choose another name.` ? `Table with name ${tableName} already exists. Please choose another name.`
: "" : ""
} }
</script> </script>
<div on:click|stopPropagation> <ActionMenu>
<div bind:this={anchor} class="icon" on:click={dropdown.show}> <div slot="control" class="icon">
<Icon s hoverable name="MoreSmallList" /> <Icon s hoverable name="MoreSmallList" />
</div> </div>
<Popover align="left" {anchor} bind:this={dropdown}> <MenuItem icon="Edit" on:click={editorModal.show}>Edit</MenuItem>
{#if editing} <MenuItem icon="Delete" on:click={showDeleteModal}>Delete</MenuItem>
<div class="actions"> </ActionMenu>
<h5>Edit Table</h5>
<Input <Modal bind:this={editorModal}>
label="Table Name" <ModalContent
thin title="Edit Table"
bind:value={table.name} confirmText="Save"
on:input={checkValid} onConfirm={save}
{error} disabled={table.name === originalName || error}
/> >
<footer> <Input
<Button secondary on:click={hideEditor}>Cancel</Button> label="Table Name"
<Button primary disabled={error} on:click={save}>Save</Button> thin
</footer> bind:value={table.name}
</div> on:input={checkValid}
{:else} {error}
<DropdownContainer> />
<DropdownItem </ModalContent>
icon="ri-edit-line" </Modal>
data-cy="edit-table"
title="Edit"
on:click={showEditor}
/>
<DropdownItem
icon="ri-delete-bin-line"
title="Delete"
on:click={showModal}
data-cy="delete-table"
/>
</DropdownContainer>
{/if}
</Popover>
</div>
<ConfirmDialog <ConfirmDialog
bind:this={confirmDeleteDialog} bind:this={confirmDeleteDialog}
okText="Delete Table" okText="Delete Table"

View File

@ -1,25 +1,18 @@
<script> <script>
import { goto } from "@roxi/routify"
import { import {
store, ActionMenu,
currentAssetName, ActionGroup,
selectedComponent, ActionButton,
currentAssetId, MenuItem,
} from "builderStore" } from "@budibase/bbui"
import { store, currentAssetName } from "builderStore"
import structure from "./componentStructure.json" import structure from "./componentStructure.json"
import { Popover } from "@budibase/bbui"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
$: enrichedStructure = enrichStructure(structure, $store.components) $: enrichedStructure = enrichStructure(structure, $store.components)
let selectedIndex
let anchors = []
let popover
$: anchor = selectedIndex === -1 ? null : anchors[selectedIndex]
const enrichStructure = (structure, definitions) => { const enrichStructure = (structure, definitions) => {
let enrichedStructure = [] let enrichedStructure = []
structure.forEach(item => { structure.forEach((item) => {
if (typeof item === "string") { if (typeof item === "string") {
const def = definitions[`@budibase/standard-components/${item}`] const def = definitions[`@budibase/standard-components/${item}`]
if (def) { if (def) {
@ -43,77 +36,37 @@
if (item.isCategory) { if (item.isCategory) {
// Select and open this category // Select and open this category
selectedIndex = idx selectedIndex = idx
popover.show()
} else { } else {
// Add this component // Add this component
await store.actions.components.create(item.component) await store.actions.components.create(item.component)
popover.hide()
} }
} }
</script> </script>
<div class="container"> <ActionGroup>
{#each enrichedStructure as item, idx} {#each enrichedStructure as item, idx}
<div <ActionMenu disabled={!item.isCategory}>
bind:this={anchors[idx]} <ActionButton
class="category" icon={item.icon}
data-cy={item.isCategory ? `category-${item.name}` : `component-${item.name}`} xs
on:click={() => onItemChosen(item, idx)} primary
class:active={idx === selectedIndex}> quiet
{#if item.icon}<i class={item.icon} />{/if} slot="control"
<span>{item.name}</span> on:click={() => onItemChosen(item, idx)}
{#if item.isCategory}<i class="ri-arrow-down-s-line arrow" />{/if} >
</div> {item.name}
</ActionButton>
{#each item.children || [] as item}
{#if !item.showOnAsset || item.showOnAsset.includes($currentAssetName)}
<MenuItem
dataCy={`component-${item.name}`}
icon={item.icon}
on:click={() => onItemChosen(item)}
>
{item.name}
</MenuItem>
{/if}
{/each}
</ActionMenu>
{/each} {/each}
</div> </ActionGroup>
<Popover
on:close={() => (selectedIndex = null)}
bind:this={popover}
{anchor}
align="left">
<DropdownContainer>
{#each enrichedStructure[selectedIndex].children as item}
{#if !item.showOnAsset || item.showOnAsset.includes($currentAssetName)}
<DropdownItem
data-cy={`component-${item.name}`}
icon={item.icon}
title={item.name}
on:click={() => onItemChosen(item)} />
{/if}
{/each}
</DropdownContainer>
</Popover>
<style>
.container {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
min-height: 24px;
flex-wrap: wrap;
gap: var(--spacing-l);
}
.category {
color: var(--grey-7);
cursor: pointer;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: var(--spacing-s);
font-size: var(--spectrum-global-dimension-font-size-75);
}
.category span {
font-weight: 500;
user-select: none;
}
.category.active,
.category:hover {
color: var(--ink);
}
.category i:not(:last-child) {
font-size: 16px;
}
</style>

View File

@ -3,23 +3,17 @@
import { store, currentAsset } from "builderStore" import { store, currentAsset } from "builderStore"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { findComponentParent } from "builderStore/storeUtils" import { findComponentParent } from "builderStore/storeUtils"
import { Icon, Popover } from "@budibase/bbui" import { ActionMenu, MenuItem, Icon } from "@budibase/bbui"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
export let component export let component
let confirmDeleteDialog let confirmDeleteDialog
let dropdown
let anchor let anchor
$: definition = store.actions.components.getDefinition(component?._component) $: definition = store.actions.components.getDefinition(component?._component)
$: noChildrenAllowed = !component || !definition?.hasChildren $: noChildrenAllowed = !component || !definition?.hasChildren
$: noPaste = !$store.componentToPaste $: noPaste = !$store.componentToPaste
const hideDropdown = () => {
dropdown.hide()
}
const moveUpComponent = () => { const moveUpComponent = () => {
const asset = get(currentAsset) const asset = get(currentAsset)
const parent = findComponentParent(asset.props, component._id) const parent = findComponentParent(asset.props, component._id)
@ -72,62 +66,42 @@
} }
</script> </script>
<div bind:this={anchor} on:click|stopPropagation> <ActionMenu>
<div class="icon" on:click={dropdown.show}><Icon hoverable name="MoreSmallList" /></div> <div slot="control" class="icon">
<Popover bind:this={dropdown} width="170px" {anchor} align="left"> <Icon s hoverable name="MoreSmallList" />
<DropdownContainer on:click={hideDropdown}> </div>
<DropdownItem <MenuItem icon="Delete" on:click={confirmDeleteDialog.show}>Delete</MenuItem>
icon="ri-delete-bin-line" <MenuItem noClose icon="ChevronUp" on:click={moveUpComponent}
title="Delete" >Move up</MenuItem
on:click={() => confirmDeleteDialog.show()} >
/> <MenuItem noClose icon="ChevronDown" on:click={moveDownComponent}
<DropdownItem >Move down</MenuItem
icon="ri-arrow-up-line" >
title="Move up" <MenuItem noClose icon="Duplicate" on:click={duplicateComponent}
on:click={moveUpComponent} >Duplicate</MenuItem
/> >
<DropdownItem <MenuItem icon="Cut" on:click={() => storeComponentForCopy(true)}
icon="ri-arrow-down-line" >Cut</MenuItem
title="Move down" >
on:click={moveDownComponent} <MenuItem icon="Copy" on:click={() => storeComponentForCopy(false)}
/> >Copy</MenuItem
<DropdownItem >
icon="ri-repeat-one-line" <MenuItem
title="Duplicate" icon="LayersBringToFront"
on:click={duplicateComponent} on:click={() => pasteComponent("above")}
/> disabled={noPaste}>Paste above</MenuItem
<DropdownItem >
icon="ri-scissors-cut-line" <MenuItem
title="Cut" icon="LayersSendToBack"
on:click={() => storeComponentForCopy(true)} on:click={() => pasteComponent("below")}
/> disabled={noPaste}>Paste below</MenuItem
<DropdownItem >
icon="ri-file-copy-line" <MenuItem
title="Copy" icon="ShowOneLayer"
on:click={() => storeComponentForCopy(false)} on:click={() => pasteComponent("inside")}
/> disabled={noPaste || noChildrenAllowed}>Paste inside</MenuItem
<hr class="hr-style" /> >
<DropdownItem </ActionMenu>
icon="ri-insert-row-top"
title="Paste above"
disabled={noPaste}
on:click={() => pasteComponent("above")}
/>
<DropdownItem
icon="ri-insert-row-bottom"
title="Paste below"
disabled={noPaste}
on:click={() => pasteComponent("below")}
/>
<DropdownItem
icon="ri-insert-column-right"
title="Paste inside"
disabled={noPaste || noChildrenAllowed}
on:click={() => pasteComponent("inside")}
/>
</DropdownContainer>
</Popover>
</div>
<ConfirmDialog <ConfirmDialog
bind:this={confirmDeleteDialog} bind:this={confirmDeleteDialog}
title="Confirm Deletion" title="Confirm Deletion"

View File

@ -2,16 +2,20 @@
import { store } from "builderStore" import { store } from "builderStore"
import { notifications } from "@budibase/bbui" import { notifications } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { Icon, Popover, Modal, ModalContent, Input } from "@budibase/bbui" import {
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" ActionMenu,
MenuItem,
Icon,
Modal,
ModalContent,
Input,
} from "@budibase/bbui"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
export let layout export let layout
let confirmDeleteDialog let confirmDeleteDialog
let editLayoutNameModal let editLayoutNameModal
let dropdown
let anchor
let name = layout.name let name = layout.name
const deleteLayout = async () => { const deleteLayout = async () => {
@ -35,25 +39,14 @@
} }
</script> </script>
<div bind:this={anchor}> <ActionMenu>
<div class="icon" on:click={() => dropdown.show()}> <div slot="control" class="icon">
<Icon name="MoreSmallList" /> <Icon s hoverable name="MoreSmallList" />
</div> </div>
<Popover bind:this={dropdown} {anchor} align="left"> <MenuItem icon="Edit" on:click={editLayoutNameModal.show}>Edit</MenuItem>
<DropdownContainer> <MenuItem icon="Delete" on:click={confirmDeleteDialog.show}>Delete</MenuItem>
<DropdownItem </ActionMenu>
icon="ri-pencil-line"
title="Edit"
on:click={() => editLayoutNameModal.show()}
/>
<DropdownItem
icon="ri-delete-bin-line"
title="Delete"
on:click={() => confirmDeleteDialog.show()}
/>
</DropdownContainer>
</Popover>
</div>
<ConfirmDialog <ConfirmDialog
bind:this={confirmDeleteDialog} bind:this={confirmDeleteDialog}
title="Confirm Deletion" title="Confirm Deletion"

View File

@ -1,16 +1,12 @@
<script> <script>
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { store, allScreens } from "builderStore" import { store, allScreens } from "builderStore"
import { notifications } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { Icon, Popover } from "@budibase/bbui" import { ActionMenu, MenuItem, Icon, notifications } from "@budibase/bbui"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
export let screenId export let screenId
let confirmDeleteDialog let confirmDeleteDialog
let dropdown
let anchor
$: screen = $allScreens.find((screen) => screen._id === screenId) $: screen = $allScreens.find((screen) => screen._id === screenId)
@ -27,20 +23,13 @@
} }
</script> </script>
<div bind:this={anchor} on:click|stopPropagation> <ActionMenu>
<div class="icon" on:click={() => dropdown.show()}> <div slot="control" class="icon">
<Icon s hoverable name="MoreSmallList" /> <Icon s hoverable name="MoreSmallList" />
</div> </div>
<Popover bind:this={dropdown} {anchor} align="left"> <MenuItem icon="Delete" on:click={confirmDeleteDialog.show}>Delete</MenuItem>
<DropdownContainer> </ActionMenu>
<DropdownItem
icon="ri-delete-bin-line"
title="Delete"
on:click={() => confirmDeleteDialog.show()}
/>
</DropdownContainer>
</Popover>
</div>
<ConfirmDialog <ConfirmDialog
bind:this={confirmDeleteDialog} bind:this={confirmDeleteDialog}
title="Confirm Deletion" title="Confirm Deletion"
@ -48,9 +37,3 @@
okText="Delete Screen" okText="Delete Screen"
onOk={deleteScreen} onOk={deleteScreen}
/> />
<style>
.icon i {
font-size: 16px;
}
</style>

View File

@ -70,6 +70,7 @@
bindings={bindableProperties} bindings={bindableProperties}
on:change={event => updateFieldValue(idx, event.detail)} /> on:change={event => updateFieldValue(idx, event.detail)} />
<ActionButton <ActionButton
s
quiet quiet
icon="Delete" icon="Delete"
on:click={() => removeField(field[0])} /> on:click={() => removeField(field[0])} />

View File

@ -52,22 +52,32 @@
placeholder="Parameter Name" placeholder="Parameter Name"
thin thin
disabled={bindable} disabled={bindable}
bind:value={parameter.name} /> bind:value={parameter.name}
/>
<Input <Input
placeholder="Default" placeholder="Default"
thin thin
disabled={bindable} disabled={bindable}
bind:value={parameter.default} /> bind:value={parameter.default}
/>
{#if bindable} {#if bindable}
<DrawerBindableInput <DrawerBindableInput
title={`Query parameter "${parameter.name}"`} title={`Query parameter "${parameter.name}"`}
placeholder="Value" placeholder="Value"
thin thin
on:change={evt => onBindingChange(parameter.name, evt.detail)} on:change={(evt) => onBindingChange(parameter.name, evt.detail)}
value={runtimeToReadableBinding(bindings, customParams?.[parameter.name])} value={runtimeToReadableBinding(
{bindings} /> bindings,
customParams?.[parameter.name]
)}
{bindings}
/>
{:else} {:else}
<Icon hoverable name="Close" on:click={() => deleteQueryParameter(idx)} /> <Icon
hoverable
name="Close"
on:click={() => deleteQueryParameter(idx)}
/>
{/if} {/if}
{/each} {/each}
</div> </div>
@ -90,16 +100,5 @@
grid-template-columns: 1fr 1fr 5%; grid-template-columns: 1fr 1fr 5%;
grid-gap: 10px; grid-gap: 10px;
align-items: center; align-items: center;
margin-bottom: var(--spacing-xl);
}
.delete {
transition: all 0.2s;
}
.delete:hover {
transform: scale(1.1);
font-weight: 500;
cursor: pointer;
} }
</style> </style>

View File

@ -6,6 +6,7 @@
Button, Button,
Body, Body,
Label, Label,
Layout,
Input, Input,
Heading, Heading,
Spacer, Spacer,
@ -110,46 +111,33 @@
} }
</script> </script>
<section class="config"> <Layout gap="S" noPadding>
<Spacer extraLarge />
<Heading m>Query {integrationInfo?.friendlyName}</Heading> <Heading m>Query {integrationInfo?.friendlyName}</Heading>
<Spacer extraLarge />
<Divider /> <Divider />
<Spacer extraLarge />
<Heading s>Config</Heading> <Heading s>Config</Heading>
<Body s>Provide a name for your query and select its function.</Body> <div class="config">
<Spacer medium />
<div class="config-field">
<Label>Query Name</Label>
<Input bind:value={query.name} />
</div>
<Spacer medium />
{#if queryConfig}
<div class="config-field"> <div class="config-field">
<Label>Function</Label> <Label>Query Name</Label>
<Select <Input bind:value={query.name} />
bind:value={query.queryVerb}
options={Object.keys(queryConfig)}
getOptionLabel={(verb) =>
queryConfig[verb]?.displayName || capitalise(verb)}
/>
</div> </div>
<Spacer extraLarge /> {#if queryConfig}
<div class="config-field">
<Label>Function</Label>
<Select
bind:value={query.queryVerb}
options={Object.keys(queryConfig)}
getOptionLabel={(verb) =>
queryConfig[verb]?.displayName || capitalise(verb)}
/>
</div>
<ParameterBuilder bind:parameters={query.parameters} bindable={false} />
{/if}
</div>
{#if shouldShowQueryConfig}
<Divider /> <Divider />
<Spacer extraLarge />
<ParameterBuilder bind:parameters={query.parameters} bindable={false} />
<Spacer extraLarge />
<Divider />
{/if}
</section>
{#if shouldShowQueryConfig}
<section>
<Spacer extraLarge />
<div class="config"> <div class="config">
<Heading s>Fields</Heading> <Heading s>Fields</Heading>
<Body s>Fill in the fields specific to this query.</Body> <Body s>Fill in the fields specific to this query.</Body>
<Spacer medium />
<IntegrationQueryEditor <IntegrationQueryEditor
{datasource} {datasource}
{query} {query}
@ -157,30 +145,27 @@
schema={queryConfig[query.queryVerb]} schema={queryConfig[query.queryVerb]}
bind:parameters bind:parameters
/> />
<Spacer extraLarge />
<Divider /> <Divider />
<Spacer extraLarge /> </div>
<div class="viewer-controls"> <div class="viewer-controls">
<Heading s>Results</Heading> <Heading s>Results</Heading>
<div class="button-container"> <div class="button-container">
<Button <Button
secondary secondary
thin thin
disabled={data.length === 0 || !query.name} disabled={data.length === 0 || !query.name}
on:click={saveQuery} on:click={saveQuery}
> >
Save Query Save Query
</Button> </Button>
<Spacer medium /> <Spacer medium />
<Button thin secondary on:click={previewQuery}>Run Query</Button> <Button thin secondary on:click={previewQuery}>Run Query</Button>
</div>
</div> </div>
<Spacer small /> </div>
<Body s> <Body s>
Below, you can preview the results from your query and change the Below, you can preview the results from your query and change the
schema. schema.
</Body> </Body>
<Spacer medium />
<section class="viewer"> <section class="viewer">
{#if data} {#if data}
<Tabs selected="JSON"> <Tabs selected="JSON">
@ -213,12 +198,14 @@
</Tabs> </Tabs>
{/if} {/if}
</section> </section>
</div> {/if}
</section> </Layout>
{/if}
<Spacer extraLarge />
<style> <style>
.config {
display: grid;
grid-gap: var(--spacing-s);
}
.config-field { .config-field {
display: grid; display: grid;
grid-template-columns: 20% 1fr; grid-template-columns: 20% 1fr;
@ -236,10 +223,6 @@
display: flex; display: flex;
} }
.config {
margin-bottom: var(--spacing-s);
}
.delete { .delete {
align-self: center; align-self: center;
cursor: pointer; cursor: pointer;

View File

@ -29,7 +29,7 @@
<Heading s>{name}</Heading> <Heading s>{name}</Heading>
<Spacer medium /> <Spacer medium />
<div class="card-footer" data-cy={`app-${name}`}> <div class="card-footer" data-cy={`app-${name}`}>
<ActionButton text medium blue on:click={() => $goto(`/builder/${_id}`)}> <ActionButton on:click={() => $goto(`/builder/${_id}`)}>
Open Open
{name} {name}