diff --git a/lerna.json b/lerna.json index 106084980f..c6a99591de 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.1.16", + "version": "0.1.17", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/package.json b/package.json index b3ce4265a6..148924b6d3 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "build": "lerna run build", "initialise": "lerna run initialise", "publishdev": "lerna run publishdev", - "publishnpm": "yarn build && lerna publish", + "publishnpm": "yarn build && lerna publish --force-publish", "clean": "lerna clean", "dev": "node ./scripts/symlinkDev.js && lerna run --parallel --stream dev:builder", "test": "lerna run test", 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 7ebbe81617..206df9d326 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.1.16", + "version": "0.1.17", "license": "AGPL-3.0", "private": true, "scripts": { @@ -58,7 +58,7 @@ }, "dependencies": { "@budibase/bbui": "^1.23.1", - "@budibase/client": "^0.1.1", + "@budibase/client": "^0.1.17", "@budibase/colorpicker": "^1.0.1", "@nx-js/compiler-util": "^2.0.0", "@sentry/browser": "5.19.1", @@ -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": "^26.2.2", "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..c7efd29253 100644 --- a/packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte +++ b/packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte @@ -1,38 +1,19 @@ - -
-
- Database Name - -
- -
- - 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..77a6db9d39 --- /dev/null +++ b/packages/builder/src/components/database/ModelDataTable/modals/CreateEditColumn.svelte @@ -0,0 +1,140 @@ + + +
+ + + + +
+
+ + (field.constraints.presence.allowEmpty = required)} /> +
+ + {#if field.type === 'string'} + + + {:else if field.type === 'datetime'} + + + {:else if field.type === 'number'} + + + {:else if field.type === 'link'} +
+ + +
+ {/if} +
+ +
+ + + 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 -
-
- - - - - - - - - - - {#each modelFields as [key, meta]} - - - - - - - {/each} - -
EditNameType -
- editField(meta)} /> - -
{key}
-
{meta.type} - deleteField(meta)} /> -
-
- Save -
-
-{: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

-
{#each modelSchema as [key, meta]} @@ -97,42 +89,13 @@
- +
diff --git a/packages/builder/src/components/database/ModelDataTable/modals/RecordFieldControl.svelte b/packages/builder/src/components/database/ModelDataTable/modals/RecordFieldControl.svelte index 465ca29c42..02d6616f87 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 @@ - - {#if type === 'select'} - {/each} - + {:else} - 0} {checked} {type} {value} on:input={handleInput} on:change={handleInput} /> {/if} - - 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 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 @@ + + +
+ +
+ +
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..6125b0851b --- /dev/null +++ b/packages/builder/src/components/nav/ModelNavigator/CreateTable.svelte @@ -0,0 +1,77 @@ + + +
+ +
+ +
+
Create Table
+ +
+
+
+ +
+
+ +
+
+
+ + 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
+
+ +
+
+
+ +
+
+ +
+
+ {: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 @@ - - -
-
-

Create New Table

-

Before you can view your table, you need to set it up.

-
- -
- 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} +