Add common collapsed button group and use it for row actions and client button groups. Add collapsed settings to grids and form blocks

This commit is contained in:
Andrew Kingston 2024-09-02 11:44:49 +01:00
parent d8b6d10dce
commit 51cbced119
No known key found for this signature in database
8 changed files with 123 additions and 85 deletions

View File

@ -0,0 +1,39 @@
<script>
import Button from "../Button/Button.svelte"
import Popover from "../Popover/Popover.svelte"
import Menu from "../Menu/Menu.svelte"
import MenuItem from "../Menu/Item.svelte"
export let buttons
export let text = "Action"
export let size = "M"
export let align = "left"
export let offset
let anchor
let popover
const handleClick = async button => {
popover.hide()
await button.onClick?.()
}
</script>
<Button
bind:ref={anchor}
{size}
icon="ChevronDown"
cta
on:click={() => popover?.show()}
>
{text || "Action"}
</Button>
<Popover bind:this={popover} {align} {anchor} {offset}>
<Menu>
{#each buttons as button}
<MenuItem on:click={() => handleClick(button)} disabled={button.disabled}>
{button.text || "Button"}
</MenuItem>
{/each}
</Menu>
</Popover>

View File

@ -39,6 +39,7 @@ export { default as ActionGroup } from "./ActionGroup/ActionGroup.svelte"
export { default as ActionMenu } from "./ActionMenu/ActionMenu.svelte"
export { default as Button } from "./Button/Button.svelte"
export { default as ButtonGroup } from "./ButtonGroup/ButtonGroup.svelte"
export { default as CollapsedButtonGroup } from "./ButtonGroup/CollapsedButtonGroup.svelte"
export { default as ClearButton } from "./ClearButton/ClearButton.svelte"
export { default as Icon } from "./Icon/Icon.svelte"
export { default as IconAvatar } from "./Icon/IconAvatar.svelte"

View File

@ -30,10 +30,6 @@
let rowActions = []
let generateButton
let rowActionPopover
let rowActionRow
let rowActionAnchor
let refreshRow
$: autoColumnStatus = verifyAutocolumns($tables?.selected)
$: duplicates = Object.values(autoColumnStatus).reduce((acc, status) => {
@ -58,21 +54,22 @@
$: relationshipsEnabled = relationshipSupport(tableDatasource)
$: currentTheme = $themeStore?.theme
$: darkMode = !currentTheme.includes("light")
$: buttons = [
{
text: "Action",
type: "cta",
icon: "ChevronDown",
onClick: async (e, row, refresh) => {
rowActionRow = row
rowActionAnchor = e.currentTarget
rowActionPopover.show()
refreshRow = refresh
},
},
]
$: buttons = makeRowActionButtons(rowActions)
$: fetchRowActions(id)
const makeRowActionButtons = rowActions => {
return rowActions.map(action => ({
text: action.name,
onClick: async row => {
await API.rowActions.trigger({
rowActionId: action.id,
tableId: id,
rowId: row._id,
})
},
}))
}
const relationshipSupport = datasource => {
const integration = $integrations[datasource?.source]
return !isInternal && integration?.relationships !== false
@ -110,16 +107,6 @@
const res = await API.rowActions.fetch(tableId)
rowActions = Object.values(res || {})
}
const runRowAction = async action => {
await API.rowActions.trigger({
rowActionId: action.id,
tableId: id,
rowId: rowActionRow._id,
})
await refreshRow()
rowActionPopover.hide()
}
</script>
{#if $tables?.selected?.name}
@ -143,7 +130,8 @@
schemaOverrides={isUsersTable ? userSchemaOverrides : null}
showAvatars={false}
isCloud={$admin.cloud}
buttons={rowActions.length ? buttons : null}
{buttons}
buttonsCollapsed
on:updatedatasource={handleGridTableUpdate}
>
<!-- Controls -->
@ -192,19 +180,6 @@
<i>Create your first table to start building</i>
{/if}
<Popover
bind:this={rowActionPopover}
align="right"
anchor={rowActionAnchor}
offset={5}
>
<Menu>
{#each rowActions as action}
<MenuItem on:click={() => runRowAction(action)}>{action.name}</MenuItem>
{/each}
</Menu>
</Popover>
<style>
i {
font-size: var(--font-size-m);

View File

@ -7591,6 +7591,18 @@
"key": "row"
}
]
},
{
"type": "boolean",
"label": "Collapse",
"key": "buttonsCollapsed"
},
{
"type": "text",
"label": "Collapsed text",
"key": "buttonsCollapsedText",
"dependsOn": "buttonsCollapsed",
"placeholder": "Action"
}
]
}

View File

@ -1,7 +1,13 @@
<script>
import BlockComponent from "../BlockComponent.svelte"
import Block from "../Block.svelte"
import { Button, Popover, Menu, MenuItem } from "@budibase/bbui"
import {
Button,
Popover,
Menu,
MenuItem,
CollapsedButtonGroup,
} from "@budibase/bbui"
import { getContext } from "svelte"
export let buttons = []
@ -16,39 +22,26 @@
const component = getContext("component")
const context = getContext("context")
let popover
let anchor
$: collapsedButtons = collapsed ? makeCollapsed(buttons) : null
const handleCollapsedClick = async button => {
const fn = enrichButtonActions(button.onClick, $context)
await fn?.()
popover.hide()
const makeCollapsed = buttons => {
return buttons.map(button => ({
...button,
onClick: async () => {
const fn = enrichButtonActions(button.onClick, $context)
await fn?.()
},
}))
}
</script>
{#if collapsed}
<div use:styleable={$component.styles}>
<Button
bind:ref={anchor}
on:click={() => popover?.show()}
icon="ChevronDown"
cta
>
{collapsedText || "Action"}
</Button>
<CollapsedButtonGroup
text={collapsedText || "Action"}
buttons={collapsedButtons}
/>
</div>
<Popover bind:this={popover} align="left" {anchor}>
<Menu>
{#each buttons as button}
<MenuItem
on:click={() => handleCollapsedClick(button)}
disabled={button.disabled}
>
{button.text || "Button"}
</MenuItem>
{/each}
</Menu>
</Popover>
{:else}
<Block>
<BlockComponent

View File

@ -19,6 +19,8 @@
export let columns = null
export let onRowClick = null
export let buttons = null
export let buttonsCollapsed = false
export let buttonsCollapsedText = null
const context = getContext("context")
const component = getContext("component")
@ -115,15 +117,13 @@
text: settings.text,
type: settings.type,
icon: settings.icon,
onClick: async (_, row, refresh) => {
onClick: async row => {
// Create a fake, ephemeral context to run the buttons actions with
const id = get(component).id
const gridContext = createContextStore(context)
gridContext.actions.provideData(id, row)
const fn = enrichButtonActions(settings.onClick, get(gridContext))
const res = await fn?.({ row })
await refresh()
return res
return await fn?.({ row })
},
}))
}
@ -183,6 +183,8 @@
notifySuccess={notificationStore.actions.success}
notifyError={notificationStore.actions.error}
buttons={enrichedButtons}
{buttonsCollapsed}
{buttonsCollapsedText}
isCloud={$environmentStore.cloud}
on:rowclick={e => onRowClick?.({ row: e.detail })}
/>

View File

@ -4,6 +4,7 @@
import GridCell from "../cells/GridCell.svelte"
import GridScrollWrapper from "./GridScrollWrapper.svelte"
import { BlankRowID } from "../lib/constants"
import CollapsedButtonGroup from "../../../../../bbui/src/ButtonGroup/CollapsedButtonGroup.svelte"
const {
renderedRows,
@ -34,12 +35,16 @@
$: gridEnd = $width - $buttonColumnWidth - 1
$: left = Math.min(columnEnd, gridEnd)
const handleClick = async (e, button, row) => {
await button.onClick?.(
e,
rows.actions.cleanRow(row),
async () => await rows.actions.refreshRow(row._id)
)
const handleClick = async (button, row) => {
await button.onClick?.(rows.actions.cleanRow(row))
await rows.actions.refreshRow(row._id)
}
const makeCollapsedButtons = (buttons, row) => {
return buttons.map(button => ({
...button,
onClick: () => handleClick(button, row),
}))
}
onMount(() => {
@ -80,26 +85,33 @@
class="buttons"
class:offset={$showVScrollbar && $showHScrollbar}
>
{#each buttons as button}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span on:click={e => handleClick(e, button, row)}>
{#if $props.buttonsCollapsed}
<CollapsedButtonGroup
buttons={makeCollapsedButtons(buttons, row)}
text={$props.buttonsCollapsedText || "Action"}
align="right"
offset={5}
size="S"
/>
{:else}
{#each buttons as button}
<Button
newStyles
size="S"
icon={button.icon}
cta={button.type === "cta"}
primary={button.type === "primary"}
secondary={button.type === "secondary"}
warning={button.type === "warning"}
overBackground={button.type === "overBackground"}
on:click={() => handleClick(button, row)}
>
{#if button.icon}
<i class="{button.icon} S" />
{/if}
{button.text || "Button"}
</Button>
</span>
{/each}
{/each}
{/if}
</div>
</GridCell>
</div>

View File

@ -43,7 +43,9 @@
export let notifySuccess = null
export let notifyError = null
export let buttons = null
export let darkMode
export let buttonsCollapsed = false
export let buttonsCollapsedText = null
export let darkMode = false
export let isCloud = null
export let rowConditions = null
@ -98,6 +100,8 @@
notifySuccess,
notifyError,
buttons,
buttonsCollapsed,
buttonsCollapsedText,
darkMode,
isCloud,
rowConditions,