bulk delete, delete column from panel

This commit is contained in:
Martin McKeaveney 2020-10-27 13:04:32 +00:00
parent 9df48c6de7
commit 50f21e61ff
17 changed files with 183 additions and 58 deletions

Binary file not shown.

Binary file not shown.

View File

@ -77,6 +77,7 @@
"lodash": "^4.17.13", "lodash": "^4.17.13",
"mustache": "^4.0.1", "mustache": "^4.0.1",
"posthog-js": "1.4.5", "posthog-js": "1.4.5",
"remixicon": "^2.5.0",
"shortid": "^2.2.15", "shortid": "^2.2.15",
"svelte-loading-spinners": "^0.1.1", "svelte-loading-spinners": "^0.1.1",
"svelte-portal": "^0.1.0", "svelte-portal": "^0.1.0",

View File

@ -178,6 +178,10 @@ export default {
src: "node_modules/@budibase/bbui/dist/bbui.css", src: "node_modules/@budibase/bbui/dist/bbui.css",
dest: outputpath, dest: outputpath,
}, },
{
src: "node_modules/remixicon/fonts/*",
dest: outputpath,
},
], ],
}), }),

View File

@ -12,6 +12,7 @@
$: title = $backendUiStore.selectedTable.name $: title = $backendUiStore.selectedTable.name
$: schema = $backendUiStore.selectedTable.schema $: schema = $backendUiStore.selectedTable.schema
$: tableId = $backendUiStore.selectedTable._id
$: tableView = { $: tableView = {
schema, schema,
name: $backendUiStore.selectedView.name, name: $backendUiStore.selectedView.name,

View File

@ -1,29 +1,39 @@
<script> <script>
import { fade } from "svelte/transition" import { fade } from "svelte/transition"
import { Button } from "@budibase/bbui"
import { goto, params } from "@sveltech/routify" import { goto, params } from "@sveltech/routify"
import Spinner from "components/common/Spinner.svelte"
import AgGrid from "@budibase/svelte-ag-grid" import AgGrid from "@budibase/svelte-ag-grid"
import { getRenderer, editRowRenderer } from "./cells/cellRenderers"
import api from "builderStore/api"
import { notifier } from "builderStore/store/notifications"
import Spinner from "components/common/Spinner.svelte"
import DeleteRowsButton from "./buttons/DeleteRowsButton.svelte"
import {
getRenderer,
editRowRenderer,
deleteRowRenderer,
} from "./cells/cellRenderers"
import TableLoadingOverlay from "./TableLoadingOverlay" import TableLoadingOverlay from "./TableLoadingOverlay"
import TableHeader from "./TableHeader" import TableHeader from "./TableHeader"
import "@budibase/svelte-ag-grid/dist/index.css" import "@budibase/svelte-ag-grid/dist/index.css"
export let schema = {} export let schema = {}
export let data = [] export let data = []
export let tableId
export let title export let title
export let allowEditing = false export let allowEditing = false
export let loading = false export let loading = false
export let theme = "alpine" export let theme = "alpine"
let columnDefs = [] let columnDefs = []
let selectedRows = []
let options = { let options = {
defaultColDef: { defaultColDef: {
flex: 1, flex: 1,
filter: true, filter: true,
}, },
rowSelection: true, rowSelection: allowEditing ? "multiple" : false,
rowMultiSelectWithClick: true, rowMultiSelectWithClick: true,
suppressRowClickSelection: false, suppressRowClickSelection: false,
paginationAutoPageSize: true, paginationAutoPageSize: true,
@ -39,21 +49,34 @@
$: { $: {
let result = [] let result = []
if (allowEditing) { if (allowEditing) {
result.push({ result = [
pinned: "left", {
headerName: "Edit", pinned: "left",
sortable: false, headerName: "Edit",
resizable: false, sortable: false,
suppressMovable: true, resizable: false,
suppressMenu: true, suppressMovable: true,
minWidth: 75, suppressMenu: true,
width: 75, minWidth: 100,
cellRenderer: editRowRenderer, width: 100,
}) cellRenderer: editRowRenderer,
},
{
headerName: "",
checkboxSelection: true,
sortable: false,
resizable: false,
suppressMovable: true,
suppressMenu: true,
minWidth: 50,
width: 50,
},
]
} }
for (let key in schema) { for (let key in schema) {
result.push({ result.push({
headerCheckboxSelection: false,
headerComponent: TableHeader, headerComponent: TableHeader,
headerComponentParams: { headerComponentParams: {
field: schema[key], field: schema[key],
@ -83,6 +106,16 @@
`/${$params.application}/data/table/${row.tableId}/relationship/${row._id}/${fieldName}` `/${$params.application}/data/table/${row.tableId}/relationship/${row._id}/${fieldName}`
) )
} }
const deleteRows = async () => {
const response = await api.post(`/api/${tableId}/rows`, {
rows: selectedRows,
type: "delete",
})
data = data.filter(row => !selectedRows.includes(row))
notifier.success(`Successfully deleted ${selectedRows.length} rows`)
selectedRows = []
}
</script> </script>
<section> <section>
@ -90,9 +123,19 @@
<h2 class="title"><span>{title}</span></h2> <h2 class="title"><span>{title}</span></h2>
<div class="popovers"> <div class="popovers">
<slot /> <slot />
{#if selectedRows.length > 0}
<DeleteRowsButton {selectedRows} {deleteRows} />
{/if}
</div> </div>
</div> </div>
<AgGrid {theme} {options} {data} {columnDefs} {loading} /> <AgGrid
{theme}
{options}
{data}
{columnDefs}
{loading}
on:select={({ detail }) => (selectedRows = detail)} />
/>
</section> </section>
<style> <style>
@ -164,7 +207,7 @@
:global(.ag-menu input) { :global(.ag-menu input) {
color: var(--ink) !important; color: var(--ink) !important;
font-size: var(--font-size-s); font-size: var(--font-size-xs);
border-radius: var(--border-radius-s) !important; border-radius: var(--border-radius-s) !important;
border: none; border: none;
background-color: var(--grey-2) !important; background-color: var(--grey-2) !important;
@ -181,7 +224,7 @@
:global(.ag-picker-field-display) { :global(.ag-picker-field-display) {
color: var(--ink) !important; color: var(--ink) !important;
font-size: var(--font-size-s) !important; font-size: var(--font-size-xs) !important;
border-radius: var(--border-radius-s) !important; border-radius: var(--border-radius-s) !important;
background-color: var(--grey-2) !important; background-color: var(--grey-2) !important;
font-family: var(--font-sans); font-family: var(--font-sans);
@ -191,6 +234,7 @@
:global(.ag-picker-field-wrapper) { :global(.ag-picker-field-wrapper) {
background: var(--grey-2) !important; background: var(--grey-2) !important;
border: var(--border-transparent) !important; border: var(--border-transparent) !important;
padding: var(--spacing-xs); padding-top: var(--spacing-xs);
padding-bottom: var(--spacing-xs);
} }
</style> </style>

View File

@ -42,9 +42,7 @@
<header on:click={onSort} data-cy="table-header"> <header on:click={onSort} data-cy="table-header">
<div> <div>
<span>{displayName}</span> <span>{displayName}</span>
{#if enableSorting && sortDirection} <i class={`${SORT_ICON_MAP[sortDirection]} sort-icon`} />
<i class={`${SORT_ICON_MAP[sortDirection]} sort-icon`} />
{/if}
</div> </div>
<Modal bind:this={modal}> <Modal bind:this={modal}>
<ModalContent <ModalContent

View File

@ -0,0 +1,34 @@
<script>
import { TextButton, Icon, Modal, ModalContent } from "@budibase/bbui"
import CreateEditRowModal from "../modals/CreateEditRowModal.svelte"
export let selectedRows
export let deleteRows
let modal
async function confirmDeletion() {
await deleteRows()
modal.hide()
}
</script>
<div>
<TextButton small text on:click={modal.show}>
<Icon name="delete" />
Delete
{selectedRows.length}
row(s)
</TextButton>
</div>
<Modal bind:this={modal}>
<ModalContent
red
confirmText="Delete"
onConfirm={confirmDeletion}
title="Confirm Row Deletion">
Are you sure you want to delete these
{selectedRows.length}
rows?
</ModalContent>
</Modal>

View File

@ -1,5 +1,6 @@
import AttachmentList from "./AttachmentCell.svelte" import AttachmentList from "./AttachmentCell.svelte"
import EditRowPopover from "../modals/EditRow.svelte" import EditRow from "../modals/EditRow.svelte"
import DeleteRow from "../modals/DeleteRow.svelte"
import RelationshipDisplay from "./RelationshipCell.svelte" import RelationshipDisplay from "./RelationshipCell.svelte"
const renderers = { const renderers = {
@ -15,10 +16,23 @@ export function getRenderer(schema, editable) {
} }
} }
export function deleteRowRenderer(params) {
const container = document.createElement("div")
new DeleteRow({
target: container,
props: {
row: params.data,
},
})
return container
}
export function editRowRenderer(params) { export function editRowRenderer(params) {
const container = document.createElement("div") const container = document.createElement("div")
new EditRowPopover({ new EditRow({
target: container, target: container,
props: { props: {
row: params.data, row: params.data,

View File

@ -24,6 +24,7 @@
$backendUiStore.selectedTable.primaryDisplay == null || $backendUiStore.selectedTable.primaryDisplay == null ||
$backendUiStore.selectedTable.primaryDisplay === field.name $backendUiStore.selectedTable.primaryDisplay === field.name
let confirmDeleteDialog let confirmDeleteDialog
let deletion
$: tableOptions = $backendUiStore.tables.filter( $: tableOptions = $backendUiStore.tables.filter(
table => table._id !== $backendUiStore.draftTable._id table => table._id !== $backendUiStore.draftTable._id
@ -47,8 +48,8 @@
notifier.danger("You cannot delete the display column") notifier.danger("You cannot delete the display column")
} else { } else {
backendUiStore.actions.tables.deleteField(field) backendUiStore.actions.tables.deleteField(field)
notifier.success("Column deleted") notifier.success(`Column ${field.name} deleted.`)
hideDeleteDialog() onClosed()
} }
} }
@ -76,15 +77,16 @@
function confirmDelete() { function confirmDelete() {
confirmDeleteDialog.show() confirmDeleteDialog.show()
onClosed() deletion = true
} }
function hideDeleteDialog() { function hideDeleteDialog() {
confirmDeleteDialog.hide() confirmDeleteDialog.hide()
deletion = false
} }
</script> </script>
<div class="actions"> <div class="actions" class:hidden={deletion}>
<Input label="Name" thin bind:value={field.name} /> <Input label="Name" thin bind:value={field.name} />
<Select <Select
@ -182,4 +184,8 @@
justify-content: flex-end; justify-content: flex-end;
gap: var(--spacing-m); gap: var(--spacing-m);
} }
.hidden {
display: none;
}
</style> </style>

View File

@ -0,0 +1,42 @@
<script>
import { backendUiStore } from "builderStore"
import { DropdownMenu, Icon, Modal } from "@budibase/bbui"
import * as api from "../api"
import { notifier } from "builderStore/store/notifications"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
export let row
let anchor
let dropdown
let confirmDeleteDialog
function showDelete() {
confirmDeleteDialog.show()
}
async function deleteRow() {
await api.deleteRow(row)
notifier.success("Row deleted")
backendUiStore.actions.rows.delete(row)
}
</script>
<div on:click={showDelete}><i class="ri-delete-row" /></div>
<ConfirmDialog
bind:this={confirmDeleteDialog}
body={`Are you sure you wish to delete this row? Your data will be deleted and this action cannot be undone.`}
okText="Delete Row"
onOk={deleteRow}
title="Confirm Delete" />
<style>
.ri-delete-bin-line:hover {
cursor: pointer;
}
div {
display: flex;
justify-content: center;
}
</style>

View File

@ -1,10 +1,7 @@
<script> <script>
import { backendUiStore } from "builderStore" import { backendUiStore } from "builderStore"
import { DropdownMenu, Icon, Modal } from "@budibase/bbui" import { DropdownMenu, Icon, Modal, Button } from "@budibase/bbui"
import CreateEditRowModal from "../modals/CreateEditRowModal.svelte" import CreateEditRowModal from "../modals/CreateEditRowModal.svelte"
import * as api from "../api"
import { notifier } from "builderStore/store/notifications"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
export let row export let row
@ -13,34 +10,13 @@
let confirmDeleteDialog let confirmDeleteDialog
let modal let modal
function showModal() { function showModal(e) {
e.stopPropagation()
modal.show() modal.show()
} }
function showDelete() {
confirmDeleteDialog.show()
}
async function deleteRow() {
await api.deleteRow(row)
notifier.success("Row deleted")
backendUiStore.actions.rows.delete(row)
}
</script> </script>
<div on:click={showModal}><i class="ri-more-line" /></div> <Button translucent small on:click={showModal}>Edit</Button>
<ConfirmDialog
bind:this={confirmDeleteDialog}
body={`Are you sure you wish to delete this row? Your data will be deleted and this action cannot be undone.`}
okText="Delete Row"
onOk={deleteRow}
title="Confirm Delete" />
<Modal bind:this={modal}> <Modal bind:this={modal}>
<CreateEditRowModal {row} /> <CreateEditRowModal {row} />
</Modal> </Modal>
<style>
.ri-more-line:hover {
cursor: pointer;
}
</style>

View File

@ -7,8 +7,6 @@
<title>Budibase Builder</title> <title>Budibase Builder</title>
<link href="https://cdn.jsdelivr.net/npm/remixicon@2.3.0/fonts/remixicon.css" rel="stylesheet">
<link rel='icon' type='image/png' href='/_builder/favicon.png'> <link rel='icon' type='image/png' href='/_builder/favicon.png'>
<link rel='stylesheet' href='/_builder/bundle.css'> <link rel='stylesheet' href='/_builder/bundle.css'>
<link rel='stylesheet' href='/_builder/external.css'> <link rel='stylesheet' href='/_builder/external.css'>

View File

@ -10,6 +10,8 @@ import "/assets/Inter-ExtraBold"
import "/assets/Inter-Black" import "/assets/Inter-Black"
import "/_builder/assets/budibase-logo.png" import "/_builder/assets/budibase-logo.png"
import "/_builder/assets/budibase-logo-only.png" import "/_builder/assets/budibase-logo-only.png"
import "remixicon/fonts/remixicon.css"
import App from "./App.svelte" import App from "./App.svelte"
/* eslint-disable */ /* eslint-disable */

View File

@ -5310,6 +5310,11 @@ regjsparser@^0.6.4:
dependencies: dependencies:
jsesc "~0.5.0" jsesc "~0.5.0"
remixicon@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/remixicon/-/remixicon-2.5.0.tgz#b5e245894a1550aa23793f95daceadbf96ad1a41"
integrity sha512-q54ra2QutYDZpuSnFjmeagmEiN9IMo56/zz5dDNitzKD23oFRw77cWo4TsrAdmdkPiEn8mxlrTqxnkujDbEGww==
remove-trailing-separator@^1.0.1: remove-trailing-separator@^1.0.1:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"

Binary file not shown.

Binary file not shown.