From a552772ccc1c33dbbc0b12a34e1c12946e436ae0 Mon Sep 17 00:00:00 2001 From: Joe <49767913+joebudi@users.noreply.github.com> Date: Thu, 11 Jun 2020 13:07:10 +0100 Subject: [PATCH 1/8] Props update, including flex, border, shadow, rotate --- .../userInterface/propertyCategories.js | 66 ++++++++++++++----- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/packages/builder/src/components/userInterface/propertyCategories.js b/packages/builder/src/components/userInterface/propertyCategories.js index 38ef0558e4..8ee38d3c35 100644 --- a/packages/builder/src/components/userInterface/propertyCategories.js +++ b/packages/builder/src/components/userInterface/propertyCategories.js @@ -12,8 +12,9 @@ export const layout = [ label: "Display", key: "display", control: OptionSelect, - initialValue: "Flex", + initialValue: "", options: [ + { label: "", value: "" }, { label: "Flex", value: "flex" }, { label: "Inline Flex", value: "inline-flex" }, ], @@ -39,6 +40,7 @@ export const layout = [ control: OptionSelect, initialValue: "Flex Start", options: [ + { label: "", value: "" }, { label: "Flex Start", value: "flex-start" }, { label: "Flex End", value: "flex-end" }, { label: "Center", value: "center" }, @@ -317,19 +319,31 @@ export const border = [ { label: "Radius", key: "border-radius", - control: Input, - width: "48px", - placeholder: "px", - textAlign: "center", + control: OptionSelect, + defaultValue: "None", + options: [ + { label: "None", value: "0" }, + { label: "small", value: "0.125rem" }, + { label: "Medium", value: "0.25rem;" }, + { label: "Large", value: "0.375rem" }, + { label: "Extra large", value: "0.5rem" }, + { label: "Full", value: "5678px" }, + ], }, { label: "Width", key: "border-width", - control: Input, - width: "48px", - placeholder: "px", - textAlign: "center", - }, //custom + control: OptionSelect, + defaultValue: "None", + options: [ + { label: "None", value: "0" }, + { label: "Extra small", value: "0.5px" }, + { label: "Small", value: "1px" }, + { label: "Medium", value: "2px" }, + { label: "Large", value: "4px" }, + { label: "Extra large", value: "8px" }, + ], + }, { label: "Color", key: "border-color", @@ -339,6 +353,7 @@ export const border = [ label: "Style", key: "border-style", control: OptionSelect, + defaultValue: "None", options: [ "none", "hidden", @@ -365,17 +380,34 @@ export const effects = [ }, { label: "Rotate", - key: "transform", - control: Input, - width: "48px", - textAlign: "center", - placeholder: "deg", + key: "transform-rotate", + control: OptionSelect, + defaultValue: "0", + options: [ + "0", + "45deg", + "90deg", + "90deg", + "135deg", + "180deg", + "225deg", + "270deg", + "315dev", + ], }, //needs special control { label: "Shadow", key: "box-shadow", - control: InputGroup, - meta: [{ placeholder: "X" }, { placeholder: "Y" }, { placeholder: "B" }], + control: OptionSelect, + defaultValue: "None", + options: [ + { label: "None", value: "none" }, + { label: "Extra small", value: "0 1px 2px 0 rgba(0, 0, 0, 0.05)" }, + { label: "Small", value: "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)" }, + { label: "Medium", value: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)" }, + { label: "Large", value: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)" }, + { label: "Extra large", value: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)" }, + ], }, ] From 9068bbc89c5236d851ead9a69bee6902b4b656ea Mon Sep 17 00:00:00 2001 From: Joe <49767913+joebudi@users.noreply.github.com> Date: Thu, 11 Jun 2020 13:15:19 +0100 Subject: [PATCH 2/8] formatting and lint update --- .../common/Inputs/InputGroup.svelte | 7 ++-- .../AppPreview/CurrentItemPreview.svelte | 38 ++++++++++--------- .../ComponentPropertiesPanel.svelte | 23 ++++++----- .../userInterface/propertyCategories.js | 24 ++++++++++-- 4 files changed, 59 insertions(+), 33 deletions(-) diff --git a/packages/builder/src/components/common/Inputs/InputGroup.svelte b/packages/builder/src/components/common/Inputs/InputGroup.svelte index e5fed68103..385623ca19 100644 --- a/packages/builder/src/components/common/Inputs/InputGroup.svelte +++ b/packages/builder/src/components/common/Inputs/InputGroup.svelte @@ -19,9 +19,10 @@ onChange(_value) } - $: displayValues = value && suffix - ? value.map(v => v.replace(new RegExp(`${suffix}$`), "")) - : value || [] + $: displayValues = + value && suffix + ? value.map(v => v.replace(new RegExp(`${suffix}$`), "")) + : value || []
diff --git a/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte b/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte index 53450c2200..00d7e6c171 100644 --- a/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte +++ b/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte @@ -21,7 +21,7 @@ return componentName || "element" } - const screenPlaceholder = { + const screenPlaceholder = { name: "Screen Placeholder", route: "*", props: { @@ -60,9 +60,8 @@ }, } - $: hasComponent = !!$store.currentPreviewItem - + $: { styles = "" // Apply the CSS from the currently selected page and its screens @@ -88,9 +87,9 @@ libraries: $store.libraries, page: $store.pages[$store.currentPageName], screens: [ - $store.currentFrontEndType === "page" - ? screenPlaceholder - : $store.currentPreviewItem, + $store.currentFrontEndType === "page" + ? screenPlaceholder + : $store.currentPreviewItem, ], appRootPath: "", } @@ -102,20 +101,25 @@ : "" const refreshContent = () => { - iframe.contentWindow.postMessage(JSON.stringify({ - styles, - stylesheetLinks, - selectedComponentType, - selectedComponentId, - frontendDefinition, - })) + iframe.contentWindow.postMessage( + JSON.stringify({ + styles, + stylesheetLinks, + selectedComponentType, + selectedComponentId, + frontendDefinition, + }) + ) } - $: if(iframe) iframe.contentWindow.addEventListener("bb-ready", refreshContent, { once: true }) + $: if (iframe) + iframe.contentWindow.addEventListener("bb-ready", refreshContent, { + once: true, + }) - $: if(iframe && frontendDefinition) { - refreshContent() - } + $: if (iframe && frontendDefinition) { + refreshContent() + }
diff --git a/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte b/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte index bfe5507256..7d33b9c963 100644 --- a/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte +++ b/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte @@ -37,27 +37,32 @@ //use for getting controls for each component property c => c._component === componentInstance._component ) || {} - + let panelDefinition = {} $: { - if(componentPropDefinition.properties) { - if(selectedCategory.value === "design") { + if (componentPropDefinition.properties) { + if (selectedCategory.value === "design") { panelDefinition = componentPropDefinition.properties["design"] - }else{ + } else { let panelDef = componentPropDefinition.properties["settings"] - if($store.currentFrontEndType === "page" && $store.currentView !== "component") { - panelDefinition = [...page,...panelDef] - }else if($store.currentFrontEndType === "screen" && $store.currentView !== "component") { + if ( + $store.currentFrontEndType === "page" && + $store.currentView !== "component" + ) { + panelDefinition = [...page, ...panelDef] + } else if ( + $store.currentFrontEndType === "screen" && + $store.currentView !== "component" + ) { panelDefinition = [...screen, ...panelDef] - }else { + } else { panelDefinition = panelDef } } } } - const onStyleChanged = store.setComponentStyle const onPropChanged = store.setComponentProp diff --git a/packages/builder/src/components/userInterface/propertyCategories.js b/packages/builder/src/components/userInterface/propertyCategories.js index 8ee38d3c35..c0485304ce 100644 --- a/packages/builder/src/components/userInterface/propertyCategories.js +++ b/packages/builder/src/components/userInterface/propertyCategories.js @@ -403,10 +403,26 @@ export const effects = [ options: [ { label: "None", value: "none" }, { label: "Extra small", value: "0 1px 2px 0 rgba(0, 0, 0, 0.05)" }, - { label: "Small", value: "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)" }, - { label: "Medium", value: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)" }, - { label: "Large", value: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)" }, - { label: "Extra large", value: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)" }, + { + label: "Small", + value: + "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)", + }, + { + label: "Medium", + value: + "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)", + }, + { + label: "Large", + value: + "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)", + }, + { + label: "Extra large", + value: + "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)", + }, ], }, ] From f8cfc8e7d7f347defe38ec3e0b0094e2d6c5d82f Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 11 Jun 2020 14:35:45 +0100 Subject: [PATCH 3/8] adding record models for brevity --- packages/server/package.json | 2 +- packages/server/src/api/controllers/record.js | 11 +++++- packages/server/src/api/index.js | 4 ++ packages/server/src/api/routes/index.js | 2 + packages/server/src/api/routes/model.js | 38 +------------------ packages/server/src/api/routes/record.js | 36 ++++++++++++++++++ .../server/src/api/routes/tests/model.spec.js | 1 - .../src/api/routes/tests/record.spec.js | 24 ++++++++++++ 8 files changed, 78 insertions(+), 40 deletions(-) create mode 100644 packages/server/src/api/routes/record.js diff --git a/packages/server/package.json b/packages/server/package.json index 0888ef2ae4..49a5626f6f 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -25,7 +25,7 @@ "scripts": { "test": "jest routes --runInBand", "test:integration": "jest workflow --runInBand", - "test:watch": "jest -w", + "test:watch": "jest --watch", "initialise": "node ../cli/bin/budi init -b local -q", "budi": "node ../cli/bin/budi", "dev:builder": "nodemon ../cli/bin/budi run", diff --git a/packages/server/src/api/controllers/record.js b/packages/server/src/api/controllers/record.js index 5fab413f04..cf8eb27606 100644 --- a/packages/server/src/api/controllers/record.js +++ b/packages/server/src/api/controllers/record.js @@ -61,7 +61,7 @@ exports.fetchView = async function(ctx) { ctx.body = response.rows.map(row => row.doc) } -exports.fetchModel = async function(ctx) { +exports.fetchModelRecords = async function(ctx) { const db = new CouchDB(ctx.params.instanceId) const response = await db.query(`database/all_${ctx.params.modelId}`, { include_docs: true, @@ -69,6 +69,15 @@ exports.fetchModel = async function(ctx) { ctx.body = response.rows.map(row => row.doc) } +exports.search = async function(ctx) { + const db = new CouchDB(ctx.params.instanceId) + const response = await db.allDocs({ + include_docs: true, + ...ctx.request.body, + }) + ctx.body = response.rows.map(row => row.doc) +} + exports.find = async function(ctx) { const db = new CouchDB(ctx.params.instanceId) const record = await db.get(ctx.params.recordId) diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js index 990714fdc7..e6143d6725 100644 --- a/packages/server/src/api/index.js +++ b/packages/server/src/api/index.js @@ -10,6 +10,7 @@ const { instanceRoutes, clientRoutes, applicationRoutes, + recordRoutes, modelRoutes, viewRoutes, staticRoutes, @@ -69,6 +70,9 @@ router.use(viewRoutes.allowedMethods()) router.use(modelRoutes.routes()) router.use(modelRoutes.allowedMethods()) +router.use(recordRoutes.routes()) +router.use(recordRoutes.allowedMethods()) + router.use(userRoutes.routes()) router.use(userRoutes.allowedMethods()) diff --git a/packages/server/src/api/routes/index.js b/packages/server/src/api/routes/index.js index c515d5f437..b50fee788a 100644 --- a/packages/server/src/api/routes/index.js +++ b/packages/server/src/api/routes/index.js @@ -5,6 +5,7 @@ const instanceRoutes = require("./instance") const clientRoutes = require("./client") const applicationRoutes = require("./application") const modelRoutes = require("./model") +const recordRoutes = require("./record") const viewRoutes = require("./view") const staticRoutes = require("./static") const componentRoutes = require("./component") @@ -18,6 +19,7 @@ module.exports = { instanceRoutes, clientRoutes, applicationRoutes, + recordRoutes, modelRoutes, viewRoutes, staticRoutes, diff --git a/packages/server/src/api/routes/model.js b/packages/server/src/api/routes/model.js index 388f4618bd..f1ec46dbe5 100644 --- a/packages/server/src/api/routes/model.js +++ b/packages/server/src/api/routes/model.js @@ -1,46 +1,10 @@ const Router = require("@koa/router") const modelController = require("../controllers/model") -const recordController = require("../controllers/record") const authorized = require("../../middleware/authorized") -const { - READ_MODEL, - WRITE_MODEL, - BUILDER, -} = require("../../utilities/accessLevels") +const { BUILDER } = require("../../utilities/accessLevels") const router = Router() -// records - -router - .get( - "/api/:instanceId/:modelId/records", - authorized(READ_MODEL, ctx => ctx.params.modelId), - recordController.fetchModel - ) - .get( - "/api/:instanceId/:modelId/records/:recordId", - authorized(READ_MODEL, ctx => ctx.params.modelId), - recordController.find - ) - .post( - "/api/:instanceId/:modelId/records", - authorized(WRITE_MODEL, ctx => ctx.params.modelId), - recordController.save - ) - .post( - "/api/:instanceId/:modelId/records/validate", - authorized(WRITE_MODEL, ctx => ctx.params.modelId), - recordController.validate - ) - .delete( - "/api/:instanceId/:modelId/records/:recordId/:revId", - authorized(WRITE_MODEL, ctx => ctx.params.modelId), - recordController.destroy - ) - -// models - router .get("/api/:instanceId/models", authorized(BUILDER), modelController.fetch) .get("/api/:instanceId/models/:id", authorized(BUILDER), modelController.find) diff --git a/packages/server/src/api/routes/record.js b/packages/server/src/api/routes/record.js new file mode 100644 index 0000000000..d555d3d8c8 --- /dev/null +++ b/packages/server/src/api/routes/record.js @@ -0,0 +1,36 @@ +const Router = require("@koa/router") +const recordController = require("../controllers/record") +const authorized = require("../../middleware/authorized") +const { READ_MODEL, WRITE_MODEL } = require("../../utilities/accessLevels") + +const router = Router() + +router + .get( + "/api/:instanceId/:modelId/records", + authorized(READ_MODEL, ctx => ctx.params.modelId), + recordController.fetchModelRecords + ) + .get( + "/api/:instanceId/:modelId/records/:recordId", + authorized(READ_MODEL, ctx => ctx.params.modelId), + recordController.find + ) + .post("/api/:instanceId/records/search", recordController.search) + .post( + "/api/:instanceId/:modelId/records", + authorized(WRITE_MODEL, ctx => ctx.params.modelId), + recordController.save + ) + .post( + "/api/:instanceId/:modelId/records/validate", + authorized(WRITE_MODEL, ctx => ctx.params.modelId), + recordController.validate + ) + .delete( + "/api/:instanceId/:modelId/records/:recordId/:revId", + authorized(WRITE_MODEL, ctx => ctx.params.modelId), + recordController.destroy + ) + +module.exports = router diff --git a/packages/server/src/api/routes/tests/model.spec.js b/packages/server/src/api/routes/tests/model.spec.js index 65a44b677a..df3b7d8b52 100644 --- a/packages/server/src/api/routes/tests/model.spec.js +++ b/packages/server/src/api/routes/tests/model.spec.js @@ -97,7 +97,6 @@ describe("/models", () => { instanceId: instance._id, }) }) - }); describe("destroy", () => { diff --git a/packages/server/src/api/routes/tests/record.spec.js b/packages/server/src/api/routes/tests/record.spec.js index 2c8c542715..22ac67ecdc 100644 --- a/packages/server/src/api/routes/tests/record.spec.js +++ b/packages/server/src/api/routes/tests/record.spec.js @@ -110,6 +110,30 @@ describe("/records", () => { expect(res.body.find(r => r.name === record.name)).toBeDefined() }) + it("lists records when queried by their ID", async () => { + const newRecord = { + modelId: model._id, + name: "Second Contact", + status: "new" + } + const record = await createRecord() + const secondRecord = await createRecord(newRecord) + + const recordIds = [record.body._id, secondRecord.body._id] + + const res = await request + .post(`/api/${instance._id}/records/search`) + .set(defaultHeaders) + .send({ + keys: recordIds + }) + .expect('Content-Type', /json/) + .expect(200) + + expect(res.body.length).toBe(2) + expect(res.body.map(response => response._id)).toEqual(expect.arrayContaining(recordIds)) + }) + it("load should return 404 when record does not exist", async () => { await createRecord() await request From 3900b216e999cc381e02d5b8941ed496848f0697 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 11 Jun 2020 17:24:09 +0100 Subject: [PATCH 4/8] remove other link fields when you delete a model --- packages/server/src/api/controllers/model.js | 32 ++++++++++++++- .../src/api/routes/tests/couchTestUtils.js | 4 ++ .../server/src/api/routes/tests/model.spec.js | 40 ++++++++++++++++++- 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/controllers/model.js b/packages/server/src/api/controllers/model.js index 9d06c7a413..c35a0ddd49 100644 --- a/packages/server/src/api/controllers/model.js +++ b/packages/server/src/api/controllers/model.js @@ -27,6 +27,23 @@ exports.create = async function(ctx) { const result = await db.post(newModel) newModel._rev = result.rev + const { schema } = ctx.request.body + for (let key in schema) { + // model has a linked record + if (schema[key].type === "link") { + // create the link field in the other model + const linkedModel = await db.get(schema[key].modelId); + linkedModel.schema[newModel.name] = { + type: "link", + modelId: newModel._id, + constraints: { + type: "array" + } + } + await db.put(linkedModel); + } + } + const designDoc = await db.get("_design/database") designDoc.views = { ...designDoc.views, @@ -50,7 +67,9 @@ exports.update = async function() {} exports.destroy = async function(ctx) { const db = new CouchDB(ctx.params.instanceId) - await db.remove(ctx.params.modelId, ctx.params.revId) + const modelToDelete = await db.get(ctx.params.modelId); + + await db.remove(modelToDelete) const modelViewId = `all_${ctx.params.modelId}` // Delete all records for that model @@ -59,6 +78,17 @@ exports.destroy = async function(ctx) { records.rows.map(record => ({ id: record.id, _deleted: true })) ) + // Delete linked record fields in dependent models + for (let key in modelToDelete.schema) { + const { type, modelId } = modelToDelete.schema[key]; + if (type === "link") { + const linkedModel = await db.get(modelId); + delete linkedModel.schema[modelToDelete.name] + await db.put(linkedModel) + } + } + + // delete the "all" view const designDoc = await db.get("_design/database") delete designDoc.views[modelViewId] diff --git a/packages/server/src/api/routes/tests/couchTestUtils.js b/packages/server/src/api/routes/tests/couchTestUtils.js index 6029e080cc..495b841b10 100644 --- a/packages/server/src/api/routes/tests/couchTestUtils.js +++ b/packages/server/src/api/routes/tests/couchTestUtils.js @@ -253,3 +253,7 @@ exports.insertDocument = async (databaseId, document) => { exports.destroyDocument = async (databaseId, documentId) => { return await new CouchDB(databaseId).destroy(documentId) } + +exports.getDocument = async (databaseId, documentId) => { + return await new CouchDB(databaseId).get(documentId) +} diff --git a/packages/server/src/api/routes/tests/model.spec.js b/packages/server/src/api/routes/tests/model.spec.js index df3b7d8b52..1fb16beb8b 100644 --- a/packages/server/src/api/routes/tests/model.spec.js +++ b/packages/server/src/api/routes/tests/model.spec.js @@ -3,9 +3,10 @@ const { createModel, supertest, createClientDatabase, - createApplication , + createApplication, defaultHeaders, - builderEndpointShouldBlockNormalUsers + builderEndpointShouldBlockNormalUsers, + getDocument } = require("./couchTestUtils") describe("/models", () => { @@ -119,6 +120,41 @@ describe("/models", () => { }); }) + it("deletes linked references to the model after deletion", async done => { + const linkedModel = await createModel(request, instance._id, { + name: "LinkedModel", + type: "model", + key: "name", + schema: { + name: { + type: "text", + constraints: { + type: "string", + }, + }, + TestModel: { + type: "link", + modelId: testModel._id, + constraints: { + type: "array" + } + } + }, + }) + + request + .delete(`/api/${instance._id}/models/${testModel._id}/${testModel._rev}`) + .set(defaultHeaders) + .expect('Content-Type', /json/) + .expect(200) + .end(async (_, res) => { + expect(res.res.statusMessage).toEqual(`Model ${testModel._id} deleted.`); + const dependentModel = await getDocument(instance._id, linkedModel._id) + expect(dependentModel.schema.TestModel).not.toBeDefined(); + done(); + }); + }) + it("should apply authorization to endpoint", async () => { await builderEndpointShouldBlockNormalUsers({ request, From 2b312d4c1f8ca1dfb61341c5790c9c85f26a2e5d Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 11 Jun 2020 17:28:19 +0100 Subject: [PATCH 5/8] lint :sparkles: --- packages/server/src/api/controllers/model.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/server/src/api/controllers/model.js b/packages/server/src/api/controllers/model.js index c35a0ddd49..f1e3f51747 100644 --- a/packages/server/src/api/controllers/model.js +++ b/packages/server/src/api/controllers/model.js @@ -32,15 +32,15 @@ exports.create = async function(ctx) { // model has a linked record if (schema[key].type === "link") { // create the link field in the other model - const linkedModel = await db.get(schema[key].modelId); + const linkedModel = await db.get(schema[key].modelId) linkedModel.schema[newModel.name] = { type: "link", modelId: newModel._id, constraints: { - type: "array" - } + type: "array", + }, } - await db.put(linkedModel); + await db.put(linkedModel) } } @@ -67,7 +67,7 @@ exports.update = async function() {} exports.destroy = async function(ctx) { const db = new CouchDB(ctx.params.instanceId) - const modelToDelete = await db.get(ctx.params.modelId); + const modelToDelete = await db.get(ctx.params.modelId) await db.remove(modelToDelete) const modelViewId = `all_${ctx.params.modelId}` @@ -80,15 +80,14 @@ exports.destroy = async function(ctx) { // Delete linked record fields in dependent models for (let key in modelToDelete.schema) { - const { type, modelId } = modelToDelete.schema[key]; + const { type, modelId } = modelToDelete.schema[key] if (type === "link") { - const linkedModel = await db.get(modelId); + const linkedModel = await db.get(modelId) delete linkedModel.schema[modelToDelete.name] await db.put(linkedModel) } } - // delete the "all" view const designDoc = await db.get("_design/database") delete designDoc.views[modelViewId] From 4ed4866bca75c020108dab5cab200de7027d6340 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 11 Jun 2020 18:11:56 +0100 Subject: [PATCH 6/8] update _rev for deleted test model --- packages/server/src/api/controllers/model.js | 1 + packages/server/src/api/routes/tests/model.spec.js | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/model.js b/packages/server/src/api/controllers/model.js index f1e3f51747..650342b33c 100644 --- a/packages/server/src/api/controllers/model.js +++ b/packages/server/src/api/controllers/model.js @@ -70,6 +70,7 @@ exports.destroy = async function(ctx) { const modelToDelete = await db.get(ctx.params.modelId) await db.remove(modelToDelete) + const modelViewId = `all_${ctx.params.modelId}` // Delete all records for that model diff --git a/packages/server/src/api/routes/tests/model.spec.js b/packages/server/src/api/routes/tests/model.spec.js index 1fb16beb8b..7134245fb3 100644 --- a/packages/server/src/api/routes/tests/model.spec.js +++ b/packages/server/src/api/routes/tests/model.spec.js @@ -108,7 +108,11 @@ describe("/models", () => { testModel = await createModel(request, instance._id, testModel) }); - it("returns a success response when a model is deleted.", done => { + afterEach(() => { + delete testModel._rev + }) + + it("returns a success response when a model is deleted.", async done => { request .delete(`/api/${instance._id}/models/${testModel._id}/${testModel._rev}`) .set(defaultHeaders) From 9830725ac1cf325dc112023a6c6f6e08b9ae0b71 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 11 Jun 2020 20:18:59 +0100 Subject: [PATCH 7/8] embed component, rename main and login to public and private --- .../src/components/userInterface/PagesList.svelte | 4 ++-- .../userInterface/temporaryPanelStructure.js | 12 ++++++++++++ packages/standard-components/components.json | 7 +++++++ packages/standard-components/src/Embed.svelte | 5 +++++ packages/standard-components/src/index.js | 1 + 5 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 packages/standard-components/src/Embed.svelte diff --git a/packages/builder/src/components/userInterface/PagesList.svelte b/packages/builder/src/components/userInterface/PagesList.svelte index 4a87c4ac8a..5a78ef7121 100644 --- a/packages/builder/src/components/userInterface/PagesList.svelte +++ b/packages/builder/src/components/userInterface/PagesList.svelte @@ -9,11 +9,11 @@ const pages = [ { - title: "Main", + title: "Private", id: "main", }, { - title: "Login", + title: "Public", id: "unauthenticated", }, ] diff --git a/packages/builder/src/components/userInterface/temporaryPanelStructure.js b/packages/builder/src/components/userInterface/temporaryPanelStructure.js index afd3a06694..7315e09736 100644 --- a/packages/builder/src/components/userInterface/temporaryPanelStructure.js +++ b/packages/builder/src/components/userInterface/temporaryPanelStructure.js @@ -11,6 +11,18 @@ export default { name: "Basic", isCategory: true, children: [ + { + _component: "@budibase/standard-components/embed", + icon: "ri-code-line", + name: "Embed", + description: "Embed content from 3rd party sources", + properties: { + design: { + ...all, + }, + settings: [{ label: "Embed", key: "embed", control: Input }], + }, + }, { _component: "@budibase/standard-components/container", name: "Container", diff --git a/packages/standard-components/components.json b/packages/standard-components/components.json index a562650b85..c4c0246672 100644 --- a/packages/standard-components/components.json +++ b/packages/standard-components/components.json @@ -6,6 +6,13 @@ "component": "button" } }, + "embed": { + "name": "Embed", + "description": "Embed stuff", + "props": { + "embed": "string" + } + }, "Navigation": { "name": "Navigation", "description": "A basic header navigation component", diff --git a/packages/standard-components/src/Embed.svelte b/packages/standard-components/src/Embed.svelte new file mode 100644 index 0000000000..2640864681 --- /dev/null +++ b/packages/standard-components/src/Embed.svelte @@ -0,0 +1,5 @@ + + +{@html embed} diff --git a/packages/standard-components/src/index.js b/packages/standard-components/src/index.js index 2284ab1fcb..24342066e8 100644 --- a/packages/standard-components/src/index.js +++ b/packages/standard-components/src/index.js @@ -21,3 +21,4 @@ export { default as datalist } from "./DataList.svelte" export { default as list } from "./List.svelte" export { default as datasearch } from "./DataSearch.svelte" export { default as datamap } from "./DataMap.svelte" +export { default as embed } from "./Embed.svelte" From 0c35f46b5f147a403f8a38034e9f4be01f62ba46 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Fri, 12 Jun 2020 12:15:17 +0100 Subject: [PATCH 8/8] bugfix - screen/page > settings throwing error --- .../builder/src/builderStore/store/index.js | 56 +++++-------------- .../builder/src/builderStore/storeUtils.js | 13 +++++ .../ComponentPropertiesPanel.svelte | 29 ++-------- .../userInterface/SettingsView.svelte | 40 +++++++++++++ 4 files changed, 72 insertions(+), 66 deletions(-) diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index 9f91550bca..1f3ea9c0ef 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -5,7 +5,6 @@ import { writable, get } from "svelte/store" import api from "../api" import { DEFAULT_PAGES_OBJECT } from "../../constants" import { getExactComponent } from "components/userInterface/pagesParsing/searchComponents" -import { rename } from "components/userInterface/pagesParsing/renameScreen" import { createProps, makePropsSafe, @@ -24,6 +23,7 @@ import { saveCurrentPreviewItem as _saveCurrentPreviewItem, saveScreenApi as _saveScreenApi, regenerateCssForCurrentScreen, + renameCurrentScreen, } from "../storeUtils" export const getStore = () => { @@ -52,7 +52,6 @@ export const getStore = () => { store.createDatabaseForApp = backendStoreActions.createDatabaseForApp(store) store.saveScreen = saveScreen(store) - store.renameScreen = renameScreen(store) store.deleteScreen = deleteScreen(store) store.setCurrentScreen = setCurrentScreen(store) store.setCurrentPage = setCurrentPage(store) @@ -63,6 +62,7 @@ export const getStore = () => { store.addChildComponent = addChildComponent(store) store.selectComponent = selectComponent(store) store.setComponentProp = setComponentProp(store) + store.setPageOrScreenProp = setPageOrScreenProp(store) store.setComponentStyle = setComponentStyle(store) store.setComponentCode = setComponentCode(store) store.setScreenType = setScreenType(store) @@ -207,46 +207,6 @@ const deleteScreen = store => name => { }) } -const renameScreen = store => (oldname, newname) => { - store.update(s => { - const { screens, pages, error, changedScreens } = rename( - s.pages, - s.screens, - oldname, - newname - ) - - if (error) { - // should really do something with this - return s - } - - s.screens = screens - s.pages = pages - if (s.currentPreviewItem.name === oldname) - s.currentPreviewItem.name = newname - - const saveAllChanged = async () => { - for (let screenName of changedScreens) { - const changedScreen = getExactComponent(screens, screenName) - await api.post(`/_builder/api/${s.appId}/screen`, changedScreen) - } - } - - api - .patch(`/_builder/api/${s.appId}/screen`, { - oldname, - newname, - }) - .then(() => saveAllChanged()) - .then(() => { - _savePage(s) - }) - - return s - }) -} - const savePage = store => async page => { store.update(state => { if (state.currentFrontEndType !== "page" || !state.currentPageName) { @@ -400,6 +360,18 @@ const setComponentProp = store => (name, value) => { }) } +const setPageOrScreenProp = store => (name, value) => { + store.update(state => { + if (name === "name" && state.currentFrontEndType === "screen") { + state = renameCurrentScreen(value, state) + } else { + state.currentPreviewItem[name] = value + _saveCurrentPreviewItem(state) + } + return state + }) +} + const setComponentStyle = store => (type, name, value) => { store.update(state => { if (!state.currentComponentInfo._styles) { diff --git a/packages/builder/src/builderStore/storeUtils.js b/packages/builder/src/builderStore/storeUtils.js index d6aa4d0308..ff951e6b6f 100644 --- a/packages/builder/src/builderStore/storeUtils.js +++ b/packages/builder/src/builderStore/storeUtils.js @@ -45,6 +45,19 @@ export const saveScreenApi = (screen, s) => { .then(() => savePage(s)) } +export const renameCurrentScreen = (newname, state) => { + const oldname = state.currentPreviewItem.name + state.currentPreviewItem.name = newname + api.patch( + `/_builder/api/${state.appId}/pages/${state.currentPageName}/screen`, + { + oldname, + newname, + } + ) + return state +} + export const walkProps = (props, action, cancelToken = null) => { cancelToken = cancelToken || { cancelled: false } action(props, () => { diff --git a/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte b/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte index 7d33b9c963..bcebb4d2d4 100644 --- a/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte +++ b/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte @@ -13,7 +13,6 @@ import CodeEditor from "./CodeEditor.svelte" import LayoutEditor from "./LayoutEditor.svelte" import EventsEditor from "./EventsEditor" - import panelStructure from "./temporaryPanelStructure.js" import CategoryTab from "./CategoryTab.svelte" import DesignView from "./DesignView.svelte" @@ -40,28 +39,8 @@ let panelDefinition = {} - $: { - if (componentPropDefinition.properties) { - if (selectedCategory.value === "design") { - panelDefinition = componentPropDefinition.properties["design"] - } else { - let panelDef = componentPropDefinition.properties["settings"] - if ( - $store.currentFrontEndType === "page" && - $store.currentView !== "component" - ) { - panelDefinition = [...page, ...panelDef] - } else if ( - $store.currentFrontEndType === "screen" && - $store.currentView !== "component" - ) { - panelDefinition = [...screen, ...panelDef] - } else { - panelDefinition = panelDef - } - } - } - } + $: panelDefinition = componentPropDefinition.properties && + componentPropDefinition.properties[selectedCategory.value] const onStyleChanged = store.setComponentStyle const onPropChanged = store.setComponentProp @@ -107,7 +86,9 @@ {componentInstance} {componentDefinition} {panelDefinition} - onChange={onPropChanged} /> + onChange={onPropChanged} + onScreenPropChange={store.setPageOrScreenProp} + screenOrPageInstance={$store.currentView !== "component" && $store.currentPreviewItem} /> {:else if selectedCategory.value === 'events'} {/if} diff --git a/packages/builder/src/components/userInterface/SettingsView.svelte b/packages/builder/src/components/userInterface/SettingsView.svelte index 99e704d1d9..17e4fe5e71 100644 --- a/packages/builder/src/components/userInterface/SettingsView.svelte +++ b/packages/builder/src/components/userInterface/SettingsView.svelte @@ -2,20 +2,60 @@ import PropertyControl from "./PropertyControl.svelte" import InputGroup from "../common/Inputs/InputGroup.svelte" import Colorpicker from "../common/Colorpicker.svelte" + import { goto } from "@sveltech/routify" import { excludeProps } from "./propertyCategories.js" + import Input from "../common/Input.svelte" export let panelDefinition = [] export let componentDefinition = {} export let componentInstance = {} export let onChange = () => {} + export let onScreenPropChange = () => {} + export let screenOrPageInstance const propExistsOnComponentDef = prop => prop in componentDefinition.props function handleChange(key, data) { data.target ? onChange(key, data.target.value) : onChange(key, data) } + + function handleScreenPropChange (name, value) { + onScreenPropChange(name,value) + if(!isPage && name === "name") { + // screen name is changed... change URL + $goto(`./:page/${value}`) + } + } + + const screenDefinition = [ + { key: "name", label: "Name", control: Input }, + { key: "description", label: "Description", control: Input }, + { key: "route", label: "Route", control: Input }, + ] + + const pageDefinition = [ + { key: "title", label: "Title", control: Input }, + { key: "favicon", label: "Favicon", control: Input }, + ] + + $: isPage = screenOrPageInstance && screenOrPageInstance.favicon + $: screenOrPageDefinition = isPage ? pageDefinition : screenDefinition + +{#if screenOrPageInstance} + {#each screenOrPageDefinition as def} + + {/each} +
+{/if} + {#if panelDefinition && panelDefinition.length > 0} {#each panelDefinition as definition} {#if propExistsOnComponentDef(definition.key)}