Merge pull request #10491 from Budibase/more-grid-tweaks
Grid improvements and fixes
This commit is contained in:
commit
687d3a9267
|
@ -1,4 +1,8 @@
|
|||
const ignoredClasses = [".flatpickr-calendar", ".spectrum-Popover"]
|
||||
const ignoredClasses = [
|
||||
".flatpickr-calendar",
|
||||
".spectrum-Popover",
|
||||
".download-js-link",
|
||||
]
|
||||
let clickHandlers = []
|
||||
|
||||
/**
|
||||
|
@ -22,8 +26,8 @@ const handleClick = event => {
|
|||
}
|
||||
|
||||
// Ignore clicks for modals, unless the handler is registered from a modal
|
||||
const sourceInModal = handler.anchor.closest(".spectrum-Modal") != null
|
||||
const clickInModal = event.target.closest(".spectrum-Modal") != null
|
||||
const sourceInModal = handler.anchor.closest(".spectrum-Underlay") != null
|
||||
const clickInModal = event.target.closest(".spectrum-Underlay") != null
|
||||
if (clickInModal && !sourceInModal) {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
{#if datasource}
|
||||
<div>
|
||||
<ActionButton icon="DataCorrelated" primary quiet on:click={modal.show}>
|
||||
Define existing relationship
|
||||
Define relationship
|
||||
</ActionButton>
|
||||
</div>
|
||||
<Modal bind:this={modal}>
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
$: selectedRowArray = Object.keys($selectedRows).map(id => ({ _id: id }))
|
||||
</script>
|
||||
|
||||
<ExportButton
|
||||
<span data-ignore-click-outside="true">
|
||||
<ExportButton
|
||||
{disabled}
|
||||
view={$tableId}
|
||||
filters={$filter}
|
||||
|
@ -18,4 +19,11 @@
|
|||
sortOrder: $sort.order,
|
||||
}}
|
||||
selectedRows={selectedRowArray}
|
||||
/>
|
||||
/>
|
||||
</span>
|
||||
|
||||
<style>
|
||||
span {
|
||||
display: contents;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,19 +2,19 @@
|
|||
import TableFilterButton from "../TableFilterButton.svelte"
|
||||
import { getContext } from "svelte"
|
||||
|
||||
const { columns, config, filter, table } = getContext("grid")
|
||||
const { columns, tableId, filter, table } = getContext("grid")
|
||||
|
||||
const onFilter = e => {
|
||||
filter.set(e.detail || [])
|
||||
}
|
||||
</script>
|
||||
|
||||
{#key $config.tableId}
|
||||
{#key $tableId}
|
||||
<TableFilterButton
|
||||
schema={$table?.schema}
|
||||
filters={$filter}
|
||||
on:change={onFilter}
|
||||
disabled={!$columns.length}
|
||||
tableId={$config.tableId}
|
||||
tableId={$tableId}
|
||||
/>
|
||||
{/key}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import ManageAccessButton from "../ManageAccessButton.svelte"
|
||||
import { getContext } from "svelte"
|
||||
|
||||
const { config } = getContext("grid")
|
||||
const { tableId } = getContext("grid")
|
||||
</script>
|
||||
|
||||
<ManageAccessButton resourceId={$config.tableId} />
|
||||
<ManageAccessButton resourceId={$tableId} />
|
||||
|
|
|
@ -70,7 +70,15 @@
|
|||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if $config.allowExpandRows}
|
||||
{#if rowSelected && $config.allowDeleteRows}
|
||||
<div class="delete" on:click={() => dispatch("request-bulk-delete")}>
|
||||
<Icon
|
||||
name="Delete"
|
||||
size="S"
|
||||
color="var(--spectrum-global-color-red-400)"
|
||||
/>
|
||||
</div>
|
||||
{:else if $config.allowExpandRows}
|
||||
<div
|
||||
class="expand"
|
||||
class:visible={!disableExpand && (rowFocused || rowHovered)}
|
||||
|
@ -111,9 +119,12 @@
|
|||
.number.visible {
|
||||
display: flex;
|
||||
}
|
||||
.delete,
|
||||
.expand {
|
||||
margin-right: 4px;
|
||||
}
|
||||
.expand {
|
||||
opacity: 0;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.expand :global(.spectrum-Icon) {
|
||||
pointer-events: none;
|
||||
|
@ -124,4 +135,11 @@
|
|||
.expand.visible :global(.spectrum-Icon) {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.delete:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
.delete:hover :global(.spectrum-Icon) {
|
||||
color: var(--spectrum-global-color-red-600) !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<script>
|
||||
import { Modal, ModalContent, Button, notifications } from "@budibase/bbui"
|
||||
import { Modal, ModalContent, notifications } from "@budibase/bbui"
|
||||
import { getContext, onMount } from "svelte"
|
||||
|
||||
const { selectedRows, rows, config, subscribe } = getContext("grid")
|
||||
const { selectedRows, rows, subscribe } = getContext("grid")
|
||||
|
||||
let modal
|
||||
|
||||
|
@ -27,20 +27,6 @@
|
|||
onMount(() => subscribe("request-bulk-delete", () => modal?.show()))
|
||||
</script>
|
||||
|
||||
{#if selectedRowCount}
|
||||
<div class="delete-button" data-ignore-click-outside="true">
|
||||
<Button
|
||||
icon="Delete"
|
||||
size="M"
|
||||
on:click={modal.show}
|
||||
disabled={!$config.allowEditRows}
|
||||
cta
|
||||
>
|
||||
Delete {selectedRowCount} row{selectedRowCount === 1 ? "" : "s"}
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<Modal bind:this={modal}>
|
||||
<ModalContent
|
||||
title="Delete rows"
|
||||
|
@ -53,14 +39,3 @@
|
|||
row{selectedRowCount === 1 ? "" : "s"}?
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
.delete-button :global(.spectrum-Button:not(:disabled)) {
|
||||
background-color: var(--spectrum-global-color-red-400);
|
||||
border-color: var(--spectrum-global-color-red-400);
|
||||
}
|
||||
.delete-button :global(.spectrum-Button:not(:disabled):hover) {
|
||||
background-color: var(--spectrum-global-color-red-500);
|
||||
border-color: var(--spectrum-global-color-red-500);
|
||||
}
|
||||
</style>
|
|
@ -3,7 +3,7 @@
|
|||
import { ActionButton, Popover } from "@budibase/bbui"
|
||||
import { DefaultColumnWidth } from "../lib/constants"
|
||||
|
||||
const { stickyColumn, columns } = getContext("grid")
|
||||
const { stickyColumn, columns, compact } = getContext("grid")
|
||||
const smallSize = 120
|
||||
const mediumSize = DefaultColumnWidth
|
||||
const largeSize = DefaultColumnWidth * 1.5
|
||||
|
@ -59,12 +59,13 @@
|
|||
on:click={() => (open = !open)}
|
||||
selected={open}
|
||||
disabled={!allCols.length}
|
||||
tooltip={$compact ? "Width" : null}
|
||||
>
|
||||
Width
|
||||
{$compact ? "" : "Width"}
|
||||
</ActionButton>
|
||||
</div>
|
||||
|
||||
<Popover bind:open {anchor} align="left">
|
||||
<Popover bind:open {anchor} align={$compact ? "right" : "left"}>
|
||||
<div class="content">
|
||||
{#each sizeOptions as option}
|
||||
<ActionButton
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import { ActionButton, Popover, Toggle } from "@budibase/bbui"
|
||||
import { ActionButton, Popover, Toggle, Icon } from "@budibase/bbui"
|
||||
import { getColumnIcon } from "../lib/utils"
|
||||
|
||||
const { columns, stickyColumn } = getContext("grid")
|
||||
const { columns, stickyColumn, compact } = getContext("grid")
|
||||
|
||||
let open = false
|
||||
let anchor
|
||||
|
@ -47,25 +48,32 @@
|
|||
on:click={() => (open = !open)}
|
||||
selected={open || anyHidden}
|
||||
disabled={!$columns.length}
|
||||
tooltip={$compact ? "Columns" : ""}
|
||||
>
|
||||
Columns
|
||||
{$compact ? "" : "Columns"}
|
||||
</ActionButton>
|
||||
</div>
|
||||
|
||||
<Popover bind:open {anchor} align="left">
|
||||
<Popover bind:open {anchor} align={$compact ? "right" : "left"}>
|
||||
<div class="content">
|
||||
<div class="columns">
|
||||
{#if $stickyColumn}
|
||||
<div class="column">
|
||||
<Icon size="S" name={getColumnIcon($stickyColumn)} />
|
||||
{$stickyColumn.label}
|
||||
</div>
|
||||
<Toggle disabled size="S" value={true} />
|
||||
<span>{$stickyColumn.label}</span>
|
||||
{/if}
|
||||
{#each $columns as column}
|
||||
<div class="column">
|
||||
<Icon size="S" name={getColumnIcon(column)} />
|
||||
{column.label}
|
||||
</div>
|
||||
<Toggle
|
||||
size="S"
|
||||
value={column.visible}
|
||||
on:change={e => toggleVisibility(column, e.detail)}
|
||||
/>
|
||||
<span>{column.label}</span>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="buttons">
|
||||
|
@ -90,6 +98,13 @@
|
|||
.columns {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
.columns :global(.spectrum-Switch) {
|
||||
margin-right: 0;
|
||||
}
|
||||
.column {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
SmallRowHeight,
|
||||
} from "../lib/constants"
|
||||
|
||||
const { rowHeight, columns, table } = getContext("grid")
|
||||
const { rowHeight, columns, table, compact } = getContext("grid")
|
||||
const sizeOptions = [
|
||||
{
|
||||
label: "Small",
|
||||
|
@ -41,12 +41,13 @@
|
|||
size="M"
|
||||
on:click={() => (open = !open)}
|
||||
selected={open}
|
||||
tooltip={$compact ? "Height" : null}
|
||||
>
|
||||
Height
|
||||
{$compact ? "" : "Height"}
|
||||
</ActionButton>
|
||||
</div>
|
||||
|
||||
<Popover bind:open {anchor} align="left">
|
||||
<Popover bind:open {anchor} align={$compact ? "right" : "left"}>
|
||||
<div class="content">
|
||||
{#each sizeOptions as option}
|
||||
<ActionButton
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { getContext } from "svelte"
|
||||
import { ActionButton, Popover, Select } from "@budibase/bbui"
|
||||
|
||||
const { sort, columns, stickyColumn } = getContext("grid")
|
||||
const { sort, columns, stickyColumn, compact } = getContext("grid")
|
||||
|
||||
let open = false
|
||||
let anchor
|
||||
|
@ -90,12 +90,13 @@
|
|||
on:click={() => (open = !open)}
|
||||
selected={open}
|
||||
disabled={!columnOptions.length}
|
||||
tooltip={$compact ? "Sort" : ""}
|
||||
>
|
||||
Sort
|
||||
{$compact ? "" : "Sort"}
|
||||
</ActionButton>
|
||||
</div>
|
||||
|
||||
<Popover bind:open {anchor} align="left">
|
||||
<Popover bind:open {anchor} align={$compact ? "right" : "left"}>
|
||||
<div class="content">
|
||||
<Select
|
||||
placeholder={null}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import { createEventManagers } from "../lib/events"
|
||||
import { createAPIClient } from "../../../api"
|
||||
import { attachStores } from "../stores"
|
||||
import DeleteButton from "../controls/DeleteButton.svelte"
|
||||
import BulkDeleteHandler from "../controls/BulkDeleteHandler.svelte"
|
||||
import BetaButton from "../controls/BetaButton.svelte"
|
||||
import GridBody from "./GridBody.svelte"
|
||||
import ResizeOverlay from "../overlays/ResizeOverlay.svelte"
|
||||
|
@ -112,13 +112,12 @@
|
|||
<AddRowButton />
|
||||
<AddColumnButton />
|
||||
<slot name="controls" />
|
||||
<SortButton />
|
||||
<HideColumnsButton />
|
||||
<ColumnWidthButton />
|
||||
<RowHeightButton />
|
||||
<HideColumnsButton />
|
||||
<SortButton />
|
||||
</div>
|
||||
<div class="controls-right">
|
||||
<DeleteButton />
|
||||
<UserAvatars />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -131,7 +130,9 @@
|
|||
<GridBody />
|
||||
</div>
|
||||
<BetaButton />
|
||||
{#if allowAddRows}
|
||||
<NewRow />
|
||||
{/if}
|
||||
<div class="overlays">
|
||||
<ResizeOverlay />
|
||||
<ReorderOverlay />
|
||||
|
@ -146,6 +147,9 @@
|
|||
<ProgressCircle />
|
||||
</div>
|
||||
{/if}
|
||||
{#if allowDeleteRows}
|
||||
<BulkDeleteHandler />
|
||||
{/if}
|
||||
<KeyboardManager />
|
||||
</div>
|
||||
|
||||
|
@ -214,6 +218,7 @@
|
|||
padding: var(--cell-padding);
|
||||
gap: var(--cell-spacing);
|
||||
background: var(--background);
|
||||
z-index: 2;
|
||||
}
|
||||
.controls-left,
|
||||
.controls-right {
|
||||
|
@ -239,7 +244,7 @@
|
|||
height: 100%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
z-index: 10;
|
||||
z-index: 100;
|
||||
}
|
||||
.grid-loading:before {
|
||||
content: "";
|
||||
|
|
|
@ -4,8 +4,14 @@
|
|||
import HeaderCell from "../cells/HeaderCell.svelte"
|
||||
import { Icon } from "@budibase/bbui"
|
||||
|
||||
const { renderedColumns, dispatch, scroll, hiddenColumnsWidth, width } =
|
||||
getContext("grid")
|
||||
const {
|
||||
renderedColumns,
|
||||
dispatch,
|
||||
scroll,
|
||||
hiddenColumnsWidth,
|
||||
width,
|
||||
config,
|
||||
} = getContext("grid")
|
||||
|
||||
$: columnsWidth = $renderedColumns.reduce(
|
||||
(total, col) => (total += col.width),
|
||||
|
@ -23,6 +29,7 @@
|
|||
{/each}
|
||||
</div>
|
||||
</GridScrollWrapper>
|
||||
{#if $config.allowAddColumns}
|
||||
<div
|
||||
class="add"
|
||||
style="left:{left}px"
|
||||
|
@ -30,6 +37,7 @@
|
|||
>
|
||||
<Icon name="Add" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
@ -38,7 +46,6 @@
|
|||
border-bottom: var(--cell-border);
|
||||
position: relative;
|
||||
height: var(--default-row-height);
|
||||
z-index: 1;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
|
@ -54,6 +61,7 @@
|
|||
border-right: var(--cell-border);
|
||||
border-bottom: var(--cell-border);
|
||||
background: var(--spectrum-global-color-gray-100);
|
||||
z-index: 20;
|
||||
}
|
||||
.add:hover {
|
||||
background: var(--spectrum-global-color-gray-200);
|
||||
|
|
|
@ -270,7 +270,7 @@
|
|||
z-index: 3;
|
||||
position: absolute;
|
||||
top: calc(var(--row-height) + var(--offset) + 24px);
|
||||
left: var(--gutter-width);
|
||||
left: 18px;
|
||||
}
|
||||
.button-with-keys {
|
||||
display: flex;
|
||||
|
|
|
@ -21,6 +21,9 @@ const TypeIconMap = {
|
|||
}
|
||||
|
||||
export const getColumnIcon = column => {
|
||||
if (column.schema.autocolumn) {
|
||||
return "MagicWand"
|
||||
}
|
||||
const type = column.schema.type
|
||||
return TypeIconMap[type] || "Text"
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
clipboard,
|
||||
dispatch,
|
||||
selectedRows,
|
||||
config,
|
||||
} = getContext("grid")
|
||||
|
||||
const ignoredOriginSelectors = [
|
||||
|
@ -37,10 +38,12 @@
|
|||
e.preventDefault()
|
||||
focusFirstCell()
|
||||
} else if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
|
||||
if ($config.allowAddRows) {
|
||||
e.preventDefault()
|
||||
dispatch("add-row-inline")
|
||||
}
|
||||
} else if (e.key === "Delete" || e.key === "Backspace") {
|
||||
if (Object.keys($selectedRows).length) {
|
||||
if (Object.keys($selectedRows).length && $config.allowDeleteRows) {
|
||||
dispatch("request-bulk-delete")
|
||||
}
|
||||
}
|
||||
|
@ -88,8 +91,10 @@
|
|||
}
|
||||
break
|
||||
case "Enter":
|
||||
if ($config.allowAddRows) {
|
||||
dispatch("add-row-inline")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (e.key) {
|
||||
case "ArrowLeft":
|
||||
|
@ -106,7 +111,7 @@
|
|||
break
|
||||
case "Delete":
|
||||
case "Backspace":
|
||||
if (Object.keys($selectedRows).length) {
|
||||
if (Object.keys($selectedRows).length && $config.allowDeleteRows) {
|
||||
dispatch("request-bulk-delete")
|
||||
} else {
|
||||
deleteSelectedCell()
|
||||
|
@ -117,7 +122,9 @@
|
|||
break
|
||||
case " ":
|
||||
case "Space":
|
||||
if ($config.allowDeleteRows) {
|
||||
toggleSelectRow()
|
||||
}
|
||||
break
|
||||
default:
|
||||
startEnteringValue(e.key, e.which)
|
||||
|
|
|
@ -2,6 +2,7 @@ import { writable, get, derived } from "svelte/store"
|
|||
import { tick } from "svelte"
|
||||
import {
|
||||
DefaultRowHeight,
|
||||
GutterWidth,
|
||||
LargeRowHeight,
|
||||
MediumRowHeight,
|
||||
NewRowID,
|
||||
|
@ -43,6 +44,8 @@ export const deriveStores = context => {
|
|||
enrichedRows,
|
||||
rowLookupMap,
|
||||
rowHeight,
|
||||
stickyColumn,
|
||||
width,
|
||||
} = context
|
||||
|
||||
// Derive the row that contains the selected cell
|
||||
|
@ -70,6 +73,7 @@ export const deriveStores = context => {
|
|||
hoveredRowId.set(null)
|
||||
}
|
||||
|
||||
// Derive the amount of content lines to show in cells depending on row height
|
||||
const contentLines = derived(rowHeight, $rowHeight => {
|
||||
if ($rowHeight === LargeRowHeight) {
|
||||
return 3
|
||||
|
@ -79,9 +83,15 @@ export const deriveStores = context => {
|
|||
return 1
|
||||
})
|
||||
|
||||
// Derive whether we should use the compact UI, depending on width
|
||||
const compact = derived([stickyColumn, width], ([$stickyColumn, $width]) => {
|
||||
return ($stickyColumn?.width || 0) + $width + GutterWidth < 1100
|
||||
})
|
||||
|
||||
return {
|
||||
focusedRow,
|
||||
contentLines,
|
||||
compact,
|
||||
ui: {
|
||||
actions: {
|
||||
blur,
|
||||
|
|
Loading…
Reference in New Issue