layouts and screens switcher, merge with component sdk

This commit is contained in:
Martin McKeaveney 2020-12-01 16:22:06 +00:00
commit 33c40063af
44 changed files with 504 additions and 600 deletions

View File

@ -81,8 +81,8 @@
"shortid": "^2.2.15",
"svelte-loading-spinners": "^0.1.1",
"svelte-portal": "^0.1.0",
"yup": "^0.29.2",
"uuid": "^8.3.1"
"uuid": "^8.3.1",
"yup": "^0.29.2"
},
"devDependencies": {
"@babel/core": "^7.5.5",
@ -107,6 +107,7 @@
"rollup-plugin-alias": "^1.5.2",
"rollup-plugin-copy": "^3.0.0",
"rollup-plugin-css-only": "^2.1.0",
"rollup-plugin-html": "^0.2.1",
"rollup-plugin-livereload": "^1.0.0",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-globals": "^1.4.0",

View File

@ -11,6 +11,7 @@ import copy from "rollup-plugin-copy"
import css from "rollup-plugin-css-only"
import replace from "rollup-plugin-replace"
import json from "@rollup/plugin-json"
import html from "rollup-plugin-html"
import path from "path"
@ -147,5 +148,6 @@ export default {
// instead of npm run dev), minify
production && terser(),
json(),
html(),
],
}

View File

