Unify all popovers and modals to the same styles and reuse common components. Fix filter options
This commit is contained in:
parent
86b475fe14
commit
6320a85bc2
17 changed files with 263 additions and 372 deletions
|
@ -8,7 +8,7 @@
|
||||||
import LinkedRecord from "./LinkedRecord.svelte"
|
import LinkedRecord from "./LinkedRecord.svelte"
|
||||||
import AttachmentList from "./AttachmentList.svelte"
|
import AttachmentList from "./AttachmentList.svelte"
|
||||||
import TablePagination from "./TablePagination.svelte"
|
import TablePagination from "./TablePagination.svelte"
|
||||||
import { DeleteRecordModal, CreateEditRecordModal } from "./modals"
|
import { CreateEditRecordModal } from "./modals"
|
||||||
import RowPopover from "./popovers/Row.svelte"
|
import RowPopover from "./popovers/Row.svelte"
|
||||||
import ColumnPopover from "./popovers/Column.svelte"
|
import ColumnPopover from "./popovers/Column.svelte"
|
||||||
import ViewPopover from "./popovers/View.svelte"
|
import ViewPopover from "./popovers/View.svelte"
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
import AttachmentList from "./AttachmentList.svelte"
|
import AttachmentList from "./AttachmentList.svelte"
|
||||||
import TablePagination from "./TablePagination.svelte"
|
import TablePagination from "./TablePagination.svelte"
|
||||||
import { DeleteRecordModal, CreateEditRecordModal } from "./modals"
|
import { CreateEditRecordModal } from "./modals"
|
||||||
import RowPopover from "./popovers/Row.svelte"
|
import RowPopover from "./popovers/Row.svelte"
|
||||||
import ColumnPopover from "./popovers/Column.svelte"
|
import ColumnPopover from "./popovers/Column.svelte"
|
||||||
import ViewPopover from "./popovers/View.svelte"
|
import ViewPopover from "./popovers/View.svelte"
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
import LinkedRecord from "./LinkedRecord.svelte"
|
import LinkedRecord from "./LinkedRecord.svelte"
|
||||||
import TablePagination from "./TablePagination.svelte"
|
import TablePagination from "./TablePagination.svelte"
|
||||||
import { DeleteRecordModal, CreateEditRecordModal } from "./modals"
|
import { CreateEditRecordModal } from "./modals"
|
||||||
import RowPopover from "./popovers/Row.svelte"
|
import RowPopover from "./popovers/Row.svelte"
|
||||||
import ColumnPopover from "./popovers/Column.svelte"
|
import ColumnPopover from "./popovers/Column.svelte"
|
||||||
import ViewPopover from "./popovers/View.svelte"
|
import ViewPopover from "./popovers/View.svelte"
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="container">
|
||||||
<Input placeholder="Name" thin bind:value={field.name} />
|
<Input placeholder="Name" thin bind:value={field.name} />
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
|
@ -65,76 +65,62 @@
|
||||||
{/each}
|
{/each}
|
||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
<div class="info">
|
<div class="field">
|
||||||
|
<label>Required</label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
bind:checked={required}
|
||||||
|
on:change={() => (field.constraints.presence.allowEmpty = required)} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if field.type === 'string' && field.constraints}
|
||||||
|
<NumberBox
|
||||||
|
label="Max Length"
|
||||||
|
bind:value={field.constraints.length.maximum} />
|
||||||
|
<ValuesList label="Categories" bind:values={field.constraints.inclusion} />
|
||||||
|
{:else if field.type === 'datetime' && field.constraints}
|
||||||
|
<DatePicker
|
||||||
|
label="Earliest"
|
||||||
|
bind:value={field.constraints.datetime.earliest} />
|
||||||
|
<DatePicker label="Latest" bind:value={field.constraints.datetime.latest} />
|
||||||
|
{:else if field.type === 'number' && field.constraints}
|
||||||
|
<NumberBox
|
||||||
|
label="Min Value"
|
||||||
|
bind:value={field.constraints.numericality.greaterThanOrEqualTo} />
|
||||||
|
<NumberBox
|
||||||
|
label="Max Value"
|
||||||
|
bind:value={field.constraints.numericality.lessThanOrEqualTo} />
|
||||||
|
{:else if field.type === 'link'}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>Required</label>
|
<label>Link</label>
|
||||||
<input
|
<select class="budibase__input" bind:value={field.modelId}>
|
||||||
type="checkbox"
|
<option value="">Choose an option</option>
|
||||||
bind:checked={required}
|
{#each $backendUiStore.models as model}
|
||||||
on:change={() => (field.constraints.presence.allowEmpty = required)} />
|
{#if model._id !== $backendUiStore.draftModel._id}
|
||||||
|
<option value={model._id}>{model.name}</option>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
{#if field.type === 'string' && field.constraints}
|
<footer>
|
||||||
<NumberBox
|
|
||||||
label="Max Length"
|
|
||||||
bind:value={field.constraints.length.maximum} />
|
|
||||||
<ValuesList
|
|
||||||
label="Categories"
|
|
||||||
bind:values={field.constraints.inclusion} />
|
|
||||||
{:else if field.type === 'datetime' && field.constraints}
|
|
||||||
<DatePicker
|
|
||||||
label="Earliest"
|
|
||||||
bind:value={field.constraints.datetime.earliest} />
|
|
||||||
<DatePicker
|
|
||||||
label="Latest"
|
|
||||||
bind:value={field.constraints.datetime.latest} />
|
|
||||||
{:else if field.type === 'number' && field.constraints}
|
|
||||||
<NumberBox
|
|
||||||
label="Min Value"
|
|
||||||
bind:value={field.constraints.numericality.greaterThanOrEqualTo} />
|
|
||||||
<NumberBox
|
|
||||||
label="Max Value"
|
|
||||||
bind:value={field.constraints.numericality.lessThanOrEqualTo} />
|
|
||||||
{:else if field.type === 'link'}
|
|
||||||
<div class="field">
|
|
||||||
<label>Link</label>
|
|
||||||
<select class="budibase__input" bind:value={field.modelId}>
|
|
||||||
<option value={''} />
|
|
||||||
{#each $backendUiStore.models as model}
|
|
||||||
{#if model._id !== $backendUiStore.draftModel._id}
|
|
||||||
<option value={model._id}>{model.name}</option>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<footer>
|
|
||||||
<div class="button-margin-3">
|
|
||||||
<Button secondary on:click={onClosed}>Cancel</Button>
|
<Button secondary on:click={onClosed}>Cancel</Button>
|
||||||
</div>
|
|
||||||
<div class="button-margin-4">
|
|
||||||
<Button primary on:click={saveColumn}>Save Column</Button>
|
<Button primary on:click={saveColumn}>Save Column</Button>
|
||||||
</div>
|
</footer>
|
||||||
</footer>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.actions {
|
.container {
|
||||||
padding: var(--spacing-l) var(--spacing-xl);
|
padding: var(--spacing-xl);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: var(--spacing-xl);
|
grid-gap: var(--spacing-xl);
|
||||||
|
min-width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
padding: 20px 30px;
|
display: flex;
|
||||||
display: grid;
|
justify-content: flex-end;
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
gap: var(--spacing-m);
|
||||||
gap: 20px;
|
|
||||||
background: var(--grey-1);
|
|
||||||
border-bottom-left-radius: 0.5rem;
|
|
||||||
border-bottom-left-radius: 0.5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.field {
|
.field {
|
||||||
|
@ -144,17 +130,6 @@
|
||||||
grid-gap: 5px;
|
grid-gap: 5px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin-bottom: var(--spacing-l);
|
|
||||||
font-family: var(--font-normal);
|
font-family: var(--font-normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-margin-3 {
|
|
||||||
grid-column-start: 3;
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-margin-4 {
|
|
||||||
grid-column-start: 4;
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -40,11 +40,11 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="container">
|
||||||
<ErrorsBox {errors} />
|
<ErrorsBox {errors} />
|
||||||
<form on:submit|preventDefault>
|
<form on:submit|preventDefault>
|
||||||
{#each modelSchema as [key, meta]}
|
{#each modelSchema as [key, meta]}
|
||||||
<div class="bb-margin-xl">
|
<div>
|
||||||
{#if meta.type === 'link'}
|
{#if meta.type === 'link'}
|
||||||
<LinkedRecordSelector
|
<LinkedRecordSelector
|
||||||
bind:linked={record[key]}
|
bind:linked={record[key]}
|
||||||
|
@ -56,38 +56,28 @@
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
<footer>
|
||||||
<footer>
|
|
||||||
<div class="button-margin-3">
|
|
||||||
<Button secondary on:click={onClosed}>Cancel</Button>
|
<Button secondary on:click={onClosed}>Cancel</Button>
|
||||||
</div>
|
|
||||||
<div class="button-margin-4">
|
|
||||||
<Button primary on:click={saveRecord}>Save</Button>
|
<Button primary on:click={saveRecord}>Save</Button>
|
||||||
</div>
|
</footer>
|
||||||
</footer>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.actions {
|
.container {
|
||||||
padding: var(--spacing-l) var(--spacing-xl);
|
padding: var(--spacing-xl);
|
||||||
|
display: grid;
|
||||||
|
grid-gap: var(--spacing-xl);
|
||||||
|
min-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: var(--spacing-xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
padding: 20px 30px;
|
display: flex;
|
||||||
display: grid;
|
justify-content: flex-end;
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
gap: var(--spacing-m);
|
||||||
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>
|
</style>
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
<script>
|
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
|
||||||
import { notifier } from "builderStore/store/notifications"
|
|
||||||
import { store, backendUiStore } from "builderStore"
|
|
||||||
import * as api from "../api"
|
|
||||||
|
|
||||||
export let record
|
|
||||||
export let onClosed
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<div class="content">
|
|
||||||
<header>
|
|
||||||
<i class="ri-information-line alert" />
|
|
||||||
<h4 class="budibase__title--4">Delete Record</h4>
|
|
||||||
</header>
|
|
||||||
<p>
|
|
||||||
Are you sure you want to delete this record? All of your data will be
|
|
||||||
permanently removed. This action cannot be undone.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-actions">
|
|
||||||
<ActionButton on:click={onClosed}>Cancel</ActionButton>
|
|
||||||
<ActionButton
|
|
||||||
alert
|
|
||||||
on:click={async () => {
|
|
||||||
await api.deleteRecord(record)
|
|
||||||
notifier.danger('Record deleted')
|
|
||||||
backendUiStore.actions.records.delete(record)
|
|
||||||
onClosed()
|
|
||||||
}}>
|
|
||||||
Delete
|
|
||||||
</ActionButton>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.alert {
|
|
||||||
color: rgba(255, 0, 31, 1);
|
|
||||||
background: var(--grey-1);
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-actions {
|
|
||||||
padding: 10px;
|
|
||||||
background: var(--grey-1);
|
|
||||||
border-top: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
padding: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin: 0 0 0 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -41,7 +41,7 @@
|
||||||
|
|
||||||
{#if type === 'select'}
|
{#if type === 'select'}
|
||||||
<Select thin secondary data-cy="{meta.name}-select" bind:value>
|
<Select thin secondary data-cy="{meta.name}-select" bind:value>
|
||||||
<option />
|
<option value="">Choose an option</option>
|
||||||
{#each meta.constraints.inclusion as opt}
|
{#each meta.constraints.inclusion as opt}
|
||||||
<option value={opt}>{opt}</option>
|
<option value={opt}>{opt}</option>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -52,24 +52,34 @@
|
||||||
{:else if type === 'file'}
|
{:else if type === 'file'}
|
||||||
<Label small forAttr={'dropzone-label'}>{meta.name}</Label>
|
<Label small forAttr={'dropzone-label'}>{meta.name}</Label>
|
||||||
<Dropzone bind:files={value} />
|
<Dropzone bind:files={value} />
|
||||||
|
{:else if type === 'checkbox'}
|
||||||
|
<div class="checkbox">
|
||||||
|
<Label small forAttr={'checkbox-label'}>{meta.name}</Label>
|
||||||
|
<input
|
||||||
|
checked={value}
|
||||||
|
data-cy="{meta.name}-input"
|
||||||
|
{type}
|
||||||
|
on:change={handleInput} />
|
||||||
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
{#if type === 'checkbox'}
|
|
||||||
<label>{meta.name}</label>
|
|
||||||
{/if}
|
|
||||||
<Input
|
<Input
|
||||||
thin
|
thin
|
||||||
placeholder={meta.name}
|
placeholder={meta.name}
|
||||||
data-cy="{meta.name}-input"
|
data-cy="{meta.name}-input"
|
||||||
checked={value}
|
|
||||||
{type}
|
{type}
|
||||||
{value}
|
{value}
|
||||||
on:change={handleInput} />
|
on:change={handleInput} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
label {
|
.checkbox {
|
||||||
font-weight: 500;
|
display: flex;
|
||||||
font-size: var(--font-size-s);
|
flex-direction: row;
|
||||||
margin-bottom: 12px;
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.checkbox :global(label) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-right: var(--spacing-xs);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
export { default as DeleteRecordModal } from "./DeleteRecord.svelte"
|
|
||||||
export { default as CreateEditRecordModal } from "./CreateEditRecord.svelte"
|
export { default as CreateEditRecordModal } from "./CreateEditRecord.svelte"
|
||||||
|
export { default as CreateEditColumnModal } from "./CreateEditColumn.svelte"
|
||||||
|
export { default as RecordFieldControlModal } from "./RecordFieldControl.svelte"
|
||||||
|
|
|
@ -46,47 +46,52 @@
|
||||||
</TextButton>
|
</TextButton>
|
||||||
</div>
|
</div>
|
||||||
<Popover bind:this={dropdown} {anchor} align="left">
|
<Popover bind:this={dropdown} {anchor} align="left">
|
||||||
<h5>Calculate</h5>
|
<div class="container">
|
||||||
<div class="input-group-row">
|
<h5>Calculate</h5>
|
||||||
<p>The</p>
|
<div class="input-group-row">
|
||||||
<Select secondary thin bind:value={view.calculation}>
|
<p>The</p>
|
||||||
<option value={null} />
|
<Select secondary thin bind:value={view.calculation}>
|
||||||
{#each CALCULATIONS as calculation}
|
<option value="">Choose an option</option>
|
||||||
<option value={calculation.key}>{calculation.name}</option>
|
{#each CALCULATIONS as calculation}
|
||||||
{/each}
|
<option value={calculation.key}>{calculation.name}</option>
|
||||||
</Select>
|
{/each}
|
||||||
<p>of</p>
|
</Select>
|
||||||
<Select secondary thin bind:value={view.field}>
|
<p>of</p>
|
||||||
<option value={null} />
|
<Select secondary thin bind:value={view.field}>
|
||||||
{#each fields as field}
|
<option value="">Choose an option</option>
|
||||||
<option value={field}>{field}</option>
|
{#each fields as field}
|
||||||
{/each}
|
<option value={field}>{field}</option>
|
||||||
</Select>
|
{/each}
|
||||||
</div>
|
</Select>
|
||||||
<div class="button-group">
|
</div>
|
||||||
<Button secondary on:click={dropdown.hide}>Cancel</Button>
|
<div class="footer">
|
||||||
<Button primary on:click={saveView}>Save</Button>
|
<Button secondary on:click={dropdown.hide}>Cancel</Button>
|
||||||
|
<Button primary on:click={saveView}>Save</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: var(--spacing-xl);
|
||||||
|
}
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
margin-bottom: var(--spacing-l);
|
margin: 0;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-group {
|
.footer {
|
||||||
margin-top: var(--spacing-l);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: var(--spacing-s);
|
gap: var(--spacing-m);
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group-row {
|
.input-group-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 50px 1fr 20px 1fr;
|
grid-template-columns: 50px 1fr 20px 1fr;
|
||||||
gap: var(--spacing-s);
|
gap: var(--spacing-s);
|
||||||
margin-bottom: var(--spacing-l);
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
import { DropdownMenu, Button, Icon, Input, Select } from "@budibase/bbui"
|
import { DropdownMenu, Button, Icon, Input, Select } from "@budibase/bbui"
|
||||||
import { FIELDS } from "constants/backend"
|
import { FIELDS } from "constants/backend"
|
||||||
import CreateEditColumn from "../modals/CreateEditColumn.svelte"
|
import { CreateEditColumnModal } from "../modals"
|
||||||
|
|
||||||
export let field
|
export let field
|
||||||
|
|
||||||
|
@ -37,14 +37,14 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:this={anchor} on:click={dropdown.show}>
|
<div class="container" bind:this={anchor} on:click={dropdown.show}>
|
||||||
{field.name}
|
{field.name}
|
||||||
<Icon name="arrowdown" />
|
<Icon name="arrowdown" />
|
||||||
</div>
|
</div>
|
||||||
<DropdownMenu bind:this={dropdown} {anchor} align="left">
|
<DropdownMenu bind:this={dropdown} {anchor} align="left">
|
||||||
{#if editing}
|
{#if editing}
|
||||||
<h5>Edit Column</h5>
|
<h5>Edit Column</h5>
|
||||||
<CreateEditColumn onClosed={hideEditor} {field} />
|
<CreateEditColumnModal onClosed={hideEditor} {field} />
|
||||||
{:else}
|
{:else}
|
||||||
<ul>
|
<ul>
|
||||||
<li data-cy="edit-column-header" on:click={showEditor}>
|
<li data-cy="edit-column-header" on:click={showEditor}>
|
||||||
|
@ -72,6 +72,14 @@
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-xs);
|
||||||
|
}
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
padding: var(--spacing-xl) 0 0 var(--spacing-xl);
|
padding: var(--spacing-xl) 0 0 var(--spacing-xl);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
|
@ -10,17 +10,17 @@
|
||||||
Heading,
|
Heading,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { FIELDS } from "constants/backend"
|
import { FIELDS } from "constants/backend"
|
||||||
import CreateEditRecord from "../modals/CreateEditRecord.svelte"
|
import { CreateEditRecordModal } from "../modals"
|
||||||
import DeleteRecordModal from "../modals/DeleteRecord.svelte"
|
import * as api from "../api"
|
||||||
|
import { notifier } from "builderStore/store/notifications"
|
||||||
const { open, close } = getContext("simple-modal")
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
|
|
||||||
export let row
|
export let row
|
||||||
|
|
||||||
let anchor
|
let anchor
|
||||||
let dropdown
|
let dropdown
|
||||||
|
|
||||||
let editing
|
let editing
|
||||||
|
let confirmDeleteDialog
|
||||||
|
|
||||||
function showEditor() {
|
function showEditor() {
|
||||||
editing = true
|
editing = true
|
||||||
|
@ -32,15 +32,11 @@
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteRow = () => {
|
async function deleteRow() {
|
||||||
open(
|
await api.deleteRecord(row)
|
||||||
DeleteRecordModal,
|
notifier.success("Record deleted")
|
||||||
{
|
backendUiStore.actions.records.delete(row)
|
||||||
onClosed: hideEditor,
|
hideEditor()
|
||||||
record: row,
|
|
||||||
},
|
|
||||||
{ styleContent: { padding: "0" } }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -50,20 +46,26 @@
|
||||||
<DropdownMenu bind:this={dropdown} {anchor} align="left">
|
<DropdownMenu bind:this={dropdown} {anchor} align="left">
|
||||||
{#if editing}
|
{#if editing}
|
||||||
<h5>Edit Row</h5>
|
<h5>Edit Row</h5>
|
||||||
<CreateEditRecord onClosed={hideEditor} record={row} />
|
<CreateEditRecordModal onClosed={hideEditor} record={row} />
|
||||||
{:else}
|
{:else}
|
||||||
<ul>
|
<ul>
|
||||||
<li data-cy="edit-row" on:click={showEditor}>
|
<li data-cy="edit-row" on:click={showEditor}>
|
||||||
<Icon name="edit" />
|
<Icon name="edit" />
|
||||||
<span>Edit</span>
|
<span>Edit</span>
|
||||||
</li>
|
</li>
|
||||||
<li data-cy="delete-row" on:click={deleteRow}>
|
<li data-cy="delete-row" on:click={() => confirmDeleteDialog.show()}>
|
||||||
<Icon name="delete" />
|
<Icon name="delete" />
|
||||||
<span>Delete</span>
|
<span>Delete</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{/if}
|
{/if}
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
<ConfirmDialog
|
||||||
|
bind:this={confirmDeleteDialog}
|
||||||
|
body={`Are you sure you wish to delete this row? Your data will be deleted and this action cannot be undone.`}
|
||||||
|
okText="Delete Row"
|
||||||
|
onOk={deleteRow}
|
||||||
|
title="Confirm Delete" />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.ri-more-line:hover {
|
.ri-more-line:hover {
|
||||||
|
@ -91,6 +93,7 @@
|
||||||
margin: auto 0px;
|
margin: auto 0px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
li:hover {
|
li:hover {
|
||||||
|
|
|
@ -95,67 +95,80 @@
|
||||||
</TextButton>
|
</TextButton>
|
||||||
</div>
|
</div>
|
||||||
<Popover bind:this={dropdown} {anchor} align="left">
|
<Popover bind:this={dropdown} {anchor} align="left">
|
||||||
<h5>Filter</h5>
|
<div class="container">
|
||||||
<div class="input-group-row">
|
<h5>Filter</h5>
|
||||||
{#each view.filters as filter, idx}
|
{#if view.filters.length}
|
||||||
{#if idx === 0}
|
<div class="input-group-row">
|
||||||
<p>Where</p>
|
{#each view.filters as filter, idx}
|
||||||
{:else}
|
{#if idx === 0}
|
||||||
<Select secondary thin bind:value={filter.conjunction}>
|
<p>Where</p>
|
||||||
{#each CONJUNCTIONS as conjunction}
|
{:else}
|
||||||
<option value={conjunction.key}>{conjunction.name}</option>
|
<Select secondary thin bind:value={filter.conjunction}>
|
||||||
{/each}
|
<option value="">Choose an option</option>
|
||||||
</Select>
|
{#each CONJUNCTIONS as conjunction}
|
||||||
{/if}
|
<option value={conjunction.key}>{conjunction.name}</option>
|
||||||
<Select secondary thin bind:value={filter.key}>
|
{/each}
|
||||||
{#each fields as field}
|
</Select>
|
||||||
<option value={field}>{field}</option>
|
{/if}
|
||||||
|
<Select secondary thin bind:value={filter.key}>
|
||||||
|
<option value="">Choose an option</option>
|
||||||
|
{#each fields as field}
|
||||||
|
<option value={field}>{field}</option>
|
||||||
|
{/each}
|
||||||
|
</Select>
|
||||||
|
<Select secondary thin bind:value={filter.condition}>
|
||||||
|
<option value="">Choose an option</option>
|
||||||
|
{#each CONDITIONS as condition}
|
||||||
|
<option value={condition.key}>{condition.name}</option>
|
||||||
|
{/each}
|
||||||
|
</Select>
|
||||||
|
{#if filter.key && isMultipleChoice(filter.key)}
|
||||||
|
<Select secondary thin bind:value={filter.value}>
|
||||||
|
<option value="">Choose an option</option>
|
||||||
|
{#each viewModel.schema[filter.key].constraints.inclusion as option}
|
||||||
|
<option value={option}>{option}</option>
|
||||||
|
{/each}
|
||||||
|
</Select>
|
||||||
|
{:else}
|
||||||
|
<Input
|
||||||
|
thin
|
||||||
|
placeholder={filter.key || fields[0]}
|
||||||
|
bind:value={filter.value} />
|
||||||
|
{/if}
|
||||||
|
<i class="ri-close-circle-fill" on:click={() => removeFilter(idx)} />
|
||||||
{/each}
|
{/each}
|
||||||
</Select>
|
</div>
|
||||||
<Select secondary thin bind:value={filter.condition}>
|
{/if}
|
||||||
{#each CONDITIONS as condition}
|
<div class="footer">
|
||||||
<option value={condition.key}>{condition.name}</option>
|
<Button text on:click={addFilter}>Add Filter</Button>
|
||||||
{/each}
|
<div class="buttons">
|
||||||
</Select>
|
<Button secondary on:click={dropdown.hide}>Cancel</Button>
|
||||||
{#if filter.key && isMultipleChoice(filter.key)}
|
<Button primary on:click={saveView}>Save</Button>
|
||||||
<Select secondary thin bind:value={filter.value}>
|
</div>
|
||||||
{#each viewModel.schema[filter.key].constraints.inclusion as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Select>
|
|
||||||
{:else}
|
|
||||||
<Input
|
|
||||||
thin
|
|
||||||
placeholder={filter.key || fields[0]}
|
|
||||||
bind:value={filter.value} />
|
|
||||||
{/if}
|
|
||||||
<i class="ri-close-circle-fill" on:click={() => removeFilter(idx)} />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
<div class="button-group">
|
|
||||||
<Button text on:click={addFilter}>Add Filter</Button>
|
|
||||||
<div>
|
|
||||||
<Button secondary on:click={dropdown.hide}>Cancel</Button>
|
|
||||||
<Button primary on:click={saveView}>Save</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: var(--spacing-xl);
|
||||||
|
}
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
margin-bottom: var(--spacing-l);
|
margin: 0;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-group {
|
.footer {
|
||||||
margin-top: var(--spacing-l);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
.buttons {
|
||||||
:global(.button-group > div > button) {
|
display: flex;
|
||||||
margin-left: var(--spacing-m);
|
justify-content: flex-end;
|
||||||
|
gap: var(--spacing-m);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ri-close-circle-fill {
|
.ri-close-circle-fill {
|
||||||
|
@ -166,7 +179,6 @@
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(50px, auto) 1fr 1fr 1fr 15px;
|
grid-template-columns: minmax(50px, auto) 1fr 1fr 1fr 15px;
|
||||||
gap: var(--spacing-s);
|
gap: var(--spacing-s);
|
||||||
margin-bottom: var(--spacing-l);
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,40 +42,45 @@
|
||||||
</TextButton>
|
</TextButton>
|
||||||
</div>
|
</div>
|
||||||
<Popover bind:this={dropdown} {anchor} align="left">
|
<Popover bind:this={dropdown} {anchor} align="left">
|
||||||
<h5>Group By</h5>
|
<div class="container">
|
||||||
<div class="input-group-row">
|
<h5>Group By</h5>
|
||||||
<p>Group By</p>
|
<div class="input-group-row">
|
||||||
<Select secondary thin bind:value={view.groupBy}>
|
<p>Group By</p>
|
||||||
<option value={false} />
|
<Select secondary thin bind:value={view.groupBy}>
|
||||||
{#each fields as field}
|
<option value="">Choose an option</option>
|
||||||
<option value={field}>{field}</option>
|
{#each fields as field}
|
||||||
{/each}
|
<option value={field}>{field}</option>
|
||||||
</Select>
|
{/each}
|
||||||
</div>
|
</Select>
|
||||||
<div class="button-group">
|
</div>
|
||||||
<Button secondary on:click={dropdown.hide}>Cancel</Button>
|
<div class="footer">
|
||||||
<Button primary on:click={saveView}>Save</Button>
|
<Button secondary on:click={dropdown.hide}>Cancel</Button>
|
||||||
|
<Button primary on:click={saveView}>Save</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: var(--spacing-xl);
|
||||||
|
}
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
margin-bottom: var(--spacing-l);
|
margin: 0;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-group {
|
.footer {
|
||||||
margin-top: var(--spacing-l);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: var(--spacing-s);
|
gap: var(--spacing-m);
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group-row {
|
.input-group-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 75px 1fr 20px 1fr;
|
grid-template-columns: 75px 1fr;
|
||||||
gap: var(--spacing-s);
|
gap: var(--spacing-s);
|
||||||
margin-bottom: var(--spacing-l);
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,32 +48,30 @@
|
||||||
</TextButton>
|
</TextButton>
|
||||||
</div>
|
</div>
|
||||||
<Popover bind:this={dropdown} {anchor} align="left">
|
<Popover bind:this={dropdown} {anchor} align="left">
|
||||||
<h5>Create View</h5>
|
<div class="container">
|
||||||
<div class="input-group-column">
|
<h5>Create View</h5>
|
||||||
<Input placeholder="View Name" thin bind:value={name} />
|
<Input placeholder="View Name" thin bind:value={name} />
|
||||||
</div>
|
<div class="footer">
|
||||||
<div class="button-group">
|
<Button secondary on:click={dropdown.hide}>Cancel</Button>
|
||||||
<Button secondary on:click={dropdown.hide}>Cancel</Button>
|
<Button primary on:click={saveView}>Save View</Button>
|
||||||
<Button primary on:click={saveView}>Save View</Button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
h5 {
|
h5 {
|
||||||
margin-bottom: var(--spacing-l);
|
margin: 0;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-group {
|
.container {
|
||||||
margin-top: var(--spacing-l);
|
display: grid;
|
||||||
display: flex;
|
grid-gap: var(--spacing-xl);
|
||||||
justify-content: flex-end;
|
|
||||||
gap: var(--spacing-s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group-column {
|
.footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
justify-content: flex-end;
|
||||||
gap: var(--spacing-s);
|
gap: var(--spacing-m);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -38,15 +38,11 @@
|
||||||
placeholder="Table Name"
|
placeholder="Table Name"
|
||||||
thin
|
thin
|
||||||
bind:value={name} />
|
bind:value={name} />
|
||||||
</div>
|
<footer>
|
||||||
<footer>
|
|
||||||
<div class="button-margin-3">
|
|
||||||
<Button secondary on:click={onClosed}>Cancel</Button>
|
<Button secondary on:click={onClosed}>Cancel</Button>
|
||||||
</div>
|
|
||||||
<div class="button-margin-4">
|
|
||||||
<Button primary on:click={saveTable}>Save</Button>
|
<Button primary on:click={saveTable}>Save</Button>
|
||||||
</div>
|
</footer>
|
||||||
</footer>
|
</div>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -54,6 +50,7 @@
|
||||||
padding: var(--spacing-xl);
|
padding: var(--spacing-xl);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: var(--spacing-xl);
|
grid-gap: var(--spacing-xl);
|
||||||
|
min-width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
|
@ -62,20 +59,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
padding: var(--spacing-xl);
|
display: flex;
|
||||||
display: grid;
|
justify-content: flex-end;
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
|
||||||
gap: var(--spacing-m);
|
gap: var(--spacing-m);
|
||||||
background: var(--grey-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-margin-3 {
|
|
||||||
grid-column-start: 3;
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-margin-4 {
|
|
||||||
grid-column-start: 4;
|
|
||||||
display: grid;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -43,15 +43,11 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h5>Edit Table</h5>
|
<h5>Edit Table</h5>
|
||||||
<Input placeholder="Table Name" thin bind:value={table.name} />
|
<Input placeholder="Table Name" thin bind:value={table.name} />
|
||||||
</div>
|
<footer>
|
||||||
<footer>
|
|
||||||
<div class="button-margin-3">
|
|
||||||
<Button secondary on:click={hideEditor}>Cancel</Button>
|
<Button secondary on:click={hideEditor}>Cancel</Button>
|
||||||
</div>
|
|
||||||
<div class="button-margin-4">
|
|
||||||
<Button primary on:click={save}>Save</Button>
|
<Button primary on:click={save}>Save</Button>
|
||||||
</div>
|
</footer>
|
||||||
</footer>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<ul>
|
<ul>
|
||||||
<li on:click={showEditor}>
|
<li on:click={showEditor}>
|
||||||
|
@ -88,6 +84,7 @@
|
||||||
padding: var(--spacing-xl);
|
padding: var(--spacing-xl);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: var(--spacing-xl);
|
grid-gap: var(--spacing-xl);
|
||||||
|
min-width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
|
@ -96,11 +93,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
padding: var(--spacing-xl);
|
display: flex;
|
||||||
display: grid;
|
justify-content: flex-end;
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
|
||||||
gap: var(--spacing-m);
|
gap: var(--spacing-m);
|
||||||
background: var(--grey-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
|
@ -127,19 +122,4 @@
|
||||||
li:active {
|
li:active {
|
||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-margin-1 {
|
|
||||||
grid-column-start: 1;
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-margin-3 {
|
|
||||||
grid-column-start: 3;
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-margin-4 {
|
|
||||||
grid-column-start: 4;
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -51,15 +51,11 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h5>Edit View</h5>
|
<h5>Edit View</h5>
|
||||||
<Input placeholder="View Name" thin bind:value={view.name} />
|
<Input placeholder="View Name" thin bind:value={view.name} />
|
||||||
</div>
|
<footer>
|
||||||
<footer>
|
|
||||||
<div class="button-margin-3">
|
|
||||||
<Button secondary on:click={hideEditor}>Cancel</Button>
|
<Button secondary on:click={hideEditor}>Cancel</Button>
|
||||||
</div>
|
|
||||||
<div class="button-margin-4">
|
|
||||||
<Button primary on:click={save}>Save</Button>
|
<Button primary on:click={save}>Save</Button>
|
||||||
</div>
|
</footer>
|
||||||
</footer>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<ul>
|
<ul>
|
||||||
<li on:click={showEditor}>
|
<li on:click={showEditor}>
|
||||||
|
@ -96,6 +92,7 @@
|
||||||
padding: var(--spacing-xl);
|
padding: var(--spacing-xl);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: var(--spacing-xl);
|
grid-gap: var(--spacing-xl);
|
||||||
|
min-width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
|
@ -104,11 +101,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
padding: var(--spacing-xl);
|
display: flex;
|
||||||
display: grid;
|
justify-content: flex-end;
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
|
||||||
gap: var(--spacing-m);
|
gap: var(--spacing-m);
|
||||||
background: var(--grey-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
|
@ -135,19 +130,4 @@
|
||||||
li:active {
|
li:active {
|
||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-margin-1 {
|
|
||||||
grid-column-start: 1;
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-margin-3 {
|
|
||||||
grid-column-start: 3;
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-margin-4 {
|
|
||||||
grid-column-start: 4;
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue