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,
"node": true
},
"parser": "babel-eslint",
"parserOptions": {
"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"],
"extends": ["eslint:recommended"],
"overrides": [

View File

@ -27,6 +27,7 @@ jobs:
node-version: ${{ matrix.node-version }}
- run: yarn
- run: yarn lint
- run: yarn bootstrap
- run: yarn build
- run: yarn test
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",
"private": true,
"devDependencies": {
"babel-eslint": "^10.0.3",
"eslint": "^6.8.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-svelte3": "^2.7.3",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,21 +7,22 @@
* @returns {Object} an object with the client state values and how they are managed.
*/
export const buildStateOrigins = screenDefinition => {
const origins = {};
const origins = {}
function traverse(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]) {
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"
export const store = getStore()
export const createNewPackage = () => createPackage(packageInfo, store)
export const initialise = async () => {
try {
setupRouter(store)
@ -17,8 +14,7 @@ export const initialise = async () => {
const setupRouter = writable => {
const pushState = history.pushState
history.pushState = () => {
pushState.apply(history, arguments)
//fireEvents('pushState', arguments);
pushState.apply(history, [writable])
writable.initialise()
}
window.addEventListener("hashchange", () => {

View File

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

View File

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

View File

@ -17,7 +17,9 @@
class="dropdown-content"
style="display: {isDroppedDown ? 'inline-block' : 'none'}">
{#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}
</div>

View File

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

View File

@ -4,7 +4,7 @@ import {
getTemplateApi,
getAuthApi,
} 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"

View File

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

View File

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

View File

@ -99,7 +99,9 @@
<Textbox label="Name:" bind:text={record.name} on:change={nameChanged} />
{#if !record.isSingle}
<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}
<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/theme/monokai.css"
/* eslint-disable */
const app = new App({
target: document.getElementById("app"),
})

View File

@ -14,7 +14,12 @@
const setActive = () => store.setActiveNav(name)
</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>
.backend-nav-item {

View File

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

View File

@ -15,15 +15,12 @@
const joinPath = join("/")
const normalizedName = name =>
pipe(
name,
[
pipe(name, [
trimCharsStart("./"),
trimCharsStart("~/"),
trimCharsStart("../"),
trimChars(" "),
]
)
])
const lastPartOfName = c => {
if (!c) return ""
@ -31,15 +28,14 @@
return last(name.split("/"))
}
const isComponentSelected = (current, comp) => current === comp
const isFolderSelected = (current, folder) => isInSubfolder(current, folder)
$: _screens = pipe(
screens,
[map(c => ({ component: c, title: lastPartOfName(c) })), sortBy("title")]
)
$: _screens = pipe(screens, [
map(c => ({ component: c, title: lastPartOfName(c) })),
sortBy("title"),
])
const isScreenSelected = component =>
component.component &&

View File

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

View File

@ -3,8 +3,8 @@
import ComponentPropertiesPanel from "./ComponentPropertiesPanel.svelte"
import ComponentSelectionList from "./ComponentSelectionList.svelte"
const PROPERTIES_TAB = "properties";
const COMPONENT_SELECTION_TAB = "components";
const PROPERTIES_TAB = "properties"
const COMPONENT_SELECTION_TAB = "components"
let selected = PROPERTIES_TAB
@ -12,7 +12,9 @@
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>
<div class="root">

View File

@ -16,15 +16,12 @@
const joinPath = join("/")
const normalizedName = name =>
pipe(
name,
[
pipe(name, [
trimCharsStart("./"),
trimCharsStart("~/"),
trimCharsStart("../"),
trimChars(" "),
]
)
])
const lastPartOfName = c =>
c && last(c.name ? c.name.split("/") : c._component.split("/"))
@ -33,10 +30,7 @@
const isFolderSelected = (current, folder) => isInSubfolder(current, folder)
$: _layout = pipe(
layout,
[c => ({ component: c, title: lastPartOfName(c) })]
)
$: _layout = pipe(layout, [c => ({ component: c, title: lastPartOfName(c) })])
const isScreenSelected = component =>
component.component &&

View File

@ -24,13 +24,10 @@
let saveAttempted = false
$: layoutComponents = pipe(
$store.components,
[
$: layoutComponents = pipe($store.components, [
filter(c => c.container),
map(c => ({ name: c.name, ...splitName(c.name) })),
]
)
])
$: layoutComponent = layoutComponent
? find(c => c.name === layoutComponent.name)(layoutComponents)
@ -43,9 +40,11 @@
saveAttempted = true
const isValid =
name.length > 0 && !screenNameExists(name)
&& route.length > 0 && !routeNameExists(route)
&& layoutComponent
name.length > 0 &&
!screenNameExists(name) &&
route.length > 0 &&
!routeNameExists(route) &&
layoutComponent
if (!isValid) return

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
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()

View File

@ -3,10 +3,8 @@ import {
isBoolean,
isNumber,
isArray,
isObjectLike,
isPlainObject,
every,
isUndefined,
} from "lodash/fp"
import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers"
@ -61,7 +59,6 @@ export const expandComponentDefinition = componentDefinition => {
return expandedComponent
}
const isComponent = isObjectLike
const isEvent = e =>
isPlainObject(e) &&
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"
const pipe = common.$
export const validatePage = (page, getComponent) => {
export const validatePage = page => {
const errors = []
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", () => {
expect(buildStateOrigins({
"name": "screen1",
"description": "",
"props": {
"_component": "@budibase/standard-components/container",
"className": "",
"type": "div",
"onClick": [
expect(
buildStateOrigins({
name: "screen1",
description: "",
props: {
_component: "@budibase/standard-components/container",
className: "",
type: "div",
onClick: [
{
"##eventHandlerType": "Set State",
"parameters": {
"path": "testKey",
"value": "value"
}
}
]
}
})).toEqual({
"testKey": {
parameters: {
path: "testKey",
value: "value",
},
},
],
},
})
).toEqual({
testKey: {
"##eventHandlerType": "Set State",
"parameters": {
"path": "testKey",
"value": "value"
}
}
});
});
parameters: {
path: "testKey",
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 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 builtins from "rollup-plugin-node-builtins"
import nodeglobals from "rollup-plugin-node-globals"
import { terser } from "rollup-plugin-terser"
const lodash_fp_exports = [
"find",

View File

@ -19,8 +19,6 @@ const appPackages = join(
const publicMain = appName => join(appPackages, appName, "public", "main")
const publicUnauth = appName =>
join(appPackages, appName, "public", "unauthenticated")
const nodeModules = appName =>
join(appPackages, appName, "node_modules", "@budibase", "client", "dist")
;(async () => {
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.
* @param {object} opts - configuration options for budibase client libary
*/
export const loadBudibase = async (opts) => {
export const loadBudibase = async opts => {
let componentLibraries = opts && opts.componentLibraries
const _window = (opts && opts.window) || window
const _localStorage = (opts && opts.localStorage) || localStorage
@ -33,8 +32,8 @@ export const loadBudibase = async (opts) => {
: "/" + trimSlash(frontendDefinition.appRootPath)
if (!componentLibraries) {
const componentLibraryUrl = lib => frontendDefinition.appRootPath + "/" + trimSlash(lib)
const componentLibraryUrl = lib =>
frontendDefinition.appRootPath + "/" + trimSlash(lib)
componentLibraries = {}
for (let lib of frontendDefinition.componentLibraries) {
@ -46,25 +45,33 @@ export const loadBudibase = async (opts) => {
componentLibraries[builtinLibName] = builtins(_window)
const { initialisePage, screenStore, pageStore, routeTo, rootNode } = createApp(
const {
initialisePage,
screenStore,
pageStore,
routeTo,
rootNode,
} = createApp(
componentLibraries,
frontendDefinition,
backendDefinition,
user,
uiFunctions || {},
_window
_window,
rootNode
)
const route = _window.location
? _window.location.pathname.replace(frontendDefinition.appRootPath, "")
: "";
: ""
initialisePage(frontendDefinition.page, _window.document.body, route)
return {
rootNode: initialisePage(frontendDefinition.page, _window.document.body, route),
screenStore,
pageStore,
routeTo,
rootNode
rootNode,
}
}

View File

@ -47,7 +47,7 @@ export const attachChildren = initialiseOpts => (htmlElement, options) => {
uiFunctions,
htmlElement,
anchor,
getCurrentState
getCurrentState,
})
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 isContextBinding = binding => binding && binding.source === "context"
export const isContextBinding = binding =>
binding && binding.source === "context"
export const isEventBinding = binding => binding && binding.source === "event"
const hasBindingObject = prop =>
@ -50,7 +51,7 @@ const isBindingExpression = prop =>
prop.startsWith("route."))
const parseBindingExpression = prop => {
let [source, ...rest] = prop.split(".");
let [source, ...rest] = prop.split(".")
let path = rest.join(".")
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.
* @param {Array} eventHandlerProp - event handler array from component definition
*/
function bindComponentEventHandlers(eventHandlerProp) {
function bindComponentEventHandlers(
eventHandlerProp,
context,
getCurrentState
) {
const boundEventHandlers = []
for (let event of eventHandlerProp) {
const boundEventHandler = {
@ -177,23 +181,24 @@ function bindComponentEventHandlers(eventHandlerProp) {
continue
}
let paramValueSource;
let paramValueSource
if (paramBinding.source === "context") paramValueSource = context;
if (paramBinding.source === "state") paramValueSource = getCurrentState();
if (paramBinding.source === "context") paramValueSource = context
if (paramBinding.source === "state") paramValueSource = getCurrentState()
// The new dynamic event parameter bound to the relevant source
boundParameters[paramName] = eventContext => getState(
boundParameters[paramName] = eventContext =>
getState(
paramBinding.source === "event" ? eventContext : paramValueSource,
paramBinding.path,
paramBinding.fallback
);
)
}
boundEventHandler.parameters = boundParameters
boundEventHandlers.push(boundEventHandlers)
return boundEventHandlers;
return boundEventHandlers
}
}
@ -239,13 +244,17 @@ const _setup = (
}
if (isEventType(propValue)) {
const boundEventHandlers = bindComponentEventHandlers(propValue);
const boundEventHandlers = bindComponentEventHandlers(
propValue,
context,
getCurrentState
)
if (boundEventHandlers.length === 0) {
initialProps[propName] = doNothing
} else {
initialProps[propName] = async context => {
for (let handlerInfo of handlersInfos) {
for (let handlerInfo of boundEventHandlers) {
const handler = makeHandler(handlerTypes, handlerInfo)
await handler(context)
}

View File

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

View File

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

View File

@ -1,5 +1,5 @@
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 {
$,

View File

@ -5,7 +5,7 @@ import {
isSingleRecord,
getNodeForCollectionPath,
} 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 { folderStructureArray, allIdChars } from "../indexing/allIds"

View File

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

View File

@ -1,6 +1,6 @@
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 and reference type fields

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,8 @@
import fs from "fs"
import { mkdir } from "fs"
import { join } from "path"
import { promisify } from "es6-promisify"
mkdirp = promisify(mkdir)
const mkdirp = promisify(mkdir)
const getConfig = async () => {
const config = {
@ -13,15 +12,13 @@ const getConfig = async () => {
memory: {},
}
try {
await mkdir("./output")
} catch (e) {}
await mkdirp("./output")
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
}

View File

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

View File

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

View File

@ -1,14 +1,8 @@
import { eventsList } from "@budibase/core"
import { filter, union, has, map } from "lodash/fp"
import records from "./records"
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")
export const register = (app, logTimeElapsed, eventNamespaces = []) => {

View File

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

View File

@ -1,5 +1,5 @@
import { action, iterateActionTimes, iterateCollection } from "./helpers"
import { isUndefined, union, takeRight } from "lodash"
import { action, iterateActionTimes } from "./helpers"
import { isUndefined, union } from "lodash"
const createClient = (apis, getState) => async i => {
const client = apis.recordApi.getNew("/clients", "client")
@ -20,16 +20,6 @@ const createClient = (apis, getState) => async i => {
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 clients = await apis.viewApi.listItems("/clients/default")
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 => {
const state = {}
const getState = () => state
@ -64,9 +48,6 @@ export default apis => {
iterateActionTimes(recordsPerIteration)
),
/*action("Get client", getClient(apis, getState),
iterateCollection(() => takeRight(getState().clientKeys, recordsPerIteration))),*/
action("List Clients", listClients(apis, getState)),
]
@ -75,14 +56,6 @@ export default apis => {
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
return () => {

View File

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

View File

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

View File

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

View File

@ -1,28 +1,48 @@
<script>
import Checkbox from "./Checkbox.svelte";
import Label from "../Common/Label.svelte";
import Checkbox from "./Checkbox.svelte"
import Label from "../Common/Label.svelte"
export let label = "";
export let orientation = "row";
export let fullwidth = false;
export let onChange = selectedItems => {};
export let label = ""
export let orientation = "row"
export let fullwidth = false
export let onChange = selectedItems => {}
export let items = [];
export let items = []
export let disabled = false;
export let alignEnd = false;
let selectedItems = [];
export let disabled = false
export let alignEnd = false
let selectedItems = []
function handleonChange(item) {
if (!!item.checked) {
item.checked = !item.checked;
item.checked = !item.checked
} else {
item.checked = true;
item.checked = true
}
onChange(items.filter(i => i.checked));
onChange(items.filter(i => i.checked))
}
</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>
.checkbox-group {
display: flex;
@ -55,23 +75,3 @@
text-align: left;
}
</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";
export { default as Checkbox } from "./Checkbox.svelte";
export { default as Checkboxgroup } from "./CheckboxGroup.svelte";
import "./_style.scss"
export { default as Checkbox } from "./Checkbox.svelte"
export { default as Checkboxgroup } from "./CheckboxGroup.svelte"

View File

@ -1,7 +1,7 @@
export default class ClassBuilder {
constructor(block, defaultIgnoreList) {
this.block = `mdc-${block}`;
this.defaultIgnoreList = defaultIgnoreList; //will be ignored when building custom classes
this.block = `mdc-${block}`
this.defaultIgnoreList = defaultIgnoreList //will be ignored when building custom classes
}
/*
@ -10,32 +10,32 @@ export default class ClassBuilder {
All are optional
*/
build(params) {
if (!params) return this.block; //return block if nothing passed
const { props, elementName } = params;
let base = !!elementName ? `${this.block}__${elementName}` : this.block;
if (!props) return base;
return this._handleProps(base, props);
if (!params) return this.block //return block if nothing passed
const { props, elementName } = params
let base = elementName ? `${this.block}__${elementName}` : this.block
if (!props) return base
return this._handleProps(base, props)
}
//Easily grab a simple element class
elem(elementName) {
return this.build({ elementName });
return this.build({ elementName })
}
//use if a different base is needed than whats defined by this.block
debase(base, elementProps) {
if (!elementProps) return base;
return this._handleProps(base, elementProps);
if (!elementProps) return base
return this._handleProps(base, elementProps)
}
//proxies bindProps and checks for which elementProps exist before binding
_handleProps(base, elementProps) {
let cls = base;
const { modifiers, customs, extras } = elementProps;
if (!!modifiers) cls += this._bindProps(modifiers, base);
if (!!customs) cls += this._bindProps(customs, base, true);
if (!!extras) cls += ` ${extras.join(" ")}`;
return cls.trim();
let cls = base
const { modifiers, customs, extras } = elementProps
if (modifiers) cls += this._bindProps(modifiers, base)
if (customs) cls += this._bindProps(customs, base, true)
if (extras) cls += ` ${extras.join(" ")}`
return cls.trim()
}
/*
@ -53,22 +53,22 @@ export default class ClassBuilder {
!!value &&
(!this.defaultIgnoreList || !this.defaultIgnoreList.includes(value))
) {
let classBase = isCustom ? `bbmd-${base}` : `${base}`;
let valueType = typeof value;
let classBase = isCustom ? `bbmd-${base}` : `${base}`
let valueType = typeof value
if (valueType == "string" || valueType == "number") {
return isCustom
? ` ${classBase}--${this._convertCamel(property)}-${value}`
: ` ${classBase}--${value}`;
: ` ${classBase}--${value}`
} else if (valueType == "boolean") {
return ` ${classBase}--${this._convertCamel(property)}`;
return ` ${classBase}--${this._convertCamel(property)}`
}
}
})
.join("");
.join("")
}
_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>
import "@material/form-field/mdc-form-field.scss";
import ClassBuilder from "../ClassBuilder.js";
import { fieldStore } from "./FormfieldStore.js";
import { MDCFormField } from "@material/form-field";
import { onMount, onDestroy, setContext } from "svelte";
import "@material/form-field/mdc-form-field.scss"
import ClassBuilder from "../ClassBuilder.js"
import { fieldStore } from "./FormfieldStore.js"
import { MDCFormField } from "@material/form-field"
import { onMount, onDestroy, setContext } from "svelte"
const cb = new ClassBuilder("form-field");
const cb = new ClassBuilder("form-field")
let store;
const unsubscribe = fieldStore.subscribe(s => (store = s));
let store
const unsubscribe = fieldStore.subscribe(s => (store = s))
export let id = "";
export let label = "";
export let alignEnd = false;
export let id = ""
export let label = ""
export let alignEnd = false
let formField = null;
let formField = null
let modifiers = { alignEnd };
let props = { modifiers };
let modifiers = { alignEnd }
let props = { modifiers }
let blockClasses = cb.build({ props });
let blockClasses = cb.build({ props })
onMount(() => {
if (!!formField) fieldStore.set(new MDCFormField(formField));
setContext("BBMD:field-element", fieldStore);
});
if (!!formField) fieldStore.set(new MDCFormField(formField))
setContext("BBMD:field-element", fieldStore)
})
onDestroy(unsubscribe);
onDestroy(unsubscribe)
</script>
<div bind:this={formField} class={blockClasses}>

View File

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

View File

@ -1,12 +1,12 @@
<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
? `material-icons mdc-${iconContext}__icon`
: "material-icons";
: "material-icons"
</script>
<i class={cls}>{icon}</i>

View File

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

View File

@ -17,8 +17,6 @@
let tableElement
let initialied = false
$: {
if (tableElement && datatable && !initialied) {
const children = _bb.attachChildren(tableElement)
@ -43,7 +41,8 @@
</script>
<div bind:this={datatable} class={cb.build()}>
<table class={cb.elem`table`} aria-label="Material Design Datatable" bind:this={tableElement}>
</table>
<table
class={cb.elem`table`}
aria-label="Material Design Datatable"
bind:this={tableElement} />
</div>

View File

@ -8,7 +8,6 @@ const cb = _bb.getContext("BBMD:data-table:cb")
let tbody
$: tbody && _bb.attachChildren(tbody)
</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
$: element && _bb.attachChildren(element)
</script>
{#if isHeader}

View File

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

View File

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

View File

@ -1,79 +1,71 @@
<script>
import { onMount, getContext } from "svelte";
import { MDCList } from "@material/list";
import { MDCRipple } from "@material/ripple";
import ListItem from "./ListItem.svelte";
import ClassBuilder from "../ClassBuilder.js";
import { onMount, getContext } from "svelte"
import { MDCList } from "@material/list"
import { MDCRipple } from "@material/ripple"
import ListItem from "./ListItem.svelte"
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 instance = null;
let list = 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]
export let items = [];
export let singleSelection = false;
export let inputElement = null;
export let items = []
export let singleSelection = false
export let inputElement = null
let role = "listbox";
let role = "listbox"
onMount(() => {
if (!!list) {
instance = new MDCList(list);
instance.singleSelection = singleSelection;
instance.listElements.map(element => new MDCRipple(element));
instance = new MDCList(list)
instance.singleSelection = singleSelection
instance.listElements.map(element => new MDCRipple(element))
}
let context = getContext("BBMD:list:context");
let context = getContext("BBMD:list:context")
if (context === "menu") {
role = "menu";
role = "menu"
}
return () => {
instance && instance.destroy();
instance = null;
};
});
instance && instance.destroy()
instance = null
}
})
function handleSelectedItem(item) {
if (!item.disabled) {
if (singleSelection || inputElement === "radiobutton") {
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) {
items[idx].selected = !item.selected;
items[idx].selected = !item.selected
} else {
items[idx].selected = true;
items[idx].selected = true
}
onSelect(items.filter(item => item.selected));
onSelect(items.filter(item => item.selected))
}
}
$: useDoubleLine =
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 };
$: props = { modifiers };
$: listClass = cb.build({ props });
$: list && _bb.attachChildren(list)
$: modifiers = { variant }
$: props = { modifiers }
$: listClass = cb.build({ props })
</script>
<ul 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>
<ul bind:this={list} class={listClass} {role} />

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -117,22 +117,39 @@ export const props = {
CustomersIndexTable: indexDatatable(templateOptions)[0].props,
List: {
_component: "@budibase/materialdesign-components/List",
_children: [
{
_component: "@budibase/materialdesign-components/ListItem",
_children: [],
variant: "two-line",
singleSelection: true,
items: [
{
text: { primary: "Curry", secondary: "Chicken or Beef" },
text: "Curry",
secondaryText: "Chicken or Beef",
value: 0,
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,
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),
},
}

View File

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

View File

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

View File

@ -16,4 +16,4 @@ export {
} from "./Datatable"
export { default as indexDatatable } from "./Templates/indexDatatable"
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")
module.exports = config => ({
module.exports = () => ({
main: {
outputToFile: async ({ filename, content }) => {
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'}

View File

@ -11,26 +11,21 @@
html, body {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
}
</style>
<link rel='stylesheet' href='//my-styles.css'>
<link rel='stylesheet' href='/css/d121e1ecc6cf44f433213222e9ff5d40.css'>
<link rel='stylesheet' href='/css/7b7c05b78e05c06eb8d69475caadfea3.css'>
<link rel='stylesheet' href='/css/f66fc2928f7d850c946e619c1a1f3096.css'>
<script src='/_master/clientFrontendDefinition.js'></script>
<script src='/_master/clientBackendDefinition.js'></script>
<script src='/clientFrontendDefinition.js'></script>
<script src='/clientBackendDefinition.js'></script>
<script src='/budibase-client.js'></script>
<script>
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")
module.exports = async (context, datastoreModule, app, instance) => {
try {
const databaseManager = getDatabaseManager(
datastoreModule,
context.config.datastoreConfig
@ -35,7 +34,4 @@ module.exports = async (context, datastoreModule, app, instance) => {
)
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")
module.exports = async (context, datastoreModule, username, password) => {
try {
const { config } = context
const databaseManager = getDatabaseManager(
datastoreModule,
@ -19,9 +18,7 @@ module.exports = async (context, datastoreModule, username, password) => {
await databaseManager.createEmptyMasterDb()
const masterDbConfig = databaseManager.masterDatastoreConfig
const datastore = setupDatastore(
datastoreModule.getDatastore(masterDbConfig)
)
const datastore = setupDatastore(datastoreModule.getDatastore(masterDbConfig))
await initialiseData(datastore, constructHierarchy(masterDbAppDefinition))
@ -34,7 +31,4 @@ module.exports = async (context, datastoreModule, username, password) => {
await bbMaster.authApi.createUser(user, 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
// copy master into /master/latest
if (await pathExists(runtimePackagesDirectory)) {
@ -26,16 +28,6 @@ module.exports = async (context, bbMaster, latestAppsFolder) => {
await mkdir(runtimePackagesDirectory)
/*
const allApps = await bbMaster
.indexApi
.listItems("/all_applications");
for(let app of allApps) {
app.
}
*/
const apps = {
_master: masterAppPackage(context),
}

View File

@ -141,7 +141,11 @@ module.exports = (config, app) => {
})
.get("/_builder/api/:appname/components", async ctx => {
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
} catch (e) {
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) */,
renew: false /** (boolean) renew session when session is nearly expired, so we can always keep user logged in. (default is false)*/,
store: {
get: async (key, maxAge, { rolling }) => ({ key }),
set: async (key, sess, maxAge, { rolling, changed }) => ({ key }),
destroy: async key => ({}),
get: async key => ({ key }),
set: async key => ({ key }),
destroy: async () => ({}),
},
}

View File

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

View File

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

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