budibase/packages/builder/src/components/backend/DataTable/Table.svelte

242 lines
5.7 KiB
Svelte

<script>
import { fade } from "svelte/transition"
import { goto, params } from "@roxi/routify"
import { Table, Modal, Heading, notifications, Layout } from "@budibase/bbui"
import { API } from "api"
import Spinner from "components/common/Spinner.svelte"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import DeleteRowsButton from "./buttons/DeleteRowsButton.svelte"
import CreateEditRow from "./modals/CreateEditRow.svelte"
import CreateEditUser from "./modals/CreateEditUser.svelte"
import CreateEditColumn from "./modals/CreateEditColumn.svelte"
import { cloneDeep } from "lodash/fp"
import {
TableNames,
UNEDITABLE_USER_FIELDS,
UNSORTABLE_TYPES,
} from "constants"
import RoleCell from "./cells/RoleCell.svelte"
export let schema = {}
export let data = []
export let tableId
export let title
export let allowEditing = false
export let loading = false
export let hideAutocolumns
export let rowCount
export let type
export let disableSorting = false
export let customPlaceholder = false
let selectedRows = []
let editableColumn
let editableRow
let editRowModal
let editColumnModal
let customRenderers = []
let confirmDelete
$: isUsersTable = tableId === TableNames.USERS
$: data && resetSelectedRows()
$: editRowComponent = isUsersTable ? CreateEditUser : CreateEditRow
$: {
UNSORTABLE_TYPES.forEach(type => {
Object.values(schema || {}).forEach(col => {
if (col.type === type) {
col.sortable = false
}
})
})
}
$: {
if (isUsersTable) {
customRenderers = [
{
column: "roleId",
component: RoleCell,
},
]
UNEDITABLE_USER_FIELDS.forEach(field => {
if (schema[field]) {
schema[field].editable = false
}
})
if (schema.email) {
schema.email.displayName = "Email"
}
if (schema.roleId) {
schema.roleId.displayName = "Role"
}
if (schema.firstName) {
schema.firstName.displayName = "First Name"
}
if (schema.lastName) {
schema.lastName.displayName = "Last Name"
}
if (schema.status) {
schema.status.displayName = "Status"
}
}
}
const resetSelectedRows = () => {
selectedRows = []
}
const selectRelationship = ({ tableId, rowId, fieldName }) => {
$goto(
`/builder/app/${$params.application}/data/table/${tableId}/relationship/${rowId}/${fieldName}`
)
}
const deleteRows = async targetRows => {
try {
await API.deleteRows({
tableId,
rows: targetRows,
})
const deletedRowIds = targetRows.map(row => row._id)
data = data.filter(row => deletedRowIds.indexOf(row._id))
notifications.success(`Successfully deleted ${targetRows.length} rows`)
} catch (error) {
notifications.error("Error deleting rows")
}
}
const editRow = row => {
editableRow = row
if (row) {
editRowModal.show()
}
}
const editColumn = field => {
editableColumn = cloneDeep(schema?.[field])
if (editableColumn) {
editColumnModal.show()
}
}
</script>
<Layout noPadding gap="S">
<Layout noPadding gap="XS">
{#if title}
<div class="table-title">
<Heading size="M">{title}</Heading>
{#if loading}
<div transition:fade|local>
<Spinner size="10" />
</div>
{/if}
</div>
{/if}
<div class="popovers">
<slot />
{#if !isUsersTable && selectedRows.length > 0}
<DeleteRowsButton
on:updaterows
{selectedRows}
deleteRows={async rows => {
await deleteRows(rows)
resetSelectedRows()
}}
/>
{/if}
</div>
</Layout>
{#key tableId}
<div class="table-wrapper">
<Table
{data}
{schema}
{loading}
{customRenderers}
{rowCount}
{disableSorting}
{customPlaceholder}
bind:selectedRows
allowSelectRows={allowEditing && !isUsersTable}
allowEditRows={allowEditing}
allowEditColumns={allowEditing}
showAutoColumns={!hideAutocolumns}
on:editcolumn={e => editColumn(e.detail)}
on:editrow={e => editRow(e.detail)}
on:clickrelationship={e => selectRelationship(e.detail)}
on:sort
>
<slot slot="placeholder" name="placeholder" />
</Table>
</div>
{/key}
</Layout>
<Modal bind:this={editRowModal}>
<svelte:component
this={editRowComponent}
on:updaterows
on:deleteRows={() => {
confirmDelete.show()
}}
row={editableRow}
/>
</Modal>
<ConfirmDialog
bind:this={confirmDelete}
okText="Delete"
onOk={async () => {
if (editableRow) {
await deleteRows([editableRow])
}
editableRow = undefined
}}
onCancel={async () => {
editRow(editableRow)
}}
title="Confirm Deletion"
>
Are you sure you want to delete this row?
</ConfirmDialog>
<Modal bind:this={editColumnModal}>
<CreateEditColumn
field={editableColumn}
on:updatecolumns
onClosed={editColumnModal.hide}
/>
</Modal>
<style>
.table-title {
height: 24px;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.table-title > div {
margin-left: var(--spacing-xs);
}
.table-wrapper {
overflow: hidden;
}
.popovers {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: var(--spacing-s);
}
.popovers :global(button) {
font-weight: 600;
margin-top: var(--spacing-l);
}
.popovers :global(button svg) {
margin-right: var(--spacing-xs);
}
</style>