Add button action for duplicating a row

This commit is contained in:
Andrew Kingston 2021-12-07 13:59:12 +00:00
parent 00179c8a33
commit d36daaf9b9
3 changed files with 179 additions and 0 deletions

View File

@ -0,0 +1,152 @@
<script>
import { Select, Label, Body, Checkbox, Input } from "@budibase/bbui"
import { store, currentAsset } from "builderStore"
import { tables } from "stores/backend"
import {
getContextProviderComponents,
getSchemaForDatasource,
} from "builderStore/dataBinding"
import SaveFields from "./SaveFields.svelte"
export let parameters
export let bindings = []
$: formComponents = getContextProviderComponents(
$currentAsset,
$store.selectedComponentId,
"form"
)
$: schemaComponents = getContextProviderComponents(
$currentAsset,
$store.selectedComponentId,
"schema"
)
$: providerOptions = getProviderOptions(formComponents, schemaComponents)
$: schemaFields = getSchemaFields($currentAsset, parameters?.tableId)
$: tableOptions = $tables.list || []
// Gets a context definition of a certain type from a component definition
const extractComponentContext = (component, contextType) => {
const def = store.actions.components.getDefinition(component?._component)
if (!def) {
return null
}
const contexts = Array.isArray(def.context) ? def.context : [def.context]
return contexts.find(context => context?.type === contextType)
}
// Gets options for valid context keys which provide valid data to submit
const getProviderOptions = (formComponents, schemaComponents) => {
const formContexts = formComponents.map(component => ({
component,
context: extractComponentContext(component, "form"),
}))
const schemaContexts = schemaComponents.map(component => ({
component,
context: extractComponentContext(component, "schema"),
}))
const allContexts = formContexts.concat(schemaContexts)
return allContexts.map(({ component, context }) => {
let runtimeBinding = component._id
if (context.suffix) {
runtimeBinding += `-${context.suffix}`
}
return {
label: component._instanceName,
value: runtimeBinding,
}
})
}
const getSchemaFields = (asset, tableId) => {
const { schema } = getSchemaForDatasource(asset, { type: "table", tableId })
delete schema._id
delete schema._rev
return Object.values(schema || {})
}
const onFieldsChanged = e => {
parameters.fields = e.detail
}
</script>
<div class="root">
<Body size="S">
Choose the data source that provides the row you would like to duplicate.
<br />
You can always add or override fields manually.
</Body>
<div class="params">
<Label small>Data Source</Label>
<Select
bind:value={parameters.providerId}
options={providerOptions}
placeholder="None"
/>
<Label small>Duplicate to Table</Label>
<Select
bind:value={parameters.tableId}
options={tableOptions}
getOptionLabel={option => option.name}
getOptionValue={option => option._id}
/>
<Label small />
<Checkbox text="Require confirmation" bind:value={parameters.confirm} />
{#if parameters.confirm}
<Label small>Confirm text</Label>
<Input
placeholder="Are you sure you want to duplicate this row?"
bind:value={parameters.confirmText}
/>
{/if}
</div>
{#if parameters.tableId}
<div class="fields">
<SaveFields
parameterFields={parameters.fields}
{schemaFields}
on:change={onFieldsChanged}
{bindings}
/>
</div>
{/if}
</div>
<style>
.root {
width: 100%;
max-width: 800px;
margin: 0 auto;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
gap: var(--spacing-xl);
}
.root :global(p) {
line-height: 1.5;
}
.params {
display: grid;
column-gap: var(--spacing-l);
row-gap: var(--spacing-s);
grid-template-columns: 100px 1fr;
align-items: center;
}
.fields {
display: grid;
column-gap: var(--spacing-l);
row-gap: var(--spacing-s);
grid-template-columns: 100px 1fr auto 1fr auto;
align-items: center;
}
</style>

View File

@ -13,6 +13,7 @@ import CloseScreenModal from "./CloseScreenModal.svelte"
import ChangeFormStep from "./ChangeFormStep.svelte"
import UpdateStateStep from "./UpdateState.svelte"
import RefreshDataProvider from "./RefreshDataProvider.svelte"
import DuplicateRow from "./DuplicateRow.svelte"
// Defines which actions are available to configure in the front end.
// Unfortunately the "name" property is used as the identifier so please don't
@ -27,6 +28,10 @@ export const getAvailableActions = () => {
name: "Save Row",
component: SaveRow,
},
{
name: "Duplicate Row",
component: DuplicateRow,
},
{
name: "Delete Row",
component: DeleteRow,

View File

@ -10,6 +10,25 @@ import { saveRow, deleteRow, executeQuery, triggerAutomation } from "api"
import { ActionTypes } from "constants"
const saveRowHandler = async (action, context) => {
const { fields, providerId, tableId } = action.parameters
let payload
if (providerId) {
payload = context[providerId]
} else {
payload = {}
}
if (fields) {
for (let [field, value] of Object.entries(fields)) {
payload[field] = value
}
}
if (tableId) {
payload.tableId = tableId
}
await saveRow(payload)
}
const duplicateRowHandler = async (action, context) => {
const { fields, providerId, tableId } = action.parameters
if (providerId) {
let draft = context[providerId]
@ -21,6 +40,8 @@ const saveRowHandler = async (action, context) => {
if (tableId) {
draft.tableId = tableId
}
delete draft._id
delete draft._rev
await saveRow(draft)
}
}
@ -120,6 +141,7 @@ const updateStateHandler = action => {
const handlerMap = {
["Save Row"]: saveRowHandler,
["Duplicate Row"]: duplicateRowHandler,
["Delete Row"]: deleteRowHandler,
["Navigate To"]: navigationHandler,
["Execute Query"]: queryExecutionHandler,