Merge branch 'master' of github.com:Budibase/budibase into fix-issues

This commit is contained in:
Martin McKeaveney 2020-10-16 21:41:58 +01:00
commit d44ff8ceeb
24 changed files with 791 additions and 266 deletions

View File

@ -63,7 +63,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "^1.41.0", "@budibase/bbui": "^1.44.0",
"@budibase/client": "^0.2.2", "@budibase/client": "^0.2.2",
"@budibase/colorpicker": "^1.0.1", "@budibase/colorpicker": "^1.0.1",
"@fortawesome/fontawesome-free": "^5.14.0", "@fortawesome/fontawesome-free": "^5.14.0",

View File

@ -1,10 +1,8 @@
export default function(tables) { export default function(tables) {
return tables.map(table => { return tables.map(table => {
const fields = Object.keys(table.schema)
const heading = fields.length > 0 ? `{{ data.${fields[0]} }}` : "Add Row"
return { return {
name: `${table.name} - New`, name: `${table.name} - New`,
create: () => createScreen(table, heading), create: () => createScreen(table),
id: NEW_ROW_TEMPLATE, id: NEW_ROW_TEMPLATE,
} }
}) })
@ -12,9 +10,9 @@ export default function(tables) {
export const NEW_ROW_TEMPLATE = "NEW_ROW_TEMPLATE" export const NEW_ROW_TEMPLATE = "NEW_ROW_TEMPLATE"
const createScreen = (table, heading) => ({ const createScreen = table => ({
props: { props: {
_id: "", _id: "c683c4ca8ffc849c6bdd3b7d637fbbf3c",
_component: "@budibase/standard-components/newrow", _component: "@budibase/standard-components/newrow",
_styles: { _styles: {
normal: {}, normal: {},
@ -25,43 +23,22 @@ const createScreen = (table, heading) => ({
table: table._id, table: table._id,
_children: [ _children: [
{ {
_id: "", _id: "ccad6cc135c7947a7ba9c631f655d6e0f",
_component: "@budibase/standard-components/heading",
_styles: {
normal: {},
hover: {},
active: {},
selected: {},
},
_code: "",
className: "",
text: heading,
type: "h1",
_instanceName: "Heading 1",
_children: [],
},
{
_id: "",
_component: "@budibase/standard-components/dataform",
_styles: {
normal: {},
hover: {},
active: {},
selected: {},
},
_code: "",
_instanceName: `${table.name} Form`,
_children: [],
},
{
_id: "",
_component: "@budibase/standard-components/container", _component: "@budibase/standard-components/container",
_styles: { _styles: {
normal: { normal: {
display: "flex", width: "700px",
"flex-direction": "row", padding: "0px",
"align-items": "center", background: "white",
"justify-content": "flex-end", "border-radius": "0.5rem",
"box-shadow": "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
margin: "auto",
"margin-top": "20px",
"padding-top": "48px",
"padding-bottom": "48px",
"padding-right": "48px",
"padding-left": "48px",
"margin-bottom": "20px",
}, },
hover: {}, hover: {},
active: {}, active: {},
@ -71,37 +48,187 @@ const createScreen = (table, heading) => ({
className: "", className: "",
onLoad: [], onLoad: [],
type: "div", type: "div",
_instanceName: "Buttons Container", _instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Container",
_children: [ _children: [
{ {
_id: "", _id: "c6e91622ba7984f468f70bf4bf5120246",
_component: "@budibase/standard-components/button", _component: "@budibase/standard-components/container",
_styles: { _styles: {
normal: { normal: {
"margin-right": "20px", "font-size": "14px",
color: "#757575",
}, },
hover: {}, hover: {},
active: {}, active: {},
selected: {}, selected: {},
}, },
_code: "", _code: "",
text: "Back",
className: "", className: "",
disabled: false, onLoad: [],
onClick: [ type: "div",
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Breadcrumbs",
_children: [
{ {
parameters: { _id: "caa33353c252c4931b2a51b48a559a7fc",
url: `/${table.name.toLowerCase()}`, _component: "@budibase/standard-components/link",
_styles: {
normal: {
color: "#757575",
"text-transform": "capitalize",
},
hover: {
color: "#4285f4",
},
active: {},
selected: {},
}, },
"##eventHandlerType": "Navigate To", _code: "",
url: `/${table.name.toLowerCase()}`,
openInNewTab: false,
text: table.name,
color: "",
hoverColor: "",
underline: false,
fontSize: "",
fontFamily: "initial",
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Back Link",
_children: [],
},
{
_id: "c6e218170201040e7a74e2c8304fe1860",
_component: "@budibase/standard-components/text",
_styles: {
normal: {
"margin-right": "4px",
"margin-left": "4px",
},
hover: {},
active: {},
selected: {},
},
_code: "",
text: ">",
type: "none",
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Arrow",
_children: [],
},
{
_id: "c799da1fa3a84442e947cc9199518f64c",
_component: "@budibase/standard-components/text",
_styles: {
normal: {
color: "#000000",
},
hover: {},
active: {},
selected: {},
},
_code: "",
text: "New",
type: "none",
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Identifier",
_children: [],
}, },
], ],
_instanceName: "Back Button",
_children: [],
}, },
{ {
_id: "", _id: "cbd1637cd1e274287a3c28ef0bf235d08",
_component: "@budibase/standard-components/button", _component: "@budibase/standard-components/container",
_styles: {
normal: {
display: "flex",
"flex-direction": "row",
"justify-content": "space-between",
"align-items": "center",
"margin-top": "32px",
"margin-bottom": "32px",
},
hover: {},
active: {},
selected: {},
},
_code: "",
className: "",
onLoad: [],
type: "div",
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Title Container",
_children: [
{
_id: "c98d3675d04114558bbf28661c5ccfb8e",
_component: "@budibase/standard-components/heading",
_styles: {
normal: {
margin: "0px",
"margin-bottom": "0px",
"margin-right": "0px",
"margin-top": "0px",
"margin-left": "0px",
flex: "1 1 auto",
},
hover: {},
active: {},
selected: {},
},
_code: "",
className: "",
text: "New Row",
type: "h3",
_instanceName: "Title",
_children: [],
},
{
_id: "cae402bd3c6a44618a8341bf7ab9ab086",
_component: "@budibase/standard-components/button",
_styles: {
normal: {
background: "#000000",
"border-width": "0",
"border-style": "None",
color: "#fff",
"font-family": "Inter",
"font-weight": "500",
"font-size": "14px",
"margin-left": "16px",
},
hover: {
background: "#4285f4",
},
active: {},
selected: {},
},
_code: "",
text: "Save",
className: "",
disabled: false,
onClick: [
{
parameters: {
contextPath: "data",
tableId: table._id,
},
"##eventHandlerType": "Save Row",
},
{
parameters: {
url: `/${table.name.toLowerCase()}`,
},
"##eventHandlerType": "Navigate To",
},
],
_instanceName: "Save Button",
_children: [],
},
],
},
{
_id: "c5e6c98d7363640f9ad3a7d19c8c10f67",
_component: "@budibase/standard-components/dataformwide",
_styles: { _styles: {
normal: {}, normal: {},
hover: {}, hover: {},
@ -109,19 +236,8 @@ const createScreen = (table, heading) => ({
selected: {}, selected: {},
}, },
_code: "", _code: "",
text: "Save", _instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
className: "", _instanceName: "Form",
disabled: false,
onClick: [
{
parameters: {
contextPath: "data",
tableId: table._id,
},
"##eventHandlerType": "Save Row",
},
],
_instanceName: "Save Button",
_children: [], _children: [],
}, },
], ],

View File

@ -1,7 +1,8 @@
export default function(tables) { export default function(tables) {
return tables.map(table => { return tables.map(table => {
const fields = Object.keys(table.schema) const heading = table.primaryDisplay
const heading = fields.length > 0 ? `{{ data.${fields[0]} }}` : "Detail" ? `{{ data.${table.primaryDisplay} }}`
: null
return { return {
name: `${table.name} - Detail`, name: `${table.name} - Detail`,
create: () => createScreen(table, heading), create: () => createScreen(table, heading),
@ -14,7 +15,7 @@ export const ROW_DETAIL_TEMPLATE = "ROW_DETAIL_TEMPLATE"
const createScreen = (table, heading) => ({ const createScreen = (table, heading) => ({
props: { props: {
_id: "", _id: "c683c4ca8ffc849c6bdd3b7d637fbbf3c",
_component: "@budibase/standard-components/rowdetail", _component: "@budibase/standard-components/rowdetail",
_styles: { _styles: {
normal: {}, normal: {},
@ -25,43 +26,22 @@ const createScreen = (table, heading) => ({
table: table._id, table: table._id,
_children: [ _children: [
{ {
_id: "", _id: "ccad6cc135c7947a7ba9c631f655d6e0f",
_component: "@budibase/standard-components/heading",
_styles: {
normal: {},
hover: {},
active: {},
selected: {},
},
_code: "",
className: "",
text: heading,
type: "h1",
_instanceName: "Heading 1",
_children: [],
},
{
_id: "",
_component: "@budibase/standard-components/dataform",
_styles: {
normal: {},
hover: {},
active: {},
selected: {},
},
_code: "",
_instanceName: `${table.name} Form`,
_children: [],
},
{
_id: "",
_component: "@budibase/standard-components/container", _component: "@budibase/standard-components/container",
_styles: { _styles: {
normal: { normal: {
display: "flex", width: "700px",
"flex-direction": "row", padding: "0px",
"align-items": "center", background: "white",
"justify-content": "flex-end", "border-radius": "0.5rem",
"box-shadow": "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
margin: "auto",
"margin-top": "20px",
"padding-top": "48px",
"padding-bottom": "48px",
"padding-right": "48px",
"padding-left": "48px",
"margin-bottom": "20px",
}, },
hover: {}, hover: {},
active: {}, active: {},
@ -71,37 +51,233 @@ const createScreen = (table, heading) => ({
className: "", className: "",
onLoad: [], onLoad: [],
type: "div", type: "div",
_instanceName: "Buttons Container", _instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Container",
_children: [ _children: [
{ {
_id: "", _id: "c6e91622ba7984f468f70bf4bf5120246",
_component: "@budibase/standard-components/button", _component: "@budibase/standard-components/container",
_styles: { _styles: {
normal: { normal: {
"margin-right": "20px", "font-size": "14px",
color: "#757575",
}, },
hover: {}, hover: {},
active: {}, active: {},
selected: {}, selected: {},
}, },
_code: "", _code: "",
text: "Back",
className: "", className: "",
disabled: false, onLoad: [],
onClick: [ type: "div",
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Breadcrumbs",
_children: [
{ {
parameters: { _id: "caa33353c252c4931b2a51b48a559a7fc",
url: `/${table.name.toLowerCase()}`, _component: "@budibase/standard-components/link",
_styles: {
normal: {
color: "#757575",
"text-transform": "capitalize",
},
hover: {
color: "#4285f4",
},
active: {},
selected: {},
}, },
"##eventHandlerType": "Navigate To", _code: "",
url: `/${table.name.toLowerCase()}`,
openInNewTab: false,
text: table.name,
color: "",
hoverColor: "",
underline: false,
fontSize: "",
fontFamily: "initial",
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Back Link",
_children: [],
},
{
_id: "c6e218170201040e7a74e2c8304fe1860",
_component: "@budibase/standard-components/text",
_styles: {
normal: {
"margin-right": "4px",
"margin-left": "4px",
},
hover: {},
active: {},
selected: {},
},
_code: "",
text: ">",
type: "none",
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Arrow",
_children: [],
},
{
_id: "c799da1fa3a84442e947cc9199518f64c",
_component: "@budibase/standard-components/text",
_styles: {
normal: {
color: "#000000",
"text-transform": "capitalize",
},
hover: {},
active: {},
selected: {},
},
_code: "",
text: heading || "Edit",
type: "none",
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Identifier",
_children: [],
}, },
], ],
_instanceName: "Back Button",
_children: [],
}, },
{ {
_id: "", _id: "cbd1637cd1e274287a3c28ef0bf235d08",
_component: "@budibase/standard-components/button", _component: "@budibase/standard-components/container",
_styles: {
normal: {
display: "flex",
"flex-direction": "row",
"justify-content": "space-between",
"align-items": "center",
"margin-top": "32px",
"margin-bottom": "32px",
},
hover: {},
active: {},
selected: {},
},
_code: "",
className: "",
onLoad: [],
type: "div",
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Title Container",
_children: [
{
_id: "c98d3675d04114558bbf28661c5ccfb8e",
_component: "@budibase/standard-components/heading",
_styles: {
normal: {
margin: "0px",
"margin-bottom": "0px",
"margin-right": "0px",
"margin-top": "0px",
"margin-left": "0px",
flex: "1 1 auto",
"text-transform": "capitalize",
},
hover: {},
active: {},
selected: {},
},
_code: "",
className: "",
text: heading || "Edit Row",
type: "h3",
_instanceName: "Title",
_children: [],
},
{
_id: "c0a162cfb7d1c4bcfa8d24c290ccd1fd6",
_component: "@budibase/standard-components/button",
_styles: {
normal: {
background: "transparent",
"border-width": "0",
"border-style": "None",
color: "#9e9e9e",
"font-family": "Inter",
"font-weight": "500",
"font-size": "14px",
"margin-right": "8px",
"margin-left": "16px",
},
hover: {
background: "transparent",
color: "#4285f4",
},
active: {},
selected: {},
},
_code: "",
text: "Delete",
className: "",
disabled: false,
onClick: [
{
parameters: {
rowId: "{{ data._id }}",
revId: "{{ data._rev }}",
tableId: table._id,
},
"##eventHandlerType": "Delete Row",
},
{
parameters: {
url: `/${table.name.toLowerCase()}`,
},
"##eventHandlerType": "Navigate To",
},
],
_instanceName: "Delete Button",
_children: [],
},
{
_id: "cae402bd3c6a44618a8341bf7ab9ab086",
_component: "@budibase/standard-components/button",
_styles: {
normal: {
background: "#000000",
"border-width": "0",
"border-style": "None",
color: "#fff",
"font-family": "Inter",
"font-weight": "500",
"font-size": "14px",
},
hover: {
background: "#4285f4",
},
active: {},
selected: {},
},
_code: "",
text: "Save",
className: "",
disabled: false,
onClick: [
{
parameters: {
contextPath: "data",
tableId: table._id,
},
"##eventHandlerType": "Save Row",
},
{
parameters: {
url: `/${table.name.toLowerCase()}`,
},
"##eventHandlerType": "Navigate To",
},
],
_instanceName: "Save Button",
_children: [],
},
],
},
{
_id: "c5e6c98d7363640f9ad3a7d19c8c10f67",
_component: "@budibase/standard-components/dataformwide",
_styles: { _styles: {
normal: {}, normal: {},
hover: {}, hover: {},
@ -109,19 +285,8 @@ const createScreen = (table, heading) => ({
selected: {}, selected: {},
}, },
_code: "", _code: "",
text: "Save", _instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
className: "", _instanceName: "Form",
disabled: false,
onClick: [
{
parameters: {
contextPath: "data",
tableId: table._id,
},
"##eventHandlerType": "Save Row",
},
],
_instanceName: "Save Button",
_children: [], _children: [],
}, },
], ],

View File

@ -12,7 +12,7 @@ export const ROW_LIST_TEMPLATE = "ROW_LIST_TEMPLATE"
const createScreen = table => ({ const createScreen = table => ({
props: { props: {
_id: "", _id: "c7365379815e4457dbe703a886c2da43b",
_component: "@budibase/standard-components/container", _component: "@budibase/standard-components/container",
_styles: { _styles: {
normal: {}, normal: {},
@ -23,14 +23,23 @@ const createScreen = table => ({
type: "div", type: "div",
_children: [ _children: [
{ {
_id: "", _id: "cf51241fc063d4d87be032dd509fe0244",
_component: "@budibase/standard-components/container", _component: "@budibase/standard-components/container",
_styles: { _styles: {
normal: { normal: {
display: "flex", background: "white",
"flex-direction": "row", "border-radius": "0.5rem",
"justify-content": "space-between", "box-shadow": "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
"align-items": "center", margin: "auto",
"margin-top": "20px",
"border-width": "2px",
"border-color": "rgba(0, 0, 0, 0.1)",
"border-style": "None",
"padding-top": "48px",
"padding-bottom": "48px",
"padding-right": "48px",
"padding-left": "48px",
"margin-bottom": "20px",
}, },
hover: {}, hover: {},
active: {}, active: {},
@ -40,69 +49,114 @@ const createScreen = table => ({
className: "", className: "",
onLoad: [], onLoad: [],
type: "div", type: "div",
_instanceName: "Header", _instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Container",
_children: [ _children: [
{ {
_id: "", _id: "c73294c301fd145aabe9bbbbd96a150ac",
_component: "@budibase/standard-components/heading", _component: "@budibase/standard-components/container",
_styles: { _styles: {
normal: {}, normal: {
display: "flex",
"flex-direction": "row",
"justify-content": "space-between",
"align-items": "center",
"margin-bottom": "32px",
},
hover: {}, hover: {},
active: {}, active: {},
selected: {}, selected: {},
}, },
_code: "", _code: "",
className: "", className: "",
text: `${table.name} List`, onLoad: [],
type: "h1", type: "div",
_instanceName: "Heading 1", _instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_children: [], _instanceName: "Title Container",
}, _children: [
{
_id: "",
_component: "@budibase/standard-components/button",
_styles: {
normal: {},
hover: {},
active: {},
selected: {},
},
_code: "",
text: "Create New",
className: "",
disabled: false,
onClick: [
{ {
parameters: { _id: "c2b77901df95a4d1ca7204c58300bc94b",
url: `/${table.name}/new`, _component: "@budibase/standard-components/heading",
_styles: {
normal: {
margin: "0px",
flex: "1 1 auto",
"text-transform": "capitalize",
},
hover: {},
active: {},
selected: {},
}, },
"##eventHandlerType": "Navigate To", _code: "",
className: "",
text: table.name,
type: "h3",
_instanceName: "Title",
_children: [],
},
{
_id: "c12a82d77baf24ca9922ea0af7cd4f723",
_component: "@budibase/standard-components/button",
_styles: {
normal: {
background: "#000000",
"border-width": "0",
"border-style": "None",
color: "#fff",
"font-family": "Inter",
"font-weight": "500",
"font-size": "14px",
},
hover: {
background: "#4285f4",
},
active: {},
selected: {},
},
_code: "",
text: "Create New",
className: "",
disabled: false,
onClick: [
{
parameters: {
url: `/${table.name.toLowerCase()}/new`,
},
"##eventHandlerType": "Navigate To",
},
],
_instanceName: "New Button",
_children: [],
}, },
], ],
_instanceName: "Create New Button", },
{
_id: "ca686a2ed89c943e6bafb63fa66a3ead3",
_component: "@budibase/standard-components/datagrid",
_styles: {
normal: {},
hover: {},
active: {},
selected: {},
},
_code: "",
datasource: {
label: table.name,
name: `all_${table._id}`,
tableId: table._id,
type: "table",
},
editable: false,
theme: "alpine",
height: "540",
pagination: true,
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
_instanceName: "Grid",
_children: [], _children: [],
detailUrl: `${table.name.toLowerCase()}/:id`,
}, },
], ],
}, },
{
_id: "",
_component: "@budibase/standard-components/datagrid",
_styles: {
normal: {},
hover: {},
active: {},
selected: {},
},
_code: "",
datasource: {
label: "Deals",
name: `all_${table._id}`,
tableId: table._id,
type: "table",
},
_instanceName: `${table.name} Table`,
_children: [],
},
], ],
_instanceName: `${table.name} - List`, _instanceName: `${table.name} - List`,
_code: "", _code: "",

View File

@ -0,0 +1,49 @@
<script>
import { DataList } from "@budibase/bbui"
import { createEventDispatcher } from "svelte"
import { store } from "builderStore"
const dispatch = createEventDispatcher()
export let value = ""
$: urls = getUrls()
const handleBlur = () => dispatch("change", value)
const getUrls = () => {
return [
...$store.screens
.filter(
screen =>
screen.props._component.endsWith("/rowdetail") ||
screen.route.endsWith(":id")
)
.map(screen => ({
name: screen.props._instanceName,
url: screen.route,
sort: screen.props._component,
})),
]
}
</script>
<div>
<DataList editable secondary thin on:blur={handleBlur} on:change bind:value>
<option value="" />
{#each urls as url}
<option value={url.url}>{url.name}</option>
{/each}
</DataList>
</div>
<style>
div {
flex: 1 1 auto;
display: flex;
flex-direction: row;
}
div :global(> div) {
flex: 1 1 auto;
}
</style>

View File

@ -0,0 +1,91 @@
<script>
import { Select, Label } from "@budibase/bbui"
import { store, backendUiStore } from "builderStore"
import fetchBindableProperties from "builderStore/fetchBindableProperties"
export let parameters
let idFields
$: bindableProperties = fetchBindableProperties({
componentInstanceId: $store.currentComponentInfo._id,
components: $store.components,
screen: $store.currentPreviewItem,
tables: $backendUiStore.tables,
})
$: idFields = bindableProperties.filter(
bindable =>
bindable.type === "context" && bindable.runtimeBinding.endsWith("._id")
)
$: {
if (parameters.rowId) {
// Set rev ID
parameters.revId = parameters.rowId.replace("_id", "_rev")
// Set table ID
const idBinding = bindableProperties.find(
prop =>
prop.runtimeBinding ===
parameters.rowId
.replace("{{", "")
.replace("}}", "")
.trim()
)
if (idBinding) {
const { instance } = idBinding
const component = $store.components[instance._component]
const tableInfo = instance[component.context]
if (tableInfo) {
parameters.tableId =
typeof tableInfo === "string" ? tableInfo : tableInfo.tableId
}
}
console.log(parameters)
}
}
</script>
<div class="root">
{#if idFields.length === 0}
<div class="cannot-use">
Delete row can only be used within a component that provides data, such as
a List
</div>
{:else}
<Label size="m" color="dark">Datasource</Label>
<Select secondary bind:value={parameters.rowId}>
<option value="" />
{#each idFields as idField}
<option value={`{{ ${idField.runtimeBinding} }}`}>
{idField.instance._instanceName}
</option>
{/each}
</Select>
{/if}
</div>
<style>
.root {
display: grid;
column-gap: var(--spacing-s);
row-gap: var(--spacing-s);
grid-template-columns: auto 1fr auto 1fr auto;
align-items: baseline;
}
.root :global(> div:nth-child(2)) {
grid-column-start: 2;
grid-column-end: 6;
}
.cannot-use {
color: var(--red);
font-size: var(--font-size-s);
text-align: center;
width: 70%;
margin: auto;
}
</style>

View File

@ -1,5 +1,6 @@
import NavigateTo from "./NavigateTo.svelte" import NavigateTo from "./NavigateTo.svelte"
import SaveRow from "./SaveRow.svelte" import SaveRow from "./SaveRow.svelte"
import DeleteRow from "./DeleteRow.svelte"
// defines what actions are available, when adding a new one // defines what actions are available, when adding a new one
// the component is the setup panel for the action // the component is the setup panel for the action
@ -11,6 +12,10 @@ export default [
name: "Save Row", name: "Save Row",
component: SaveRow, component: SaveRow,
}, },
{
name: "Delete Row",
component: DeleteRow,
},
{ {
name: "Navigate To", name: "Navigate To",
component: NavigateTo, component: NavigateTo,

View File

@ -81,6 +81,7 @@ export const layout = [
{ label: "16px", value: "16px" }, { label: "16px", value: "16px" },
{ label: "20px", value: "20px" }, { label: "20px", value: "20px" },
{ label: "32px", value: "32px" }, { label: "32px", value: "32px" },
{ label: "48px", value: "48px" },
{ label: "64px", value: "64px" }, { label: "64px", value: "64px" },
], ],
}, },
@ -98,6 +99,7 @@ export const margin = [
{ label: "16px", value: "16px" }, { label: "16px", value: "16px" },
{ label: "20px", value: "20px" }, { label: "20px", value: "20px" },
{ label: "32px", value: "32px" }, { label: "32px", value: "32px" },
{ label: "48px", value: "48px" },
{ label: "64px", value: "64px" }, { label: "64px", value: "64px" },
{ label: "128px", value: "128px" }, { label: "128px", value: "128px" },
{ label: "256px", value: "256px" }, { label: "256px", value: "256px" },
@ -116,6 +118,7 @@ export const margin = [
{ label: "16px", value: "16px" }, { label: "16px", value: "16px" },
{ label: "20px", value: "20px" }, { label: "20px", value: "20px" },
{ label: "32px", value: "32px" }, { label: "32px", value: "32px" },
{ label: "48px", value: "48px" },
{ label: "64px", value: "64px" }, { label: "64px", value: "64px" },
{ label: "128px", value: "128px" }, { label: "128px", value: "128px" },
{ label: "256px", value: "256px" }, { label: "256px", value: "256px" },
@ -134,6 +137,7 @@ export const margin = [
{ label: "16px", value: "16px" }, { label: "16px", value: "16px" },
{ label: "20px", value: "20px" }, { label: "20px", value: "20px" },
{ label: "32px", value: "32px" }, { label: "32px", value: "32px" },
{ label: "48px", value: "48px" },
{ label: "64px", value: "64px" }, { label: "64px", value: "64px" },
{ label: "Auto", value: "auto" }, { label: "Auto", value: "auto" },
{ label: "100%", value: "100%" }, { label: "100%", value: "100%" },
@ -150,6 +154,7 @@ export const margin = [
{ label: "16px", value: "16px" }, { label: "16px", value: "16px" },
{ label: "20px", value: "20px" }, { label: "20px", value: "20px" },
{ label: "32px", value: "32px" }, { label: "32px", value: "32px" },
{ label: "48px", value: "48px" },
{ label: "64px", value: "64px" }, { label: "64px", value: "64px" },
{ label: "128px", value: "128px" }, { label: "128px", value: "128px" },
{ label: "256px", value: "256px" }, { label: "256px", value: "256px" },
@ -168,6 +173,7 @@ export const margin = [
{ label: "16px", value: "16px" }, { label: "16px", value: "16px" },
{ label: "20px", value: "20px" }, { label: "20px", value: "20px" },
{ label: "32px", value: "32px" }, { label: "32px", value: "32px" },
{ label: "48px", value: "48px" },
{ label: "64px", value: "64px" }, { label: "64px", value: "64px" },
{ label: "128px", value: "128px" }, { label: "128px", value: "128px" },
{ label: "256px", value: "256px" }, { label: "256px", value: "256px" },
@ -189,6 +195,7 @@ export const padding = [
{ label: "16px", value: "16px" }, { label: "16px", value: "16px" },
{ label: "20px", value: "20px" }, { label: "20px", value: "20px" },
{ label: "32px", value: "32px" }, { label: "32px", value: "32px" },
{ label: "48px", value: "48px" },
{ label: "64px", value: "64px" }, { label: "64px", value: "64px" },
{ label: "Auto", value: "auto" }, { label: "Auto", value: "auto" },
{ label: "100%", value: "100%" }, { label: "100%", value: "100%" },
@ -205,6 +212,7 @@ export const padding = [
{ label: "16px", value: "16px" }, { label: "16px", value: "16px" },
{ label: "20px", value: "20px" }, { label: "20px", value: "20px" },
{ label: "32px", value: "32px" }, { label: "32px", value: "32px" },
{ label: "48px", value: "48px" },
{ label: "64px", value: "64px" }, { label: "64px", value: "64px" },
{ label: "Auto", value: "auto" }, { label: "Auto", value: "auto" },
{ label: "100%", value: "100%" }, { label: "100%", value: "100%" },
@ -221,6 +229,7 @@ export const padding = [
{ label: "16px", value: "16px" }, { label: "16px", value: "16px" },
{ label: "20px", value: "20px" }, { label: "20px", value: "20px" },
{ label: "32px", value: "32px" }, { label: "32px", value: "32px" },
{ label: "48px", value: "48px" },
{ label: "64px", value: "64px" }, { label: "64px", value: "64px" },
{ label: "Auto", value: "auto" }, { label: "Auto", value: "auto" },
{ label: "100%", value: "100%" }, { label: "100%", value: "100%" },
@ -237,6 +246,7 @@ export const padding = [
{ label: "16px", value: "16px" }, { label: "16px", value: "16px" },
{ label: "20px", value: "20px" }, { label: "20px", value: "20px" },
{ label: "32px", value: "32px" }, { label: "32px", value: "32px" },
{ label: "48px", value: "48px" },
{ label: "64px", value: "64px" }, { label: "64px", value: "64px" },
{ label: "Auto", value: "auto" }, { label: "Auto", value: "auto" },
{ label: "100%", value: "100%" }, { label: "100%", value: "100%" },
@ -253,6 +263,7 @@ export const padding = [
{ label: "16px", value: "16px" }, { label: "16px", value: "16px" },
{ label: "20px", value: "20px" }, { label: "20px", value: "20px" },
{ label: "32px", value: "32px" }, { label: "32px", value: "32px" },
{ label: "48px", value: "48px" },
{ label: "64px", value: "64px" }, { label: "64px", value: "64px" },
{ label: "Auto", value: "auto" }, { label: "Auto", value: "auto" },
{ label: "100%", value: "100%" }, { label: "100%", value: "100%" },

View File

@ -6,6 +6,7 @@ import TableViewSelect from "components/userInterface/TableViewSelect.svelte"
import TableViewFieldSelect from "components/userInterface/TableViewFieldSelect.svelte" import TableViewFieldSelect from "components/userInterface/TableViewFieldSelect.svelte"
import Event from "components/userInterface/EventsEditor/EventPropertyControl.svelte" import Event from "components/userInterface/EventsEditor/EventPropertyControl.svelte"
import ScreenSelect from "components/userInterface/ScreenSelect.svelte" import ScreenSelect from "components/userInterface/ScreenSelect.svelte"
import DetailScreenSelect from "components/userInterface/DetailScreenSelect.svelte"
import { IconSelect } from "components/userInterface/IconSelect" import { IconSelect } from "components/userInterface/IconSelect"
import Colorpicker from "@budibase/colorpicker" import Colorpicker from "@budibase/colorpicker"
@ -328,10 +329,9 @@ export default {
control: TableViewSelect, control: TableViewSelect,
}, },
{ {
label: "Table URL", label: "Detail URL",
key: "detailUrl", key: "detailUrl",
placeholder: "tableName", control: DetailScreenSelect,
control: ScreenSelect,
}, },
{ {
label: "Editable", label: "Editable",

View File

@ -709,10 +709,10 @@
lodash "^4.17.13" lodash "^4.17.13"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@budibase/bbui@^1.41.0": "@budibase/bbui@^1.44.0":
version "1.41.0" version "1.44.0"
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.41.0.tgz#cb239db3071a4a6c6f0ef48ddde55f5eab9808ce" resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.44.0.tgz#0c00d98173a8b0ab757f61e349ed366bf640be4b"
integrity sha512-pT5u6HDdXcylWgSE1TBt3jETg92GwgAXpUsBVqX+OUE/2lNbmThb8egAckpemHDvm91FAL0nApQYpV7c/qLzvw== integrity sha512-YlcRSgOZct8W07z9IaOXNFrVvG0EUWxzcfuEOfXZRviGxm9TIhe/G6T9Cai1ZgPGicnKXa0dPAT3UrzIVB5xJg==
dependencies: dependencies:
sirv-cli "^0.4.6" sirv-cli "^0.4.6"
svelte-flatpickr "^2.4.0" svelte-flatpickr "^2.4.0"

View File

@ -1,5 +1,5 @@
import { authenticate } from "./authenticate" import { authenticate } from "./authenticate"
import appStore from "../state/store" // import appStore from "../state/store"
const apiCall = method => async ({ url, body }) => { const apiCall = method => async ({ url, body }) => {
const response = await fetch(url, { const response = await fetch(url, {
@ -37,7 +37,7 @@ const del = apiCall("DELETE")
const ERROR_MEMBER = "##error" const ERROR_MEMBER = "##error"
const error = message => { const error = message => {
const err = { [ERROR_MEMBER]: message } const err = { [ERROR_MEMBER]: message }
appStore.update(s => s["##error_message"], message) // appStore.update(s => s["##error_message"], message)
return err return err
} }
@ -67,6 +67,11 @@ const updateRow = async (params, state) => {
}) })
} }
const deleteRow = async params =>
await del({
url: `/api/${params.tableId}/rows/${params.rowId}/${params.revId}`,
})
const makeRowRequestBody = (parameters, state) => { const makeRowRequestBody = (parameters, state) => {
// start with the row thats currently in context // start with the row thats currently in context
const body = { ...(state.data || {}) } const body = { ...(state.data || {}) }
@ -103,4 +108,5 @@ export default {
authenticate: authenticate(apiOpts), authenticate: authenticate(apiOpts),
saveRow, saveRow,
updateRow, updateRow,
deleteRow,
} }

View File

@ -3,21 +3,28 @@ import appStore from "../state/store"
import { parseAppIdFromCookie } from "./getAppId" import { parseAppIdFromCookie } from "./getAppId"
export const screenRouter = ({ screens, onScreenSelected, window }) => { export const screenRouter = ({ screens, onScreenSelected, window }) => {
const isRunningLocally = () => {
const hostname = (window.location && window.location.hostname) || ""
return (
hostname === "localhost" ||
hostname === "127.0.0.1" ||
hostname.startsWith("192.168")
)
}
const makeRootedPath = url => { const makeRootedPath = url => {
const hostname = window.location && window.location.hostname if (isRunningLocally()) {
if (hostname) { const appId = parseAppIdFromCookie(window.document.cookie)
if ( if (url) {
hostname === "localhost" || if (!url.startsWith("/")) {
hostname === "127.0.0.1" || url = `/${url}`
hostname.startsWith("192.168")
) {
const appId = parseAppIdFromCookie(window.document.cookie)
if (url) {
if (url.startsWith(appId)) return url
return `/${appId}${url.startsWith("/") ? "" : "/"}${url}`
} }
return appId if (url.startsWith(`/${appId}`)) {
return url
}
return `/${appId}${url}`
} }
return `/${appId}`
} }
return url return url
} }

View File

@ -8,6 +8,7 @@ export const eventHandlers = routeTo => {
"Navigate To": param => routeTo(param && param.url), "Navigate To": param => routeTo(param && param.url),
"Update Row": api.updateRow, "Update Row": api.updateRow,
"Save Row": api.saveRow, "Save Row": api.saveRow,
"Delete Row": api.deleteRow,
"Trigger Workflow": api.triggerWorkflow, "Trigger Workflow": api.triggerWorkflow,
} }

View File

@ -19,7 +19,8 @@
"justify-content": "flex-start", "justify-content": "flex-start",
"align-items": "flex-start", "align-items": "flex-start",
"background": "#fff", "background": "#fff",
"width": "100%" "width": "100%",
"box-shadow": "0 1px 2px 0 rgba(0, 0, 0, 0.05)"
}, },
"hover": {}, "hover": {},
"active": {}, "active": {},
@ -67,7 +68,7 @@
"_styles": { "_styles": {
"normal": { "normal": {
"font-family": "Inter", "font-family": "Inter",
"font-weight": "400", "font-weight": "500",
"color": "#000000", "color": "#000000",
"text-decoration-line": "none", "text-decoration-line": "none",
"font-size": "16px" "font-size": "16px"

View File

@ -97,6 +97,6 @@
], ],
"_instanceName": "Home" "_instanceName": "Home"
}, },
"route": "/*", "route": "/",
"name": "d834fea2-1b3e-4320-ab34-f9009f5ecc59" "name": "d834fea2-1b3e-4320-ab34-f9009f5ecc59"
} }

View File

@ -240,7 +240,7 @@
}, },
"height": { "height": {
"type": "number", "type": "number",
"default": "500" "default": "540"
}, },
"pagination": { "pagination": {
"type": "bool", "type": "bool",

View File

@ -36,7 +36,7 @@
"gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691", "gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691",
"dependencies": { "dependencies": {
"@beyonk/svelte-googlemaps": "^2.2.0", "@beyonk/svelte-googlemaps": "^2.2.0",
"@budibase/bbui": "^1.41.0", "@budibase/bbui": "^1.44.0",
"@budibase/svelte-ag-grid": "^0.0.13", "@budibase/svelte-ag-grid": "^0.0.13",
"@fortawesome/fontawesome-free": "^5.14.0", "@fortawesome/fontawesome-free": "^5.14.0",
"@svelteschool/svelte-forms": "^0.7.0", "@svelteschool/svelte-forms": "^0.7.0",

View File

@ -25,12 +25,10 @@
<style> <style>
.default { .default {
align-items: center; align-items: center;
font-size: 16px; padding: var(--spacing-s) var(--spacing-l);
padding: 0px 16px;
box-sizing: border-box; box-sizing: border-box;
border-radius: 4px; border-radius: 4px;
outline: none; outline: none;
height: 40px;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease 0s; transition: all 0.2s ease 0s;
overflow: hidden; overflow: hidden;

View File

@ -80,22 +80,29 @@
autoHeight: true, autoHeight: true,
} }
}) })
columnDefs = [
...columnDefs, if (detailUrl) {
{ columnDefs = [
headerName: "Details", ...columnDefs,
field: "_id", {
width: 25, headerName: "Detail",
flex: 0, field: "_id",
editable: false, minWidth: 100,
sortable: false, width: 100,
cellRenderer: getRenderer({ flex: 0,
type: "_id", editable: false,
options: detailUrl, sortable: false,
}), cellRenderer: getRenderer({
autoHeight: true, type: "_id",
}, options: { detailUrl },
] }),
autoHeight: true,
pinned: "left",
filter: false,
},
]
}
dataLoaded = true dataLoaded = true
} }
}) })
@ -139,7 +146,7 @@
href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css" /> href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css" />
</svelte:head> </svelte:head>
<div style="--grid-height: {height}px"> <div class="container" style="--grid-height: {height}px">
{#if dataLoaded} {#if dataLoaded}
{#if canAddDelete} {#if canAddDelete}
<div class="controls"> <div class="controls">
@ -172,6 +179,10 @@
</div> </div>
<style> <style>
.container :global(.ag-pinned-left-header .ag-header-cell-label) {
justify-content: center;
}
.controls { .controls {
min-height: 15px; min-height: 15px;
margin-bottom: var(--spacing-s); margin-bottom: var(--spacing-s);

View File

@ -1,12 +1,14 @@
<script> <script>
import { Icon } from "@budibase/bbui" import { Button } from "@budibase/bbui"
export let url export let url
let link
</script> </script>
<a href={url}><Icon name="view" /></a> <a href={url} bind:this={link} />
<Button small translucent on:click={() => link.click()}>View</Button>
<style> <style>
a { a {
color: var(--grey-6); display: none;
} }
</style> </style>

View File

@ -17,14 +17,18 @@ const renderers = new Map([
export function getRenderer(schema, editable) { export function getRenderer(schema, editable) {
if (renderers.get(schema.type)) { if (renderers.get(schema.type)) {
return renderers.get(schema.type)(schema.options, editable) return renderers.get(schema.type)(
schema.options,
schema.constraints,
editable
)
} else { } else {
return false return false
} }
} }
/* eslint-disable no-unused-vars */ /* eslint-disable no-unused-vars */
function booleanRenderer(options, editable) { function booleanRenderer(options, constraints, editable) {
return params => { return params => {
const toggle = e => { const toggle = e => {
params.value = !params.value params.value = !params.value
@ -46,7 +50,7 @@ function booleanRenderer(options, editable) {
} }
} }
/* eslint-disable no-unused-vars */ /* eslint-disable no-unused-vars */
function attachmentRenderer(options, editable) { function attachmentRenderer(options, constraints, editable) {
return params => { return params => {
const container = document.createElement("div") const container = document.createElement("div")
@ -68,7 +72,7 @@ function attachmentRenderer(options, editable) {
} }
} }
/* eslint-disable no-unused-vars */ /* eslint-disable no-unused-vars */
function dateRenderer(options, editable) { function dateRenderer(options, constraints, editable) {
return function(params) { return function(params) {
const container = document.createElement("div") const container = document.createElement("div")
const toggle = e => { const toggle = e => {
@ -76,8 +80,7 @@ function dateRenderer(options, editable) {
} }
// Options need to be passed in with minTime and maxTime! Needs bbui update. // Options need to be passed in with minTime and maxTime! Needs bbui update.
new DatePicker({
const datePickerInstance = new DatePicker({
target: container, target: container,
props: { props: {
value: params.value, value: params.value,
@ -88,7 +91,7 @@ function dateRenderer(options, editable) {
} }
} }
function optionsRenderer({ inclusion }, editable) { function optionsRenderer(options, constraints, editable) {
return params => { return params => {
if (!editable) return params.value if (!editable) return params.value
const container = document.createElement("div") const container = document.createElement("div")
@ -103,7 +106,7 @@ function optionsRenderer({ inclusion }, editable) {
target: container, target: container,
props: { props: {
value: params.value, value: params.value,
options: inclusion, options: constraints.inclusion,
}, },
}) })
@ -113,7 +116,7 @@ function optionsRenderer({ inclusion }, editable) {
} }
} }
/* eslint-disable no-unused-vars */ /* eslint-disable no-unused-vars */
function linkedRowRenderer(options, editable) { function linkedRowRenderer(options, constraints, editable) {
return params => { return params => {
let container = document.createElement("div") let container = document.createElement("div")
container.style.display = "grid" container.style.display = "grid"
@ -133,18 +136,21 @@ function linkedRowRenderer(options, editable) {
} }
/* eslint-disable no-unused-vars */ /* eslint-disable no-unused-vars */
function viewDetailsRenderer(options) { function viewDetailsRenderer(options, constraints, editable) {
return params => { return params => {
let container = document.createElement("div") let container = document.createElement("div")
container.style.display = "grid" container.style.display = "grid"
container.style.placeItems = "center" container.style.alignItems = "center"
container.style.height = "100%" container.style.height = "100%"
let url = "/"
if (options.detailUrl) {
url = options.detailUrl.replace(":id", params.data._id)
}
new ViewDetails({ new ViewDetails({
target: container, target: container,
props: { props: { url },
url: `${options}/${params.data._id}`,
},
}) })
return container return container

View File

@ -23,9 +23,7 @@
{#each fields as field} {#each fields as field}
<div class="form-field" class:wide> <div class="form-field" class:wide>
{#if !(schema[field].type === 'boolean' && !wide)} {#if !(schema[field].type === 'boolean' && !wide)}
<Label extraSmall={!wide} grey={!wide}> <Label extraSmall={!wide} grey>{capitalise(schema[field].name)}</Label>
{capitalise(schema[field].name)}
</Label>
{/if} {/if}
{#if schema[field].type === 'options'} {#if schema[field].type === 'options'}
<Select secondary bind:value={$store.data[field]}> <Select secondary bind:value={$store.data[field]}>
@ -65,7 +63,6 @@
} }
.form-content { .form-content {
margin-bottom: var(--spacing-xl);
display: grid; display: grid;
gap: var(--spacing-xl); gap: var(--spacing-xl);
width: 100%; width: 100%;
@ -76,7 +73,7 @@
} }
.form-field.wide { .form-field.wide {
align-items: center; align-items: center;
grid-template-columns: 30% 1fr; grid-template-columns: 20% 1fr;
gap: var(--spacing-xl); gap: var(--spacing-xl);
} }
.form-field.wide :global(label) { .form-field.wide :global(label) {

View File

@ -65,9 +65,7 @@
placeholder="Password" placeholder="Password"
class={_inputClass} /> class={_inputClass} />
</div> </div>
</div>
<div class="login-button-container">
<button disabled={loading} on:click={login} class={_buttonClass}> <button disabled={loading} on:click={login} class={_buttonClass}>
{buttonText || 'Log In'} {buttonText || 'Log In'}
</button> </button>
@ -91,25 +89,24 @@
.content { .content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: stretch;
justify-content: center; justify-content: center;
} }
.logo-container { .logo-container {
margin-bottom: 10px; margin-bottom: 10px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
} }
.logo-container > img { .logo-container > img {
height: 80px; max-height: 80px;
max-width: 200px; max-width: 200px;
margin-bottom: 20px; margin-bottom: 20px;
} }
.login-button-container {
margin-top: 6px;
max-width: 100%;
}
.header-content { .header-content {
font-family: Inter; font-family: Inter;
font-weight: 700; font-weight: 700;
@ -137,12 +134,13 @@
.form-root { .form-root {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: stretch;
width: 300px; width: 300px;
margin: auto;
gap: 8px;
} }
.control { .control {
padding: 6px 0px;
width: 100%; width: 100%;
} }
@ -186,4 +184,9 @@
border-color: #393c44; border-color: #393c44;
color: #393c44; color: #393c44;
} }
h2 {
text-align: center;
margin-bottom: 10px;
}
</style> </style>

View File

@ -1,11 +1,7 @@
<script> <script>
import { buildStyle } from "./buildStyle"
export let text = "" export let text = ""
export let className = "" export let className = ""
export let type = "" export let type = ""
export let _bb export let _bb
const isTag = tag => type === tag const isTag = tag => type === tag
@ -34,3 +30,9 @@
{:else if isTag('sup')} {:else if isTag('sup')}
<sup class={className}>{text}</sup> <sup class={className}>{text}</sup>
{:else}<span>{text}</span>{/if} {:else}<span>{text}</span>{/if}
<style>
span {
display: inline-block;
}
</style>