Browse Source

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

master
Michael Shanks 7 years ago
parent
commit
634a7a8c3f
  1. 23
      .eslintrc.json
  2. 35
      .github/workflows/budibase_ci.yml
  3. 7
      .prettierrc
  4. 12
      package.json
  5. 1
      packages/builder/package.json
  6. 54
      packages/builder/rollup.config.js
  7. 118
      packages/builder/src/builderStore/generate_css.js
  8. 20
      packages/builder/src/builderStore/store.js
  9. 7
      packages/builder/src/builderStore/uuid.js
  10. 53
      packages/builder/src/common/ActionButton.svelte
  11. 9
      packages/builder/src/common/Icons/Events.svelte
  12. 19
      packages/builder/src/common/Icons/Pencil.svelte
  13. 2
      packages/builder/src/common/Icons/index.js
  14. 27
      packages/builder/src/common/Input.svelte
  15. 3
      packages/builder/src/common/Inputs/InputGroup.svelte
  16. 63
      packages/builder/src/common/Modal.svelte
  17. 23
      packages/builder/src/common/PlusButton.svelte
  18. 55
      packages/builder/src/common/Select.svelte
  19. 11
      packages/builder/src/userInterface/ComponentPanel.svelte
  20. 6
      packages/builder/src/userInterface/ComponentsHierarchyChildren.svelte
  21. 6
      packages/builder/src/userInterface/CurrentItemPreview.svelte
  22. 88
      packages/builder/src/userInterface/EventListSelector.svelte
  23. 105
      packages/builder/src/userInterface/EventSelector.svelte
  24. 164
      packages/builder/src/userInterface/EventsEditor/EventEditorModal.svelte
  25. 152
      packages/builder/src/userInterface/EventsEditor/EventsEditor.svelte
  26. 148
      packages/builder/src/userInterface/EventsEditor/HandlerSelector.svelte
  27. 1
      packages/builder/src/userInterface/EventsEditor/index.js
  28. 36
      packages/builder/src/userInterface/LayoutEditor.svelte
  29. 2
      packages/builder/src/userInterface/PropsView.svelte
  30. 7
      packages/builder/src/userInterface/StateBindingControl.svelte
  31. 337
      packages/builder/tests/generate_css.spec.js
  32. 2
      packages/client/src/render/initialiseChildren.js
  33. 6
      packages/client/src/render/renderComponent.js
  34. 12
      packages/core/.eslintrc.json
  35. 6
      packages/core/package.json
  36. 2
      packages/server/app.js
  37. 42880
      packages/server/appPackages/_master/public/main/budibase-client.js
  38. 2
      packages/server/appPackages/_master/public/main/budibase-client.js.map
  39. 42880
      packages/server/appPackages/_master/public/unauthenticated/budibase-client.js
  40. 2
      packages/server/appPackages/_master/public/unauthenticated/budibase-client.js.map
  41. 42880
      packages/server/appPackages/testApp/public/main/budibase-client.js
  42. 2
      packages/server/appPackages/testApp/public/main/budibase-client.js.map
  43. 42880
      packages/server/appPackages/testApp/public/unauthenticated/budibase-client.js
  44. 2
      packages/server/appPackages/testApp/public/unauthenticated/budibase-client.js.map
  45. 42880
      packages/server/appPackages/testApp2/public/main/budibase-client.js
  46. 2
      packages/server/appPackages/testApp2/public/main/budibase-client.js.map
  47. 42880
      packages/server/appPackages/testApp2/public/unauthenticated/budibase-client.js
  48. 2
      packages/server/appPackages/testApp2/public/unauthenticated/budibase-client.js.map
  49. 5343
      yarn.lock

23
.eslintrc.json

@ -0,0 +1,23 @@
{
"env": {
"browser": true,
"es6": true,
"jest": true
},
"parserOptions": {
"ecmaVersion": 2019,
"sourceType": "module"
},
"ignorePatterns": ["node_modules", "dist", "public"],
"plugins": ["prettier", "svelte3"],
"extends": ["eslint:recommended"],
"overrides": [
{
"files": ["**/*.svelte"],
"processor": "svelte3/svelte3"
}
],
"rules": {
"prettier/prettier": "error"
}
}

35
.github/workflows/budibase_ci.yml

@ -0,0 +1,35 @@
name: Budibase CI
on:
# Trigger the workflow on push or pull request,
# but only for the master branch
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: yarn
- run: yarn lint
- run: yarn build
- run: yarn test
env:
CI: true
name: Budibase CI

7
.prettierrc

@ -0,0 +1,7 @@
{
"tabWidth": 2,
"semi": false,
"singleQuote": false,
"trailingComma": "es5",
"plugins": ["prettier-plugin-svelte"]
}

12
package.json

@ -2,7 +2,12 @@
"name": "root",
"private": true,
"devDependencies": {
"lerna": "^3.14.1"
"eslint": "^6.8.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-svelte3": "^2.7.3",
"lerna": "^3.14.1",
"prettier": "^1.19.1",
"prettier-plugin-svelte": "^0.7.0"
},
"dependencies": {},
"scripts": {
@ -10,6 +15,9 @@
"build": "lerna run build",
"initialise": "lerna run initialise",
"clean": "lerna clean",
"dev": "lerna run --parallel --stream dev:builder"
"dev": "lerna run --parallel --stream dev:builder",
"test": "lerna run test",
"lint": "eslint packages",
"format": "prettier --write \"{,!(node_modules)/**/}*.{js,jsx}\""
}
}

1
packages/builder/package.json

