adds add row functionality to grid component

This commit is contained in:
kevmodrome 2020-10-02 09:43:56 +02:00
parent 09a26a286a
commit 193f536834
No known key found for this signature in database
GPG Key ID: E8F9CD141E63BF38
3 changed files with 168 additions and 15 deletions

View File

@ -12,7 +12,6 @@
import { onMount } from "svelte" import { onMount } from "svelte"
import AgGrid from "@budibase/svelte-ag-grid" import AgGrid from "@budibase/svelte-ag-grid"
import InputForm from "./InputForm.svelte"
import CreateRowButton from "./CreateRow/Button.svelte" import CreateRowButton from "./CreateRow/Button.svelte"
import { TextButton as DeleteButton, Icon } from "@budibase/bbui" import { TextButton as DeleteButton, Icon } from "@budibase/bbui"
@ -23,10 +22,12 @@
let data let data
let columnDefs let columnDefs
let selectedRows = [] let selectedRows = []
let model
onMount(async () => { onMount(async () => {
const jsonModel = await _bb.api.get(`/api/models/${datasource.modelId}`) 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)) { if (!isEmpty(datasource)) {
data = await fetchData(datasource) data = await fetchData(datasource)
columnDefs = Object.keys(schema).map((key, i) => { columnDefs = Object.keys(schema).map((key, i) => {
@ -34,7 +35,7 @@
headerCheckboxSelection: i === 0, headerCheckboxSelection: i === 0,
checkboxSelection: i === 0, checkboxSelection: i === 0,
valueSetter: setters.get(schema[key].type), 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, field: key,
hide: shouldHideField(key), hide: shouldHideField(key),
sortable: true, sortable: true,
@ -88,16 +89,16 @@
</script> </script>
<div class="container"> <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} {#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 <AgGrid
{data} {data}
{columnDefs} {columnDefs}

View File

@ -1,9 +1,11 @@
<script> <script>
import { DropdownMenu, TextButton as Button, Icon } from "@budibase/bbui" import { DropdownMenu, TextButton as Button, Icon } from "@budibase/bbui"
// import CreateEditRecord from "../modals/CreateEditRecord.svelte" import Modal from "./Modal.svelte"
let anchor let anchor
let dropdown let dropdown
export let _bb, model
</script> </script>
<div bind:this={anchor}> <div bind:this={anchor}>
@ -14,8 +16,7 @@
</div> </div>
<DropdownMenu bind:this={dropdown} {anchor} align="left"> <DropdownMenu bind:this={dropdown} {anchor} align="left">
<h5>Add New Row</h5> <h5>Add New Row</h5>
popup goes here! <Modal {_bb} {model} onClosed={dropdown.hide} />
<!-- <CreateEditRecord onClosed={dropdown.hide} /> -->
</DropdownMenu> </DropdownMenu>
<style> <style>

View File

@ -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>