diff --git a/lerna.json b/lerna.json index c6a99591de..5d5fb16e81 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.1.17", + "version": "0.1.19", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/package.json b/package.json index 148924b6d3..69f7b0f21d 100644 --- a/package.json +++ b/package.json @@ -28,9 +28,5 @@ "format": "prettier --write \"{,!(node_modules)/**/}*.{js,jsx,svelte}\"", "test:e2e": "lerna run cy:test", "test:e2e:ci": "lerna run cy:ci" - }, - "dependencies": { - "@material/icon-button": "4.0.0", - "date-fns": "^2.10.0" } } diff --git a/packages/builder/cypress/integration/createTable.spec.js b/packages/builder/cypress/integration/createTable.spec.js index c744eb7e4f..214727ab7d 100644 --- a/packages/builder/cypress/integration/createTable.spec.js +++ b/packages/builder/cypress/integration/createTable.spec.js @@ -38,10 +38,10 @@ context('Create a Table', () => { 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.get(".actions input").type("Updated") cy.contains("Save").click() - cy.contains('updatedRecord').should('have.text', 'updatedRecord') + cy.contains('RoverUpdated').should('have.text', 'RoverUpdated') }) it('deletes a record', () => { @@ -49,7 +49,7 @@ context('Create a Table', () => { cy.get("[data-cy=delete-row]").click() cy.get(".modal-actions").contains("Delete").click() - cy.contains('updatedRecord').should('not.exist') + cy.contains('RoverUpdated').should('not.exist') }) it('deletes a column', () => { diff --git a/packages/builder/cypress/integration/createView.spec.js b/packages/builder/cypress/integration/createView.spec.js new file mode 100644 index 0000000000..b605135ad4 --- /dev/null +++ b/packages/builder/cypress/integration/createView.spec.js @@ -0,0 +1,85 @@ +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') + + 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 stats view based on age', () => { + cy.contains("Create New View").click() + cy.get("[placeholder='View Name']").type("Test View") + cy.contains("Save View").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([ + "group", + "sum", + "min", + "max", + "sumsqr", + "count", + "avg", + ]) + }) + cy.get("tbody td").should(($values) => { + const values = $values.map((i, value) => Cypress.$(value).text()) + expect(values.get()).to.deep.eq([ + "null", + "173", + "18", + "49", + "5671", + "6", + "28.833333333333332" + ]) + }) + }) + + it('groups the stats 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", + "88", + "18", + "25", + "1974", + "4", + "22" + ]) + }) + }) + + 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").find(".ri-more-line").click() + cy.contains("Delete").click() + cy.get(".content").contains("button", "Delete").click() + cy.contains("TestView Updated").should("not.be.visible") + }) +}) diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index 40ffb0f489..da85abddb3 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -131,9 +131,9 @@ Cypress.Commands.add("navigateToFrontend", () => { Cypress.Commands.add("createScreen", (screenName, route) => { cy.get(".newscreen").click() - cy.get(".uk-input:first").type(screenName) + cy.get("[data-cy=new-screen-dialog] input:first").type(screenName) if (route) { - cy.get(".uk-input:last").type(route) + cy.get("[data-cy=new-screen-dialog] input:last").type(route) } cy.get(".uk-modal-footer").within(() => { cy.contains("Create Screen").click() diff --git a/packages/builder/package.json b/packages/builder/package.json index 7b9cd630b6..42d1677ecf 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.1.17", + "version": "0.1.19", "license": "AGPL-3.0", "private": true, "scripts": { @@ -58,26 +58,20 @@ }, "dependencies": { "@budibase/bbui": "^1.27.0", - "@budibase/client": "^0.1.17", + "@budibase/client": "^0.1.19", "@budibase/colorpicker": "^1.0.1", - "@nx-js/compiler-util": "^2.0.0", "@sentry/browser": "5.19.1", "@svelteschool/svelte-forms": "^0.7.0", "britecharts": "^2.16.0", - "codemirror": "^5.51.0", "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", - "lunr": "^2.3.5", "mustache": "^4.0.1", "posthog-js": "1.3.1", - "safe-buffer": "^5.1.2", "shortid": "^2.2.15", - "string_decoder": "^1.2.0", "svelte-portal": "^0.1.0", "svelte-simple-modal": "^0.4.2", "uikit": "^3.1.7", @@ -93,20 +87,16 @@ "@sveltech/routify": "1.7.11", "@testing-library/jest-dom": "^5.11.0", "@testing-library/svelte": "^3.0.0", - "babel-jest": "^26.2.2", - "browser-sync": "^2.26.7", + "babel-jest": "^24.8.0", "cypress": "^4.8.0", "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", + "jest": "^24.8.0", "ncp": "^2.0.0", - "npm-run-all": "^4.1.5", "rimraf": "^3.0.2", "rollup": "^1.12.0", "rollup-plugin-alias": "^1.5.2", - "rollup-plugin-browsersync": "^1.0.0", "rollup-plugin-commonjs": "^10.0.0", "rollup-plugin-copy": "^3.0.0", "rollup-plugin-livereload": "^1.0.0", diff --git a/packages/builder/src/builderStore/store/backend.js b/packages/builder/src/builderStore/store/backend.js index 28272d9893..6e75323b6d 100644 --- a/packages/builder/src/builderStore/store/backend.js +++ b/packages/builder/src/builderStore/store/backend.js @@ -23,13 +23,10 @@ export const getBackendUiStore = () => { database: { select: async db => { const modelsResponse = await api.get(`/api/models`) - const viewsResponse = await api.get(`/api/views`) const models = await modelsResponse.json() - const views = await viewsResponse.json() store.update(state => { state.selectedDatabase = db state.models = models - state.views = views return state }) }, @@ -59,8 +56,7 @@ export const getBackendUiStore = () => { store.update(state => { state.selectedModel = model state.draftModel = cloneDeep(model) - state.selectedField = "" - state.selectedView = `all_${model._id}` + state.selectedView = { name: `all_${model._id}` } return state }), save: async model => { @@ -97,12 +93,16 @@ export const getBackendUiStore = () => { 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), + if (originalName) { + delete state.draftModel.schema[originalName] + state.draftModel._rename = { + old: originalName, + updated: field.name, + } } + + state.draftModel.schema[field.name] = cloneDeep(field) + store.actions.models.save(state.draftModel) return state }) @@ -119,8 +119,30 @@ export const getBackendUiStore = () => { select: view => store.update(state => { state.selectedView = view + state.selectedModel = {} return state }), + delete: async view => { + await api.delete(`/api/views/${view}`) + await store.actions.models.fetch() + }, + save: async view => { + await api.post(`/api/views`, view) + + store.update(state => { + const viewModel = state.models.find( + model => model._id === view.modelId + ) + // TODO: Cleaner? + if (!viewModel.views) viewModel.views = {} + if (view.originalName) delete viewModel.views[view.originalName] + viewModel.views[view.name] = view + + state.models = state.models + state.selectedView = view + return state + }) + }, }, users: { create: user => diff --git a/packages/builder/src/components/common/Block.svelte b/packages/builder/src/components/common/Block.svelte deleted file mode 100644 index eccf798742..0000000000 --- a/packages/builder/src/components/common/Block.svelte +++ /dev/null @@ -1,59 +0,0 @@ - - -
{header.name} | + {/each} +
---|
{getOr(row.default || '', header.key, row)} | + {/each} +