Merge branch 'master' of github.com:Budibase/budibase into deployment-history
This commit is contained in:
commit
a64c1c9ded
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/builder",
|
"name": "@budibase/builder",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -63,8 +63,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "^1.41.0",
|
"@budibase/bbui": "^1.44.0",
|
||||||
"@budibase/client": "^0.2.1",
|
"@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",
|
||||||
"@sentry/browser": "5.19.1",
|
"@sentry/browser": "5.19.1",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import api from "../api"
|
import api from "../api"
|
||||||
|
|
||||||
|
@ -62,16 +62,30 @@ export const getBackendUiStore = () => {
|
||||||
}),
|
}),
|
||||||
save: async table => {
|
save: async table => {
|
||||||
const updatedTable = cloneDeep(table)
|
const updatedTable = cloneDeep(table)
|
||||||
|
const oldTable = get(store).tables.filter(t => t._id === table._id)[0]
|
||||||
|
|
||||||
|
const fieldNames = []
|
||||||
// update any renamed schema keys to reflect their names
|
// update any renamed schema keys to reflect their names
|
||||||
for (let key in updatedTable.schema) {
|
for (let key of Object.keys(updatedTable.schema)) {
|
||||||
|
// if field name has been seen before remove it
|
||||||
|
if (fieldNames.indexOf(key.toLowerCase()) !== -1) {
|
||||||
|
delete updatedTable.schema[key]
|
||||||
|
continue
|
||||||
|
}
|
||||||
const field = updatedTable.schema[key]
|
const field = updatedTable.schema[key]
|
||||||
|
const oldField = oldTable?.schema[key]
|
||||||
|
// if the type has changed then revert back to the old field
|
||||||
|
if (oldField != null && oldField.type !== field.type) {
|
||||||
|
updatedTable.schema[key] = oldField
|
||||||
|
}
|
||||||
// field has been renamed
|
// field has been renamed
|
||||||
if (field.name && field.name !== key) {
|
if (field.name && field.name !== key) {
|
||||||
updatedTable.schema[field.name] = field
|
updatedTable.schema[field.name] = field
|
||||||
updatedTable._rename = { old: key, updated: field.name }
|
updatedTable._rename = { old: key, updated: field.name }
|
||||||
delete updatedTable.schema[key]
|
delete updatedTable.schema[key]
|
||||||
}
|
}
|
||||||
|
// finally record this field has been used
|
||||||
|
fieldNames.push(key.toLowerCase())
|
||||||
}
|
}
|
||||||
|
|
||||||
const SAVE_TABLE_URL = `/api/tables`
|
const SAVE_TABLE_URL = `/api/tables`
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { values, cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import getNewComponentName from "../getNewComponentName"
|
import getNewComponentName from "../getNewComponentName"
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
|
@ -129,7 +129,10 @@ const setPackage = (store, initial) => async pkg => {
|
||||||
initial.appId = pkg.application._id
|
initial.appId = pkg.application._id
|
||||||
initial.pages = pkg.pages
|
initial.pages = pkg.pages
|
||||||
initial.hasAppPackage = true
|
initial.hasAppPackage = true
|
||||||
initial.screens = values(pkg.screens)
|
initial.screens = [
|
||||||
|
...Object.values(main_screens),
|
||||||
|
...Object.values(unauth_screens),
|
||||||
|
]
|
||||||
initial.builtins = [getBuiltin("##builtin/screenslot")]
|
initial.builtins = [getBuiltin("##builtin/screenslot")]
|
||||||
initial.appInstances = pkg.application.instances
|
initial.appInstances = pkg.application.instances
|
||||||
initial.appId = pkg.application._id
|
initial.appId = pkg.application._id
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
|
import sanitizeUrl from "./sanitizeUrl"
|
||||||
|
import { rowListUrl } from "./rowListScreen"
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const newRowUrl = table => sanitizeUrl(`/${table.name}/new`)
|
||||||
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 +27,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,40 +52,157 @@ 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",
|
||||||
|
_component: "@budibase/standard-components/link",
|
||||||
|
_styles: {
|
||||||
|
normal: {
|
||||||
|
color: "#757575",
|
||||||
|
"text-transform": "capitalize",
|
||||||
|
},
|
||||||
|
hover: {
|
||||||
|
color: "#4285f4",
|
||||||
|
},
|
||||||
|
active: {},
|
||||||
|
selected: {},
|
||||||
|
},
|
||||||
|
_code: "",
|
||||||
url: `/${table.name.toLowerCase()}`,
|
url: `/${table.name.toLowerCase()}`,
|
||||||
},
|
openInNewTab: false,
|
||||||
"##eventHandlerType": "Navigate To",
|
text: table.name,
|
||||||
},
|
color: "",
|
||||||
],
|
hoverColor: "",
|
||||||
_instanceName: "Back Button",
|
underline: false,
|
||||||
|
fontSize: "",
|
||||||
|
fontFamily: "initial",
|
||||||
|
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
|
||||||
|
_instanceName: "Back Link",
|
||||||
_children: [],
|
_children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_id: "",
|
_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: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_id: "cbd1637cd1e274287a3c28ef0bf235d08",
|
||||||
|
_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",
|
_component: "@budibase/standard-components/button",
|
||||||
_styles: {
|
_styles: {
|
||||||
normal: {},
|
normal: {
|
||||||
hover: {},
|
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: {},
|
active: {},
|
||||||
selected: {},
|
selected: {},
|
||||||
},
|
},
|
||||||
|
@ -120,16 +218,38 @@ const createScreen = (table, heading) => ({
|
||||||
},
|
},
|
||||||
"##eventHandlerType": "Save Row",
|
"##eventHandlerType": "Save Row",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
parameters: {
|
||||||
|
url: rowListUrl(table),
|
||||||
|
},
|
||||||
|
"##eventHandlerType": "Navigate To",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
_instanceName: "Save Button",
|
_instanceName: "Save Button",
|
||||||
_children: [],
|
_children: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
_id: "c5e6c98d7363640f9ad3a7d19c8c10f67",
|
||||||
|
_component: "@budibase/standard-components/dataformwide",
|
||||||
|
_styles: {
|
||||||
|
normal: {},
|
||||||
|
hover: {},
|
||||||
|
active: {},
|
||||||
|
selected: {},
|
||||||
|
},
|
||||||
|
_code: "",
|
||||||
|
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
|
||||||
|
_instanceName: "Form",
|
||||||
|
_children: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
_instanceName: `${table.name} - New`,
|
_instanceName: `${table.name} - New`,
|
||||||
_code: "",
|
_code: "",
|
||||||
},
|
},
|
||||||
route: `/${table.name.toLowerCase()}/new`,
|
route: newRowUrl(table),
|
||||||
name: "",
|
name: "",
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
import sanitizeUrl from "./sanitizeUrl"
|
||||||
|
import { rowListUrl } from "./rowListScreen"
|
||||||
|
|
||||||
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),
|
||||||
|
@ -11,10 +15,11 @@ export default function(tables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ROW_DETAIL_TEMPLATE = "ROW_DETAIL_TEMPLATE"
|
export const ROW_DETAIL_TEMPLATE = "ROW_DETAIL_TEMPLATE"
|
||||||
|
export const rowDetailUrl = table => sanitizeUrl(`/${table.name}/:id`)
|
||||||
|
|
||||||
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 +30,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,40 +55,203 @@ 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: "",
|
||||||
|
onLoad: [],
|
||||||
|
type: "div",
|
||||||
|
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
|
||||||
|
_instanceName: "Breadcrumbs",
|
||||||
|
_children: [
|
||||||
|
{
|
||||||
|
_id: "caa33353c252c4931b2a51b48a559a7fc",
|
||||||
|
_component: "@budibase/standard-components/link",
|
||||||
|
_styles: {
|
||||||
|
normal: {
|
||||||
|
color: "#757575",
|
||||||
|
"text-transform": "capitalize",
|
||||||
|
},
|
||||||
|
hover: {
|
||||||
|
color: "#4285f4",
|
||||||
|
},
|
||||||
|
active: {},
|
||||||
|
selected: {},
|
||||||
|
},
|
||||||
|
_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: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_id: "cbd1637cd1e274287a3c28ef0bf235d08",
|
||||||
|
_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: "",
|
className: "",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
onClick: [
|
onClick: [
|
||||||
{
|
{
|
||||||
parameters: {
|
parameters: {
|
||||||
url: `/${table.name.toLowerCase()}`,
|
rowId: "{{ data._id }}",
|
||||||
|
revId: "{{ data._rev }}",
|
||||||
|
tableId: table._id,
|
||||||
|
},
|
||||||
|
"##eventHandlerType": "Delete Row",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameters: {
|
||||||
|
url: rowListUrl(table),
|
||||||
},
|
},
|
||||||
"##eventHandlerType": "Navigate To",
|
"##eventHandlerType": "Navigate To",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
_instanceName: "Back Button",
|
_instanceName: "Delete Button",
|
||||||
_children: [],
|
_children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_id: "",
|
_id: "cae402bd3c6a44618a8341bf7ab9ab086",
|
||||||
_component: "@budibase/standard-components/button",
|
_component: "@budibase/standard-components/button",
|
||||||
_styles: {
|
_styles: {
|
||||||
normal: {},
|
normal: {
|
||||||
hover: {},
|
background: "#000000",
|
||||||
|
"border-width": "0",
|
||||||
|
"border-style": "None",
|
||||||
|
color: "#fff",
|
||||||
|
"font-family": "Inter",
|
||||||
|
"font-weight": "500",
|
||||||
|
"font-size": "14px",
|
||||||
|
},
|
||||||
|
hover: {
|
||||||
|
background: "#4285f4",
|
||||||
|
},
|
||||||
active: {},
|
active: {},
|
||||||
selected: {},
|
selected: {},
|
||||||
},
|
},
|
||||||
|
@ -120,16 +267,38 @@ const createScreen = (table, heading) => ({
|
||||||
},
|
},
|
||||||
"##eventHandlerType": "Save Row",
|
"##eventHandlerType": "Save Row",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
parameters: {
|
||||||
|
url: rowListUrl(table),
|
||||||
|
},
|
||||||
|
"##eventHandlerType": "Navigate To",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
_instanceName: "Save Button",
|
_instanceName: "Save Button",
|
||||||
_children: [],
|
_children: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
_id: "c5e6c98d7363640f9ad3a7d19c8c10f67",
|
||||||
|
_component: "@budibase/standard-components/dataformwide",
|
||||||
|
_styles: {
|
||||||
|
normal: {},
|
||||||
|
hover: {},
|
||||||
|
active: {},
|
||||||
|
selected: {},
|
||||||
|
},
|
||||||
|
_code: "",
|
||||||
|
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
|
||||||
|
_instanceName: "Form",
|
||||||
|
_children: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
_instanceName: `${table.name} - Detail`,
|
_instanceName: `${table.name} - Detail`,
|
||||||
_code: "",
|
_code: "",
|
||||||
},
|
},
|
||||||
route: `/${table.name.toLowerCase()}/:id`,
|
route: rowDetailUrl(table),
|
||||||
name: "",
|
name: "",
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import sanitizeUrl from "./sanitizeUrl"
|
||||||
|
import { newRowUrl } from "./newRowScreen"
|
||||||
|
|
||||||
export default function(tables) {
|
export default function(tables) {
|
||||||
return tables.map(table => {
|
return tables.map(table => {
|
||||||
return {
|
return {
|
||||||
|
@ -9,10 +12,11 @@ export default function(tables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ROW_LIST_TEMPLATE = "ROW_LIST_TEMPLATE"
|
export const ROW_LIST_TEMPLATE = "ROW_LIST_TEMPLATE"
|
||||||
|
export const rowListUrl = table => sanitizeUrl(`/${table.name}`)
|
||||||
|
|
||||||
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 +27,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,30 +53,67 @@ 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",
|
||||||
|
_instanceName: "Title Container",
|
||||||
|
_children: [
|
||||||
|
{
|
||||||
|
_id: "c2b77901df95a4d1ca7204c58300bc94b",
|
||||||
|
_component: "@budibase/standard-components/heading",
|
||||||
|
_styles: {
|
||||||
|
normal: {
|
||||||
|
margin: "0px",
|
||||||
|
flex: "1 1 auto",
|
||||||
|
"text-transform": "capitalize",
|
||||||
|
},
|
||||||
|
hover: {},
|
||||||
|
active: {},
|
||||||
|
selected: {},
|
||||||
|
},
|
||||||
|
_code: "",
|
||||||
|
className: "",
|
||||||
|
text: table.name,
|
||||||
|
type: "h3",
|
||||||
|
_instanceName: "Title",
|
||||||
_children: [],
|
_children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_id: "",
|
_id: "c12a82d77baf24ca9922ea0af7cd4f723",
|
||||||
_component: "@budibase/standard-components/button",
|
_component: "@budibase/standard-components/button",
|
||||||
_styles: {
|
_styles: {
|
||||||
normal: {},
|
normal: {
|
||||||
hover: {},
|
background: "#000000",
|
||||||
|
"border-width": "0",
|
||||||
|
"border-style": "None",
|
||||||
|
color: "#fff",
|
||||||
|
"font-family": "Inter",
|
||||||
|
"font-weight": "500",
|
||||||
|
"font-size": "14px",
|
||||||
|
},
|
||||||
|
hover: {
|
||||||
|
background: "#4285f4",
|
||||||
|
},
|
||||||
active: {},
|
active: {},
|
||||||
selected: {},
|
selected: {},
|
||||||
},
|
},
|
||||||
|
@ -74,18 +124,18 @@ const createScreen = table => ({
|
||||||
onClick: [
|
onClick: [
|
||||||
{
|
{
|
||||||
parameters: {
|
parameters: {
|
||||||
url: `/${table.name}/new`,
|
url: newRowUrl(table),
|
||||||
},
|
},
|
||||||
"##eventHandlerType": "Navigate To",
|
"##eventHandlerType": "Navigate To",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
_instanceName: "Create New Button",
|
_instanceName: "New Button",
|
||||||
_children: [],
|
_children: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_id: "",
|
_id: "ca686a2ed89c943e6bafb63fa66a3ead3",
|
||||||
_component: "@budibase/standard-components/datagrid",
|
_component: "@budibase/standard-components/datagrid",
|
||||||
_styles: {
|
_styles: {
|
||||||
normal: {},
|
normal: {},
|
||||||
|
@ -95,13 +145,21 @@ const createScreen = table => ({
|
||||||
},
|
},
|
||||||
_code: "",
|
_code: "",
|
||||||
datasource: {
|
datasource: {
|
||||||
label: "Deals",
|
label: table.name,
|
||||||
name: `all_${table._id}`,
|
name: `all_${table._id}`,
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
type: "table",
|
type: "table",
|
||||||
},
|
},
|
||||||
_instanceName: `${table.name} Table`,
|
editable: false,
|
||||||
|
theme: "alpine",
|
||||||
|
height: "540",
|
||||||
|
pagination: true,
|
||||||
|
_instanceId: "inst_app_8fb_631af42f9dc94da2b5c48dc6c5124610",
|
||||||
|
_instanceName: "Grid",
|
||||||
_children: [],
|
_children: [],
|
||||||
|
detailUrl: `${table.name.toLowerCase()}/:id`,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
_instanceName: `${table.name} - List`,
|
_instanceName: `${table.name} - List`,
|
||||||
|
@ -109,6 +167,6 @@ const createScreen = table => ({
|
||||||
className: "",
|
className: "",
|
||||||
onLoad: [],
|
onLoad: [],
|
||||||
},
|
},
|
||||||
route: `/${table.name.toLowerCase()}`,
|
route: rowListUrl(table),
|
||||||
name: "",
|
name: "",
|
||||||
})
|
})
|
||||||
|
|
|
@ -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(/ /g, "-"))
|
||||||
|
})
|
||||||
|
.join("/")
|
||||||
|
.toLowerCase()
|
||||||
|
}
|
|
@ -132,7 +132,6 @@
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
text-transform: capitalize;
|
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import api from "builderStore/api"
|
import api from "builderStore/api"
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
import Table from "./Table.svelte"
|
import Table from "./Table.svelte"
|
||||||
import CalculateButton from "./buttons/CalculateButton.svelte"
|
import CalculateButton from "./buttons/CalculateButton.svelte"
|
||||||
import GroupByButton from "./buttons/GroupByButton.svelte"
|
import GroupByButton from "./buttons/GroupByButton.svelte"
|
||||||
|
@ -22,6 +23,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchViewData(name, field, groupBy, calculation) {
|
async function fetchViewData(name, field, groupBy, calculation) {
|
||||||
|
const tables = $backendUiStore.tables
|
||||||
|
const allTableViews = tables.map(table => table.views)
|
||||||
|
const thisView = allTableViews.filter(
|
||||||
|
views => views != null && views[name] != null
|
||||||
|
)[0]
|
||||||
|
// don't fetch view data if the view no longer exists
|
||||||
|
if (!thisView) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const params = new URLSearchParams()
|
const params = new URLSearchParams()
|
||||||
if (calculation) {
|
if (calculation) {
|
||||||
params.set("field", field)
|
params.set("field", field)
|
||||||
|
|
|
@ -110,9 +110,6 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--spacing-xs);
|
gap: var(--spacing-xs);
|
||||||
}
|
}
|
||||||
.container span {
|
|
||||||
text-transform: capitalize;
|
|
||||||
}
|
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
padding: var(--spacing-xl) 0 0 var(--spacing-xl);
|
padding: var(--spacing-xl) 0 0 var(--spacing-xl);
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
$: tableOptions = $backendUiStore.tables.filter(
|
$: tableOptions = $backendUiStore.tables.filter(
|
||||||
table => table._id !== $backendUiStore.draftTable._id
|
table => table._id !== $backendUiStore.draftTable._id
|
||||||
)
|
)
|
||||||
$: required = !!field?.constraints?.presence
|
$: required = !!field?.constraints?.presence || primaryDisplay
|
||||||
|
|
||||||
async function saveColumn() {
|
async function saveColumn() {
|
||||||
backendUiStore.update(state => {
|
backendUiStore.update(state => {
|
||||||
|
@ -67,6 +67,14 @@
|
||||||
field.constraints.presence = req ? { allowEmpty: false } : false
|
field.constraints.presence = req ? { allowEmpty: false } : false
|
||||||
required = req
|
required = req
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onChangePrimaryDisplay(e) {
|
||||||
|
const isPrimary = e.target.checked
|
||||||
|
// primary display is always required
|
||||||
|
if (isPrimary) {
|
||||||
|
field.constraints.presence = { allowEmpty: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
|
@ -88,6 +96,7 @@
|
||||||
<Toggle
|
<Toggle
|
||||||
checked={required}
|
checked={required}
|
||||||
on:change={onChangeRequired}
|
on:change={onChangeRequired}
|
||||||
|
disabled={primaryDisplay}
|
||||||
thin
|
thin
|
||||||
text="Required" />
|
text="Required" />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -95,6 +104,7 @@
|
||||||
{#if field.type !== 'link'}
|
{#if field.type !== 'link'}
|
||||||
<Toggle
|
<Toggle
|
||||||
bind:checked={primaryDisplay}
|
bind:checked={primaryDisplay}
|
||||||
|
on:change={onChangePrimaryDisplay}
|
||||||
thin
|
thin
|
||||||
text="Use as table display column" />
|
text="Use as table display column" />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
async function deleteTable() {
|
async function deleteTable() {
|
||||||
await backendUiStore.actions.tables.delete(table)
|
await backendUiStore.actions.tables.delete(table)
|
||||||
store.deleteScreens(templateScreens)
|
store.deleteScreens(templateScreens)
|
||||||
|
await backendUiStore.actions.tables.fetch()
|
||||||
notifier.success("Table deleted")
|
notifier.success("Table deleted")
|
||||||
hideEditor()
|
hideEditor()
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,15 +27,12 @@
|
||||||
const joinPath = join("/")
|
const joinPath = join("/")
|
||||||
|
|
||||||
const normalizedName = name =>
|
const normalizedName = name =>
|
||||||
pipe(
|
pipe(name, [
|
||||||
name,
|
|
||||||
[
|
|
||||||
trimCharsStart("./"),
|
trimCharsStart("./"),
|
||||||
trimCharsStart("~/"),
|
trimCharsStart("~/"),
|
||||||
trimCharsStart("../"),
|
trimCharsStart("../"),
|
||||||
trimChars(" "),
|
trimChars(" "),
|
||||||
]
|
])
|
||||||
)
|
|
||||||
|
|
||||||
const changeScreen = screen => {
|
const changeScreen = screen => {
|
||||||
store.setCurrentScreen(screen.props._instanceName)
|
store.setCurrentScreen(screen.props._instanceName)
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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,
|
||||||
|
|
|
@ -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,7 +137,10 @@ 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: "256px", value: "256px" },
|
||||||
{ label: "Auto", value: "auto" },
|
{ label: "Auto", value: "auto" },
|
||||||
{ label: "100%", value: "100%" },
|
{ label: "100%", value: "100%" },
|
||||||
],
|
],
|
||||||
|
@ -150,6 +156,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 +175,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 +197,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 +214,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 +231,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 +248,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 +265,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%" },
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
@ -131,12 +132,6 @@ export default {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Input",
|
|
||||||
description: "These components handle user input.",
|
|
||||||
icon: "ri-edit-box-line",
|
|
||||||
commonProps: {},
|
|
||||||
children: [
|
|
||||||
{
|
{
|
||||||
_component: "@budibase/standard-components/input",
|
_component: "@budibase/standard-components/input",
|
||||||
name: "Textfield",
|
name: "Textfield",
|
||||||
|
@ -156,39 +151,6 @@ export default {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
_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",
|
_component: "@budibase/standard-components/button",
|
||||||
name: "Button",
|
name: "Button",
|
||||||
|
@ -327,6 +289,11 @@ export default {
|
||||||
key: "datasource",
|
key: "datasource",
|
||||||
control: TableViewSelect,
|
control: TableViewSelect,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "Detail URL",
|
||||||
|
key: "detailUrl",
|
||||||
|
control: DetailScreenSelect,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: "Editable",
|
label: "Editable",
|
||||||
key: "editable",
|
key: "editable",
|
||||||
|
@ -578,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",
|
name: "Form",
|
||||||
description: "A component that generates a form from your data.",
|
description: "A component that generates a form from your data.",
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TemplateList onSelect={selectTemplate} />
|
<!-- <TemplateList onSelect={selectTemplate} /> -->
|
||||||
|
|
||||||
<AppList />
|
<AppList />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "budibase",
|
"name": "budibase",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"description": "Budibase CLI",
|
"description": "Budibase CLI",
|
||||||
"repository": "https://github.com/Budibase/Budibase",
|
"repository": "https://github.com/Budibase/Budibase",
|
||||||
"homepage": "https://www.budibase.com",
|
"homepage": "https://www.budibase.com",
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/server": "^0.2.1",
|
"@budibase/server": "^0.2.2",
|
||||||
"@inquirer/password": "^0.0.6-alpha.0",
|
"@inquirer/password": "^0.0.6-alpha.0",
|
||||||
"chalk": "^2.4.2",
|
"chalk": "^2.4.2",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/client",
|
"name": "@budibase/client",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"main": "dist/budibase-client.js",
|
"main": "dist/budibase-client.js",
|
||||||
"module": "dist/budibase-client.esm.mjs",
|
"module": "dist/budibase-client.esm.mjs",
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,27 +3,48 @@ 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 makeRootedPath = url => {
|
function sanitize(url) {
|
||||||
const hostname = window.location && window.location.hostname
|
if (!url) return url
|
||||||
if (hostname) {
|
return url
|
||||||
if (
|
.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 (
|
||||||
hostname === "localhost" ||
|
hostname === "localhost" ||
|
||||||
hostname === "127.0.0.1" ||
|
hostname === "127.0.0.1" ||
|
||||||
hostname.startsWith("192.168")
|
hostname.startsWith("192.168")
|
||||||
) {
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const makeRootedPath = url => {
|
||||||
|
if (isRunningLocally()) {
|
||||||
const appId = parseAppIdFromCookie(window.document.cookie)
|
const appId = parseAppIdFromCookie(window.document.cookie)
|
||||||
if (url) {
|
if (url) {
|
||||||
if (url.startsWith(appId)) return url
|
url = sanitize(url)
|
||||||
return `/${appId}${url.startsWith("/") ? "" : "/"}${url}`
|
if (!url.startsWith("/")) {
|
||||||
}
|
url = `/${url}`
|
||||||
return appId
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (url.startsWith(`/${appId}`)) {
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
return `/${appId}${url}`
|
||||||
|
}
|
||||||
|
return `/${appId}`
|
||||||
|
}
|
||||||
|
return sanitize(url)
|
||||||
|
}
|
||||||
|
|
||||||
const routes = screens.map(s => makeRootedPath(s.route))
|
const routes = screens.map(s => makeRootedPath(s.route))
|
||||||
let fallback = routes.findIndex(([p]) => p === "*")
|
let fallback = routes.findIndex(([p]) => p === makeRootedPath("*"))
|
||||||
if (fallback < 0) fallback = 0
|
if (fallback < 0) fallback = 0
|
||||||
|
|
||||||
let current
|
let current
|
||||||
|
@ -32,7 +53,7 @@ export const screenRouter = ({ screens, onScreenSelected, window }) => {
|
||||||
const _url = makeRootedPath(url.state || url)
|
const _url = makeRootedPath(url.state || url)
|
||||||
current = routes.findIndex(
|
current = routes.findIndex(
|
||||||
p =>
|
p =>
|
||||||
p !== "*" &&
|
p !== makeRootedPath("*") &&
|
||||||
new RegExp("^" + p.toLowerCase() + "$").test(_url.toLowerCase())
|
new RegExp("^" + p.toLowerCase() + "$").test(_url.toLowerCase())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -40,6 +61,8 @@ export const screenRouter = ({ screens, onScreenSelected, window }) => {
|
||||||
|
|
||||||
if (current === -1) {
|
if (current === -1) {
|
||||||
routes.forEach((p, i) => {
|
routes.forEach((p, i) => {
|
||||||
|
// ignore home - which matched everything
|
||||||
|
if (p === makeRootedPath("*")) return
|
||||||
const pm = regexparam(p)
|
const pm = regexparam(p)
|
||||||
const matches = pm.pattern.exec(_url)
|
const matches = pm.pattern.exec(_url)
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/server",
|
"name": "@budibase/server",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"description": "Budibase Web Server",
|
"description": "Budibase Web Server",
|
||||||
"main": "src/electron.js",
|
"main": "src/electron.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
"author": "Michael Shanks",
|
"author": "Michael Shanks",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/client": "^0.2.1",
|
"@budibase/client": "^0.2.2",
|
||||||
"@koa/router": "^8.0.0",
|
"@koa/router": "^8.0.0",
|
||||||
"@sendgrid/mail": "^7.1.1",
|
"@sendgrid/mail": "^7.1.1",
|
||||||
"@sentry/node": "^5.19.2",
|
"@sentry/node": "^5.19.2",
|
||||||
|
|
|
@ -41,6 +41,18 @@ exports.save = async function(ctx) {
|
||||||
oldTable = await db.get(ctx.request.body._id)
|
oldTable = await db.get(ctx.request.body._id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure that types don't change of a column, have to remove
|
||||||
|
// the column if you want to change the type
|
||||||
|
if (oldTable && oldTable.schema) {
|
||||||
|
for (let propKey of Object.keys(tableToSave.schema)) {
|
||||||
|
let column = tableToSave.schema[propKey]
|
||||||
|
let oldColumn = oldTable.schema[propKey]
|
||||||
|
if (oldColumn && oldColumn.type !== column.type) {
|
||||||
|
ctx.throw(400, "Cannot change the type of a column")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Don't rename if the name is the same
|
// Don't rename if the name is the same
|
||||||
let { _rename } = tableToSave
|
let { _rename } = tableToSave
|
||||||
if (_rename && _rename.old === _rename.updated) {
|
if (_rename && _rename.old === _rename.updated) {
|
||||||
|
@ -50,9 +62,9 @@ exports.save = async function(ctx) {
|
||||||
|
|
||||||
// rename row fields when table column is renamed
|
// rename row fields when table column is renamed
|
||||||
if (_rename && tableToSave.schema[_rename.updated].type === "link") {
|
if (_rename && tableToSave.schema[_rename.updated].type === "link") {
|
||||||
throw "Cannot rename a linked field."
|
ctx.throw(400, "Cannot rename a linked column.")
|
||||||
} else if (_rename && tableToSave.primaryDisplay === _rename.old) {
|
} else if (_rename && tableToSave.primaryDisplay === _rename.old) {
|
||||||
throw "Cannot rename the display column."
|
ctx.throw(400, "Cannot rename the display column.")
|
||||||
} else if (_rename) {
|
} else if (_rename) {
|
||||||
const rows = await db.allDocs(
|
const rows = await db.allDocs(
|
||||||
getRowParams(tableToSave._id, null, {
|
getRowParams(tableToSave._id, null, {
|
||||||
|
|
|
@ -51,6 +51,7 @@ router
|
||||||
process.env.NODE_ENV !== "cypress"
|
process.env.NODE_ENV !== "cypress"
|
||||||
await next()
|
await next()
|
||||||
})
|
})
|
||||||
|
.use("/health", ctx => (ctx.status = 200))
|
||||||
.use(authenticated)
|
.use(authenticated)
|
||||||
|
|
||||||
// error handling middleware
|
// error handling middleware
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const CouchDB = require("../index")
|
const CouchDB = require("../index")
|
||||||
const { IncludeDocs, getLinkDocuments } = require("./linkUtils")
|
const { IncludeDocs, getLinkDocuments } = require("./linkUtils")
|
||||||
const { generateLinkID } = require("../utils")
|
const { generateLinkID } = require("../utils")
|
||||||
|
const Sentry = require("@sentry/node")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new link document structure which can be put to the database. It is important to
|
* Creates a new link document structure which can be put to the database. It is important to
|
||||||
|
@ -289,11 +290,15 @@ class LinkController {
|
||||||
const schema = table.schema
|
const schema = table.schema
|
||||||
for (let fieldName of Object.keys(schema)) {
|
for (let fieldName of Object.keys(schema)) {
|
||||||
const field = schema[fieldName]
|
const field = schema[fieldName]
|
||||||
|
try {
|
||||||
if (field.type === "link") {
|
if (field.type === "link") {
|
||||||
const linkedTable = await this._db.get(field.tableId)
|
const linkedTable = await this._db.get(field.tableId)
|
||||||
delete linkedTable.schema[table.name]
|
delete linkedTable.schema[field.fieldName]
|
||||||
await this._db.put(linkedTable)
|
await this._db.put(linkedTable)
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
Sentry.captureException(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// need to get the full link docs to delete them
|
// need to get the full link docs to delete them
|
||||||
const linkDocs = await this.getTableLinkDocs()
|
const linkDocs = await this.getTableLinkDocs()
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
const LinkController = require("./LinkController")
|
const LinkController = require("./LinkController")
|
||||||
const { IncludeDocs, getLinkDocuments, createLinkView } = require("./linkUtils")
|
const {
|
||||||
|
IncludeDocs,
|
||||||
|
getLinkDocuments,
|
||||||
|
createLinkView,
|
||||||
|
getUniqueByProp,
|
||||||
|
} = require("./linkUtils")
|
||||||
const _ = require("lodash")
|
const _ = require("lodash")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,7 +115,12 @@ exports.attachLinkInfo = async (instanceId, rows) => {
|
||||||
// now iterate through the rows and all field information
|
// now iterate through the rows and all field information
|
||||||
for (let row of rows) {
|
for (let row of rows) {
|
||||||
// get all links for row, ignore fieldName for now
|
// get all links for row, ignore fieldName for now
|
||||||
const linkVals = responses.filter(el => el.thisId === row._id)
|
// have to get unique as the previous table query can
|
||||||
|
// return duplicates, could be querying for both tables in a relation
|
||||||
|
const linkVals = getUniqueByProp(
|
||||||
|
responses.filter(el => el.thisId === row._id),
|
||||||
|
"id"
|
||||||
|
)
|
||||||
for (let linkVal of linkVals) {
|
for (let linkVal of linkVals) {
|
||||||
// work out which link pertains to this row
|
// work out which link pertains to this row
|
||||||
if (!(row[linkVal.fieldName] instanceof Array)) {
|
if (!(row[linkVal.fieldName] instanceof Array)) {
|
||||||
|
|
|
@ -92,3 +92,9 @@ exports.getLinkDocuments = async function({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.getUniqueByProp = (array, prop) => {
|
||||||
|
return array.filter((obj, pos, arr) => {
|
||||||
|
return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -97,6 +97,6 @@
|
||||||
],
|
],
|
||||||
"_instanceName": "Home"
|
"_instanceName": "Home"
|
||||||
},
|
},
|
||||||
"route": "/*",
|
"route": "/",
|
||||||
"name": "d834fea2-1b3e-4320-ab34-f9009f5ecc59"
|
"name": "d834fea2-1b3e-4320-ab34-f9009f5ecc59"
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,12 +240,13 @@
|
||||||
},
|
},
|
||||||
"height": {
|
"height": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": "500"
|
"default": "540"
|
||||||
},
|
},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"default": true
|
"default": true
|
||||||
}
|
},
|
||||||
|
"detailUrl": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dataform": {
|
"dataform": {
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"dev:builder": "rollup -cw"
|
"dev:builder": "rollup -cw"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@budibase/client": "^0.2.1",
|
"@budibase/client": "^0.2.2",
|
||||||
"@rollup/plugin-commonjs": "^11.1.0",
|
"@rollup/plugin-commonjs": "^11.1.0",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"rollup": "^2.11.2",
|
"rollup": "^2.11.2",
|
||||||
|
@ -31,12 +31,12 @@
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"svelte"
|
"svelte"
|
||||||
],
|
],
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"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",
|
||||||
|
|
|
@ -18,19 +18,17 @@
|
||||||
bind:this={theButton}
|
bind:this={theButton}
|
||||||
class="default"
|
class="default"
|
||||||
disabled={disabled || false}
|
disabled={disabled || false}
|
||||||
on:click={clickHandler}>
|
on:click|once={clickHandler}>
|
||||||
{#if !_bb.props._children || _bb.props._children.length === 0}{text}{/if}
|
{#if !_bb.props._children || _bb.props._children.length === 0}{text}{/if}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<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;
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
|
|
||||||
import AgGrid from "@budibase/svelte-ag-grid"
|
import AgGrid from "@budibase/svelte-ag-grid"
|
||||||
import CreateRowButton from "./CreateRow/Button.svelte"
|
|
||||||
import {
|
import {
|
||||||
TextButton as DeleteButton,
|
TextButton as DeleteButton,
|
||||||
Icon,
|
Icon,
|
||||||
|
@ -24,7 +23,8 @@
|
||||||
export let editable
|
export let editable
|
||||||
export let theme = "alpine"
|
export let theme = "alpine"
|
||||||
export let height = 500
|
export let height = 500
|
||||||
export let pagination = true
|
export let pagination
|
||||||
|
export let detailUrl
|
||||||
|
|
||||||
// These can never change at runtime so don't need to be reactive
|
// These can never change at runtime so don't need to be reactive
|
||||||
let canEdit = editable && datasource && datasource.type !== "view"
|
let canEdit = editable && datasource && datasource.type !== "view"
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
headerCheckboxSelection: i === 0 && canEdit,
|
headerCheckboxSelection: i === 0 && canEdit,
|
||||||
checkboxSelection: i === 0 && canEdit,
|
checkboxSelection: i === 0 && canEdit,
|
||||||
valueSetter: setters.get(schema[key].type),
|
valueSetter: setters.get(schema[key].type),
|
||||||
headerName: key.charAt(0).toUpperCase() + key.slice(1),
|
headerName: key,
|
||||||
field: key,
|
field: key,
|
||||||
hide: shouldHideField(key),
|
hide: shouldHideField(key),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
|
@ -80,17 +80,33 @@
|
||||||
autoHeight: true,
|
autoHeight: true,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (detailUrl) {
|
||||||
|
columnDefs = [
|
||||||
|
...columnDefs,
|
||||||
|
{
|
||||||
|
headerName: "Detail",
|
||||||
|
field: "_id",
|
||||||
|
minWidth: 100,
|
||||||
|
width: 100,
|
||||||
|
flex: 0,
|
||||||
|
editable: false,
|
||||||
|
sortable: false,
|
||||||
|
cellRenderer: getRenderer({
|
||||||
|
type: "_id",
|
||||||
|
options: { detailUrl },
|
||||||
|
}),
|
||||||
|
autoHeight: true,
|
||||||
|
pinned: "left",
|
||||||
|
filter: false,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
dataLoaded = true
|
dataLoaded = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const isEditable = type =>
|
|
||||||
type !== "boolean" &&
|
|
||||||
type !== "options" &&
|
|
||||||
// type !== "datetime" &&
|
|
||||||
type !== "link" &&
|
|
||||||
type !== "attachment"
|
|
||||||
|
|
||||||
const shouldHideField = name => {
|
const shouldHideField = name => {
|
||||||
if (name.startsWith("_")) return true
|
if (name.startsWith("_")) return true
|
||||||
// always 'row'
|
// always 'row'
|
||||||
|
@ -101,10 +117,6 @@
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleNewRow = async () => {
|
|
||||||
data = await fetchData(datasource)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleUpdate = ({ detail }) => {
|
const handleUpdate = ({ detail }) => {
|
||||||
data[detail.row] = detail.data
|
data[detail.row] = detail.data
|
||||||
updateRow(detail.data)
|
updateRow(detail.data)
|
||||||
|
@ -134,11 +146,10 @@
|
||||||
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">
|
||||||
<CreateRowButton {_bb} {table} on:newRow={handleNewRow} />
|
|
||||||
{#if selectedRows.length > 0}
|
{#if selectedRows.length > 0}
|
||||||
<DeleteButton text small on:click={modal.show()}>
|
<DeleteButton text small on:click={modal.show()}>
|
||||||
<Icon name="addrow" />
|
<Icon name="addrow" />
|
||||||
|
@ -168,7 +179,12 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.container :global(.ag-pinned-left-header .ag-header-cell-label) {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
|
min-height: 15px;
|
||||||
margin-bottom: var(--spacing-s);
|
margin-bottom: var(--spacing-s);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: var(--spacing-s);
|
grid-gap: var(--spacing-s);
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script>
|
||||||
|
import { Button } from "@budibase/bbui"
|
||||||
|
export let url
|
||||||
|
let link
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<a href={url} bind:this={link} />
|
||||||
|
<Button small translucent on:click={() => link.click()}>View</Button>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -2,6 +2,7 @@
|
||||||
// https://www.ag-grid.com/javascript-grid-cell-rendering-components/
|
// https://www.ag-grid.com/javascript-grid-cell-rendering-components/
|
||||||
|
|
||||||
import AttachmentCell from "./AttachmentCell/Button.svelte"
|
import AttachmentCell from "./AttachmentCell/Button.svelte"
|
||||||
|
import ViewDetails from "./ViewDetails/Cell.svelte"
|
||||||
import Select from "./Select/Wrapper.svelte"
|
import Select from "./Select/Wrapper.svelte"
|
||||||
import DatePicker from "./DateTime/Wrapper.svelte"
|
import DatePicker from "./DateTime/Wrapper.svelte"
|
||||||
import RelationshipDisplay from "./Relationship/RelationshipDisplay.svelte"
|
import RelationshipDisplay from "./Relationship/RelationshipDisplay.svelte"
|
||||||
|
@ -11,18 +12,23 @@ const renderers = new Map([
|
||||||
["attachment", attachmentRenderer],
|
["attachment", attachmentRenderer],
|
||||||
["options", optionsRenderer],
|
["options", optionsRenderer],
|
||||||
["link", linkedRowRenderer],
|
["link", linkedRowRenderer],
|
||||||
|
["_id", viewDetailsRenderer],
|
||||||
])
|
])
|
||||||
|
|
||||||
export function getRenderer({ type, constraints }, editable) {
|
export function getRenderer(schema, editable) {
|
||||||
if (renderers.get(type)) {
|
if (renderers.get(schema.type)) {
|
||||||
return renderers.get(type)(constraints, 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(constraints, editable) {
|
function booleanRenderer(options, constraints, editable) {
|
||||||
return params => {
|
return params => {
|
||||||
const toggle = e => {
|
const toggle = e => {
|
||||||
params.value = !params.value
|
params.value = !params.value
|
||||||
|
@ -44,7 +50,7 @@ function booleanRenderer(constraints, editable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* eslint-disable no-unused-vars */
|
/* eslint-disable no-unused-vars */
|
||||||
function attachmentRenderer(constraints, editable) {
|
function attachmentRenderer(options, constraints, editable) {
|
||||||
return params => {
|
return params => {
|
||||||
const container = document.createElement("div")
|
const container = document.createElement("div")
|
||||||
|
|
||||||
|
@ -66,7 +72,7 @@ function attachmentRenderer(constraints, editable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* eslint-disable no-unused-vars */
|
/* eslint-disable no-unused-vars */
|
||||||
function dateRenderer(constraints, 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 => {
|
||||||
|
@ -74,8 +80,7 @@ function dateRenderer(constraints, 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,
|
||||||
|
@ -86,7 +91,7 @@ function dateRenderer(constraints, 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")
|
||||||
|
@ -101,7 +106,7 @@ function optionsRenderer({ inclusion }, editable) {
|
||||||
target: container,
|
target: container,
|
||||||
props: {
|
props: {
|
||||||
value: params.value,
|
value: params.value,
|
||||||
options: inclusion,
|
options: constraints.inclusion,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -111,7 +116,7 @@ function optionsRenderer({ inclusion }, editable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* eslint-disable no-unused-vars */
|
/* eslint-disable no-unused-vars */
|
||||||
function linkedRowRenderer(constraints, 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"
|
||||||
|
@ -129,3 +134,25 @@ function linkedRowRenderer(constraints, editable) {
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
function viewDetailsRenderer(options, constraints, editable) {
|
||||||
|
return params => {
|
||||||
|
let container = document.createElement("div")
|
||||||
|
container.style.display = "grid"
|
||||||
|
container.style.alignItems = "center"
|
||||||
|
container.style.height = "100%"
|
||||||
|
|
||||||
|
let url = "/"
|
||||||
|
if (options.detailUrl) {
|
||||||
|
url = options.detailUrl.replace(":id", params.data._id)
|
||||||
|
}
|
||||||
|
|
||||||
|
new ViewDetails({
|
||||||
|
target: container,
|
||||||
|
props: { url },
|
||||||
|
})
|
||||||
|
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -46,13 +46,18 @@ export default async function fetchData(datasource, store) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchViewData() {
|
async function fetchViewData() {
|
||||||
const { field, groupBy } = datasource
|
const { field, groupBy, calculation } = datasource
|
||||||
const params = new URLSearchParams()
|
const params = new URLSearchParams()
|
||||||
|
|
||||||
if (field) {
|
if (calculation) {
|
||||||
params.set("field", field)
|
params.set("field", field)
|
||||||
params.set("stats", true)
|
params.set("calculation", calculation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (groupBy) {
|
||||||
|
params.set("group", groupBy)
|
||||||
|
}
|
||||||
|
|
||||||
if (groupBy) params.set("group", groupBy)
|
if (groupBy) params.set("group", groupBy)
|
||||||
|
|
||||||
let QUERY_VIEW_URL = field
|
let QUERY_VIEW_URL = field
|
||||||
|
|
|
@ -4,11 +4,8 @@ export { default as container } from "./Container.svelte"
|
||||||
export { default as text } from "./Text.svelte"
|
export { default as text } from "./Text.svelte"
|
||||||
export { default as heading } from "./Heading.svelte"
|
export { default as heading } from "./Heading.svelte"
|
||||||
export { default as input } from "./Input.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 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 button } from "./Button.svelte"
|
||||||
export { default as login } from "./Login.svelte"
|
export { default as login } from "./Login.svelte"
|
||||||
export { default as saveRowButton } from "./Templates/saveRowButton"
|
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 image } from "./Image.svelte"
|
||||||
export { default as Navigation } from "./Navigation.svelte"
|
export { default as Navigation } from "./Navigation.svelte"
|
||||||
export { default as datagrid } from "./DataGrid/Component.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 dataform } from "./DataForm.svelte"
|
||||||
export { default as dataformwide } from "./DataFormWide.svelte"
|
export { default as dataformwide } from "./DataFormWide.svelte"
|
||||||
export { default as datachart } from "./DataChart.svelte"
|
export { default as datachart } from "./DataChart.svelte"
|
||||||
|
|
Loading…
Reference in New Issue