Browse Source

base analytics and settings

master
marblekirby 7 years ago
parent
commit
011aa9f2cc
  1. 3
      AUTHORS.md
  2. 4
      packages/builder/package.json
  3. 5
      packages/builder/rollup.config.js
  4. 2
      packages/builder/src/App.svelte
  5. 15
      packages/builder/src/accessLevels/AccessLevelsRoot.svelte
  6. 15
      packages/builder/src/actionsAndTriggers/ActionView.svelte
  7. 25
      packages/builder/src/actionsAndTriggers/Actions.svelte
  8. 50
      packages/builder/src/actionsAndTriggers/ActionsAndTriggersRoot.svelte
  9. 4
      packages/builder/src/actionsAndTriggers/TriggerView.svelte
  10. 24
      packages/builder/src/actionsAndTriggers/Triggers.svelte
  11. BIN
      packages/builder/src/assets/lato-latin-ext.woff2
  12. BIN
      packages/builder/src/assets/lato-latin.woff2
  13. BIN
      packages/builder/src/assets/roboto-v20-latin-ext_latin-300.woff
  14. BIN
      packages/builder/src/assets/roboto-v20-latin-ext_latin-300.woff2
  15. BIN
      packages/builder/src/assets/roboto-v20-latin-ext_latin-500.woff
  16. BIN
      packages/builder/src/assets/roboto-v20-latin-ext_latin-500.woff2
  17. BIN
      packages/builder/src/assets/roboto-v20-latin-ext_latin-700.woff
  18. BIN
      packages/builder/src/assets/roboto-v20-latin-ext_latin-700.woff2
  19. BIN
      packages/builder/src/assets/roboto-v20-latin-ext_latin-900.woff
  20. BIN
      packages/builder/src/assets/roboto-v20-latin-ext_latin-900.woff2
  21. BIN
      packages/builder/src/assets/roboto-v20-latin-ext_latin-regular.woff
  22. BIN
      packages/builder/src/assets/roboto-v20-latin-ext_latin-regular.woff2
  23. 2
      packages/builder/src/builderStore/api.js
  24. 11
      packages/builder/src/builderStore/loadComponentLibraries.js
  25. 28
      packages/builder/src/builderStore/store.js
  26. 4
      packages/builder/src/common/Button.svelte
  27. 5
      packages/builder/src/common/CodeArea.svelte
  28. 2
      packages/builder/src/common/DropdownButton.svelte
  29. 4
      packages/builder/src/common/Modal.svelte
  30. 25
      packages/builder/src/common/binding.js
  31. 1
      packages/builder/src/common/eventHandlers.js
  32. 2
      packages/builder/src/common/icon.js
  33. 10
      packages/builder/src/database/ActionsHeader.svelte
  34. 2
      packages/builder/src/database/FieldView.svelte
  35. 4
      packages/builder/src/database/HierarchyRow.svelte
  36. 55
      packages/builder/src/database/RecordView.svelte
  37. BIN
      packages/builder/src/favicon.ico
  38. BIN
      packages/builder/src/favicon.png
  39. 102
      packages/builder/src/fonts.css
  40. 19
      packages/builder/src/global.css
  41. 7
      packages/builder/src/main.js
  42. 6
      packages/builder/src/nav/BackendNav.svelte
  43. 7
      packages/builder/src/nav/HierarchyRow.svelte
  44. 4
      packages/builder/src/nav/NavItem.svelte
  45. 23
      packages/builder/src/userInterface/ComponentInstanceEditor.svelte
  46. 2
      packages/builder/src/userInterface/ComponentPropSelector.svelte
  47. 61
      packages/builder/src/userInterface/CurrentItemPreview.svelte
  48. 31
      packages/builder/src/userInterface/EditComponent.svelte
  49. 97
      packages/builder/src/userInterface/EventListSelector.svelte
  50. 104
      packages/builder/src/userInterface/EventSelector.svelte
  51. 6
      packages/builder/src/userInterface/PropArraySelector.svelte
  52. 48
      packages/builder/src/userInterface/PropControl.svelte
  53. 155
      packages/builder/src/userInterface/StateBindingControl.svelte
  54. 2
      packages/builder/src/userInterface/UserInterfaceRoot.svelte
  55. 3
      packages/builder/src/userInterface/pagesParsing/buildPropsHierarchy.js
  56. 2
      packages/builder/src/userInterface/pagesParsing/createProps.js
  57. 17
      packages/builder/src/userInterface/pagesParsing/types.js
  58. 30
      packages/builder/src/userInterface/pagesParsing/validateProps.js
  59. 12
      packages/builder/tests/createDefaultProps.spec.js
  60. 11
      packages/builder/tests/validateProps.spec.js
  61. 2
      packages/client/package.json
  62. 23
      packages/client/rollup.config.js
  63. 50
      packages/client/src/createApp.js
  64. 33
      packages/client/src/index.js
  65. 22
      packages/client/src/initialise.js
  66. 36
      packages/client/src/initialiseComponent.js
  67. 26
      packages/client/src/state/eventHandlers.js
  68. 34
      packages/client/src/state/getState.js
  69. 33
      packages/client/src/state/setState.js
  70. 118
      packages/client/src/state/stateBinding.js
  71. 146
      packages/client/tests/stateBinding.spec.js
  72. 2
      packages/server/appPackages/_master/public/main/budibase-client.js
  73. 2
      packages/server/appPackages/_master/public/unauthenticated/budibase-client.js
  74. 11
      packages/server/appPackages/testApp/components/Button.json
  75. 15
      packages/server/appPackages/testApp/components/LoginForm.json
  76. 9
      packages/server/appPackages/testApp/components/joeTextBox.json
  77. 2
      packages/server/appPackages/testApp/public/main/budibase-client.js
  78. 2
      packages/server/appPackages/testApp/public/unauthenticated/budibase-client.js
  79. 75
      packages/server/appPackages/testApp2/appDefinition.json
  80. 29
      packages/server/appPackages/testApp2/components/Primary Button.json
  81. 15
      packages/server/appPackages/testApp2/components/containers/two_columns.json
  82. 65
      packages/server/appPackages/testApp2/components/mike.json
  83. 10
      packages/server/appPackages/testApp2/pages.json
  84. 3
      packages/server/appPackages/testApp2/public/main/budibase-client.js
  85. 2
      packages/server/appPackages/testApp2/public/main/budibase-client.js.map
  86. 2
      packages/server/appPackages/testApp2/public/main/clientAppDefinition.js
  87. 18
      packages/server/appPackages/testApp2/public/main/index.html
  88. 3
      packages/server/appPackages/testApp2/public/unauthenticated/budibase-client.js
  89. 2
      packages/server/appPackages/testApp2/public/unauthenticated/budibase-client.js.map
  90. 2
      packages/server/appPackages/testApp2/public/unauthenticated/clientAppDefinition.js
  91. 18
      packages/server/appPackages/testApp2/public/unauthenticated/index.html
  92. 2
      packages/server/builder/budibase-client.esm.mjs
  93. 44
      packages/server/builder/bundle.css
  94. 106
      packages/server/builder/bundle.css.map
  95. 4322
      packages/server/builder/bundle.js
  96. 2
      packages/server/builder/bundle.js.map
  97. BIN
      packages/server/builder/favicon.png
  98. 102
      packages/server/builder/fonts.css
  99. 19
      packages/server/builder/global.css
  100. 11
      packages/server/utilities/builder/index.template.html

3
AUTHORS.md

