new table creation
This commit is contained in:
parent
160703863b
commit
cfe262d602
|
@ -1,22 +0,0 @@
|
||||||
xcontext('Create a Model', () => {
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
cy.visit('localhost:4001/_builder')
|
|
||||||
// https://on.cypress.io/type
|
|
||||||
cy.createApp('Model App', 'Model App Description')
|
|
||||||
})
|
|
||||||
|
|
||||||
// https://on.cypress.io/interacting-with-elements
|
|
||||||
it('should create a new model', () => {
|
|
||||||
|
|
||||||
cy.createModel('dog', 'name', 'age')
|
|
||||||
|
|
||||||
// Check if model exists
|
|
||||||
cy.get('.title').should('have.text', 'dog')
|
|
||||||
})
|
|
||||||
it('should add a record', () => {
|
|
||||||
cy.addRecord('bob', '15')
|
|
||||||
|
|
||||||
cy.contains('bob').should('have.text', 'bob')
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
xcontext('Create a Table', () => {
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
cy.visit('localhost:4001/_builder')
|
||||||
|
// https://on.cypress.io/type
|
||||||
|
cy.createApp('Table App', 'Table App Description')
|
||||||
|
})
|
||||||
|
|
||||||
|
// https://on.cypress.io/interacting-with-elements
|
||||||
|
it('should create a new Table', () => {
|
||||||
|
|
||||||
|
cy.createTable('dog', 'name', 'age')
|
||||||
|
|
||||||
|
// Check if Table exists
|
||||||
|
cy.get('.title').should('have.text', 'dog')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('adds a new column to the table', () => {
|
||||||
|
cy.addRecord('bob', '15')
|
||||||
|
|
||||||
|
cy.contains('bob').should('have.text', 'bob')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('updates a column on the table', () => {
|
||||||
|
cy.addRecord('bob', '15')
|
||||||
|
|
||||||
|
cy.contains('bob').should('have.text', 'bob')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('edits a record', () => {
|
||||||
|
cy.addRecord('bob', '15')
|
||||||
|
|
||||||
|
cy.contains('bob').should('have.text', 'bob')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('deletes a record', () => {
|
||||||
|
cy.addRecord('bob', '15')
|
||||||
|
|
||||||
|
cy.contains('bob').should('have.text', 'bob')
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
|
@ -66,6 +66,7 @@
|
||||||
"codemirror": "^5.51.0",
|
"codemirror": "^5.51.0",
|
||||||
"date-fns": "^1.29.0",
|
"date-fns": "^1.29.0",
|
||||||
"deepmerge": "^4.2.2",
|
"deepmerge": "^4.2.2",
|
||||||
|
"fast-sort": "^2.2.0",
|
||||||
"feather-icons": "^4.21.0",
|
"feather-icons": "^4.21.0",
|
||||||
"flatpickr": "^4.5.7",
|
"flatpickr": "^4.5.7",
|
||||||
"lodash": "^4.17.13",
|
"lodash": "^4.17.13",
|
||||||
|
|
|
@ -63,7 +63,7 @@ export const getBackendUiStore = () => {
|
||||||
state.selectedView = `all_${model._id}`
|
state.selectedView = `all_${model._id}`
|
||||||
return state
|
return state
|
||||||
}),
|
}),
|
||||||
save: async ({ model }) => {
|
save: async model => {
|
||||||
const updatedModel = cloneDeep(model)
|
const updatedModel = cloneDeep(model)
|
||||||
|
|
||||||
// update any renamed schema keys to reflect their names
|
// update any renamed schema keys to reflect their names
|
||||||
|
@ -97,14 +97,14 @@ export const getBackendUiStore = () => {
|
||||||
...state.draftModel.schema,
|
...state.draftModel.schema,
|
||||||
[field.name]: cloneDeep(field),
|
[field.name]: cloneDeep(field),
|
||||||
}
|
}
|
||||||
store.actions.models.save({ model: state.draftModel })
|
store.actions.models.save(state.draftModel)
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
deleteField: field => {
|
deleteField: field => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
delete state.draftModel.schema[field.name]
|
delete state.draftModel.schema[field.name]
|
||||||
store.actions.models.save({ model: state.draftModel })
|
store.actions.models.save(state.draftModel)
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount, getContext } from "svelte"
|
import { onMount } from "svelte"
|
||||||
|
import fsort from "fast-sort";
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import { Button, Icon } from "@budibase/bbui"
|
import { Button, Icon } from "@budibase/bbui"
|
||||||
import Select from "components/common/Select.svelte"
|
import Select from "components/common/Select.svelte"
|
||||||
|
@ -10,32 +11,9 @@
|
||||||
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 ColumnHeaderPopover from "./popovers/ColumnHeader.svelte"
|
import ColumnHeaderPopover from "./popovers/ColumnHeader.svelte"
|
||||||
|
import EditRowPopover from "./popovers/EditRow.svelte"
|
||||||
import * as api from "./api"
|
import * as api from "./api"
|
||||||
|
|
||||||
const { open, close } = getContext("simple-modal")
|
|
||||||
|
|
||||||
const editRecord = async row => {
|
|
||||||
open(
|
|
||||||
CreateEditRecordModal,
|
|
||||||
{
|
|
||||||
onClosed: close,
|
|
||||||
record: row,
|
|
||||||
},
|
|
||||||
{ styleContent: { padding: "0" } }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const deleteRecord = async row => {
|
|
||||||
open(
|
|
||||||
DeleteRecordModal,
|
|
||||||
{
|
|
||||||
onClosed: close,
|
|
||||||
record: row,
|
|
||||||
},
|
|
||||||
{ styleContent: { padding: "0" } }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const ITEMS_PER_PAGE = 10
|
const ITEMS_PER_PAGE = 10
|
||||||
// Internal headers we want to hide from the user
|
// Internal headers we want to hide from the user
|
||||||
const INTERNAL_HEADERS = ["_id", "_rev", "modelId", "type"]
|
const INTERNAL_HEADERS = ["_id", "_rev", "modelId", "type"]
|
||||||
|
@ -62,6 +40,8 @@
|
||||||
currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE
|
currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE
|
||||||
)
|
)
|
||||||
: []
|
: []
|
||||||
|
$: sort = $backendUiStore.sort
|
||||||
|
$: sorted = sort ? fsort(data)[sort.direction](sort.column) : data
|
||||||
|
|
||||||
$: headers = Object.keys($backendUiStore.selectedModel.schema).filter(
|
$: headers = Object.keys($backendUiStore.selectedModel.schema).filter(
|
||||||
id => !INTERNAL_HEADERS.includes(id)
|
id => !INTERNAL_HEADERS.includes(id)
|
||||||
|
@ -90,10 +70,6 @@
|
||||||
<div class="table-controls">
|
<div class="table-controls">
|
||||||
<h2 class="title">{$backendUiStore.selectedModel.name}</h2>
|
<h2 class="title">{$backendUiStore.selectedModel.name}</h2>
|
||||||
<div class="popovers">
|
<div class="popovers">
|
||||||
<!-- <Button text small on:click={() => alert('Clicked!')}>
|
|
||||||
<Icon name="view" />
|
|
||||||
Create New View
|
|
||||||
</Button> -->
|
|
||||||
<ColumnPopover />
|
<ColumnPopover />
|
||||||
<RowPopover />
|
<RowPopover />
|
||||||
</div>
|
</div>
|
||||||
|
@ -113,33 +89,13 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#if paginatedData.length === 0}
|
{#if sorted.length === 0}
|
||||||
<div class="no-data">No Data.</div>
|
<div class="no-data">No Data.</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#each paginatedData as row}
|
{#each sorted as row}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div class="uk-inline">
|
<EditRowPopover {row} />
|
||||||
<i class="ri-more-line" />
|
|
||||||
<div uk-dropdown="mode: click">
|
|
||||||
<ul class="uk-nav uk-dropdown-nav">
|
|
||||||
<li
|
|
||||||
on:click={() => {
|
|
||||||
editRecord(row)
|
|
||||||
}}>
|
|
||||||
<i class="ri-edit-line" />
|
|
||||||
<div class="label">Edit</div>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
on:click={() => {
|
|
||||||
deleteRecord(row)
|
|
||||||
}}>
|
|
||||||
<i class="ri-delete-bin-2-line" />
|
|
||||||
<div class="label">Delete</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
{#each headers as header}
|
{#each headers as header}
|
||||||
<td class="hoverable">
|
<td class="hoverable">
|
||||||
|
|
|
@ -30,10 +30,6 @@
|
||||||
field.constraints = FIELDS[field.type.toUpperCase()].constraints
|
field.constraints = FIELDS[field.type.toUpperCase()].constraints
|
||||||
}
|
}
|
||||||
|
|
||||||
function closed() {
|
|
||||||
onClosed()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function saveColumn() {
|
async function saveColumn() {
|
||||||
// if existing
|
// if existing
|
||||||
// update the name and type
|
// update the name and type
|
|
@ -20,10 +20,6 @@
|
||||||
? Object.entries($backendUiStore.selectedModel.schema)
|
? Object.entries($backendUiStore.selectedModel.schema)
|
||||||
: []
|
: []
|
||||||
|
|
||||||
function closed() {
|
|
||||||
onClosed()
|
|
||||||
}
|
|
||||||
|
|
||||||
const isSelect = meta =>
|
const isSelect = meta =>
|
||||||
meta.type === "string" &&
|
meta.type === "string" &&
|
||||||
meta.constraints &&
|
meta.constraints &&
|
||||||
|
@ -68,7 +64,6 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<h5>Add New Row</h5>
|
|
||||||
<ErrorsBox {errors} />
|
<ErrorsBox {errors} />
|
||||||
<form on:submit|preventDefault class="uk-form-stacked">
|
<form on:submit|preventDefault class="uk-form-stacked">
|
||||||
{#each modelSchema as [key, meta]}
|
{#each modelSchema as [key, meta]}
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import "@testing-library/jest-dom/extend-expect"
|
import "@testing-library/jest-dom/extend-expect"
|
||||||
import { render, fireEvent } from "@testing-library/svelte"
|
import { render, fireEvent } from "@testing-library/svelte"
|
||||||
import CreateEditTable from "../CreateEditTable.svelte";
|
import CreateEditColumn from "../CreateEditColumn.svelte";
|
||||||
|
|
||||||
const testField = {
|
const testField = {
|
||||||
field: {},
|
field: {},
|
||||||
name: "Yeet"
|
name: "Yeet"
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("<CreateEditTable />", () => {
|
describe("<CreateEditColumn />", () => {
|
||||||
|
|
||||||
describe("New Column", () => {
|
describe("New Column", () => {
|
||||||
it("shows proper heading when rendered", () => {
|
it("shows proper heading when rendered", () => {
|
||||||
const { getByText } = render(CreateEditTable, { name: 'World' })
|
const { getByText } = render(CreateEditColumn, { name: 'World' })
|
||||||
|
|
||||||
expect(getByText('Hello World!')).toBeInTheDocument()
|
expect(getByText('Hello World!')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("Edit Existing Column", () => {
|
describe("Edit Existing Column", () => {
|
||||||
const { getByText } = render(CreateEditTable, testField)
|
const { getByText } = render(CreateEditColumn, testField)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import { FIELDS } from "constants/backend"
|
import { FIELDS } from "constants/backend"
|
||||||
import { ModelSetupNav } from "components/nav/ModelSetupNav"
|
import { ModelSetupNav } from "components/nav/ModelSetupNav"
|
||||||
import ModelFieldEditor from "components/nav/ModelSetupNav/ModelFieldEditor.svelte"
|
import ModelFieldEditor from "components/nav/ModelSetupNav/ModelFieldEditor.svelte"
|
||||||
import CreateEditTable from "../modals/CreateEditTable.svelte"
|
import CreateEditColumn from "../modals/CreateEditColumn.svelte"
|
||||||
|
|
||||||
let anchor
|
let anchor
|
||||||
let dropdown
|
let dropdown
|
||||||
|
@ -18,10 +18,13 @@
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<DropdownMenu bind:this={dropdown} {anchor} align="left">
|
<DropdownMenu bind:this={dropdown} {anchor} align="left">
|
||||||
<h5>Create Column</h5>
|
<h4>Create Column</h4>
|
||||||
<CreateEditTable onClosed={dropdown.hide} />
|
<CreateEditColumn onClosed={dropdown.hide} />
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
h4 {
|
||||||
|
padding: var(--spacing-l);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import { FIELDS } from "constants/backend"
|
import { FIELDS } from "constants/backend"
|
||||||
import { ModelSetupNav } from "components/nav/ModelSetupNav"
|
import { ModelSetupNav } from "components/nav/ModelSetupNav"
|
||||||
import ModelFieldEditor from "components/nav/ModelSetupNav/ModelFieldEditor.svelte"
|
import ModelFieldEditor from "components/nav/ModelSetupNav/ModelFieldEditor.svelte"
|
||||||
import CreateEditTable from "../modals/CreateEditTable.svelte"
|
import CreateEditColumn from "../modals/CreateEditColumn.svelte"
|
||||||
|
|
||||||
export let field
|
export let field
|
||||||
|
|
||||||
|
@ -26,7 +26,13 @@
|
||||||
backendUiStore.actions.models.deleteField(field)
|
backendUiStore.actions.models.deleteField(field)
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {}
|
function sort(direction, column) {
|
||||||
|
backendUiStore.update(state => {
|
||||||
|
state.sort = { direction, column }
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
hideEditor()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:this={anchor} on:click={dropdown.show}>
|
<div bind:this={anchor} on:click={dropdown.show}>
|
||||||
|
@ -35,9 +41,9 @@
|
||||||
</div>
|
</div>
|
||||||
<DropdownMenu bind:this={dropdown} {anchor} align="left">
|
<DropdownMenu bind:this={dropdown} {anchor} align="left">
|
||||||
{#if editing}
|
{#if editing}
|
||||||
<h5>Edit Column</h5>
|
<h4>Edit Column</h4>
|
||||||
<CreateEditTable
|
<CreateEditColumn
|
||||||
onClosed={dropdown.hide}
|
onClosed={hideEditor}
|
||||||
field={field.field}
|
field={field.field}
|
||||||
columnName={field.name} />
|
columnName={field.name} />
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -50,11 +56,11 @@
|
||||||
<Icon name="delete" />
|
<Icon name="delete" />
|
||||||
Delete
|
Delete
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li on:click={() => sort('asc', field.name)}>
|
||||||
<Icon name="sortascending" />
|
<Icon name="sortascending" />
|
||||||
Sort A - Z
|
Sort A - Z
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li on:click={() => sort('desc', field.name)}>
|
||||||
<Icon name="sortdescending" />
|
<Icon name="sortdescending" />
|
||||||
Sort Z - A
|
Sort Z - A
|
||||||
</li>
|
</li>
|
||||||
|
@ -63,6 +69,11 @@
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
h4 {
|
||||||
|
padding: var(--spacing-l);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
<script>
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
|
import { DropdownMenu, Button, Icon, Input, Select } 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")
|
||||||
|
|
||||||
|
export let row
|
||||||
|
|
||||||
|
let anchor
|
||||||
|
let dropdown
|
||||||
|
|
||||||
|
let editing
|
||||||
|
|
||||||
|
function showEditor() {
|
||||||
|
editing = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideEditor() {
|
||||||
|
dropdown.hide()
|
||||||
|
editing = false
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteRow = () => {
|
||||||
|
open(
|
||||||
|
DeleteRecordModal,
|
||||||
|
{
|
||||||
|
onClosed: hideEditor,
|
||||||
|
record: row,
|
||||||
|
},
|
||||||
|
{ styleContent: { padding: "0" } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function save() {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div bind:this={anchor} on:click={dropdown.show}>
|
||||||
|
<i class="ri-more-line" />
|
||||||
|
</div>
|
||||||
|
<DropdownMenu bind:this={dropdown} {anchor} align="left">
|
||||||
|
{#if editing}
|
||||||
|
<h4>Edit Row</h4>
|
||||||
|
<CreateEditRecord onClosed={hideEditor} record={row} />
|
||||||
|
{:else}
|
||||||
|
<ul>
|
||||||
|
<li on:click={showEditor}>
|
||||||
|
<Icon name="edit" />
|
||||||
|
Edit
|
||||||
|
</li>
|
||||||
|
<li on:click={deleteRow}>
|
||||||
|
<Icon name="delete" />
|
||||||
|
Delete
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
|
</DropdownMenu>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h4 {
|
||||||
|
padding: var(--spacing-l);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: var(--spacing-s) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
|
color: var(--ink);
|
||||||
|
padding: var(--spacing-s) var(--spacing-m);
|
||||||
|
margin: auto 0px;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:hover {
|
||||||
|
background-color: var(--grey-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
li:active {
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -13,9 +13,13 @@
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<DropdownMenu bind:this={dropdown} anchor={anchor} align="left">
|
<DropdownMenu bind:this={dropdown} anchor={anchor} align="left">
|
||||||
|
<h4>Add New Row</h4>
|
||||||
<CreateEditRecord onClosed={dropdown.hide} />
|
<CreateEditRecord onClosed={dropdown.hide} />
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
h4 {
|
||||||
|
padding: var(--spacing-l);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
<script>
|
|
||||||
import * as blockDefinitions from "constants/backend"
|
|
||||||
import { backendUiStore } from "builderStore"
|
|
||||||
import Block from "components/common/Block.svelte"
|
|
||||||
|
|
||||||
const HEADINGS = [
|
|
||||||
{
|
|
||||||
title: "Fields",
|
|
||||||
key: "FIELDS",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Blocks",
|
|
||||||
key: "BLOCKS",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
let selectedTab = "FIELDS"
|
|
||||||
|
|
||||||
function addField(blockDefinition) {
|
|
||||||
backendUiStore.actions.models.addField(blockDefinition)
|
|
||||||
backendUiStore.actions.models.fetch()
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<header>
|
|
||||||
{#each HEADINGS as tab}
|
|
||||||
<span
|
|
||||||
class:selected={selectedTab === tab.key}
|
|
||||||
on:click={() => (selectedTab = tab.key)}>
|
|
||||||
{tab.title}
|
|
||||||
</span>
|
|
||||||
{/each}
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="block-grid">
|
|
||||||
{#each Object.values(blockDefinitions[selectedTab]) as blockDefinition}
|
|
||||||
<Block
|
|
||||||
on:click={() => addField(blockDefinition)}
|
|
||||||
title={blockDefinition.name}
|
|
||||||
icon={blockDefinition.icon} />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
header {
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(3, 1fr);
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
cursor: pointer;
|
|
||||||
display: grid;
|
|
||||||
justify-content: center;
|
|
||||||
align-content: center;
|
|
||||||
padding: 0px 16px;
|
|
||||||
height: 36px;
|
|
||||||
text-align: center;
|
|
||||||
background: #ffffff;
|
|
||||||
color: var(--grey-7);
|
|
||||||
border-radius: 5px;
|
|
||||||
font-family: inter;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 400;
|
|
||||||
transition: all 0.3s;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
border: none !important;
|
|
||||||
transition: 0.2s;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
span:hover {
|
|
||||||
color: var(--ink);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected {
|
|
||||||
background: var(--grey-3);
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.block-grid {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
grid-gap: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
<script>
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
|
import { notifier } from "builderStore/store/notifications"
|
||||||
|
import { DropdownMenu, Button, Icon, Input, Select } from "@budibase/bbui"
|
||||||
|
|
||||||
|
export let table
|
||||||
|
|
||||||
|
let anchor
|
||||||
|
let dropdown
|
||||||
|
let name
|
||||||
|
|
||||||
|
async function saveTable() {
|
||||||
|
await backendUiStore.actions.models.save({
|
||||||
|
name,
|
||||||
|
schema: {},
|
||||||
|
})
|
||||||
|
notifier.success(`Table ${name} created successfully.`)
|
||||||
|
dropdown.hide()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div bind:this={anchor}>
|
||||||
|
<Button primary wide on:click={dropdown.show}>Create New Table</Button>
|
||||||
|
</div>
|
||||||
|
<DropdownMenu bind:this={dropdown} {anchor} align="left">
|
||||||
|
<div class="container">
|
||||||
|
<h4>Create Table</h4>
|
||||||
|
<Input placeholder="Table Name" thin bind:value={name} />
|
||||||
|
</div>
|
||||||
|
<footer>
|
||||||
|
<div class="button-margin-3">
|
||||||
|
<Button secondary on:click={dropdown.hide}>Cancel</Button>
|
||||||
|
</div>
|
||||||
|
<div class="button-margin-4">
|
||||||
|
<Button primary on:click={saveTable}>Save</Button>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</DropdownMenu>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,93 +0,0 @@
|
||||||
<script>
|
|
||||||
import { backendUiStore } from "builderStore"
|
|
||||||
import { uuid } from "builderStore/uuid"
|
|
||||||
import { fade } from "svelte/transition"
|
|
||||||
import { notifier } from "builderStore/store/notifications"
|
|
||||||
import { FIELDS, BLOCKS } from "constants/backend"
|
|
||||||
import Block from "components/common/Block.svelte"
|
|
||||||
|
|
||||||
function addNewField(field) {
|
|
||||||
backendUiStore.actions.models.addField(field)
|
|
||||||
}
|
|
||||||
|
|
||||||
function createModel(model) {
|
|
||||||
const { schema, ...rest } = $backendUiStore.selectedModel
|
|
||||||
|
|
||||||
backendUiStore.actions.models.save({
|
|
||||||
model: {
|
|
||||||
...model,
|
|
||||||
...rest,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
notifier.success(`${model.name} table created.`)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<section transition:fade>
|
|
||||||
<header>
|
|
||||||
<h2>Create New Table</h2>
|
|
||||||
<p>Before you can view your table, you need to set it up.</p>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="block-row">
|
|
||||||
<span class="block-row-title">Fields</span>
|
|
||||||
<p>Blocks are pre-made fields and help you build your table quicker.</p>
|
|
||||||
<div class="blocks">
|
|
||||||
{#each Object.values(FIELDS) as field}
|
|
||||||
<Block
|
|
||||||
primary
|
|
||||||
title={field.name}
|
|
||||||
icon={field.icon}
|
|
||||||
on:click={() => addNewField(field)} />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="block-row">
|
|
||||||
<span class="block-row-title">Blocks</span>
|
|
||||||
<p>Blocks are pre-made fields and help you build your table quicker.</p>
|
|
||||||
<div class="blocks">
|
|
||||||
{#each Object.values(BLOCKS) as field}
|
|
||||||
<Block
|
|
||||||
secondary
|
|
||||||
title={field.name}
|
|
||||||
icon={field.icon}
|
|
||||||
on:click={() => addNewField(field)} />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
section {
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block-row-title {
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-top: 8px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block-row {
|
|
||||||
margin-top: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block-row .blocks {
|
|
||||||
display: grid;
|
|
||||||
grid-auto-flow: column;
|
|
||||||
grid-auto-columns: 110px;
|
|
||||||
grid-gap: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -9,6 +9,7 @@
|
||||||
<div class:selected on:click class={className}>
|
<div class:selected on:click class={className}>
|
||||||
<i class:indented class={icon} />
|
<i class:indented class={icon} />
|
||||||
<span>{title}</span>
|
<span>{title}</span>
|
||||||
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
import { Switcher } from "@budibase/bbui"
|
import { Switcher } from "@budibase/bbui"
|
||||||
import { goto } from "@sveltech/routify"
|
import { goto } from "@sveltech/routify"
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import BlockNavigator from "./BlockNavigator.svelte"
|
|
||||||
import ListItem from "./ListItem.svelte"
|
import ListItem from "./ListItem.svelte"
|
||||||
import { Button } from "@budibase/bbui"
|
import { Button } from "@budibase/bbui"
|
||||||
|
import CreateTablePopover from "./CreateEditTable.svelte"
|
||||||
|
|
||||||
const { open, close } = getContext("simple-modal")
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
|
@ -37,14 +37,6 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupForNewModel() {
|
|
||||||
backendUiStore.update(state => {
|
|
||||||
state.selectedModel = {}
|
|
||||||
state.draftModel = { schema: {} }
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="items-root">
|
<div class="items-root">
|
||||||
|
@ -52,16 +44,16 @@
|
||||||
<div class="hierarchy">
|
<div class="hierarchy">
|
||||||
<div class="components-list-container">
|
<div class="components-list-container">
|
||||||
<h3>Tables</h3>
|
<h3>Tables</h3>
|
||||||
<Button primary wide on:click={setupForNewModel}>
|
<CreateTablePopover />
|
||||||
Create New Table
|
|
||||||
</Button>
|
|
||||||
<div class="hierarchy-items-container">
|
<div class="hierarchy-items-container">
|
||||||
{#each $backendUiStore.models as model}
|
{#each $backendUiStore.models as model}
|
||||||
<ListItem
|
<ListItem
|
||||||
selected={!$backendUiStore.selectedField && model._id === $backendUiStore.selectedModel._id}
|
selected={!$backendUiStore.selectedField && model._id === $backendUiStore.selectedModel._id}
|
||||||
title={model.name}
|
title={model.name}
|
||||||
icon="ri-table-fill"
|
icon="ri-table-fill"
|
||||||
on:click={() => selectModel(model)} />
|
on:click={() => selectModel(model)}>
|
||||||
|
|
||||||
|
</ListItem>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
if (field) {
|
if (field) {
|
||||||
const name = model.schema[field].name
|
const name = model.schema[field].name
|
||||||
delete model.schema[field]
|
delete model.schema[field]
|
||||||
backendUiStore.actions.models.save({ model })
|
backendUiStore.actions.models.save(model)
|
||||||
notifier.danger(`Field ${name} deleted.`)
|
notifier.danger(`Field ${name} deleted.`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -81,9 +81,7 @@
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await backendUiStore.actions.models.save({
|
await backendUiStore.actions.models.save($backendUiStore.draftModel)
|
||||||
model: $backendUiStore.draftModel,
|
|
||||||
})
|
|
||||||
notifier.success(
|
notifier.success(
|
||||||
"Success! Your changes have been saved. Please continue on with your greatness."
|
"Success! Your changes have been saved. Please continue on with your greatness."
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
import { Button } from "@budibase/bbui"
|
import { Button } from "@budibase/bbui"
|
||||||
import EmptyModel from "components/nav/ModelNavigator/EmptyModel.svelte"
|
|
||||||
import ModelDataTable from "components/database/ModelDataTable"
|
import ModelDataTable from "components/database/ModelDataTable"
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
|
@ -11,16 +10,6 @@
|
||||||
const { open, close } = getContext("simple-modal")
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
$: selectedModel = $backendUiStore.selectedModel
|
$: selectedModel = $backendUiStore.selectedModel
|
||||||
|
|
||||||
const createNewRecord = () => {
|
|
||||||
open(
|
|
||||||
CreateEditRecordModal,
|
|
||||||
{
|
|
||||||
onClosed: close,
|
|
||||||
},
|
|
||||||
{ styleContent: { padding: "0" } }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $backendUiStore.selectedDatabase._id && selectedModel.name}
|
{#if $backendUiStore.selectedDatabase._id && selectedModel.name}
|
||||||
|
|
Loading…
Reference in New Issue