@ -11,11 +11,15 @@ export const automationStore = getAutomationStore()
export const themeStore = getThemeStore()
export const currentAsset = derived(store, $store => {
const layout = $store.layouts ? $store.layouts.find(layout => layout._id === $store.currentAssetId) : null
const layout = $store.layouts
? $store.layouts.find(layout => layout._id === $store.currentAssetId)
: null
if (layout) {
return layout
}
const screen = $store.screens ? $store.screens.find(screen => screen._id === $store.currentAssetId) : null
const screen = $store.screens
? $store.screens.find(screen => screen._id === $store.currentAssetId)
: null
if (screen) {
return screen
}
@ -32,7 +36,9 @@ export const allScreens = derived(store, $store => {
})
export const mainLayout = derived(store, $store => {
return $store.layouts?.find(layout => layout.props?._id === "private-master-layout")
return $store.layouts?.find(
layout => layout.props?._id === "private-master-layout"
)
})
export const initialise = async () => {

View File

@ -5,10 +5,15 @@ import {
getBuiltin,
makePropsSafe,
} from "components/userInterface/assetParsing/createProps"
import { allScreens, backendUiStore, currentAsset, mainLayout } from "builderStore"
import {
allScreens,
backendUiStore,
currentAsset,
mainLayout,
} from "builderStore"
import { fetchComponentLibDefinitions } from "../loadComponentLibraries"
import api from "../api"
import { DEFAULT_LAYOUTS } from "../../constants"
import { DEFAULT_LAYOUTS, FrontendTypes } from "../../constants"
import getNewComponentName from "../getNewComponentName"
import analytics from "analytics"
import {
@ -44,7 +49,8 @@ export const getFrontendStore = () => {
store.actions = {
initialise: async pkg => {
const layouts = pkg.layouts, screens = pkg.screens, application = pkg.application
const { layouts, screens, application } = pkg
store.update(state => {
state.appId = application._id
return state
@ -97,7 +103,7 @@ export const getFrontendStore = () => {
store.update(state => {
const screen = get(allScreens).find(screen => screen._id === screenId)
state.currentPreviewItem = screen
state.currentFrontEndType = "screen"
state.currentFrontEndType = FrontendTypes.SCREEN
state.currentAssetId = screenId
state.currentView = "detail"
@ -117,10 +123,12 @@ export const getFrontendStore = () => {
store.update(state => {
state.currentPreviewItem = screen
state.currentComponentInfo = screen.props
state.currentFrontEndType = "screen"
state.currentFrontEndType = FrontendTypes.SCREEN
if (state.currentPreviewItem) {
promises.push(store.actions.screens.regenerateCss(state.currentPreviewItem))
promises.push(
store.actions.screens.regenerateCss(state.currentPreviewItem)
)
}
promises.push(store.actions.screens.save(screen))
@ -137,7 +145,9 @@ export const getFrontendStore = () => {
screen._id = json.id
store.update(state => {
const foundScreen = state.screens.findIndex(el => el._id === screen._id)
const foundScreen = state.screens.findIndex(
el => el._id === screen._id
)
if (foundScreen !== -1) {
state.screens.splice(foundScreen, 1)
}
@ -171,10 +181,14 @@ export const getFrontendStore = () => {
const screenDeletePromises = []
store.update(state => {
for (let screenToDelete of screensToDelete) {
state.screens = state.screens.filter(screen => screen._id !== screenToDelete._id)
screenDeletePromises.push(api.delete(
state.screens = state.screens.filter(
screen => screen._id !== screenToDelete._id
)
screenDeletePromises.push(
api.delete(
`/api/screens/${screenToDelete._id}/${screenToDelete._rev}`
))
)
)
}
return state
})
@ -184,7 +198,7 @@ export const getFrontendStore = () => {
preview: {
saveSelected: async () => {
const state = get(store)
if (state.currentFrontEndType !== "layout") {
if (state.currentFrontEndType !== FrontendTypes.LAYOUT) {
await store.actions.screens.save(currentAsset)
}
await store.actions.layouts.save(currentAsset)
@ -195,7 +209,7 @@ export const getFrontendStore = () => {
store.update(state => {
const layout = store.actions.layouts.find(layoutName)
state.currentFrontEndType = "layout"
state.currentFrontEndType = FrontendTypes.LAYOUT
state.currentView = "detail"
state.currentAssetId = layout._id
@ -209,7 +223,7 @@ export const getFrontendStore = () => {
)
state.currentComponentInfo = safeProps
layout.props = safeProps
state.currentPreviewItem = store.actions.layouts.find(layoutName)
state.currentPreviewItem = layout
return state
})
@ -231,7 +245,9 @@ export const getFrontendStore = () => {
if (!json.ok) throw new Error("Error updating layout")
store.update(state => {
const layoutToUpdate = state.layouts.find(stateLayouts => stateLayouts._id === layout._id)
const layoutToUpdate = state.layouts.find(
stateLayouts => stateLayouts._id === layout._id
)
if (layoutToUpdate) {
layoutToUpdate._rev = json.rev
}
@ -243,7 +259,12 @@ export const getFrontendStore = () => {
return get(mainLayout)
}
const storeContents = get(store)
return storeContents.layouts.find(layout => layout.name.toLowerCase() === layoutName.toLowerCase())
// TODO: only use ID
return storeContents.layouts.find(
layout =>
layout.name.toLowerCase() === layoutName.toLowerCase() ||
layout._id === layoutName
)
},
},
components: {

View File

@ -15,8 +15,6 @@ export class Component extends BaseStructure {
selected: {},
},
_code: "",
className: "",
onLoad: [],
type: "",
_instanceName: "",
_children: [],

View File

@ -4,12 +4,13 @@ import getNewComponentName from "./getNewComponentName"
export const getParent = (rootProps, child) => {
let parent
walkProps(rootProps, (p, breakWalk) => {
walkProps(rootProps, (props, breakWalk) => {
if (
p._children &&
(p._children.includes(child) || p._children.some(c => c._id === child))
props._children &&
(props._children.includes(child) ||
props._children.some(c => c._id === child))
) {
parent = p
parent = props
breakWalk()
}
})

View File

@ -28,21 +28,36 @@
selectedComponentId,
}
// Saving pages and screens to the DB causes them to have _revs.
// These revisions change every time a save happens and causes
// these reactive statements to fire, even though the actual
// definition hasn't changed.
// By deleting all _rev properties we can avoid this and increase
// performance.
$: json = JSON.stringify(previewData)
$: strippedJson = json.replaceAll(/"_rev":\s*"[^"]+"/g, `"_rev":""`)
// Update the iframe with the builder info to render the correct preview
const refreshContent = () => {
const refreshContent = message => {
if (iframe) {
iframe.contentWindow.postMessage(JSON.stringify(previewData))
iframe.contentWindow.postMessage(message)
}
}
// Refresh the preview when required
$: refreshContent(previewData)
$: refreshContent(strippedJson)
// Initialise the app when mounted
onMount(() => {
iframe.contentWindow.addEventListener("bb-ready", refreshContent, {
iframe.contentWindow.addEventListener(
"bb-ready",
() => {
refreshContent(strippedJson)
},
{
once: true,
})
}
)
})
</script>

View File

@ -0,0 +1,65 @@
<html>
<head>
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono">
<style>
body, html {
height: 100% !important;
font-family: Inter !important;
margin: 0px !important;
}
*, *:before, *:after {
box-sizing: border-box;
}
</style>
<script src='/assets/budibase-client.js'></script>
<script>
function receiveMessage(event) {
if (!event.data) {
return
}
// Extract data from message
const { selectedComponentId, layout, screen } = JSON.parse(event.data)
// Update selected component style
if (selectedComponentStyle) {
document.head.removeChild(selectedComponentStyle)
}
selectedComponentStyle = document.createElement("style");
document.head.appendChild(selectedComponentStyle)
var selectedCss = '[data-bb-id="' + selectedComponentId + '"]' + '{border:2px solid #0055ff !important;}'
selectedComponentStyle.appendChild(document.createTextNode(selectedCss))
// Set some flags so the app knows we're in the builder
window["##BUDIBASE_IN_BUILDER##"] = true;
window["##BUDIBASE_PREVIEW_LAYOUT##"] = layout;
window["##BUDIBASE_PREVIEW_SCREEN##"] = screen;
window["##BUDIBASE_IN_BUILDER##"] = true
window["##BUDIBASE_SELECTED_COMPONENT_ID##"] = selectedComponentId
window["##BUDIBASE_PREVIEW_ID##"] = Math.random()
// Initialise app
if (window.loadBudibase) {
loadBudibase()
}
}
let selectedComponentStyle
// Ignore clicks
["click", "mousedown"].forEach(type => {
document.addEventListener(type, function(e) {
e.preventDefault()
e.stopPropagation()
return false
}, true)
})
window.addEventListener("message", receiveMessage)
window.dispatchEvent(new Event("bb-ready"))
</script>
</head>
<body>
</body>
</html>

View File

@ -1,62 +1 @@
export default `<html>
<head>
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono">
<style>
body, html {
height: 100% !important;
font-family: Inter !important;
margin: 0px !important;
}
*, *:before, *:after {
box-sizing: border-box;
}
</style>
<script src='/assets/budibase-client.js'></script>
<script>
function receiveMessage(event) {
if (!event.data) {
return
}
// Extract data from message
const { selectedComponentId, layout, screen } = JSON.parse(event.data)
// Update selected component style
if (selectedComponentStyle) {
document.head.removeChild(selectedComponentStyle)
}
selectedComponentStyle = document.createElement("style");
document.head.appendChild(selectedComponentStyle)
var selectedCss = '[data-bb-id="' + selectedComponentId + '"]' + '{border:2px solid #0055ff !important;}'
selectedComponentStyle.appendChild(document.createTextNode(selectedCss))
// Set some flags so the app knows we're in the builder
window["##BUDIBASE_IN_BUILDER##"] = true;
window["##BUDIBASE_PREVIEW_LAYOUT##"] = layout;
window["##BUDIBASE_PREVIEW_SCREEN##"] = screen;
// Initialise app
if (window.loadBudibase) {
loadBudibase()
}
}
let selectedComponentStyle
// Ignore clicks
["click", "mousedown"].forEach(type => {
document.addEventListener(type, function(e) {
e.preventDefault()
e.stopPropagation()
return false
}, true)
})
window.addEventListener("message", receiveMessage)
window.dispatchEvent(new Event("bb-ready"))
</script>
</head>
<body>
</body>
</html>`
export { default } from "./iframeTemplate.html"

View File

@ -23,7 +23,7 @@
const path = store.actions.components.findRoute(component)
// Go to correct URL
$goto(`./:screen/${path}`)
$goto(`./screens/:screen/${path}`)
}
const dragstart = component => e => {

View File

@ -19,7 +19,7 @@
const changeScreen = screenId => {
// select the route
store.actions.screens.select(screenId)
$goto(`./${screenId}`)
$goto(`./screens/${screenId}`)
}
</script>

View File

@ -2,10 +2,12 @@
import { goto } from "@sveltech/routify"
import { store } from "builderStore"
import PathTree from "./PathTree.svelte"
$: console.log("routes", $store.routes)
</script>
<div class="root">
{#each Object.keys($store.routes) as path}
{#each Object.keys($store.routes || {}) as path}
<PathTree {path} route={$store.routes[path]} />
{/each}
</div>

View File

@ -1,127 +0,0 @@
<script>
import { keys, map, includes, filter } from "lodash/fp"
import EventEditorModal from "./EventEditorModal.svelte"
import { Modal } from "@budibase/bbui"
export const EVENT_TYPE = "event"
export let component
let events = []
let selectedEvent = null
let modal
$: {
events = Object.keys(component)
// TODO: use real events
.filter(propName => ["onChange", "onClick", "onLoad"].includes(propName))
.map(propName => ({
name: propName,
handlers: component[propName] || [],
}))
}
const openModal = event => {
selectedEvent = event
modal.show()
}
</script>
<button class="newevent" on:click={() => openModal()}>
<i class="icon ri-add-circle-fill" />
Create New Event
</button>
<div class="root">
<form on:submit|preventDefault class="form-root">
{#each events as event, index}
{#if event.handlers.length > 0}
<div
class:selected={selectedEvent && selectedEvent.index === index}
class="handler-container budibase__nav-item"
on:click={() => openModal({ ...event, index })}>
<span class="event-name">{event.name}</span>
<span class="edit-text">EDIT</span>
</div>
{/if}
{/each}
</form>
</div>
<Modal bind:this={modal} width="600px">
<EventEditorModal eventOptions={events} event={selectedEvent} />
</Modal>
<style>
.root {
font-size: 10pt;
width: 100%;
}
.newevent {
cursor: pointer;
border: 1px solid var(--grey-4);
border-radius: 3px;
width: 100%;
padding: 8px 16px;
margin: 0px 0px 12px 0px;
display: flex;
justify-content: center;
align-items: center;
background: var(--background);
color: var(--ink);
font-size: 14px;
font-weight: 500;
transition: all 2ms;
}
.newevent:hover {
background: var(--grey-1);
}
.icon {
color: var(--ink);
font-size: 16px;
margin-right: 4px;
}
.form-root {
display: flex;
flex-wrap: wrap;
}
header {
display: flex;
align-items: center;
justify-content: space-between;
}
.handler-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
border: 2px solid var(--grey-1);
height: 80px;
width: 100%;
}
.event-name {
margin-top: 5px;
font-weight: bold;
font-size: 16px;
color: rgba(22, 48, 87, 0.6);
align-self: end;
}
.edit-text {
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
align-self: end;
justify-self: end;
font-size: 10px;
color: rgba(35, 65, 105, 0.4);
}
.selected {
color: var(--blue);
background: var(--grey-1) !important;
}
</style>

View File

@ -1,53 +0,0 @@
<script>
import { Input, DataList, Select } from "@budibase/bbui"
import { automationStore, allScreens } from "builderStore"
export let parameter
let isOpen = false
const capitalize = s => {
if (typeof s !== "string") return ""
return s.charAt(0).toUpperCase() + s.slice(1)
}
</script>
<div class="handler-option">
{#if parameter.name === 'automation'}<span>{parameter.name}</span>{/if}
{#if parameter.name === 'automation'}
<Select on:change bind:value={parameter.value}>
<option value="" />
{#each $automationStore.automations.filter(wf => wf.live) as automation}
<option value={automation._id}>{automation.name}</option>
{/each}
</Select>
{:else if parameter.name === 'url'}
<DataList on:change bind:value={parameter.value}>
<option value="" />
{#each $allScreens as screen}
<option value={screen.routing.route}>
{screen.props._instanceName}
</option>
{/each}
</DataList>
{:else}
<Input
name={parameter.name}
label={capitalize(parameter.name)}
on:change
value={parameter.value} />
{/if}
</div>
<style>
.handler-option {
display: flex;
flex-direction: column;
}
span {
font-size: 18px;
margin-bottom: 10px;
font-weight: 500;
}
</style>

View File

@ -1,16 +1,28 @@
<script>
import { onMount } from "svelte"
import { store, currentAsset } from "builderStore"
import { FrontendTypes } from "constants"
import api from "builderStore/api"
import ComponentNavigationTree from "components/userInterface/ComponentNavigationTree/index.svelte"
import Layout from "components/userInterface/Layout.svelte"
import LayoutsList from "components/userInterface/LayoutsList.svelte"
import NewScreenModal from "components/userInterface/NewScreenModal.svelte"
import { Modal } from "@budibase/bbui"
import { Modal, Switcher } from "@budibase/bbui"
const tabs = [
{
title: "Screens",
key: "SCREENS",
},
{
title: "Layouts",
key: "LAYOUTS",
},
]
let modal
let routes = {}
let tab = "SCREENS"
onMount(() => {
store.actions.routing.fetch()
@ -18,20 +30,38 @@
</script>
<div class="title">
<h1>Screens</h1>
<i on:click={modal.show} data-cy="new-screen" class="ri-add-circle-fill" />
</div>
<LayoutsList />
{#if $store.currentFrontEndType === "layout" && $currentAsset}
<div class="nav-items-container">
<Layout layout={$currentAsset} />
<Switcher headings={tabs} bind:value={tab}>
{#if tab === 'SCREENS'}
<i
on:click={modal.show}
data-cy="new-screen"
class="ri-add-circle-fill" />
<!-- <LayoutsList /> -->
{#if $currentAsset}
<div class="nav-items-container">
<!-- <Layout layout={$currentAsset} /> -->
<ComponentNavigationTree />
</div>
<Modal bind:this={modal}>
</div>
{/if}
<Modal bind:this={modal}>
<NewScreenModal />
</Modal>
{/if}
</Modal>
{:else if tab === 'LAYOUTS'}
<Layout />
{/if}
</Switcher>
</div>
<!-- {#if $store.currentFrontEndType === FrontendTypes.LAYOUT && $currentAsset} -->
<!-- <div class="nav-items-container"> -->
<!-- <Layout layout={$currentAsset} /> -->
<!-- <ComponentNavigationTree /> -->
<!-- </div> -->
<!-- <Modal bind:this={modal}> -->
<!-- <NewScreenModal /> -->
<!-- </Modal> -->
<!-- {/if} -->
<style>
.title {

View File

@ -1,12 +1,13 @@
<script>
import { goto } from "@sveltech/routify"
import { FrontendTypes } from "constants"
import ComponentTree from "./ComponentNavigationTree/ComponentTree.svelte"
import NavItem from "components/common/NavItem.svelte"
import { last } from "lodash/fp"
import { store } from "builderStore"
import { store, currentAsset } from "builderStore"
import { writable } from "svelte/store"
export let layout
export let layout = $currentAsset
let confirmDeleteDialog
let componentToDelete = ""
@ -17,13 +18,13 @@
c && last(c.name ? c.name.split("/") : c._component.split("/"))
$: _layout = {
component: layout,
component: $currentAsset,
title: lastPartOfName(layout),
}
const setCurrentScreenToLayout = () => {
store.actions.selectAssetType("layout")
$goto("./layout")
store.actions.selectAssetType(FrontendTypes.LAYOUT)
$goto("./layouts")
}
</script>

View File

@ -1,3 +0,0 @@
<script>
import ComponentsHierarchyChildren from "./ComponentsHierarchyChildren.svelte"
</script>

View File

@ -13,8 +13,10 @@
},
]
if (!$store.currentAssetId)
store.actions.layouts.select($params.layout ? $params.layout : "main")
if (!$store.currentAssetId) {
// refactor so the right layout is chosen
store.actions.layouts.select($params.layout || "main")
}
const changeLayout = id => {
store.actions.layouts.select(id)
@ -24,7 +26,9 @@
<div class="root">
{#each layouts as { title, id }}
<button class:active={id === $params.layout} on:click={() => changeLayout(id)}>
<button
class:active={id === $params.layout}
on:click={() => changeLayout(id)}>
{title}
</button>
{/each}

View File

@ -2,6 +2,13 @@ export const TableNames = {
USERS: "ta_users",
}
export const FrontendTypes = {
PAGE: "page",
SCREEN: "screen",
LAYOUT: "layout",
NONE: "none",
}
// fields on the user table that cannot be edited
export const UNEDITABLE_USER_FIELDS = ["username", "password", "accessLevelId"]

View File

@ -1,69 +0,0 @@
<script>
import { params, leftover, goto } from "@sveltech/routify"
import { store, allScreens } from "builderStore"
// Get any leftover params not caught by Routifys params store.
const componentIds = $leftover.split("/").filter(id => id !== "")
// It's a screen, set it to that screen
if ($params.screen !== "layout") {
const currentScreenName = decodeURI($params.screen)
const validScreen =
$allScreens.findIndex(screen => screen._id === currentScreenName) !== -1
if (!validScreen) {
// Go to main layout if URL set to invalid screen
store.actions.layouts.select("main")
$goto("../../main")
} else {
// Otherwise proceed to set screen
store.actions.screens.select(currentScreenName)
// There are leftover stuff, like IDs, so navigate the components and find the ID and select it.
if ($leftover) {
// Get the correct screen children.
const screenChildren = allScreens.find(
screen =>
screen._id === $params.screen ||
screen._id === decodeURIComponent($params.screen)
).props._children
findComponent(componentIds, screenChildren)
}
}
} else {
// It's a layout, so set the screen type to layout
store.actions.selectAssetType("layout")
// There are leftover stuff, like IDs, so navigate the components and find the ID and select it.
const layout = store.actions.layouts.find($params.layout)
if ($leftover) {
findComponent(componentIds, layout.props._children)
}
}
// Find Component with ID and continue
function findComponent(ids, children) {
// Setup stuff
let componentToSelect
let currentChildren = children
// Loop through each ID
ids.forEach(id => {
// Find ID
const component = currentChildren.find(child => child._id === id)
// If it does not exist, ignore (use last valid route)
if (!component) return
componentToSelect = component
// Update childrens array to selected components children
currentChildren = componentToSelect._children
})
// Select Component!
if (componentToSelect) store.actions.components.select(componentToSelect)
}
</script>
<slot />

View File

@ -1,6 +1,7 @@
<script>
import { store, backendUiStore } from "builderStore"
import { onMount } from "svelte"
import { FrontendTypes } from "constants"
import CurrentItemPreview from "components/userInterface/AppPreview"
import ComponentPropertiesPanel from "components/userInterface/ComponentPropertiesPanel.svelte"
import ComponentSelectionList from "components/userInterface/ComponentSelectionList.svelte"
@ -26,8 +27,6 @@
const settings = () => {
settingsView.show()
}
const lastPartOfName = c => (c ? last(c.split("/")) : "")
</script>
<!-- routify:options index=1 -->
@ -45,7 +44,7 @@
{/if}
</div>
{#if $store.currentFrontEndType === 'screen' || $store.currentFrontEndType === 'page'}
{#if $store.currentFrontEndType === FrontendTypes.SCREEN || $store.currentFrontEndType === FrontendTypes.LAYOUT}
<div class="components-pane">
<ComponentPropertiesPanel />
</div>

View File

@ -1,6 +1,6 @@
<script>
import { goto } from "@sveltech/routify"
$goto("../main")
$goto("../screens")
</script>
<!-- routify:options index=false -->

View File

@ -0,0 +1,65 @@
<script>
import { params, leftover, goto } from "@sveltech/routify"
import { store, allScreens } from "builderStore"
// Get any leftover params not caught by Routifys params store.
const componentIds = $leftover.split("/").filter(id => id !== "")
const currentScreenId = decodeURI($params.screen)
const validScreen = $allScreens.some(screen => screen._id === currentScreenId)
console.log({
validScreen,
currentScreenId,
componentIds
})
if (!validScreen) {
// Go to main layout if URL set to invalid screen
console.error("Invalid screen", $params.screen)
const firstScreenId = $allScreens[0]?._id
store.actions.screens.select(firstScreenId)
$goto(`./${firstScreenId}`)
} else {
// Otherwise proceed to set screen
store.actions.screens.select(currentScreenId)
// There are leftover stuff, like IDs, so navigate the components and find the ID and select it.
if ($leftover) {
console.log("leftover", $params.screen)
// Get the correct screen children.
const screenChildren = allScreens.find(
screen =>
screen._id === $params.screen ||
screen._id === decodeURIComponent($params.screen)
).props._children
findComponent(componentIds, screenChildren)
}
}
// Find Component with ID and continue
function findComponent(ids, children) {
// Setup stuff
let componentToSelect
let currentChildren = children
// Loop through each ID
ids.forEach(id => {
// Find ID
const component = currentChildren.find(child => child._id === id)
// If it does not exist, ignore (use last valid route)
if (!component) return
componentToSelect = component
// Update childrens array to selected components children
currentChildren = componentToSelect._children
})
// Select Component!
if (componentToSelect) store.actions.components.select(componentToSelect)
}
</script>
<slot />

View File

@ -0,0 +1,4 @@
<script>
import { goto } from "@sveltech/routify"
$goto("../screen")
</script>

View File

@ -11,7 +11,7 @@ describe("fetch bindable properties", () => {
)
expect(componentBinding).toBeDefined()
expect(componentBinding.type).toBe("instance")
expect(componentBinding.runtimeBinding).toBe("search-input-id.value")
expect(componentBinding.runtimeBinding).toBe("search-input-id")
})
it("should not return bindable components when not in their context", () => {
@ -37,20 +37,22 @@ describe("fetch bindable properties", () => {
expect(contextBindings.length).toBe(4)
const namebinding = contextBindings.find(
b => b.runtimeBinding === "data.name"
b => b.runtimeBinding === "list-id.name"
)
expect(namebinding).toBeDefined()
expect(namebinding.readableBinding).toBe("list-name.Test Table.name")
const descriptionbinding = contextBindings.find(
b => b.runtimeBinding === "data.description"
b => b.runtimeBinding === "list-id.description"
)
expect(descriptionbinding).toBeDefined()
expect(descriptionbinding.readableBinding).toBe(
"list-name.Test Table.description"
)
const idbinding = contextBindings.find(b => b.runtimeBinding === "data._id")
const idbinding = contextBindings.find(
b => b.runtimeBinding === "list-id._id"
)
expect(idbinding).toBeDefined()
expect(idbinding.readableBinding).toBe("list-name.Test Table._id")
})
@ -65,13 +67,13 @@ describe("fetch bindable properties", () => {
expect(contextBindings.length).toBe(8)
const namebinding_parent = contextBindings.find(
b => b.runtimeBinding === "parent.data.name"
b => b.runtimeBinding === "list-id.name"
)
expect(namebinding_parent).toBeDefined()
expect(namebinding_parent.readableBinding).toBe("list-name.Test Table.name")
const descriptionbinding_parent = contextBindings.find(
b => b.runtimeBinding === "parent.data.description"
b => b.runtimeBinding === "list-id.description"
)
expect(descriptionbinding_parent).toBeDefined()
expect(descriptionbinding_parent.readableBinding).toBe(
@ -79,7 +81,7 @@ describe("fetch bindable properties", () => {
)
const namebinding_own = contextBindings.find(
b => b.runtimeBinding === "data.name"
b => b.runtimeBinding === "child-list-id.name"
)
expect(namebinding_own).toBeDefined()
expect(namebinding_own.readableBinding).toBe(
@ -87,7 +89,7 @@ describe("fetch bindable properties", () => {
)
const descriptionbinding_own = contextBindings.find(
b => b.runtimeBinding === "data.description"
b => b.runtimeBinding === "child-list-id.description"
)
expect(descriptionbinding_own).toBeDefined()
expect(descriptionbinding_own.readableBinding).toBe(
@ -104,7 +106,7 @@ describe("fetch bindable properties", () => {
r => r.instance._id === "list-item-input-id" && r.type === "instance"
)
expect(componentBinding).toBeDefined()
expect(componentBinding.runtimeBinding).toBe("list-item-input-id.value")
expect(componentBinding.runtimeBinding).toBe("list-item-input-id")
})
it("should not return components from child context", () => {

View File

@ -2040,6 +2040,14 @@ callsites@^3.0.0:
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
camel-case@3.0.x:
version "3.0.0"
resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=
dependencies:
no-case "^2.2.0"
upper-case "^1.1.1"
camelcase@^5.0.0, camelcase@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
@ -2150,6 +2158,13 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
clean-css@4.2.x:
version "4.2.3"
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78"
integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==
dependencies:
source-map "~0.6.0"
cli-cursor@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
@ -2265,11 +2280,21 @@ commander@2, commander@^2.20.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commander@2.17.x:
version "2.17.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
commander@^5.0.0, commander@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==
commander@~2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
common-tags@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937"
@ -3113,6 +3138,11 @@ estraverse@^4.2.0:
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
estree-walker@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.2.1.tgz#bdafe8095383d8414d5dc2ecf4c9173b6db9412e"
integrity sha1-va/oCVOD2EFNXcLs9MkXO225QS4=
estree-walker@^0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.5.2.tgz#d3850be7529c9580d815600b53126515e146dd39"
@ -3725,6 +3755,11 @@ hash.js@^1.0.0, hash.js@^1.0.3:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
he@1.2.x:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
hmac-drbg@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@ -3758,6 +3793,19 @@ html-escaper@^2.0.0:
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
html-minifier@^3.0.2:
version "3.5.21"
resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c"
integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==
dependencies:
camel-case "3.0.x"
clean-css "4.2.x"
commander "2.17.x"
he "1.2.x"
param-case "2.1.x"
relateurl "0.2.x"
uglify-js "3.4.x"
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
@ -5027,6 +5075,11 @@ loose-envify@^1.0.0:
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
lower-case@^1.1.1:
version "1.1.4"
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
ltgt@^2.1.2:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5"
@ -5184,7 +5237,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
minimatch@^3.0.4:
minimatch@^3.0.2, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@ -5278,6 +5331,13 @@ nice-try@^1.0.4:
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
no-case@^2.2.0:
version "2.3.2"
resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
dependencies:
lower-case "^1.1.1"
node-fetch@^2.6.0:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
@ -5542,6 +5602,13 @@ p-try@^2.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
param-case@2.1.x:
version "2.1.1"
resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc=
dependencies:
no-case "^2.2.0"
parchment@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/parchment/-/parchment-1.1.4.tgz#aeded7ab938fe921d4c34bc339ce1168bc2ffde5"
@ -6023,6 +6090,11 @@ regjsparser@^0.6.4:
dependencies:
jsesc "~0.5.0"
relateurl@0.2.x:
version "0.2.7"
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
remixicon@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/remixicon/-/remixicon-2.5.0.tgz#b5e245894a1550aa23793f95daceadbf96ad1a41"
@ -6216,6 +6288,14 @@ rollup-plugin-css-only@^2.1.0:
"@rollup/pluginutils" "^3.0.0"
fs-extra "^9.0.0"
rollup-plugin-html@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/rollup-plugin-html/-/rollup-plugin-html-0.2.1.tgz#a1862eca87ae54b677689d0d4133911e8226463d"
integrity sha1-oYYuyoeuVLZ3aJ0NQTORHoImRj0=
dependencies:
html-minifier "^3.0.2"
rollup-pluginutils "^1.5.0"
rollup-plugin-livereload@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-livereload/-/rollup-plugin-livereload-1.3.0.tgz#8da90df13df6502b9d982997d6ac871092f15fdd"
@ -6284,6 +6364,14 @@ rollup-plugin-url@^2.2.2:
mkdirp "^0.5.1"
rollup-pluginutils "^2.8.2"
rollup-pluginutils@^1.5.0:
version "1.5.2"
resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz#1e156e778f94b7255bfa1b3d0178be8f5c552408"
integrity sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg=
dependencies:
estree-walker "^0.2.1"
minimatch "^3.0.2"
rollup-pluginutils@^2.3.1, rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2:
version "2.8.2"
resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e"
@ -6575,7 +6663,7 @@ source-map@^0.5.0, source-map@^0.5.6:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
@ -7056,6 +7144,14 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
uglify-js@3.4.x:
version "3.4.10"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==
dependencies:
commander "~2.19.0"
source-map "~0.6.1"
unicode-canonical-property-names-ecmascript@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
@ -7117,6 +7213,11 @@ untildify@^4.0.0:
resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
upper-case@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
uri-js@^4.2.2:
version "4.4.0"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602"

View File

@ -21,6 +21,6 @@
</script>
{#if loaded}
// TODO: need to get the active screen as well
<!-- // TODO: need to get the active screen as well -->
<Component definition={$screenStore.activeLayout.props} />
{/if}

View File

@ -4,7 +4,7 @@
import * as ComponentLibrary from "@budibase/standard-components"
import Router from "./Router.svelte"
import { enrichProps } from "../utils/componentProps"
import { bindingStore } from "../store"
import { bindingStore, builderStore } from "../store"
export let definition = {}
@ -32,12 +32,20 @@
const name = split?.[split.length - 1]
return name === "screenslot" ? Router : ComponentLibrary[name]
}
// Returns a unique key to let svelte know when to remount components.
// If a component is selected we want to remount it every time any props
// change.
const getChildKey = childId => {
const selected = childId === $builderStore.selectedComponentId
return selected ? `${childId}-${$builderStore.previewId}` : childId
}
</script>
{#if constructor}
<svelte:component this={constructor} {...enrichedProps}>
{#if children && children.length}
{#each children as child (child._id)}
{#each children as child (getChildKey(child._id))}
<svelte:self definition={child} />
{/each}
{/if}

View File

@ -4,7 +4,7 @@
import Component from "./Component.svelte"
// Keep route params up to date
export let params
export let params = {}
$: routeStore.actions.setRouteParams(params || {})
// Get the screen definition for the current route

View File

@ -9,6 +9,8 @@ const loadBudibase = () => {
inBuilder: !!window["##BUDIBASE_IN_BUILDER##"],
layout: window["##BUDIBASE_PREVIEW_LAYOUT##"],
screen: window["##BUDIBASE_PREVIEW_SCREEN##"],
selectedComponentId: window["##BUDIBASE_SELECTED_COMPONENT_ID##"],
previewId: window["##BUDIBASE_PREVIEW_ID##"],
})
// Create app if one hasn't been created yet

View File

@ -5,6 +5,8 @@ const createBuilderStore = () => {
inBuilder: false,
layout: null,
screen: null,
selectedComponentId: null,
previewId: null,
}
return writable(initialState)
}

View File

@ -27,7 +27,7 @@ const {
downloadExtractComponentLibraries,
} = require("../../utilities/createAppPackage")
const { BASE_LAYOUTS } = require("../../constants/layouts")
const { HOME_SCREEN } = require("../../constants/screens")
const { HOME_SCREEN, LOGIN_SCREEN } = require("../../constants/screens")
const { cloneDeep } = require("lodash/fp")
const { recurseMustache } = require("../../utilities/mustache")
const { generateAssetCss } = require("../../utilities/builder/generateCss")
@ -222,8 +222,16 @@ const createEmptyAppPackage = async (ctx, app) => {
const homeScreen = cloneDeep(HOME_SCREEN)
homeScreen._id = generateScreenID()
// TODO: fix - could have multiple base layouts
homeScreen.props.layoutId = screensAndLayouts[0]._id
screensAndLayouts.push(homeScreen)
const loginScreen = cloneDeep(LOGIN_SCREEN)
loginScreen._id = generateScreenID()
// TODO: fix - could have multiple base layouts
loginScreen.props.layoutId = screensAndLayouts[0]._id
screensAndLayouts.push(loginScreen)
await db.bulkDocs(screensAndLayouts)
// at the end add CSS to all the structures
for (let asset of screensAndLayouts) {

View File

@ -22,7 +22,7 @@ exports.destroy = async function(ctx) {
})
)
).rows.map(element => element.doc.props.layoutId)
if (layoutsUsedByScreens.indexOf(layoutId) !== -1) {
if (layoutsUsedByScreens.includes(layoutId)) {
ctx.throw(400, "Cannot delete a base layout")
}

View File

@ -148,76 +148,76 @@ const BASE_LAYOUTS = [
onLoad: [],
},
},
// TODO: needs removed
{
componentLibraries: ["@budibase/standard-components"],
title: "{{ name }}",
favicon: "./_shared/favicon.png",
stylesheets: [],
name: "Unauthenticated",
props: {
_id: BASE_LAYOUT_PROP_IDS.PUBLIC,
_component: "@budibase/standard-components/container",
_children: [
{
_id: "686c252d-dbf2-4e28-9078-414ba4719759",
_component: "@budibase/standard-components/login",
_styles: {
normal: {
padding: "64px",
background: "rgba(255, 255, 255, 0.4)",
"border-radius": "0.5rem",
"margin-top": "0px",
margin: "0px",
"line-height": "1",
"box-shadow":
"0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
"font-size": "16px",
"font-family": "Inter",
flex: "0 1 auto",
transform: "0",
},
hover: {},
active: {},
selected: {},
},
_code: "",
loginRedirect: "",
usernameLabel: "Username",
passwordLabel: "Password",
loginButtonLabel: "Login",
buttonClass: "",
_instanceName: "Login",
inputClass: "",
_children: [],
title: "Log in to {{ name }}",
buttonText: "Log In",
logo:
"https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg",
},
],
type: "div",
_styles: {
active: {},
hover: {},
normal: {
display: "flex",
"flex-direction": "column",
"align-items": "center",
"justify-content": "center",
"margin-right": "auto",
"margin-left": "auto",
"min-height": "100%",
"background-image":
"linear-gradient(135deg, rgba(252,215,212,1) 20%, rgba(207,218,255,1) 100%);",
},
selected: {},
},
_code: "",
className: "",
onLoad: [],
},
},
// // TODO: needs removed
// {
// componentLibraries: ["@budibase/standard-components"],
// title: "{{ name }}",
// favicon: "./_shared/favicon.png",
// stylesheets: [],
// name: "Unauthenticated",
// props: {
// _id: BASE_LAYOUT_PROP_IDS.PUBLIC,
// _component: "@budibase/standard-components/container",
// _children: [
// {
// _id: "686c252d-dbf2-4e28-9078-414ba4719759",
// _component: "@budibase/standard-components/login",
// _styles: {
// normal: {
// padding: "64px",
// background: "rgba(255, 255, 255, 0.4)",
// "border-radius": "0.5rem",
// "margin-top": "0px",
// margin: "0px",
// "line-height": "1",
// "box-shadow":
// "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
// "font-size": "16px",
// "font-family": "Inter",
// flex: "0 1 auto",
// transform: "0",
// },
// hover: {},
// active: {},
// selected: {},
// },
// _code: "",
// loginRedirect: "",
// usernameLabel: "Username",
// passwordLabel: "Password",
// loginButtonLabel: "Login",
// buttonClass: "",
// _instanceName: "Login",
// inputClass: "",
// _children: [],
// title: "Log in to {{ name }}",
// buttonText: "Log In",
// logo:
// "https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg",
// },
// ],
// type: "div",
// _styles: {
// active: {},
// hover: {},
// normal: {
// display: "flex",
// "flex-direction": "column",
// "align-items": "center",
// "justify-content": "center",
// "margin-right": "auto",
// "margin-left": "auto",
// "min-height": "100%",
// "background-image":
// "linear-gradient(135deg, rgba(252,215,212,1) 20%, rgba(207,218,255,1) 100%);",
// },
// selected: {},
// },
// _code: "",
// className: "",
// onLoad: [],
// },
// },
]
module.exports = {

View File

@ -19,8 +19,6 @@ exports.HOME_SCREEN = {
selected: {},
},
_code: "",
className: "",
onLoad: [],
type: "div",
_children: [
{
@ -35,7 +33,6 @@ exports.HOME_SCREEN = {
selected: {},
},
_code: "",
className: "",
text: "Welcome to your Budibase App 👋",
type: "h2",
_appId: "inst_cf8ace4_69efc0d72e6f443db2d4c902c14d9394",
@ -61,8 +58,6 @@ exports.HOME_SCREEN = {
selected: {},
},
_code: "",
className: "",
onLoad: [],
type: "div",
_appId: "inst_app_2cc_ca3383f896034e9295345c05f7dfca0c",
_instanceName: "Video Container",

View File

@ -0,0 +1,4 @@
class Integration {
constructor() {
}
}

View File

@ -18,13 +18,7 @@
"description": "A basic header navigation component",
"children": true,
"props": {
"logoUrl": "string",
"title": "string",
"backgroundColor": "string",
"color": "string",
"borderWidth": "string",
"borderColor": "string",
"borderStyle": "string"
"logoUrl": "string"
}
},
"button": {
@ -32,7 +26,6 @@
"description": "an html <button />",
"props": {
"text": "string",
"className": "string",
"disabled": "bool",
"onClick": "event"
},
@ -65,23 +58,8 @@
"name": "Login Control",
"description": "A control that accepts username, password an also handles password resets",
"props": {
"logo": "asset",
"loginRedirect": "string",
"logo": "string",
"title": "string",
"usernameLabel": {
"type": "string",
"default": "Username"
},
"passwordLabel": {
"type": "string",
"default": "Password"
},
"loginButtonLabel": {
"type": "string",
"default": "Login"
},
"buttonClass": "string",
"inputClass": "string",
"buttonText": "string"
},
"tags": [
@ -96,7 +74,6 @@
"bindable": "value",
"description": "An HTML input",
"props": {
"value": "string",
"type": {
"type": "options",
"options": [
@ -122,27 +99,15 @@
"week"
],
"default": "text"
},
"onChange": "event",
"className": "string"
}
},
"tags": [
"form"
]
},
"option": {
"name": "Option",
"description": "An HTML <option>, to be used with <select>",
"children": false,
"props": {
"value": "string",
"text": "string"
}
},
"text": {
"name": "Text",
"description": "stylable block of text",
"children": false,
"props": {
"text": "string",
"type": {
@ -155,16 +120,6 @@
"container"
]
},
"textfield": {
"name": "Textfield",
"description": "A component that allows the user to input text.",
"props": {
"label": "string",
"type": "string",
"value": "string",
"onchange": "event"
}
},
"richtext": {
"name": "Rich Text",
"description": "A component that allows the user to enter long form text.",
@ -186,17 +141,6 @@
}
}
},
"datatable": {
"description": "an HTML table that fetches data from a table or view and displays it.",
"data": true,
"props": {
"datasource": "tables",
"stripeColor": "string",
"borderColor": "string",
"backgroundColor": "string",
"color": "string"
}
},
"datagrid": {
"name": "Grid",
"description": "a datagrid component with functionality to add, remove and edit rows.",
@ -238,21 +182,6 @@
"data": true,
"props": {}
},
"datalist": {
"description": "A configurable data list that attaches to your backend tables.",
"data": true,
"props": {
"table": "tables",
"layout": {
"type": "options",
"default": "list",
"options": [
"list",
"grid"
]
}
}
},
"list": {
"name": "Repeater",
"description": "A configurable data list that attaches to your backend tables.",
@ -656,8 +585,7 @@
"description": "Date Picker",
"bindable": "value",
"props": {
"placeholder": "string",
"value": "string"
"placeholder": "string"
}
},
"link": {
@ -666,36 +594,13 @@
"props": {
"url": "string",
"openInNewTab": "bool",
"text": "string",
"color": "string",
"hoverColor": "string",
"underline": "bool",
"fontSize": "string",
"fontFamily": {
"type": "options",
"default": "initial",
"styleBindingProperty": "font-family",
"options": [
"initial",
"Times New Roman",
"Georgia",
"Arial",
"Arial Black",
"Comic Sans MS",
"Impact",
"Lucida Sans Unicode"
]
}
"text": "string"
}
},
"image": {
"description": "an HTML <img> tag",
"props": {
"url": "string",
"className": "string",
"description": "string",
"height": "string",
"width": "string"
"url": "string"
}
},
"container": {
@ -703,8 +608,6 @@
"children": true,
"description": "An element that contains and lays out other elements. e.g. <div>, <header> etc",
"props": {
"className": "string",
"onLoad": "event",
"type": {
"type": "options",
"options": [
@ -736,7 +639,6 @@
"name": "Heading",
"description": "An HTML H1 - H6 tag",
"props": {
"className": "string",
"text": "string",
"type": {
"type": "options",
@ -752,19 +654,5 @@
}
},
"tags": []
},
"thead": {
"name": "Table Head",
"description": "an HTML <thead> tab",
"props": {
"className": "string"
}
},
"tbody": {
"name": "Table Body",
"description": "an HTML <tbody> tab",
"props": {
"className": "string"
}
}
}

View File

@ -4,7 +4,6 @@
const { styleable } = getContext("sdk")
const component = getContext("component")
export let className = ""
export let type = "div"
</script>

View File

@ -5,7 +5,6 @@
const component = getContext("component")
export let logoUrl
export let title
const logOut = () => {
authStore.actions.logOut()
@ -18,7 +17,6 @@
{#if logoUrl}
<img class="logo" alt="logo" src={logoUrl} height="48" />
{/if}
{#if title}<span>{title}</span>{/if}
</a>
<div class="nav__controls">
<div on:click={logOut}>Log out</div>

View File

@ -1,10 +0,0 @@
<script>
import Input from "./Input.svelte"
export let _bb
export let label = ""
export let value = ""
export let onchange = () => {}
</script>
<Input type="text" {_bb} {label} {value} {onchange} />

View File

@ -5,7 +5,6 @@ export { default as container } from "./Container.svelte"
export { default as text } from "./Text.svelte"
export { default as heading } from "./Heading.svelte"
export { default as input } from "./Input.svelte"
export { default as textfield } from "./Textfield.svelte"
export { default as richtext } from "./RichText.svelte"
export { default as button } from "./Button.svelte"
export { default as login } from "./Login.svelte"