From ba82d2d8831dea74e0274251fba581ea1f44e034 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Fri, 16 Oct 2020 15:43:55 +0100 Subject: [PATCH 1/5] screen templates - convert spaces to "-" in urls --- .../store/screenTemplates/newRowScreen.js | 14 ++++++++++++-- .../store/screenTemplates/rowDetailScreen.js | 8 ++++++-- .../store/screenTemplates/rowListScreen.js | 10 +++++++--- .../store/screenTemplates/urlSanitize.js | 11 +++++++++++ 4 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 packages/builder/src/builderStore/store/screenTemplates/urlSanitize.js diff --git a/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js b/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js index 571007c092..b28630346c 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js +++ b/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js @@ -1,3 +1,6 @@ +import urlSanitize from "./urlSanitize" +import { rowListUrl } from "./rowListScreen" + export default function(tables) { return tables.map(table => { const fields = Object.keys(table.schema) @@ -11,6 +14,7 @@ export default function(tables) { } export const NEW_ROW_TEMPLATE = "NEW_ROW_TEMPLATE" +export const newRowUrl = table => urlSanitize(`/${table.name}/new`) const createScreen = (table, heading) => ({ props: { @@ -91,7 +95,7 @@ const createScreen = (table, heading) => ({ onClick: [ { parameters: { - url: `/${table.name.toLowerCase()}`, + url: rowListUrl(table), }, "##eventHandlerType": "Navigate To", }, @@ -120,6 +124,12 @@ const createScreen = (table, heading) => ({ }, "##eventHandlerType": "Save Row", }, + { + parameters: { + url: rowListUrl(table), + }, + "##eventHandlerType": "Navigate To", + }, ], _instanceName: "Save Button", _children: [], @@ -130,6 +140,6 @@ const createScreen = (table, heading) => ({ _instanceName: `${table.name} - New`, _code: "", }, - route: `/${table.name.toLowerCase()}/new`, + route: newRowUrl(table), name: "", }) diff --git a/packages/builder/src/builderStore/store/screenTemplates/rowDetailScreen.js b/packages/builder/src/builderStore/store/screenTemplates/rowDetailScreen.js index 58ca2f6d05..d901efa359 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/rowDetailScreen.js +++ b/packages/builder/src/builderStore/store/screenTemplates/rowDetailScreen.js @@ -1,3 +1,6 @@ +import urlSanitize from "./urlSanitize" +import { rowListUrl } from "./rowListScreen" + export default function(tables) { return tables.map(table => { const fields = Object.keys(table.schema) @@ -11,6 +14,7 @@ export default function(tables) { } export const ROW_DETAIL_TEMPLATE = "ROW_DETAIL_TEMPLATE" +export const editRowUrl = table => urlSanitize(`/${table.name}/:id`) const createScreen = (table, heading) => ({ props: { @@ -91,7 +95,7 @@ const createScreen = (table, heading) => ({ onClick: [ { parameters: { - url: `/${table.name.toLowerCase()}`, + url: rowListUrl(table), }, "##eventHandlerType": "Navigate To", }, @@ -130,6 +134,6 @@ const createScreen = (table, heading) => ({ _instanceName: `${table.name} - Detail`, _code: "", }, - route: `/${table.name.toLowerCase()}/:id`, + route: editRowUrl(table), name: "", }) diff --git a/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js b/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js index c01fc9e3ae..0ff84d9cc3 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js +++ b/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js @@ -1,3 +1,6 @@ +import urlSanitize from "./urlSanitize" +import { newRowUrl } from "./newRowScreen" + export default function(tables) { return tables.map(table => { return { @@ -9,6 +12,7 @@ export default function(tables) { } export const ROW_LIST_TEMPLATE = "ROW_LIST_TEMPLATE" +export const rowListUrl = table => urlSanitize(`/${table.name}`) const createScreen = table => ({ props: { @@ -74,7 +78,7 @@ const createScreen = table => ({ onClick: [ { parameters: { - url: `/${table.name}/new`, + url: newRowUrl(table), }, "##eventHandlerType": "Navigate To", }, @@ -95,7 +99,7 @@ const createScreen = table => ({ }, _code: "", datasource: { - label: "Deals", + label: table.name, name: `all_${table._id}`, tableId: table._id, type: "table", @@ -109,6 +113,6 @@ const createScreen = table => ({ className: "", onLoad: [], }, - route: `/${table.name.toLowerCase()}`, + route: rowListUrl(table), name: "", }) diff --git a/packages/builder/src/builderStore/store/screenTemplates/urlSanitize.js b/packages/builder/src/builderStore/store/screenTemplates/urlSanitize.js new file mode 100644 index 0000000000..eab985c0a5 --- /dev/null +++ b/packages/builder/src/builderStore/store/screenTemplates/urlSanitize.js @@ -0,0 +1,11 @@ +export default function(url) { + return url + .split("/") + .map(part => { + // if parameter, then use as is + if (part.startsWith(":")) return part + return encodeURIComponent(part.replace(" ", "-")) + }) + .join("/") + .toLowerCase() +} From acd17a6668bf86ecbbf6fc4386154a7396610bac Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Fri, 16 Oct 2020 15:44:39 +0100 Subject: [PATCH 2/5] client - sanitize urls, so we can match routes with nasty chars --- packages/client/src/render/screenRouter.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/client/src/render/screenRouter.js b/packages/client/src/render/screenRouter.js index 6af4f5491a..a925fab198 100644 --- a/packages/client/src/render/screenRouter.js +++ b/packages/client/src/render/screenRouter.js @@ -3,6 +3,18 @@ import appStore from "../state/store" import { parseAppIdFromCookie } from "./getAppId" export const screenRouter = ({ screens, onScreenSelected, window }) => { + function sanitize(url) { + return url + .split("/") + .map(part => { + // if parameter, then use as is + if (part.startsWith(":")) return part + return encodeURIComponent(part) + }) + .join("/") + .toLowerCase() + } + const makeRootedPath = url => { const hostname = window.location && window.location.hostname if (hostname) { @@ -13,13 +25,16 @@ export const screenRouter = ({ screens, onScreenSelected, window }) => { ) { const appId = parseAppIdFromCookie(window.document.cookie) if (url) { - if (url.startsWith(appId)) return url - return `/${appId}${url.startsWith("/") ? "" : "/"}${url}` + const sanitizedUrl = sanitize(url) + if (sanitizedUrl.startsWith(appId)) return sanitizedUrl + return `/${appId}${ + sanitizedUrl.startsWith("/") ? "" : "/" + }${sanitizedUrl}` } return appId } } - return url + return sanitize(url) } const routes = screens.map(s => makeRootedPath(s.route)) From 5027a6e49af9f14f8b5cef7f7c5765a6a7ca1efa Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Fri, 16 Oct 2020 16:04:49 +0100 Subject: [PATCH 3/5] removes unused components --- .../userInterface/temporaryPanelStructure.js | 111 +++--------------- packages/standard-components/src/index.js | 6 +- 2 files changed, 16 insertions(+), 101 deletions(-) diff --git a/packages/builder/src/components/userInterface/temporaryPanelStructure.js b/packages/builder/src/components/userInterface/temporaryPanelStructure.js index cb35d140c4..8d9e27357b 100644 --- a/packages/builder/src/components/userInterface/temporaryPanelStructure.js +++ b/packages/builder/src/components/userInterface/temporaryPanelStructure.js @@ -132,62 +132,23 @@ export default { ], }, { - name: "Input", - description: "These components handle user input.", + _component: "@budibase/standard-components/input", + name: "Textfield", + description: + "A textfield component that allows the user to input text.", icon: "ri-edit-box-line", - commonProps: {}, - children: [ - { - _component: "@budibase/standard-components/input", - name: "Textfield", - description: - "A textfield component that allows the user to input text.", - icon: "ri-edit-box-line", - properties: { - design: { ...all }, - settings: [ - { label: "Label", key: "label", control: Input }, - { - label: "Type", - key: "type", - control: OptionSelect, - options: ["text", "password"], - }, - ], + properties: { + design: { ...all }, + settings: [ + { label: "Label", key: "label", control: Input }, + { + label: "Type", + key: "type", + control: OptionSelect, + options: ["text", "password"], }, - }, - { - _component: "@budibase/standard-components/checkbox", - name: "Checkbox", - description: "A selectable checkbox component", - icon: "ri-checkbox-line", - properties: { - design: { ...all }, - settings: [{ label: "Label", key: "label", control: Input }], - }, - }, - { - _component: "@budibase/standard-components/radiobutton", - name: "Radiobutton", - description: "A selectable radiobutton component", - icon: "ri-radio-button-line", - properties: { - design: { ...all }, - settings: [{ label: "Label", key: "label", control: Input }], - }, - }, - { - _component: "@budibase/standard-components/select", - name: "Select", - description: - "A select component for choosing from different options", - icon: "ri-file-list-line", - properties: { - design: { ...all }, - settings: [], - }, - }, - ], + ], + }, }, { _component: "@budibase/standard-components/button", @@ -584,48 +545,6 @@ export default { }, ], }, - { - name: "Table", - _component: "@budibase/standard-components/datatable", - description: "A component that generates a table from your data.", - icon: "ri-archive-drawer-line", - properties: { - design: { ...all }, - settings: [ - { - label: "Data", - key: "datasource", - control: TableViewSelect, - }, - { - label: "Stripe Color", - key: "stripeColor", - control: Colorpicker, - defaultValue: "#FFFFFF", - }, - { - label: "Border Color", - key: "borderColor", - control: Colorpicker, - defaultValue: "#FFFFFF", - }, - { - label: "TH Color", - key: "backgroundColor", - control: Colorpicker, - defaultValue: "#FFFFFF", - }, - { - label: "TH Font Color", - key: "color", - control: Colorpicker, - defaultValue: "#FFFFFF", - }, - { label: "Table", key: "table", control: TableSelect }, - ], - }, - children: [], - }, { name: "Form", description: "A component that generates a form from your data.", diff --git a/packages/standard-components/src/index.js b/packages/standard-components/src/index.js index b4e87aced9..c99c2cbe56 100644 --- a/packages/standard-components/src/index.js +++ b/packages/standard-components/src/index.js @@ -4,11 +4,8 @@ export { default as container } from "./Container.svelte" export { default as text } from "./Text.svelte" export { default as heading } from "./Heading.svelte" export { default as input } from "./Input.svelte" -export { default as select } from "./Select.svelte" export { default as textfield } from "./Textfield.svelte" -export { default as checkbox } from "./Checkbox.svelte" -export { default as radiobutton } from "./Radiobutton.svelte" -export { default as option } from "./Option.svelte" + export { default as button } from "./Button.svelte" export { default as login } from "./Login.svelte" export { default as saveRowButton } from "./Templates/saveRowButton" @@ -16,7 +13,6 @@ export { default as link } from "./Link.svelte" export { default as image } from "./Image.svelte" export { default as Navigation } from "./Navigation.svelte" export { default as datagrid } from "./DataGrid/Component.svelte" -export { default as datatable } from "./DataTable.svelte" export { default as dataform } from "./DataForm.svelte" export { default as dataformwide } from "./DataFormWide.svelte" export { default as datachart } from "./DataChart.svelte" From 143177a0d5bb51bcc683df2617a343bafa74d6c9 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Fri, 16 Oct 2020 21:50:58 +0100 Subject: [PATCH 4/5] Primary display column is always required --- .../popovers/CreateEditColumnPopover.svelte | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/components/backend/DataTable/popovers/CreateEditColumnPopover.svelte b/packages/builder/src/components/backend/DataTable/popovers/CreateEditColumnPopover.svelte index e803ca21cf..9549041a18 100644 --- a/packages/builder/src/components/backend/DataTable/popovers/CreateEditColumnPopover.svelte +++ b/packages/builder/src/components/backend/DataTable/popovers/CreateEditColumnPopover.svelte @@ -40,7 +40,7 @@ $: tableOptions = $backendUiStore.tables.filter( table => table._id !== $backendUiStore.draftTable._id ) - $: required = !!field?.constraints?.presence + $: required = !!field?.constraints?.presence || primaryDisplay async function saveColumn() { backendUiStore.update(state => { @@ -67,6 +67,14 @@ field.constraints.presence = req ? { allowEmpty: false } : false required = req } + + function onChangePrimaryDisplay(e) { + const isPrimary = e.target.checked + // primary display is always required + if (isPrimary) { + field.constraints.presence = { allowEmpty: false } + } + }
@@ -88,6 +96,7 @@ {/if} @@ -95,6 +104,7 @@ {#if field.type !== 'link'} {/if} From 5578e48f34d535e53d9db2684d00ef26e71964d7 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Fri, 16 Oct 2020 22:46:15 +0100 Subject: [PATCH 5/5] stop multiple creates on save record --- packages/standard-components/src/Button.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/standard-components/src/Button.svelte b/packages/standard-components/src/Button.svelte index cde82ce37e..54f7812dc2 100644 --- a/packages/standard-components/src/Button.svelte +++ b/packages/standard-components/src/Button.svelte @@ -18,7 +18,7 @@ bind:this={theButton} class="default" disabled={disabled || false} - on:click={clickHandler}> + on:click|once={clickHandler}> {#if !_bb.props._children || _bb.props._children.length === 0}{text}{/if}