1
0
Fork 0
mirror of synced 2024-06-01 18:20:18 +12:00
budibase/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte

264 lines
7.3 KiB
Svelte
Raw Normal View History

2020-08-08 03:13:57 +12:00
<script>
2021-02-10 07:49:12 +13:00
import {
Input,
Button,
Label,
TextButton,
Select,
Toggle,
} from "@budibase/bbui"
2020-10-24 11:55:51 +13:00
import { cloneDeep } from "lodash/fp"
import { backendUiStore } from "builderStore"
2020-11-25 03:04:14 +13:00
import { TableNames, UNEDITABLE_USER_FIELDS } from "constants"
2021-02-17 05:38:36 +13:00
import { FIELDS, AUTO_COLUMN_SUB_TYPES } from "constants/backend"
import { getAutoColumnInformation, buildAutoColumn } from "builderStore/utils"
2020-08-08 03:13:57 +12:00
import { notifier } from "builderStore/store/notifications"
import ValuesList from "components/common/ValuesList.svelte"
import DatePicker from "components/common/DatePicker.svelte"
2020-10-24 05:38:10 +13:00
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
2020-08-08 03:13:57 +12:00
const AUTO_COL = "auto"
let fieldDefinitions = cloneDeep(FIELDS)
2020-08-08 03:13:57 +12:00
export let onClosed
export let field = {
type: "string",
constraints: fieldDefinitions.STRING.constraints,
// Initial value for column name in other table for linked records
fieldName: $backendUiStore.selectedTable.name,
}
2020-08-08 03:13:57 +12:00
2020-08-11 02:34:37 +12:00
let originalName = field.name
let primaryDisplay =
$backendUiStore.selectedTable.primaryDisplay == null ||
$backendUiStore.selectedTable.primaryDisplay === field.name
2021-02-10 07:49:12 +13:00
let indexes = [...($backendUiStore.selectedTable.indexes || [])]
2020-10-24 05:38:10 +13:00
let confirmDeleteDialog
2020-10-28 02:04:32 +13:00
let deletion
2020-10-24 05:38:10 +13:00
$: tableOptions = $backendUiStore.tables.filter(
table => table._id !== $backendUiStore.draftTable._id
)
$: required = !!field?.constraints?.presence || primaryDisplay
$: uneditable =
$backendUiStore.selectedTable?._id === TableNames.USERS &&
UNEDITABLE_USER_FIELDS.includes(field.name)
2020-08-08 04:41:20 +12:00
// used to select what different options can be displayed for column type
2021-02-16 08:59:49 +13:00
$: canBeSearched =
field.type !== "link" &&
field.subtype !== AUTO_COLUMN_SUB_TYPES.CREATED_BY &&
field.subtype !== AUTO_COLUMN_SUB_TYPES.UPDATED_BY
$: canBeDisplay = field.type !== "link" && field.type !== AUTO_COL
$: canBeRequired =
field.type !== "link" && !uneditable && field.type !== AUTO_COL
2020-08-08 03:13:57 +12:00
async function saveColumn() {
if (field.type === AUTO_COL) {
2021-02-16 08:59:49 +13:00
field = buildAutoColumn(
$backendUiStore.draftTable.name,
field.name,
field.subtype
)
}
2020-08-08 04:41:20 +12:00
backendUiStore.update(state => {
backendUiStore.actions.tables.saveField({
2020-08-08 04:41:20 +12:00
originalName,
2020-08-11 22:23:07 +12:00
field,
primaryDisplay,
2021-02-10 07:49:12 +13:00
indexes,
2020-08-08 04:41:20 +12:00
})
return state
2020-08-08 03:13:57 +12:00
})
onClosed()
}
2020-10-24 05:38:10 +13:00
function deleteColumn() {
if (field.name === $backendUiStore.selectedTable.primaryDisplay) {
notifier.danger("You cannot delete the display column")
} else {
backendUiStore.actions.tables.deleteField(field)
2020-10-28 02:04:32 +13:00
notifier.success(`Column ${field.name} deleted.`)
onClosed()
2020-10-24 05:38:10 +13:00
}
}
function handleFieldConstraints(event) {
2021-02-16 08:59:49 +13:00
const definition = fieldDefinitions[event.target.value.toUpperCase()]
if (!definition) {
return
}
field.type = definition.type
field.constraints = definition.constraints
}
function onChangeRequired(e) {
const req = e.target.checked
field.constraints.presence = req ? { allowEmpty: false } : false
required = req
}
function onChangePrimaryDisplay(e) {
const isPrimary = e.target.checked
// primary display is always required
if (isPrimary) {
field.constraints.presence = { allowEmpty: false }
}
}
2020-10-24 05:38:10 +13:00
2021-02-10 07:49:12 +13:00
function onChangePrimaryIndex(e) {
2021-02-10 07:57:32 +13:00
indexes = e.target.checked ? [field.name] : []
2021-02-10 07:49:12 +13:00
}
2021-02-02 10:02:54 +13:00
2021-02-10 07:49:12 +13:00
function onChangeSecondaryIndex(e) {
2021-02-10 07:57:32 +13:00
if (e.target.checked) {
2021-02-10 07:49:12 +13:00
indexes[1] = field.name
} else {
2021-02-10 07:57:32 +13:00
indexes = indexes.slice(0, 1)
2021-02-10 07:49:12 +13:00
}
2021-02-02 10:02:54 +13:00
}
2020-10-24 05:38:10 +13:00
function confirmDelete() {
confirmDeleteDialog.show()
2020-10-28 02:04:32 +13:00
deletion = true
2020-10-24 11:55:51 +13:00
}
function hideDeleteDialog() {
confirmDeleteDialog.hide()
2020-10-28 02:04:32 +13:00
deletion = false
2020-10-24 05:38:10 +13:00
}
2020-08-08 03:13:57 +12:00
</script>
2020-10-28 02:04:32 +13:00
<div class="actions" class:hidden={deletion}>
2020-11-25 03:04:14 +13:00
<Input label="Name" thin bind:value={field.name} disabled={uneditable} />
2020-08-08 03:13:57 +12:00
<Select
disabled={originalName}
secondary
thin
label="Type"
on:change={handleFieldConstraints}
bind:value={field.type}>
{#each Object.values(fieldDefinitions) as field}
<option value={field.type}>{field.name}</option>
{/each}
<option value={AUTO_COL}>Auto Column</option>
</Select>
2020-08-08 03:13:57 +12:00
{#if canBeRequired}
<Toggle
checked={required}
on:change={onChangeRequired}
disabled={primaryDisplay}
thin
text="Required" />
{/if}
2020-08-08 03:13:57 +12:00
{#if canBeDisplay}
<Toggle
bind:checked={primaryDisplay}
on:change={onChangePrimaryDisplay}
thin
text="Use as table display column" />
2021-02-10 07:49:12 +13:00
2021-02-11 11:23:27 +13:00
<Label grey small>Search Indexes</Label>
{/if}
{#if canBeSearched}
2021-02-10 07:49:12 +13:00
<Toggle
checked={indexes[0] === field.name}
disabled={indexes[1] === field.name}
on:change={onChangePrimaryIndex}
thin
text="Primary" />
2021-02-02 10:02:54 +13:00
<Toggle
2021-02-10 07:49:12 +13:00
checked={indexes[1] === field.name}
disabled={!indexes[0] || indexes[0] === field.name}
on:change={onChangeSecondaryIndex}
2021-02-02 10:02:54 +13:00
thin
2021-02-10 07:49:12 +13:00
text="Secondary" />
{/if}
{#if field.type === 'string'}
<Input
thin
type="number"
label="Max Length"
bind:value={field.constraints.length.maximum} />
{:else if field.type === 'options'}
<ValuesList
label="Options (one per line)"
bind:values={field.constraints.inclusion} />
{:else if field.type === 'datetime'}
<DatePicker
label="Earliest"
bind:value={field.constraints.datetime.earliest} />
<DatePicker label="Latest" bind:value={field.constraints.datetime.latest} />
{:else if field.type === 'number'}
<Input
thin
type="number"
label="Min Value"
bind:value={field.constraints.numericality.greaterThanOrEqualTo} />
<Input
thin
type="number"
label="Max Value"
bind:value={field.constraints.numericality.lessThanOrEqualTo} />
{:else if field.type === 'link'}
<Select label="Table" thin secondary bind:value={field.tableId}>
<option value="">Choose an option</option>
{#each tableOptions as table}
<option value={table._id}>{table.name}</option>
{/each}
</Select>
<Input
label={`Column Name in Other Table`}
thin
bind:value={field.fieldName} />
{:else if field.type === AUTO_COL}
<Select label="Auto Column Type" thin secondary bind:value={field.subtype}>
<option value="">Choose a subtype</option>
{#each Object.entries(getAutoColumnInformation()) as [subtype, info]}
<option value={subtype}>{info.name}</option>
{/each}
</Select>
{/if}
2020-10-28 11:57:05 +13:00
<footer class="create-column-options">
{#if !uneditable && originalName != null}
2020-10-28 11:57:05 +13:00
<TextButton text on:click={confirmDelete}>Delete Column</TextButton>
2020-10-24 05:38:10 +13:00
{/if}
2020-10-28 11:57:05 +13:00
<Button secondary on:click={onClosed}>Cancel</Button>
2020-08-08 03:13:57 +12:00
<Button primary on:click={saveColumn}>Save Column</Button>
2020-10-24 05:38:10 +13:00
</footer>
</div>
2020-10-24 05:38:10 +13:00
<ConfirmDialog
bind:this={confirmDeleteDialog}
body={`Are you sure you wish to delete this column? Your data will be deleted and this action cannot be undone.`}
okText="Delete Column"
onOk={deleteColumn}
2020-10-24 11:55:51 +13:00
onCancel={hideDeleteDialog}
title="Confirm Deletion" />
2020-08-08 03:13:57 +12:00
<style>
.actions {
2020-08-08 03:13:57 +12:00
display: grid;
grid-gap: var(--spacing-xl);
min-width: 400px;
2020-08-08 03:13:57 +12:00
}
footer {
display: flex;
justify-content: flex-end;
gap: var(--spacing-m);
2020-08-08 03:13:57 +12:00
}
2020-10-28 02:04:32 +13:00
2020-10-28 11:57:05 +13:00
:global(.create-column-options button:first-child) {
margin-right: auto;
}
2020-10-28 02:04:32 +13:00
.hidden {
display: none;
}
2020-08-08 03:13:57 +12:00
</style>