@ -2,4 +2,5 @@ Contributors
===
* Michael Shanks - [@mjashanks](https://github.com/mjashanks)
* Daniel Loudon - [@danbudi](https://github.com/danbudi)
* Dan - [@danbudi](https://github.com/danbudi)
* Joe - [@joebudi](https://github.com/joebudi)

4
packages/builder/package.json

@ -33,6 +33,7 @@
]
},
"dependencies": {
"@budibase/client": "*",
"@nx-js/compiler-util": "^2.0.0",
"date-fns": "^1.29.0",
"feather-icons": "^4.21.0",
@ -42,8 +43,7 @@
"safe-buffer": "^5.1.2",
"shortid": "^2.2.8",
"string_decoder": "^1.2.0",
"uikit": "^3.1.7",
"universal-analytics": "^0.4.20"
"uikit": "^3.1.7"
},
"devDependencies": {
"@babel/core": "^7.5.5",

5
packages/builder/rollup.config.js

@ -33,7 +33,7 @@ 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", "isNumber", "isString", "isBoolean", "isDate", "isArray", "isObject", "clone", "values", "keyBy",
"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"];
"differenceBy", "intersectionBy", "isEqual", "max", "sortBy", "assign", "uniq", "trimChars", "trimCharsStart", "isObjectLike", "flattenDeep", "indexOf", "isPlainObject"];
const lodash_exports = ["toNumber", "flow", "isArray", "join", "replace", "trim", "dropRight", "takeRight", "head", "isUndefined", "isNull", "isNaN", "reduce", "isEmpty",
"constant", "tail", "includes", "startsWith", "findIndex", "isInteger", "isDate", "isString", "split", "clone", "keys", "isFunction", "merge", "has", "isBoolean", "isNumber",
@ -59,7 +59,8 @@ export default {
copy({
targets: [
{ src: 'src/index.html', dest: outputpath },
{ src: 'src/favicon.png', dest: outputpath }
{ src: 'src/favicon.png', dest: outputpath },
{ src: 'node_modules/@budibase/client/dist/budibase-client.esm.mjs', dest: outputpath }
]
}),

2
packages/builder/src/App.svelte

@ -48,7 +48,7 @@
main {
height: 100%;
width: 100%;
font-family: "Lato", Helvetica, Arial, sans-serif;
font-family: "Roboto", Helvetica, Arial, sans-serif;
}
.settings {

15
packages/builder/src/accessLevels/AccessLevelsRoot.svelte

@ -100,16 +100,19 @@ const getPermissionsString = perms => {
<style>
.root {
padding:10px;
height: 100%;
position: relative;
padding: 1.5rem;
}
.edit-button {
cursor:pointer;
color: var(--white);
.actions-header {
flex: 0 1 auto;
}
tr:hover .edit-button {
color: var(--secondary75);
.node-view {
overflow-y: auto;
flex: 1 1 auto;
}

15
packages/builder/src/actionsAndTriggers/ActionView.svelte

@ -81,8 +81,8 @@ const cancel = () => {
<div class=" uk-form-stacked" style="margin-bottom: 20px">
<label class="uk-form-label">Default Options</label>
<div class="uk-grid-small" uk-grid>
<input class="uk-input uk-width-1-4" placeholder="key" bind:value={optKey} >
<input class="uk-input uk-width-1-4" placeholder="value" bind:value={optValue} >
<input class="uk-input uk-width-1-4 uk-margin-right" placeholder="key" bind:value={optKey} >
<input class="uk-input uk-width-1-4 uk-margin-right" placeholder="value" bind:value={optValue} >
<Button color="primary-outline uk-width-1-4" on:click={addNewOption}>Add</Button>
</div>
<div style="margin-top: 10px">
@ -93,8 +93,8 @@ const cancel = () => {
</div>
<ButtonGroup>
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="secondary" grouped on:click={cancel}>Cancel</Button>
<Button color="secondary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button>
</ButtonGroup>
@ -104,7 +104,12 @@ const cancel = () => {
<style>
.root {
padding: 10px;
padding: 2rem;
border-radius: 2rem;
}
.uk-grid-small {
padding: 1rem;
}
.option-container {

25
packages/builder/src/actionsAndTriggers/Actions.svelte

@ -45,13 +45,13 @@ let actionEditingFinished = (action) => {
</script>
<h3>Actions</h3>
<h3 class="title">Actions</h3>
{#if actionsArray}
<table class="fields-table uk-table uk-table-small">
<table class="fields-table uk-table uk-table-small uk-table-striped">
<thead>
<tr>
<th>Description</th>
<th >Description</th>
<th>Behaviour Source</th>
<th>Behaviour Name</th>
<th>Default Options</th>
@ -61,10 +61,10 @@ let actionEditingFinished = (action) => {
<tbody>
{#each actionsArray as action}
<tr>
<td >{action.name}</td>
<td >{action.behaviourSource}</td>
<td >{action.behaviourName}</td>
<td >{@html getDefaultOptionsHtml(action.initialOptions)}</td>
<td class="table-content">{action.name}</td>
<td class="table-content">{action.behaviourSource}</td>
<td class="table-content">{action.behaviourName}</td>
<td class="table-content">{@html getDefaultOptionsHtml(action.initialOptions)}</td>
<td class="edit-button">
<span on:click={() => onActionEdit(action)}>{@html getIcon("edit")}</span>
<span on:click={() => onActionDelete(action)}>{@html getIcon("trash")}</span>
@ -92,12 +92,21 @@ let actionEditingFinished = (action) => {
.edit-button {
cursor:pointer;
color: var(--white);
color: var(--secondary25);
}
tr:hover .edit-button {
color: var(--secondary75);
}
.title {
margin: 3rem 0rem 0rem 0rem;
font-weight: 700;
}
.table-content {
font-weight: 500;
font-size: .9rem;
}
</style>

50
packages/builder/src/actionsAndTriggers/ActionsAndTriggersRoot.svelte

@ -85,31 +85,45 @@ let onTriggerDelete = (trigger) => {
</script>
<div class="root">
<ButtonGroup>
<Button color="secondary"
grouped
on:click={newAction}>Create New Action</Button>
<Button color="secondary"
grouped
on:click={newTrigger}>Create New Trigger</Button>
</ButtonGroup>
<Actions {editingActionIsNew} {editingAction}
{onActionEdit} {onActionDelete} {onActionSave}
{onActionCancel} />
<Triggers {editingTriggerIsNew} {editingTrigger}
{onTriggerEdit} {onTriggerDelete} {onTriggerSave}
{onTriggerCancel} />
<div class="actions-header">
<ButtonGroup>
<Button color="secondary"
grouped
on:click={newAction}>Create New Action</Button>
<Button color="tertiary"
grouped
on:click={newTrigger}>Create New Trigger</Button>
</ButtonGroup>
</div>
<div class="node-view">
<Actions {editingActionIsNew} {editingAction}
{onActionEdit} {onActionDelete} {onActionSave}
{onActionCancel} />
<Triggers {editingTriggerIsNew} {editingTrigger}
{onTriggerEdit} {onTriggerDelete} {onTriggerSave}
{onTriggerCancel} />
</div>
</div>
<style>
.root {
padding: 10px;
height: 100%;
position: relative;
padding: 1.5rem;
}
.actions-header {
flex: 0 1 auto;
}
.node-view {
overflow-y: auto;
flex: 1 1 auto;
}
</style>

4
packages/builder/src/actionsAndTriggers/TriggerView.svelte

@ -57,8 +57,8 @@ let save = () => {
</form>
<ButtonGroup>
<Button grouped on:click={save}>Save</Button>
<Button grouped on:click={cancel}>Cancel</Button>
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button>
</ButtonGroup>
</div>

24
packages/builder/src/actionsAndTriggers/Triggers.svelte

@ -27,10 +27,10 @@ let triggerEditingFinished = (trigger) => {
</script>
<h3>Triggers</h3>
<h3 class="title">Triggers</h3>
{#if $store.triggers}
<table class="fields-table uk-table uk-table-small">
<table class="fields-table uk-table uk-table-small uk-table-striped">
<thead>
<tr>
<th>Event</th>
@ -43,10 +43,10 @@ let triggerEditingFinished = (trigger) => {
<tbody>
{#each $store.triggers as trigger}
<tr>
<td >{trigger.eventName}</td>
<td >{trigger.actionName}</td>
<td >{trigger.condition}</td>
<td >{trigger.optionsCreator}</td>
<td class="table-content">{trigger.eventName}</td>
<td class="table-content">{trigger.actionName}</td>
<td class="table-content">{trigger.condition}</td>
<td class="table-content">{trigger.optionsCreator}</td>
<td class="edit-button">
<span on:click={() => onTriggerEdit(trigger)}>{@html getIcon("edit")}</span>
<span on:click={() => onTriggerDelete(trigger)}>{@html getIcon("trash")}</span>
@ -74,7 +74,17 @@ let triggerEditingFinished = (trigger) => {
.edit-button {
cursor:pointer;
color: var(--white);
color: var(--secondary25);
}
.title {
margin: 3rem 0rem 0rem 0rem;
font-weight: 700;
}
.table-content {
font-weight: 500;
font-size: .9rem;
}
tr:hover .edit-button {

BIN
packages/builder/src/assets/lato-latin-ext.woff2

Binary file not shown.

BIN
packages/builder/src/assets/lato-latin.woff2

Binary file not shown.

BIN
packages/builder/src/assets/roboto-v20-latin-ext_latin-300.woff

Binary file not shown.

BIN
packages/builder/src/assets/roboto-v20-latin-ext_latin-300.woff2

Binary file not shown.

BIN
packages/builder/src/assets/roboto-v20-latin-ext_latin-500.woff

Binary file not shown.

BIN
packages/builder/src/assets/roboto-v20-latin-ext_latin-500.woff2

Binary file not shown.

BIN
packages/builder/src/assets/roboto-v20-latin-ext_latin-700.woff

Binary file not shown.

BIN
packages/builder/src/assets/roboto-v20-latin-ext_latin-700.woff2

Binary file not shown.

BIN
packages/builder/src/assets/roboto-v20-latin-ext_latin-900.woff

Binary file not shown.

BIN
packages/builder/src/assets/roboto-v20-latin-ext_latin-900.woff2

Binary file not shown.

BIN
packages/builder/src/assets/roboto-v20-latin-ext_latin-regular.woff

Binary file not shown.

BIN
packages/builder/src/assets/roboto-v20-latin-ext_latin-regular.woff2

Binary file not shown.

2
packages/builder/src/builderStore/api.js

@ -1,5 +1,3 @@
import { isUndefined } from "lodash/fp";
const apiCall = (method) => (url, body) =>
fetch(url, {
method: method,

11
packages/builder/src/builderStore/loadComponentLibraries.js

@ -11,6 +11,17 @@ export const loadLibs = async (appName, appPackage) => {
return allLibraries;
}
export const loadLibUrls = (appName, appPackage) => {
const allLibraries = [];
for(let lib of appPackage.pages.componentLibraries) {
const libUrl = makeLibraryUrl(appName, lib);
allLibraries.push({libName:lib, importPath:libUrl});
}
return allLibraries;
}
export const loadLib = async (appName, lib, allLibs) => {
allLibs[lib] = await import(makeLibraryUrl(appName, lib));
return allLibs;

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

@ -1,26 +1,14 @@
import {
hierarchy as hierarchyFunctions,
common
} from "../../../core/src";
import {
filter,
cloneDeep,
sortBy,
map,
last,
keys,
concat,
find,
isEmpty,
groupBy,
reduce
filter, cloneDeep, sortBy,
map, last, keys, concat,
find, isEmpty, reduce
} from "lodash/fp";
import {
pipe,
getNode,
validate,
constructHierarchy,
templateApi
pipe, getNode, validate,
constructHierarchy, templateApi
} from "../common/core";
import {writable} from "svelte/store";
import { defaultPagesObject } from "../userInterface/pagesParsing/defaultPagesObject"
@ -28,10 +16,9 @@ import { buildPropsHierarchy } from "../userInterface/pagesParsing/buildPropsHie
import api from "./api";
import { isRootComponent } from "../userInterface/pagesParsing/searchComponents";
import {
getComponentInfo,
getNewComponentInfo
getComponentInfo, getNewComponentInfo
} from "../userInterface/pagesParsing/createProps";
import { loadLibs } from "./loadComponentLibraries";
import { loadLibs, loadLibUrls } from "./loadComponentLibraries";
let appname = "";
@ -121,6 +108,7 @@ const initialise = (store, initial) => async () => {
.then(r => r.json());
initial.libraries = await loadLibs(appname, pkg);
initial.loadLibraryUrls = () => loadLibUrls(appname, pkg);
initial.appname = appname;
initial.pages = pkg.pages;
initial.hasAppPackage = true;

4
packages/builder/src/common/Button.svelte

@ -27,8 +27,10 @@ $: borderClass = grouped
button {
border-style: solid;
padding: 7px 15px;
padding: 7.5px 15px;
cursor:pointer;
margin:5px;
border-radius: 5px;
}
/* ---- PRIMARY ----*/

5
packages/builder/src/common/CodeArea.svelte

@ -11,11 +11,14 @@ export let label = "";
textarea {
padding:3px;
background: var(--darkslate);
margin-top:5px;
margin-bottom:10px;
background: var(--lightslate);
color: var(--white);
font-family: 'Courier New', Courier, monospace;
width:95%;
height:100px;
border-radius: 5px;
}
</style>

2
packages/builder/src/common/DropdownButton.svelte

@ -46,7 +46,7 @@ let isDroppedDown = false;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
font-weight: normal;
border-style:solid;
border-style: solid;
border-width: 1px;
border-color: var(--secondary10);
}

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

@ -34,4 +34,8 @@ $: {
<style>
.uk-modal-dialog {
border-radius: .3rem;
}
</style>

25
packages/builder/src/common/binding.js

@ -0,0 +1,25 @@
import {
isString
} from "lodash/fp";
export const BB_STATE_BINDINGPATH = "##bbstate";
export const BB_STATE_FALLBACK = "##bbstatefallback";
export const isBinding = value =>
!isString(value)
&& value
&& isString(value[BB_STATE_BINDINGPATH])
&& value[BB_STATE_BINDINGPATH].length > 0;
export const setBinding = ({path, fallback}, binding={} ) => {
if(isNonEmptyString(path)) binding[BB_STATE_BINDINGPATH] = path;
if(isNonEmptyString(fallback)) binding[BB_STATE_FALLBACK] = fallback;
return binding
}
export const getBinding = binding => ({
path: binding[BB_STATE_BINDINGPATH] || "",
fallback: binding[BB_STATE_FALLBACK] || ""
});
const isNonEmptyString = s => isString(s) && s.length > 0;

1
packages/builder/src/common/eventHandlers.js

@ -0,0 +1 @@
export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType";

2
packages/builder/src/common/icon.js

@ -1,3 +1,3 @@
import feather from "feather-icons";
const getIcon = (icon, size) => feather.icons[icon].toSvg({height:size||"24", width:size||"24"});
const getIcon = (icon, size) => feather.icons[icon].toSvg({height:size||"16", width:size||"16"});
export default getIcon;

10
packages/builder/src/database/ActionsHeader.svelte

@ -30,7 +30,7 @@ const deleteCurrentNode = () => {
</Button>
{#if !$store.currentNodeIsNew}
<Button color="secondary" grouped on:click={openConfirmDelete}>
<Button color="tertiary" grouped on:click={openConfirmDelete}>
Delete
</Button>
{/if}
@ -54,9 +54,9 @@ const deleteCurrentNode = () => {
<style>
.root {
padding:5px;
top:0;
width:100%;
}
padding: 1.5rem;
width: 100%;
align-items: right;
}
</style>

2
packages/builder/src/database/FieldView.svelte

@ -109,7 +109,7 @@ const save = () => {
<ButtonGroup style="float: right;">
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="secondary" grouped on:click={() => onFinished(false)}>Cancel</Button>
<Button color="tertiary" grouped on:click={() => onFinished(false)}>Cancel</Button>
</ButtonGroup>
</div>

4
packages/builder/src/database/HierarchyRow.svelte

@ -24,13 +24,13 @@ export let node;
.root {
display: block;
font-size: 13pt;
font-size: 1rem;
width: 100%;
cursor: pointer;
}
.title {
font: var(--bodytext);
font: var(--fontblack);
padding-top: 10px;
padding-right: 5px;
padding-bottom: 10px;

55
packages/builder/src/database/RecordView.svelte

@ -85,18 +85,21 @@ let getTypeOptions = typeOptions =>
<div class="root">
<form class="uk-form-horizontal">
<h3 class="settings-title">
Settings
</h3>
<Textbox label="Name" bind:text={record.name} />
<div>{record.nodeKey()}</div>
<Textbox label="Name:" bind:text={record.name} />
{#if !record.isSingle}
<Textbox label="Collection Name" bind:text={record.collectionName} />
<Textbox label="Shard Factor" bind:text={record.allidsShardFactor} />
<Textbox label="Collection Name:" bind:text={record.collectionName} />
<Textbox label="Shard Factor:" bind:text={record.allidsShardFactor} />
{/if}
<div class="recordkey">{record.nodeKey()}</div>
</form>
<h4>
<h3 class="title">
Fields <span class="add-field-button" on:click={newField}>{@html getIcon("plus")}</span>
</h4>
</h3>
{#if record.fields.length > 0}
<table class="fields-table uk-table">
@ -138,9 +141,9 @@ let getTypeOptions = typeOptions =>
</Modal>
{/if}
<h4>
<h3 class="title">
Indexes
</h4>
</h3>
{#each record.indexes as index}
<div class="index-container">
@ -166,7 +169,9 @@ let getTypeOptions = typeOptions =>
{/if}
</div>
{:else}
(no indexes added)
<div class="no-indexes">
No indexes added.
</div>
{/each}
</div>
@ -176,25 +181,40 @@ let getTypeOptions = typeOptions =>
.root {
height: 100%;
padding: 15px;
padding: 2rem;
}
.settings-title {
font-weight: 700;
}
.title {
margin: 3rem 0rem 0rem 0rem;
font-weight: 700;
}
.recordkey {
font-size: 14px;
font-weight: 600;
color: var(--primary100);
}
.fields-table {
margin:10px;
margin: 1rem 1rem 0rem 0rem;
border-collapse:collapse;
}
.add-field-button {
margin-left:15px;
cursor:pointer;
}
.edit-button {
cursor:pointer;
color: var(--white);
color: var(--secondary25);
}
.edit-button:hover {
cursor:pointer;
color: var(--secondary75);
}
@ -203,7 +223,7 @@ th {
}
td {
padding: 5px 30px 5px 0px;
padding: 1rem 5rem 1rem 0rem;
margin:0;
}
@ -255,7 +275,12 @@ tbody > tr:hover .edit-button {
}
.index-field-row {
margin-top: 7px;
margin: 1rem 0rem 0rem 0rem;
}
.no-indexes {
margin: 1rem 0rem 0rem 0rem;
font-family: var(--fontnormal);
font-size: 14px;
}
</style>

BIN
packages/builder/src/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
packages/builder/src/favicon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

102
packages/builder/src/fonts.css

@ -1,61 +1,47 @@
/* latin-ext */
@font-face {
font-family: 'Lato';
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Lato';
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Black latin-ext */
@font-face {
font-family: 'Lato Black';
font-weight: 900;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Black latin */
@font-face {
font-family: 'Lato Black';
font-weight: 900;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Bold latin-ext */
@font-face {
font-family: 'Lato Bold';
font-weight: 700;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Bold latin */
@font-face {
font-family: 'Lato Bold';
font-weight: 700;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Semi Bold latin-ext */
@font-face {
font-family: 'Lato Semi Bold';
font-weight: 600;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Semi Bold latin */
@font-face {
font-family: 'Lato Semi Bold';
font-weight: 600;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
/* roboto-regular - latin-ext_latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'),
url('/_builder/assets/roboto-v20-latin-ext_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/_builder/assets/roboto-v20-latin-ext_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-300 - latin-ext_latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'),
url('/_builder/assets/roboto-v20-latin-ext_latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/_builder/assets/roboto-v20-latin-ext_latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-500 - latin-ext_latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'),
url('/_builder/assets/roboto-v20-latin-ext_latin-500.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/_builder/assets/roboto-v20-latin-ext_latin-500.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-700 - latin-ext_latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'),
url('/_builder/assets/roboto-v20-latin-ext_latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/_builder/assets/roboto-v20-latin-ext_latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-900 - latin-ext_latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 900;
src: local('Roboto Black'), local('Roboto-Black'),
url('/_builder/assets/roboto-v20-latin-ext_latin-900.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/_builder/assets/roboto-v20-latin-ext_latin-900.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}

19
packages/builder/src/global.css

@ -4,6 +4,7 @@
--primary50: #454CA080;
--primary25: #454CA040;
--primary10: #454CA01A;
--primary5: #454ca00c;
--primarydark: #3F448A;
--secondary100: #162B4DFF;
@ -11,6 +12,7 @@
--secondary50: #162B4D80;
--secondary25: #162B4D40;
--secondary10: #162B4D1A;
--secondary5: rgba(22, 43, 77, 0.068);
--secondarydark: #3F448A;
--tertiary: #F2F5F7;
@ -30,17 +32,18 @@
--deletiondark: #CF4046;
--white: #FFFFFF;
--darkslate: #5C6B82;
--slate: #8B95A6;
--lightslate: rgb(203, 212, 228);
--darkslate: #1a202c;
--slate: #a0aec0;
--lightslate: #f7fafc;
--borderradius: 2px;
--borderradiusall: 2px 2px 2px 2px;
--fontblack: "Lato Black";
--fontbold: "Lato Bold";
--fontsemibold: "Lato Semi Bold";
--fontnormal: "Lato";
--fontblack: "Roboto Black";
--fontbold: "Roboto Bold";
--fontsemibold: "Roboto Medium";
--fontnormal: "Roboto";
--fontlight: "Roboto Light";
--bodytext: var(--fontnormal) "regular" var(--secondary100) 16pt;
--bigbodytext: var(--fontnormal) "regular" var(--secondary100) 20pt;
@ -79,7 +82,7 @@ h3 {
}
h4 {
font-family: var(--fontsemibold);
font-family: var(--fontbold);
font-size: 18pt;
color: var(--secondary100);
}

7
packages/builder/src/main.js

@ -1,8 +1,11 @@
import App from "./App.svelte";
import "./global.css";
import "./fonts.css";
import "/assets/lato-latin-ext.woff2";
import "/assets/lato-latin.woff2";
import "/assets/roboto-v20-latin-ext_latin-300";
import "/assets/roboto-v20-latin-ext_latin-400";
import "/assets/roboto-v20-latin-ext_latin-500";
import "/assets/roboto-v20-latin-ext_latin-700";
import "/assets/roboto-v20-latin-ext_latin-900";
import "/assets/budibase-logo.png";
import "/assets/budibase-logo-only.png";
import "uikit/dist/css/uikit.min.css";

6
packages/builder/src/nav/BackendNav.svelte

@ -73,7 +73,7 @@ store.subscribe(db => {
.root {
height: 100%;
background-color: var(--primary10);
background-color: var(--secondary5);
}
.items-root {
@ -90,8 +90,8 @@ store.subscribe(db => {
.hierarchy-title-row {
padding: 15px 7px;
font-size: 12pt;
padding: 2rem 1rem 0rem 1rem;
font-size: 10pt;
display: flex;
font-weight: bold;
}

7
packages/builder/src/nav/HierarchyRow.svelte

@ -43,15 +43,14 @@ store.subscribe(s => {
.root {
display: block;
font-size: 12pt;
font-size: 10pt;
width: 100%;
cursor: pointer;
}
.title {
padding-top: 5px;
padding-right: 5px;
padding-bottom: 5px;
padding-top: .5rem;
padding-right: .5rem;
color: var(--secondary100);
}

4
packages/builder/src/nav/NavItem.svelte

@ -25,8 +25,8 @@ const setActive = () =>
<style>
.nav-item {
padding: 7px;
font-size: 12pt;
padding: 1rem 1rem 0rem 1rem;
font-size: 10pt;
font-weight: bold;
cursor: pointer;
flex: 0 0 auto;

23
packages/builder/src/userInterface/ComponentInstanceEditor.svelte

@ -10,7 +10,7 @@ import {
} from "lodash/fp";
import { fade, slide } from 'svelte/transition';
export let propertyName = "";
export let title = "";
export let onGoBack = () => {};
export let instanceProps = {};
export let onPropsChanged = () => {};
@ -18,6 +18,9 @@ export let onPropsChanged = () => {};
let editingSubComponentName;
let editingSubComponentProps;
let editingSubComponentArrayIndex;
let editingSubComponentArrayPropName;
let editingSubComponentTitle;
let allComponents;
store.subscribe(s => {
@ -33,18 +36,28 @@ const onSubComponentGoBack = () => {
}
const onEditComponentProp = (propName, arrayIndex, arrayPropName) => {
editingSubComponentName = isUndefined(arrayIndex)
editingSubComponentName = propName;
editingSubComponentTitle = isUndefined(arrayIndex)
? propName
: `${propName}[${arrayIndex}].${arrayPropName}`;
editingSubComponentProps = isUndefined(arrayIndex)
? instanceProps[propName]
: instanceProps[propName][arrayIndex][arrayPropName];
editingSubComponentArrayIndex = arrayIndex;
editingSubComponentArrayPropName = arrayPropName;
};
const onSubComponentPropsChanged = (subProps) => {
const newProps = cloneDeep(instanceProps);
newProps[editingSubComponentName] = subProps;
if(isUndefined(editingSubComponentArrayIndex)) {
newProps[editingSubComponentName] = subProps;
} else {
newProps[editingSubComponentName]
[editingSubComponentArrayIndex]
[editingSubComponentArrayPropName] = subProps;
}
instanceProps = newProps;
onPropsChanged(newProps);
}
@ -62,7 +75,7 @@ const propsChanged = newProps => {
<div class="title">
<IconButton icon="chevron-left"
on:click={onGoBack}/>
<span>{propertyName}</span>
<span>{title}</span>
</div>
{#if editingSubComponentName}
@ -71,7 +84,7 @@ const propsChanged = newProps => {
<svelte:self onPropsChanged={onSubComponentPropsChanged}
onGoBack={onSubComponentGoBack}
instanceProps={editingSubComponentProps}
propertyName={editingSubComponentName} />
title={editingSubComponentTitle} />
</div>
{:else}
<PropsView {instanceProps}

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

@ -18,7 +18,6 @@ export let props = emptyProps();
export let onValueChanged = () => {};
export let onComponentChosen = () => {};
export let onEdit = () => {};
export let label = "";
export let disabled = false;
const CHOOSE_COMPONENT = "choose_component";
@ -70,7 +69,6 @@ const confirmClearComponent = () => {
</script>
<label class="uk-form-label">{label}</label>
<div class="root uk-form-controls">
<div class:selectedname={componentSelected}>
{componentSelected ? shortName : "(none)"}

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

@ -2,79 +2,47 @@
import { store } from "../builderStore";
import { makeLibraryUrl } from "../builderStore/loadComponentLibraries";
import {
last,
split,
map,
join
last, split, map, join
} from "lodash/fp";
import { pipe } from "../common/core";
import { splitName } from "./pagesParsing/splitRootComponentName"
import { afterUpdate } from 'svelte';
import { getRootComponent } from "./pagesParsing/getRootComponent";
import { buildPropsHierarchy } from "./pagesParsing/buildPropsHierarchy";
if(!window.budibaseIframeConnector) {
window.budibaseIframeConnector = {
initialiseComponent(props, htmlElement) {
const rootComponent = getRootComponent(
props._component, allComponents);
const {componentName, libName} = splitName(
rootComponent.name);
new (libraries[libName][componentName])({
target: htmlElement,
props: {...props, _app: window.budibaseIframeConnector}
});
}
}
}
let component;
let stylesheetLinks = "";
let componentHtml = "";
let props;
let componentLibraryUrl = "";
let rootComponentName = "";
let iframe;
let libraries;
let allComponents;
let appDefinition = {};
store.subscribe(s => {
const {componentName, libName} = splitName(
s.currentComponentInfo.rootComponent.name);
rootComponentName = componentName;
props = s.currentComponentInfo.fullProps;
component = s.libraries[libName][componentName];
stylesheetLinks = pipe(s.pages.stylesheets, [
map(s => `<link rel="stylesheet" href="${s}"/>`),
join("\n")
]);
componentLibraryUrl = makeLibraryUrl(s.appname, libName);
appDefinition = {
componentLibraries: s.loadLibraryUrls(),
props: buildPropsHierarchy(s.allComponents, s.currentFrontEndItem)
};
libraries = s.libraries;
allComponents = s.allComponents;
});
/*
afterUpdate(() => {
if(iframe) iframeLoaded();
});
*/
const iframeLoaded = () => {
setTimeout(() => {
iframe.style.height = (iframe.contentWindow.document.body.scrollHeight + 1).toString() + "px";
iframe.style.width = (iframe.contentWindow.document.body.scrollWidth + 1).toString() + "px";
}, 100);
}
</script>
<div class="component-preview" >
<div class="component-container">
<iframe bind:this={iframe}
on:load={iframeLoaded}
<iframe style="height: 100%; width: 100%"
title="componentPreview"
srcdoc={
`<html>
@ -82,16 +50,11 @@ const iframeLoaded = () => {
<head>
${stylesheetLinks}
<script>
import('${componentLibraryUrl}')
window["##BUDIBASE_APPDEFINITION##"] = ${JSON.stringify(appDefinition)};
import('./budibase-client.esm.mjs')
.then(module => {
const componentClass = module['${rootComponentName}'];
const instance = new componentClass({
target: document.body,
props: {...${JSON.stringify(props)}, _app: window.parent.budibaseIframeConnector}
}) ;
})
module.loadBudibase();
})
</script>
</head>
<body>

31
packages/builder/src/userInterface/EditComponent.svelte

@ -36,6 +36,10 @@ let modalElement
let propsValidationErrors = [];
let editingComponentInstance;
let editingComponentInstancePropName="";
let editingComponentArrayIndex;
let editingComponentArrayPropName;
let editingComponentInstanceTitle;
let allComponents;
$: shortName = last(name.split("/"));
@ -116,9 +120,13 @@ const onEditComponentProp = (propName, arrayIndex, arrayPropName) => {
editingComponentInstance = isUndefined(arrayIndex)
? component.props[propName]
: component.props[propName][arrayIndex][arrayPropName];
editingComponentInstancePropName = isUndefined(arrayIndex)
editingComponentInstancePropName = propName;
editingComponentInstanceTitle = isUndefined(arrayIndex)
? propName
: `${propName}[${arrayIndex}].${arrayPropName}`;
editingComponentArrayIndex = arrayIndex;
editingComponentArrayPropName = arrayPropName;
}
const componentInstanceCancelEdit = () => {
@ -127,8 +135,15 @@ const componentInstanceCancelEdit = () => {
}
const componentInstancePropsChanged = (instanceProps) => {
updateComponent(newComponent =>
newComponent.props[editingComponentInstancePropName] = instanceProps);
updateComponent(newComponent => {
if(isUndefined(editingComponentArrayIndex)) {
newComponent.props[editingComponentInstancePropName] = instanceProps;
} else {
newComponent.props[editingComponentInstancePropName]
[editingComponentArrayIndex]
[editingComponentArrayPropName] = instanceProps;
}
});
}
</script>
@ -151,11 +166,11 @@ const componentInstancePropsChanged = (instanceProps) => {
{#if editingComponentInstance}
<ComponentInstanceEditor onGoBack={componentInstanceCancelEdit}
propertyName={editingComponentInstancePropName}
title={editingComponentInstanceTitle}
instanceProps={editingComponentInstance}
onPropsChanged={componentInstancePropsChanged}/>
{:else}
<div>
<div class="component-props-container">
<div class="section-header padding" on:click={() => componentDetailsExpanded = !componentDetailsExpanded}>
<span style="margin-right: 7px">Component Details</span>
@ -232,6 +247,8 @@ const componentInstancePropsChanged = (instanceProps) => {
border-style: solid;
border-color: var(--lightslate);
border-width: 0px 0px 0px 1px;
display:flex;
flex-direction: column;
}
.padding {
@ -267,4 +284,8 @@ const componentInstancePropsChanged = (instanceProps) => {
margin-top: 20px;
}
.component-props-container {
flex: 1 1 auto;
overflow-y: auto;
}
</style>

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

@ -0,0 +1,97 @@
<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;
export let onValidate = () => {};
let events = [];
let elementErrors = {};
$: {
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>

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

@ -0,0 +1,104 @@
<script>
import IconButton from "../common/IconButton.svelte";
import StateBindingControl from "./StateBindingControl.svelte";
import {
find, map, keys, reduce
} from "lodash/fp";
import { pipe } from "../common/core";
import { EVENT_TYPE_MEMBER_NAME } from "../common/eventHandlers";
export let event;
export let onChanged;
export let onRemoved;
const events = [
{name:"", parameters: []},
{name:"Set State", parameters: ["path", "value"]},
{name:"Load Record", parameters: ["recordKey", "statePath"]},
];
let eventType;
let parameters = [];
$: {
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}>
{#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>

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

@ -18,7 +18,6 @@ export let onEditComponentProp = () => {};
let value = [];
let elementDefinitionArray;
let label = "";
let elementErrors = {};
$: {
@ -31,7 +30,6 @@ $: {
});
}
elementDefinitionArray = elArray;
label = propDef.____name;
value = parentProps[propDef.____name];
}
@ -73,9 +71,7 @@ const onEditComponent = (index, propName) => () => {
</script>
<div class="root">
<div>
{label}
</div>
<div class="item-container">
{#each value as item, index}

48
packages/builder/src/userInterface/PropControl.svelte

@ -5,6 +5,8 @@ import Textbox from "../common/Textbox.svelte";
import Dropdown from "../common/Dropdown.svelte";
import ComponentPropSelector from "./ComponentPropSelector.svelte";
import PropArraySelector from "./PropArraySelector.svelte";
import EventListSelector from "./EventListSelector.svelte";
import StateBindingControl from "./StateBindingControl.svelte";
export let errors = [];
export let setProp = () => {};
@ -26,37 +28,39 @@ const setComponentProp = (props) => {
<div class="root" >
{#if propDef.type === "component"}
{#if propDef.type === "bool"}
<Checkbox label={propDef.____name}
checked={props[propDef.____name]}
on:change={ev => setProp(propDef.____name, ev.target.checked)}
hasError={fieldHasError(propDef.____name)} />
{:else if propDef.type === "options"}
<Dropdown label={propDef.____name}
selected={props[propDef.____name]}
options={propDef.options}
on:change={ev => setProp(propDef.____name, ev.target.value)}
hasError={fieldHasError(propDef.____name)}/>
{:else if propDef.type === "component"}
<div class="prop-label">{propDef.____name}</div>
<ComponentPropSelector label={propDef.____name}
props={props[propDef.____name]}
{disabled}
onEdit={onEditComponent}
onComponentChosen={onEditComponent}
onValueChanged={setComponentProp}/>
{:else if propDef.type === "array"}
<div class="prop-label">{propDef.____name}</div>
<PropArraySelector parentProps={props}
{propDef}
onValueChanged={setComponentProp}
onEditComponentProp={onEditComponent}/>
onEditComponentProp={onEditComponent} />
{:else if propDef.type === "event"}
<div class="prop-label">{propDef.____name}</div>
<EventListSelector parentProps={props}
{propDef}
onValueChanged={setComponentProp} />
{:else}
<Textbox label={propDef.____name}
text={props[propDef.____name]}
on:change={ev => setProp(propDef.____name, ev.target.value)}
margin={false}
hasError={fieldHasError(propDef.____name)}
{disabled}/>
<div class="prop-label">{propDef.____name}</div>
<StateBindingControl value={props[propDef.____name]}
type={propDef.type}
options={propDef.options}
onChanged={v => setProp(propDef.____name, v)}/>
{/if}
</div>
@ -70,4 +74,10 @@ const setComponentProp = (props) => {
border-color: var(--primary25);
}
.prop-label {
font-size: 0.9em;
color: var(--primary100);
font-weight: bold;
}
</style>

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

@ -0,0 +1,155 @@
<script>
import {
isString
} from "lodash/fp";
import IconButton from "../common/IconButton.svelte";
import {
isBinding, getBinding, setBinding
} from "../common/binding";
export let value="";
export let onChanged= () => {};
export let type="";
export let options=[];
let isBound=false;
let bindingPath="";
let bindingFallbackValue="";
let isExpanded = false;
let forceIsBound = false;
$: {
isBound= forceIsBound || isBinding(value);
if(isBound) {
const binding = getBinding(value);
bindingPath= binding.path;
bindingFallbackValue= binding.fallback;
} else {
bindingPath="";
bindingFallbackValue="";
}
}
const clearBinding = () => {
forceIsBound = false;
onChanged("");
}
const bind = (path, fallback) => {
if(!path) {
clearBinding("");
return;
}
const binding = setBinding({path, fallback});
onChanged(binding);
}
const setBindingPath = ev => {
forceIsBound = false;
bind(ev.target.value, bindingFallbackValue)
}
const setBindingFallback = ev => {
bind(bindingPath, ev.target.value);
}
const makeBinding = () => {
forceIsBound=true;
isExpanded=true;
}
</script>
{#if isBound}
<div>
<div class="bound-header">
<div>{isExpanded ? "" : bindingPath}</div>
<IconButton icon={isExpanded ? "chevron-up" : "chevron-down"}
size="12"
on:click={() => isExpanded=!isExpanded}/>
<IconButton icon="trash"
size="12"
on:click={clearBinding}/>
</div>
{#if isExpanded}
<div>
<div class="binding-prop-label">Binding Path</div>
<input class="uk-input uk-form-small"
value={bindingPath}
on:change={setBindingPath} >
<div class="binding-prop-label">Fallback Value</div>
<input class="uk-input uk-form-small"
value={bindingFallbackValue}
on:change={setBindingFallback} >
</div>
{/if}
</div>
{:else}
<div class="unbound-container">
{#if type === "bool"}
<div>
<IconButton icon={value == true ? "check-square" : "square"}
size="19"
on:click={() => value = !value}/>
</div>
{:else if type === "options"}
<select class="uk-select uk-form-small"
value={value}
on:change={ev => onChanged(ev.target.checked)}>
{#each options as option}
<option value={option}>{option}</option>
{/each}
</select>
{:else}
<input class="uk-input uk-form-small"
on:change={ev => onChanged(ev.target.value)}
bind:value={value}
style="flex: 1 0 auto;" >
{/if}
<IconButton icon="link"
size="12"
on:click={makeBinding} />
</div>
{/if}
<style>
.unbound-container {
display:flex;
}
.unbound-container > *:nth-child(1) {
width:auto;
flex: 1 0 auto;
}
.bound-header {
display: flex;
}
.bound-header > div:nth-child(1) {
flex: 1 0 auto;
width: 30px;
color: var(--darkslate);
padding-left: 5px;
font-style: italic;
}
.binding-prop-label {
color: var(--darkslate);
}
</style>

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

@ -88,6 +88,7 @@ const settings = () => {
grid-template-columns: [uiNav] 250px [preview] auto [properties] 300px;
height: 100%;
width: 100%;
overflow-y: auto;
}
.ui-nav {
@ -100,6 +101,7 @@ const settings = () => {
grid-column-start: properties;
background-color: var(--primary10);
height: 100%;
overflow-y: hidden;
}
.pages-list-container {

3
packages/builder/src/userInterface/pagesParsing/buildPropsHierarchy.js

@ -1,7 +1,6 @@
import {
getComponentInfo, createProps, getInstanceProps
} from "./createProps";
import { cloneDeep } from "lodash/fp";
export const buildPropsHierarchy = (allComponents, baseComponent) => {
@ -39,7 +38,7 @@ export const buildPropsHierarchy = (allComponents, baseComponent) => {
for(let element of propsArray) {
newPropsArray.push(
buildProps(
`${propName}[${index}]`,
`${propName}#array_element#`,
propDef.elementDefinition,
element));
index++;

2
packages/builder/src/userInterface/pagesParsing/createProps.js

@ -150,7 +150,7 @@ export const createProps = (componentName, propsDefinition, derivedFromProps) =>
export const createArrayElementProps = (arrayPropName, elementDefinition) =>
createProps(
`#element#${arrayPropName}`,
`#${arrayPropName}#array_element`,
elementDefinition);
const parsePropDef = propDef => {

17
packages/builder/src/userInterface/pagesParsing/types.js

@ -3,9 +3,15 @@ import {
isBoolean,
isNumber,
isArray,
isObjectLike
isObjectLike,
isPlainObject,
every
} from "lodash/fp";
import {
EVENT_TYPE_MEMBER_NAME
} from "../../common/eventHandlers";
const defaultDef = typeName => () => ({
type: typeName,
required:false,
@ -47,6 +53,14 @@ export const expandPropsDefinition = propsDefinition => {
}
const isComponent = isObjectLike;
const isEvent = e =>
isPlainObject(e)
&& isString(e[EVENT_TYPE_MEMBER_NAME])
&& isPlainObject(e.parameters);
const isEventList = e =>
isArray(e) && every(isEvent)(e);
export const types = {
string: propType(() => "", isString, defaultDef("string")),
@ -56,4 +70,5 @@ export const types = {
options: propType(() => "", isString, defaultDef("options")),
component: propType(() => ({_component:""}), isComponent, defaultDef("component")),
asset: propType(() => "", isString, defaultDef("asset")),
event: propType(() => [], isEventList, defaultDef("event"))
};

30
packages/builder/src/userInterface/pagesParsing/validateProps.js

@ -1,21 +1,17 @@
import { types } from "./types";
import {
createProps,
arrayElementComponentName
createProps, arrayElementComponentName
} from "./createProps";
import { isString } from "util";
import {
includes,
filter,
map,
keys,
flatten,
flattenDeep,
each,
indexOf,
isUndefined
includes, filter, map, keys,
flatten, flattenDeep, each,
indexOf, isUndefined
} from "lodash/fp";
import { common } from "../../../../core/src";
import {
isBinding
} from "../../common/binding";
const pipe = common.$;
@ -133,7 +129,15 @@ export const validateProps = (propsDefinition, props, stack=[], isFinal=true) =>
continue;
}
if(!type.isOfType(propValue)) {
if(isBinding(propValue)) {
if(propDef.type === "array"
|| propDef.type === "component"
|| propDef.type === "event") {
error(`Cannot apply binding to type ${propDef.type}`);
continue;
}
}
else if(!type.isOfType(propValue)) {
error(`Property ${propDefName} is not of type ${propDef.type}. Actual value ${propValue}`)
continue;
}
@ -141,7 +145,6 @@ export const validateProps = (propsDefinition, props, stack=[], isFinal=true) =>
if(propDef.type === "array") {
let index = 0;
for(let arrayItem of propValue) {
arrayItem._component = arrayElementComponentName(props._component, propDefName);
const arrayErrs = validateProps(
propDef.elementDefinition,
arrayItem,
@ -157,6 +160,7 @@ export const validateProps = (propsDefinition, props, stack=[], isFinal=true) =>
if(propDef.type === "options"
&& propValue
&& !isBinding(propValue)
&& !includes(propValue)(propDef.options)) {
error(`Property ${propDefName} is not one of allowed options. Acutal value is ${propValue}`);
}

12
packages/builder/tests/createDefaultProps.spec.js

@ -103,6 +103,18 @@ describe("createDefaultProps", () => {
expect(props.columns).toEqual([]);
});
it("should create a object with single empty array, when prop definition is 'event' ", () => {
const propDef = {
onClick: "event"
};
const { props, errors } = createProps("some_component",propDef);
expect(errors).toEqual([]);
expect(props.onClick).toBeDefined();
expect(props.onClick).toEqual([]);
});
it("should create a object with single empty component props, when prop definition is 'component' ", () => {
const propDef = {
content: "component"

11
packages/builder/tests/validateProps.spec.js

@ -4,6 +4,9 @@ import {
recursivelyValidate
} from "../src/userInterface/pagesParsing/validateProps";
import { createProps } from "../src/userInterface/pagesParsing/createProps";
import {
setBinding
} from "../src/common/binding";
// not that allot of this functionality is covered
// in createDefaultProps - as validate props uses that.
@ -151,6 +154,14 @@ describe("validateProps", () => {
expect(errors[0].propName).toBe("width");
});
it("should not return error when has binding", () => {
const props = validProps();
props.columns[0].width = setBinding({path:"some_path"});
props.size = setBinding({path:"other path", fallback:"small"});
const errors = validateProps(validPropDef, props, [], true);
expect(errors.length).toEqual(0);
});
});
describe("recursivelyValidateProps", () => {

2
packages/client/package.json

@ -3,7 +3,7 @@
"version": "0.0.3",
"license": "MPL-2.0",
"main": "dist/budibase-client.js",
"module": "dist/budibase-client.js",
"module": "dist/budibase-client.esm.mjs",
"scripts": {
"build": "rollup -c",
"test": "jest",

23
packages/client/rollup.config.js

@ -6,8 +6,8 @@ import { terser } from 'rollup-plugin-terser';
const lodash_fp_exports = [
"find", "isUndefined", "split",
"last", "union", "reduce",
"cloneDeep", "some"];
"last", "union", "reduce", "isObject",
"cloneDeep", "some", "isArray"];
const lodash_exports = [
"flow","reduce", "constant", "head", "isEmpty",
@ -26,12 +26,19 @@ const coreExternal = [
export default {
input: 'src/index.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: `./dist/budibase-client.js`
},
output: [
{
sourcemap: true,
format: 'iife',
name: 'app',
file: `./dist/budibase-client.js`
},
{
file: 'dist/budibase-client.esm.mjs',
format: 'esm',
sourcemap: 'inline'
}
],
plugins: [
resolve({

50
packages/client/src/createApp.js

@ -0,0 +1,50 @@
import {
split,
last
} from "lodash/fp";
import {writable} from "svelte/store";
import { $ } from "./core/common";
import { setupBinding } from "./state/stateBinding";
export const createApp = componentLibraries => {
const initialiseComponent = (props, htmlElement) => {
const {componentName, libName} = splitName(props._component);
if(!componentName || !libName) return;
const {initialProps, bind} = setupBinding(store, props);
const component = new (componentLibraries[libName][componentName])({
target: htmlElement,
props: {...initialProps, _app}
});
bind(component);
}
const store = writable({});
const _app = {
initialiseComponent,
store
};
return _app;
}
const splitName = fullname => {
const componentName = $(fullname, [
split("/"),
last
]);
const libName =fullname.substring(
0, fullname.length - componentName.length - 1);
return {libName, componentName};
}

33
packages/client/src/index.js

@ -1,5 +1,32 @@
import { initialise } from "./initialise";
import { createApp } from "./createApp";
const appDefinition = window["##BUDIBASE_APPDEFINITION##"];
initialise(window.document, appDefinition);
export const loadBudibase = async (componentLibraries, props) => {
const appDefinition = window["##BUDIBASE_APPDEFINITION##"];
if(!componentLibraries) {
const componentLibraryUrl = (lib) => "./" + trimSlash(lib)
const trimSlash = (str) => str.replace(/^\/+|\/+$/g, '');
componentLibraries = {};
for(let lib of appDefinition.componentLibraries) {
componentLibraries[lib.libName] = await import(
componentLibraryUrl(lib.importPath));
}
}
if(!props) {
props = appDefinition.props;
}
const _app = createApp(componentLibraries);
_app.initialiseComponent(
props,
document.body);
};
window.loadBudibase = loadBudibase;

22
packages/client/src/initialise.js

@ -1,22 +0,0 @@
import { writable } from "svelte/store";
import { initialiseComponent } from "./initialiseComponent";
export const initialise = async (document, appDefinition) => {
const componentLibraries = {};
for(let lib of appDefinition.componentLibraries) {
componentLibraries[lib.libName] = await import(
componentLibraryUrl(lib.importPath));
}
const store = writable({});
initialiseComponent(componentLibraries, store)(
appDefinition.props,
document.body);
}
const componentLibraryUrl = (lib) => "./" + trimSlash(lib)
const trimSlash = (str) => str.replace(/^\/+|\/+$/g, '');

36
packages/client/src/initialiseComponent.js

@ -1,36 +0,0 @@
import {
find,
isUndefined,
split,
last
} from "lodash/fp";
import { $ } from "./core/common";
export const initialiseComponent = (componentLibraries, store) => (props, htmlElement) => {
const _app = {
initialiseComponent: initialiseComponent(componentLibraries, store),
store
};
const {componentName, libName} = splitName(props._component);
new (componentLibraries[libName][componentName])({
target: htmlElement,
props: {...props, _app}
});
}
const splitName = fullname => {
const componentName = $(fullname, [
split("/"),
last
]);
const libName =fullname.substring(
0, fullname.length - componentName.length - 1);
return {libName, componentName};
}

26
packages/client/src/state/eventHandlers.js

@ -0,0 +1,26 @@
import {
setState
} from "./setState";
import {
isArray, isUndefined
} from "lodash/fp";
export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType";
export const eventHandlers = store => {
const handler = (parameters, execute) => ({
execute, parameters
});
const setStateHandler = ({path, value}) => setState(store, path, value);
return {
"Set State": handler(["path", "value"], setStateHandler)
};
};
export const isEventType = prop =>
isArray(prop)
&& prop.length > 0
&& !isUndefined(prop[0][EVENT_TYPE_MEMBER_NAME]);

34
packages/client/src/state/getState.js

@ -0,0 +1,34 @@
import {
isUndefined,
isObject
} from "lodash/fp";
export const getState = (s, path, fallback) => {
const pathParts = path.split(".");
const safeGetPath = (obj, currentPartIndex=0) => {
const currentKey = pathParts[currentPartIndex];
if(pathParts.length - 1 == currentPartIndex) {
const value = obj[currentKey];
if(isUndefined(value))
return fallback;
else
return value;
}
if(obj[currentKey] === null
|| obj[currentKey] === undefined
|| !isObject(obj[currentKey])) {
return fallback;
}
return safeGetPath(obj[currentKey], currentPartIndex + 1);
}
return safeGetPath(s);
}

33
packages/client/src/state/setState.js

@ -0,0 +1,33 @@
import {
isObject
} from "lodash/fp";
export const setState = (store, path, value) => {
const pathParts = path.split(".");
const safeSetPath = (obj, currentPartIndex=0) => {
const currentKey = pathParts[currentPartIndex];
if(pathParts.length - 1 == currentPartIndex) {
obj[currentKey] = value;
return;
}
if(obj[currentKey] === null
|| obj[currentKey] === undefined
|| !isObject(obj.currentKey)) {
obj[currentKey] = {};
}
safeSetPath(obj[currentKey], currentPartIndex + 1);
}
store.update(s => {
safeSetPath(s);
return s;
});
}

118
packages/client/src/state/stateBinding.js

@ -0,0 +1,118 @@
import {
isEventType, eventHandlers, EVENT_TYPE_MEMBER_NAME
} from "./eventHandlers";
import {
getState
} from "./getState";
export const BB_STATE_BINDINGPATH = "##bbstate";
export const BB_STATE_FALLBACK = "##bbstatefallback";
const doNothing = () => {};
export const setupBinding = (store, props) => {
const initialProps = {...props};
const boundProps = [];
const componentEventHandlers = [];
for(let propName in props) {
const val = initialProps[propName];
if(isState(val)) {
const binding = stateBinding(val);
const fallback = stateFallback(val);
boundProps.push({
stateBinding:binding,
fallback, propName
});
initialProps[propName] = fallback;
} else if(isEventType(val)) {
const handlers = { propName, handlers:[] };
componentEventHandlers.push(handlers);
for(let e of val) {
handlers.handlers.push({
handlerType: e[EVENT_TYPE_MEMBER_NAME],
parameters: e.parameters
})
}
initialProps[propName] = doNothing;
}
}
const bind = (component) => {
if(boundProps.length === 0 && componentEventHandlers.length === 0) return;
const handlerTypes = eventHandlers(store);
const unsubscribe = store.subscribe(s => {
const newProps = {};
for(let boundProp of boundProps) {
const val = getState(
s,
boundProp.stateBinding,
boundProp.fallback);
if(val === undefined && newProps[boundProp.propName] !== undefined) {
delete newProps[boundProp.propName];
}
if(val !== undefined) {
newProps[boundProp.propName] = val;
}
}
for(let boundHandler of componentEventHandlers) {
const closuredHandlers = [];
for(let h of boundHandler.handlers) {
const parameters = {};
for(let pname in h.parameters) {
const p = h.parameters[pname];
parameters[pname] = isState(p)
? getState(
s, p[BB_STATE_BINDINGPATH], p[BB_STATE_FALLBACK])
: p;
}
const handlerType = handlerTypes[h.handlerType];
closuredHandlers.push(() => handlerType.execute(parameters));
}
newProps[boundHandler.propName] = () => {
for(let runHandler of closuredHandlers) {
runHandler();
}
}
}
component.$set(newProps);
});
return unsubscribe;
}
return {
initialProps, bind
};
}
const isState = (prop) => prop[BB_STATE_BINDINGPATH] !== undefined;
const stateBinding = (prop) => prop[BB_STATE_BINDINGPATH];
const stateFallback = (prop) => prop[BB_STATE_FALLBACK];

146
packages/client/tests/stateBinding.spec.js

@ -0,0 +1,146 @@
import {
setupBinding,
BB_STATE_BINDINGPATH,
BB_STATE_FALLBACK
} from "../src/state/stateBinding";
import { EVENT_TYPE_MEMBER_NAME } from "../src/state/eventHandlers";
import {writable} from "svelte/store";
import { isFunction } from "lodash/fp";
describe("setupBinding", () => {
it("should correctly create initials props, including fallback values", () => {
const {store, props, component} = testSetup();
const {initialProps} = testSetupBinding(store, props, component);
expect(initialProps.boundWithFallback).toBe("Bob");
expect(initialProps.boundNoFallback).toBeUndefined();
expect(initialProps.unbound).toBe("hello");
expect(isFunction(initialProps.eventBound)).toBeTruthy();
initialProps.eventBound();
});
it("should update component bound props when store is updated", () => {
const {component, store, props} = testSetup();
const {bind} = testSetupBinding(store, props, component);
bind(component);
store.update(s => {
s.FirstName = "Bobby";
s.LastName = "Thedog";
s.Customer = {
Name: "ACME inc",
Address: ""
};
s.addressToSet = "123 Main Street"
return s;
});
expect(component.props.boundWithFallback).toBe("Bobby");
expect(component.props.boundNoFallback).toBe("Thedog");
expect(component.props.multiPartBound).toBe("ACME inc");
});
it("should not update unbound props when store is updated", () => {
const {component, store, props} = testSetup();
const {bind} = testSetupBinding(store, props, component);
bind(component);
store.update(s => {
s.FirstName = "Bobby";
s.LastName = "Thedog";
s.Customer = {
Name: "ACME inc",
Address: ""
};
s.addressToSet = "123 Main Street"
return s;
});
expect(component.props.unbound).toBe("hello");
});
it("should update event handlers on state change", () => {
const {component, store, props} = testSetup();
const {bind} = testSetupBinding(store, props, component);
bind(component);
expect(component.props.boundToEventOutput).toBe("initial address");
component.props.eventBound();
expect(component.props.boundToEventOutput).toBe("event fallback address");
store.update(s => {
s.addressToSet = "123 Main Street"
return s;
});
component.props.eventBound();
expect(component.props.boundToEventOutput).toBe("123 Main Street");
});
});
const testSetupBinding = (store, props, component) => {
const setup = setupBinding(store, props);
component.props = setup.initialProps; // svelte does this for us in real life
return setup;
}
const testSetup = () => {
const c = {};
c.props = {};
c.$set = propsToSet => {
for(let pname in propsToSet)
c.props[pname] = propsToSet[pname];
}
const binding = (path, fallback) => {
const b = {};
b[BB_STATE_BINDINGPATH] = path;
b[BB_STATE_FALLBACK] = fallback;
return b;
};
const event = (handlerType, parameters) => {
const e = {};
e[EVENT_TYPE_MEMBER_NAME] = handlerType;
e.parameters = parameters;
return e;
}
const props = {
boundWithFallback : binding("FirstName", "Bob"),
boundNoFallback : binding("LastName"),
unbound: "hello",
multiPartBound: binding("Customer.Name", "ACME"),
boundToEventOutput: binding("Customer.Address", "initial address"),
eventBound: [
event("Set State", {
path: "Customer.Address",
value: binding("addressToSet", "event fallback address")
})
]
}
return {
component:c,
store:writable({}),
props
};
}

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

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

11
packages/server/appPackages/testApp/components/Button.json

@ -0,0 +1,11 @@
{
"name": "Button",
"description": "PrimaryButton",
"inherits": "@budibase/standard-components/button",
"props": {
"contentText": "Save"
},
"tags": [
"button"
]
}

15
packages/server/appPackages/testApp/components/LoginForm.json

@ -0,0 +1,15 @@
{
"name": "LoginForm",
"description": "",
"inherits": "@budibase/standard-components/formControl",
"props": {
"label": "Joe",
"labelContainerClass": "Joe",
"controlContainerClass": "Joe",
"containerClass": "Joe",
"fullWidth": true
},
"tags": [
"login"
]
}

9
packages/server/appPackages/testApp/components/joeTextBox.json

@ -0,0 +1,9 @@
{
"name": "joeTextBox",
"description": "",
"inherits": "subfolder/otherTextBox",
"props": {},
"tags": [
""
]
}

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

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

75
packages/server/appPackages/testApp2/appDefinition.json

@ -156,14 +156,75 @@
]
},
"props": {
"main": {},
"main": {
"_component": "@budibase/standard-components/grid",
"gridTemplateRows": "",
"gridTemplateColumns": "[left] 1fr [right] 1fr",
"children": [
{
"_component": "children#array_element#",
"control": {
"_component": "@budibase/standard-components/button",
"contentText": "Click Me",
"contentComponent": {
"_component": ""
},
"className": "default",
"disabled": false,
"onClick": [
{
"##eventHandlerType": "Set State",
"parameters": {
"path": "SomeText",
"value": "hello !"
}
}
]
},
"gridColumn": "left",
"gridRow": "",
"gridColumnStart": "",
"gridColumnEnd": "",
"gridRowStart": "",
"gridRowEnd": ""
},
{
"_component": "children#array_element#",
"control": {
"_component": "@budibase/standard-components/button",
"contentText": {
"##bbstate": "SomeText",
"##bbstatefallback": "(none)"
},
"contentComponent": {
"_component": ""
},
"className": "default",
"disabled": false,
"onClick": []
},
"gridColumn": "",
"gridRow": "",
"gridColumnStart": "",
"gridColumnEnd": "",
"gridRowStart": "",
"gridRowEnd": ""
}
],
"width": "auto",
"height": "auto",
"containerClass": "",
"itemContainerClass": ""
},
"unauthenticated": {
"_component": "budibase-standard-components/login",
"logo": "/_shared/budibase-logo.png",
"loginRedirect": "",
"usernameLabel": "Username",
"passwordLabel": "Password",
"loginButtonLabel": "Login"
"_component": "@budibase/standard-components/grid",
"gridTemplateRows": "",
"gridTemplateColumns": "[left] 1fr [right] 1fr",
"children": [],
"width": "auto",
"height": "auto",
"containerClass": "",
"itemContainerClass": ""
}
}
}

29
packages/server/appPackages/testApp2/components/Primary Button.json

@ -0,0 +1,29 @@
{
"name": "Primary Button",
"description": "",
"inherits": "@budibase/standard-components/button",
"props": {
"onClick": [
{
"##eventHandlerType": "Load Record",
"parameters": {
"recordKey": "waa",
"statePath": "yea"
}
},
{
"##eventHandlerType": "Load Record",
"parameters": {
"recordKey": "ttt",
"statePath": "eee"
}
}
],
"contentText": {
"##bbstate": "yea"
}
},
"tags": [
"button"
]
}

15
packages/server/appPackages/testApp2/components/containers/two_columns.json

@ -0,0 +1,15 @@
{
"name": "/containers/two_columns",
"description": "",
"inherits": "@budibase/standard-components/grid",
"props": {
"gridTemplateColumns": "[left] 1fr [right] 1fr"
},
"tags": [
"div",
"container",
"layout",
"panel",
"grid"
]
}

65
packages/server/appPackages/testApp2/components/mike.json

@ -0,0 +1,65 @@
{
"name": "mike",
"description": "",
"inherits": "containers/two_columns",
"props": {
"children": [
{
"_component": "#children#array_element",
"control": {
"_component": "@budibase/standard-components/button",
"contentText": "Click Me",
"contentComponent": {
"_component": ""
},
"className": "default",
"disabled": false,
"onClick": [
{
"##eventHandlerType": "Set State",
"parameters": {
"path": "SomeText",
"value": "hello !"
}
}
]
},
"gridColumn": "left",
"gridRow": "",
"gridColumnStart": "",
"gridColumnEnd": "",
"gridRowStart": "",
"gridRowEnd": ""
},
{
"_component": "#children#array_element",
"control": {
"_component": "@budibase/standard-components/button",
"contentText": {
"##bbstate": "SomeText",
"##bbstatefallback": "(none)"
},
"contentComponent": {
"_component": ""
},
"className": "default",
"disabled": false,
"onClick": []
},
"gridColumn": "",
"gridRow": "",
"gridColumnStart": "",
"gridColumnEnd": "",
"gridRowStart": "",
"gridRowEnd": ""
}
]
},
"tags": [
"div",
"container",
"layout",
"panel",
"grid"
]
}

10
packages/server/appPackages/testApp2/pages.json

@ -1,13 +1,15 @@
{
"main": {
"index": {},
"appBody": ""
"index": {
"title": "main yeo"
},
"appBody": "mike"
},
"unauthenticated": {
"index": {
"title": "Test App Two"
"title": "main"
},
"appBody": "login"
"appBody": "containers/two_columns"
},
"componentLibraries": [
"@budibase/standard-components"

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

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

2
packages/server/appPackages/testApp2/public/main/clientAppDefinition.js

@ -1 +1 @@
window['##BUDIBASE_APPDEFINITION##'] = {"hierarchy":{"name":"root","type":"root","children":[{"name":"customer","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"name","getInitialValue":"default","getUndefinedValue":"default"}],"children":[{"name":"invoiceyooo","type":"record","fields":[{"name":"amount","type":"number","typeOptions":{"minValue":99999999999,"maxValue":99999999999,"decimalPlaces":2},"label":"amount","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":2,"indexes":[],"allidsShardFactor":1,"collectionName":"invoices","isSingle":false}],"validationRules":[],"nodeId":1,"indexes":[{"name":"customer_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":5}],"allidsShardFactor":64,"collectionName":"customers","isSingle":false}],"pathMaps":[],"indexes":[{"name":"Yeo index","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[1],"nodeId":4},{"name":"everyones_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":6}],"nodeId":0},"componentLibraries":["budibase-standard-components"],"appRootPath":"/testApp2","props":{}}
window['##BUDIBASE_APPDEFINITION##'] = {"hierarchy":{"name":"root","type":"root","children":[{"name":"customer","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"name","getInitialValue":"default","getUndefinedValue":"default"}],"children":[{"name":"invoiceyooo","type":"record","fields":[{"name":"amount","type":"number","typeOptions":{"minValue":99999999999,"maxValue":99999999999,"decimalPlaces":2},"label":"amount","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":2,"indexes":[],"allidsShardFactor":1,"collectionName":"invoices","isSingle":false}],"validationRules":[],"nodeId":1,"indexes":[{"name":"customer_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":5}],"allidsShardFactor":64,"collectionName":"customers","isSingle":false}],"pathMaps":[],"indexes":[{"name":"Yeo index","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[1],"nodeId":4},{"name":"everyones_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":6}],"nodeId":0},"componentLibraries":[{"importPath":"/lib/node_modules/@budibase/standard-components/dist/index.js","libName":"@budibase/standard-components"}],"appRootPath":"/testApp2","props":{"_component":"@budibase/standard-components/grid","gridTemplateRows":"","gridTemplateColumns":"[left] 1fr [right] 1fr","children":[{"_component":"children#array_element#","control":{"_component":"@budibase/standard-components/button","contentText":"Click Me","contentComponent":{"_component":""},"className":"default","disabled":false,"onClick":[{"##eventHandlerType":"Set State","parameters":{"path":"SomeText","value":"hello !"}}]},"gridColumn":"left","gridRow":"","gridColumnStart":"","gridColumnEnd":"","gridRowStart":"","gridRowEnd":""},{"_component":"children#array_element#","control":{"_component":"@budibase/standard-components/button","contentText":{"##bbstate":"SomeText","##bbstatefallback":"(none)"},"contentComponent":{"_component":""},"className":"default","disabled":false,"onClick":[]},"gridColumn":"","gridRow":"","gridColumnStart":"","gridColumnEnd":"","gridRowStart":"","gridRowEnd":""}],"width":"auto","height":"auto","containerClass":"","itemContainerClass":""}}

18
packages/server/appPackages/testApp2/public/main/index.html

@ -4,16 +4,26 @@
<meta charset='utf8'>
<meta name='viewport' content='width=device-width'>
<title>Budibase App</title>
<link rel='icon' type='image/png' href='/testApp2/_shared/favicon.png'>
<title>main yeo</title>
<link rel='icon' type='image/png' href='/testApp2//_shared/favicon.png'>
<style>
html, body {
height: 100%;
width: 100%;
}
</style>
<script src='/testApp2/clientAppDefinition.js'></script>
<script src='/testApp2/budibase-client.js'></script>
<script>
loadBudibase();
</script>
</head>
<body id="app">
<script src='/testApp2/clientAppDefinition.js'></script>
</body>
</html>

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

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

2
packages/server/appPackages/testApp2/public/unauthenticated/clientAppDefinition.js

@ -1 +1 @@
window['##BUDIBASE_APPDEFINITION##'] = {"hierarchy":{"name":"root","type":"root","children":[{"name":"customer","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"name","getInitialValue":"default","getUndefinedValue":"default"}],"children":[{"name":"invoiceyooo","type":"record","fields":[{"name":"amount","type":"number","typeOptions":{"minValue":99999999999,"maxValue":99999999999,"decimalPlaces":2},"label":"amount","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":2,"indexes":[],"allidsShardFactor":1,"collectionName":"invoices","isSingle":false}],"validationRules":[],"nodeId":1,"indexes":[{"name":"customer_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":5}],"allidsShardFactor":64,"collectionName":"customers","isSingle":false}],"pathMaps":[],"indexes":[{"name":"Yeo index","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[1],"nodeId":4},{"name":"everyones_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":6}],"nodeId":0},"componentLibraries":["budibase-standard-components"],"appRootPath":"/testApp2","props":{"_component":"budibase-standard-components/login","logo":"/_shared/budibase-logo.png","loginRedirect":"","usernameLabel":"Username","passwordLabel":"Password","loginButtonLabel":"Login"}}
window['##BUDIBASE_APPDEFINITION##'] = {"hierarchy":{"name":"root","type":"root","children":[{"name":"customer","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"name","getInitialValue":"default","getUndefinedValue":"default"}],"children":[{"name":"invoiceyooo","type":"record","fields":[{"name":"amount","type":"number","typeOptions":{"minValue":99999999999,"maxValue":99999999999,"decimalPlaces":2},"label":"amount","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":2,"indexes":[],"allidsShardFactor":1,"collectionName":"invoices","isSingle":false}],"validationRules":[],"nodeId":1,"indexes":[{"name":"customer_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":5}],"allidsShardFactor":64,"collectionName":"customers","isSingle":false}],"pathMaps":[],"indexes":[{"name":"Yeo index","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[1],"nodeId":4},{"name":"everyones_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":6}],"nodeId":0},"componentLibraries":[{"importPath":"/lib/node_modules/@budibase/standard-components/dist/index.js","libName":"@budibase/standard-components"}],"appRootPath":"/testApp2","props":{"_component":"@budibase/standard-components/grid","gridTemplateRows":"","gridTemplateColumns":"[left] 1fr [right] 1fr","children":[],"width":"auto","height":"auto","containerClass":"","itemContainerClass":""}}

18
packages/server/appPackages/testApp2/public/unauthenticated/index.html

@ -4,16 +4,26 @@
<meta charset='utf8'>
<meta name='viewport' content='width=device-width'>
<title>Test App Two</title>
<link rel='icon' type='image/png' href='/testApp2/_shared/favicon.png'>
<title>main</title>
<link rel='icon' type='image/png' href='/testApp2//_shared/favicon.png'>
<style>
html, body {
height: 100%;
width: 100%;
}
</style>
<script src='/testApp2/clientAppDefinition.js'></script>
<script src='/testApp2/budibase-client.js'></script>
<script>
loadBudibase();
</script>
</head>
<body id="app">
<script src='/testApp2/clientAppDefinition.js'></script>
</body>
</html>

2
packages/server/builder/budibase-client.esm.mjs

File diff suppressed because one or more lines are too long

44
packages/server/builder/bundle.css

@ -1,43 +1 @@
main.svelte-pnvh8{height:100%;width:100%;font-family:"Lato", Helvetica, Arial, sans-serif}.settings.svelte-pnvh8{position:absolute;bottom:25px;right:25px}
.root.svelte-jymnqv{position:fixed;margin:0 auto;text-align:center;top:20%;width:100%}.inner.svelte-jymnqv{display:inline-block;margin:auto}.logo.svelte-jymnqv{width:300px;margin-bottom:40px}.root.svelte-jymnqv .option{width:250px}.app-link.svelte-jymnqv{margin-top:10px;display:block}
.root.svelte-h9y88z{height:100%;width:100%;display:flex;flex-direction:column}.top-nav.svelte-h9y88z{flex:0 0 auto;height:25px;background:white;border-style:solid;border-width:0px 0px 1px 0px;border-color:var(--lightslate);padding:5px;width:100%}.content.svelte-h9y88z{flex:1 1 auto;width:100%;height:100px}.content.svelte-h9y88z>div.svelte-h9y88z{height:100%;width:100%}.topnavitem.svelte-h9y88z{cursor:pointer;color:var(--slate);padding:0px 15px}.topnavitem.svelte-h9y88z:hover{color:var(--secondary75)}.active.svelte-h9y88z{color:var(--secondary100)}
.root.svelte-tavaga{height:100%;display:flex}.content.svelte-tavaga{flex:1 1 auto;height:100%;background-color:var(--white);margin:0}.nav.svelte-tavaga{flex:0 1 auto;width:300px;height:100%}
.border-normal.svelte-7rfkdx{border-radius:var(--borderradiusall)}.border-left.svelte-7rfkdx{border-radius:var(--borderradius) 0 0 var(--borderradius)}.border-right.svelte-7rfkdx{border-radius:0 var(--borderradius) var(--borderradius) 0}.border-middle.svelte-7rfkdx{border-radius:0}button.svelte-7rfkdx{border-style:solid;padding:7px 15px;cursor:pointer}.primary.svelte-7rfkdx{background-color:var(--primary100);border-color:var(--primary100);color:var(--white)}.primary.svelte-7rfkdx:hover{background-color:var(--primary75);border-color:var(--primary75)}.primary.svelte-7rfkdx:active{background-color:var(--primarydark);border-color:var(--primarydark)}.primary-outline.svelte-7rfkdx{background-color:var(--white);border-color:var(--primary100);color:var(--primary100)}.primary-outline.svelte-7rfkdx:hover{background-color:var(--primary10)}.primary-outline.svelte-7rfkdx:pressed{background-color:var(--primary25)}.secondary.svelte-7rfkdx{background-color:var(--secondary100);border-color:var(--secondary100);color:var(--white)}.secondary.svelte-7rfkdx:hover{background-color:var(--secondary75);border-color:var(--secondary75)}.secondary.svelte-7rfkdx:pressed{background-color:var(--secondarydark);border-color:var(--secondarydark)}.secondary-outline.svelte-7rfkdx{background-color:var(--white);border-color:var(--secondary100);color:var(--secondary100)}.secondary-outline.svelte-7rfkdx:hover{background-color:var(--secondary10)}.secondary-outline.svelte-7rfkdx:pressed{background-color:var(--secondary25)}.success.svelte-7rfkdx{background-color:var(--success100);border-color:var(--success100);color:var(--white)}.success.svelte-7rfkdx:hover{background-color:var(--success75);border-color:var(--success75)}.success.svelte-7rfkdx:pressed{background-color:var(--successdark);border-color:var(--successdark)}.success-outline.svelte-7rfkdx{background-color:var(--white);border-color:var(--success100);color:var(--success100)}.success-outline.svelte-7rfkdx:hover{background-color:var(--success10)}.success-outline.svelte-7rfkdx:pressed{background-color:var(--success25)}.deletion.svelte-7rfkdx{background-color:var(--deletion100);border-color:var(--deletion100);color:var(--white)}.deletion.svelte-7rfkdx:hover{background-color:var(--deletion75);border-color:var(--deletion75)}.deletion.svelte-7rfkdx:pressed{background-color:var(--deletiondark);border-color:var(--deletiondark)}.deletion-outline.svelte-7rfkdx{background-color:var(--white);border-color:var(--deletion100);color:var(--deletion100)}.deletion-outline.svelte-7rfkdx:hover{background-color:var(--deletion10)}.deletion-outline.svelte-7rfkdx:pressed{background-color:var(--deletion25)}
button.svelte-4po3k2{border-style:none;background-color:rgba(0,0,0,0);cursor:pointer;outline:none}button.svelte-4po3k2:hover{color:var(--hovercolor)}button.svelte-4po3k2:active{outline:none}
.root.svelte-1rbfs7z{display:grid;grid-template-columns:[uiNav] 250px [preview] auto [properties] 300px;height:100%;width:100%}.ui-nav.svelte-1rbfs7z{grid-column-start:uiNav;background-color:var(--primary10);height:100%}.properties-pane.svelte-1rbfs7z{grid-column-start:properties;background-color:var(--primary10);height:100%}.pages-list-container.svelte-1rbfs7z{padding-top:20px}.nav-group-header.svelte-1rbfs7z{font-size:10pt;padding-left:10px}.nav-items-container.svelte-1rbfs7z{padding-top:10px}.nav-group-header.svelte-1rbfs7z{display:grid;grid-template-columns:[icon] auto [title] 1fr [button] auto;padding:10px 2px 0px 7px}.nav-group-header.svelte-1rbfs7z>div.svelte-1rbfs7z:nth-child(1){padding:0px 7px 0px 0px;vertical-align:bottom;grid-column-start:icon;margin-right:5px}.nav-group-header.svelte-1rbfs7z>span.svelte-1rbfs7z:nth-child(2){margin-left:5px;vertical-align:bottom;grid-column-start:title;margin-top:auto}.nav-group-header.svelte-1rbfs7z>div.svelte-1rbfs7z:nth-child(3){vertical-align:bottom;grid-column-start:button;cursor:pointer;color:var(--slate)}.nav-group-header.svelte-1rbfs7z>div.svelte-1rbfs7z:nth-child(3):hover{color:var(--primary75)}
h4.svelte-o0id5a{margin-top:20px}
.root.svelte-85bkcq{height:100%;position:relative}.actions-header.svelte-85bkcq{flex:0 1 auto}.node-view.svelte-85bkcq{overflow-y:auto;flex:1 1 auto}
.root.svelte-1be865r{padding:10px}.edit-button.svelte-1be865r{cursor:pointer;color:var(--white)}tr.svelte-1be865r:hover .edit-button.svelte-1be865r{color:var(--secondary75)}
.root.svelte-1py90dy{height:100%;background-color:var(--primary10)}.items-root.svelte-1py90dy{display:flex;flex-direction:column;max-height:100%;height:10px}.hierarchy.svelte-1py90dy{flex:1 1 auto}.hierarchy-title-row.svelte-1py90dy{padding:15px 7px;font-size:12pt;display:flex;font-weight:bold}.hierarchy-title.svelte-1py90dy{flex:auto 1 1}.space-filler.svelte-1py90dy{flex:1 1 auto}
.root.svelte-1y6dy5x{padding:10px}
.root.svelte-1ba51k0{color:var(--secondary50)}.hierarchy-item.svelte-1ba51k0{cursor:pointer;padding:5px 0px}.hierarchy-item.svelte-1ba51k0:hover{color:var(--secondary75)}.component.svelte-1ba51k0{margin-left:5px}.currentfolder.svelte-1ba51k0{color:var(--secondary100)}.selected.svelte-1ba51k0{color:var(--primary100)}.title.svelte-1ba51k0{margin-left:10px}
.root.svelte-xai2hc{height:100%;border-style:solid;border-color:var(--lightslate);border-width:0px 0px 0px 1px}.padding.svelte-xai2hc{padding:0px 5px 0px 10px}.title.svelte-xai2hc{background-color:white;padding:3px;display:grid;grid-template-columns:[name] 1fr [actions] auto}.title.svelte-xai2hc>div.svelte-xai2hc:nth-child(1){grid-column-start:name;color:var(--secondary100)}.title.svelte-xai2hc>div.svelte-xai2hc:nth-child(2){grid-column-start:actions}.section-header.svelte-xai2hc{font-style:italic;color:var(--slate);border-style:solid;border-color:var(--lightslate);border-width:0px 0px 1px 0px}.section-header.svelte-xai2hc{vertical-align:middle;margin-top:20px}
.root.svelte-1iwq1b2{padding-bottom:10px;padding-left:10px;font-size:16px;color:var(--secondary50)}.hierarchy-item.svelte-1iwq1b2{cursor:pointer;padding:5px 0px}.hierarchy-item.svelte-1iwq1b2:hover{color:var(--secondary75)}.component.svelte-1iwq1b2{margin-left:5px}.selected.svelte-1iwq1b2{color:var(--primary100)}.title.svelte-1iwq1b2{margin-left:10px}
.component-preview.svelte-1rf8xuh{display:grid;grid-template-rows:[top] 1fr [middle] auto [bottom] 1fr;grid-template-columns:[left] 1fr [middle] auto [right] 1fr;grid-column-start:preview;height:100%}.component-container.svelte-1rf8xuh{grid-row-start:middle;grid-column-start:middle}
h1.svelte-2ukyrk{font-size:1.2em}
.root.svelte-is81a4{padding:15px}.help-text.svelte-is81a4{color:var(--slate);font-size:10pt}
.section-container.svelte-1t0x31f{padding:15px;border-style:dotted;border-width:1px;border-color:var(--lightslate);border-radius:2px}.section-container.svelte-1t0x31f:nth-child(1){margin-bottom:15px}.row-text.svelte-1t0x31f{margin-right:15px;color:var(--primary100)}input.svelte-1t0x31f{margin-right:15px}p.svelte-1t0x31f>span.svelte-1t0x31f{margin-left:30px}.header.svelte-1t0x31f{display:grid;grid-template-columns:[title] 1fr [icon] auto}.header.svelte-1t0x31f>div.svelte-1t0x31f:nth-child(1){grid-column-start:title}.header.svelte-1t0x31f>div.svelte-1t0x31f:nth-child(2){grid-column-start:icon}
.root.svelte-1rctf7f{display:block;font-size:13pt;width:100%;cursor:pointer}.title.svelte-1rctf7f{font:var(--bodytext);padding-top:10px;padding-right:5px;padding-bottom:10px;color:var(--secondary100)}.title.svelte-1rctf7f:hover{background-color:var(--secondary10)}
.root.svelte-gq7l8x{height:100%;padding:15px}.fields-table.svelte-gq7l8x{margin:10px;border-collapse:collapse}.add-field-button.svelte-gq7l8x{margin-left:15px;cursor:pointer}.edit-button.svelte-gq7l8x{cursor:pointer;color:var(--white)}.edit-button.svelte-gq7l8x:hover{color:var(--secondary75)}th.svelte-gq7l8x{text-align:left}td.svelte-gq7l8x{padding:5px 30px 5px 0px;margin:0}thead.svelte-gq7l8x>tr.svelte-gq7l8x{border-width:0px 0px 1px 0px;border-style:solid;border-color:var(--secondary75);margin-bottom:20px}tbody.svelte-gq7l8x>tr.svelte-gq7l8x{border-width:0px 0px 1px 0px;border-style:solid;border-color:var(--primary10)}tbody.svelte-gq7l8x>tr.svelte-gq7l8x:hover{background-color:var(--primary10)}tbody.svelte-gq7l8x>tr:hover .edit-button.svelte-gq7l8x{color:var(--secondary75)}.index-container.svelte-gq7l8x{border-style:solid;border-width:0 0 1px 0;border-color:var(--secondary25);padding:10px;margin-bottom:5px}.index-label.svelte-gq7l8x{color:var(--slate)}.index-name.svelte-gq7l8x{font-weight:bold;color:var(--primary100)}.index-container.svelte-gq7l8x code.svelte-gq7l8x{margin:0;display:inline;background-color:var(--primary10);color:var(--secondary100);padding:3px}.index-field-row.svelte-gq7l8x{margin-top:7px}
.root.svelte-1fkfoam{height:100%;padding:15px}.allowed-records.svelte-1fkfoam{margin:20px 0px}.allowed-records.svelte-1fkfoam>span.svelte-1fkfoam{margin-right:30px}
.root.svelte-160njkp{padding:5px;top:0;width:100%}
.dropdown-background.svelte-179p8ge{position:fixed;top:0;left:0;width:100vw;height:100vh}.root.svelte-179p8ge{cursor:pointer;z-index:1}.dropdown-content.svelte-179p8ge{position:absolute;background-color:var(--white);min-width:160px;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);z-index:1;font-weight:normal;border-style:solid;border-width:1px;border-color:var(--secondary10)}.dropdown-content.svelte-179p8ge:not(:focus){display:none}.action-row.svelte-179p8ge{padding:7px 10px;cursor:pointer}.action-row.svelte-179p8ge:hover{background-color:var(--primary100);color:var(--white)}
.nav-item.svelte-1e0ymco{padding:7px;font-size:12pt;font-weight:bold;cursor:pointer;flex:0 0 auto}.nav-item.svelte-1e0ymco:hover{background-color:var(--primary10)}.active.svelte-1e0ymco{background-color:var(--primary10)}
.root.svelte-d6wwkb{display:flex}.root.svelte-d6wwkb:last-child{border-radius:0 var(--borderradius) var(--borderradius) 0}.root.svelte-d6wwkb:first-child{border-radius:var(--borderradius) 0 0 var(--borderradius)}.root.svelte-d6wwkb:not(:first-child):not(:last-child){border-radius:0}
.edit-button.svelte-12jzg4k{cursor:pointer;color:var(--white)}tr.svelte-12jzg4k:hover .edit-button.svelte-12jzg4k{color:var(--secondary75)}
.edit-button.svelte-1le5bpl{cursor:pointer;color:var(--white)}tr.svelte-1le5bpl:hover .edit-button.svelte-1le5bpl{color:var(--secondary75)}
.root.svelte-10avxhq{display:block;font-size:12pt;width:100%;cursor:pointer}.title.svelte-10avxhq{padding-top:5px;padding-right:5px;padding-bottom:5px;color:var(--secondary100)}.title.svelte-10avxhq:hover{background-color:var(--secondary10)}.active.svelte-10avxhq{background-color:var(--primary10)}
.root.svelte-beukw7{font-size:10pt}.padding.svelte-beukw7{padding:0 10px}.inherited-title.svelte-beukw7{margin-top:40px;display:grid;grid-template-columns:[name] 1fr [actions] auto;border-style:solid;border-width:0px 0px 1px 0px;border-color:var(--lightslate);font-style:italic}.inherited-title.svelte-beukw7>div.svelte-beukw7:nth-child(1){grid-column-start:name;color:var(--slate)}.inherited-title.svelte-beukw7>div.svelte-beukw7:nth-child(2){grid-column-start:actions;color:var(--secondary100)}
.info-text.svelte-um9cf7{font-size:0.8em;color:var(--slate)}
.title.svelte-1pp53c5{padding:3px;background-color:white;color:var(--secondary100);border-style:solid;border-width:1px 0 0 0;border-color:var(--lightslate)}.title.svelte-1pp53c5>span.svelte-1pp53c5{margin-left:10px}
.component.svelte-13tuzj8{padding:5px;border-style:solid;border-width:0 0 1px 0;border-color:var(--lightslate);cursor:pointer}.component.svelte-13tuzj8:hover{background-color:var(--primary10)}.component.svelte-13tuzj8>.title.svelte-13tuzj8{font-size:13pt;color:var(--secondary100)}.component.svelte-13tuzj8>.description.svelte-13tuzj8{font-size:10pt;color:var(--primary75);font-style:italic}
textarea.svelte-1ooq0hh{padding:3px;background:var(--darkslate);color:var(--white);font-family:'Courier New', Courier, monospace;width:95%;height:100px}
.error-container.svelte-jwy920{padding:10px;border-style:solid;border-color:var(--deletion100);border-radius:var(--borderradiusall);background:var(--deletion75)}.error-row.svelte-jwy920{padding:5px 0px}
input.svelte-66516k{margin-right:7px}
.root.svelte-emcy8y{padding:10px}.option-container.svelte-emcy8y{border-style:dotted;border-width:1px;border-color:var(--primary75);padding:3px;margin-right:5px}
.root.svelte-woqcuf{display:grid;grid-template-columns:[name] 1fr [actions] auto}.root.svelte-woqcuf>div.svelte-woqcuf:nth-child(1){grid-column-start:name;color:var(--secondary50)}.root.svelte-woqcuf>div.svelte-woqcuf:nth-child(2){grid-column-start:actions}.selectedname.svelte-woqcuf{font-weight:bold;color:var(--secondary)}
.root.svelte-w5on8s{padding:3px 5px 7px 10px;border-style:dotted;border-width:0 0 1px 0;border-color:var(--primary25)}
textarea.svelte-1wfv4cc{width:300px;height:200px}
.addelement-container.svelte-jliz3p{cursor:pointer;padding:3px 0px;text-align:center}.addelement-container.svelte-jliz3p:hover{background-color:var(--primary25)}.item-container.svelte-jliz3p{padding-left:3px;background:var(--secondary10)}
/*# sourceMappingURL=bundle.css.map */
main.svelte-24wuof{height:100%;width:100%;font-family:"Roboto", Helvetica, Arial, sans-serif}.settings.svelte-24wuof{position:absolute;bottom:25px;right:25px}

106
packages/server/builder/bundle.css.map

File diff suppressed because one or more lines are too long

4322
packages/server/builder/bundle.js

File diff suppressed because it is too large

2
packages/server/builder/bundle.js.map

File diff suppressed because one or more lines are too long

BIN
packages/server/builder/favicon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

102
packages/server/builder/fonts.css

@ -1,61 +1,47 @@
/* latin-ext */
@font-face {
font-family: 'Lato';
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Lato';
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Black latin-ext */
@font-face {
font-family: 'Lato Black';
font-weight: 900;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Black latin */
@font-face {
font-family: 'Lato Black';
font-weight: 900;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Bold latin-ext */
@font-face {
font-family: 'Lato Bold';
font-weight: 700;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Bold latin */
@font-face {
font-family: 'Lato Bold';
font-weight: 700;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Semi Bold latin-ext */
@font-face {
font-family: 'Lato Semi Bold';
font-weight: 600;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Semi Bold latin */
@font-face {
font-family: 'Lato Semi Bold';
font-weight: 600;
src: local('Lato Regular'), local('Lato-Regular'), url(/_builder/assets/lato-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
/* roboto-regular - latin-ext_latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'),
url('/_builder/assets/roboto-v20-latin-ext_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/_builder/assets/roboto-v20-latin-ext_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-300 - latin-ext_latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'),
url('/_builder/assets/roboto-v20-latin-ext_latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/_builder/assets/roboto-v20-latin-ext_latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-500 - latin-ext_latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'),
url('/_builder/assets/roboto-v20-latin-ext_latin-500.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/_builder/assets/roboto-v20-latin-ext_latin-500.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-700 - latin-ext_latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'),
url('/_builder/assets/roboto-v20-latin-ext_latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/_builder/assets/roboto-v20-latin-ext_latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-900 - latin-ext_latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 900;
src: local('Roboto Black'), local('Roboto-Black'),
url('/_builder/assets/roboto-v20-latin-ext_latin-900.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/_builder/assets/roboto-v20-latin-ext_latin-900.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}

19
packages/server/builder/global.css

@ -4,6 +4,7 @@
--primary50: #454CA080;
--primary25: #454CA040;
--primary10: #454CA01A;
--primary5: #454ca00c;
--primarydark: #3F448A;
--secondary100: #162B4DFF;
@ -11,6 +12,7 @@
--secondary50: #162B4D80;
--secondary25: #162B4D40;
--secondary10: #162B4D1A;
--secondary5: rgba(22, 43, 77, 0.068);
--secondarydark: #3F448A;
--tertiary: #F2F5F7;
@ -30,17 +32,18 @@
--deletiondark: #CF4046;
--white: #FFFFFF;
--darkslate: #5C6B82;
--slate: #8B95A6;
--lightslate: rgb(203, 212, 228);
--darkslate: #1a202c;
--slate: #a0aec0;
--lightslate: #f7fafc;
--borderradius: 2px;
--borderradiusall: 2px 2px 2px 2px;
--fontblack: "Lato Black";
--fontbold: "Lato Bold";
--fontsemibold: "Lato Semi Bold";
--fontnormal: "Lato";
--fontblack: "Roboto Black";
--fontbold: "Roboto Bold";
--fontsemibold: "Roboto Medium";
--fontnormal: "Roboto";
--fontlight: "Roboto Light";
--bodytext: var(--fontnormal) "regular" var(--secondary100) 16pt;
--bigbodytext: var(--fontnormal) "regular" var(--secondary100) 20pt;
@ -79,7 +82,7 @@ h3 {
}
h4 {
font-family: var(--fontsemibold);
font-family: var(--fontbold);
font-size: 18pt;
color: var(--secondary100);
}

11
packages/server/utilities/builder/index.template.html

@ -7,13 +7,22 @@
<title>{{ title }}</title>
<link rel='icon' type='image/png' href='{{ favicon }}'>
<style>
html, body {
height: 100%;
width: 100%;
}
</style>
{{ each(options.stylesheets) }}
<link rel='stylesheet' href='{{ @this }}'>
{{ /each }}
<script src='{{ appRootPath }}/clientAppDefinition.js'></script>
<script src='{{ appRootPath }}/budibase-client.js'></script>
<script>
loadBudibase();
</script>
</head>

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

Loading…
Cancel
Save