diff --git a/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js b/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js index 94b80c824f..50e90cddcf 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js +++ b/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js @@ -1,3 +1,6 @@ +import sanitizeUrl from "./sanitizeUrl" +import { rowListUrl } from "./rowListScreen" + export default function(tables) { return tables.map(table => { return { @@ -8,6 +11,7 @@ export default function(tables) { }) } +export const newRowUrl = table => sanitizeUrl(`/${table.name}/new`) export const NEW_ROW_TEMPLATE = "NEW_ROW_TEMPLATE" const createScreen = table => ({ @@ -216,7 +220,7 @@ const createScreen = table => ({ }, { parameters: { - url: `/${table.name.toLowerCase()}`, + url: rowListUrl(table), }, "##eventHandlerType": "Navigate To", }, @@ -246,6 +250,6 @@ const createScreen = table => ({ _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 6173559fb9..a4f55f2fd1 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/rowDetailScreen.js +++ b/packages/builder/src/builderStore/store/screenTemplates/rowDetailScreen.js @@ -1,3 +1,6 @@ +import sanitizeUrl from "./sanitizeUrl" +import { rowListUrl } from "./rowListScreen" + export default function(tables) { return tables.map(table => { const heading = table.primaryDisplay @@ -12,6 +15,7 @@ export default function(tables) { } export const ROW_DETAIL_TEMPLATE = "ROW_DETAIL_TEMPLATE" +export const rowDetailUrl = table => sanitizeUrl(`/${table.name}/:id`) const createScreen = (table, heading) => ({ props: { @@ -224,7 +228,7 @@ const createScreen = (table, heading) => ({ }, { parameters: { - url: `/${table.name.toLowerCase()}`, + url: rowListUrl(table), }, "##eventHandlerType": "Navigate To", }, @@ -265,7 +269,7 @@ const createScreen = (table, heading) => ({ }, { parameters: { - url: `/${table.name.toLowerCase()}`, + url: rowListUrl(table), }, "##eventHandlerType": "Navigate To", }, @@ -295,6 +299,6 @@ const createScreen = (table, heading) => ({ _instanceName: `${table.name} - Detail`, _code: "", }, - route: `/${table.name.toLowerCase()}/:id`, + route: rowDetailUrl(table), name: "", }) diff --git a/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js b/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js index 2935d36ce1..5c71a45f1f 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js +++ b/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js @@ -1,3 +1,6 @@ +import sanitizeUrl from "./sanitizeUrl" +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 => sanitizeUrl(`/${table.name}`) const createScreen = table => ({ props: { @@ -120,7 +124,7 @@ const createScreen = table => ({ onClick: [ { parameters: { - url: `/${table.name.toLowerCase()}/new`, + url: newRowUrl(table), }, "##eventHandlerType": "Navigate To", }, @@ -163,6 +167,6 @@ const createScreen = table => ({ className: "", onLoad: [], }, - route: `/${table.name.toLowerCase()}`, + route: rowListUrl(table), name: "", }) diff --git a/packages/builder/src/builderStore/store/screenTemplates/sanitizeUrl.js b/packages/builder/src/builderStore/store/screenTemplates/sanitizeUrl.js new file mode 100644 index 0000000000..eab985c0a5 --- /dev/null +++ b/packages/builder/src/builderStore/store/screenTemplates/sanitizeUrl.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() +} 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} diff --git a/packages/builder/src/components/userInterface/temporaryPanelStructure.js b/packages/builder/src/components/userInterface/temporaryPanelStructure.js index a24d101f5d..db1079b8ee 100644 --- a/packages/builder/src/components/userInterface/temporaryPanelStructure.js +++ b/packages/builder/src/components/userInterface/temporaryPanelStructure.js @@ -133,62 +133,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/client/src/render/screenRouter.js b/packages/client/src/render/screenRouter.js index 164cd840aa..3bfc85caaf 100644 --- a/packages/client/src/render/screenRouter.js +++ b/packages/client/src/render/screenRouter.js @@ -3,6 +3,19 @@ import appStore from "../state/store" import { parseAppIdFromCookie } from "./getAppId" export const screenRouter = ({ screens, onScreenSelected, window }) => { + function sanitize(url) { + if (!url) return url + return url + .split("/") + .map(part => { + // if parameter, then use as is + if (part.startsWith(":")) return part + return encodeURIComponent(part) + }) + .join("/") + .toLowerCase() + } + const isRunningLocally = () => { const hostname = (window.location && window.location.hostname) || "" return ( @@ -16,6 +29,7 @@ export const screenRouter = ({ screens, onScreenSelected, window }) => { if (isRunningLocally()) { const appId = parseAppIdFromCookie(window.document.cookie) if (url) { + url = sanitize(url) if (!url.startsWith("/")) { url = `/${url}` } @@ -26,7 +40,7 @@ export const screenRouter = ({ screens, onScreenSelected, window }) => { } return `/${appId}` } - return url + return sanitize(url) } const routes = screens.map(s => makeRootedPath(s.route)) 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} 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"