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 { 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,8 +89,9 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
{#if dataLoaded}
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<CreateRowButton />
|
<CreateRowButton {_bb} {model} />
|
||||||
{#if selectedRows.length > 0}
|
{#if selectedRows.length > 0}
|
||||||
<DeleteButton text small on:click={deleteRecords}>
|
<DeleteButton text small on:click={deleteRecords}>
|
||||||
<Icon name="addrow" />
|
<Icon name="addrow" />
|
||||||
|
@ -97,7 +99,6 @@
|
||||||
</DeleteButton>
|
</DeleteButton>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if dataLoaded}
|
|
||||||
<AgGrid
|
<AgGrid
|
||||||
{data}
|
{data}
|
||||||
{columnDefs}
|
{columnDefs}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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