@ -6,6 +6,7 @@
"build": "rollup -c",
"start": "rollup -c -w",
"test": "jest",
"test:watch": "jest --watchAll",
"dev:builder": "rollup -c -w"
},
"jest": {

54
packages/builder/rollup.config.js

@ -11,34 +11,34 @@ import browsersync from "rollup-plugin-browsersync";
import proxy from "http-proxy-middleware";
const target = 'http://localhost:4001';
const _builderProxy = proxy('/_builder', {
target:"http://localhost:3000",
pathRewrite: {'^/_builder' : ''}
const _builderProxy = proxy('/_builder', {
target: "http://localhost:3000",
pathRewrite: { '^/_builder': '' }
});
const apiProxy = proxy(['/_builder/api/**', '/_builder/**/componentlibrary', '/_builder/**/componentlibraryGenerators'] , {
const apiProxy = proxy(['/_builder/api/**', '/_builder/**/componentlibrary', '/_builder/**/componentlibraryGenerators'], {
target,
logLevel: "debug",
changeOrigin: true,
cookieDomainRewrite: true,
onProxyReq(proxyReq) {
if (proxyReq.getHeader("origin")) {
proxyReq.setHeader("origin", target)
}
if (proxyReq.getHeader("origin")) {
proxyReq.setHeader("origin", target)
}
}
});
});
const production = !process.env.ROLLUP_WATCH;
const lodash_fp_exports = ["union", "reduce", "isUndefined", "cloneDeep", "split", "some", "map", "filter", "isEmpty", "countBy", "includes", "last", "find", "constant",
"take", "first", "intersection", "mapValues", "isNull", "has", "isInteger", "isNumber", "isString", "isBoolean", "isDate", "isArray", "isObject", "clone", "values", "keyBy", "isNaN",
"keys", "orderBy", "concat", "reverse", "difference", "merge", "flatten", "each", "pull", "join", "defaultCase", "uniqBy", "every", "uniqWith", "isFunction", "groupBy",
"differenceBy", "intersectionBy", "isEqual", "max", "sortBy", "assign", "uniq", "trimChars", "trimCharsStart", "isObjectLike", "flattenDeep", "indexOf", "isPlainObject",
"toNumber", "takeRight"];
const lodash_fp_exports = ["union", "reduce", "isUndefined", "cloneDeep", "split", "some", "map", "filter", "isEmpty", "countBy", "includes", "last", "find", "constant",
"take", "first", "intersection", "mapValues", "isNull", "has", "isInteger", "isNumber", "isString", "isBoolean", "isDate", "isArray", "isObject", "clone", "values", "keyBy", "isNaN",
"keys", "orderBy", "concat", "reverse", "difference", "merge", "flatten", "each", "pull", "join", "defaultCase", "uniqBy", "every", "uniqWith", "isFunction", "groupBy",
"differenceBy", "intersectionBy", "isEqual", "max", "sortBy", "assign", "uniq", "trimChars", "trimCharsStart", "isObjectLike", "flattenDeep", "indexOf", "isPlainObject",
"toNumber", "takeRight", "toPairs"];
const lodash_exports = ["flow", "join", "replace", "trim", "dropRight", "takeRight", "head", "reduce",
"tail", "startsWith", "findIndex", "merge",
"assign", "each", "find", "orderBy", "union"];
const lodash_exports = ["flow", "join", "replace", "trim", "dropRight", "takeRight", "head", "reduce",
"tail", "startsWith", "findIndex", "merge",
"assign", "each", "find", "orderBy", "union"];
const outputpath = "../server/builder";
@ -63,7 +63,7 @@ export default {
{ src: 'src/favicon.png', dest: outputpath },
{ src: 'src/assets', dest: outputpath },
{ src: 'node_modules/@budibase/client/dist/budibase-client.esm.mjs', dest: outputpath },
]
]
}),
svelte({
@ -80,28 +80,28 @@ export default {
resolve({
browser: true,
dedupe: importee => {
return importee === 'svelte'
|| importee.startsWith('svelte/')
|| coreExternal.includes(importee);
return importee === 'svelte'
|| importee.startsWith('svelte/')
|| coreExternal.includes(importee);
}
}),
commonjs({
namedExports: {
"lodash/fp": lodash_fp_exports,
"lodash":lodash_exports,
"lodash": lodash_exports,
"shortid": ["generate"]
}
}),
url({
limit: 0,
include: ["**/*.woff2", "**/*.png"],
limit: 0,
include: ["**/*.woff2", "**/*.png"],
fileName: "[dirname][name][extname]",
emitFiles: true
}),
url({
limit: 0,
include: ["**/*.css"],
limit: 0,
include: ["**/*.css"],
fileName: "[name][extname]",
emitFiles: true
}),
@ -113,7 +113,7 @@ export default {
!production && livereload(outputpath),
!production && browsersync({
server: outputpath,
middleware: [apiProxy,_builderProxy]
middleware: [apiProxy, _builderProxy]
}),
// If we're building for production (npm run build

118
packages/builder/src/builderStore/generate_css.js

@ -0,0 +1,118 @@
import { filter, map, reduce, toPairs } from "lodash/fp";
import { pipe } from "../common/core";
const self = n => n;
const join_with = delimiter => a => a.join(delimiter);
const empty_string_to_unset = s => s.length ? s : "0";
const add_suffix = suffix => s => s + suffix;
export const make_margin = (values) => pipe(values, [
map(empty_string_to_unset),
map(add_suffix('px')),
join_with(' ')
]);
const tap = message => x => {
console.log(x);
return x;
}
const css_map = {
templaterows: {
name: 'grid-template-columns',
generate: self
},
templatecolumns: {
name: 'grid-template-rows',
generate: self
},
gridarea: {
name: 'grid-area',
generate: make_margin
},
gap: {
name: 'grid-gap',
generate: n => `${n}px`
},
columnstart: {
name: 'grid-column-start',
generate: self
},
columnend: {
name: 'grid-column-end',
generate: self
},
rowstart: {
name: 'grid-row-start',
generate: self
},
rowend: {
name: 'grid-row-end',
generate: self
},
padding: {
name: 'padding',
generate: make_margin
},
margin: {
name: 'margin',
generate: make_margin
},
zindex: {
name: 'z-index',
generate: self
}
}
export const generate_rule = ([name, values]) =>
`${css_map[name].name}: ${css_map[name].generate(values)};`
const handle_grid = (acc, [name, value]) => {
let tmp = [];
if (name === 'row' || name === 'column') {
if (value[0]) tmp.push([`${name}start`, value[0]]);
if (value[1]) tmp.push([`${name}end`, value[1]]);
return acc.concat(tmp)
}
return acc.concat([[name, value]]);
}
const object_to_css_string = [
toPairs,
reduce(handle_grid, []),
filter(v => Array.isArray(v[1]) ? v[1].some(s => s.length) : v[1].length),
map(generate_rule),
join_with('\n'),
];
export const generate_css = ({ layout, position }) => {
let _layout = pipe(layout, object_to_css_string);
_layout = _layout.length ? _layout + "\ndisplay: grid;" : _layout;
return {
layout: _layout,
position: pipe(position, object_to_css_string)
}
}
const apply_class = (id, name, styles) => `.${name}-${id} {\n${styles}\n}`;
export const generate_screen_css = (component_array) => {
let styles = "";
for (let i = 0; i < component_array.length; i += 1) {
const { _styles, _id, _children } = component_array[i];
const { layout, position } = generate_css(_styles);
styles += apply_class(_id, 'pos', position) + "\n";
styles += apply_class(_id, 'lay', layout) + "\n";
if (_children && _children.length) {
styles += generate_screen_css(_children) + "\n";
}
}
return styles.trim();
}

20
packages/builder/src/builderStore/store.js

@ -4,7 +4,7 @@ import {
import {
filter, cloneDeep, sortBy,
map, last, keys, concat, keyBy,
find, isEmpty, reduce, values, isEqual
find, isEmpty, values,
} from "lodash/fp";
import {
pipe, getNode, validate,
@ -17,11 +17,13 @@ import api from "./api";
import { isRootComponent, getExactComponent } from "../userInterface/pagesParsing/searchComponents";
import { rename } from "../userInterface/pagesParsing/renameScreen";
import {
getNewComponentInfo, getScreenInfo, getComponentInfo
getNewComponentInfo, getScreenInfo,
} from "../userInterface/pagesParsing/createProps";
import {
loadLibs, loadLibUrls, loadGeneratorLibs
} from "./loadComponentLibraries";
import { uuid } from './uuid';
import { generate_screen_css } from './generate_css';
let appname = "";
@ -710,7 +712,8 @@ const addChildComponent = store => component => {
const component_definition = Object.assign(
cloneDeep(newComponent.fullProps), {
_component: component,
_layout: {}
_styles: { position: {}, layout: {} },
_id: uuid()
})
if (children) {
@ -729,6 +732,8 @@ const addChildComponent = store => component => {
_saveScreen(store, s, s.currentFrontEndItem);
_saveScreen(store, s, s.currentFrontEndItem);
return s;
})
}
@ -751,12 +756,13 @@ const setComponentProp = store => (name, value) => {
})
}
const setComponentStyle = store => (name, value) => {
const setComponentStyle = store => (type, name, value) => {
store.update(s => {
if (!s.currentComponentInfo._layout) {
s.currentComponentInfo._layout = {};
if (!s.currentComponentInfo._styles) {
s.currentComponentInfo._styles = {};
}
s.currentComponentInfo._layout[name] = value;
s.currentComponentInfo._styles[type][name] = value;
s.currentFrontEndItem._css = generate_screen_css(s.currentFrontEndItem.props._children)
// save without messing with the store
_save(s.appname, s.currentFrontEndItem, store, s)

7
packages/builder/src/builderStore/uuid.js

@ -0,0 +1,7 @@
export function uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0,
v = c == 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}

53
packages/builder/src/common/ActionButton.svelte

@ -0,0 +1,53 @@
<script>
export let disabled = false;
export let hidden = false;
export let primary = true;
export let alert = false;
export let warning = false;
</script>
<style>
.primary {
color: #0055ff;
background: rgb(54, 133, 249, 0.1);
}
.alert {
color: rgba(255, 0, 31, 1);
background: rgba(255, 0, 31, 0.1);;
}
.button {
font-size: 18px;
font-weight: bold;
border-radius: 5px;
border: none;
width: 167px;
height: 64px;
}
.button:hover {
cursor: pointer;
}
.button:disabled {
color: rgba(22, 48, 87, 0.2);
cursor: default;
background: transparent;
}
.hidden {
visibility: hidden;
}
</style>
<button
on:click
class="button"
class:hidden
class:primary
class:alert
class:warning
{disabled}>
<slot />
</button>

9
packages/builder/src/common/Icons/Events.svelte

@ -0,0 +1,9 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24">
<path fill="none" d="M0 0h24v24H0z" />
<path
d="M13 9h8L11 24v-9H4l9-15v9zm-2 2V7.22L7.532 13H13v4.394L17.263 11H11z" />
</svg>

After

Width:  |  Height:  |  Size: 228 B

19
packages/builder/src/common/Icons/Pencil.svelte

@ -0,0 +1,19 @@
<svg
on:click
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24">
<path fill="none" d="M0 0h24v24H0z" />
<path
d="M15.728 9.686l-1.414-1.414L5
17.586V19h1.414l9.314-9.314zm1.414-1.414l1.414-1.414-1.414-1.414-1.414 1.414
1.414 1.414zM7.242 21H3v-4.243L16.435 3.322a1 1 0 0 1 1.414 0l2.829 2.829a1
1 0 0 1 0 1.414L7.243 21z" />
</svg>
<style>
svg:hover {
cursor: pointer;
}
</style>

After

Width:  |  Height:  |  Size: 446 B

2
packages/builder/src/common/Icons/index.js

@ -4,3 +4,5 @@ export { default as TerminalIcon } from './Terminal.svelte';
export { default as InputIcon } from './Input.svelte';
export { default as ImageIcon } from './Image.svelte';
export { default as ArrowDownIcon } from './ArrowDown.svelte';
export { default as EventsIcon } from './Events.svelte';
export { default as PencilIcon } from './Pencil.svelte';

27
packages/builder/src/common/Input.svelte

@ -0,0 +1,27 @@
<script>
export let value = "";
</script>
<style>
input {
display: block;
font-size: 14px;
font-family: sans-serif;
font-weight: 500;
color: #163057;
line-height: 1.3;
padding: 1em 2.6em 0.9em 1.4em;
width: 100%;
max-width: 100%;
box-sizing: border-box;
margin: 0;
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
background: #fff;
border: 1px solid #ccc;
height: 50px;
}
</style>
<input type="text" on:change bind:value />

3
packages/builder/src/common/Inputs/InputGroup.svelte

@ -2,6 +2,7 @@
export let meta = [];
export let size = '';
export let values = [];
export let type = "number";
export let onStyleChanged = () => {};
let _values = values.map(v => v);
@ -11,7 +12,7 @@
<div class="inputs {size}">
{#each meta as { placeholder }, i}
<input type="number"
<input {type}
placeholder="{placeholder}"
value={values[i]}
on:input={(e) => _values[i] = e.target.value} />

63
packages/builder/src/common/Modal.svelte

@ -1,41 +1,44 @@
<script>
import UIkit from "uikit";
import UIkit from "uikit";
export let isOpen = false;
export let onClosed = () => {};
export let id = "";
export let isOpen = false;
export let onClosed = () => {};
export let id = "";
let ukModal;
let listenerAdded = false;
let ukModal;
let listenerAdded = false;
$: {
if(ukModal && !listenerAdded) {
listenerAdded = true;
ukModal.addEventListener("hidden", onClosed);
$: {
if (ukModal && !listenerAdded) {
listenerAdded = true;
ukModal.addEventListener("hidden", onClosed);
}
if(ukModal) {
if(isOpen) {
UIkit.modal(ukModal).show();
} else {
UIkit.modal(ukModal).hide();
}
if (ukModal) {
if (isOpen) {
UIkit.modal(ukModal).show();
} else {
UIkit.modal(ukModal).hide();
}
}
}
}
</script>
<div bind:this={ukModal} uk-modal {id}>
<div class="uk-modal-dialog uk-modal-body" uk-overflow-auto>
<slot />
</div>
</div>
<style>
.uk-modal-dialog {
border-radius: 0.3rem;
width: 60%;
height: 80vh;
display: flex;
flex-direction: column;
}
</style>
.uk-modal-dialog {
border-radius: .3rem;
}
</style>
<div bind:this={ukModal} uk-modal {id}>
<div class="uk-modal-dialog uk-modal-body" uk-overflow-auto>
{#if onClosed}
<button class="uk-modal-close-default" type="button" uk-close />
{/if}
<slot />
</div>
</div>

23
packages/builder/src/common/PlusButton.svelte

@ -0,0 +1,23 @@
<style>
button {
cursor: pointer;
outline: none;
border: none;
border-radius: 5px;
background: rgba(249, 249, 249, 1);
width: 1.8rem;
height: 1.8rem;
padding-bottom: 10px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2rem;
font-weight: 700;
color: rgba(22, 48, 87, 1);
}
</style>
<button on:click>+</button>

55
packages/builder/src/common/Select.svelte

@ -0,0 +1,55 @@
<script>
import getIcon from "./icon";
export let value;
</script>
<style>
.select-container {
padding-bottom: 10px;
font-size: 0.9rem;
color: var(--secondary50);
font-weight: bold;
position: relative;
}
select {
display: block;
font-size: 14px;
font-family: sans-serif;
font-weight: 500;
color: #163057;
line-height: 1.3;
padding: 1em 2.6em 0.9em 1.4em;
width: 100%;
max-width: 100%;
box-sizing: border-box;
margin: 0;
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
background: #fff;
border: 1px solid #ccc;
height: 50px;
}
.arrow {
position: absolute;
right: 10px;
top: 0;
bottom: 0;
margin: auto;
width: 30px;
height: 30px;
pointer-events: none;
color: var(--primary100);
}
</style>
<div class="select-container">
<select on:change {value}>
<slot />
</select>
<span class="arrow">
{@html getIcon('chevron-down', '24')}
</span>
</div>

11
packages/builder/src/userInterface/ComponentPanel.svelte

@ -2,9 +2,10 @@
import PropsView from "./PropsView.svelte";
import { store } from "../builderStore";
import IconButton from "../common/IconButton.svelte";
import { LayoutIcon, PaintIcon, TerminalIcon } from '../common/Icons/';
import { LayoutIcon, PaintIcon, TerminalIcon, EventsIcon } from '../common/Icons/';
import CodeEditor from './CodeEditor.svelte';
import LayoutEditor from './LayoutEditor.svelte';
import EventsEditor from "./EventsEditor";
let current_view = 'props';
@ -17,6 +18,7 @@
const onPropChanged = store.setComponentProp;
const onStyleChanged = store.setComponentStyle;
</script>
<div class="root">
@ -36,6 +38,11 @@
<TerminalIcon />
</button>
</li>
<li>
<button class:selected={current_view === 'events'} on:click={() => current_view = 'events'}>
<EventsIcon />
</button>
</li>
</ul>
{#if !componentInfo.component}
@ -45,6 +52,8 @@
<PropsView {componentInfo} {components} {onPropChanged} />
{:else if current_view === 'layout'}
<LayoutEditor {onStyleChanged} {componentInfo}/>
{:else if current_view === 'events'}
<EventsEditor {componentInfo} {components} {onPropChanged} />
{:else}
<CodeEditor />
{/if}

6
packages/builder/src/userInterface/ComponentsHierarchyChildren.svelte

@ -1,13 +1,10 @@
<script>
import { last } from "lodash/fp";
import { pipe } from "../common/core";
export let components = [];
export let currentComponent;
export let onSelect = () => {};
export let level = 0;
const capitalise = s => s.substring(0,1).toUpperCase() + s.substring(1);
const get_name = s => last(s.split('/'));
const get_capitalised_name = name => pipe(name, [get_name,capitalise]);
@ -38,18 +35,15 @@
padding-left: 0;
margin: 0;
}
.item {
display: block;
padding: 11px 67px;
border-radius: 3px;
}
.item:hover {
background: #fafafa;
cursor: pointer;
}
.selected {
color: var(--button-text);
background: var(--background-button)!important;

6
packages/builder/src/userInterface/CurrentItemPreview.svelte

@ -4,7 +4,11 @@
import { pipe } from "../common/core";
import { buildPropsHierarchy } from "./pagesParsing/buildPropsHierarchy";
let iframe;
$: iframe && console.log(iframe.contentDocument.head.insertAdjacentHTML('beforeend', '<style></style>'))
$: hasComponent = !!$store.currentFrontEndItem;
$: styles = hasComponent ? $store.currentFrontEndItem._css : '';
$: stylesheetLinks = pipe($store.pages.stylesheets, [
map(s => `<link rel="stylesheet" href="${s}"/>`),
@ -27,6 +31,7 @@
{#if hasComponent}
<iframe style="height: 100%; width: 100%"
title="componentPreview"
bind:this={iframe}
srcdoc={
`<html>
@ -45,6 +50,7 @@
box-sizing: border-box;
padding: 20px;
}
${styles}
</style>
</head>
<body>

88
packages/builder/src/userInterface/EventListSelector.svelte

@ -1,88 +0,0 @@
<script>
import IconButton from "../common/IconButton.svelte";
import EventSelector from "./EventSelector.svelte";
import {
filter
} from "lodash/fp";
import {EVENT_TYPE_MEMBER_NAME} from "../common/eventHandlers";
export let parentProps;
export let propDef;
export let onValueChanged;
$: events = parentProps[propDef.____name];
const addHandler = () => {
const newHandler = {parameters:{}};
newHandler[EVENT_TYPE_MEMBER_NAME] = "";
events = [...events, newHandler];
onValueChanged(events);
}
const onEventHandlerChanged = (oldEvent) => (newEvent) => {
const indexOfOldEvent = events.indexOf(oldEvent);
const newEvents = [...events];
newEvents.splice(
events.indexOf(oldEvent),
1,
newEvent);
events = newEvents;
onValueChanged(events);
}
const removeHandler = (index) => () => {
events = filter(e => e !== events[index])(events);
onValueChanged(events);
}
</script>
<div class="root">
<div class="control-container">
{#each events as ev, index}
<div class="handler-container">
<EventSelector onChanged={onEventHandlerChanged(ev)}
onRemoved={removeHandler(index)}
event={ev} />
</div>
<div class="separator"></div>
{/each}
<div class="addelement-container"
on:click={addHandler}>
<IconButton icon="plus"
size="12"/>
</div>
</div>
</div>
<style>
.addelement-container {
cursor: pointer;
padding: 3px 0px;
text-align: center;
}
.addelement-container:hover {
background-color: var(--primary25);
margin-top: 5px;
}
.control-container {
padding-left: 3px;
background: var(--secondary10);
}
.separator {
width: 60%;
margin: 10px auto;
border-style:solid;
border-width: 1px 0 0 0;
border-color: var(--primary25);
}
</style>

105
packages/builder/src/userInterface/EventSelector.svelte

@ -1,105 +0,0 @@
<script>
import IconButton from "../common/IconButton.svelte";
import StateBindingControl from "./StateBindingControl.svelte";
import {
find, map, keys, reduce, keyBy
} from "lodash/fp";
import { pipe, userWithFullAccess } from "../common/core";
import { EVENT_TYPE_MEMBER_NAME, allHandlers } from "../common/eventHandlers";
import { store } from "../builderStore";
export let event;
export let onChanged;
export let onRemoved;
let eventType;
let parameters = [];
$: events = allHandlers(
{hierarchy: $store.hierarchy},
userWithFullAccess({
hierarchy: s.hierarchy,
actions: keyBy("name")($store.actions)
})
);
$: if(event) {
eventType = event[EVENT_TYPE_MEMBER_NAME];
parameters = pipe(event.parameters, [
keys,
map(k => ({name:k, value:event.parameters[k]}))
]);
} else {
eventType = "";
parameters = [];
}
const eventChanged = (type, parameters) => {
const paramsAsObject = reduce(
(obj, p) => {
obj[p.name] = p.value;
return obj;
}
, {}
)(parameters)
const ev = {};
ev[EVENT_TYPE_MEMBER_NAME]=type;
ev.parameters = paramsAsObject;
onChanged(ev);
}
const eventTypeChanged = (ev) => {
const eType = find(e => e.name === ev.target.value)(events);
const emptyParameters = map(p => ({name:p, value:""}))(eType.parameters);
eventChanged(eType.name, emptyParameters);
}
const onParameterChanged = index => val => {
const newparameters = [...parameters];
newparameters[index].value = val;
eventChanged(eventType, newparameters);
}
</script>
<div class="type-selector-container">
<select class="type-selector uk-select uk-form-small " value={eventType} on:change={eventTypeChanged}>
<option></option>
{#each events as ev}
<option value={ev.name}>{ev.name}</option>
{/each}
</select>
<IconButton icon="trash"
size="12"
on:click={onRemoved}/>
</div>
{#if parameters}
{#each parameters as p, index}
<div>
{p.name}
</div>
<StateBindingControl onChanged={onParameterChanged(index)}
value={p.value} />
{/each}
{/if}
<style>
.type-selector-container {
display: flex;
}
.type-selector {
border-color: var(--primary50);
border-radius: 2px;
width: 50px;
flex: 1 0 auto;
}
</style>

164
packages/builder/src/userInterface/EventsEditor/EventEditorModal.svelte

@ -0,0 +1,164 @@
<script>
import Modal from "../../common/Modal.svelte";
import HandlerSelector from "./HandlerSelector.svelte";
import IconButton from "../../common/IconButton.svelte";
import ActionButton from "../../common/ActionButton.svelte";
import PlusButton from "../../common/PlusButton.svelte";
import Select from "../../common/Select.svelte";
import Input from "../../common/Input.svelte";
import getIcon from "../../common/icon";
import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers";
export let event;
export let eventOptions;
export let open;
export let onClose;
export let onPropChanged;
let eventType = "onClick";
let draftEventHandler = { parameters: [] };
$: eventData = event || { handlers: [] };
const closeModal = () => {
onClose();
draftEventHandler = { parameters: [] };
eventData = { handlers: [] };
};
const updateEventHandler = (updatedHandler, index) => {
eventData.handlers[index] = updatedHandler;
};
const updateDraftEventHandler = updatedHandler => {
draftEventHandler = updatedHandler;
};
const deleteEventHandler = index => {
eventData.handlers.splice(index, 1);
eventData = eventData;
};
const createNewEventHandler = handler => {
const newHandler = handler || {
parameters: {},
[EVENT_TYPE_MEMBER_NAME]: ""
};
eventData.handlers.push(newHandler);
eventData = eventData;
};
const deleteEvent = () => {
onPropChanged(eventType, []);
closeModal();
};
const saveEventData = () => {
onPropChanged(eventType, eventData.handlers);
closeModal();
};
</script>
<style>
h2 {
color: var(--primary100);
font-size: 20px;
font-weight: bold;
margin-bottom: 0;
}
h5 {
color: rgba(22, 48, 87, 0.6);
font-size: 15px;
margin: 0;
}
.event-options {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
}
.actions,
header {
display: flex;
justify-content: space-between;
align-items: center;
}
.actions {
margin-top: auto;
}
header {
margin-top: 30px;
margin-bottom: 10px;
}
a {
color: rgba(22, 48, 87, 0.6);
font-size: 12px;
margin-top: 0;
}
</style>
<Modal bind:isOpen={open} onClosed={closeModal}>
<h2>
{eventData.name ? `${eventData.name} Event` : 'Create a New Component Event'}
</h2>
<a href="https://docs.budibase.com/" target="_blank">
Click here to learn more about component events
</a>
<div class="event-options">
<div>
<header>
<h5>Event Type</h5>
{@html getIcon('info', 20)}
</header>
<Select :value={eventType}>
{#each eventOptions as option}
<option value={option.name}>{option.name}</option>
{/each}
</Select>
</div>
</div>
<header>
<h5>Event Action(s)</h5>
{@html getIcon('info', 20)}
</header>
<HandlerSelector
newHandler
onChanged={updateDraftEventHandler}
onCreate={() => {
createNewEventHandler(draftEventHandler);
draftEventHandler = { parameters: [] };
}}
handler={draftEventHandler} />
{#if eventData}
{#each eventData.handlers as handler, index}
<HandlerSelector
{index}
onChanged={updateEventHandler}
onRemoved={() => deleteEventHandler(index)}
{handler} />
{/each}
{/if}
<div class="actions">
<ActionButton
alert
disabled={eventData.handlers.length === 0}
hidden={!eventData.name}
on:click={deleteEvent}>
Delete
</ActionButton>
<ActionButton
disabled={eventData.handlers.length === 0}
on:click={saveEventData}>
Save
</ActionButton>
</div>
</Modal>

152
packages/builder/src/userInterface/EventsEditor/EventsEditor.svelte

@ -0,0 +1,152 @@
<script>
import {
keys,
map,
some,
includes,
cloneDeep,
isEqual,
sortBy,
filter,
difference
} from "lodash/fp";
import { pipe } from "../../common/core";
import Checkbox from "../../common/Checkbox.svelte";
import Textbox from "../../common/Textbox.svelte";
import Dropdown from "../../common/Dropdown.svelte";
import PlusButton from "../../common/PlusButton.svelte";
import IconButton from "../../common/IconButton.svelte";
import Modal from "../../common/Modal.svelte";
import EventEditorModal from "./EventEditorModal.svelte";
import HandlerSelector from "./HandlerSelector.svelte";
import { PencilIcon } from "../../common/Icons";
import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers";
export const EVENT_TYPE = "event";
export let componentInfo;
export let onPropChanged = () => {};
export let components;
let modalOpen = false;
let events = [];
let selectedEvent = null;
$: {
events = Object.keys(componentInfo)
.filter(key => findType(key) === EVENT_TYPE)
.map(key => ({ name: key, handlers: componentInfo[key] }));
}
function findType(propName) {
if (!componentInfo._component) return;
return components.find(({ name }) => name === componentInfo._component)
.props[propName];
}
const openModal = event => {
selectedEvent = event;
modalOpen = true;
};
const closeModal = () => {
selectedEvent = null;
modalOpen = false;
};
</script>
<style>
h3 {
text-transform: uppercase;
font-size: 12px;
font-weight: 700;
color: #8997ab;
margin-bottom: 10px;
}
.root {
font-size: 10pt;
width: 100%;
}
.form-root {
display: flex;
flex-wrap: wrap;
}
header {
display: flex;
align-items: center;
justify-content: space-between;
}
.handler-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
border: 2px solid #f9f9f9;
height: 80px;
}
.hierarchy-item {
cursor: pointer;
padding: 11px 7px;
margin: 5px 0;
border-radius: 5px;
font-size: 1.5em;
width: 100%;
}
.hierarchy-item:hover {
background: #f9f9f9;
}
.event-name {
margin-top: 5px;
font-weight: bold;
font-size: 16px;
color: rgba(22, 48, 87, 0.6);
align-self: end;
}
.edit-text {
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
align-self: end;
justify-self: end;
font-size: 10px;
color: rgba(35, 65, 105, 0.4);
}
.selected {
color: var(--button-text);
background: var(--background-button) !important;
}
</style>
<header>
<h3>Events</h3>
<PlusButton on:click={() => openModal()} />
</header>
<div class="root">
<form class="uk-form-stacked form-root">
{#each events as event, index}
{#if event.handlers.length > 0}
<div
class="handler-container hierarchy-item {selectedEvent && selectedEvent.index === index ? 'selected' : ''}"
on:click={() => openModal({ ...event, index })}>
<span class="event-name">{event.name}</span>
<span class="edit-text">EDIT</span>
</div>
{/if}
{/each}
</form>
</div>
<EventEditorModal
{onPropChanged}
open={modalOpen}
onClose={closeModal}
eventOptions={events}
event={selectedEvent}
/>

148
packages/builder/src/userInterface/EventsEditor/HandlerSelector.svelte

@ -0,0 +1,148 @@
<script>
import IconButton from "../../common/IconButton.svelte";
import PlusButton from "../../common/PlusButton.svelte";
import Select from "../../common/Select.svelte";
import StateBindingControl from "../StateBindingControl.svelte";
import { find, map, keys, reduce, keyBy } from "lodash/fp";
import { pipe, userWithFullAccess } from "../../common/core";
import {
EVENT_TYPE_MEMBER_NAME,
allHandlers
} from "../../common/eventHandlers";
import { store } from "../../builderStore";
export let handler;
export let onCreate;
export let onChanged;
export let onRemoved;
export let index;
export let newHandler;
let eventOptions;
let handlerType;
let parameters = [];
$: eventOptions = allHandlers(
{ hierarchy: $store.hierarchy },
userWithFullAccess({
hierarchy: $store.hierarchy,
actions: keyBy("name")($store.actions)
})
);
$: {
if (handler) {
handlerType = handler[EVENT_TYPE_MEMBER_NAME];
parameters = Object.entries(handler.parameters).map(([name, value]) => ({
name,
value
}));
} else {
// Empty Handler
handlerType = "";
parameters = [];
}
}
const handlerChanged = (type, params) => {
const handlerParams = {};
for (let param of params) {
handlerParams[param.name] = param.value;
}
const updatedHandler = {
[EVENT_TYPE_MEMBER_NAME]: type,
parameters: handlerParams
};
onChanged(updatedHandler, index);
};
const handlerTypeChanged = e => {
const handlerType = eventOptions.find(
handler => handler.name === e.target.value
);
const defaultParams = handlerType.parameters.map(param => ({
name: param,
value: ""
}));
handlerChanged(handlerType.name, defaultParams);
};
const onParameterChanged = index => value => {
const newParams = [...parameters];
newParams[index].value = value;
handlerChanged(handlerType, newParams);
};
</script>
<style>
.type-selector-container {
display: flex;
justify-content: space-between;
align-items: center;
background: rgba(223, 223, 223, 0.5);
border: 1px solid #dfdfdf;
margin-bottom: 18px;
}
.handler-option {
display: flex;
flex-direction: column;
}
.new-handler {
background: #fff;
}
.handler-controls {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px;
padding: 22px;
}
.event-action-button {
margin-right: 20px;
}
span {
font-size: 12px;
margin-bottom: 5px;
}
</style>
<div class="type-selector-container {newHandler && 'new-handler'}">
<div class="handler-controls">
<div class="handler-option">
<span>Action</span>
<Select value={handlerType} on:change={handlerTypeChanged}>
<option />
{#each eventOptions as option}
<option value={option.name}>{option.name}</option>
{/each}
</Select>
</div>
{#if parameters}
{#each parameters as param, idx}
<div class="handler-option">
<span>{param.name}</span>
<StateBindingControl
onChanged={onParameterChanged(idx)}
value={param.value} />
</div>
{/each}
{/if}
</div>
<div class="event-action-button">
{#if parameters.length > 0}
{#if newHandler}
<PlusButton on:click={onCreate} />
{:else}
<IconButton icon="x" on:click={onRemoved} />
{/if}
{/if}
</div>
</div>

1
packages/builder/src/userInterface/EventsEditor/index.js

@ -0,0 +1 @@
export { default } from "./EventsEditor.svelte";

36
packages/builder/src/userInterface/LayoutEditor.svelte

@ -19,13 +19,16 @@
const single = [{ placeholder: '' }];
$: layout = componentInfo._layout;
$: layout = { ...componentInfo._styles.position, ...componentInfo._styles.layout };
$: layouts = {
templaterows: ['Grid Rows', single],
templatecolumns: ['Grid Columns', single],
};
$: positions = {
gridarea: ['Grid Area', tbrl, 'small'],
column: ['Column', se],
row: ['Row', se],
gap: ['Gap', single],
};
$: spacing = {
@ -41,15 +44,28 @@
</script>
<h3>Layout</h3>
<h3>Styles</h3>
<h4>Positioning</h4>
<div class="layout-pos">
{#each Object.entries(layouts) as [key, [name, meta, size]]}
<div class="grid">
<h5>{name}:</h5>
<InputGroup onStyleChanged={_value => onStyleChanged('layout',key, _value)}
values={layout[key] || newValue(meta.length)}
{meta}
{size}
type="text"/>
</div>
{/each}
</div>
<h4>Positioning</h4>
<div class="layout-pos">
{#each Object.entries(positions) as [key, [name, meta, size]]}
<div class="grid">
<h5>Grid Area:</h5>
<InputGroup onStyleChanged={_value => onStyleChanged(key, _value)}
<h5>{name}:</h5>
<InputGroup onStyleChanged={_value => onStyleChanged('position',key, _value)}
values={layout[key] || newValue(meta.length)}
{meta}
{size} />
@ -61,8 +77,8 @@
<div class="layout-spacing">
{#each Object.entries(spacing) as [key, [name, meta, size]]}
<div class="grid">
<h5>Grid Area:</h5>
<InputGroup onStyleChanged={_value => onStyleChanged(key, _value)}
<h5>{name}:</h5>
<InputGroup onStyleChanged={_value => onStyleChanged('position', key, _value)}
values={layout[key] || newValue(meta.length)}
{meta}
{size} />
@ -74,8 +90,8 @@
<div class="layout-layer">
{#each Object.entries(zindex) as [key, [name, meta, size]]}
<div class="grid">
<h5>Grid Area:</h5>
<InputGroup onStyleChanged={_value => onStyleChanged(key, _value)}
<h5>{name}:</h5>
<InputGroup onStyleChanged={_value => onStyleChanged('position', key, _value)}
values={layout[key] || newValue(meta.length)}
{meta}
{size} />

2
packages/builder/src/userInterface/PropsView.svelte

@ -12,7 +12,7 @@
let errors = [];
let props = {};
const props_to_ignore = ['_component','_children', '_layout'];
const props_to_ignore = ['_component','_children', '_styles', '_id'];
$: propDefs = componentInfo && Object.entries(componentInfo).filter(([name])=> !props_to_ignore.includes(name));

7
packages/builder/src/userInterface/StateBindingControl.svelte

@ -1,5 +1,6 @@
<script>
import IconButton from "../common/IconButton.svelte";
import Input from "../common/Input.svelte";
import {
isBinding, getBinding, setBinding
} from "../common/binding";
@ -119,9 +120,9 @@
{/each}
</select>
{:else}
<input on:change={ev => onChanged(ev.target.value)}
bind:value={value}
style="flex: 1 0 auto;" />
<Input
on:change={ev => onChanged(ev.target.value)}
bind:value={value} />
{/if}
</div>

337
packages/builder/tests/generate_css.spec.js

@ -0,0 +1,337 @@
import { generate_css, make_margin, generate_screen_css } from '../src/builderStore/generate_css.js';
describe('make_margin', () => {
test('it should generate a valid rule', () => {
expect(make_margin(["1", "1", "1", "1"])).toEqual('1px 1px 1px 1px')
})
test('empty values should output 0', () => {
expect(make_margin(["1", "1", "", ""])).toEqual('1px 1px 0px 0px')
expect(make_margin(["1", "", "", "1"])).toEqual('1px 0px 0px 1px')
expect(make_margin(["", "", "", ""])).toEqual('0px 0px 0px 0px')
})
})
describe('generate_css', () => {
test('it should generate a valid css rule: grid-area', () => {
expect(
generate_css({ layout: { gridarea: ["", "", "", ""] } })
).toEqual({
layout: '',
position: ''
});
})
test('it should generate a valid css rule: grid-gap', () => {
expect(
generate_css({ layout: { gap: "10" } })
).toEqual({
layout: 'grid-gap: 10px;\ndisplay: grid;',
position: ''
});
})
test('it should generate a valid css rule: column 1', () => {
expect(
generate_css({ position: { column: ["", ""] } }
)).toEqual({ layout: '', position: '' });
})
test('it should generate a valid css rule: column 2', () => {
expect(
generate_css({ position: { column: ["1", ""] } })
).toEqual({
position: 'grid-column-start: 1;',
layout: ''
});
})
test('it should generate a valid css rule: column 3', () => {
expect(
generate_css({ position: { column: ["", "1"] } })
).toEqual({
position: 'grid-column-end: 1;',
layout: ''
});
})
test('it should generate a valid css rule: column 4', () => {
expect(
generate_css({ position: { column: ["1", "1"] } })
).toEqual({
position: 'grid-column-start: 1;\ngrid-column-end: 1;',
layout: ''
});
})
test('it should generate a valid css rule: row 1', () => {
expect(
generate_css({ position: { row: ["", ""] } })
).toEqual({ layout: '', position: '' });
})
test('it should generate a valid css rule: row 2', () => {
expect(
generate_css({ position: { row: ["1", ""] } })
).toEqual({
position: 'grid-row-start: 1;',
layout: ''
});
})
test('it should generate a valid css rule: row 3', () => {
expect(
generate_css({ position: { row: ["", "1"] } })
).toEqual({
position: 'grid-row-end: 1;',
layout: ''
});
})
test('it should generate a valid css rule: row 4', () => {
expect(
generate_css({ position: { row: ["1", "1"] } })
).toEqual({
position: 'grid-row-start: 1;\ngrid-row-end: 1;',
layout: ''
});
})
test('it should generate a valid css rule: padding 1', () => {
expect(
generate_css({ position: { padding: ["1", "1", "1", "1"] } })
).toEqual({
position: 'padding: 1px 1px 1px 1px;',
layout: ''
});
})
test('it should generate a valid css rule: padding 2', () => {
expect(
generate_css({ position: { padding: ["1", "", "", "1"] } })
).toEqual({
position: 'padding: 1px 0px 0px 1px;',
layout: ''
});
})
test('it should generate a valid css rule: margin 1', () => {
expect(
generate_css({ position: { margin: ["1", "1", "1", "1"] } })
).toEqual({
position: 'margin: 1px 1px 1px 1px;',
layout: ''
});
})
test('it should generate a valid css rule: margin 2', () => {
expect(
generate_css({ position: { margin: ["1", "", "", "1"] } })
).toEqual({
position: 'margin: 1px 0px 0px 1px;',
layout: ''
});
})
test('it should generate a valid css rule: z-index 1', () => {
expect(
generate_css({ position: { zindex: "" } })
).toEqual({
position: '',
layout: ''
});
})
test('it should generate a valid css rule: z-index 2', () => {
expect(
generate_css({ position: { zindex: "1" } })
).toEqual({
position: 'z-index: 1;',
layout: ''
});
})
})
describe('generate_screen_css', () => {
test('it should compile the css for a list of components', () => {
const components = [
{
_styles: {
layout: { gridarea: ["", "", "", ""] },
position: { margin: ["1", "1", "1", "1"] }
},
_id: 1
},
{
_styles: {
layout: { gridarea: ["", "", "", ""] },
position: { margin: ["1", "1", "1", "1"] }
},
_id: 2
}, {
_styles: {
layout: { gridarea: ["", "", "", ""] },
position: { margin: ["1", "1", "1", "1"] }
},
_id: 3
}
, {
_styles: {
layout: { gridarea: ["", "", "", ""] },
position: { margin: ["1", "1", "1", "1"] }
},
_id: 4
}
]
const compiled = `.pos-1 {
margin: 1px 1px 1px 1px;
}
.lay-1 {
}
.pos-2 {
margin: 1px 1px 1px 1px;
}
.lay-2 {
}
.pos-3 {
margin: 1px 1px 1px 1px;
}
.lay-3 {
}
.pos-4 {
margin: 1px 1px 1px 1px;
}
.lay-4 {
}`
expect(generate_screen_css(components)).toEqual(compiled)
})
test('it should compile the css for a list of components', () => {
const components = [
{
_styles: {
layout: { gridarea: ["", "", "", ""] },
position: { margin: ["1", "1", "1", "1"] }
},
_id: 1,
_children: [
{
_styles: {
layout: { gridarea: ["", "", "", ""] },
position: { margin: ["1", "1", "1", "1"] }
},
_id: 2,
_children: [
{
_styles: {
layout: { gridarea: ["", "", "", ""] },
position: { margin: ["1", "1", "1", "1"] }
},
_id: 3,
_children: [
{
_styles: {
layout: { gridarea: ["", "", "", ""] },
position: { margin: ["1", "1", "1", "1"] }
},
_id: 4,
_children: [
{
_styles: {
layout: { gridarea: ["", "", "", ""] },
position: { margin: ["1", "1", "1", "1"] }
},
_id: 5,
_children: [
]
},
]
},
]
},
]
},
]
},
{
_styles: {
layout: { gridarea: ["", "", "", ""] },
position: { margin: ["1", "1", "1", "1"] }
},
_id: 6
}, {
_styles: {
layout: { gridarea: ["", "", "", ""] },
position: { margin: ["1", "1", "1", "1"] }
},
_id: 7
}
, {
_styles: {
layout: { gridarea: ["", "", "", ""] },
position: { margin: ["1", "1", "1", "1"] }
},
_id: 8
}
]
const compiled = `.pos-1 {
margin: 1px 1px 1px 1px;
}
.lay-1 {
}
.pos-2 {
margin: 1px 1px 1px 1px;
}
.lay-2 {
}
.pos-3 {
margin: 1px 1px 1px 1px;
}
.lay-3 {
}
.pos-4 {
margin: 1px 1px 1px 1px;
}
.lay-4 {
}
.pos-5 {
margin: 1px 1px 1px 1px;
}
.lay-5 {
}
.pos-6 {
margin: 1px 1px 1px 1px;
}
.lay-6 {
}
.pos-7 {
margin: 1px 1px 1px 1px;
}
.lay-7 {
}
.pos-8 {
margin: 1px 1px 1px 1px;
}
.lay-8 {
}`
expect(generate_screen_css(components)).toEqual(compiled)
})
})

2
packages/client/src/render/initialiseChildren.js

@ -27,6 +27,8 @@ export const _initialiseChildren = (initialiseOpts) =>
htmlElement.removeChild(htmlElement.firstChild);
}
}
htmlElement.classList.add(`lay-${treeNode.props._id}`)
const renderedComponents = [];
for(let childProps of childrenProps) {

6
packages/client/src/render/renderComponent.js

@ -23,6 +23,7 @@ export const renderComponent = ({
const thisNode = createTreeNode();
thisNode.context = componentContext;
thisNode.parentNode = parentNode;
thisNode.props = props;
parentNode.children.push(thisNode);
renderedNodes.push(thisNode);
@ -38,6 +39,10 @@ export const renderComponent = ({
thisNode.rootElement = htmlElement.children[
htmlElement.children.length - 1];
if (initialProps._id) {
thisNode.rootElement.classList.add(`pos-${initialProps._id}`)
}
}
if(func) {
@ -51,6 +56,7 @@ export const renderComponent = ({
export const createTreeNode = () => ({
context: {},
props: {},
rootElement: null,
parentNode: null,
children: [],

12
packages/core/.eslintrc.json

@ -1,12 +0,0 @@
{
"env": {
"browser": true,
"es6": true,
"jest": true
},
"extends": "eslint:recommended",
"parser": "babel-eslint",
"parserOptions": {
"sourceType": "module"
}
}

6
packages/core/package.json

@ -51,15 +51,9 @@
"@babel/plugin-transform-runtime": "^7.4.4",
"@babel/preset-env": "^7.4.5",
"@babel/runtime": "^7.4.5",
"babel-eslint": "^10.0.2",
"babel-jest": "^23.6.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"cross-env": "^5.1.4",
"eslint": "^5.3.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jsx-a11y": "^6.1.1",
"eslint-plugin-react": "^7.11.0",
"jest": "^24.8.0",
"readable-stream": "^3.1.1",
"regenerator-runtime": "^0.11.1",

2
packages/server/app.js

@ -14,7 +14,7 @@ module.exports = async (budibaseContext) => {
app.context.master,
config.latestPackagesFolder
);
app.use(koaBody({ multipart : true }));
app.use(koaBody({ multipart: true }));
app.use(router(config, app).routes());
return app.listen(config.port);
};

42880
packages/server/appPackages/_master/public/main/budibase-client.js

File diff suppressed because it is too large

2
packages/server/appPackages/_master/public/main/budibase-client.js.map

File diff suppressed because one or more lines are too long

42880
packages/server/appPackages/_master/public/unauthenticated/budibase-client.js

File diff suppressed because it is too large

2
packages/server/appPackages/_master/public/unauthenticated/budibase-client.js.map

File diff suppressed because one or more lines are too long

42880
packages/server/appPackages/testApp/public/main/budibase-client.js

File diff suppressed because it is too large

2
packages/server/appPackages/testApp/public/main/budibase-client.js.map

File diff suppressed because one or more lines are too long

42880
packages/server/appPackages/testApp/public/unauthenticated/budibase-client.js

File diff suppressed because it is too large

2
packages/server/appPackages/testApp/public/unauthenticated/budibase-client.js.map

File diff suppressed because one or more lines are too long

42880
packages/server/appPackages/testApp2/public/main/budibase-client.js

File diff suppressed because it is too large

2
packages/server/appPackages/testApp2/public/main/budibase-client.js.map

File diff suppressed because one or more lines are too long

42880
packages/server/appPackages/testApp2/public/unauthenticated/budibase-client.js

File diff suppressed because it is too large

2
packages/server/appPackages/testApp2/public/unauthenticated/budibase-client.js.map

File diff suppressed because one or more lines are too long

5343
yarn.lock

File diff suppressed because it is too large
Loading…
Cancel
Save