From f62e7e06d85d32788512e9f65dc6f742e1a68576 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 13 Aug 2020 15:04:19 +0100 Subject: [PATCH 1/9] new view foundations --- .../src/api/controllers/view/customViews.js | 27 +++++++++++++++++ .../controllers/{view.js => view/index.js} | 29 +++++++++++++++---- packages/server/src/api/routes/view.js | 5 ++-- packages/server/src/electron.js | 5 +++- .../src/Chart/tests/bar.html | 2 +- 5 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 packages/server/src/api/controllers/view/customViews.js rename packages/server/src/api/controllers/{view.js => view/index.js} (53%) diff --git a/packages/server/src/api/controllers/view/customViews.js b/packages/server/src/api/controllers/view/customViews.js new file mode 100644 index 0000000000..66e643f809 --- /dev/null +++ b/packages/server/src/api/controllers/view/customViews.js @@ -0,0 +1,27 @@ +const FORMULA_MAP = { + SUM: "_sum", + COUNT: "_count", + STATS: "_stats" +}; + +function customViewTemplate({ + field, + formula, + modelId +}) { + return { + meta: { + field, + formula, + modelId + }, + map: `function (doc) { + if (doc.modelId === "${modelId}") { + emit(doc._id, doc["${field}"]); + } + }`, + reduce: "_stats" + } +} + +module.exports = customViewTemplate \ No newline at end of file diff --git a/packages/server/src/api/controllers/view.js b/packages/server/src/api/controllers/view/index.js similarity index 53% rename from packages/server/src/api/controllers/view.js rename to packages/server/src/api/controllers/view/index.js index d449ae36f9..e65cfd97c3 100644 --- a/packages/server/src/api/controllers/view.js +++ b/packages/server/src/api/controllers/view/index.js @@ -1,9 +1,23 @@ -const CouchDB = require("../../db") +const CouchDB = require("../../../db") +const customViewTemplate = require("./customViews"); const controller = { - query: async () => {}, + query: async ctx => { + // const db = new CouchDB(ctx.user.instanceId) + const db = new CouchDB("inst_4e6f424_970ca7f2b9e24ec8896eb10862d7f22b") + const response = await db.query(`database/${ctx.params.viewName}`, { + group: false + }) + + ctx.body = response.rows + // ctx.body = { + // ...data, + // avg: data.sum / data.count + // } + }, fetch: async ctx => { - const db = new CouchDB(ctx.user.instanceId) + // const db = new CouchDB(ctx.user.instanceId) + const db = new CouchDB("inst_4e6f424_970ca7f2b9e24ec8896eb10862d7f22b") const designDoc = await db.get("_design/database") const response = [] @@ -24,14 +38,19 @@ const controller = { ctx.body = response }, create: async ctx => { - const db = new CouchDB(ctx.user.instanceId) + // const db = new CouchDB(ctx.user.instanceId) + const db = new CouchDB("inst_4e6f424_970ca7f2b9e24ec8896eb10862d7f22b") const newView = ctx.request.body const designDoc = await db.get("_design/database") + + const view = customViewTemplate(ctx.request.body) + designDoc.views = { ...designDoc.views, - [newView.name]: newView, + [newView.name]: view, } + await db.put(designDoc) ctx.body = newView diff --git a/packages/server/src/api/routes/view.js b/packages/server/src/api/routes/view.js index 5a73eea22e..aa839c0d96 100644 --- a/packages/server/src/api/routes/view.js +++ b/packages/server/src/api/routes/view.js @@ -12,9 +12,10 @@ router authorized(READ_VIEW, ctx => ctx.params.viewName), recordController.fetchView ) - .get("/api/views", authorized(BUILDER), viewController.fetch) + .get("/api/views", viewController.fetch) + .get("/api/views/query/:viewName", viewController.query) // .patch("/api/:databaseId/views", controller.update); // .delete("/api/:instanceId/views/:viewId/:revId", controller.destroy); - .post("/api/views", authorized(BUILDER), viewController.create) + .post("/api/views", viewController.create) module.exports = router diff --git a/packages/server/src/electron.js b/packages/server/src/electron.js index 32bcd2bd43..36b7118306 100644 --- a/packages/server/src/electron.js +++ b/packages/server/src/electron.js @@ -36,7 +36,10 @@ async function startApp() { async function createWindow() { app.server = require("./app") - win = new BrowserWindow({ width: 1920, height: 1080 }) + win = new BrowserWindow({ + width: 1920, + height: 1080, + }) win.setTitle(APP_TITLE) win.loadURL(APP_URL) if (isDev) { diff --git a/packages/standard-components/src/Chart/tests/bar.html b/packages/standard-components/src/Chart/tests/bar.html index 4bedca035a..8a00ee98f2 100644 --- a/packages/standard-components/src/Chart/tests/bar.html +++ b/packages/standard-components/src/Chart/tests/bar.html @@ -6,7 +6,7 @@ Document - From 6862be744bf3a9e98338851bdd0071d9d4b14c60 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Fri, 14 Aug 2020 16:31:53 +0100 Subject: [PATCH 2/9] began UI for custom views --- .../builder/src/builderStore/store/backend.js | 19 ++- .../ModelDataTable/ModelDataTable.svelte | 5 +- .../modals/RecordFieldControl.svelte | 6 +- .../ModelDataTable/popovers/Column.svelte | 2 - .../popovers/ColumnHeader.svelte | 2 - .../ModelDataTable/popovers/View.svelte | 41 +++++ .../nav/ModelNavigator/EditView.svelte | 137 +++++++++++++++ .../nav/ModelNavigator/ListItem.svelte | 10 +- .../nav/ModelNavigator/ModelNavigator.svelte | 26 ++- .../nav/ModelSetupNav/ModelFieldEditor.svelte | 120 -------------- .../nav/ModelSetupNav/ModelSetupNav.svelte | 156 ------------------ .../src/components/nav/ModelSetupNav/index.js | 1 - .../[application]/backend/_layout.svelte | 38 ----- .../src/api/controllers/view/customViews.js | 27 --- .../server/src/api/controllers/view/index.js | 42 +++-- .../src/api/controllers/view/viewBuilder.js | 21 +++ .../tests/__snapshots__/view.spec.js.snap | 44 +++++ .../src/api/routes/tests/couchTestUtils.js | 3 - .../server/src/api/routes/tests/view.spec.js | 131 ++++++++++++--- packages/server/src/api/routes/view.js | 6 +- .../server/src/middleware/authenticated.js | 4 + 21 files changed, 427 insertions(+), 414 deletions(-) create mode 100644 packages/builder/src/components/nav/ModelNavigator/EditView.svelte delete mode 100644 packages/builder/src/components/nav/ModelSetupNav/ModelFieldEditor.svelte delete mode 100644 packages/builder/src/components/nav/ModelSetupNav/ModelSetupNav.svelte delete mode 100644 packages/builder/src/components/nav/ModelSetupNav/index.js delete mode 100644 packages/builder/src/pages/[application]/backend/_layout.svelte delete mode 100644 packages/server/src/api/controllers/view/customViews.js create mode 100644 packages/server/src/api/controllers/view/viewBuilder.js create mode 100644 packages/server/src/api/routes/tests/__snapshots__/view.spec.js.snap diff --git a/packages/builder/src/builderStore/store/backend.js b/packages/builder/src/builderStore/store/backend.js index 28272d9893..7c80f21353 100644 --- a/packages/builder/src/builderStore/store/backend.js +++ b/packages/builder/src/builderStore/store/backend.js @@ -59,7 +59,6 @@ export const getBackendUiStore = () => { store.update(state => { state.selectedModel = model state.draftModel = cloneDeep(model) - state.selectedField = "" state.selectedView = `all_${model._id}` return state }), @@ -87,10 +86,8 @@ export const getBackendUiStore = () => { delete: async model => { await api.delete(`/api/models/${model._id}/${model._rev}`) store.update(state => { - state.models = state.models.filter( - existing => existing._id !== model._id - ) - state.selectedModel = state.models[0] || {} + state.models = state.models.filter(existing => existing._id !== model._id) + state.selectedModel = state.models[0] || {} return state }) }, @@ -113,14 +110,24 @@ export const getBackendUiStore = () => { store.actions.models.save(state.draftModel) return state }) - }, + } }, views: { select: view => store.update(state => { state.selectedView = view + state.selectedModel = {} return state }), + save: async view => { + const response = await api.post(`/api/views`, view) + const savedView = await response.json() + await store.actions.models.fetch() + store.update(state => { + state.selectedView = view.name + return state + }) + } }, users: { create: user => diff --git a/packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte b/packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte index fa36018ae8..3caa7e4678 100644 --- a/packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte +++ b/packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte @@ -1,6 +1,7 @@ + +
+ +
+ +
Create View
+
+ +
+
+ + +
+
+ + diff --git a/packages/builder/src/components/nav/ModelNavigator/EditView.svelte b/packages/builder/src/components/nav/ModelNavigator/EditView.svelte new file mode 100644 index 0000000000..cc6ce2036d --- /dev/null +++ b/packages/builder/src/components/nav/ModelNavigator/EditView.svelte @@ -0,0 +1,137 @@ + + +
+ +
+ + {#if editing} +
Edit View
+
+ +
+
+
+ +
+
+ +
+
+ {:else} +
    +
  • + + Edit +
  • +
  • + + Delete +
  • +
+ {/if} +
+ + diff --git a/packages/builder/src/components/nav/ModelNavigator/ListItem.svelte b/packages/builder/src/components/nav/ModelNavigator/ListItem.svelte index 5fb2832162..85582f0345 100644 --- a/packages/builder/src/components/nav/ModelNavigator/ListItem.svelte +++ b/packages/builder/src/components/nav/ModelNavigator/ListItem.svelte @@ -6,15 +6,19 @@ export let indented -
- +
+ {title}
diff --git a/packages/builder/src/components/nav/ModelSetupNav/ModelSetupNav.svelte b/packages/builder/src/components/nav/ModelSetupNav/ModelSetupNav.svelte deleted file mode 100644 index cdbe784421..0000000000 --- a/packages/builder/src/components/nav/ModelSetupNav/ModelSetupNav.svelte +++ /dev/null @@ -1,156 +0,0 @@ - - -
- - {#if selectedTab === 'SETUP'} - {#if $backendUiStore.selectedField} - - {:else if $backendUiStore.draftModel.schema} -
-
Name
- -
- - {/if} -
- -
- {:else if selectedTab === 'DELETE'} -
-
Danger Zone
- -
- {/if} -
-
- - diff --git a/packages/builder/src/components/nav/ModelSetupNav/index.js b/packages/builder/src/components/nav/ModelSetupNav/index.js deleted file mode 100644 index e772d21707..0000000000 --- a/packages/builder/src/components/nav/ModelSetupNav/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default as ModelSetupNav } from "./ModelSetupNav.svelte" diff --git a/packages/builder/src/pages/[application]/backend/_layout.svelte b/packages/builder/src/pages/[application]/backend/_layout.svelte deleted file mode 100644 index 36fc25c869..0000000000 --- a/packages/builder/src/pages/[application]/backend/_layout.svelte +++ /dev/null @@ -1,38 +0,0 @@ - - -
- -
- -
-
- - diff --git a/packages/server/src/api/controllers/view/customViews.js b/packages/server/src/api/controllers/view/customViews.js deleted file mode 100644 index 66e643f809..0000000000 --- a/packages/server/src/api/controllers/view/customViews.js +++ /dev/null @@ -1,27 +0,0 @@ -const FORMULA_MAP = { - SUM: "_sum", - COUNT: "_count", - STATS: "_stats" -}; - -function customViewTemplate({ - field, - formula, - modelId -}) { - return { - meta: { - field, - formula, - modelId - }, - map: `function (doc) { - if (doc.modelId === "${modelId}") { - emit(doc._id, doc["${field}"]); - } - }`, - reduce: "_stats" - } -} - -module.exports = customViewTemplate \ No newline at end of file diff --git a/packages/server/src/api/controllers/view/index.js b/packages/server/src/api/controllers/view/index.js index e65cfd97c3..a58bcf7ead 100644 --- a/packages/server/src/api/controllers/view/index.js +++ b/packages/server/src/api/controllers/view/index.js @@ -1,23 +1,25 @@ const CouchDB = require("../../../db") -const customViewTemplate = require("./customViews"); +const statsViewTemplate = require("./viewBuilder"); const controller = { query: async ctx => { - // const db = new CouchDB(ctx.user.instanceId) - const db = new CouchDB("inst_4e6f424_970ca7f2b9e24ec8896eb10862d7f22b") + const db = new CouchDB(ctx.user.instanceId) + const { meta } = ctx.request.body const response = await db.query(`database/${ctx.params.viewName}`, { - group: false + group: !!meta.groupBy }) + for (row of response.rows) { + row.value = { + ...row.value, + avg: row.value.sum / row.value.count + } + } + ctx.body = response.rows - // ctx.body = { - // ...data, - // avg: data.sum / data.count - // } }, fetch: async ctx => { - // const db = new CouchDB(ctx.user.instanceId) - const db = new CouchDB("inst_4e6f424_970ca7f2b9e24ec8896eb10862d7f22b") + const db = new CouchDB(ctx.user.instanceId) const designDoc = await db.get("_design/database") const response = [] @@ -37,14 +39,13 @@ const controller = { ctx.body = response }, - create: async ctx => { - // const db = new CouchDB(ctx.user.instanceId) - const db = new CouchDB("inst_4e6f424_970ca7f2b9e24ec8896eb10862d7f22b") + save: async ctx => { + const db = new CouchDB(ctx.user.instanceId) const newView = ctx.request.body const designDoc = await db.get("_design/database") - const view = customViewTemplate(ctx.request.body) + const view = statsViewTemplate(newView) designDoc.views = { ...designDoc.views, @@ -53,8 +54,17 @@ const controller = { await db.put(designDoc) - ctx.body = newView - ctx.message = `View ${newView.name} created successfully.` + + // add views to model document + const model = await db.get(ctx.request.body.modelId) + model.views = { + ...(model.views ? model.views : {}), + [newView.name]: view.meta + } + await db.put(model) + + ctx.body = view + ctx.message = `View ${newView.name} saved successfully.` }, destroy: async ctx => { const db = new CouchDB(ctx.user.instanceId) diff --git a/packages/server/src/api/controllers/view/viewBuilder.js b/packages/server/src/api/controllers/view/viewBuilder.js new file mode 100644 index 0000000000..76ebd2c437 --- /dev/null +++ b/packages/server/src/api/controllers/view/viewBuilder.js @@ -0,0 +1,21 @@ +function statsViewTemplate({ + field, + modelId, + groupBy +}) { + return { + meta: { + field, + modelId, + groupBy + }, + map: `function (doc) { + if (doc.modelId === "${modelId}") { + emit(doc["${groupBy || "_id"}"], doc["${field}"]); + } + }`, + reduce: "_stats" + } +} + +module.exports = statsViewTemplate \ No newline at end of file diff --git a/packages/server/src/api/routes/tests/__snapshots__/view.spec.js.snap b/packages/server/src/api/routes/tests/__snapshots__/view.spec.js.snap new file mode 100644 index 0000000000..96ce281ee1 --- /dev/null +++ b/packages/server/src/api/routes/tests/__snapshots__/view.spec.js.snap @@ -0,0 +1,44 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`/views query returns data for the created view 1`] = ` +Array [ + Object { + "key": null, + "value": Object { + "avg": 2333.3333333333335, + "count": 3, + "max": 4000, + "min": 1000, + "sum": 7000, + "sumsqr": 21000000, + }, + }, +] +`; + +exports[`/views query returns data for the created view using a group by 1`] = ` +Array [ + Object { + "key": "One", + "value": Object { + "avg": 1500, + "count": 2, + "max": 2000, + "min": 1000, + "sum": 3000, + "sumsqr": 5000000, + }, + }, + Object { + "key": "Two", + "value": Object { + "avg": 4000, + "count": 1, + "max": 4000, + "min": 4000, + "sum": 4000, + "sumsqr": 16000000, + }, + }, +] +`; diff --git a/packages/server/src/api/routes/tests/couchTestUtils.js b/packages/server/src/api/routes/tests/couchTestUtils.js index e87233d458..594c4a3121 100644 --- a/packages/server/src/api/routes/tests/couchTestUtils.js +++ b/packages/server/src/api/routes/tests/couchTestUtils.js @@ -193,9 +193,6 @@ const createUserWithPermissions = async ( accessLevelId: accessRes.body._id, }) - //const db = new CouchDB(instanceId) - //const designDoc = await db.get("_design/database") - const anonUser = { userId: "ANON", accessLevelId: ANON_LEVEL_ID, diff --git a/packages/server/src/api/routes/tests/view.spec.js b/packages/server/src/api/routes/tests/view.spec.js index 5a889bed67..ef173a224a 100644 --- a/packages/server/src/api/routes/tests/view.spec.js +++ b/packages/server/src/api/routes/tests/view.spec.js @@ -4,7 +4,8 @@ const { createInstance, createModel, supertest, - defaultHeaders + defaultHeaders, + getDocument } = require("./couchTestUtils") describe("/views", () => { @@ -14,6 +15,25 @@ describe("/views", () => { let instance let model + const createView = async (config = { + name: "TestView", + field: "Price", + modelId: model._id + }) => + await request + .post(`/api/views`) + .send(config) + .set(defaultHeaders(app._id, instance._id)) + .expect('Content-Type', /json/) + .expect(200) + + const createRecord = async record => request + .post(`/api/${model._id}/records`) + .send(record) + .set(defaultHeaders(app._id, instance._id)) + .expect('Content-Type', /json/) + .expect(200) + beforeAll(async () => { ({ request, server } = await supertest()) await createClientDatabase(request) @@ -28,46 +48,111 @@ describe("/views", () => { server.close() }) - const createView = async () => - await request - .post(`/api/views`) - .send({ - name: "TestView", - map: `function(doc) { - if (doc.id) { - emit(doc.name, doc._id); - } - }`, - reduce: `function(keys, values) { }` - }) - .set(defaultHeaders(app._id, instance._id)) - .expect('Content-Type', /json/) - .expect(200) - describe("create", () => { + beforeEach(async () => { + model = await createModel(request, app._id, instance._id); + }) it("returns a success message when the view is successfully created", async () => { const res = await createView() - expect(res.res.statusMessage).toEqual("View TestView created successfully."); - expect(res.body.name).toEqual("TestView"); + expect(res.res.statusMessage).toEqual("View TestView saved successfully."); + }) + + it("updates the model record with the new view metadata", async () => { + const res = await createView() + expect(res.res.statusMessage).toEqual("View TestView saved successfully."); + const updatedModel = await getDocument(instance._id, model._id) + expect(updatedModel.views).toEqual({ + TestView: { + field: "Price", + modelId: model._id + } + }); }) }); describe("fetch", () => { - beforeEach(async () => { model = await createModel(request, app._id, instance._id); }); - it("should only return custom views", async () => { - const view = await createView() + it("returns only custom views", async () => { + await createView() const res = await request .get(`/api/views`) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) .expect(200) expect(res.body.length).toBe(1) - expect(res.body.find(v => v.name === view.body.name)).toBeDefined() + expect(res.body.find(({ name }) => name === "TestView")).toBeDefined() + }) + }); + + describe("query", () => { + beforeEach(async () => { + model = await createModel(request, app._id, instance._id); + }); + + it("returns data for the created view", async () => { + await createView() + await createRecord({ + modelId: model._id, + Price: 1000 + }) + await createRecord({ + modelId: model._id, + Price: 2000 + }) + await createRecord({ + modelId: model._id, + Price: 4000 + }) + const res = await request + .post(`/api/views/query/TestView`) + .send({ + meta: {} + }) + .set(defaultHeaders(app._id, instance._id)) + .expect('Content-Type', /json/) + .expect(200) + expect(res.body.length).toBe(1) + expect(res.body).toMatchSnapshot() + }) + + it("returns data for the created view using a group by", async () => { + await createView({ + name: "TestView", + field: "Price", + groupBy: "Category", + modelId: model._id + }) + await createRecord({ + modelId: model._id, + Price: 1000, + Category: "One" + }) + await createRecord({ + modelId: model._id, + Price: 2000, + Category: "One" + }) + await createRecord({ + modelId: model._id, + Price: 4000, + Category: "Two" + }) + const res = await request + .post(`/api/views/query/TestView`) + .send({ + meta: { + groupBy: "Category" + } + }) + .set(defaultHeaders(app._id, instance._id)) + .expect('Content-Type', /json/) + .expect(200) + expect(res.body.length).toBe(2) + expect(res.body).toMatchSnapshot() }) }); }); \ No newline at end of file diff --git a/packages/server/src/api/routes/view.js b/packages/server/src/api/routes/view.js index aa839c0d96..549fc1659e 100644 --- a/packages/server/src/api/routes/view.js +++ b/packages/server/src/api/routes/view.js @@ -13,9 +13,7 @@ router recordController.fetchView ) .get("/api/views", viewController.fetch) - .get("/api/views/query/:viewName", viewController.query) - // .patch("/api/:databaseId/views", controller.update); - // .delete("/api/:instanceId/views/:viewId/:revId", controller.destroy); - .post("/api/views", viewController.create) + .post("/api/views/query/:viewName", viewController.query) + .post("/api/views", viewController.save) module.exports = router diff --git a/packages/server/src/middleware/authenticated.js b/packages/server/src/middleware/authenticated.js index 53cb0b2c13..e1ad397d7e 100644 --- a/packages/server/src/middleware/authenticated.js +++ b/packages/server/src/middleware/authenticated.js @@ -14,6 +14,10 @@ module.exports = async (ctx, next) => { return } + // ctx.user = { + // instanceId: "inst_4e6f424_970ca7f2b9e24ec8896eb10862d7f22b" + // } + const appToken = ctx.cookies.get("budibase:token") const builderToken = ctx.cookies.get("builder:token") From 28b4b6fcb94a8bad96e384f614f373d27eb78160 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 17 Aug 2020 21:01:43 +0100 Subject: [PATCH 3/9] deletion of views, statistics calculation popover, unit tests --- packages/builder/package.json | 2 +- .../builder/src/builderStore/store/backend.js | 22 +- .../LinkedRecord.svelte | 0 .../ModelDataTable.svelte | 21 +- .../database/DataTable/Table.svelte | 150 +++++++++++ .../TablePagination.svelte | 0 .../database/DataTable/ViewDataTable.svelte | 63 +++++ .../{ModelDataTable => DataTable}/api.js | 24 +- .../{ModelDataTable => DataTable}/index.js | 0 .../modals/CreateEditColumn.svelte | 0 .../modals/CreateEditRecord.svelte | 0 .../modals/CreateUser.svelte | 0 .../modals/DeleteRecord.svelte | 0 .../modals/DeleteTable.svelte | 0 .../DataTable/modals/DeleteView.svelte | 60 +++++ .../modals/RecordFieldControl.svelte | 0 .../modals/index.js | 1 - .../DataTable/popovers/Calculate.svelte | 88 +++++++ .../popovers/Column.svelte | 0 .../popovers/ColumnHeader.svelte | 0 .../popovers/EditRow.svelte | 0 .../popovers/Row.svelte | 0 .../popovers/View.svelte | 31 ++- .../modals/CreateEditView.svelte | 127 ---------- .../src/components/nav/HierarchyRow.svelte | 45 ---- .../nav/ModelNavigator/EditTable.svelte | 4 +- .../nav/ModelNavigator/EditView.svelte | 16 +- .../nav/ModelNavigator/ModelNavigator.svelte | 13 +- .../userInterface/ModelSelect.svelte | 20 +- .../[application]/backend/_layout.svelte | 34 +++ .../model/[selectedModel]/index.svelte | 6 +- .../view/[selectedView]/_layout.svelte | 22 ++ .../backend/view/[selectedView]/index.svelte | 27 ++ packages/builder/yarn.lock | 239 +++++++++++++++++- packages/server/src/api/controllers/record.js | 19 +- .../server/src/api/controllers/view/index.js | 17 +- .../src/api/controllers/view/viewBuilder.js | 10 +- packages/server/src/api/routes/view.js | 7 +- packages/server/src/app.js | 2 + 39 files changed, 807 insertions(+), 263 deletions(-) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/LinkedRecord.svelte (100%) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/ModelDataTable.svelte (91%) create mode 100644 packages/builder/src/components/database/DataTable/Table.svelte rename packages/builder/src/components/database/{ModelDataTable => DataTable}/TablePagination.svelte (100%) create mode 100644 packages/builder/src/components/database/DataTable/ViewDataTable.svelte rename packages/builder/src/components/database/{ModelDataTable => DataTable}/api.js (67%) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/index.js (100%) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/modals/CreateEditColumn.svelte (100%) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/modals/CreateEditRecord.svelte (100%) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/modals/CreateUser.svelte (100%) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/modals/DeleteRecord.svelte (100%) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/modals/DeleteTable.svelte (100%) create mode 100644 packages/builder/src/components/database/DataTable/modals/DeleteView.svelte rename packages/builder/src/components/database/{ModelDataTable => DataTable}/modals/RecordFieldControl.svelte (100%) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/modals/index.js (74%) create mode 100644 packages/builder/src/components/database/DataTable/popovers/Calculate.svelte rename packages/builder/src/components/database/{ModelDataTable => DataTable}/popovers/Column.svelte (100%) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/popovers/ColumnHeader.svelte (100%) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/popovers/EditRow.svelte (100%) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/popovers/Row.svelte (100%) rename packages/builder/src/components/database/{ModelDataTable => DataTable}/popovers/View.svelte (52%) delete mode 100644 packages/builder/src/components/database/ModelDataTable/modals/CreateEditView.svelte delete mode 100644 packages/builder/src/components/nav/HierarchyRow.svelte create mode 100644 packages/builder/src/pages/[application]/backend/_layout.svelte create mode 100644 packages/builder/src/pages/[application]/backend/view/[selectedView]/_layout.svelte create mode 100644 packages/builder/src/pages/[application]/backend/view/[selectedView]/index.svelte diff --git a/packages/builder/package.json b/packages/builder/package.json index 75faa8671f..5b77a06687 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -57,7 +57,7 @@ ] }, "dependencies": { - "@budibase/bbui": "^1.23.1", + "@budibase/bbui": "^1.24.0", "@budibase/client": "^0.1.17", "@budibase/colorpicker": "^1.0.1", "@nx-js/compiler-util": "^2.0.0", diff --git a/packages/builder/src/builderStore/store/backend.js b/packages/builder/src/builderStore/store/backend.js index 7c80f21353..0100d77934 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,7 +56,7 @@ export const getBackendUiStore = () => { store.update(state => { state.selectedModel = model state.draftModel = cloneDeep(model) - state.selectedView = `all_${model._id}` + state.selectedView = { name: `all_${model._id}` } return state }), save: async model => { @@ -119,12 +116,19 @@ export const getBackendUiStore = () => { state.selectedModel = {} return state }), - save: async view => { - const response = await api.post(`/api/views`, view) - const savedView = await response.json() - await store.actions.models.fetch() + delete: async view => { + await api.delete(`/api/views/${view}`) store.update(state => { - state.selectedView = view.name + store.actions.models.select(state.models[0]) + return state + }) + await store.actions.models.fetch() + }, + save: async view => { + await api.post(`/api/views`, view) + store.update(state => { + state.selectedModel.views[view.name] = view + state.selectedView = view return state }) } diff --git a/packages/builder/src/components/database/ModelDataTable/LinkedRecord.svelte b/packages/builder/src/components/database/DataTable/LinkedRecord.svelte similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/LinkedRecord.svelte rename to packages/builder/src/components/database/DataTable/LinkedRecord.svelte diff --git a/packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte b/packages/builder/src/components/database/DataTable/ModelDataTable.svelte similarity index 91% rename from packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte rename to packages/builder/src/components/database/DataTable/ModelDataTable.svelte index 3caa7e4678..486eec5633 100644 --- a/packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte +++ b/packages/builder/src/components/database/DataTable/ModelDataTable.svelte @@ -23,12 +23,11 @@ let modalOpen = false let data = [] let headers = [] - let views = [] let currentPage = 0 let search $: { - if ($backendUiStore.selectedView) { + if ($backendUiStore.selectedView && $backendUiStore.selectedView.name.startsWith("all_")) { api.fetchDataForView($backendUiStore.selectedView).then(records => { data = records || [] }) @@ -49,22 +48,6 @@ ) $: schema = $backendUiStore.selectedModel.schema - - const createNewRecord = () => { - open( - CreateEditRecordModal, - { - onClosed: close, - }, - { styleContent: { padding: "0" } } - ) - } - - onMount(() => { - if (views.length) { - backendUiStore.actions.views.select(views[0]) - } - })
@@ -105,7 +88,7 @@ {#if schema[header].type === 'link'} - {:else}{getOr("", header, row)}{/if} + {:else}{getOr('', header, row)}{/if} {/each} diff --git a/packages/builder/src/components/database/DataTable/Table.svelte b/packages/builder/src/components/database/DataTable/Table.svelte new file mode 100644 index 0000000000..5d519cd7c8 --- /dev/null +++ b/packages/builder/src/components/database/DataTable/Table.svelte @@ -0,0 +1,150 @@ + + +
+
+

{title}

+
+ +
+
+ + + + {#each columns as header} + + {/each} + + + + {#if paginatedData.length === 0} +
No Data.
+ {/if} + {#each paginatedData as row} + + {#each columns as header} + + {/each} + + {/each} + +
{header.name}
{getOr('', header.key, row)}
+ +
+ + diff --git a/packages/builder/src/components/database/ModelDataTable/TablePagination.svelte b/packages/builder/src/components/database/DataTable/TablePagination.svelte similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/TablePagination.svelte rename to packages/builder/src/components/database/DataTable/TablePagination.svelte diff --git a/packages/builder/src/components/database/DataTable/ViewDataTable.svelte b/packages/builder/src/components/database/DataTable/ViewDataTable.svelte new file mode 100644 index 0000000000..804bec6810 --- /dev/null +++ b/packages/builder/src/components/database/DataTable/ViewDataTable.svelte @@ -0,0 +1,63 @@ + + + + +
diff --git a/packages/builder/src/components/database/ModelDataTable/api.js b/packages/builder/src/components/database/DataTable/api.js similarity index 67% rename from packages/builder/src/components/database/ModelDataTable/api.js rename to packages/builder/src/components/database/DataTable/api.js index 3434cdb4f1..f4c9a44380 100644 --- a/packages/builder/src/components/database/ModelDataTable/api.js +++ b/packages/builder/src/components/database/DataTable/api.js @@ -6,20 +6,6 @@ export async function createUser(user) { return await response.json() } -export async function createDatabase(appname, instanceName) { - const CREATE_DATABASE_URL = `/api/${appname}/instances` - const response = await api.post(CREATE_DATABASE_URL, { - name: instanceName, - }) - return await response.json() -} - -export async function deleteRecord(record) { - const DELETE_RECORDS_URL = `/api/${record.modelId}/records/${record._id}/${record._rev}` - const response = await api.delete(DELETE_RECORDS_URL) - return response -} - export async function saveRecord(record, modelId) { const SAVE_RECORDS_URL = `/api/${modelId}/records` const response = await api.post(SAVE_RECORDS_URL, record) @@ -27,8 +13,14 @@ export async function saveRecord(record, modelId) { return await response.json() } -export async function fetchDataForView(viewName) { - const FETCH_RECORDS_URL = `/api/views/${viewName}` +export async function deleteRecord(record) { + const DELETE_RECORDS_URL = `/api/${record.modelId}/records/${record._id}/${record._rev}` + const response = await api.delete(DELETE_RECORDS_URL) + return response +} + +export async function fetchDataForView(view) { + const FETCH_RECORDS_URL = `/api/views/${view.name}` const response = await api.get(FETCH_RECORDS_URL) return await response.json() diff --git a/packages/builder/src/components/database/ModelDataTable/index.js b/packages/builder/src/components/database/DataTable/index.js similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/index.js rename to packages/builder/src/components/database/DataTable/index.js diff --git a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/database/DataTable/modals/CreateEditColumn.svelte similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/modals/CreateEditColumn.svelte rename to packages/builder/src/components/database/DataTable/modals/CreateEditColumn.svelte diff --git a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditRecord.svelte b/packages/builder/src/components/database/DataTable/modals/CreateEditRecord.svelte similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/modals/CreateEditRecord.svelte rename to packages/builder/src/components/database/DataTable/modals/CreateEditRecord.svelte diff --git a/packages/builder/src/components/database/ModelDataTable/modals/CreateUser.svelte b/packages/builder/src/components/database/DataTable/modals/CreateUser.svelte similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/modals/CreateUser.svelte rename to packages/builder/src/components/database/DataTable/modals/CreateUser.svelte diff --git a/packages/builder/src/components/database/ModelDataTable/modals/DeleteRecord.svelte b/packages/builder/src/components/database/DataTable/modals/DeleteRecord.svelte similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/modals/DeleteRecord.svelte rename to packages/builder/src/components/database/DataTable/modals/DeleteRecord.svelte diff --git a/packages/builder/src/components/database/ModelDataTable/modals/DeleteTable.svelte b/packages/builder/src/components/database/DataTable/modals/DeleteTable.svelte similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/modals/DeleteTable.svelte rename to packages/builder/src/components/database/DataTable/modals/DeleteTable.svelte diff --git a/packages/builder/src/components/database/DataTable/modals/DeleteView.svelte b/packages/builder/src/components/database/DataTable/modals/DeleteView.svelte new file mode 100644 index 0000000000..f845b18425 --- /dev/null +++ b/packages/builder/src/components/database/DataTable/modals/DeleteView.svelte @@ -0,0 +1,60 @@ + + +
+
+ + +

Delete View

+
+

+ Are you sure you want to delete this view? All of your data will be + permanently removed. This action cannot be undone. +

+
+ +
+ + diff --git a/packages/builder/src/components/database/ModelDataTable/modals/RecordFieldControl.svelte b/packages/builder/src/components/database/DataTable/modals/RecordFieldControl.svelte similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/modals/RecordFieldControl.svelte rename to packages/builder/src/components/database/DataTable/modals/RecordFieldControl.svelte diff --git a/packages/builder/src/components/database/ModelDataTable/modals/index.js b/packages/builder/src/components/database/DataTable/modals/index.js similarity index 74% rename from packages/builder/src/components/database/ModelDataTable/modals/index.js rename to packages/builder/src/components/database/DataTable/modals/index.js index bb49df8746..6bd9691228 100644 --- a/packages/builder/src/components/database/ModelDataTable/modals/index.js +++ b/packages/builder/src/components/database/DataTable/modals/index.js @@ -1,4 +1,3 @@ export { default as DeleteRecordModal } from "./DeleteRecord.svelte" export { default as CreateEditRecordModal } from "./CreateEditRecord.svelte" -export { default as CreateEditViewModal } from "./CreateEditView.svelte" export { default as CreateUserModal } from "./CreateUser.svelte" diff --git a/packages/builder/src/components/database/DataTable/popovers/Calculate.svelte b/packages/builder/src/components/database/DataTable/popovers/Calculate.svelte new file mode 100644 index 0000000000..ab25c8b4ee --- /dev/null +++ b/packages/builder/src/components/database/DataTable/popovers/Calculate.svelte @@ -0,0 +1,88 @@ + + +
+ +
+ +
Calculate
+
+

The

+ +

of

+ +
+
+ + +
+
+ + diff --git a/packages/builder/src/components/database/ModelDataTable/popovers/Column.svelte b/packages/builder/src/components/database/DataTable/popovers/Column.svelte similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/popovers/Column.svelte rename to packages/builder/src/components/database/DataTable/popovers/Column.svelte diff --git a/packages/builder/src/components/database/ModelDataTable/popovers/ColumnHeader.svelte b/packages/builder/src/components/database/DataTable/popovers/ColumnHeader.svelte similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/popovers/ColumnHeader.svelte rename to packages/builder/src/components/database/DataTable/popovers/ColumnHeader.svelte diff --git a/packages/builder/src/components/database/ModelDataTable/popovers/EditRow.svelte b/packages/builder/src/components/database/DataTable/popovers/EditRow.svelte similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/popovers/EditRow.svelte rename to packages/builder/src/components/database/DataTable/popovers/EditRow.svelte diff --git a/packages/builder/src/components/database/ModelDataTable/popovers/Row.svelte b/packages/builder/src/components/database/DataTable/popovers/Row.svelte similarity index 100% rename from packages/builder/src/components/database/ModelDataTable/popovers/Row.svelte rename to packages/builder/src/components/database/DataTable/popovers/Row.svelte diff --git a/packages/builder/src/components/database/ModelDataTable/popovers/View.svelte b/packages/builder/src/components/database/DataTable/popovers/View.svelte similarity index 52% rename from packages/builder/src/components/database/ModelDataTable/popovers/View.svelte rename to packages/builder/src/components/database/DataTable/popovers/View.svelte index fe150b2337..d78d6a923d 100644 --- a/packages/builder/src/components/database/ModelDataTable/popovers/View.svelte +++ b/packages/builder/src/components/database/DataTable/popovers/View.svelte @@ -1,18 +1,29 @@ @@ -26,6 +37,11 @@
Create View
+
@@ -38,4 +54,17 @@ margin-bottom: var(--spacing-l); font-weight: 500; } + + .button-group { + margin-top: var(--spacing-l); + display: flex; + justify-content: flex-end; + gap: var(--spacing-s); + } + + .input-group-column { + display: flex; + flex-direction: column; + gap: var(--spacing-s); + } diff --git a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditView.svelte b/packages/builder/src/components/database/ModelDataTable/modals/CreateEditView.svelte deleted file mode 100644 index c7d3ec8af0..0000000000 --- a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditView.svelte +++ /dev/null @@ -1,127 +0,0 @@ - - -
- -

Create / Edit View

-
-
- {#if $store.errors && $store.errors.length > 0} - - {/if} -
-
-
- -
-
-
- {#each Object.values(SNIPPET_EDITORS) as snippetType} - (currentSnippetEditor = snippetType)}> - {snippetType} - - {/each} - {#if currentSnippetEditor === SNIPPET_EDITORS.MAP} - - {:else if currentSnippetEditor === SNIPPET_EDITORS.FILTER} - - {:else if currentSnippetEditor === SNIPPET_EDITORS.REDUCE} - - {/if} -
-
-
-
- Delete -
- Save -
- - - diff --git a/packages/builder/src/components/nav/HierarchyRow.svelte b/packages/builder/src/components/nav/HierarchyRow.svelte deleted file mode 100644 index 3baacd208e..0000000000 --- a/packages/builder/src/components/nav/HierarchyRow.svelte +++ /dev/null @@ -1,45 +0,0 @@ - - -
-
onSelect(node)} - class="budibase__nav-item hierarchy-item" - class:capitalized={type === 'model'} - class:selected={$backendUiStore.selectedView === `all_${node._id}`}> - - {node.name} -
-
- - diff --git a/packages/builder/src/components/nav/ModelNavigator/EditTable.svelte b/packages/builder/src/components/nav/ModelNavigator/EditTable.svelte index 3bfa5892d1..e4893e3a3f 100644 --- a/packages/builder/src/components/nav/ModelNavigator/EditTable.svelte +++ b/packages/builder/src/components/nav/ModelNavigator/EditTable.svelte @@ -3,7 +3,7 @@ import { backendUiStore } from "builderStore" import { DropdownMenu, Button, Icon, Input, Select } from "@budibase/bbui" import { FIELDS } from "constants/backend" - import DeleteTableModal from "components/database/ModelDataTable/modals/DeleteTable.svelte" + import DeleteTableModal from "components/database/DataTable/modals/DeleteTable.svelte" const { open, close } = getContext("simple-modal") @@ -28,7 +28,7 @@ open( DeleteTableModal, { - onClosed: close, + onClosed: hideEditor, table, }, { styleContent: { padding: "0" } } diff --git a/packages/builder/src/components/nav/ModelNavigator/EditView.svelte b/packages/builder/src/components/nav/ModelNavigator/EditView.svelte index cc6ce2036d..4cd14e454c 100644 --- a/packages/builder/src/components/nav/ModelNavigator/EditView.svelte +++ b/packages/builder/src/components/nav/ModelNavigator/EditView.svelte @@ -3,11 +3,11 @@ import { backendUiStore } from "builderStore" import { DropdownMenu, Button, Icon, Input, Select } from "@budibase/bbui" import { FIELDS } from "constants/backend" - import DeleteTableModal from "components/database/ModelDataTable/modals/DeleteTable.svelte" + import DeleteViewModal from "components/database/DataTable/modals/DeleteView.svelte" const { open, close } = getContext("simple-modal") - export let table + export let view let anchor let dropdown @@ -24,19 +24,19 @@ close() } - const deleteTable = () => { + const deleteView = () => { open( - DeleteTableModal, + DeleteViewModal, { onClosed: close, - table, + view, }, { styleContent: { padding: "0" } } ) } function save() { - backendUiStore.actions.models.save(table) + backendUiStore.actions.views.save(view) hideEditor() } @@ -48,7 +48,7 @@ {#if editing}
Edit View
- +