Merge branch 'linked-records' of github.com:Budibase/budibase into linked-records

This commit is contained in:
mike12345567 2020-09-25 18:05:38 +01:00
commit a20ffd4c17
52 changed files with 710 additions and 1233 deletions

View File

@ -1,70 +1,62 @@
context('Create a Table', () => {
before(() => {
cy.visit('localhost:4001/_builder')
cy.createApp('Table App', 'Table App Description')
})
context("Create a Table", () => {
before(() => {
cy.visit("localhost:4001/_builder")
cy.createApp("Table App", "Table App Description")
})
it('should create a new Table', () => {
cy.createTable('dog')
it("should create a new Table", () => {
cy.createTable("dog")
// Check if Table exists
cy.get('.title').should('have.text', 'dog')
})
// Check if Table exists
cy.get(".title").should("have.text", "dog")
})
it('adds a new column to the table', () => {
cy.addColumn('dog', 'name', 'Plain Text')
it("adds a new column to the table", () => {
cy.addColumn("dog", "name", "Plain Text")
cy.contains("name").should("be.visible")
})
cy.contains('name').should("be.visible")
})
it("creates a record in the table", () => {
cy.addRecord(["Rover"])
cy.contains("Rover").should("be.visible")
})
it('creates a record in the table', () => {
cy.addRecord(["Rover"])
it("updates a column on the table", () => {
cy.contains("name").click()
cy.get("[data-cy='edit-column-header']").click()
cy.get("[placeholder=Name]").type("updated")
cy.get("select").select("Plain Text")
cy.contains("Save Column").click()
cy.contains("nameupdated").should("have.text", "nameupdated ")
})
cy.contains('Rover').should("be.visible")
})
it("edits a record", () => {
cy.get("tbody .ri-more-line").click()
cy.get("[data-cy=edit-row]").click()
cy.get(".actions input").type("Updated")
cy.contains("Save").click()
cy.contains("RoverUpdated").should("have.text", "RoverUpdated")
})
it('updates a column on the table', () => {
cy.contains("name").click()
cy.get("[data-cy='edit-column-header']").click()
it("deletes a record", () => {
cy.get("tbody .ri-more-line").click()
cy.get("[data-cy=delete-row]").click()
cy.contains("Delete Row").click()
cy.contains("RoverUpdated").should("not.exist")
})
cy.get("[placeholder=Name]").type("updated")
cy.get("select").select("Plain Text")
cy.contains("Save Column").click()
cy.contains('nameupdated').should('have.text', 'nameupdated ')
})
it('edits a record', () => {
cy.get("tbody .ri-more-line").click()
cy.get("[data-cy=edit-row]").click()
cy.get(".actions input").type("Updated")
cy.contains("Save").click()
cy.contains('RoverUpdated').should('have.text', 'RoverUpdated')
})
it('deletes a record', () => {
cy.get("tbody .ri-more-line").click()
cy.get("[data-cy=delete-row]").click()
cy.get(".modal-actions").contains("Delete").click()
cy.contains('RoverUpdated').should('not.exist')
})
it('deletes a column', () => {
cy.contains("name").click()
cy.get("[data-cy='delete-column-header']").click()
cy.contains('nameupdated').should('not.exist')
})
it('deletes a table', () => {
cy.contains("div", "dog").get(".ri-more-line").click()
cy.get("[data-cy=delete-table]").click()
cy.get(".modal-actions").contains("Delete").click()
cy.contains('dog').should('not.exist')
})
it("deletes a column", () => {
cy.contains("name").click()
cy.get("[data-cy='delete-column-header']").click()
cy.contains("nameupdated").should("not.exist")
})
it("deletes a table", () => {
cy.contains("div", "dog")
.get(".ri-more-line")
.click()
cy.get("[data-cy=delete-table]").click()
cy.contains("Delete Table").click()
cy.contains("dog").should("not.exist")
})
})

View File

@ -1,90 +1,100 @@
context("Create a View", () => {
before(() => {
cy.visit("localhost:4001/_builder")
cy.createApp("View App", "View App Description")
cy.createTable("data")
cy.addColumn("data", "group", "Plain Text")
cy.addColumn("data", "age", "Number")
cy.addColumn("data", "rating", "Number")
context('Create a View', () => {
before(() => {
cy.visit('localhost:4001/_builder')
cy.createApp('View App', 'View App Description')
cy.createTable('data')
cy.addColumn('data', 'group', 'Plain Text')
cy.addColumn('data', 'age', 'Number')
cy.addColumn('data', 'rating', 'Number')
// 6 Records
cy.addRecord(["Students", 25, 1])
cy.addRecord(["Students", 20, 3])
cy.addRecord(["Students", 18, 6])
cy.addRecord(["Students", 25, 2])
cy.addRecord(["Teachers", 49, 5])
cy.addRecord(["Teachers", 36, 3])
})
// 6 Records
cy.addRecord(["Students", 25, 1])
cy.addRecord(["Students", 20, 3])
cy.addRecord(["Students", 18, 6])
cy.addRecord(["Students", 25, 2])
cy.addRecord(["Teachers", 49, 5])
cy.addRecord(["Teachers", 36, 3])
it("creates a view", () => {
cy.contains("Create New View").click()
cy.get("[placeholder='View Name']").type("Test View")
cy.contains("Save View").click()
cy.get(".title").contains("Test View")
cy.get("thead th").should($headers => {
expect($headers).to.have.length(3)
const headers = $headers.map((i, header) => Cypress.$(header).text())
expect(headers.get()).to.deep.eq(["group", "age", "rating"])
})
})
it('creates a view', () => {
cy.contains("Create New View").click()
cy.get("[placeholder='View Name']").type("Test View")
cy.contains("Save View").click()
cy.get(".title").contains("Test View")
cy.get("thead th").should(($headers) => {
expect($headers).to.have.length(3)
const headers = $headers.map((i, header) => Cypress.$(header).text())
expect(headers.get()).to.deep.eq([
"group",
"age",
"rating"
])
})
});
it('filters the view by age over 10', () => {
cy.contains("Filter").click()
cy.contains("Add Filter").click()
cy.get(".menu-container").find("select").first().select("age")
cy.get(".menu-container").find("select").eq(1).select("More Than")
cy.get("input[placeholder='age']").type(18)
cy.contains("Save").click()
cy.get("tbody tr").should(($values) => {
expect($values).to.have.length(5)
})
});
it('creates a stats calculation view based on age', () => {
cy.contains("Calculate").click()
cy.get(".menu-container").find("select").first().select("Statistics")
cy.get(".menu-container").find("select").eq(1).select("age")
cy.contains("Save").click()
cy.get("thead th").should(($headers) => {
expect($headers).to.have.length(7)
const headers = $headers.map((i, header) => Cypress.$(header).text())
expect(headers.get()).to.deep.eq([
"field",
"sum",
"min",
"max",
"count",
"sumsqr",
"avg",
])
})
cy.get("tbody td").should(($values) => {
const values = $values.map((i, value) => Cypress.$(value).text())
expect(values.get()).to.deep.eq([
"age",
"155",
"20",
"49",
"5",
"5347",
"31"
])
})
it("filters the view by age over 10", () => {
cy.contains("Filter").click()
cy.contains("Add Filter").click()
cy.get(".menu-container")
.find("select")
.first()
.select("age")
cy.get(".menu-container")
.find("select")
.eq(1)
.select("More Than")
cy.get("input[placeholder='age']").type(18)
cy.contains("Save").click()
cy.get("tbody tr").should($values => {
expect($values).to.have.length(5)
})
})
it('groups the view by group', () => {
cy.contains("Group By").click()
cy.get("select").select("group")
cy.contains("Save").click()
cy.contains("Students").should("be.visible")
cy.contains("Teachers").should("be.visible")
it("creates a stats calculation view based on age", () => {
cy.contains("Calculate").click()
cy.get(".menu-container")
.find("select")
.first()
.select("Statistics")
cy.get(".menu-container")
.find("select")
.eq(1)
.select("age")
cy.contains("Save").click()
cy.get("thead th").should($headers => {
expect($headers).to.have.length(7)
const headers = $headers.map((i, header) => Cypress.$(header).text())
expect(headers.get()).to.deep.eq([
"field",
"sum",
"min",
"max",
"count",
"sumsqr",
"avg",
])
})
cy.get("tbody td").should($values => {
const values = $values.map((i, value) => Cypress.$(value).text())
expect(values.get()).to.deep.eq([
"age",
"155",
"20",
"49",
"5",
"5347",
"31",
])
})
})
cy.get("tbody tr").first().find("td").should(($values) => {
it("groups the view by group", () => {
cy.contains("Group By").click()
cy.get("select").select("group")
cy.contains("Save").click()
cy.contains("Students").should("be.visible")
cy.contains("Teachers").should("be.visible")
cy.get("tbody tr")
.first()
.find("td")
.should($values => {
const values = $values.map((i, value) => Cypress.$(value).text())
expect(values.get()).to.deep.eq([
"Students",
@ -93,24 +103,28 @@ context('Create a View', () => {
"25",
"3",
"1650",
"23.333333333333332"
"23.333333333333332",
])
})
})
})
it('renames a view', () => {
cy.contains("[data-cy=model-nav-item]", "Test View").find(".ri-more-line").click()
cy.contains("Edit").click()
cy.get("[placeholder='View Name']").type(" Updated")
cy.contains("Save").click()
cy.contains("Test View Updated").should("be.visible")
})
it("renames a view", () => {
cy.contains("[data-cy=model-nav-item]", "Test View")
.find(".ri-more-line")
.click()
cy.contains("Edit").click()
cy.get("[placeholder='View Name']").type(" Updated")
cy.contains("Save").click()
cy.contains("Test View Updated").should("be.visible")
})
it('deletes a view', () => {
cy.contains("[data-cy=model-nav-item]", "Test View Updated").click()
cy.contains("[data-cy=model-nav-item]", "Test View Updated").find(".ri-more-line").click()
cy.contains("Delete").click()
cy.get(".content").contains("button", "Delete").click()
cy.contains("TestView Updated").should("not.be.visible")
})
it("deletes a view", () => {
cy.contains("[data-cy=model-nav-item]", "Test View Updated").click()
cy.contains("[data-cy=model-nav-item]", "Test View Updated")
.find(".ri-more-line")
.click()
cy.contains("Delete").click()
cy.contains("Delete View").click()
cy.contains("TestView Updated").should("not.be.visible")
})
})

View File

@ -63,7 +63,7 @@
}
},
"dependencies": {
"@budibase/bbui": "^1.34.2",
"@budibase/bbui": "^1.34.5",
"@budibase/client": "^0.1.21",
"@budibase/colorpicker": "^1.0.1",
"@fortawesome/fontawesome-free": "^5.14.0",

View File

@ -50,7 +50,7 @@
header {
font-size: var(--font-size-xl);
color: var(--ink);
font-weight: bold;
font-weight: 600;
display: flex;
flex-direction: row;
justify-content: flex-start;

View File

@ -1,89 +0,0 @@
<script>
import { store, backendUiStore, automationStore } from "builderStore"
import { notifier } from "builderStore/store/notifications"
import ActionButton from "components/common/ActionButton.svelte"
export let onClosed
let name
$: valid = !!name
$: instanceId = $backendUiStore.selectedDatabase._id
async function deleteAutomation() {
await automationStore.actions.delete({
instanceId,
automation: $automationStore.selectedAutomation.automation,
})
onClosed()
notifier.danger("Automation deleted.")
}
</script>
<header>
<i class="ri-stackshare-line" />
Delete Automation
</header>
<div>
<p>
Are you sure you want to delete this automation? This action can't be
undone.
</p>
</div>
<footer>
<a href="https://docs.budibase.com">
<i class="ri-information-line" />
Learn about automations
</a>
<ActionButton on:click={onClosed}>Cancel</ActionButton>
<ActionButton alert on:click={deleteAutomation}>Delete</ActionButton>
</footer>
<style>
header {
font-size: 24px;
color: var(--ink);
font-weight: bold;
padding: 30px;
}
header i {
margin-right: 10px;
font-size: 20px;
background: var(--blue-light);
color: var(--grey-4);
padding: 8px;
}
div {
padding: 0 30px 30px 30px;
}
label {
font-size: 18px;
font-weight: 500;
}
footer {
display: grid;
grid-auto-flow: column;
grid-gap: 5px;
grid-auto-columns: 3fr 1fr 1fr;
padding: 20px;
background: var(--grey-1);
border-radius: 0.5rem;
}
footer a {
color: var(--primary);
font-size: 14px;
vertical-align: middle;
display: flex;
align-items: center;
}
footer i {
font-size: 20px;
margin-right: 10px;
}
</style>

View File

@ -28,9 +28,9 @@
</div>
{#if schemaFields.length}
<div class="bb-margin-xl block-field">
<div class="schema-fields">
{#each schemaFields as [field, schema]}
<div class="bb-margin-xl capitalise">
<div class="capitalise">
{#if schemaHasOptions(schema)}
<div class="field-label">{field}</div>
<Select thin secondary bind:value={value[field]}>
@ -66,4 +66,10 @@
.field-label {
text-transform: capitalize;
}
.schema-fields {
display: grid;
grid-gap: var(--spacing-xl);
margin-top: var(--spacing-xl);
}
</style>

View File

@ -1,28 +1,19 @@
<script>
import { getContext } from "svelte"
import { backendUiStore, automationStore } from "builderStore"
import { notifier } from "builderStore/store/notifications"
import AutomationBlockSetup from "./AutomationBlockSetup.svelte"
import DeleteAutomationModal from "./DeleteAutomationModal.svelte"
import { Button, Input, Label } from "@budibase/bbui"
const { open, close } = getContext("simple-modal")
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
let selectedTab = "SETUP"
let confirmDeleteDialog
$: instanceId = $backendUiStore.selectedDatabase._id
$: automation = $automationStore.selectedAutomation?.automation
$: allowDeleteBlock =
$automationStore.selectedBlock?.type !== "TRIGGER" ||
!automation?.definition?.steps?.length
function deleteAutomation() {
open(
DeleteAutomationModal,
{ onClosed: close },
{ styleContent: { padding: "0" } }
)
}
function deleteAutomationBlock() {
automationStore.actions.deleteAutomationBlock(
$automationStore.selectedBlock
@ -42,11 +33,19 @@
async function saveAutomation() {
await automationStore.actions.save({
instanceId: $backendUiStore.selectedDatabase._id,
instanceId,
automation,
})
notifier.success(`Automation ${automation.name} saved.`)
}
async function deleteAutomation() {
await automationStore.actions.delete({
instanceId,
automation,
})
notifier.success("Automation deleted.")
}
</script>
<section>
@ -93,11 +92,18 @@
on:click={saveAutomation}>
Save Automation
</Button>
<Button red wide on:click={deleteAutomation}>Delete Automation</Button>
<Button red wide on:click={() => confirmDeleteDialog.show()}>
Delete Automation
</Button>
{/if}
</div>
</section>
<ConfirmDialog
bind:this={confirmDeleteDialog}
title="Confirm Delete"
body={`Are you sure you wish to delete the automation '${automation.name}'?`}
okText="Delete Automation"
onOk={deleteAutomation} />
<style>
section {

View File

@ -8,7 +8,7 @@
import LinkedRecord from "./LinkedRecord.svelte"
import AttachmentList from "./AttachmentList.svelte"
import TablePagination from "./TablePagination.svelte"
import { DeleteRecordModal, CreateEditRecordModal } from "./modals"
import { CreateEditRecordModal } from "./modals"
import RowPopover from "./popovers/Row.svelte"
import ColumnPopover from "./popovers/Column.svelte"
import ViewPopover from "./popovers/View.svelte"
@ -54,15 +54,13 @@
</script>
<section>
<div class="table-controls">
<h2 class="title">{$backendUiStore.selectedModel.name}</h2>
<div class="popovers">
<ColumnPopover />
{#if Object.keys($backendUiStore.selectedModel.schema).length > 0}
<RowPopover />
<ViewPopover />
{/if}
</div>
<h2 class="title">{$backendUiStore.selectedModel.name}</h2>
<div class="popovers">
<ColumnPopover />
{#if Object.keys($backendUiStore.selectedModel.schema).length > 0}
<RowPopover />
<ViewPopover />
{/if}
</div>
<table class="bb-table">
<thead>
@ -80,7 +78,10 @@
</thead>
<tbody>
{#if paginatedData.length === 0}
<div class="no-data">No Data.</div>
<td class="no-border">No data.</td>
{#each headers as header}
<td class="no-border" />
{/each}
{/if}
{#each paginatedData as row}
<tr>
@ -108,30 +109,31 @@
</section>
<style>
section {
margin-bottom: 20px;
}
.title {
font-size: 24px;
font-weight: 600;
text-rendering: optimizeLegibility;
text-transform: capitalize;
margin-top: 0;
}
.popovers {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
table {
border: 1px solid var(--grey-4);
background: #fff;
border-radius: 3px;
border-collapse: collapse;
}
thead {
height: 40px;
background: var(--grey-3);
border: 1px solid var(--grey-4);
border-bottom: 1px solid var(--grey-4);
}
thead th {
color: var(--ink);
text-transform: capitalize;
@ -140,13 +142,15 @@
text-rendering: optimizeLegibility;
transition: 0.5s all;
vertical-align: middle;
height: 48px;
padding-top: 0;
padding-bottom: 0;
}
.edit-header {
width: 100px;
cursor: default;
}
.edit-header:hover {
color: var(--ink);
}
@ -161,30 +165,24 @@
text-overflow: ellipsis;
border: 1px solid var(--grey-4);
overflow: hidden;
white-space: pre;
white-space: nowrap;
box-sizing: border-box;
padding: var(--spacing-l) var(--spacing-m);
font-size: var(--font-size-xs);
}
td.no-border {
border: none;
}
tbody {
border: 1px solid var(--grey-4);
}
tbody tr {
border-bottom: 1px solid var(--grey-4);
transition: 0.3s background-color;
color: var(--ink);
font-size: 12px;
}
tbody tr:hover {
background: var(--grey-1);
}
.table-controls {
width: 100%;
}
.popovers {
display: flex;
}
.no-data {
padding: 14px;
}
</style>

View File

@ -8,7 +8,7 @@
import ActionButton from "components/common/ActionButton.svelte"
import AttachmentList from "./AttachmentList.svelte"
import TablePagination from "./TablePagination.svelte"
import { DeleteRecordModal, CreateEditRecordModal } from "./modals"
import { CreateEditRecordModal } from "./modals"
import RowPopover from "./popovers/Row.svelte"
import ColumnPopover from "./popovers/Column.svelte"
import ViewPopover from "./popovers/View.svelte"
@ -54,7 +54,11 @@
</thead>
<tbody>
{#if paginatedData.length === 0}
<div class="no-data">No Data.</div>
{#each columns as header, idx}
<td class="no-border">
{#if idx === 0}No data.{/if}
</td>
{/each}
{/if}
{#each paginatedData as row}
<tr>
@ -77,29 +81,24 @@
</section>
<style>
section {
margin-bottom: 20px;
}
.title {
font-size: 24px;
font-weight: 600;
text-rendering: optimizeLegibility;
text-transform: capitalize;
margin-top: 0;
}
table {
border: 1px solid var(--grey-4);
background: #fff;
border-radius: 3px;
border-collapse: collapse;
}
thead {
height: 40px;
background: var(--grey-3);
border: 1px solid var(--grey-4);
}
thead th {
color: var(--ink);
text-transform: capitalize;
@ -108,9 +107,11 @@
text-rendering: optimizeLegibility;
transition: 0.5s all;
vertical-align: middle;
height: 48px;
padding-top: 0;
padding-bottom: 0;
}
th:hover {
thead th:hover {
color: var(--blue);
cursor: pointer;
}
@ -119,15 +120,20 @@
max-width: 200px;
text-overflow: ellipsis;
border: 1px solid var(--grey-4);
white-space: nowrap;
box-sizing: border-box;
padding: var(--spacing-l) var(--spacing-m);
font-size: var(--font-size-xs);
}
td.no-border {
border: none;
}
tbody tr {
border-bottom: 1px solid var(--grey-4);
transition: 0.3s background-color;
color: var(--ink);
font-size: 12px;
}
tbody tr:hover {
background: var(--grey-1);
}
@ -143,8 +149,4 @@
:global(.popovers > div) {
margin-right: var(--spacing-m);
}
.no-data {
padding: 14px;
}
</style>

View File

@ -1,14 +1,11 @@
<script>
import { backendUiStore } from "builderStore"
export let data
export let currentPage
export let pageItemCount
export let ITEMS_PER_PAGE
let numPages = 0
$: numPages = Math.ceil(data.length / ITEMS_PER_PAGE)
$: numPages = Math.ceil((data?.length ?? 0) / ITEMS_PER_PAGE)
const next = () => {
if (currentPage + 1 === numPages) return
@ -27,8 +24,7 @@
<div class="pagination">
<div class="pagination__buttons">
<button on:click={previous}>Previous</button>
<button on:click={next}>Next</button>
<button on:click={previous} disabled={currentPage === 0}>&lt;</button>
{#each Array(numPages) as _, idx}
<button
class:selected={idx === currentPage}
@ -36,8 +32,19 @@
{idx + 1}
</button>
{/each}
<button
on:click={next}
disabled={currentPage === numPages - 1 || numPages === 0}>
&gt;
</button>
</div>
<p>Showing {pageItemCount} of {data.length} entries</p>
<p>
{#if numPages > 1}
Showing {ITEMS_PER_PAGE * currentPage + 1} - {ITEMS_PER_PAGE * currentPage + pageItemCount}
of {data.length} rows
{:else if numPages === 1}Showing all {data.length} row(s){/if}
</p>
</div>
<style>
@ -51,26 +58,36 @@
.pagination__buttons {
display: flex;
border: 1px solid var(--grey-4);
border-radius: var(--border-radius-s);
overflow: hidden;
}
.pagination__buttons button {
display: inline-block;
padding: 10px;
padding: var(--spacing-s) var(--spacing-m);
margin: 0;
background: #fff;
border: 1px solid var(--grey-4);
border: none;
outline: none;
border-right: 1px solid var(--grey-4);
text-transform: capitalize;
border-radius: 3px;
min-width: 20px;
transition: 0.3s background-color;
}
.pagination__buttons button:last-child {
border-right: none;
}
.pagination__buttons button:hover {
cursor: pointer;
background-color: var(--grey-1);
}
.pagination__buttons button.selected {
background: var(--grey-2);
}
.selected {
color: var(--blue);
p {
font-size: var(--font-size-s);
margin: var(--spacing-xl) 0;
}
</style>

View File

@ -9,7 +9,7 @@
import ActionButton from "components/common/ActionButton.svelte"
import LinkedRecord from "./LinkedRecord.svelte"
import TablePagination from "./TablePagination.svelte"
import { DeleteRecordModal, CreateEditRecordModal } from "./modals"
import { CreateEditRecordModal } from "./modals"
import RowPopover from "./popovers/Row.svelte"
import ColumnPopover from "./popovers/Column.svelte"
import ViewPopover from "./popovers/View.svelte"

View File

@ -65,76 +65,62 @@
{/each}
</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">
<label>Required</label>
<input
type="checkbox"
bind:checked={required}
on:change={() => (field.constraints.presence.allowEmpty = required)} />
<label>Link</label>
<select class="budibase__input" bind:value={field.modelId}>
<option value="">Choose an option</option>
{#each $backendUiStore.models as model}
{#if model._id !== $backendUiStore.draftModel._id}
<option value={model._id}>{model.name}</option>
{/if}
{/each}
</select>
</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">
<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">
{/if}
<footer>
<Button secondary on:click={onClosed}>Cancel</Button>
</div>
<div class="button-margin-4">
<Button primary on:click={saveColumn}>Save Column</Button>
</div>
</footer>
</footer>
</div>
<style>
.actions {
padding: var(--spacing-l) var(--spacing-xl);
padding: var(--spacing-xl);
display: grid;
grid-gap: var(--spacing-xl);
min-width: 400px;
}
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;
display: flex;
justify-content: flex-end;
gap: var(--spacing-m);
}
.field {
@ -144,17 +130,6 @@
grid-gap: 5px;
font-size: 14px;
font-weight: 500;
margin-bottom: var(--spacing-l);
font-family: var(--font-normal);
}
.button-margin-3 {
grid-column-start: 3;
display: grid;
}
.button-margin-4 {
grid-column-start: 4;
display: grid;
}
</style>

View File

@ -44,7 +44,7 @@
<ErrorsBox {errors} />
<form on:submit|preventDefault>
{#each modelSchema as [key, meta]}
<div class="bb-margin-xl">
<div>
{#if meta.type === 'link'}
<LinkedRecordSelector
bind:linked={record[key]}
@ -56,38 +56,28 @@
</div>
{/each}
</form>
</div>
<footer>
<div class="button-margin-3">
<footer>
<Button secondary on:click={onClosed}>Cancel</Button>
</div>
<div class="button-margin-4">
<Button primary on:click={saveRecord}>Save</Button>
</div>
</footer>
</footer>
</div>
<style>
.actions {
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 {
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;
display: flex;
justify-content: flex-end;
gap: var(--spacing-m);
}
</style>

View File

@ -41,7 +41,7 @@
{#if type === 'select'}
<Select thin secondary data-cy="{meta.name}-select" bind:value>
<option />
<option value="">Choose an option</option>
{#each meta.constraints.inclusion as opt}
<option value={opt}>{opt}</option>
{/each}
@ -52,24 +52,34 @@
{:else if type === 'file'}
<Label small forAttr={'dropzone-label'}>{meta.name}</Label>
<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}
{#if type === 'checkbox'}
<label>{meta.name}</label>
{/if}
<Input
thin
placeholder={meta.name}
data-cy="{meta.name}-input"
checked={value}
{type}
{value}
on:change={handleInput} />
{/if}
<style>
label {
font-weight: 500;
font-size: var(--font-size-s);
margin-bottom: 12px;
.checkbox {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.checkbox :global(label) {
margin-bottom: 0;
margin-right: var(--spacing-xs);
}
</style>

View File

@ -0,0 +1,3 @@
export { default as CreateEditRecordModal } from "./CreateEditRecord.svelte"
export { default as CreateEditColumnModal } from "./CreateEditColumn.svelte"
export { default as RecordFieldControlModal } from "./RecordFieldControl.svelte"

View File

@ -46,47 +46,52 @@
</TextButton>
</div>
<Popover bind:this={dropdown} {anchor} align="left">
<h5>Calculate</h5>
<div class="input-group-row">
<p>The</p>
<Select secondary thin bind:value={view.calculation}>
<option value={null} />
{#each CALCULATIONS as calculation}
<option value={calculation.key}>{calculation.name}</option>
{/each}
</Select>
<p>of</p>
<Select secondary thin bind:value={view.field}>
<option value={null} />
{#each fields as field}
<option value={field}>{field}</option>
{/each}
</Select>
</div>
<div class="button-group">
<Button secondary on:click={dropdown.hide}>Cancel</Button>
<Button primary on:click={saveView}>Save</Button>
<div class="actions">
<h5>Calculate</h5>
<div class="input-group-row">
<p>The</p>
<Select secondary thin bind:value={view.calculation}>
<option value="">Choose an option</option>
{#each CALCULATIONS as calculation}
<option value={calculation.key}>{calculation.name}</option>
{/each}
</Select>
<p>of</p>
<Select secondary thin bind:value={view.field}>
<option value="">Choose an option</option>
{#each fields as field}
<option value={field}>{field}</option>
{/each}
</Select>
</div>
<div class="footer">
<Button secondary on:click={dropdown.hide}>Cancel</Button>
<Button primary on:click={saveView}>Save</Button>
</div>
</div>
</Popover>
<style>
.actions {
display: grid;
grid-gap: var(--spacing-xl);
}
h5 {
margin-bottom: var(--spacing-l);
margin: 0;
font-weight: 500;
}
.button-group {
margin-top: var(--spacing-l);
.footer {
display: flex;
justify-content: flex-end;
gap: var(--spacing-s);
gap: var(--spacing-m);
}
.input-group-row {
display: grid;
grid-template-columns: 50px 1fr 20px 1fr;
gap: var(--spacing-s);
margin-bottom: var(--spacing-l);
align-items: center;
}

View File

@ -2,7 +2,7 @@
import { backendUiStore } from "builderStore"
import { DropdownMenu, Button, Icon, Input, Select } from "@budibase/bbui"
import { FIELDS } from "constants/backend"
import CreateEditColumn from "../modals/CreateEditColumn.svelte"
import { CreateEditColumnModal } from "../modals"
export let field
@ -37,14 +37,14 @@
}
</script>
<div bind:this={anchor} on:click={dropdown.show}>
<div class="container" bind:this={anchor} on:click={dropdown.show}>
{field.name}
<Icon name="arrowdown" />
</div>
<DropdownMenu bind:this={dropdown} {anchor} align="left">
{#if editing}
<h5>Edit Column</h5>
<CreateEditColumn onClosed={hideEditor} {field} />
<CreateEditColumnModal onClosed={hideEditor} {field} />
{:else}
<ul>
<li data-cy="edit-column-header" on:click={showEditor}>
@ -72,6 +72,14 @@
</DropdownMenu>
<style>
.container {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: var(--spacing-xs);
}
h5 {
padding: var(--spacing-xl) 0 0 var(--spacing-xl);
margin: 0;

View File

@ -10,17 +10,17 @@
Heading,
} from "@budibase/bbui"
import { FIELDS } from "constants/backend"
import CreateEditRecord from "../modals/CreateEditRecord.svelte"
import DeleteRecordModal from "../modals/DeleteRecord.svelte"
const { open, close } = getContext("simple-modal")
import { CreateEditRecordModal } from "../modals"
import * as api from "../api"
import { notifier } from "builderStore/store/notifications"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
export let row
let anchor
let dropdown
let editing
let confirmDeleteDialog
function showEditor() {
editing = true
@ -32,15 +32,11 @@
close()
}
const deleteRow = () => {
open(
DeleteRecordModal,
{
onClosed: hideEditor,
record: row,
},
{ styleContent: { padding: "0" } }
)
async function deleteRow() {
await api.deleteRecord(row)
notifier.success("Record deleted")
backendUiStore.actions.records.delete(row)
hideEditor()
}
</script>
@ -50,20 +46,26 @@
<DropdownMenu bind:this={dropdown} {anchor} align="left">
{#if editing}
<h5>Edit Row</h5>
<CreateEditRecord onClosed={hideEditor} record={row} />
<CreateEditRecordModal onClosed={hideEditor} record={row} />
{:else}
<ul>
<li data-cy="edit-row" on:click={showEditor}>
<Icon name="edit" />
<span>Edit</span>
</li>
<li data-cy="delete-row" on:click={deleteRow}>
<li data-cy="delete-row" on:click={() => confirmDeleteDialog.show()}>
<Icon name="delete" />
<span>Delete</span>
</li>
</ul>
{/if}
</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>
.ri-more-line:hover {
@ -91,6 +93,7 @@
margin: auto 0px;
align-items: center;
cursor: pointer;
font-size: var(--font-size-xs);
}
li:hover {

View File

@ -95,67 +95,80 @@
</TextButton>
</div>
<Popover bind:this={dropdown} {anchor} align="left">
<h5>Filter</h5>
<div class="input-group-row">
{#each view.filters as filter, idx}
{#if idx === 0}
<p>Where</p>
{:else}
<Select secondary thin bind:value={filter.conjunction}>
{#each CONJUNCTIONS as conjunction}
<option value={conjunction.key}>{conjunction.name}</option>
{/each}
</Select>
{/if}
<Select secondary thin bind:value={filter.key}>
{#each fields as field}
<option value={field}>{field}</option>
<div class="actions">
<h5>Filter</h5>
{#if view.filters.length}
<div class="input-group-row">
{#each view.filters as filter, idx}
{#if idx === 0}
<p>Where</p>
{:else}
<Select secondary thin bind:value={filter.conjunction}>
<option value="">Choose an option</option>
{#each CONJUNCTIONS as conjunction}
<option value={conjunction.key}>{conjunction.name}</option>
{/each}
</Select>
{/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}
</Select>
<Select secondary thin bind:value={filter.condition}>
{#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}>
{#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>
{/if}
<div class="footer">
<Button text on:click={addFilter}>Add Filter</Button>
<div class="buttons">
<Button secondary on:click={dropdown.hide}>Cancel</Button>
<Button primary on:click={saveView}>Save</Button>
</div>
</div>
</div>
</Popover>
<style>
.actions {
display: grid;
grid-gap: var(--spacing-xl);
}
h5 {
margin-bottom: var(--spacing-l);
margin: 0;
font-weight: 500;
}
.button-group {
margin-top: var(--spacing-l);
.footer {
display: flex;
justify-content: space-between;
align-items: center;
}
:global(.button-group > div > button) {
margin-left: var(--spacing-m);
.buttons {
display: flex;
justify-content: flex-end;
gap: var(--spacing-m);
}
.ri-close-circle-fill {
@ -166,7 +179,6 @@
display: grid;
grid-template-columns: minmax(50px, auto) 1fr 1fr 1fr 15px;
gap: var(--spacing-s);
margin-bottom: var(--spacing-l);
align-items: center;
}

View File

@ -42,40 +42,45 @@
</TextButton>
</div>
<Popover bind:this={dropdown} {anchor} align="left">
<h5>Group By</h5>
<div class="input-group-row">
<p>Group By</p>
<Select secondary thin bind:value={view.groupBy}>
<option value={false} />
{#each fields as field}
<option value={field}>{field}</option>
{/each}
</Select>
</div>
<div class="button-group">
<Button secondary on:click={dropdown.hide}>Cancel</Button>
<Button primary on:click={saveView}>Save</Button>
<div class="actions">
<h5>Group By</h5>
<div class="input-group-row">
<p>Group By</p>
<Select secondary thin bind:value={view.groupBy}>
<option value="">Choose an option</option>
{#each fields as field}
<option value={field}>{field}</option>
{/each}
</Select>
</div>
<div class="footer">
<Button secondary on:click={dropdown.hide}>Cancel</Button>
<Button primary on:click={saveView}>Save</Button>
</div>
</div>
</Popover>
<style>
.actions {
display: grid;
grid-gap: var(--spacing-xl);
}
h5 {
margin-bottom: var(--spacing-l);
margin: 0;
font-weight: 500;
}
.button-group {
margin-top: var(--spacing-l);
.footer {
display: flex;
justify-content: flex-end;
gap: var(--spacing-s);
gap: var(--spacing-m);
}
.input-group-row {
display: grid;
grid-template-columns: 75px 1fr 20px 1fr;
grid-template-columns: 75px 1fr;
gap: var(--spacing-s);
margin-bottom: var(--spacing-l);
align-items: center;
}

View File

@ -48,32 +48,30 @@
</TextButton>
</div>
<Popover bind:this={dropdown} {anchor} align="left">
<h5>Create View</h5>
<div class="input-group-column">
<div class="actions">
<h5>Create View</h5>
<Input placeholder="View Name" thin bind:value={name} />
</div>
<div class="button-group">
<Button secondary on:click={dropdown.hide}>Cancel</Button>
<Button primary on:click={saveView}>Save View</Button>
<div class="footer">
<Button secondary on:click={dropdown.hide}>Cancel</Button>
<Button primary on:click={saveView}>Save View</Button>
</div>
</div>
</Popover>
<style>
h5 {
margin-bottom: var(--spacing-l);
margin: 0;
font-weight: 500;
}
.button-group {
margin-top: var(--spacing-l);
display: flex;
justify-content: flex-end;
gap: var(--spacing-s);
.actions {
display: grid;
grid-gap: var(--spacing-xl);
}
.input-group-column {
.footer {
display: flex;
flex-direction: column;
gap: var(--spacing-s);
justify-content: flex-end;
gap: var(--spacing-m);
}
</style>

View File

@ -31,52 +31,36 @@
<Button primary wide on:click={dropdown.show}>Create New Table</Button>
</div>
<DropdownMenu bind:this={dropdown} {anchor} align="left">
<div class="container">
<div class="actions">
<h5>Create Table</h5>
<Input
data-cy="table-name-input"
placeholder="Table Name"
thin
bind:value={name} />
</div>
<footer>
<div class="button-margin-3">
<footer>
<Button secondary on:click={onClosed}>Cancel</Button>
</div>
<div class="button-margin-4">
<Button primary on:click={saveTable}>Save</Button>
</div>
</footer>
</footer>
</div>
</DropdownMenu>
<style>
.actions {
padding: var(--spacing-xl);
display: grid;
grid-gap: var(--spacing-xl);
min-width: 400px;
}
h5 {
margin-bottom: var(--spacing-l);
margin: 0;
font-weight: 500;
}
.container {
padding: var(--spacing-l);
margin: 0;
}
footer {
padding: 20px;
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;
display: flex;
justify-content: flex-end;
gap: var(--spacing-m);
}
</style>

View File

@ -1,18 +1,17 @@
<script>
import { getContext } from "svelte"
import { backendUiStore } from "builderStore"
import { notifier } from "builderStore/store/notifications"
import { DropdownMenu, Button, Icon, Input, Select } from "@budibase/bbui"
import { FIELDS } from "constants/backend"
import DeleteTableModal from "components/database/DataTable/modals/DeleteTable.svelte"
const { open, close } = getContext("simple-modal")
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
export let table
let anchor
let dropdown
let editing
let confirmDeleteDialog
function showEditor() {
editing = true
@ -24,69 +23,83 @@
close()
}
const deleteTable = () => {
open(
DeleteTableModal,
{
onClosed: close,
table,
},
{ styleContent: { padding: "0" } }
)
async function deleteTable() {
await backendUiStore.actions.models.delete(table)
notifier.success("Table deleted")
}
function save() {
backendUiStore.actions.models.save(table)
async function save() {
await backendUiStore.actions.models.save(table)
notifier.success("Table renamed successfully")
hideEditor()
}
</script>
<div bind:this={anchor} on:click={dropdown.show}>
<div bind:this={anchor} class="icon" on:click={dropdown.show}>
<i class="ri-more-line" />
</div>
<DropdownMenu bind:this={dropdown} {anchor} align="left">
<DropdownMenu align="left" {anchor} bind:this={dropdown}>
{#if editing}
<h5>Edit Table</h5>
<div class="container">
<div class="actions">
<h5>Edit Table</h5>
<Input placeholder="Table Name" thin bind:value={table.name} />
</div>
<footer>
<div class="button-margin-3">
<footer>
<Button secondary on:click={hideEditor}>Cancel</Button>
</div>
<div class="button-margin-4">
<Button primary on:click={save}>Save</Button>
</div>
</footer>
</footer>
</div>
{:else}
<ul>
<li on:click={showEditor}>
<Icon name="edit" />
Edit
</li>
<li data-cy="delete-table" on:click={deleteTable}>
<li data-cy="delete-table" on:click={() => confirmDeleteDialog.show()}>
<Icon name="delete" />
Delete
</li>
</ul>
{/if}
</DropdownMenu>
<ConfirmDialog
bind:this={confirmDeleteDialog}
body={`Are you sure you wish to delete the table '${table.name}'? Your data will be deleted and this action cannot be undone.`}
okText="Delete Table"
onOk={deleteTable}
title="Confirm Delete" />
<style>
div.icon {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
div.icon i {
font-size: 16px;
}
.actions {
padding: var(--spacing-xl);
display: grid;
grid-gap: var(--spacing-xl);
min-width: 400px;
}
h5 {
padding: var(--spacing-xl) 0 0 var(--spacing-xl);
margin: 0;
font-weight: 500;
}
.container {
padding: var(--spacing-xl);
footer {
display: flex;
justify-content: flex-end;
gap: var(--spacing-m);
}
ul {
padding: var(--spacing-xl) 0 0 var(--spacing-xl);
list-style: none;
padding-left: 0;
margin: 0;
padding: var(--spacing-s) 0;
}
@ -109,29 +122,4 @@
li:active {
color: var(--blue);
}
footer {
padding: 20px;
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-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>

View File

@ -1,20 +1,19 @@
<script>
import { goto } from "@sveltech/routify"
import { getContext } from "svelte"
import { backendUiStore } from "builderStore"
import { notifier } from "builderStore/store/notifications"
import { DropdownMenu, Button, Icon, Input, Select } from "@budibase/bbui"
import { FIELDS } from "constants/backend"
import DeleteViewModal from "components/database/DataTable/modals/DeleteView.svelte"
const { open, close } = getContext("simple-modal")
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
export let view
let anchor
let dropdown
let editing
let originalName = view.name
let confirmDeleteDialog
function showEditor() {
editing = true
@ -26,73 +25,89 @@
close()
}
const deleteView = () => {
open(
DeleteViewModal,
{
onClosed: close,
viewName: view.name,
},
{ styleContent: { padding: "0" } }
)
}
function save() {
backendUiStore.actions.views.save({
async function save() {
await backendUiStore.actions.views.save({
originalName,
...view,
})
notifier.success("Renamed View Successfully.")
notifier.success("View renamed successfully")
hideEditor()
}
async function deleteView() {
const name = view.name
const id = view.modelId
await backendUiStore.actions.views.delete(name)
notifier.success("View deleted")
$goto(`./model/${id}`)
}
</script>
<div bind:this={anchor} on:click={dropdown.show}>
<div bind:this={anchor} class="icon" on:click={dropdown.show}>
<i class="ri-more-line" />
</div>
<DropdownMenu bind:this={dropdown} {anchor} align="left">
<DropdownMenu align="left" {anchor} bind:this={dropdown}>
{#if editing}
<h5>Edit View</h5>
<div class="container">
<div class="actions">
<h5>Edit View</h5>
<Input placeholder="View Name" thin bind:value={view.name} />
</div>
<footer>
<div class="button-margin-3">
<footer>
<Button secondary on:click={hideEditor}>Cancel</Button>
</div>
<div class="button-margin-4">
<Button primary on:click={save}>Save</Button>
</div>
</footer>
</footer>
</div>
{:else}
<ul>
<li on:click={showEditor}>
<Icon name="edit" />
Edit
</li>
<li data-cy="delete-view" on:click={deleteView}>
<li data-cy="delete-view" on:click={() => confirmDeleteDialog.show()}>
<Icon name="delete" />
Delete
</li>
</ul>
{/if}
</DropdownMenu>
<ConfirmDialog
bind:this={confirmDeleteDialog}
body={`Are you sure you wish to delete the view '${view.name}'? Your data will be deleted and this action cannot be undone.`}
okText="Delete View"
onOk={deleteView}
title="Confirm Delete" />
<style>
div.icon {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
div.icon i {
font-size: 16px;
}
.actions {
padding: var(--spacing-xl);
display: grid;
grid-gap: var(--spacing-xl);
min-width: 400px;
}
h5 {
padding: var(--spacing-xl) 0 0 var(--spacing-xl);
margin: 0;
font-weight: 500;
}
.container {
padding: var(--spacing-xl);
footer {
display: flex;
justify-content: flex-end;
gap: var(--spacing-m);
}
ul {
padding: var(--spacing-xl) 0 0 var(--spacing-xl);
list-style: none;
padding-left: 0;
margin: 0;
padding: var(--spacing-s) 0;
}
@ -115,29 +130,4 @@
li:active {
color: var(--blue);
}
footer {
padding: 20px;
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-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>

View File

@ -19,26 +19,24 @@
<style>
.indented {
grid-template-columns: 50px 1fr 20px;
grid-template-columns: 46px 1fr 20px;
}
.indented i {
justify-self: end;
}
div {
padding: 0 10px 0 10px;
height: 36px;
border-radius: 5px;
padding: var(--spacing-s) var(--spacing-m);
border-radius: var(--border-radius-m);
display: grid;
grid-template-columns: 30px 1fr 20px;
grid-template-columns: 20px 1fr 20px;
align-items: center;
transition: 0.3s background-color;
color: var(--ink);
font-weight: 400;
font-size: 14px;
margin-top: 4px;
margin-bottom: 4px;
margin-bottom: var(--spacing-xs);
grid-gap: var(--spacing-s);
}
.selected {
@ -53,6 +51,5 @@
i {
color: var(--grey-7);
font-size: 20px;
margin-right: 8px;
}
</style>

View File

@ -30,7 +30,7 @@
{#if $backendUiStore.selectedDatabase && $backendUiStore.selectedDatabase._id}
<div class="hierarchy">
<div class="components-list-container">
<h4>Tables</h4>
<h5>Tables</h5>
<CreateTablePopover />
<div class="hierarchy-items-container">
{#each $backendUiStore.models as model}
@ -63,17 +63,18 @@
</div>
<style>
h4 {
font-weight: 500;
h5 {
font-size: 18px;
font-weight: 600;
margin-top: 0;
margin-bottom: var(--spacing-xl);
}
.items-root {
display: flex;
flex-direction: column;
max-height: 100%;
height: 100%;
background: var(--white);
padding: 20px;
justify-content: flex-start;
align-items: stretch;
}
.hierarchy {
@ -82,7 +83,7 @@
}
.hierarchy-items-container {
margin-top: 20px;
margin-top: var(--spacing-xl);
flex: 1 1 auto;
}
</style>

View File

@ -34,7 +34,9 @@
<Modal id={title} bind:this={theModal}>
<h2>{title}</h2>
<Spacer extraLarge />
<slot class="rows">{body}</slot>
<div class="content">
<slot class="rows">{body}</slot>
</div>
<Spacer extraLarge />
<div class="modal-footer">
<Button red wide on:click={ok}>{okText}</Button>
@ -54,4 +56,9 @@
display: grid;
grid-gap: var(--spacing-s);
}
.content {
white-space: normal;
font-size: var(--font-size-s);
}
</style>

View File

@ -11,6 +11,4 @@
}
</script>
<div class="bb-margin-m">
<DatePicker placeholder={label} on:change={onChange} {value} />
</div>
<DatePicker placeholder={label} on:change={onChange} {value} />

View File

@ -26,7 +26,6 @@
.numberbox {
display: grid;
align-items: center;
margin-bottom: 16px;
}
label {

View File

@ -17,14 +17,11 @@
<div class="margin">
<label class="label">{label}</label>
<textarea value={valuesText} on:change={inputChanged} />
</div>
<style>
.margin {
margin-bottom: 16px;
display: grid;
}
.label {

View File

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

View File

@ -1,64 +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 table
export let onClosed
function deleteTable() {
backendUiStore.actions.models.delete(table)
}
</script>
<section>
<div class="content">
<header>
<i class="ri-information-line alert" />
<h4 class="budibase__title--4">Delete Table</h4>
</header>
<p>
Are you sure you want to delete this table? 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 backendUiStore.actions.models.delete(table)
notifier.danger('Table deleted')
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>

View File

@ -1,62 +0,0 @@
<script>
import { goto } from "@sveltech/routify"
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 viewName
export let onClosed
</script>
<section>
<div class="content">
<header>
<i class="ri-information-line alert" />
<h4 class="budibase__title--4">Delete View</h4>
</header>
<p>
Are you sure you want to delete this view? 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 backendUiStore.actions.views.delete(viewName)
notifier.danger(`View ${viewName} deleted.`)
$goto(`./backend`)
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>

View File

@ -1,2 +0,0 @@
export { default as DeleteRecordModal } from "./DeleteRecord.svelte"
export { default as CreateEditRecordModal } from "./CreateEditRecord.svelte"

View File

@ -1,20 +0,0 @@
<script>
import { isActive, url, goto } from "@sveltech/routify"
export let label = ""
export let href
</script>
<div
on:click={() => $goto(href)}
class="budibase__nav-item backend-nav-item"
class:selected={$isActive(href)}>
{label}
</div>
<style>
.backend-nav-item {
padding-left: 25px;
cursor: pointer;
}
</style>

View File

@ -1,8 +1,8 @@
<script>
import { getContext } from "svelte"
import { store, backendUiStore } from "builderStore"
import * as api from "components/database/DataTable/api"
import ModelNavigator from "components/nav/ModelNavigator/ModelNavigator.svelte"
import * as api from "components/backend/DataTable/api"
import ModelNavigator from "components/backend/ModelNavigator/ModelNavigator.svelte"
</script>
<!-- routify:options index=1 -->
@ -17,7 +17,7 @@
<style>
.root {
height: 100%;
height: calc(100vh - 60px);
display: grid;
grid-template-columns: 300px minmax(0, 1fr);
background: var(--grey-1);
@ -25,11 +25,12 @@
}
.content {
flex: 1 1 auto;
margin: 20px 40px;
padding: var(--spacing-xl) 40px;
overflow-y: auto;
}
.nav {
flex: 0 1 auto;
width: 300px;
height: 100%;
overflow-y: auto;
background: var(--white);
padding: var(--spacing-xl);
}
</style>

View File

@ -1,11 +1,11 @@
<script>
import { getContext } from "svelte"
import { Button } from "@budibase/bbui"
import ModelDataTable from "components/database/DataTable"
import ModelDataTable from "components/backend/DataTable"
import { backendUiStore } from "builderStore"
import ActionButton from "components/common/ActionButton.svelte"
import * as api from "components/database/DataTable/api"
import { CreateEditRecordModal } from "components/database/DataTable/modals"
import * as api from "components/backend/DataTable/api"
import { CreateEditRecordModal } from "components/backend/DataTable/modals"
const { open, close } = getContext("simple-modal")
@ -15,12 +15,13 @@
{#if $backendUiStore.selectedDatabase._id && selectedModel.name}
<ModelDataTable />
{:else}
<i style="color: var(--grey-4)">create your first table to start building</i>
<i>Create your first table to start building</i>
{/if}
<style>
i {
font-size: 20px;
margin-right: 10px;
padding-bottom: 10px;
color: var(--grey-4);
}
</style>

View File

@ -21,9 +21,7 @@
</script>
<div class="root">
<div class="node-view">
<slot />
</div>
<slot />
</div>
<style>
@ -31,9 +29,4 @@
height: 100%;
position: relative;
}
.node-view {
overflow-y: auto;
flex: 1 1 auto;
}
</style>

View File

@ -22,5 +22,13 @@
</script>
{#if $backendUiStore.models.length === 0}
Please create a table
<i>Create your first table to start building</i>
{:else}Please select a table{/if}
<style>
i {
font-size: 20px;
padding-bottom: 10px;
color: var(--grey-4);
}
</style>

View File

@ -1,11 +1,11 @@
<script>
import { getContext } from "svelte"
import { Button } from "@budibase/bbui"
import ViewDataTable from "components/database/DataTable/ViewDataTable"
import ViewDataTable from "components/backend/DataTable/ViewDataTable"
import { backendUiStore } from "builderStore"
import ActionButton from "components/common/ActionButton.svelte"
import * as api from "components/database/DataTable/api"
import { CreateEditRecordModal } from "components/database/DataTable/modals"
import * as api from "components/backend/DataTable/api"
import { CreateEditRecordModal } from "components/backend/DataTable/modals"
const { open, close } = getContext("simple-modal")

View File

@ -709,23 +709,14 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
"@budibase/bbui@^1.34.2":
version "1.34.2"
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.34.2.tgz#e4fcc728dc8d51a918f8ebd5c3f0b0afacfa4047"
integrity sha512-6RusGPZnEpHx1gtGcjk/lFLgMgFdDpSIxB8v2MiA+kp+uP1pFlzegbaDh+/JXyqFwK7HO91I0yXXBoPjibi7Aw==
"@budibase/bbui@^1.34.5":
version "1.34.5"
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.34.5.tgz#357f0b3c3aa139b21d5d38a11fd39f0f79a5d1db"
integrity sha512-nMEVPRLuz+BXQbCRiKLBr0uT4mx1PbUZuviJHiROcj8wWvGwKhEmFYilBTZhXGboRE5VSV+M6ImThCDIjYEQlQ==
dependencies:
sirv-cli "^0.4.6"
svelte-flatpickr "^2.4.0"
"@budibase/client@^0.1.21":
version "0.1.21"
resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.1.21.tgz#db414445c132b373f6c25e39d62628eb60cd8ac3"
integrity sha512-/ju0vYbWh9MUjmxkGNlOL4S/VQd4p5mbz5rHu0yt55ak9t/yyzI6PzBBxlucBeRbXYd9OFynFjy1pvYt1v+z9Q==
dependencies:
deep-equal "^2.0.1"
mustache "^4.0.1"
regexparam "^1.3.0"
"@budibase/colorpicker@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@budibase/colorpicker/-/colorpicker-1.0.1.tgz#940c180e7ebba0cb0756c4c8ef13f5dfab58e810"
@ -1402,11 +1393,6 @@ array-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
array-filter@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83"
integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=
array-union@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
@ -1461,13 +1447,6 @@ atob@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5"
integrity sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==
dependencies:
array-filter "^1.0.0"
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
@ -2417,26 +2396,6 @@ decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
deep-equal@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.3.tgz#cad1c15277ad78a5c01c49c2dee0f54de8a6a7b0"
integrity sha512-Spqdl4H+ky45I9ByyJtXteOm9CaIrPmnIPmOhrkKGNYWeDgCvJ8jNYVCTjChxW4FqGuZnLHADc8EKRMX6+CgvA==
dependencies:
es-abstract "^1.17.5"
es-get-iterator "^1.1.0"
is-arguments "^1.0.4"
is-date-object "^1.0.2"
is-regex "^1.0.5"
isarray "^2.0.5"
object-is "^1.1.2"
object-keys "^1.1.1"
object.assign "^4.1.0"
regexp.prototype.flags "^1.3.0"
side-channel "^1.0.2"
which-boxed-primitive "^1.0.1"
which-collection "^1.0.1"
which-typed-array "^1.1.2"
deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
@ -2606,54 +2565,6 @@ es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.5:
string.prototype.trimleft "^2.1.1"
string.prototype.trimright "^2.1.1"
es-abstract@^1.17.4:
version "1.17.6"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a"
integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==
dependencies:
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.1"
is-callable "^1.2.0"
is-regex "^1.1.0"
object-inspect "^1.7.0"
object-keys "^1.1.1"
object.assign "^4.1.0"
string.prototype.trimend "^1.0.1"
string.prototype.trimstart "^1.0.1"
es-abstract@^1.18.0-next.0:
version "1.18.0-next.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.0.tgz#b302834927e624d8e5837ed48224291f2c66e6fc"
integrity sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==
dependencies:
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.1"
is-callable "^1.2.0"
is-negative-zero "^2.0.0"
is-regex "^1.1.1"
object-inspect "^1.8.0"
object-keys "^1.1.1"
object.assign "^4.1.0"
string.prototype.trimend "^1.0.1"
string.prototype.trimstart "^1.0.1"
es-get-iterator@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.0.tgz#bb98ad9d6d63b31aacdc8f89d5d0ee57bcb5b4c8"
integrity sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==
dependencies:
es-abstract "^1.17.4"
has-symbols "^1.0.1"
is-arguments "^1.0.4"
is-map "^2.0.1"
is-set "^2.0.1"
is-string "^1.0.5"
isarray "^2.0.5"
es-to-primitive@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
@ -2960,7 +2871,7 @@ for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
foreach@^2.0.5, foreach@~2.0.1:
foreach@~2.0.1:
version "2.0.5"
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k=
@ -3334,31 +3245,16 @@ is-accessor-descriptor@^1.0.0:
dependencies:
kind-of "^6.0.0"
is-arguments@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3"
integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
is-bigint@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.0.tgz#73da8c33208d00f130e9b5e15d23eac9215601c4"
integrity sha512-t5mGUXC/xRheCK431ylNiSkGGpBp8bHENBcENTkDT6ppwPzEVxNGZRvgvmOEfbWkFhA7D2GEuE2mmQTr78sl2g==
is-binary-path@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
dependencies:
binary-extensions "^2.0.0"
is-boolean-object@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.1.tgz#10edc0900dd127697a92f6f9807c7617d68ac48e"
integrity sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==
is-buffer@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@ -3367,11 +3263,6 @@ is-callable@^1.1.4, is-callable@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab"
is-callable@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.1.tgz#4d1e21a4f437509d25ce55f8184350771421c96d"
integrity sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==
is-ci@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
@ -3390,7 +3281,7 @@ is-data-descriptor@^1.0.0:
dependencies:
kind-of "^6.0.0"
is-date-object@^1.0.1, is-date-object@^1.0.2:
is-date-object@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
@ -3455,25 +3346,10 @@ is-installed-globally@^0.3.2:
global-dirs "^2.0.1"
is-path-inside "^3.0.1"
is-map@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.1.tgz#520dafc4307bb8ebc33b813de5ce7c9400d644a1"
integrity sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==
is-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
is-negative-zero@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461"
integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=
is-number-object@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197"
integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==
is-number@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
@ -3530,18 +3406,6 @@ is-regex@^1.0.5:
dependencies:
has "^1.0.3"
is-regex@^1.1.0, is-regex@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9"
integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==
dependencies:
has-symbols "^1.0.1"
is-set@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.1.tgz#d1604afdab1724986d30091575f54945da7e5f43"
integrity sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==
is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
@ -3550,41 +3414,16 @@ is-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
is-string@^1.0.4, is-string@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
is-symbol@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
dependencies:
has-symbols "^1.0.1"
is-typed-array@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d"
integrity sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ==
dependencies:
available-typed-arrays "^1.0.0"
es-abstract "^1.17.4"
foreach "^2.0.5"
has-symbols "^1.0.1"
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
is-weakmap@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2"
integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==
is-weakset@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83"
integrity sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==
is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
@ -3605,11 +3444,6 @@ isarray@1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
isarray@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
isbuffer@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/isbuffer/-/isbuffer-0.0.0.tgz#38c146d9df528b8bf9b0701c3d43cf12df3fc39b"
@ -4729,19 +4563,6 @@ object-inspect@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
object-inspect@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
object-is@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6"
integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.5"
object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
@ -5252,19 +5073,6 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
regexp.prototype.flags@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75"
integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.0-next.1"
regexparam@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-1.3.0.tgz#2fe42c93e32a40eff6235d635e0ffa344b92965f"
integrity sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g==
regexpu-core@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938"
@ -5672,14 +5480,6 @@ shortid@^2.2.15:
dependencies:
nanoid "^2.1.0"
side-channel@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.3.tgz#cdc46b057550bbab63706210838df5d4c19519c3"
integrity sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g==
dependencies:
es-abstract "^1.18.0-next.0"
object-inspect "^1.8.0"
signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
@ -5906,7 +5706,7 @@ string-width@^4.2.0:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.0"
string.prototype.trimend@^1.0.0, string.prototype.trimend@^1.0.1:
string.prototype.trimend@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
dependencies:
@ -5929,7 +5729,7 @@ string.prototype.trimright@^2.1.1:
es-abstract "^1.17.5"
string.prototype.trimend "^1.0.0"
string.prototype.trimstart@^1.0.0, string.prototype.trimstart@^1.0.1:
string.prototype.trimstart@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
dependencies:
@ -6384,43 +6184,10 @@ whatwg-url@^8.0.0:
tr46 "^2.0.2"
webidl-conversions "^5.0.0"
which-boxed-primitive@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz#cbe8f838ebe91ba2471bb69e9edbda67ab5a5ec1"
integrity sha512-7BT4TwISdDGBgaemWU0N0OU7FeAEJ9Oo2P1PHRm/FCWoEi2VLWC9b6xvxAA3C/NMpxg3HXVgi0sMmGbNUbNepQ==
dependencies:
is-bigint "^1.0.0"
is-boolean-object "^1.0.0"
is-number-object "^1.0.3"
is-string "^1.0.4"
is-symbol "^1.0.2"
which-collection@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906"
integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==
dependencies:
is-map "^2.0.1"
is-set "^2.0.1"
is-weakmap "^2.0.1"
is-weakset "^2.0.1"
which-module@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
which-typed-array@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2"
integrity sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ==
dependencies:
available-typed-arrays "^1.0.2"
es-abstract "^1.17.5"
foreach "^2.0.5"
function-bind "^1.1.1"
has-symbols "^1.0.1"
is-typed-array "^1.1.3"
which@^1.2.9, which@^1.3.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"

View File

@ -1,10 +1,10 @@
const recordController = require("../../api/controllers/record")
module.exports.definition = {
description: "Delete a record from your database",
description: "Delete a row from your database",
icon: "ri-delete-bin-line",
name: "Delete Record",
tagline: "Delete a {{inputs.enriched.model.name}} record",
name: "Delete Row",
tagline: "Delete a {{inputs.enriched.model.name}} row",
type: "ACTION",
stepId: "DELETE_RECORD",
inputs: {},
@ -18,11 +18,11 @@ module.exports.definition = {
},
id: {
type: "string",
title: "Record ID",
title: "Row ID",
},
revision: {
type: "string",
title: "Record Revision",
title: "Row Revision",
},
},
required: ["modelId", "id", "revision"],
@ -32,7 +32,7 @@ module.exports.definition = {
record: {
type: "object",
customType: "record",
description: "The deleted record",
description: "The deleted row",
},
response: {
type: "object",

View File

@ -2,10 +2,10 @@ const recordController = require("../../api/controllers/record")
const automationUtils = require("../automationUtils")
module.exports.definition = {
name: "Save Record",
tagline: "Save a {{inputs.enriched.model.name}} record",
name: "Create Row",
tagline: "Create a {{inputs.enriched.model.name}} row",
icon: "ri-save-3-fill",
description: "Save a record to your database",
description: "Add a row to your database",
type: "ACTION",
stepId: "SAVE_RECORD",
inputs: {},
@ -32,7 +32,7 @@ module.exports.definition = {
record: {
type: "object",
customType: "record",
description: "The new record",
description: "The new row",
},
response: {
type: "object",
@ -44,11 +44,11 @@ module.exports.definition = {
},
id: {
type: "string",
description: "The identifier of the new record",
description: "The identifier of the new row",
},
revision: {
type: "string",
description: "The revision of the new record",
description: "The revision of the new row",
},
},
required: ["success", "id", "revision"],

View File

@ -2,10 +2,10 @@ const recordController = require("../../api/controllers/record")
const automationUtils = require("../automationUtils")
module.exports.definition = {
name: "Update Record",
name: "Update Row",
tagline: "Update a {{inputs.enriched.model.name}} record",
icon: "ri-refresh-fill",
description: "Update a record to your database",
description: "Update a row in your database",
type: "ACTION",
stepId: "UPDATE_RECORD",
inputs: {},
@ -15,11 +15,11 @@ module.exports.definition = {
record: {
type: "object",
customType: "record",
title: "Record",
title: "Table",
},
recordId: {
type: "string",
title: "Record ID",
title: "Row ID",
},
},
required: ["record", "recordId"],

View File

@ -11,11 +11,11 @@ const FAKE_DATETIME = "1970-01-01T00:00:00.000Z"
const BUILTIN_DEFINITIONS = {
RECORD_SAVED: {
name: "Record Saved",
name: "Row Saved",
event: "record:save",
icon: "ri-save-line",
tagline: "Record is added to {{inputs.enriched.model.name}}",
description: "Fired when a record is saved to your database",
tagline: "Row is added to {{inputs.enriched.model.name}}",
description: "Fired when a row is saved to your database",
stepId: "RECORD_SAVED",
inputs: {},
schema: {
@ -34,15 +34,15 @@ const BUILTIN_DEFINITIONS = {
record: {
type: "object",
customType: "record",
description: "The new record that was saved",
description: "The new row that was saved",
},
id: {
type: "string",
description: "Record ID - can be used for updating",
description: "Row ID - can be used for updating",
},
revision: {
type: "string",
description: "Revision of record",
description: "Revision of row",
},
},
required: ["record", "id"],
@ -51,11 +51,11 @@ const BUILTIN_DEFINITIONS = {
type: "TRIGGER",
},
RECORD_DELETED: {
name: "Record Deleted",
name: "Row Deleted",
event: "record:delete",
icon: "ri-delete-bin-line",
tagline: "Record is deleted from {{inputs.enriched.model.name}}",
description: "Fired when a record is deleted from your database",
tagline: "Row is deleted from {{inputs.enriched.model.name}}",
description: "Fired when a row is deleted from your database",
stepId: "RECORD_DELETED",
inputs: {},
schema: {
@ -74,7 +74,7 @@ const BUILTIN_DEFINITIONS = {
record: {
type: "object",
customType: "record",
description: "The record that was deleted",
description: "The row that was deleted",
},
},
required: ["record", "id"],

View File

@ -37,7 +37,7 @@
"dependencies": {
"@beyonk/svelte-googlemaps": "^2.2.0",
"@fortawesome/fontawesome-free": "^5.14.0",
"@budibase/bbui": "^1.34.2",
"@budibase/bbui": "^1.34.5",
"britecharts": "^2.16.1",
"d3-selection": "^1.4.2",
"fast-sort": "^2.2.0",