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"