Merge branch 'master' of github.com:Budibase/budibase

This commit is contained in:
Michael Shanks 2020-02-25 17:06:00 +00:00
commit 4809105fc3
131 changed files with 33050 additions and 23491 deletions

View File

@ -5,11 +5,13 @@
"jest": true, "jest": true,
"node": true "node": true
}, },
"parser": "babel-eslint",
"parserOptions": { "parserOptions": {
"ecmaVersion": 2019, "ecmaVersion": 2019,
"sourceType": "module" "sourceType": "module",
"allowImportExportEverywhere": true
}, },
"ignorePatterns": ["node_modules", "dist", "public"], "ignorePatterns": ["node_modules", "dist", "public", "*.spec.js", "bundle.js"],
"plugins": ["prettier", "svelte3"], "plugins": ["prettier", "svelte3"],
"extends": ["eslint:recommended"], "extends": ["eslint:recommended"],
"overrides": [ "overrides": [

View File

@ -27,6 +27,7 @@ jobs:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- run: yarn - run: yarn
- run: yarn lint - run: yarn lint
- run: yarn bootstrap
- run: yarn build - run: yarn build
- run: yarn test - run: yarn test
env: env:

5
.prettierignore Normal file
View File

@ -0,0 +1,5 @@
packages/builder/src/userInterface/CurrentItemPreview.svelte
public
dist
packages/server/builder
**/*.spec.js

View File

@ -2,6 +2,7 @@
"name": "root", "name": "root",
"private": true, "private": true,
"devDependencies": { "devDependencies": {
"babel-eslint": "^10.0.3",
"eslint": "^6.8.0", "eslint": "^6.8.0",
"eslint-plugin-prettier": "^3.1.2", "eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-svelte3": "^2.7.3", "eslint-plugin-svelte3": "^2.7.3",

View File

@ -16,12 +16,7 @@ const _builderProxy = proxy("/_builder", {
pathRewrite: { "^/_builder": "" }, pathRewrite: { "^/_builder": "" },
}) })
const apiProxy = proxy( const apiProxy = proxy(["/_builder/api/**", "/_builder/**/componentlibrary"], {
[
"/_builder/api/**",
"/_builder/**/componentlibrary"
],
{
target, target,
logLevel: "debug", logLevel: "debug",
changeOrigin: true, changeOrigin: true,
@ -31,8 +26,7 @@ const apiProxy = proxy(
proxyReq.setHeader("origin", target) proxyReq.setHeader("origin", target)
} }
}, },
} })
)
const production = !process.env.ROLLUP_WATCH const production = !process.env.ROLLUP_WATCH

View File

@ -61,5 +61,4 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
</style> </style>

View File

