adds add row functionality to grid component
This commit is contained in:
parent
09a26a286a
commit
193f536834
|
@ -12,7 +12,6 @@
|
|||
import { onMount } from "svelte"
|
||||
|
||||
import AgGrid from "@budibase/svelte-ag-grid"
|
||||
import InputForm from "./InputForm.svelte"
|
||||
import CreateRowButton from "./CreateRow/Button.svelte"
|
||||
import { TextButton as DeleteButton, Icon } from "@budibase/bbui"
|
||||
|
||||
|
@ -23,10 +22,12 @@
|
|||
let data
|
||||
let columnDefs
|
||||
let selectedRows = []
|
||||
let model
|
||||
|
||||
onMount(async () => {
|
||||
const jsonModel = await _bb.api.get(`/api/models/${datasource.modelId}`)
|
||||
const { schema } = await jsonModel.json()
|
||||
model = await jsonModel.json()
|
||||
const { schema } = model
|
||||
if (!isEmpty(datasource)) {
|
||||
data = await fetchData(datasource)
|
||||
columnDefs = Object.keys(schema).map((key, i) => {
|
||||
|
@ -34,7 +35,7 @@
|
|||
headerCheckboxSelection: i === 0,
|
||||
checkboxSelection: i === 0,
|
||||
valueSetter: setters.get(schema[key].type),
|
||||
headerName: key.charAt(0).toUpperCase() + key.slice(1), // Capitalise first letter
|
||||
headerName: key.charAt(0).toUpperCase() + key.slice(1),
|
||||
field: key,
|
||||
hide: shouldHideField(key),
|
||||
sortable: true,
|
||||
|
@ -88,16 +89,16 @@
|
|||
</script>
|
||||
|
||||
<div class="container">
|
||||
<div class="controls">
|
||||
<CreateRowButton />
|
||||
{#if selectedRows.length > 0}
|
||||
<DeleteButton text small on:click={deleteRecords}>
|
||||
<Icon name="addrow" />
|
||||
Delete {selectedRows.length} row(s)
|
||||
</DeleteButton>
|
||||
{/if}
|
||||
</div>
|
||||
{#if dataLoaded}
|
||||
<div class="controls">
|
||||
<CreateRowButton {_bb} {model} />
|
||||
{#if selectedRows.length > 0}
|
||||
<DeleteButton text small on:click={deleteRecords}>
|
||||
<Icon name="addrow" />
|
||||
Delete {selectedRows.length} row(s)
|
||||
</DeleteButton>
|
||||
{/if}
|
||||
</div>
|
||||
<AgGrid
|
||||
{data}
|
||||
{columnDefs}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
<script>
|
||||
import { DropdownMenu, TextButton as Button, Icon } from "@budibase/bbui"
|
||||
// import CreateEditRecord from "../modals/CreateEditRecord.svelte"
|
||||
import Modal from "./Modal.svelte"
|
||||
|
||||
let anchor
|
||||
let dropdown
|
||||
|
||||
export let _bb, model
|
||||
</script>
|
||||
|
||||
<div bind:this={anchor}>
|
||||
|
@ -14,8 +16,7 @@
|
|||
</div>
|
||||
<DropdownMenu bind:this={dropdown} {anchor} align="left">
|
||||
<h5>Add New Row</h5>
|
||||
popup goes here!
|
||||
<!-- <CreateEditRecord onClosed={dropdown.hide} /> -->
|
||||
<Modal {_bb} {model} onClosed={dropdown.hide} />
|
||||
</DropdownMenu>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import { fade } from "svelte/transition"
|
||||
import { Button, Label, DatePicker } from "@budibase/bbui"
|
||||
import Dropzone from "../../attachments/Dropzone.svelte"
|
||||
import debounce from "lodash.debounce"
|
||||
|
||||
const DEFAULTS_FOR_TYPE = {
|
||||
string: "",
|
||||
boolean: false,
|
||||
number: null,
|
||||
link: [],
|
||||
}
|
||||
|
||||
export let _bb
|
||||
export let model
|
||||
export let onClosed
|
||||
|
||||
let record = { modelId: model._id }
|
||||
let store = _bb.store
|
||||
let schema = model.schema
|
||||
let saved = false
|
||||
let recordId
|
||||
let isNew = true
|
||||
let errors = {}
|
||||
|
||||
$: fields = schema ? Object.keys(schema) : []
|
||||
|
||||
$: errorMessages = Object.entries(errors).map(
|
||||
([field, message]) => `${field} ${message}`
|
||||
)
|
||||
|
||||
const save = debounce(async () => {
|
||||
for (let field of fields) {
|
||||
// Assign defaults to empty fields to prevent validation issues
|
||||
if (!(field in record)) {
|
||||
record[field] = DEFAULTS_FOR_TYPE[schema[field].type]
|
||||
}
|
||||
}
|
||||
|
||||
const SAVE_RECORD_URL = `/api/${model._id}/records`
|
||||
const response = await _bb.api.post(SAVE_RECORD_URL, record)
|
||||
|
||||
const json = await response.json()
|
||||
|
||||
console.log(json)
|
||||
|
||||
if (response.status === 200) {
|
||||
store.update(state => {
|
||||
state[model._id] = state[model._id]
|
||||
? [...state[model._id], json]
|
||||
: [json]
|
||||
return state
|
||||
})
|
||||
|
||||
errors = {}
|
||||
|
||||
// wipe form, if new record, otherwise update
|
||||
// model to get new _rev
|
||||
record = isNew ? { modelId: model._id } : json
|
||||
|
||||
onClosed()
|
||||
}
|
||||
|
||||
if (response.status === 400) {
|
||||
errors = json.errors
|
||||
}
|
||||
})
|
||||
|
||||
onMount(async () => {
|
||||
const routeParams = _bb.routeParams()
|
||||
recordId =
|
||||
Object.keys(routeParams).length > 0 && (routeParams.id || routeParams[0])
|
||||
isNew = !recordId || recordId === "new"
|
||||
|
||||
if (isNew) {
|
||||
record = { modelId: model }
|
||||
return
|
||||
}
|
||||
|
||||
const GET_RECORD_URL = `/api/${model._id}/records/${recordId}`
|
||||
const response = await _bb.api.get(GET_RECORD_URL)
|
||||
const json = await response.json()
|
||||
record = json
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="actions">
|
||||
{#each errorMessages as error}
|
||||
<p class="error">{error}</p>
|
||||
{/each}
|
||||
<form on:submit|preventDefault>
|
||||
{#each fields as field}
|
||||
<div class="form-item">
|
||||
<Label small forAttr={'form-stacked-text'}>{field}</Label>
|
||||
{#if schema[field].type === 'string' && schema[field].constraints.inclusion}
|
||||
<select bind:value={record[field]}>
|
||||
{#each schema[field].constraints.inclusion as opt}
|
||||
<option>{opt}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{:else if schema[field].type === 'datetime'}
|
||||
<DatePicker bind:value={record[field]} />
|
||||
{:else if schema[field].type === 'boolean'}
|
||||
<input class="input" type="checkbox" bind:checked={record[field]} />
|
||||
{:else if schema[field].type === 'number'}
|
||||
<input class="input" type="number" bind:value={record[field]} />
|
||||
{:else if schema[field].type === 'string'}
|
||||
<input class="input" type="text" bind:value={record[field]} />
|
||||
{:else if schema[field].type === 'attachment'}
|
||||
<Dropzone bind:files={record[field]} />
|
||||
{/if}
|
||||
</div>
|
||||
<hr />
|
||||
{/each}
|
||||
</form>
|
||||
</div>
|
||||
<footer>
|
||||
<div class="button-margin-3">
|
||||
<Button secondary on:click={onClosed}>Cancel</Button>
|
||||
</div>
|
||||
<div class="button-margin-4">
|
||||
<Button primary on:click={save}>Save</Button>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
.actions {
|
||||
padding: var(--spacing-l) var(--spacing-xl);
|
||||
}
|
||||
|
||||
footer {
|
||||
padding: 20px 30px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
gap: 20px;
|
||||
background: var(--grey-1);
|
||||
border-bottom-left-radius: 0.5rem;
|
||||
border-bottom-left-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.button-margin-3 {
|
||||
grid-column-start: 3;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.button-margin-4 {
|
||||
grid-column-start: 4;
|
||||
display: grid;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue