diff --git a/packages/builder/cypress/integration/createComponents.spec.js b/packages/builder/cypress/integration/createComponents.spec.js
index d6c471b74f..2e247f7110 100644
--- a/packages/builder/cypress/integration/createComponents.spec.js
+++ b/packages/builder/cypress/integration/createComponents.spec.js
@@ -5,7 +5,7 @@ xcontext('Create Components', () => {
cy.visit('localhost:4001/_builder')
// https://on.cypress.io/type
cy.createApp('Model App', 'Model App Description')
- cy.createModel('dog', 'name', 'age')
+ cy.createTable('dog', 'name', 'age')
cy.addRecord('bob', '15')
})
diff --git a/packages/builder/cypress/integration/createModel.spec.js b/packages/builder/cypress/integration/createModel.spec.js
deleted file mode 100644
index 06b2420331..0000000000
--- a/packages/builder/cypress/integration/createModel.spec.js
+++ /dev/null
@@ -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')
- })
-})
diff --git a/packages/builder/cypress/integration/createTable.spec.js b/packages/builder/cypress/integration/createTable.spec.js
new file mode 100644
index 0000000000..c744eb7e4f
--- /dev/null
+++ b/packages/builder/cypress/integration/createTable.spec.js
@@ -0,0 +1,70 @@
+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')
+
+ // 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')
+
+ cy.contains('name').should("be.visible")
+ })
+
+ it('creates a record in the table', () => {
+ cy.addRecord(["Rover"])
+
+ cy.contains('Rover').should("be.visible")
+ })
+
+ 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 ')
+ })
+
+ it('edits a record', () => {
+ cy.get("tbody .ri-more-line").click()
+ cy.get("[data-cy=edit-row]").click()
+ cy.get(".actions input").type("updatedRecord")
+ cy.contains("Save").click()
+
+ cy.contains('updatedRecord').should('have.text', 'updatedRecord')
+ })
+
+ 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('updatedRecord').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')
+ })
+
+})
diff --git a/packages/builder/cypress/integration/createWorkflow.spec.js b/packages/builder/cypress/integration/createWorkflow.spec.js
index ed14ce1487..f341bf86b1 100644
--- a/packages/builder/cypress/integration/createWorkflow.spec.js
+++ b/packages/builder/cypress/integration/createWorkflow.spec.js
@@ -9,7 +9,7 @@ xcontext('Create a workflow', () => {
// https://on.cypress.io/interacting-with-elements
it('should create a workflow', () => {
- cy.createModel('dog', 'name', 'age')
+ cy.createTable('dog', 'name', 'age')
cy.contains('workflow').click()
cy.contains('Create New Workflow').click()
diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js
index abd44d7061..40ffb0f489 100644
--- a/packages/builder/cypress/support/commands.js
+++ b/packages/builder/cypress/support/commands.js
@@ -57,29 +57,37 @@ Cypress.Commands.add("createApp", name => {
})
})
-Cypress.Commands.add("createModel", modelName => {
+Cypress.Commands.add("createTable", tableName => {
// Enter model name
cy.contains("Create New Table").click()
- cy.get("[data-cy=table-name-input]").type(modelName)
+ cy.get("[placeholder='Table Name']").type(tableName)
// Add 'name' field
- cy.contains("Add").click()
- cy.contains("Plain Text").click()
-
- // Add 'age' field
- cy.contains("Add").click()
- cy.contains("Number").click()
-
cy.contains("Save").click()
-
- cy.contains(modelName).click()
+ cy.contains(tableName).should("be.visible")
})
-Cypress.Commands.add("addRecord", (firstField, secondField) => {
- cy.contains("Create New Record").click()
+Cypress.Commands.add("addColumn", (tableName, columnName, type) => {
+ // Select Table
+ cy.contains(tableName).click()
+ cy.contains("Create New Column").click()
- cy.get("[data-cy='Plain Text-input']").type(firstField)
- cy.get("[data-cy=Number-input]").type(secondField)
+ cy.get("[placeholder=Name]").type(columnName)
+ cy.get("select").select(type)
+
+ cy.contains("Save Column")
+
+ cy.contains("Save").click()
+})
+
+Cypress.Commands.add("addRecord", values => {
+ cy.contains("Create New Row").click()
+
+ for (let i = 0; i < values.length; i++) {
+ cy.get("input")
+ .eq(i)
+ .type(values[i])
+ }
// Save
cy.contains("Save").click()
diff --git a/packages/builder/package.json b/packages/builder/package.json
index 8034ad4756..75faa8671f 100644
--- a/packages/builder/package.json
+++ b/packages/builder/package.json
@@ -68,6 +68,7 @@
"d3-selection": "^1.4.1",
"date-fns": "^1.29.0",
"deepmerge": "^4.2.2",
+ "fast-sort": "^2.2.0",
"feather-icons": "^4.21.0",
"flatpickr": "^4.5.7",
"lodash": "^4.17.13",
@@ -98,6 +99,7 @@
"cypress-terminal-report": "^1.4.1",
"eslint-plugin-cypress": "^2.11.1",
"http-proxy-middleware": "^0.19.1",
+ "identity-obj-proxy": "^3.0.0",
"jest": "^24.8.0",
"ncp": "^2.0.0",
"npm-run-all": "^4.1.5",
diff --git a/packages/builder/src/builderStore/store/backend.js b/packages/builder/src/builderStore/store/backend.js
index 393371ce85..28272d9893 100644
--- a/packages/builder/src/builderStore/store/backend.js
+++ b/packages/builder/src/builderStore/store/backend.js
@@ -61,10 +61,9 @@ export const getBackendUiStore = () => {
state.draftModel = cloneDeep(model)
state.selectedField = ""
state.selectedView = `all_${model._id}`
- state.tabs.SETUP_PANEL = "SETUP"
return state
}),
- save: async ({ model }) => {
+ save: async model => {
const updatedModel = cloneDeep(model)
// update any renamed schema keys to reflect their names
@@ -83,20 +82,35 @@ export const getBackendUiStore = () => {
const savedModel = await response.json()
await store.actions.models.fetch()
store.actions.models.select(savedModel)
+ return savedModel
},
- addField: field => {
+ delete: async model => {
+ await api.delete(`/api/models/${model._id}/${model._rev}`)
store.update(state => {
- if (!state.draftModel.schema) {
- state.draftModel.schema = {}
- }
+ state.models = state.models.filter(
+ existing => existing._id !== model._id
+ )
+ state.selectedModel = state.models[0] || {}
+ return state
+ })
+ },
+ saveField: ({ originalName, field }) => {
+ store.update(state => {
+ // delete the original if renaming
+ delete state.draftModel.schema[originalName]
state.draftModel.schema = {
...state.draftModel.schema,
[field.name]: cloneDeep(field),
}
- state.selectedField = field.name
- state.tabs.NAVIGATION_PANEL = "NAVIGATE"
-
+ store.actions.models.save(state.draftModel)
+ return state
+ })
+ },
+ deleteField: field => {
+ store.update(state => {
+ delete state.draftModel.schema[field.name]
+ store.actions.models.save(state.draftModel)
return state
})
},
diff --git a/packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte b/packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte
index bbd9d6d4a3..180ce154a3 100644
--- a/packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte
+++ b/packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte
@@ -1,38 +1,19 @@
-
-
-
-
diff --git a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/database/ModelDataTable/modals/CreateEditColumn.svelte
new file mode 100644
index 0000000000..3c125260ea
--- /dev/null
+++ b/packages/builder/src/components/database/ModelDataTable/modals/CreateEditColumn.svelte
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+ {#each Object.values(FIELDS) as field}
+ {field.name}
+ {/each}
+
+
+
+
+ Required
+ (field.constraints.presence.allowEmpty = required)} />
+
+
+ {#if field.type === 'string'}
+
+
+ {:else if field.type === 'datetime'}
+
+
+ {:else if field.type === 'number'}
+
+
+ {:else if field.type === 'link'}
+
+ Link
+
+
+ {#each $backendUiStore.models as model}
+ {#if model._id !== $backendUiStore.draftModel._id}
+ {model.name}
+ {/if}
+ {/each}
+
+
+ {/if}
+
+
+
+
+
+ Cancel
+
+
+ Save Column
+
+
+
+
diff --git a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditModel/CreateEditModel.svelte b/packages/builder/src/components/database/ModelDataTable/modals/CreateEditModel/CreateEditModel.svelte
deleted file mode 100644
index 2cb718c278..0000000000
--- a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditModel/CreateEditModel.svelte
+++ /dev/null
@@ -1,165 +0,0 @@
-
-
-
- {#if !showFieldView}
-
-
Create / Edit Table
- {:else}
-
- Create / Edit Field
- {/if}
-
-{#if !showFieldView}
-
- {#if $store.errors && $store.errors.length > 0}
-
- {/if}
-
-
-
-
-
Fields
-
(showFieldView = true)}>
- Add new field
-
-
-
-
-
-
- Edit
- Name
- Type
-
-
-
-
- {#each modelFields as [key, meta]}
-
-
- editField(meta)} />
-
-
- {key}
-
- {meta.type}
-
- deleteField(meta)} />
-
-
- {/each}
-
-
-
-
-{:else}
- (showFieldView = false)} />
-{/if}
-
-
diff --git a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditRecord.svelte b/packages/builder/src/components/database/ModelDataTable/modals/CreateEditRecord.svelte
index f17730893c..424b18dc12 100644
--- a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditRecord.svelte
+++ b/packages/builder/src/components/database/ModelDataTable/modals/CreateEditRecord.svelte
@@ -20,10 +20,6 @@
? Object.entries($backendUiStore.selectedModel.schema)
: []
- function closed() {
- onClosed()
- }
-
const isSelect = meta =>
meta.type === "string" &&
meta.constraints &&
@@ -68,10 +64,6 @@
-
-
- Create / Edit Record
-
- Save
+ Save
diff --git a/packages/builder/src/components/database/ModelDataTable/modals/RecordFieldControl.svelte b/packages/builder/src/components/database/ModelDataTable/modals/RecordFieldControl.svelte
index 465ca29c42..ecc79b2ba0 100644
--- a/packages/builder/src/components/database/ModelDataTable/modals/RecordFieldControl.svelte
+++ b/packages/builder/src/components/database/ModelDataTable/modals/RecordFieldControl.svelte
@@ -1,18 +1,13 @@
-{label}
-
{#if type === 'select'}
- 0}>
+
{#each options as opt}
{opt}
{/each}
-
+
{:else}
- {label}
+ {/if}
+ 0}
{checked}
{type}
{value}
@@ -55,13 +47,9 @@
diff --git a/packages/builder/src/components/database/ModelDataTable/modals/index.js b/packages/builder/src/components/database/ModelDataTable/modals/index.js
index fb6affc2d5..bb49df8746 100644
--- a/packages/builder/src/components/database/ModelDataTable/modals/index.js
+++ b/packages/builder/src/components/database/ModelDataTable/modals/index.js
@@ -1,5 +1,4 @@
export { default as DeleteRecordModal } from "./DeleteRecord.svelte"
export { default as CreateEditRecordModal } from "./CreateEditRecord.svelte"
export { default as CreateEditViewModal } from "./CreateEditView.svelte"
-export { default as CreateDatabaseModal } from "./CreateDatabase.svelte"
export { default as CreateUserModal } from "./CreateUser.svelte"
diff --git a/packages/builder/src/components/database/ModelDataTable/popovers/Column.svelte b/packages/builder/src/components/database/ModelDataTable/popovers/Column.svelte
new file mode 100644
index 0000000000..be75da71ce
--- /dev/null
+++ b/packages/builder/src/components/database/ModelDataTable/popovers/Column.svelte
@@ -0,0 +1,31 @@
+
+
+
+
+
+ Create New Column
+
+
+
+ Create Column
+
+
+
+
diff --git a/packages/builder/src/components/database/ModelDataTable/popovers/ColumnHeader.svelte b/packages/builder/src/components/database/ModelDataTable/popovers/ColumnHeader.svelte
new file mode 100644
index 0000000000..35e72427e2
--- /dev/null
+++ b/packages/builder/src/components/database/ModelDataTable/popovers/ColumnHeader.svelte
@@ -0,0 +1,107 @@
+
+
+
+ {field.name}
+
+
+
+ {#if editing}
+ Edit Column
+
+ {:else}
+
+
+
+ Edit
+
+
+
+ Delete
+
+ {#if sortDirection === 'desc' || sortColumn !== field.name}
+ sort('asc', field.name)}>
+
+ Sort A - Z
+
+ {/if}
+ {#if sortDirection === 'asc' || sortColumn !== field.name}
+ sort('desc', field.name)}>
+
+ Sort Z - A
+
+ {/if}
+
+ {/if}
+
+
+
diff --git a/packages/builder/src/components/database/ModelDataTable/popovers/EditRow.svelte b/packages/builder/src/components/database/ModelDataTable/popovers/EditRow.svelte
new file mode 100644
index 0000000000..4a88d200d9
--- /dev/null
+++ b/packages/builder/src/components/database/ModelDataTable/popovers/EditRow.svelte
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+ {#if editing}
+ Edit Row
+
+ {:else}
+
+
+
+ Edit
+
+
+
+ Delete
+
+
+ {/if}
+
+
+
diff --git a/packages/builder/src/components/database/ModelDataTable/popovers/Row.svelte b/packages/builder/src/components/database/ModelDataTable/popovers/Row.svelte
new file mode 100644
index 0000000000..afa97c369f
--- /dev/null
+++ b/packages/builder/src/components/database/ModelDataTable/popovers/Row.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+
+ Create New Row
+
+
+
+ Add New Row
+
+
+
+
diff --git a/packages/builder/src/components/database/ModelDataTable/popovers/View.svelte b/packages/builder/src/components/database/ModelDataTable/popovers/View.svelte
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/builder/src/components/nav/ModelNavigator/BlockNavigator.svelte b/packages/builder/src/components/nav/ModelNavigator/BlockNavigator.svelte
deleted file mode 100644
index a1eb2b7d3b..0000000000
--- a/packages/builder/src/components/nav/ModelNavigator/BlockNavigator.svelte
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
-
-
- {#each HEADINGS as tab}
- (selectedTab = tab.key)}>
- {tab.title}
-
- {/each}
-
-
-
- {#each Object.values(blockDefinitions[selectedTab]) as blockDefinition}
- addField(blockDefinition)}
- title={blockDefinition.name}
- icon={blockDefinition.icon} />
- {/each}
-
-
-
-
diff --git a/packages/builder/src/components/nav/ModelNavigator/CreateTable.svelte b/packages/builder/src/components/nav/ModelNavigator/CreateTable.svelte
new file mode 100644
index 0000000000..9763ade62e
--- /dev/null
+++ b/packages/builder/src/components/nav/ModelNavigator/CreateTable.svelte
@@ -0,0 +1,76 @@
+
+
+
+ Create New Table
+
+
+
+
Create Table
+
+
+
+
+ Cancel
+
+
+ Save
+
+
+
+
+
diff --git a/packages/builder/src/components/nav/ModelNavigator/EditTable.svelte b/packages/builder/src/components/nav/ModelNavigator/EditTable.svelte
new file mode 100644
index 0000000000..3bfa5892d1
--- /dev/null
+++ b/packages/builder/src/components/nav/ModelNavigator/EditTable.svelte
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+ {#if editing}
+ Edit Table
+
+
+
+
+
+ Cancel
+
+
+ Save
+
+
+ {:else}
+
+
+
+ Edit
+
+
+
+ Delete
+
+
+ {/if}
+
+
+
diff --git a/packages/builder/src/components/nav/ModelNavigator/EmptyModel.svelte b/packages/builder/src/components/nav/ModelNavigator/EmptyModel.svelte
deleted file mode 100644
index 4541c095d3..0000000000
--- a/packages/builder/src/components/nav/ModelNavigator/EmptyModel.svelte
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
-
-
-
-
-
Fields
-
Blocks are pre-made fields and help you build your table quicker.
-
- {#each Object.values(FIELDS) as field}
- addNewField(field)} />
- {/each}
-
-
-
-
-
Blocks
-
Blocks are pre-made fields and help you build your table quicker.
-
- {#each Object.values(BLOCKS) as field}
- addNewField(field)} />
- {/each}
-
-
-
-
-
Tables
-
Blocks are pre-made fields and help you build your table quicker.
-
- {#each Object.values(MODELS) as model}
- createModel(model)} />
- {/each}
-
-
-
-
-
diff --git a/packages/builder/src/components/nav/ModelNavigator/ListItem.svelte b/packages/builder/src/components/nav/ModelNavigator/ListItem.svelte
index 83d83487a3..5fb2832162 100644
--- a/packages/builder/src/components/nav/ModelNavigator/ListItem.svelte
+++ b/packages/builder/src/components/nav/ModelNavigator/ListItem.svelte
@@ -9,6 +9,7 @@
{title}
+
diff --git a/packages/standard-components/src/CardHorizontal.svelte b/packages/standard-components/src/CardHorizontal.svelte
new file mode 100644
index 0000000000..86dc6437ec
--- /dev/null
+++ b/packages/standard-components/src/CardHorizontal.svelte
@@ -0,0 +1,104 @@
+
+
+
+ {#if showImage}
+
+ {/if}
+
+
+ {heading}
+ {description}
+
+
+
+
+
+
diff --git a/packages/standard-components/src/index.js b/packages/standard-components/src/index.js
index 071ffa1bcf..598f372988 100644
--- a/packages/standard-components/src/index.js
+++ b/packages/standard-components/src/index.js
@@ -23,5 +23,7 @@ export { default as list } from "./List.svelte"
export { default as datasearch } from "./DataSearch.svelte"
export { default as embed } from "./Embed.svelte"
export { default as stackedlist } from "./StackedList.svelte"
+export { default as card } from "./Card.svelte"
+export { default as cardhorizontal } from "./CardHorizontal.svelte"
export { default as recorddetail } from "./RecordDetail.svelte"
export * from "./Chart"