@ -83,10 +83,9 @@
{:else}(no actions added){/if} {:else}(no actions added){/if}
<Modal <Modal
onClosed={() => isEditing = false} onClosed={() => (isEditing = false)}
bind:isOpen={isEditing} bind:isOpen={isEditing}
title={isEditing ? "Edit Access Level" : "Create Access Level"} title={isEditing ? 'Edit Access Level' : 'Create Access Level'}>
>
{#if isEditing} {#if isEditing}
<AccessLevelView <AccessLevelView
level={editingLevel} level={editingLevel}

View File

@ -16,10 +16,10 @@
let optValue = "" let optValue = ""
let clonedAction = cloneDeep(action) let clonedAction = cloneDeep(action)
let initialOptions = pipe( let initialOptions = pipe(action.initialOptions, [
action.initialOptions, keys,
[keys, map(k => ({ key: k, value: action.initialOptions[k] }))] map(k => ({ key: k, value: action.initialOptions[k] })),
) ])
let errors = [] let errors = []
const addNewOption = () => { const addNewOption = () => {
@ -44,26 +44,17 @@
const removeOption = opt => { const removeOption = opt => {
if (opt) { if (opt) {
delete clonedAction.initialOptions[opt.key] delete clonedAction.initialOptions[opt.key]
initialOptions = pipe( initialOptions = pipe(initialOptions, [filter(o => o.key !== opt.key)])
initialOptions,
[filter(o => o.key !== opt.key)]
)
} }
} }
const save = () => { const save = () => {
const newActionsList = [ const newActionsList = [
...pipe( ...pipe(allActions, [filter(a => a !== action)]),
allActions,
[filter(a => a !== action)]
),
clonedAction, clonedAction,
] ]
errors = pipe( errors = pipe(newActionsList, [validateActions, map(e => e.error)])
newActionsList,
[validateActions, map(e => e.error)]
)
if (errors.length === 0) onFinished(clonedAction) if (errors.length === 0) onFinished(clonedAction)
} }

View File

@ -19,16 +19,11 @@
let actionsArray = [] let actionsArray = []
store.subscribe(s => { store.subscribe(s => {
actionsArray = pipe( actionsArray = pipe(s.actions, [keys, map(k => s.actions[k])])
s.actions,
[keys, map(k => s.actions[k])]
)
}) })
let getDefaultOptionsHtml = defaultOptions => let getDefaultOptionsHtml = defaultOptions =>
pipe( pipe(defaultOptions, [
defaultOptions,
[
keys, keys,
map( map(
k => k =>
@ -37,8 +32,7 @@
)}` )}`
), ),
join("<br>"), join("<br>"),
] ])
)
let actionEditingFinished = action => { let actionEditingFinished = action => {
if (action) { if (action) {

View File

@ -22,10 +22,7 @@
let cancel = () => onFinished() let cancel = () => onFinished()
let save = () => { let save = () => {
const newTriggersList = [ const newTriggersList = [
...pipe( ...pipe(allTriggers, [filter(t => t !== trigger)]),
allTriggers,
[filter(t => t !== trigger)]
),
clonedTrigger, clonedTrigger,
] ]

View File

@ -1,4 +1,4 @@
/** /**
* buildStateOrigins * buildStateOrigins
* *
* Builds an object that details all the bound state in the application, and what updates it. * Builds an object that details all the bound state in the application, and what updates it.
@ -6,22 +6,23 @@
* @param screenDefinition - the screen definition metadata. * @param screenDefinition - the screen definition metadata.
* @returns {Object} an object with the client state values and how they are managed. * @returns {Object} an object with the client state values and how they are managed.
*/ */
export const buildStateOrigins = screenDefinition => { export const buildStateOrigins = screenDefinition => {
const origins = {}; const origins = {}
function traverse(propValue) { function traverse(propValue) {
for (let key in propValue) { for (let key in propValue) {
if (!Array.isArray(propValue[key])) continue; if (!Array.isArray(propValue[key])) continue
if (key === "_children") propValue[key].forEach(traverse); if (key === "_children") propValue[key].forEach(traverse)
for (let element of propValue[key]) { for (let element of propValue[key]) {
if (element["##eventHandlerType"] === "Set State") origins[element.parameters.path] = element; if (element["##eventHandlerType"] === "Set State")
origins[element.parameters.path] = element
} }
} }
} }
traverse(screenDefinition.props); traverse(screenDefinition.props)
return origins; return origins
}; }

View File

@ -1,10 +1,7 @@
import { createPackage } from "./createPackage"
import getStore from "./store" import getStore from "./store"
export const store = getStore() export const store = getStore()
export const createNewPackage = () => createPackage(packageInfo, store)
export const initialise = async () => { export const initialise = async () => {
try { try {
setupRouter(store) setupRouter(store)
@ -17,8 +14,7 @@ export const initialise = async () => {
const setupRouter = writable => { const setupRouter = writable => {
const pushState = history.pushState const pushState = history.pushState
history.pushState = () => { history.pushState = () => {
pushState.apply(history, arguments) pushState.apply(history, [writable])
//fireEvents('pushState', arguments);
writable.initialise() writable.initialise()
} }
window.addEventListener("hashchange", () => { window.addEventListener("hashchange", () => {

View File

@ -5,7 +5,6 @@ export const loadLibs = async (appName, appPackage) => {
const allLibraries = {} const allLibraries = {}
for (let lib of libsFromPages(appPackage.pages)) { for (let lib of libsFromPages(appPackage.pages)) {
const libModule = await import(makeLibraryUrl(appName, lib)) const libModule = await import(makeLibraryUrl(appName, lib))
allLibraries[lib] = libModule allLibraries[lib] = libModule
} }
@ -31,10 +30,5 @@ export const loadLib = async (appName, lib, allLibs) => {
export const makeLibraryUrl = (appName, lib) => export const makeLibraryUrl = (appName, lib) =>
`/_builder/${appName}/componentlibrary?lib=${encodeURI(lib)}` `/_builder/${appName}/componentlibrary?lib=${encodeURI(lib)}`
export const libsFromPages = pages => pipe(pages, [ export const libsFromPages = pages =>
values, pipe(pages, [values, map(p => p.componentLibraries), flatten, uniq])
map(p => p.componentLibraries),
flatten,
uniq
])

View File

@ -1,6 +1,6 @@
<script> <script>
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import Select from "../common/Select.svelte"; import Select from "../common/Select.svelte"
export let selected export let selected
export let label export let label

View File

@ -17,7 +17,9 @@
class="dropdown-content" class="dropdown-content"
style="display: {isDroppedDown ? 'inline-block' : 'none'}"> style="display: {isDroppedDown ? 'inline-block' : 'none'}">
{#each actions as action} {#each actions as action}
<div class="budibase__nav-item" on:click={action.onclick}>{action.label}</div> <div class="budibase__nav-item" on:click={action.onclick}>
{action.label}
</div>
{/each} {/each}
</div> </div>

View File

@ -1,7 +1,5 @@
<button on:click> <button on:click>
<slot> <slot>+</slot>
+
</slot>
</button> </button>
<style> <style>

View File

@ -4,7 +4,7 @@ import {
getTemplateApi, getTemplateApi,
getAuthApi, getAuthApi,
} from "../../../core/src" } from "../../../core/src"
import { find, filter, includes, keyBy, some, flatten, map } from "lodash/fp" import { find, filter, keyBy, flatten, map } from "lodash/fp"
import { generateSchema } from "../../../core/src/indexing/indexSchemaCreator" import { generateSchema } from "../../../core/src/indexing/indexSchemaCreator"

View File

@ -39,9 +39,7 @@
{/if} {/if}
<Modal onClosed={() => (confirmDelete = false)} bind:isOpen={confirmDelete}> <Modal onClosed={() => (confirmDelete = false)} bind:isOpen={confirmDelete}>
<span> <span>Are you sure you want to delete {$store.currentNode.name}?</span>
Are you sure you want to delete {$store.currentNode.name}?
</span>
<div class="uk-modal-footer uk-text-right"> <div class="uk-modal-footer uk-text-right">
<ButtonGroup> <ButtonGroup>
<ActionButton alert on:click={deleteCurrentNode}>Yes</ActionButton> <ActionButton alert on:click={deleteCurrentNode}>Yes</ActionButton>

View File

@ -14,9 +14,7 @@
store.subscribe($store => { store.subscribe($store => {
index = $store.currentNode index = $store.currentNode
indexableRecords = pipe( indexableRecords = pipe($store.hierarchy, [
$store.hierarchy,
[
hierarchyFunctions.getFlattenedHierarchy, hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isDecendant(index.parent())), filter(hierarchyFunctions.isDecendant(index.parent())),
filter(hierarchyFunctions.isRecord), filter(hierarchyFunctions.isRecord),
@ -24,8 +22,7 @@
node: n, node: n,
isallowed: some(id => n.nodeId === id)(index.allowedRecordNodeIds), isallowed: some(id => n.nodeId === id)(index.allowedRecordNodeIds),
})), })),
] ])
)
}) })
const toggleAllowedRecord = record => { const toggleAllowedRecord = record => {

View File

@ -99,7 +99,9 @@
<Textbox label="Name:" bind:text={record.name} on:change={nameChanged} /> <Textbox label="Name:" bind:text={record.name} on:change={nameChanged} />
{#if !record.isSingle} {#if !record.isSingle}
<Textbox label="Collection Name:" bind:text={record.collectionName} /> <Textbox label="Collection Name:" bind:text={record.collectionName} />
<Textbox label="Estimated Record Count:" bind:text={record.estimatedRecordCount} /> <Textbox
label="Estimated Record Count:"
bind:text={record.estimatedRecordCount} />
{/if} {/if}
<div class="recordkey">{record.nodeKey()}</div> <div class="recordkey">{record.nodeKey()}</div>

View File

@ -13,6 +13,7 @@ import "uikit/dist/js/uikit.min.js"
import "codemirror/lib/codemirror.css" import "codemirror/lib/codemirror.css"
import "codemirror/theme/monokai.css" import "codemirror/theme/monokai.css"
/* eslint-disable */
const app = new App({ const app = new App({
target: document.getElementById("app"), target: document.getElementById("app"),
}) })

View File

@ -14,7 +14,12 @@
const setActive = () => store.setActiveNav(name) const setActive = () => store.setActiveNav(name)
</script> </script>
<div class="budibase__nav-item backend-nav-item" class:selected={navActive} on:click={setActive}>{label}</div> <div
class="budibase__nav-item backend-nav-item"
class:selected={navActive}
on:click={setActive}>
{label}
</div>
<style> <style>
.backend-nav-item { .backend-nav-item {

View File

@ -1,13 +1,26 @@
<script> <script>
import { splitName } from "./pagesParsing/splitRootComponentName.js" import { splitName } from "./pagesParsing/splitRootComponentName.js"
import { store } from "../builderStore" import { store } from "../builderStore"
import { find, sortBy, groupBy, values, filter, map, uniqBy, flatten } from "lodash/fp" import {
find,
sortBy,
groupBy,
values,
filter,
map,
uniqBy,
flatten,
} from "lodash/fp"
import { ImageIcon, InputIcon, LayoutIcon } from "../common/Icons/" import { ImageIcon, InputIcon, LayoutIcon } from "../common/Icons/"
import Select from "../common/Select.svelte" import Select from "../common/Select.svelte"
import Button from "../common/PlusButton.svelte" import Button from "../common/PlusButton.svelte"
import ConfirmDialog from "../common/ConfirmDialog.svelte" import ConfirmDialog from "../common/ConfirmDialog.svelte"
import { getRecordNodes, getIndexNodes, getIndexSchema, pipe } from "../common/core" import {
getRecordNodes,
getIndexNodes,
getIndexSchema,
pipe,
} from "../common/core"
export let toggleTab export let toggleTab
@ -27,7 +40,7 @@
flatten, flatten,
filter(t => !$store.components.some(c => c.name === t.component)), filter(t => !$store.components.some(c => c.name === t.component)),
map(t => ({ name: splitName(t.component).componentName, template: t })), map(t => ({ name: splitName(t.component).componentName, template: t })),
uniqBy(t => t.name) uniqBy(t => t.name),
]) ])
const addRootComponent = (component, allComponents) => { const addRootComponent = (component, allComponents) => {
@ -62,18 +75,20 @@
records: getRecordNodes(hierarchy), records: getRecordNodes(hierarchy),
indexes: getIndexNodes(hierarchy), indexes: getIndexNodes(hierarchy),
helpers: { helpers: {
indexSchema: getIndexSchema(hierarchy) indexSchema: getIndexSchema(hierarchy),
} },
} }
templateInstances = libraryModules[libName][componentName](templateOptions) templateInstances = libraryModules[libName][componentName](templateOptions)
if(!templateInstances || templateInstances.length === 0) return if (!templateInstances || templateInstances.length === 0) return
selectedTemplateInstance = templateInstances[0].name selectedTemplateInstance = templateInstances[0].name
selectTemplateDialog.show() selectTemplateDialog.show()
} }
const onTemplateInstanceChosen = () => { const onTemplateInstanceChosen = () => {
selectedComponent = null selectedComponent = null
const instance = templateInstances.find(i => i.name === selectedTemplateInstance) const instance = templateInstances.find(
i => i.name === selectedTemplateInstance
)
store.addTemplatedComponent(instance.props) store.addTemplatedComponent(instance.props)
toggleTab() toggleTab()
} }
@ -81,7 +96,8 @@
function generate_components_list(components) { function generate_components_list(components) {
return ($store.currentFrontEndType === "page" return ($store.currentFrontEndType === "page"
? $store.builtins.concat(components) ? $store.builtins.concat(components)
: components).concat(standaloneTemplates) : components
).concat(standaloneTemplates)
} }
$: { $: {
@ -96,15 +112,12 @@
} }
$: componentLibrary = componentLibraries.find(l => l.libName === selectedLib) $: componentLibrary = componentLibraries.find(l => l.libName === selectedLib)
</script> </script>
<div class="root"> <div class="root">
<Select on:change={e => selectedLib = e.target.value}> <Select on:change={e => (selectedLib = e.target.value)}>
{#each componentLibraries as lib} {#each componentLibraries as lib}
<option value={lib.libName}> <option value={lib.libName}>{lib.libName}</option>
{lib.libName}
</option>
{/each} {/each}
</Select> </Select>
@ -136,9 +149,7 @@
{#if componentLibrary} {#if componentLibrary}
{#each generate_components_list(componentLibrary.components) as component} {#each generate_components_list(componentLibrary.components) as component}
<div class="component-container"> <div class="component-container">
<div <div class="component" on:click={() => onComponentChosen(component)}>
class="component"
on:click={() => onComponentChosen(component)}>
<div class="name">{splitName(component.name).componentName}</div> <div class="name">{splitName(component.name).componentName}</div>
{#if (component.presets || templatesByComponent[component.name]) && component.name === selectedComponent} {#if (component.presets || templatesByComponent[component.name]) && component.name === selectedComponent}
<ul class="preset-menu"> <ul class="preset-menu">
@ -152,7 +163,9 @@
{/each} {/each}
{/if} {/if}
{#if templatesByComponent[component.name]} {#if templatesByComponent[component.name]}
<span>{splitName(component.name).componentName} Templates</span> <span>
{splitName(component.name).componentName} Templates
</span>
{#each templatesByComponent[component.name] as template} {#each templatesByComponent[component.name] as template}
<li <li
on:click|stopPropagation={() => onTemplateChosen(template)}> on:click|stopPropagation={() => onTemplateChosen(template)}>
@ -180,18 +193,21 @@
{/if} {/if}
</div> </div>
</div> </div>
<ConfirmDialog <ConfirmDialog
bind:this={selectTemplateDialog} bind:this={selectTemplateDialog}
title="Choose Template" title="Choose Template"
onCancel={() => selectedComponent = null} onCancel={() => (selectedComponent = null)}
onOk={onTemplateInstanceChosen}> onOk={onTemplateInstanceChosen}>
{#each templateInstances.map(i => i.name) as instance} {#each templateInstances.map(i => i.name) as instance}
<div class="uk-margin uk-grid-small uk-child-width-auto uk-grid"> <div class="uk-margin uk-grid-small uk-child-width-auto uk-grid">
<label> <label>
<input class="uk-radio" type="radio" bind:group={selectedTemplateInstance} value={instance}> <input
class="uk-radio"
type="radio"
bind:group={selectedTemplateInstance}
value={instance} />
<span class="template-instance-label">{instance}</span> <span class="template-instance-label">{instance}</span>
</label> </label>
</div> </div>
@ -307,5 +323,4 @@
.template-instance-label { .template-instance-label {
margin-left: 20px; margin-left: 20px;
} }
</style> </style>

View File

@ -15,15 +15,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 lastPartOfName = c => { const lastPartOfName = c => {
if (!c) return "" if (!c) return ""
@ -31,15 +28,14 @@
return last(name.split("/")) return last(name.split("/"))
} }
const isComponentSelected = (current, comp) => current === comp const isComponentSelected = (current, comp) => current === comp
const isFolderSelected = (current, folder) => isInSubfolder(current, folder) const isFolderSelected = (current, folder) => isInSubfolder(current, folder)
$: _screens = pipe( $: _screens = pipe(screens, [
screens, map(c => ({ component: c, title: lastPartOfName(c) })),
[map(c => ({ component: c, title: lastPartOfName(c) })), sortBy("title")] sortBy("title"),
) ])
const isScreenSelected = component => const isScreenSelected = component =>
component.component && component.component &&

View File

@ -20,11 +20,7 @@
const capitalise = s => s.substring(0, 1).toUpperCase() + s.substring(1) const capitalise = s => s.substring(0, 1).toUpperCase() + s.substring(1)
const get_name = s => (!s ? "" : last(s.split("/"))) const get_name = s => (!s ? "" : last(s.split("/")))
const get_capitalised_name = name => const get_capitalised_name = name => pipe(name, [get_name, capitalise])
pipe(
name,
[get_name, capitalise]
)
const moveDownComponent = component => { const moveDownComponent = component => {
const c = component const c = component

View File

@ -3,8 +3,8 @@
import ComponentPropertiesPanel from "./ComponentPropertiesPanel.svelte" import ComponentPropertiesPanel from "./ComponentPropertiesPanel.svelte"
import ComponentSelectionList from "./ComponentSelectionList.svelte" import ComponentSelectionList from "./ComponentSelectionList.svelte"
const PROPERTIES_TAB = "properties"; const PROPERTIES_TAB = "properties"
const COMPONENT_SELECTION_TAB = "components"; const COMPONENT_SELECTION_TAB = "components"
let selected = PROPERTIES_TAB let selected = PROPERTIES_TAB
@ -12,7 +12,9 @@
const selectTab = tab => (selected = tab) const selectTab = tab => (selected = tab)
const toggleTab = () => selected = selected === PROPERTIES_TAB ? COMPONENT_SELECTION_TAB : PROPERTIES_TAB; const toggleTab = () =>
(selected =
selected === PROPERTIES_TAB ? COMPONENT_SELECTION_TAB : PROPERTIES_TAB)
</script> </script>
<div class="root"> <div class="root">

View File

@ -16,15 +16,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 lastPartOfName = c => const lastPartOfName = c =>
c && last(c.name ? c.name.split("/") : c._component.split("/")) c && last(c.name ? c.name.split("/") : c._component.split("/"))
@ -33,10 +30,7 @@
const isFolderSelected = (current, folder) => isInSubfolder(current, folder) const isFolderSelected = (current, folder) => isInSubfolder(current, folder)
$: _layout = pipe( $: _layout = pipe(layout, [c => ({ component: c, title: lastPartOfName(c) })])
layout,
[c => ({ component: c, title: lastPartOfName(c) })]
)
const isScreenSelected = component => const isScreenSelected = component =>
component.component && component.component &&

View File

@ -24,13 +24,10 @@
let saveAttempted = false let saveAttempted = false
$: layoutComponents = pipe( $: layoutComponents = pipe($store.components, [
$store.components,
[
filter(c => c.container), filter(c => c.container),
map(c => ({ name: c.name, ...splitName(c.name) })), map(c => ({ name: c.name, ...splitName(c.name) })),
] ])
)
$: layoutComponent = layoutComponent $: layoutComponent = layoutComponent
? find(c => c.name === layoutComponent.name)(layoutComponents) ? find(c => c.name === layoutComponent.name)(layoutComponents)
@ -43,9 +40,11 @@
saveAttempted = true saveAttempted = true
const isValid = const isValid =
name.length > 0 && !screenNameExists(name) name.length > 0 &&
&& route.length > 0 && !routeNameExists(route) !screenNameExists(name) &&
&& layoutComponent route.length > 0 &&
!routeNameExists(route) &&
layoutComponent
if (!isValid) return if (!isValid) return
@ -102,7 +101,7 @@
class="uk-input uk-form-small" class="uk-input uk-form-small"
class:uk-form-danger={saveAttempted && (route.length === 0 || routeNameExists(route))} class:uk-form-danger={saveAttempted && (route.length === 0 || routeNameExists(route))}
bind:value={route} bind:value={route}
on:change={routeChanged}/> on:change={routeChanged} />
</div> </div>
</div> </div>

View File

@ -3,7 +3,7 @@
import { store } from "../../builderStore" import { store } from "../../builderStore"
import { buildStateOrigins } from "../../builderStore/buildStateOrigins" import { buildStateOrigins } from "../../builderStore/buildStateOrigins"
import { isBinding, getBinding, setBinding } from "../../common/binding" import { isBinding, getBinding, setBinding } from "../../common/binding"
import StateBindingOptions from "./StateBindingOptions.svelte"; import StateBindingOptions from "./StateBindingOptions.svelte"
export let onChanged = () => {} export let onChanged = () => {}
export let value = "" export let value = ""
@ -28,7 +28,8 @@
const setBindingPath = value => const setBindingPath = value =>
bindValueToSource(value, bindingFallbackValue, bindingSource) bindValueToSource(value, bindingFallbackValue, bindingSource)
const setBindingFallback = value => bindValueToSource(bindingPath, value, bindingSource) const setBindingFallback = value =>
bindValueToSource(bindingPath, value, bindingSource)
const setBindingSource = source => const setBindingSource = source =>
bindValueToSource(bindingPath, bindingFallbackValue, source) bindValueToSource(bindingPath, bindingFallbackValue, source)
@ -69,9 +70,10 @@
</button> </button>
</div> </div>
{#if isOpen} {#if isOpen}
<StateBindingOptions onSelect={option => { <StateBindingOptions
onChanged(option); onSelect={option => {
isOpen = false; onChanged(option)
isOpen = false
}} /> }} />
{/if} {/if}
</div> </div>

View File

@ -13,15 +13,13 @@
const props_to_ignore = ["_component", "_children", "_styles", "_code", "_id"] const props_to_ignore = ["_component", "_children", "_styles", "_code", "_id"]
$: componentDef = $: componentDef =
component && components && component &&
components &&
components.find(({ name }) => name === component._component) components.find(({ name }) => name === component._component)
let setProp = (name, value) => { let setProp = (name, value) => {
onPropChanged(name, value) onPropChanged(name, value)
} }
</script> </script>
<div class="root"> <div class="root">

View File

@ -23,7 +23,7 @@
class="uk-select uk-form-small" class="uk-select uk-form-small"
{value} {value}
on:change={ev => onChanged(ev.target.value)}> on:change={ev => onChanged(ev.target.value)}>
{#each (options || []) as option} {#each options || [] as option}
<option value={option}>{option}</option> <option value={option}>{option}</option>
{/each} {/each}
</select> </select>

View File

@ -5,7 +5,7 @@ import { isRootComponent } from "./searchComponents"
export const libraryDependencies = (components, lib) => { export const libraryDependencies = (components, lib) => {
const componentDependsOnLibrary = comp => { const componentDependsOnLibrary = comp => {
if (isRootComponent(comp)) { if (isRootComponent(comp)) {
const { libName } = splitName(component.name) const { libName } = splitName(comp.name)
return libName === lib return libName === lib
} }
return componentDependsOnLibrary( return componentDependsOnLibrary(

View File

@ -1,6 +1,6 @@
import { pipe } from "../../common/core" import { pipe } from "../../common/core"
import { find, isUndefined, filter, some, includes, has } from "lodash/fp" import { find, isUndefined, filter, some, includes } from "lodash/fp"
const normalString = s => (s || "").trim().toLowerCase() const normalString = s => (s || "").trim().toLowerCase()

View File

@ -3,10 +3,8 @@ import {
isBoolean, isBoolean,
isNumber, isNumber,
isArray, isArray,
isObjectLike,
isPlainObject, isPlainObject,
every, every,
isUndefined,
} from "lodash/fp" } from "lodash/fp"
import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers" import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers"
@ -61,7 +59,6 @@ export const expandComponentDefinition = componentDefinition => {
return expandedComponent return expandedComponent
} }
const isComponent = isObjectLike
const isEvent = e => const isEvent = e =>
isPlainObject(e) && isPlainObject(e) &&
isString(e[EVENT_TYPE_MEMBER_NAME]) && isString(e[EVENT_TYPE_MEMBER_NAME]) &&

View File

@ -2,7 +2,7 @@ import { isString, keys, flatten, isArray, map, filter } from "lodash/fp"
import { common } from "../../../../core/src" import { common } from "../../../../core/src"
const pipe = common.$ const pipe = common.$
export const validatePage = (page, getComponent) => { export const validatePage = page => {
const errors = [] const errors = []
const error = message => errors.push(message) const error = message => errors.push(message)

View File

@ -1,30 +1,32 @@
import { buildStateOrigins } from "../src/builderStore/buildStateOrigins"; import { buildStateOrigins } from "../src/builderStore/buildStateOrigins"
it("builds the correct stateOrigins object from a screen definition with handlers", () => { it("builds the correct stateOrigins object from a screen definition with handlers", () => {
expect(buildStateOrigins({ expect(
"name": "screen1", buildStateOrigins({
"description": "", name: "screen1",
"props": { description: "",
"_component": "@budibase/standard-components/container", props: {
"className": "", _component: "@budibase/standard-components/container",
"type": "div", className: "",
"onClick": [ type: "div",
onClick: [
{ {
"##eventHandlerType": "Set State", "##eventHandlerType": "Set State",
"parameters": { parameters: {
"path": "testKey", path: "testKey",
"value": "value" value: "value",
} },
} },
] ],
} },
})).toEqual({ })
"testKey": { ).toEqual({
testKey: {
"##eventHandlerType": "Set State", "##eventHandlerType": "Set State",
"parameters": { parameters: {
"path": "testKey", path: "testKey",
"value": "value" value: "value",
} },
} },
}); })
}); })

View File

@ -1 +1 @@
module.exports = config => ({}) module.exports = () => ({})

View File

@ -1,4 +1,4 @@
const { resolve, join } = require("path") const { resolve } = require("path")
const { cwd } = require("process") const { cwd } = require("process")
const buildAppContext = require("@budibase/server/initialise/buildAppContext") const buildAppContext = require("@budibase/server/initialise/buildAppContext")

View File

@ -2,7 +2,6 @@ import resolve from "rollup-plugin-node-resolve"
import commonjs from "rollup-plugin-commonjs" import commonjs from "rollup-plugin-commonjs"
import builtins from "rollup-plugin-node-builtins" import builtins from "rollup-plugin-node-builtins"
import nodeglobals from "rollup-plugin-node-globals" import nodeglobals from "rollup-plugin-node-globals"
import { terser } from "rollup-plugin-terser"
const lodash_fp_exports = [ const lodash_fp_exports = [
"find", "find",

View File

@ -19,8 +19,6 @@ const appPackages = join(
const publicMain = appName => join(appPackages, appName, "public", "main") const publicMain = appName => join(appPackages, appName, "public", "main")
const publicUnauth = appName => const publicUnauth = appName =>
join(appPackages, appName, "public", "unauthenticated") join(appPackages, appName, "public", "unauthenticated")
const nodeModules = appName =>
join(appPackages, appName, "node_modules", "@budibase", "client", "dist")
;(async () => { ;(async () => {
const apps = await readdir(appPackages) const apps = await readdir(appPackages)

View File

@ -6,8 +6,7 @@ import { builtins, builtinLibName } from "./render/builtinComponents"
* create a web application from static budibase definition files. * create a web application from static budibase definition files.
* @param {object} opts - configuration options for budibase client libary * @param {object} opts - configuration options for budibase client libary
*/ */
export const loadBudibase = async (opts) => { export const loadBudibase = async opts => {
let componentLibraries = opts && opts.componentLibraries let componentLibraries = opts && opts.componentLibraries
const _window = (opts && opts.window) || window const _window = (opts && opts.window) || window
const _localStorage = (opts && opts.localStorage) || localStorage const _localStorage = (opts && opts.localStorage) || localStorage
@ -33,8 +32,8 @@ export const loadBudibase = async (opts) => {
: "/" + trimSlash(frontendDefinition.appRootPath) : "/" + trimSlash(frontendDefinition.appRootPath)
if (!componentLibraries) { if (!componentLibraries) {
const componentLibraryUrl = lib =>
const componentLibraryUrl = lib => frontendDefinition.appRootPath + "/" + trimSlash(lib) frontendDefinition.appRootPath + "/" + trimSlash(lib)
componentLibraries = {} componentLibraries = {}
for (let lib of frontendDefinition.componentLibraries) { for (let lib of frontendDefinition.componentLibraries) {
@ -46,25 +45,33 @@ export const loadBudibase = async (opts) => {
componentLibraries[builtinLibName] = builtins(_window) componentLibraries[builtinLibName] = builtins(_window)
const { initialisePage, screenStore, pageStore, routeTo, rootNode } = createApp( const {
initialisePage,
screenStore,
pageStore,
routeTo,
rootNode,
} = createApp(
componentLibraries, componentLibraries,
frontendDefinition, frontendDefinition,
backendDefinition, backendDefinition,
user, user,
uiFunctions || {}, uiFunctions || {},
_window _window,
rootNode
) )
const route = _window.location const route = _window.location
? _window.location.pathname.replace(frontendDefinition.appRootPath, "") ? _window.location.pathname.replace(frontendDefinition.appRootPath, "")
: ""; : ""
initialisePage(frontendDefinition.page, _window.document.body, route)
return { return {
rootNode: initialisePage(frontendDefinition.page, _window.document.body, route),
screenStore, screenStore,
pageStore, pageStore,
routeTo, routeTo,
rootNode rootNode,
} }
} }

View File

@ -47,7 +47,7 @@ export const attachChildren = initialiseOpts => (htmlElement, options) => {
uiFunctions, uiFunctions,
htmlElement, htmlElement,
anchor, anchor,
getCurrentState getCurrentState,
}) })
for (let childNode of childNodesThisIteration) { for (let childNode of childNodesThisIteration) {

View File

@ -34,7 +34,8 @@ export const parseBinding = prop => {
} }
export const isStoreBinding = binding => binding && binding.source === "store" export const isStoreBinding = binding => binding && binding.source === "store"
export const isContextBinding = binding => binding && binding.source === "context" export const isContextBinding = binding =>
binding && binding.source === "context"
export const isEventBinding = binding => binding && binding.source === "event" export const isEventBinding = binding => binding && binding.source === "event"
const hasBindingObject = prop => const hasBindingObject = prop =>
@ -50,7 +51,7 @@ const isBindingExpression = prop =>
prop.startsWith("route.")) prop.startsWith("route."))
const parseBindingExpression = prop => { const parseBindingExpression = prop => {
let [source, ...rest] = prop.split("."); let [source, ...rest] = prop.split(".")
let path = rest.join(".") let path = rest.join(".")
if (source === "route") { if (source === "route") {

View File

@ -160,7 +160,11 @@ const setNodeState = (storeState, node) => {
* Bind a components event handler parameters to state, context or the event itself. * Bind a components event handler parameters to state, context or the event itself.
* @param {Array} eventHandlerProp - event handler array from component definition * @param {Array} eventHandlerProp - event handler array from component definition
*/ */
function bindComponentEventHandlers(eventHandlerProp) { function bindComponentEventHandlers(
eventHandlerProp,
context,
getCurrentState
) {
const boundEventHandlers = [] const boundEventHandlers = []
for (let event of eventHandlerProp) { for (let event of eventHandlerProp) {
const boundEventHandler = { const boundEventHandler = {
@ -177,23 +181,24 @@ function bindComponentEventHandlers(eventHandlerProp) {
continue continue
} }
let paramValueSource; let paramValueSource
if (paramBinding.source === "context") paramValueSource = context; if (paramBinding.source === "context") paramValueSource = context
if (paramBinding.source === "state") paramValueSource = getCurrentState(); if (paramBinding.source === "state") paramValueSource = getCurrentState()
// The new dynamic event parameter bound to the relevant source // The new dynamic event parameter bound to the relevant source
boundParameters[paramName] = eventContext => getState( boundParameters[paramName] = eventContext =>
getState(
paramBinding.source === "event" ? eventContext : paramValueSource, paramBinding.source === "event" ? eventContext : paramValueSource,
paramBinding.path, paramBinding.path,
paramBinding.fallback paramBinding.fallback
); )
} }
boundEventHandler.parameters = boundParameters boundEventHandler.parameters = boundParameters
boundEventHandlers.push(boundEventHandlers) boundEventHandlers.push(boundEventHandlers)
return boundEventHandlers; return boundEventHandlers
} }
} }
@ -239,13 +244,17 @@ const _setup = (
} }
if (isEventType(propValue)) { if (isEventType(propValue)) {
const boundEventHandlers = bindComponentEventHandlers(propValue); const boundEventHandlers = bindComponentEventHandlers(
propValue,
context,
getCurrentState
)
if (boundEventHandlers.length === 0) { if (boundEventHandlers.length === 0) {
initialProps[propName] = doNothing initialProps[propName] = doNothing
} else { } else {
initialProps[propName] = async context => { initialProps[propName] = async context => {
for (let handlerInfo of handlersInfos) { for (let handlerInfo of boundEventHandlers) {
const handler = makeHandler(handlerTypes, handlerInfo) const handler = makeHandler(handlerTypes, handlerInfo)
await handler(context) await handler(context)
} }

View File

@ -1,5 +1,5 @@
import { flatten, orderBy, filter, isUndefined } from "lodash/fp" import { flatten, orderBy, filter, isUndefined } from "lodash/fp"
import hierarchy, { import {
getFlattenedHierarchy, getFlattenedHierarchy,
getCollectionNodeByKeyOrNodeKey, getCollectionNodeByKeyOrNodeKey,
isCollectionRecord, isCollectionRecord,

View File

@ -5,7 +5,6 @@ import {
isGlobalIndex, isGlobalIndex,
getParentKey, getParentKey,
isShardedIndex, isShardedIndex,
getExactNodeForKey,
} from "../templateApi/hierarchy" } from "../templateApi/hierarchy"
import { joinKey, isNonEmptyString, splitKey, $ } from "../common" import { joinKey, isNonEmptyString, splitKey, $ } from "../common"

View File

@ -1,5 +1,5 @@
import { keyBy, mapValues, filter, map, includes, last } from "lodash/fp" import { keyBy, mapValues, filter, map, includes, last } from "lodash/fp"
import { getExactNodeForKey, getNode } from "../templateApi/hierarchy" import { getNode } from "../templateApi/hierarchy"
import { safeParseField } from "../types" import { safeParseField } from "../types"
import { import {
$, $,

View File

@ -5,7 +5,7 @@ import {
isSingleRecord, isSingleRecord,
getNodeForCollectionPath, getNodeForCollectionPath,
} from "../templateApi/hierarchy" } from "../templateApi/hierarchy"
import { reduce, find, filter, take } from "lodash/fp" import { reduce, find, filter } from "lodash/fp"
import { $, getFileFromKey, joinKey, safeKey, keySep } from "../common" import { $, getFileFromKey, joinKey, safeKey, keySep } from "../common"
import { folderStructureArray, allIdChars } from "../indexing/allIds" import { folderStructureArray, allIdChars } from "../indexing/allIds"

View File

@ -73,9 +73,7 @@ const _uploadFile = async (
) )
if (!isExpectedFileSize) { if (!isExpectedFileSize) {
throw new BadRequestError( throw new BadRequestError(
`Fields for ${relativeFilePath} do not have expected size: ${join( `Fields for ${relativeFilePath} do not have expected size.`
","
)(incorrectFields)}`
) )
} }
}) })

View File

@ -1,6 +1,6 @@
import {} from "../templateApi/heirarchy" import {} from "../templateApi/heirarchy"
export const canDelete = (app, node) => { export const canDelete = () => {
/* /*
it must not exist on any index.allowedRecordNodeIds it must not exist on any index.allowedRecordNodeIds
it must not exist on and reference type fields it must not exist on and reference type fields

View File

@ -1,6 +1,6 @@
import { apiWrapper, apiWrapperSync } from "../src/common/apiWrapper" import { apiWrapper, apiWrapperSync } from "../src/common/apiWrapper"
import { filter } from "lodash/fp" import { filter } from "lodash/fp"
import { event, onComplete, onBegin, onError, events } from "../src/common" import { events } from "../src/common"
const getApp = () => { const getApp = () => {
var events = [] var events = []
@ -26,7 +26,7 @@ describe("apiWrapper", () => {
const getErrorEvents = app => app.getEvents(testNamespace.onError) const getErrorEvents = app => app.getEvents(testNamespace.onError)
const runThrowEx = (arg1, arg2) => { const runThrowEx = (arg1, arg2) => {
const throwEx = (x, y) => { const throwEx = () => {
throw new Error("test error") throw new Error("test error")
} }
const app = getApp() const app = getApp()
@ -47,7 +47,7 @@ describe("apiWrapper", () => {
} }
const runThrowExAsync = async (arg1, arg2) => { const runThrowExAsync = async (arg1, arg2) => {
const throwEx = async (x, y) => { const throwEx = async () => {
throw new Error("test error") throw new Error("test error")
} }
const app = getApp() const app = getApp()

View File

@ -33,7 +33,7 @@ describe("authApi > authenticate", () => {
}) })
it("should return null when non existing user", async () => { it("should return null when non existing user", async () => {
const { authApi, app } = await setupApphierarchy( const { authApi } = await setupApphierarchy(
basicAppHierarchyCreator_WithFields basicAppHierarchyCreator_WithFields
) )
const result = await authApi.authenticate("nobody", "password") const result = await authApi.authenticate("nobody", "password")

View File

@ -31,7 +31,7 @@ describe("recordApi > files", () => {
const { recordApi } = await setupApphierarchy( const { recordApi } = await setupApphierarchy(
basicAppHierarchyCreator_WithFields basicAppHierarchyCreator_WithFields
) )
const { file, stream, content } = getFile() const { file, stream } = getFile()
file.size = file.size - 1 file.size = file.size - 1
const record = recordApi.getNew("/customers", "customer") const record = recordApi.getNew("/customers", "customer")
record.surname = "Ledog" record.surname = "Ledog"
@ -46,7 +46,7 @@ describe("recordApi > files", () => {
const { recordApi } = await setupApphierarchy( const { recordApi } = await setupApphierarchy(
basicAppHierarchyCreator_WithFields basicAppHierarchyCreator_WithFields
) )
const { file, stream, content } = getFile() const { file, stream } = getFile()
const record = recordApi.getNew("/customers", "customer") const record = recordApi.getNew("/customers", "customer")
record.surname = "Ledog" record.surname = "Ledog"
record.profilepic = file record.profilepic = file
@ -80,7 +80,7 @@ describe("recordApi > files", () => {
const { recordApi } = await setupApphierarchy( const { recordApi } = await setupApphierarchy(
basicAppHierarchyCreator_WithFields basicAppHierarchyCreator_WithFields
) )
const { file, stream, content } = getFile() const { file, stream } = getFile()
const record = recordApi.getNew("/customers", "customer") const record = recordApi.getNew("/customers", "customer")
record.surname = "Ledog" record.surname = "Ledog"
record.profilepic = file record.profilepic = file
@ -98,7 +98,7 @@ describe("recordApi > files", () => {
const { recordApi } = await setupApphierarchy( const { recordApi } = await setupApphierarchy(
basicAppHierarchyCreator_WithFields basicAppHierarchyCreator_WithFields
) )
const { file, stream, content } = getFile() const { file, stream } = getFile()
const record = recordApi.getNew("/customers", "customer") const record = recordApi.getNew("/customers", "customer")
record.surname = "Ledog" record.surname = "Ledog"
record.profilepic = file record.profilepic = file

View File

@ -4,7 +4,6 @@ import { promisify } from "es6-promisify"
import _rimraf from "rimraf" import _rimraf from "rimraf"
const mkdir = promisify(fs.mkdir) const mkdir = promisify(fs.mkdir)
const rmdir = promisify(fs.rmdir)
const rimraf = promisify(_rimraf) const rimraf = promisify(_rimraf)
const getConfig = async () => { const getConfig = async () => {

View File

@ -1,9 +1,8 @@
import fs from "fs"
import { mkdir } from "fs" import { mkdir } from "fs"
import { join } from "path" import { join } from "path"
import { promisify } from "es6-promisify" import { promisify } from "es6-promisify"
mkdirp = promisify(mkdir) const mkdirp = promisify(mkdir)
const getConfig = async () => { const getConfig = async () => {
const config = { const config = {
@ -13,15 +12,13 @@ const getConfig = async () => {
memory: {}, memory: {},
} }
try { await mkdirp("./output")
await mkdir("./output")
} catch (e) {}
for (let type in config) { for (let type in config) {
await mkdir(join("output", type)) await mkdirp(join("output", type))
} }
await mkdir("./output/local/files") await mkdirp("./output/local/files")
return config return config
} }

View File

@ -9,7 +9,7 @@ import {
} from "@azure/storage-blob" } from "@azure/storage-blob"
export const createFile = ({ containerUrl }) => async (key, content) => { export const createFile = ({ containerUrl }) => async (key, content) => {
const blobURL = BlobURL.fromContainerURL(containerURL, key) const blobURL = BlobURL.fromContainerURL(containerUrl, key)
const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL) const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL)
await blockBlobURL.upload(Aborter.none, content, content.length) await blockBlobURL.upload(Aborter.none, content, content.length)
} }
@ -17,7 +17,7 @@ export const createFile = ({ containerUrl }) => async (key, content) => {
export const updateFile = opts => async (path, content) => export const updateFile = opts => async (path, content) =>
createFile(opts)(path, content) createFile(opts)(path, content)
export const loadFile = ({ containerUrl }) => async key => { export const loadFile = ({ containerUrl }) => async (key, content) => {
const blobURL = BlobURL.fromContainerURL(containerUrl, key) const blobURL = BlobURL.fromContainerURL(containerUrl, key)
const downloadBlockBlobResponse = await blobURL.download(Aborter.none, 0) const downloadBlockBlobResponse = await blobURL.download(Aborter.none, 0)
@ -27,8 +27,8 @@ export const loadFile = ({ containerUrl }) => async key => {
.toString() .toString()
} }
export const exists = ({ containerURL }) => async key => { export const exists = ({ containerUrl }) => async key => {
const blobURL = BlobURL.fromContainerURL(containerURL, key) const blobURL = BlobURL.fromContainerURL(containerUrl, key)
const getPropsResponse = await blobURL.getProperties() const getPropsResponse = await blobURL.getProperties()
return getPropsResponse._response.StatusCode === 200 return getPropsResponse._response.StatusCode === 200
} }
@ -53,7 +53,7 @@ const initialise = opts => {
const pipeline = StorageURL.newPipeline(sharedKeyCredential) const pipeline = StorageURL.newPipeline(sharedKeyCredential)
const serviceURL = new ServiceURL( const serviceURL = new ServiceURL(
`https://${account}.blob.core.windows.net`, `https://${opts.account}.blob.core.windows.net`,
pipeline pipeline
) )
@ -77,6 +77,5 @@ export default opts => {
datastoreType: "azure-blob-storage", datastoreType: "azure-blob-storage",
datastoreDescription: "", datastoreDescription: "",
data,
} }
} }

View File

@ -24,5 +24,5 @@ initialise()
.then(init => { .then(init => {
return tests(init.datastore, init.config) return tests(init.datastore, init.config)
}) })
.then(_ => console.log("done")) .then(() => console.log("done"))
.catch(e => console.log(e)) .catch(e => console.log(e))

View File

@ -1,14 +1,8 @@
import { eventsList } from "@budibase/core" import { eventsList } from "@budibase/core"
import { filter, union, has, map } from "lodash/fp" import { filter, union, has, map } from "lodash/fp"
import records from "./records"
const allEventsOfType = type => filter(e => e.endsWith(`:${type}`))(eventsList) const allEventsOfType = type => filter(e => e.endsWith(`:${type}`))(eventsList)
const getEventNamespace = ev => {
const parts = ev.split(":")
return `${parts[0]}:${parts[1]}`
}
const hasRecord = has("record") const hasRecord = has("record")
export const register = (app, logTimeElapsed, eventNamespaces = []) => { export const register = (app, logTimeElapsed, eventNamespaces = []) => {

View File

@ -16,7 +16,6 @@ const iterateActions = async (apis, getIterator) => {
limit(() => result.action.run(i)) limit(() => result.action.run(i))
) )
let n = 1
await Promise.all(runPromises) await Promise.all(runPromises)
result = iterator() result = iterator()
} catch (e) { } catch (e) {

View File

@ -1,5 +1,5 @@
import { action, iterateActionTimes, iterateCollection } from "./helpers" import { action, iterateActionTimes } from "./helpers"
import { isUndefined, union, takeRight } from "lodash" import { isUndefined, union } from "lodash"
const createClient = (apis, getState) => async i => { const createClient = (apis, getState) => async i => {
const client = apis.recordApi.getNew("/clients", "client") const client = apis.recordApi.getNew("/clients", "client")
@ -20,16 +20,6 @@ const createClient = (apis, getState) => async i => {
return client.key() return client.key()
} }
const getClient = (apis, getState) => async k => {
const state = getState()
if (isUndefined(state.clients)) state.clients = []
const client = await apis.recordApi.load(k)
state.clients.push(client)
return `key: ${k} , add1: ${client.Address1} , count: ${state.clients.length}`
}
const listClients = (apis, getState) => async () => { const listClients = (apis, getState) => async () => {
const clients = await apis.viewApi.listItems("/clients/default") const clients = await apis.viewApi.listItems("/clients/default")
const state = getState() const state = getState()
@ -43,12 +33,6 @@ const listClients = (apis, getState) => async () => {
} }
} }
const deleteClient = (apis, getState) => async k => {
await apis.recordApi.delete(k)
const state = getState()
state.clientKeys = state.clientKeys.filter(key => key !== k)
}
export default apis => { export default apis => {
const state = {} const state = {}
const getState = () => state const getState = () => state
@ -64,9 +48,6 @@ export default apis => {
iterateActionTimes(recordsPerIteration) iterateActionTimes(recordsPerIteration)
), ),
/*action("Get client", getClient(apis, getState),
iterateCollection(() => takeRight(getState().clientKeys, recordsPerIteration))),*/
action("List Clients", listClients(apis, getState)), action("List Clients", listClients(apis, getState)),
] ]
@ -75,14 +56,6 @@ export default apis => {
actions = union(actions, actionsInOneIteration()) actions = union(actions, actionsInOneIteration())
} }
/*
for (let index = 0; index < noOfIterations; index++) {
actions.push(
action("Delete Clients", deleteClient(apis, getState),
iterateCollection(() => takeRight(getState().clientKeys, recordsPerIteration))),
action("List Clients", listClients(apis, getState))
);
}*/
let actionIndex = 0 let actionIndex = 0
return () => { return () => {

View File

@ -1,5 +1,4 @@
import { getAppApis, getTemplateApi, setupDatastore } from "@budibase/core" import { getAppApis, getTemplateApi, setupDatastore } from "@budibase/core"
import { action } from "./helpers"
const addField = templateApi => type => (record, name) => { const addField = templateApi => type => (record, name) => {
const field = templateApi.getNewField(type) const field = templateApi.getNewField(type)

View File

@ -1,7 +1,6 @@
import svelte from "rollup-plugin-svelte" import svelte from "rollup-plugin-svelte"
import postcss from "rollup-plugin-postcss" import postcss from "rollup-plugin-postcss"
import resolve from "rollup-plugin-node-resolve" import resolve from "rollup-plugin-node-resolve"
import path from "path"
const postcssOptions = () => ({ const postcssOptions = () => ({
extensions: [".scss", ".sass"], extensions: [".scss", ".sass"],

View File

@ -5,7 +5,7 @@ import livereload from "rollup-plugin-livereload"
import { terser } from "rollup-plugin-terser" import { terser } from "rollup-plugin-terser"
import json from "rollup-plugin-json" import json from "rollup-plugin-json"
import alias from "rollup-plugin-alias" import alias from "rollup-plugin-alias"
import postcss from "rollup-plugin-postcss"; import postcss from "rollup-plugin-postcss"
import path from "path" import path from "path"
const aliases = { const aliases = {

View File

@ -1,28 +1,48 @@
<script> <script>
import Checkbox from "./Checkbox.svelte"; import Checkbox from "./Checkbox.svelte"
import Label from "../Common/Label.svelte"; import Label from "../Common/Label.svelte"
export let label = ""; export let label = ""
export let orientation = "row"; export let orientation = "row"
export let fullwidth = false; export let fullwidth = false
export let onChange = selectedItems => {}; export let onChange = selectedItems => {}
export let items = []; export let items = []
export let disabled = false; export let disabled = false
export let alignEnd = false; export let alignEnd = false
let selectedItems = []; let selectedItems = []
function handleonChange(item) { function handleonChange(item) {
if (!!item.checked) { if (!!item.checked) {
item.checked = !item.checked; item.checked = !item.checked
} else { } else {
item.checked = true; item.checked = true
} }
onChange(items.filter(i => i.checked)); onChange(items.filter(i => i.checked))
} }
</script> </script>
<div class="checkbox-group">
<div class="checkbox-group__label">
<Label text={label} bold />
</div>
<div class={`checkbox-group__boxes ${orientation}`}>
{#each items as item, i}
<div class:fullwidth>
<Checkbox
id={`${item.label}-${i}`}
{disabled}
{alignEnd}
indeterminate={item.indeterminate || false}
label={item.label}
checked={item.checked || false}
onClick={() => handleonChange(item)} />
</div>
{/each}
</div>
</div>
<style> <style>
.checkbox-group { .checkbox-group {
display: flex; display: flex;
@ -55,23 +75,3 @@
text-align: left; text-align: left;
} }
</style> </style>
<div class="checkbox-group">
<div class="checkbox-group__label">
<Label text={label} bold />
</div>
<div class={`checkbox-group__boxes ${orientation}`}>
{#each items as item, i}
<div class:fullwidth>
<Checkbox
id={`${item.label}-${i}`}
{disabled}
{alignEnd}
indeterminate={item.indeterminate || false}
label={item.label}
checked={item.checked || false}
onClick={() => handleonChange(item)} />
</div>
{/each}
</div>
</div>

View File

@ -1,4 +1,3 @@
import "./_style.scss"; import "./_style.scss"
export { default as Checkbox } from "./Checkbox.svelte"; export { default as Checkbox } from "./Checkbox.svelte"
export { default as Checkboxgroup } from "./CheckboxGroup.svelte"; export { default as Checkboxgroup } from "./CheckboxGroup.svelte"

View File

@ -1,7 +1,7 @@
export default class ClassBuilder { export default class ClassBuilder {
constructor(block, defaultIgnoreList) { constructor(block, defaultIgnoreList) {
this.block = `mdc-${block}`; this.block = `mdc-${block}`
this.defaultIgnoreList = defaultIgnoreList; //will be ignored when building custom classes this.defaultIgnoreList = defaultIgnoreList //will be ignored when building custom classes
} }
/* /*
@ -10,32 +10,32 @@ export default class ClassBuilder {
All are optional All are optional
*/ */
build(params) { build(params) {
if (!params) return this.block; //return block if nothing passed if (!params) return this.block //return block if nothing passed
const { props, elementName } = params; const { props, elementName } = params
let base = !!elementName ? `${this.block}__${elementName}` : this.block; let base = elementName ? `${this.block}__${elementName}` : this.block
if (!props) return base; if (!props) return base
return this._handleProps(base, props); return this._handleProps(base, props)
} }
//Easily grab a simple element class //Easily grab a simple element class
elem(elementName) { elem(elementName) {
return this.build({ elementName }); return this.build({ elementName })
} }
//use if a different base is needed than whats defined by this.block //use if a different base is needed than whats defined by this.block
debase(base, elementProps) { debase(base, elementProps) {
if (!elementProps) return base; if (!elementProps) return base
return this._handleProps(base, elementProps); return this._handleProps(base, elementProps)
} }
//proxies bindProps and checks for which elementProps exist before binding //proxies bindProps and checks for which elementProps exist before binding
_handleProps(base, elementProps) { _handleProps(base, elementProps) {
let cls = base; let cls = base
const { modifiers, customs, extras } = elementProps; const { modifiers, customs, extras } = elementProps
if (!!modifiers) cls += this._bindProps(modifiers, base); if (modifiers) cls += this._bindProps(modifiers, base)
if (!!customs) cls += this._bindProps(customs, base, true); if (customs) cls += this._bindProps(customs, base, true)
if (!!extras) cls += ` ${extras.join(" ")}`; if (extras) cls += ` ${extras.join(" ")}`
return cls.trim(); return cls.trim()
} }
/* /*
@ -53,22 +53,22 @@ export default class ClassBuilder {
!!value && !!value &&
(!this.defaultIgnoreList || !this.defaultIgnoreList.includes(value)) (!this.defaultIgnoreList || !this.defaultIgnoreList.includes(value))
) { ) {
let classBase = isCustom ? `bbmd-${base}` : `${base}`; let classBase = isCustom ? `bbmd-${base}` : `${base}`
let valueType = typeof value; let valueType = typeof value
if (valueType == "string" || valueType == "number") { if (valueType == "string" || valueType == "number") {
return isCustom return isCustom
? ` ${classBase}--${this._convertCamel(property)}-${value}` ? ` ${classBase}--${this._convertCamel(property)}-${value}`
: ` ${classBase}--${value}`; : ` ${classBase}--${value}`
} else if (valueType == "boolean") { } else if (valueType == "boolean") {
return ` ${classBase}--${this._convertCamel(property)}`; return ` ${classBase}--${this._convertCamel(property)}`
} }
} }
}) })
.join(""); .join("")
} }
_convertCamel(str) { _convertCamel(str) {
return str.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`); return str.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`)
} }
} }

View File

@ -1,32 +1,32 @@
<script> <script>
import "@material/form-field/mdc-form-field.scss"; import "@material/form-field/mdc-form-field.scss"
import ClassBuilder from "../ClassBuilder.js"; import ClassBuilder from "../ClassBuilder.js"
import { fieldStore } from "./FormfieldStore.js"; import { fieldStore } from "./FormfieldStore.js"
import { MDCFormField } from "@material/form-field"; import { MDCFormField } from "@material/form-field"
import { onMount, onDestroy, setContext } from "svelte"; import { onMount, onDestroy, setContext } from "svelte"
const cb = new ClassBuilder("form-field"); const cb = new ClassBuilder("form-field")
let store; let store
const unsubscribe = fieldStore.subscribe(s => (store = s)); const unsubscribe = fieldStore.subscribe(s => (store = s))
export let id = ""; export let id = ""
export let label = ""; export let label = ""
export let alignEnd = false; export let alignEnd = false
let formField = null; let formField = null
let modifiers = { alignEnd }; let modifiers = { alignEnd }
let props = { modifiers }; let props = { modifiers }
let blockClasses = cb.build({ props }); let blockClasses = cb.build({ props })
onMount(() => { onMount(() => {
if (!!formField) fieldStore.set(new MDCFormField(formField)); if (!!formField) fieldStore.set(new MDCFormField(formField))
setContext("BBMD:field-element", fieldStore); setContext("BBMD:field-element", fieldStore)
}); })
onDestroy(unsubscribe); onDestroy(unsubscribe)
</script> </script>
<div bind:this={formField} class={blockClasses}> <div bind:this={formField} class={blockClasses}>

View File

@ -1,19 +1,19 @@
import { writable } from "svelte/store"; import { writable } from "svelte/store"
function store() { function store() {
const { set, update, subscribe } = writable({}); const { set, update, subscribe } = writable({})
function setInput(inp) { function setInput(inp) {
update(n => { update(n => {
n.input = inp; n.input = inp
}); })
} }
return { return {
subscribe, subscribe,
set, set,
setInput setInput,
}; }
} }
export const fieldStore = store(); export const fieldStore = store()

View File

@ -1,12 +1,12 @@
<script> <script>
import { getContext } from "svelte"; import { getContext } from "svelte"
export let icon = ""; export let icon = ""
let iconContext = getContext("BBMD:icon:context"); let iconContext = getContext("BBMD:icon:context")
let cls = iconContext let cls = iconContext
? `material-icons mdc-${iconContext}__icon` ? `material-icons mdc-${iconContext}__icon`
: "material-icons"; : "material-icons"
</script> </script>
<i class={cls}>{icon}</i> <i class={cls}>{icon}</i>

View File

@ -1,12 +1,12 @@
<script> <script>
export let bold = false; export let bold = false
export let text = ""; export let text = ""
</script> </script>
<span class="mdc-typography" class:bold>{text}</span>
<style> <style>
.bold { .bold {
font-weight: 500; font-weight: 500;
} }
</style> </style>
<span class="mdc-typography" class:bold>{text}</span>

View File

@ -17,12 +17,10 @@
let tableElement let tableElement
let initialied = false let initialied = false
$: { $: {
if(tableElement && datatable && !initialied) { if (tableElement && datatable && !initialied) {
const children = _bb.attachChildren(tableElement) const children = _bb.attachChildren(tableElement)
if(children.length > 0) { if (children.length > 0) {
instance = new MDCDataTable(datatable) instance = new MDCDataTable(datatable)
initialied = true initialied = true
} }
@ -34,7 +32,7 @@
return () => { return () => {
try { try {
!!instance && instance.destroy() !!instance && instance.destroy()
} catch(e) { } catch (e) {
console.log(e) console.log(e)
} }
instance = null instance = null
@ -43,7 +41,8 @@
</script> </script>
<div bind:this={datatable} class={cb.build()}> <div bind:this={datatable} class={cb.build()}>
<table class={cb.elem`table`} aria-label="Material Design Datatable" bind:this={tableElement}> <table
class={cb.elem`table`}
</table> aria-label="Material Design Datatable"
bind:this={tableElement} />
</div> </div>

View File

@ -1,14 +1,13 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
export let _bb export let _bb
const cb = _bb.getContext("BBMD:data-table:cb") const cb = _bb.getContext("BBMD:data-table:cb")
let tbody let tbody
$: tbody && _bb.attachChildren(tbody)
$: tbody && _bb.attachChildren(tbody)
</script> </script>
<tbody bind:this={tbody} class={cb.elem`content`}></tbody> <tbody bind:this={tbody} class={cb.elem`content`} />

View File

@ -14,7 +14,6 @@
let element let element
$: element && _bb.attachChildren(element) $: element && _bb.attachChildren(element)
</script> </script>
{#if isHeader} {#if isHeader}

View File

@ -1,13 +1,11 @@
<script> <script>
export let _bb
export let _bb const cb = _bb.getContext("BBMD:data-table:cb")
const cb = _bb.getContext("BBMD:data-table:cb") let thead
let thead
$: thead && _bb.attachChildren(thead)
$: thead && _bb.attachChildren(thead)
</script> </script>
<thead bind:this={thead} class=className></thead> <thead bind:this={thead} class="className" />

View File

@ -1,27 +1,27 @@
<script> <script>
import { getContext } from "svelte"; import { getContext } from "svelte"
export let onSelect = () => {}; export let onSelect = () => {}
export let isHeader = false; export let isHeader = false
export let _bb export let _bb
let row = null; let row = null
let selected = false; let selected = false
const cb = _bb.getContext("BBMD:data-table:cb") const cb = _bb.getContext("BBMD:data-table:cb")
let elementName = isHeader ? "header-row" : "row"; let elementName = isHeader ? "header-row" : "row"
let modifiers = {}; let modifiers = {}
$: modifiers = { selected }; $: modifiers = { selected }
$: props = { modifiers }; $: props = { modifiers }
$: rowClass = cb.build({ elementName, props }); $: rowClass = cb.build({ elementName, props })
$: row && _bb.attachChildren(row) $: row && _bb.attachChildren(row)
function rowSelected() { function rowSelected() {
selected = !selected; selected = !selected
onSelect(); onSelect()
} }
</script> </script>

View File

@ -1,79 +1,71 @@
<script> <script>
import { onMount, getContext } from "svelte"; import { onMount, getContext } from "svelte"
import { MDCList } from "@material/list"; import { MDCList } from "@material/list"
import { MDCRipple } from "@material/ripple"; import { MDCRipple } from "@material/ripple"
import ListItem from "./ListItem.svelte"; import ListItem from "./ListItem.svelte"
import ClassBuilder from "../ClassBuilder.js"; import ClassBuilder from "../ClassBuilder.js"
const cb = new ClassBuilder("list", ["one-line"]); export let _bb
const cb = new ClassBuilder("list", ["one-line"])
let list = null; let list = null
let instance = null; let instance = null
export let onSelect = selectedItems => {}; export let onSelect = selectedItems => {}
export let variant = "one-line"; export let variant = "one-line"
//items: [{text: string | {primary: string, secondary: string}, value: any, selected: bool}...n] //items: [{text: string | {primary: string, secondary: string}, value: any, selected: bool}...n]
export let items = []; export let items = []
export let singleSelection = false; export let singleSelection = false
export let inputElement = null; export let inputElement = null
let role = "listbox"; let role = "listbox"
onMount(() => { onMount(() => {
if (!!list) { if (!!list) {
instance = new MDCList(list); instance = new MDCList(list)
instance.singleSelection = singleSelection; instance.singleSelection = singleSelection
instance.listElements.map(element => new MDCRipple(element)); instance.listElements.map(element => new MDCRipple(element))
} }
let context = getContext("BBMD:list:context"); let context = getContext("BBMD:list:context")
if (context === "menu") { if (context === "menu") {
role = "menu"; role = "menu"
} }
return () => { return () => {
instance && instance.destroy(); instance && instance.destroy()
instance = null; instance = null
}; }
}); })
function handleSelectedItem(item) { function handleSelectedItem(item) {
if (!item.disabled) { if (!item.disabled) {
if (singleSelection || inputElement === "radiobutton") { if (singleSelection || inputElement === "radiobutton") {
items.forEach(i => { items.forEach(i => {
if (i.selected) i.selected = false; if (i.selected) i.selected = false
}); })
} }
let idx = items.indexOf(item); let idx = items.indexOf(item)
if (!!item.selected) { if (!!item.selected) {
items[idx].selected = !item.selected; items[idx].selected = !item.selected
} else { } else {
items[idx].selected = true; items[idx].selected = true
} }
onSelect(items.filter(item => item.selected)); onSelect(items.filter(item => item.selected))
} }
} }
$: useDoubleLine = $: useDoubleLine =
variant == "two-line" && variant == "two-line" &&
items.every(i => typeof i.text == "object" && "primary" in i.text); items.every(i => typeof i.text == "object" && "primary" in i.text)
$: modifiers = { variant }; $: list && _bb.attachChildren(list)
$: props = { modifiers };
$: listClass = cb.build({ props }); $: modifiers = { variant }
$: props = { modifiers }
$: listClass = cb.build({ props })
</script> </script>
<ul class={listClass} {role}> <ul bind:this={list} class={listClass} {role} />
{#each items as item, i}
<ListItem
{item}
{useDoubleLine}
{inputElement}
onClick={() => handleSelectedItem(item)} />
{#if item.divider}
<li role="separator" class="mdc-list-divider" />
{/if}
{/each}
</ul>

View File

@ -1,71 +1,73 @@
<script> <script>
import { onMount, getContext } from "svelte"; import { onMount, getContext } from "svelte"
import { Radiobutton } from "../Radiobutton"; import { Radiobutton } from "../Radiobutton"
import { Checkbox } from "../Checkbox"; import { Checkbox } from "../Checkbox"
import ClassBuilder from "../ClassBuilder.js"; import ClassBuilder from "../ClassBuilder.js"
const cb = new ClassBuilder("list-item"); const cb = new ClassBuilder("list-item")
export let onClick = item => {}; export let onClick = item => {}
export let item = null; export let text = ""
export let useDoubleLine = false; export let secondaryText = ""
export let inputElement = null; //radiobutton or checkbox export let variant = "two-line"
export let inputElement = null
export let leadingIcon = ""
export let trailingIcon = ""
export let selected = false
export let disabled = false
let role = "option"; let role = "option"
onMount(() => { onMount(() => {
let context = getContext("BBMD:list:context"); let context = getContext("BBMD:list:context")
if (context === "menu") { if (context === "menu") {
role = "menuitem"; role = "menuitem"
} }
}); })
$: if (!!inputElement) { $: if (!!inputElement) {
setContext("BBMD:input:context", "list-item"); setContext("BBMD:input:context", "list-item")
} }
$: modifiers = { $: modifiers = {
selected: !inputElement ? item.selected : null, selected,
disabled: item.disabled disabled,
}; }
$: props = { modifiers }; $: props = { modifiers }
$: listItemClass = cb.build({ props }); $: listItemClass = cb.build({ props })
$: useSecondaryText = $: useTwoLine = variant === "two-line" && !!secondaryText
typeof item.text === "object" && "secondary" in item.text;
</script> </script>
<li <li
class={listItemClass} class={listItemClass}
role="option" role="option"
aria-selected={item.selected} aria-selected={selected}
tabindex="0" tabindex="0"
on:click={onClick}> on:click={onClick}>
{#if item.leadingIcon} {#if leadingIcon}
<span class="mdc-list-item__graphic material-icons" aria-hidden="true"> <span class="mdc-list-item__graphic material-icons" aria-hidden="true">
{item.leadingIcon} {leadingIcon}
</span> </span>
{/if} {/if}
<span class={cb.elem`text`}> <span class={cb.elem`text`}>
{#if useDoubleLine} {#if useTwoLine}
<span class={cb.elem`primary-text`}>{item.text.primary}</span> <span class={cb.elem`primary-text`}>{text}</span>
{#if useSecondaryText} <span class={cb.elem`secondary-text`}>{secondaryText}</span>
<span class={cb.elem`secondary-text`}>{item.text.secondary}</span> {:else}{text}{/if}
{/if}
{:else}{item.text}{/if}
</span> </span>
{#if inputElement} {#if inputElement}
{#if inputElement === 'radiobutton'} {#if inputElement === 'radiobutton'}
<Radiobutton checked={item.selected} disabled={item.disabled} /> <Radiobutton checked={selected} {disabled} />
{:else if inputElement === 'checkbox'} {:else if inputElement === 'checkbox'}
<Checkbox checked={item.selected} disabled={item.disabled} /> <Checkbox checked={selected} {disabled} />
{/if} {/if}
{:else if item.trailingIcon} {:else if trailingIcon}
<!-- TODO: Adapt label to accept class prop to handle this. Context is insufficient --> <!-- TODO: Adapt label to accept class prop to handle this. Context is insufficient -->
<span class="mdc-list-item__meta material-icons" aria-hidden="true"> <span class="mdc-list-item__meta material-icons" aria-hidden="true">
{item.trailingIcon} {trailingIcon}
</span> </span>
{/if} {/if}
</li> </li>

View File

@ -1,2 +1,3 @@
import "./_style.scss"; import "./_style.scss"
export { default as List } from "./List.svelte"; export { default as List } from "./List.svelte"
export { default as ListItem } from "./ListItem.svelte"

View File

@ -1,32 +1,32 @@
<script> <script>
import { List } from "../List"; import { List } from "../List"
import { MDCMenu } from "@material/menu"; import { MDCMenu } from "@material/menu"
import { onMount, setContext } from "svelte"; import { onMount, setContext } from "svelte"
export let items = []; export let items = []
export let singleSelection = true; export let singleSelection = true
export let width = "400px"; export let width = "400px"
export let open = true; export let open = true
export let useFixedPosition = false; export let useFixedPosition = false
export let useAbsolutePosition = false; export let useAbsolutePosition = false
//{x: number, y: number} //{x: number, y: number}
export let absolutePositionCoords = null; export let absolutePositionCoords = null
let menu = null; let menu = null
let instance = null; let instance = null
onMount(() => { onMount(() => {
if (!!menu) { if (!!menu) {
instance = new MDCMenu(menu); instance = new MDCMenu(menu)
instance.open = open; instance.open = open
if (useFixedPosition) { if (useFixedPosition) {
instance.setFixedPosition(true); instance.setFixedPosition(true)
} else if (useAbsolutePosition) { } else if (useAbsolutePosition) {
let { x, y } = absolutePositionCoords; let { x, y } = absolutePositionCoords
instance.setAbsolutePosition(x | 0, y | 0); instance.setAbsolutePosition(x | 0, y | 0)
} }
} }
setContext("BBMD:list:context", "menu"); setContext("BBMD:list:context", "menu")
}); })
</script> </script>
{#if useFixedPosition || useAbsolutePosition} {#if useFixedPosition || useAbsolutePosition}

View File

@ -1,2 +1,2 @@
import "./_styles.scss"; import "./_styles.scss"
export { default as Menu } from "./Menu.svelte"; export { default as Menu } from "./Menu.svelte"

View File

@ -1,3 +1,3 @@
import "./_style.scss"; import "./_style.scss"
export { default as Radiobutton } from "./Radiobutton.svelte"; export { default as Radiobutton } from "./Radiobutton.svelte"
export { default as Radiobuttongroup } from "./RadiobuttonGroup.svelte"; export { default as Radiobuttongroup } from "./RadiobuttonGroup.svelte"

View File

@ -15,6 +15,7 @@
Datatable, Datatable,
CustomersIndexTable, CustomersIndexTable,
List, List,
Icon,
} = props } = props
let currentComponent let currentComponent
@ -35,6 +36,7 @@
Checkboxgroup, Checkboxgroup,
Radiobutton, Radiobutton,
Radiobuttongroup, Radiobuttongroup,
Icon,
Datatable, Datatable,
CustomersIndexTable, CustomersIndexTable,
List, List,

View File

@ -4,7 +4,7 @@ import packageJson from "../../package.json"
import { rootComponent } from "./rootComponent" import { rootComponent } from "./rootComponent"
import * as standardcomponents from "@budibase/standard-components/src/index" import * as standardcomponents from "@budibase/standard-components/src/index"
export default async props => { export default async () => {
delete components._lib delete components._lib
const componentLibraries = {} const componentLibraries = {}
componentLibraries[packageJson.name] = components componentLibraries[packageJson.name] = components

View File

@ -117,22 +117,39 @@ export const props = {
CustomersIndexTable: indexDatatable(templateOptions)[0].props, CustomersIndexTable: indexDatatable(templateOptions)[0].props,
List: { List: {
_component: "@budibase/materialdesign-components/List", _component: "@budibase/materialdesign-components/List",
_children: [
{
_component: "@budibase/materialdesign-components/ListItem",
_children: [], _children: [],
variant: "two-line", variant: "two-line",
singleSelection: true, singleSelection: true,
items: [ text: "Curry",
{ secondaryText: "Chicken or Beef",
text: { primary: "Curry", secondary: "Chicken or Beef" },
value: 0, value: 0,
divider: true, divider: true,
}, },
{ {
text: { primary: "Pastie", secondary: "Bap with Mayo" }, _component: "@budibase/materialdesign-components/ListItem",
_children: [],
variant: "two-line",
singleSelection: true,
text: "Pastie",
secondaryText: "Bap with Mayo",
value: 1, value: 1,
disabled: true, disabled: true,
}, },
{ text: { primary: "Fish", secondary: "Salmon or Cod" }, value: 2 }, {
_component: "@budibase/materialdesign-components/ListItem",
_children: [],
variant: "two-line",
singleSelection: true,
text: "Fish",
secondaryText: "Salmon or Cod",
value: 2,
},
], ],
variant: "two-line",
singleSelection: true,
onSelect: selected => console.log(selected), onSelect: selected => console.log(selected),
}, },
} }

View File

@ -68,7 +68,7 @@
} }
let useLabel = !!label && (!fullwidth || (fullwidth && textarea)) let useLabel = !!label && (!fullwidth || (fullwidth && textarea))
let useIcon = !!icon && (!textarea && !fullwidth) let useIcon = !!icon && !textarea && !fullwidth
if (useIcon) { if (useIcon) {
setContext("BBMD:icon:context", "text-field") setContext("BBMD:icon:context", "text-field")
@ -120,7 +120,7 @@ TODO:Needs error handling - this will depend on how Budibase handles errors
{placeholder} {placeholder}
{minLength} {minLength}
maxLength={safeMaxLength} maxLength={safeMaxLength}
value={value} {value}
on:change={changed} /> on:change={changed} />
{:else} {:else}
{#if renderLeadingIcon} {#if renderLeadingIcon}
@ -135,7 +135,7 @@ TODO:Needs error handling - this will depend on how Budibase handles errors
placeholder={!!label && fullwidth ? label : placeholder} placeholder={!!label && fullwidth ? label : placeholder}
{minLength} {minLength}
maxLength={safeMaxLength} maxLength={safeMaxLength}
value={value} {value}
aria-label={`Textfield ${variant}`} aria-label={`Textfield ${variant}`}
on:focus={focus} on:focus={focus}
on:input={changed} /> on:input={changed} />

View File

@ -1,13 +1,13 @@
import "./_style.scss"; import "./_style.scss"
export { default as Body1 } from "./Body1.svelte"; export { default as Body1 } from "./Body1.svelte"
export { default as Body2 } from "./Body2.svelte"; export { default as Body2 } from "./Body2.svelte"
export { default as Caption } from "./Caption.svelte"; export { default as Caption } from "./Caption.svelte"
export { default as H1 } from "./H1.svelte"; export { default as H1 } from "./H1.svelte"
export { default as H2 } from "./H2.svelte"; export { default as H2 } from "./H2.svelte"
export { default as H3 } from "./H3.svelte"; export { default as H3 } from "./H3.svelte"
export { default as H4 } from "./H4.svelte"; export { default as H4 } from "./H4.svelte"
export { default as H5 } from "./H5.svelte"; export { default as H5 } from "./H5.svelte"
export { default as H6 } from "./H6.svelte"; export { default as H6 } from "./H6.svelte"
export { default as Overline } from "./Overline.svelte"; export { default as Overline } from "./Overline.svelte"
export { default as Sub1 } from "./Sub1.svelte"; export { default as Sub1 } from "./Sub1.svelte"
export { default as Sub2 } from "./Sub2.svelte"; export { default as Sub2 } from "./Sub2.svelte"

View File

@ -16,4 +16,4 @@ export {
} from "./Datatable" } from "./Datatable"
export { default as indexDatatable } from "./Templates/indexDatatable" export { default as indexDatatable } from "./Templates/indexDatatable"
export { default as recordForm } from "./Templates/recordForm" export { default as recordForm } from "./Templates/recordForm"
export { List } from "./List" export { List, ListItem } from "./List"

View File

@ -1,6 +1,6 @@
const fs = require("fs") const fs = require("fs")
module.exports = config => ({ module.exports = () => ({
main: { main: {
outputToFile: async ({ filename, content }) => { outputToFile: async ({ filename, content }) => {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
window['##BUDIBASE_FRONTEND_DEINITION##'] = {"componentLibraries":[{"importPath":"/lib/customComponents/index.js","libName":"./customComponents"},{"importPath":"/lib/moreCustomComponents/index.js","libName":"./moreCustomComponents"}],"appRootPath":"","page":{"title":"Test App","favicon":"./_shared/favicon.png","stylesheets":["my-styles.css"],"componentLibraries":["./customComponents","./moreCustomComponents"],"props":{"_component":"@budibase/standard-components/container"}},"screens":[{"name":"screen1","description":"","props":{"_component":"@budibase/standard-components/container","className":""},"_css":"/css/d121e1ecc6cf44f433213222e9ff5d40.css"},{"name":"screen2","description":"","props":{"_component":"@budibase/standard-components/container","className":""},"_css":"/css/7b7c05b78e05c06eb8d69475caadfea3.css"}]}; window['##BUDIBASE_FRONTEND_DEFINITION##'] = {"componentLibraries":[{"importPath":"/lib/customComponents/index.js","libName":"./customComponents"},{"importPath":"/lib/moreCustomComponents/index.js","libName":"./moreCustomComponents"}],"appRootPath":"","page":{"title":"Test App","favicon":"./_shared/favicon.png","stylesheets":["my-styles.css"],"componentLibraries":["./customComponents","./moreCustomComponents"],"props":{"_component":"@budibase/standard-components/container","type":"div"}},"screens":[{"name":"screen1","description":"","props":{"_component":"@budibase/standard-components/container","className":"","type":"div"},"_css":"/css/d121e1ecc6cf44f433213222e9ff5d40.css"},{"name":"screen2","description":"","props":{"_component":"@budibase/standard-components/container","className":"","type":"div"},"_css":"/css/7b7c05b78e05c06eb8d69475caadfea3.css"}]};
window['##BUDIBASE_FRONTEND_FUNCTIONS##'] = {'1234':() => 'test return'} window['##BUDIBASE_FRONTEND_FUNCTIONS##'] = {'1234':() => 'test return'}

View File

@ -11,26 +11,21 @@
html, body { html, body {
height: 100%; height: 100%;
width: 100%; width: 100%;
margin: 0px;
padding: 0px;
} }
</style> </style>
<link rel='stylesheet' href='//my-styles.css'> <link rel='stylesheet' href='//my-styles.css'>
<link rel='stylesheet' href='/css/d121e1ecc6cf44f433213222e9ff5d40.css'> <link rel='stylesheet' href='/css/d121e1ecc6cf44f433213222e9ff5d40.css'>
<link rel='stylesheet' href='/css/7b7c05b78e05c06eb8d69475caadfea3.css'> <link rel='stylesheet' href='/css/7b7c05b78e05c06eb8d69475caadfea3.css'>
<link rel='stylesheet' href='/css/f66fc2928f7d850c946e619c1a1f3096.css'> <link rel='stylesheet' href='/css/f66fc2928f7d850c946e619c1a1f3096.css'>
<script src='/clientFrontendDefinition.js'></script>
<script src='/_master/clientFrontendDefinition.js'></script> <script src='/clientBackendDefinition.js'></script>
<script src='/_master/clientBackendDefinition.js'></script>
<script src='/budibase-client.js'></script> <script src='/budibase-client.js'></script>
<script> <script>
loadBudibase(); loadBudibase();

View File

@ -1 +1 @@
module.exports = config => ({}) module.exports = () => ({})

View File

@ -4,7 +4,6 @@ const { applictionVersionPackage } = require("../utilities/createAppPackage")
const { determineVersionId } = require("../utilities/runtimePackages") const { determineVersionId } = require("../utilities/runtimePackages")
module.exports = async (context, datastoreModule, app, instance) => { module.exports = async (context, datastoreModule, app, instance) => {
try {
const databaseManager = getDatabaseManager( const databaseManager = getDatabaseManager(
datastoreModule, datastoreModule,
context.config.datastoreConfig context.config.datastoreConfig
@ -35,7 +34,4 @@ module.exports = async (context, datastoreModule, app, instance) => {
) )
return dbConfig return dbConfig
} catch (e) {
throw e
}
} }

View File

@ -10,7 +10,6 @@ const masterDbAccessLevels = require("../appPackages/_master/access_levels.json"
const { masterAppPackage } = require("../utilities/createAppPackage") const { masterAppPackage } = require("../utilities/createAppPackage")
module.exports = async (context, datastoreModule, username, password) => { module.exports = async (context, datastoreModule, username, password) => {
try {
const { config } = context const { config } = context
const databaseManager = getDatabaseManager( const databaseManager = getDatabaseManager(
datastoreModule, datastoreModule,
@ -19,9 +18,7 @@ module.exports = async (context, datastoreModule, username, password) => {
await databaseManager.createEmptyMasterDb() await databaseManager.createEmptyMasterDb()
const masterDbConfig = databaseManager.masterDatastoreConfig const masterDbConfig = databaseManager.masterDatastoreConfig
const datastore = setupDatastore( const datastore = setupDatastore(datastoreModule.getDatastore(masterDbConfig))
datastoreModule.getDatastore(masterDbConfig)
)
await initialiseData(datastore, constructHierarchy(masterDbAppDefinition)) await initialiseData(datastore, constructHierarchy(masterDbAppDefinition))
@ -34,7 +31,4 @@ module.exports = async (context, datastoreModule, username, password) => {
await bbMaster.authApi.createUser(user, password) await bbMaster.authApi.createUser(user, password)
return await getApisForUser(datastore, masterPackage, username, password) return await getApisForUser(datastore, masterPackage, username, password)
} catch (e) {
throw e
}
} }

View File

@ -13,7 +13,9 @@ const copyfolder = (source, destination) =>
}) })
}) })
module.exports = async (context, bbMaster, latestAppsFolder) => { exports.copyfolder = copyfolder
module.exports = async context => {
// create runtime folder // create runtime folder
// copy master into /master/latest // copy master into /master/latest
if (await pathExists(runtimePackagesDirectory)) { if (await pathExists(runtimePackagesDirectory)) {
@ -26,16 +28,6 @@ module.exports = async (context, bbMaster, latestAppsFolder) => {
await mkdir(runtimePackagesDirectory) await mkdir(runtimePackagesDirectory)
/*
const allApps = await bbMaster
.indexApi
.listItems("/all_applications");
for(let app of allApps) {
app.
}
*/
const apps = { const apps = {
_master: masterAppPackage(context), _master: masterAppPackage(context),
} }

View File

@ -141,7 +141,11 @@ module.exports = (config, app) => {
}) })
.get("/_builder/api/:appname/components", async ctx => { .get("/_builder/api/:appname/components", async ctx => {
try { try {
ctx.body = getComponentDefinitions(config, ctx.params.appname, ctx.query.lib) ctx.body = getComponentDefinitions(
config,
ctx.params.appname,
ctx.query.lib
)
ctx.response.status = StatusCodes.OK ctx.response.status = StatusCodes.OK
} catch (e) { } catch (e) {
if (e.status) { if (e.status) {

View File

@ -14,9 +14,9 @@ module.exports = (config, app) => {
rolling: false /** (boolean) Force a session identifier cookie to be set on every response. The expiration is reset to the original maxAge, resetting the expiration countdown. (default is false) */, rolling: false /** (boolean) Force a session identifier cookie to be set on every response. The expiration is reset to the original maxAge, resetting the expiration countdown. (default is false) */,
renew: false /** (boolean) renew session when session is nearly expired, so we can always keep user logged in. (default is false)*/, renew: false /** (boolean) renew session when session is nearly expired, so we can always keep user logged in. (default is false)*/,
store: { store: {
get: async (key, maxAge, { rolling }) => ({ key }), get: async key => ({ key }),
set: async (key, sess, maxAge, { rolling, changed }) => ({ key }), set: async key => ({ key }),
destroy: async key => ({}), destroy: async () => ({}),
}, },
} }

View File

@ -25,6 +25,7 @@ beforeAll(async () => {
await app.start() await app.start()
}) })
afterAll(async () => await app.destroy()) afterAll(async () => await app.destroy())
it("/apppackage should get appDefinition", async () => { it("/apppackage should get appDefinition", async () => {

View File

@ -1,14 +1,9 @@
const statusCodes = require("../utilities/statusCodes") const statusCodes = require("../utilities/statusCodes")
const constructHierarchy = require("../utilities/constructHierarchy") const constructHierarchy = require("../utilities/constructHierarchy")
const { readFile } = require("fs-extra") const { readFile } = require("fs-extra")
const { hierarchy } = require("@budibase/core") constructHierarchy(require("../appPackages/_master/appDefinition.json"))
const { take } = require("lodash/fp")
const masterAppDefinition = constructHierarchy(
require("../appPackages/_master/appDefinition.json")
)
const { getApisWithFullAccess } = require("../utilities/budibaseApi") const { getApisWithFullAccess } = require("../utilities/budibaseApi")
const { createTarGzPackage } = require("../utilities/targzAppPackage") const { createTarGzPackage } = require("../utilities/targzAppPackage")
const { timeout } = require("./helpers")
module.exports = app => { module.exports = app => {
let _master let _master

Some files were not shown because too many files have changed in this diff Show More