Merge pull request from shogunpurple/housekeeping

running prettier over codebase, removing merge files
This commit is contained in:
Martin McKeaveney 2020-02-03 09:52:01 +00:00 committed by GitHub
commit 66cbb574b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
438 changed files with 251094 additions and 187589 deletions
.eslintrc.json.prettierrcpackage.json
packages
bootstrap-components
builder

View File

@ -2,7 +2,8 @@
"env": {
"browser": true,
"es6": true,
"jest": true
"jest": true,
"node": true
},
"parserOptions": {
"ecmaVersion": 2019,

View File

@ -3,5 +3,6 @@
"semi": false,
"singleQuote": false,
"trailingComma": "es5",
"plugins": ["prettier-plugin-svelte"]
"plugins": ["prettier-plugin-svelte"],
"svelteSortOrder" : "scripts-markup-styles"
}

View File

@ -7,7 +7,8 @@
"eslint-plugin-svelte3": "^2.7.3",
"lerna": "^3.14.1",
"prettier": "^1.19.1",
"prettier-plugin-svelte": "^0.7.0"
"prettier-plugin-svelte": "^0.7.0",
"svelte": "^3.18.1"
},
"dependencies": {},
"scripts": {
@ -18,6 +19,7 @@
"dev": "lerna run --parallel --stream dev:builder",
"test": "lerna run test",
"lint": "eslint packages",
"format": "prettier --write \"{,!(node_modules)/**/}*.{js,jsx}\""
"lint:fix": "eslint --fix packages",
"format": "prettier --write \"{,!(node_modules)/**/}*.{js,jsx,svelte}\""
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1 +1,103 @@
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: ["budibase-standard-components"],
appRootPath: "/testApp2",
props: {},
}

View File

@ -1,20 +1,20 @@
import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
import svelte from "rollup-plugin-svelte"
import resolve from "rollup-plugin-node-resolve"
export default {
input: 'src/index.js',
output: [
{
file: "dist/index.js",
format: 'esm',
name:"budibaseStandardComponents",
sourcemap: "inline"
}
],
plugins: [
svelte({
hydratable:true
}),
resolve()
]
};
input: "src/index.js",
output: [
{
file: "dist/index.js",
format: "esm",
name: "budibaseStandardComponents",
sourcemap: "inline",
},
],
plugins: [
svelte({
hydratable: true,
}),
resolve(),
],
}

View File

@ -1,16 +1,14 @@
import resolve from 'rollup-plugin-node-resolve';
import resolve from "rollup-plugin-node-resolve"
export default {
input: 'src/generators.js',
output: [
{
file: "dist/generators.js",
format: 'esm',
name:"budibaseStandardComponents",
sourcemap: "inline"
}
],
plugins: [
resolve()
]
};
input: "src/generators.js",
output: [
{
file: "dist/generators.js",
format: "esm",
name: "budibaseStandardComponents",
sourcemap: "inline",
},
],
plugins: [resolve()],
}

View File

@ -1,89 +1,131 @@
import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import json from 'rollup-plugin-json';
import svelte from "rollup-plugin-svelte"
import resolve from "rollup-plugin-node-resolve"
import commonjs from "rollup-plugin-commonjs"
import livereload from "rollup-plugin-livereload"
import { terser } from "rollup-plugin-terser"
import json from "rollup-plugin-json"
const production = !process.env.ROLLUP_WATCH;
const production = !process.env.ROLLUP_WATCH
const lodash_fp_exports = [
"find", "isUndefined", "split",
"last", "union", "reduce", "isObject",
"cloneDeep", "some", "isArray", "map",
"filter", "keys", "isFunction", "isEmpty",
"countBy", "join", "includes", "flatten",
"constant", "first", "intersection", "take",
"has", "mapValues", "isString", "isBoolean",
"isNull", "isNumber", "isObjectLike", "isDate",
"clone", "values", "keyBy", "isNaN",
"isInteger", "toNumber"];
"find",
"isUndefined",
"split",
"last",
"union",
"reduce",
"isObject",
"cloneDeep",
"some",
"isArray",
"map",
"filter",
"keys",
"isFunction",
"isEmpty",
"countBy",
"join",
"includes",
"flatten",
"constant",
"first",
"intersection",
"take",
"has",
"mapValues",
"isString",
"isBoolean",
"isNull",
"isNumber",
"isObjectLike",
"isDate",
"clone",
"values",
"keyBy",
"isNaN",
"isInteger",
"toNumber",
]
const lodash_exports = [
"flow", "head",
"tail", "findIndex", "startsWith",
"dropRight", "takeRight",
"trim", "split", "replace",
"merge", "assign"];
"flow",
"head",
"tail",
"findIndex",
"startsWith",
"dropRight",
"takeRight",
"trim",
"split",
"replace",
"merge",
"assign",
]
const coreExternal = [
"lodash", "lodash/fp", "date-fns",
"lunr", "safe-buffer", "shortid",
"@nx-js/compiler-util"
];
"lodash",
"lodash/fp",
"date-fns",
"lunr",
"safe-buffer",
"shortid",
"@nx-js/compiler-util",
]
export default {
input: 'src/Test/testMain.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/bundle.js'
},
plugins: [
svelte({
// enable run-time checks when not in production
dev: !production,
// we'll extract any component CSS out into
// a separate file — better for performance
css: css => {
css.write('public/bundle.css');
},
hydratable:true
}),
input: "src/Test/testMain.js",
output: {
sourcemap: true,
format: "iife",
name: "app",
file: "public/bundle.js",
},
plugins: [
svelte({
// enable run-time checks when not in production
dev: !production,
// we'll extract any component CSS out into
// a separate file — better for performance
css: css => {
css.write("public/bundle.css")
},
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration —
// consult the documentation for details:
// https://github.com/rollup/rollup-plugin-commonjs
resolve({
browser: true,
dedupe: importee => {
return importee === 'svelte'
|| importee.startsWith('svelte/')
|| coreExternal.includes(importee);
}
}),
commonjs({
namedExports: {
"lodash/fp": lodash_fp_exports,
"lodash":lodash_exports,
"shortid": ["generate"]
}
}),
json(),
hydratable: true,
}),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration —
// consult the documentation for details:
// https://github.com/rollup/rollup-plugin-commonjs
resolve({
browser: true,
dedupe: importee => {
return (
importee === "svelte" ||
importee.startsWith("svelte/") ||
coreExternal.includes(importee)
)
},
}),
commonjs({
namedExports: {
"lodash/fp": lodash_fp_exports,
lodash: lodash_exports,
shortid: ["generate"],
},
}),
json(),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload("public"),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser(),
],
watch: {
clearScreen: false,
},
}

View File

@ -1,61 +1,92 @@
const { readdir, stat, copyFile } = require("fs-extra");
const { constants } = require("fs");
const { join, basename } = require("path");
const { readdir, stat, copyFile } = require("fs-extra")
const { constants } = require("fs")
const { join, basename } = require("path")
const packagesFolder = "..";
const packagesFolder = ".."
const jsFile = dir => join(dir, "index.js");
const generatorsFile = dir => join(dir, "generators.js");
const jsMapFile = dir => join(dir, "index.js.map");
const sourceJs = jsFile("dist");
const sourceJsMap = jsMapFile("dist");
const componentsFile = "components.json";
const sourceGenerators = generatorsFile("dist");
const jsFile = dir => join(dir, "index.js")
const generatorsFile = dir => join(dir, "generators.js")
const jsMapFile = dir => join(dir, "index.js.map")
const sourceJs = jsFile("dist")
const sourceJsMap = jsMapFile("dist")
const componentsFile = "components.json"
const sourceGenerators = generatorsFile("dist")
const appPackages = join(packagesFolder, "server", "appPackages");
const appPackages = join(packagesFolder, "server", "appPackages")
const publicMain = appName => join(appPackages, appName, "public", "main", "lib", "node_modules", "@budibase", "bootstrap-components");
const publicUnauth = appName => join(appPackages, appName, "public", "unauthenticated", "lib", "node_modules", "@budibase", "bootstrap-components");
const nodeModulesDist = appName => join(appPackages, appName, "node_modules", "@budibase", "bootstrap-components", "dist");
const nodeModules = appName => join(appPackages, appName, "node_modules", "@budibase", "bootstrap-components");
const publicMain = appName =>
join(
appPackages,
appName,
"public",
"main",
"lib",
"node_modules",
"@budibase",
"bootstrap-components"
)
const publicUnauth = appName =>
join(
appPackages,
appName,
"public",
"unauthenticated",
"lib",
"node_modules",
"@budibase",
"bootstrap-components"
)
const nodeModulesDist = appName =>
join(
appPackages,
appName,
"node_modules",
"@budibase",
"bootstrap-components",
"dist"
)
const nodeModules = appName =>
join(
appPackages,
appName,
"node_modules",
"@budibase",
"bootstrap-components"
)
(async () => {
;(async () => {
const apps = await readdir(appPackages)
const apps = await readdir(appPackages);
const copySource = file => async toDir => {
const dest = join(toDir, basename(file));
try {
await copyFile(file, dest, constants.COPYFILE_FICLONE);
console.log(`COPIED ${file} to ${dest}`);
} catch(e) {
console.log(`COPY FAILED ${file} to ${dest}: ${e}`);
}
const copySource = file => async toDir => {
const dest = join(toDir, basename(file))
try {
await copyFile(file, dest, constants.COPYFILE_FICLONE)
console.log(`COPIED ${file} to ${dest}`)
} catch (e) {
console.log(`COPY FAILED ${file} to ${dest}: ${e}`)
}
}
const copySourceJs = copySource(sourceJs);
const copySourceJsMap = copySource(sourceJsMap);
const copyGenerators = copySource(sourceGenerators);
const copyComponentsJson = copySource(componentsFile);
const copySourceJs = copySource(sourceJs)
const copySourceJsMap = copySource(sourceJsMap)
const copyGenerators = copySource(sourceGenerators)
const copyComponentsJson = copySource(componentsFile)
for(let app of apps) {
if(!(await stat(join(appPackages, app))).isDirectory()) continue;
for (let app of apps) {
if (!(await stat(join(appPackages, app))).isDirectory()) continue
await copySourceJs(nodeModulesDist(app));
await copySourceJsMap(nodeModulesDist(app));
await copyGenerators(nodeModulesDist(app));
await copySourceJs(nodeModulesDist(app))
await copySourceJsMap(nodeModulesDist(app))
await copyGenerators(nodeModulesDist(app))
await copyComponentsJson(nodeModules(app));
await copyComponentsJson(nodeModules(app))
await copySourceJs(join(publicMain(app), "dist"));
await copySourceJsMap(join(publicMain(app), "dist"));
await copyGenerators(join(publicMain(app), "dist"));
await copySourceJs(join(publicMain(app), "dist"))
await copySourceJsMap(join(publicMain(app), "dist"))
await copyGenerators(join(publicMain(app), "dist"))
await copySourceJs(join(publicUnauth(app), "dist"));
await copySourceJsMap(join(publicUnauth(app), "dist"));
await copyGenerators(join(publicUnauth(app), "dist"));
}
})();
await copySourceJs(join(publicUnauth(app), "dist"))
await copySourceJsMap(join(publicUnauth(app), "dist"))
await copyGenerators(join(publicUnauth(app), "dist"))
}
})()

View File

@ -1,47 +1,44 @@
<script>
export let formControls = []
export let formControls = [];
export let _bb
export let _bb;
let htmlElements = {}
let labelElements = {}
let labels = {}
let isInitialised = false
let htmlElements = {};
let labelElements = {};
let labels = {};
let isInitialised = false;
$: {
if (_bb && htmlElements && !isInitialised) {
let cIndex = 0
for (let c of formControls) {
labels[cIndex] = c.label
cIndex++
}
$ : {
if(_bb && htmlElements && !isInitialised) {
let cIndex = 0;
for(let c of formControls) {
labels[cIndex] = c.label;
cIndex++;
for (let el in htmlElements) {
if (formControls[el].control.controlPosition === "Before Label") {
_bb.insertChildren(
_bb.props.formControls[el].control,
htmlElements[el],
htmlElements[el].childNodes.find(n => n.tagName === "LABEL")
)
} else {
_bb.appendChildren(
_bb.props.formControls[el].control,
htmlElements[el]
)
}
for(let el in htmlElements) {
if(formControls[el].control.controlPosition === "Before Label") {
_bb.insertChildren(
_bb.props.formControls[el].control,
htmlElements[el],
htmlElements[el].childNodes.find(n => n.tagName === "LABEL"));
} else {
_bb.appendChildren(
_bb.props.formControls[el].control,
htmlElements[el]);
}
}
isInitialised = true;
}
isInitialised = true
}
}
}
</script>
<form>
{#each formControls as child, idx}
{#each formControls as child, idx}
<div class="form-group" bind:this={htmlElements[idx]}>
<label>{labels[idx]}</label>
<label>{labels[idx]}</label>
</div>
{/each}
{/each}
</form>

View File

@ -1,132 +1,119 @@
<script>
export let items = []
export let hideNavBar = false
export let selectedItem = ""
export let orientation = "horizontal" // horizontal, verical
export let alignment = "start" // start, center, end
export let pills = false
export let fill = false
export let className = ""
export let _bb
export let items = [];
export let hideNavBar=false;
export let selectedItem="";
export let orientation="horizontal"; // horizontal, verical
export let alignment="start"; // start, center, end
export let pills=false;
export let fill=false;
export let className="";
export let _bb;
let selectedIndex = -1
let styleVars = {}
let components = {}
let componentElement
let orientationClass = ""
let navClasses = ""
let currentComponent
let _selectedItem = ""
let selectedIndex = -1;
let styleVars={};
let components = {};
let componentElement;
let orientationClass="";
let navClasses="";
let currentComponent;
let _selectedItem="";
const hasComponentElements = () =>
Object.getOwnPropertyNames(componentElements).length > 0
const hasComponentElements = () =>
Object.getOwnPropertyNames(componentElements).length > 0;
const getSelectedItemByIndex = index => (index >= 0 ? items[index].title : "")
const getSelectedItemByIndex = (index) =>
index >= 0
? items[index].title
: "";
$: {
let _navClasses = ""
$: {
let _navClasses = "";
if(orientation === "vertical") {
_navClasses += " flex-column";
if (orientation === "vertical") {
_navClasses += " flex-column"
} else {
_navClasses += ` justify-content-${alignment}`;
_navClasses += ` justify-content-${alignment}`
}
if(pills)
_navClasses += " nav-pills";
if(fill)
_navClasses += " nav-fill nav-justified";
if (pills) _navClasses += " nav-pills"
navClasses = _navClasses;
if (fill) _navClasses += " nav-fill nav-justified"
navClasses = _navClasses
if(items && componentElement) {
const currentSelectedItem = getSelectedItemByIndex(selectedIndex);
if (items && componentElement) {
const currentSelectedItem = getSelectedItemByIndex(selectedIndex)
if(selectedItem && currentSelectedItem !== selectedItem) {
let i=0;
for(let item of items) {
if(item.title === selectedItem) {
SelectItem(i);
}
i++;
}
} else if(!selectedItem) {
SelectItem(-1);
if (selectedItem && currentSelectedItem !== selectedItem) {
let i = 0
for (let item of items) {
if (item.title === selectedItem) {
SelectItem(i)
}
i++
}
} else if (!selectedItem) {
SelectItem(-1)
}
}
}
}
const SelectItem = (index) => {
selectedIndex = index;
const newSelectedItem = getSelectedItemByIndex(index);
if(newSelectedItem !== selectedItem) {
selectedItem = newSelectedItem;
const SelectItem = index => {
selectedIndex = index
const newSelectedItem = getSelectedItemByIndex(index)
if (newSelectedItem !== selectedItem) {
selectedItem = newSelectedItem
}
if(currentComponent) {
try {
currentComponent.$destroy();
} catch(_) {}
if (currentComponent) {
try {
currentComponent.$destroy()
} catch (_) {}
}
if(index >= 0)
currentComponent = _bb.hydrateChildren(
_bb.props.items[index].component, componentElement);
if (index >= 0)
currentComponent = _bb.hydrateChildren(
_bb.props.items[index].component,
componentElement
)
}
}
const onSelectItemClicked = index => () => {
if(_bb.props.selectedItem) {
// binding - call state, which should SelectItem(..)
const selectedItemBinding = _bb.props.selectedItem;
_bb.setStateFromBinding(
selectedItemBinding, getSelectedItemByIndex(index))
const onSelectItemClicked = index => () => {
if (_bb.props.selectedItem) {
// binding - call state, which should SelectItem(..)
const selectedItemBinding = _bb.props.selectedItem
_bb.setStateFromBinding(
selectedItemBinding,
getSelectedItemByIndex(index)
)
} else {
// no binding - call this
SelectItem(index);
// no binding - call this
SelectItem(index)
}
}
}
</script>
<div class="root {className}">
{#if !hideNavBar}
{#if !hideNavBar}
<ul class="nav {navClasses}">
{#each items as navItem, index}
{#each items as navItem, index}
<li class="nav-item">
<button class="nav-link btn btn-link"
on:click={onSelectItemClicked(index)}
class:disabled={navItem.disabled}
class:active={selectedIndex === index}>
{navItem.title}
</button>
<button
class="nav-link btn btn-link"
on:click={onSelectItemClicked(index)}
class:disabled={navItem.disabled}
class:active={selectedIndex === index}>
{navItem.title}
</button>
</li>
{/each}
{/each}
</ul>
{/if}
{#each items as navItem, index}
<div bind:this={componentElement}>
</div>
{/each}
{/if}
{#each items as navItem, index}
<div bind:this={componentElement} />
{/each}
</div>
<style>
.root {
.root {
height: 100%;
width:100%;
}
width: 100%;
}
</style>

View File

@ -1,40 +1,34 @@
<script>
import createApp from "./createApp";
import { props } from "./props";
import createApp from "./createApp"
import { props } from "./props"
let _bb;
let _bb
const _appPromise = createApp();
_appPromise.then(a => _bb = a);
const _appPromise = createApp()
_appPromise.then(a => (_bb = a))
const testProps = props.hiddenNav;
const testProps = props.hiddenNav
let currentComponent;
let currentComponent
$: {
if(_bb && currentComponent) {
_bb.hydrateChildren(testProps, currentComponent);
$: {
if (_bb && currentComponent) {
_bb.hydrateChildren(testProps, currentComponent)
}
}
}
</script>
{#await _appPromise}
loading
loading
{:then _bb}
<div id="current_component" bind:this={currentComponent}>
</div>
<div id="current_component" bind:this={currentComponent} />
{/await}
<style>
#current_component {
#current_component {
height: 100%;
width: 100%;
}
}
</style>

View File

@ -1,46 +1,43 @@
import { writable } from "svelte/store";
import Login from "../Login.svelte";
import Grid from "../Grid.svelte";
import Form from "../Form.svelte";
import Textbox from "../Textbox.svelte";
import Text from "../Text.svelte";
import Nav from "../Nav.svelte";
import Panel from "../Panel.svelte";
import StackPanel from "../StackPanel.svelte";
import Table from "../Table.svelte";
import Button from "../Button.svelte";
import { createApp } from "@budibase/client/src/createApp";
import Login from "../Login.svelte"
import Grid from "../Grid.svelte"
import Form from "../Form.svelte"
import Textbox from "../Textbox.svelte"
import Text from "../Text.svelte"
import Nav from "../Nav.svelte"
import Panel from "../Panel.svelte"
import StackPanel from "../StackPanel.svelte"
import Table from "../Table.svelte"
import Button from "../Button.svelte"
import { createApp } from "@budibase/client/src/createApp"
export default async () => {
export default async () => {
const componentLibraries = {
components: {
login: Login,
grid: Grid,
form: Form,
textbox: Textbox,
text: Text,
nav: Nav,
panel: Panel,
table: Table,
stackpanel: StackPanel,
button: Button,
},
}
const componentLibraries = {
components : {
login : Login,
grid : Grid,
form : Form,
textbox : Textbox,
text: Text,
nav: Nav,
panel: Panel,
table: Table,
stackpanel: StackPanel,
button: Button
}
}
const appDef = { hierarchy: {}, actions: {} }
const user = { name: "yeo", permissions: [] }
const appDef = {hierarchy:{}, actions:{}};
const user = {name:"yeo", permissions:[]};
var app = createApp(componentLibraries, appDef, user);
app.store.update(s => {
s.people = [
{name:"bob", address: "123 Main Street", status: "Open"},
{name:"poppy", address: "456 Side Road", status: "Closed"},
{name:"Oscar", address: "678 Dodgy Alley", status: "Open"},
];
return s;
})
var app = createApp(componentLibraries, appDef, user)
app.store.update(s => {
s.people = [
{ name: "bob", address: "123 Main Street", status: "Open" },
{ name: "poppy", address: "456 Side Road", status: "Closed" },
{ name: "Oscar", address: "678 Dodgy Alley", status: "Open" },
]
return s
})
return app;
}
return app
}

View File

@ -1,253 +1,247 @@
export const props = {
login: { _component: "components/login" },
login: { _component:"components/login" },
form: {
_component: "components/form",
formControls: [
{
control: {
_component: "components/textbox"
},
label:"First Name"
},
{
control: {
_component: "components/textbox"
},
label:"Last Name"
}
]
},
nav: {
_component: "components/nav",
navBarBackground: "red",
navBarBorder: "1px solid maroon",
navBarColor: "black",
selectedItemBackground: "maroon",
selectedItemColor: "white",
selectedItemBorder: "green",
itemHoverBackground: "yellow",
itemHoverColor: "pink",
items: [
{
title: "People",
component: {
_component: "components/panel",
text:"People Panel",
padding: "40px",
border: "2px solid pink",
background: "mistyrose"
}
},
{
title: "Animals",
component: {
_component: "components/panel",
text:"Animals Panel",
padding: "40px",
border: "2px solid green",
background: "azure"
}
}
]
},
table: {
_component:"components/table",
columns: [
{
title: {
"##bbstate":"NameColumnName",
"##bbsource":"store",
"##bbstatefallback": "Name"
},
value: {
"##bbstate":"name",
"##bbsource":"context"
}
},
{
title: "Address",
value: {
"##bbstate":"address",
"##bbsource":"context"
}
},
{
title: "Status",
value: {
"##bbstate":"status",
"##bbsource":"context"
}
}
],
data: {
"##bbstate":"people"
form: {
_component: "components/form",
formControls: [
{
control: {
_component: "components/textbox",
},
onRowClick: [
{
"##eventHandlerType": "Set State",
parameters: {
path: "NameColumnName",
value: {
"##bbstate":"name",
"##bbsource":"context",
"##bbstatefallback": "balls to that"
}
}
}
],
tableClass: "table-default",
theadClass: "thead-default",
tbodyClass: "tbody-default",
trClass: "tr-default",
thClass: "th-default"
},
grid: {
_component: "components/grid",
gridTemplateColumns: "[left] auto [center] auto [right] auto",
gridTemplateRows: "[top] auto [middle] auto [bottom] auto",
children : [
{
control: {
_component: "components/text",
value: "1",
background: "blue",
textAlign:"center",
color: "white"
},
gridColumn: "left",
gridRow: "top"
},
{
control: {
_component: "components/text",
value: "2",
background: "red",
textAlign:"center",
color: "white",
padding: "10px"
},
gridColumn: "center",
gridRow: "middle"
},
{
control: {
_component: "components/text",
value: "3",
background: "yellow",
textAlign:"center",
color: "black"
},
gridColumn: "right",
gridRow: "bottom"
}
]
},
boundStackPanel: {
_component: "components/stackpanel",
direction: "horizontal",
children: [
{
control: {
_component: "components/text",
value: "STATIC"
}
}
],
data: {
"##bbstate":"people"
label: "First Name",
},
{
control: {
_component: "components/textbox",
},
dataItemComponent: {
_component: "components/panel",
text: {
"##bbstate":"name",
"##bbsource":"context",
"##bbstatefallback": "balls to that"
},
padding: "10px",
border: "5px solid black",
margin: "10px",
hoverColor: "white",
hoverBackground: "black",
height:"200px",
weight:"200px"
}
},
hiddenNav: {
_component: "components/stackpanel",
children: [
{
control:{
_component: "components/button",
contentText: "Peep",
onClick: [
{
"##eventHandlerType": "Set State",
parameters: {
path: "selected",
value: "People"
}
}
]
}
},
{
control:{
_component: "components/button",
contentText: "Ani",
onClick: [
{
"##eventHandlerType": "Set State",
parameters: {
path: "selected",
value: "Animals"
}
}
]
}
},
{
control: {
_component: "components/nav",
hideNavBar: true,
selectedItem: {
"##bbstate":"selected",
"##bbsource":"store",
"##bbstatefallback": "Animals"
},
items: [
{
title: "People",
component: {
_component: "components/panel",
text:"People Panel",
padding: "40px",
border: "2px solid pink",
background: "mistyrose"
}
},
{
title: "Animals",
component: {
_component: "components/panel",
text:"Animals Panel",
padding: "40px",
border: "2px solid green",
background: "azure"
}
}
]
}
}
]
}
label: "Last Name",
},
],
},
}
nav: {
_component: "components/nav",
navBarBackground: "red",
navBarBorder: "1px solid maroon",
navBarColor: "black",
selectedItemBackground: "maroon",
selectedItemColor: "white",
selectedItemBorder: "green",
itemHoverBackground: "yellow",
itemHoverColor: "pink",
items: [
{
title: "People",
component: {
_component: "components/panel",
text: "People Panel",
padding: "40px",
border: "2px solid pink",
background: "mistyrose",
},
},
{
title: "Animals",
component: {
_component: "components/panel",
text: "Animals Panel",
padding: "40px",
border: "2px solid green",
background: "azure",
},
},
],
},
table: {
_component: "components/table",
columns: [
{
title: {
"##bbstate": "NameColumnName",
"##bbsource": "store",
"##bbstatefallback": "Name",
},
value: {
"##bbstate": "name",
"##bbsource": "context",
},
},
{
title: "Address",
value: {
"##bbstate": "address",
"##bbsource": "context",
},
},
{
title: "Status",
value: {
"##bbstate": "status",
"##bbsource": "context",
},
},
],
data: {
"##bbstate": "people",
},
onRowClick: [
{
"##eventHandlerType": "Set State",
parameters: {
path: "NameColumnName",
value: {
"##bbstate": "name",
"##bbsource": "context",
"##bbstatefallback": "balls to that",
},
},
},
],
tableClass: "table-default",
theadClass: "thead-default",
tbodyClass: "tbody-default",
trClass: "tr-default",
thClass: "th-default",
},
grid: {
_component: "components/grid",
gridTemplateColumns: "[left] auto [center] auto [right] auto",
gridTemplateRows: "[top] auto [middle] auto [bottom] auto",
children: [
{
control: {
_component: "components/text",
value: "1",
background: "blue",
textAlign: "center",
color: "white",
},
gridColumn: "left",
gridRow: "top",
},
{
control: {
_component: "components/text",
value: "2",
background: "red",
textAlign: "center",
color: "white",
padding: "10px",
},
gridColumn: "center",
gridRow: "middle",
},
{
control: {
_component: "components/text",
value: "3",
background: "yellow",
textAlign: "center",
color: "black",
},
gridColumn: "right",
gridRow: "bottom",
},
],
},
boundStackPanel: {
_component: "components/stackpanel",
direction: "horizontal",
children: [
{
control: {
_component: "components/text",
value: "STATIC",
},
},
],
data: {
"##bbstate": "people",
},
dataItemComponent: {
_component: "components/panel",
text: {
"##bbstate": "name",
"##bbsource": "context",
"##bbstatefallback": "balls to that",
},
padding: "10px",
border: "5px solid black",
margin: "10px",
hoverColor: "white",
hoverBackground: "black",
height: "200px",
weight: "200px",
},
},
hiddenNav: {
_component: "components/stackpanel",
children: [
{
control: {
_component: "components/button",
contentText: "Peep",
onClick: [
{
"##eventHandlerType": "Set State",
parameters: {
path: "selected",
value: "People",
},
},
],
},
},
{
control: {
_component: "components/button",
contentText: "Ani",
onClick: [
{
"##eventHandlerType": "Set State",
parameters: {
path: "selected",
value: "Animals",
},
},
],
},
},
{
control: {
_component: "components/nav",
hideNavBar: true,
selectedItem: {
"##bbstate": "selected",
"##bbsource": "store",
"##bbstatefallback": "Animals",
},
items: [
{
title: "People",
component: {
_component: "components/panel",
text: "People Panel",
padding: "40px",
border: "2px solid pink",
background: "mistyrose",
},
},
{
title: "Animals",
component: {
_component: "components/panel",
text: "Animals Panel",
padding: "40px",
border: "2px solid green",
background: "azure",
},
},
],
},
},
],
},
}

View File

@ -1,7 +1,7 @@
import App from './TestApp.svelte';
import App from "./TestApp.svelte"
const app = new App({
target: document.body,
});
target: document.body,
})
export default app;
export default app

View File

@ -1,9 +1,9 @@
export const buildStyle = (styles) => {
let str = "";
for(let s in styles) {
if(styles[s]) {
str += `${s}: ${styles[s]}; `
}
export const buildStyle = styles => {
let str = ""
for (let s in styles) {
if (styles[s]) {
str += `${s}: ${styles[s]}; `
}
return str;
}
}
return str
}

View File

@ -1,21 +1,19 @@
// https://github.com/kaisermann/svelte-css-vars
export default (node, props) => {
Object.entries(props).forEach(([key, value]) => {
node.style.setProperty(`--${key}`, value);
});
return {
update(new_props) {
Object.entries(new_props).forEach(([key, value]) => {
node.style.setProperty(`--${key}`, value);
delete props[key];
});
Object.keys(props).forEach(name =>
node.style.removeProperty(`--${name}`),
);
props = new_props;
},
};
};
Object.entries(props).forEach(([key, value]) => {
node.style.setProperty(`--${key}`, value)
})
return {
update(new_props) {
Object.entries(new_props).forEach(([key, value]) => {
node.style.setProperty(`--${key}`, value)
delete props[key]
})
Object.keys(props).forEach(name => node.style.removeProperty(`--${name}`))
props = new_props
},
}
}

View File

@ -1 +1 @@
export const emptyProps = () => ({_component:""});
export const emptyProps = () => ({ _component: "" })

View File

@ -1,4 +1,4 @@
export { forms } from "./generators/formsGenerator";
export { indexTables } from "./generators/indexTablesGenerator";
export { app } from "./generators/appGenerator";
export { recordHomePageComponents as recordHomepages } from "./generators/recordHomePageGenerator";
export { forms } from "./generators/formsGenerator"
export { indexTables } from "./generators/indexTablesGenerator"
export { app } from "./generators/appGenerator"
export { recordHomePageComponents as recordHomepages } from "./generators/recordHomePageGenerator"

View File

@ -1,37 +1,37 @@
import { navContentComponentName, selectNavContent } from "./selectedNavContentGenerator";
import { recordHomepages } from "./recordHomePageGenerator";
export const app = ({records, indexes, helpers}) => [
{
name: "Application Root",
inherits: "@budibase/bootstrap-components/nav",
props: {
items: recordHomepages({indexes, records})
.map(navItem),
orientation: "horizontal",
alignment: "start",
fill: false,
pills: true,
selectedItem: {
"##bbstate":"selectedNav",
"##bbstatefallback":`${records[0].name}`,
"##bbsource": "store"
},
className: "p-3"
}
import {
navContentComponentName,
selectNavContent,
} from "./selectedNavContentGenerator"
import { recordHomepages } from "./recordHomePageGenerator"
export const app = ({ records, indexes, helpers }) => [
{
name: "Application Root",
inherits: "@budibase/bootstrap-components/nav",
props: {
items: recordHomepages({ indexes, records }).map(navItem),
orientation: "horizontal",
alignment: "start",
fill: false,
pills: true,
selectedItem: {
"##bbstate": "selectedNav",
"##bbstatefallback": `${records[0].name}`,
"##bbsource": "store",
},
className: "p-3",
},
{
name: "Login",
inherits: "@budibase/standard-components/login",
props: {}
},
...selectNavContent({records, indexes, helpers})
},
{
name: "Login",
inherits: "@budibase/standard-components/login",
props: {},
},
...selectNavContent({ records, indexes, helpers }),
]
export const navItem = ({record}) => ({
title: record.collectionName,
component : {
_component: navContentComponentName(record)
}
export const navItem = ({ record }) => ({
title: record.collectionName,
component: {
_component: navContentComponentName(record),
},
})

View File

@ -1,18 +1,18 @@
export const buttons = () => [
{
name: "common/Primary Button",
description: "Bootstrap primary button ",
inherits: "@budibase/standard-components/button",
props: {
className: "btn btn-primary"
}
{
name: "common/Primary Button",
description: "Bootstrap primary button ",
inherits: "@budibase/standard-components/button",
props: {
className: "btn btn-primary",
},
{
name: "common/Default Button",
description: "Bootstrap default button",
inherits: "@budibase/standard-components/button",
props: {
className: "btn btn-secondary"
}
}
]
},
{
name: "common/Default Button",
description: "Bootstrap default button",
inherits: "@budibase/standard-components/button",
props: {
className: "btn btn-secondary",
},
},
]

View File

@ -1,123 +1,128 @@
import {buttons} from "./buttonGenerators";
import { buttons } from "./buttonGenerators"
export const forms = ({records, indexes, helpers}) =>
[
...records.map(root),
...buttons({records, indexes, helpers})
];
export const forms = ({ records, indexes, helpers }) => [
...records.map(root),
...buttons({ records, indexes, helpers }),
]
export const formName = record => `${record.name}/${record.name} Form`;
export const formName = record => `${record.name}/${record.name} Form`
const root = record => ({
name: formName(record),
description: `Control for creating/updating '${record.nodeKey()}' `,
inherits: "@budibase/standard-components/div",
props: {
className:"p-1",
children: [
{
component: {
_component: "@budibase/standard-components/h3",
text: `Edit ${record.name}`,
}
},
form(record),
saveCancelButtons(record)
]
}
})
name: formName(record),
description: `Control for creating/updating '${record.nodeKey()}' `,
inherits: "@budibase/standard-components/div",
props: {
className: "p-1",
children: [
{
component: {
_component: "@budibase/standard-components/h3",
text: `Edit ${record.name}`,
},
},
form(record),
saveCancelButtons(record),
],
},
})
const form = record => ({
component: {
_component: "@budibase/standard-components/form",
formControls:
record.fields.map(f => formControl(record, f))
}
component: {
_component: "@budibase/standard-components/form",
formControls: record.fields.map(f => formControl(record, f)),
},
})
const formControl = (record, field) => {
if(field.type === "string" && field.typeOptions.values && field.typeOptions.values.length > 0) {
return ({
control: {
_component: "@budibase/standard-components/select",
options: field.typeOptions.values.map(v => ({id:v, value:v})),
value: {
"##bbstate":`${record.name}.${field.name}`,
"##bbsource":"store"
},
className: "form-control"
},
label: field.label
});
} else {
return ({
control: {
_component: "@budibase/standard-components/input",
value: {
"##bbstate":`${record.name}.${field.name}`,
"##bbsource":"store"
},
className: "form-control",
type: field.type === "string" ? "text"
: field.type === "datetime" ? "date"
: field.type === "number" ? "number"
: "text"
},
label: field.label
});
if (
field.type === "string" &&
field.typeOptions.values &&
field.typeOptions.values.length > 0
) {
return {
control: {
_component: "@budibase/standard-components/select",
options: field.typeOptions.values.map(v => ({ id: v, value: v })),
value: {
"##bbstate": `${record.name}.${field.name}`,
"##bbsource": "store",
},
className: "form-control",
},
label: field.label,
}
} else {
return {
control: {
_component: "@budibase/standard-components/input",
value: {
"##bbstate": `${record.name}.${field.name}`,
"##bbsource": "store",
},
className: "form-control",
type:
field.type === "string"
? "text"
: field.type === "datetime"
? "date"
: field.type === "number"
? "number"
: "text",
},
label: field.label,
}
}
}
const saveCancelButtons = (record) => ({
component: {
_component: "@budibase/standard-components/stackpanel",
direction: "horizontal",
children: [
paddedPanelForButton({
_component: "common/Primary Button",
contentText: `Save ${record.name}`,
onClick: [
{
"##eventHandlerType": "Save Record",
parameters: {
statePath: `${record.name}`,
}
},
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: ""
}
}
]
}),
paddedPanelForButton({
_component: "common/Default Button",
contentText: `Cancel`,
onClick: [
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: ""
}
}
]
})
]
}
const saveCancelButtons = record => ({
component: {
_component: "@budibase/standard-components/stackpanel",
direction: "horizontal",
children: [
paddedPanelForButton({
_component: "common/Primary Button",
contentText: `Save ${record.name}`,
onClick: [
{
"##eventHandlerType": "Save Record",
parameters: {
statePath: `${record.name}`,
},
},
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: "",
},
},
],
}),
paddedPanelForButton({
_component: "common/Default Button",
contentText: `Cancel`,
onClick: [
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: "",
},
},
],
}),
],
},
})
const paddedPanelForButton = (button) => ({
control: {
_component: "@budibase/standard-components/div",
className: "btn-group",
children: [
{
component: button
}
]
}
});
const paddedPanelForButton = button => ({
control: {
_component: "@budibase/standard-components/div",
className: "btn-group",
children: [
{
component: button,
},
],
},
})

View File

@ -1,15 +1,14 @@
export const getRecordPath = (record) => {
export const getRecordPath = () => {
const parts = []
const parts = [];
const add = (current) => {
parts.push(current.name);
if(current.parent().type === "root") {
return;
}
add(current.parent());
const add = current => {
parts.push(current.name)
if (current.parent().type === "root") {
return
}
return parts.reverse().join("/");
}
add(current.parent())
}
return parts.reverse().join("/")
}

View File

@ -1,54 +1,53 @@
import { getRecordPath } from "./getRecordPath";
import { getRecordPath } from "./getRecordPath"
export const indexTables = ({indexes, helpers}) =>
indexes.map(i => indexTable(i, helpers));
export const indexTables = ({ indexes, helpers }) =>
indexes.map(i => indexTable(i, helpers))
const excludedColumns = ["id", "isNew", "key", "type", "sortKey"];
const excludedColumns = ["id", "isNew", "key", "type", "sortKey"]
export const indexTableProps = (index, helpers) => ({
data: {
"##bbstate":index.nodeKey(),
"##bbsource":"store"
data: {
"##bbstate": index.nodeKey(),
"##bbsource": "store",
},
tableClass: "table table-hover",
theadClass: "thead-dark",
columns: helpers
.indexSchema(index)
.filter(c => !excludedColumns.includes(c.name))
.map(column),
onRowClick: [
{
"##eventHandlerType": "Set State",
parameters: {
path: `selectedrow_${index.name}`,
value: {
"##bbstate": "key",
"##bbsource": "event",
},
},
},
tableClass: "table table-hover",
theadClass: "thead-dark",
columns: helpers
.indexSchema(index)
.filter(c => !excludedColumns.includes(c.name))
.map(column),
onRowClick: [
{
"##eventHandlerType": "Set State",
parameters: {
path: `selectedrow_${index.name}`,
value: {
"##bbstate": "key",
"##bbsource": "event"
}
},
}
]
});
],
})
export const getIndexTableName = (index, record) => {
record = record
|| index.parent().type === "record" ? index.parent() : null;
return (record
? `${getRecordPath(record)}/${index.name} Table`
: `${index.name} Table`);
record = record || index.parent().type === "record" ? index.parent() : null
return record
? `${getRecordPath(record)}/${index.name} Table`
: `${index.name} Table`
}
const indexTable = (index, helpers) => ({
name: getIndexTableName(index),
inherits: "@budibase/standard-components/table",
props: indexTableProps(index, helpers)
});
name: getIndexTableName(index),
inherits: "@budibase/standard-components/table",
props: indexTableProps(index, helpers),
})
const column = (col) => ({
title: col.name,
value: {
"##bbstate": col.name,
"##bbsource":"context"
}
})
const column = col => ({
title: col.name,
value: {
"##bbstate": col.name,
"##bbsource": "context",
},
})

View File

@ -1,190 +1,183 @@
import {
getIndexTableName, indexTables
} from "./indexTablesGenerator";
import { getIndexTableName, indexTables } from "./indexTablesGenerator"
import {
buttons
} from "./buttonGenerators";
import { buttons } from "./buttonGenerators"
export const recordHomePageComponents = ({indexes, records, helpers}) =>
[
...recordHomepages({indexes, records})
.map(component),
export const recordHomePageComponents = ({ indexes, records, helpers }) => [
...recordHomepages({ indexes, records }).map(component),
...recordHomepages({indexes, records})
.map(homePageButtons),
...indexTables({indexes, records, helpers}),
...recordHomepages({ indexes, records }).map(homePageButtons),
...buttons({indexes, buttons, helpers})
]
...indexTables({ indexes, records, helpers }),
...buttons({ indexes, buttons, helpers }),
]
const findIndexForRecord = (indexes, record) => {
const forRecord = indexes.filter(i => i.allowedRecordNodeIds.includes(record.nodeId));
if(forRecord.length === 0) return;
if(forRecord.length === 1) return forRecord[0];
const noMap = forRecord.filter(i => !i.filter || !i.filter.trim());
if(noMap.length === 0) forRecord[0];
return noMap[0];
const forRecord = indexes.filter(i =>
i.allowedRecordNodeIds.includes(record.nodeId)
)
if (forRecord.length === 0) return
if (forRecord.length === 1) return forRecord[0]
const noMap = forRecord.filter(i => !i.filter || !i.filter.trim())
if (noMap.length === 0) forRecord[0]
return noMap[0]
}
export const recordHomepages = ({indexes, records}) =>
records.filter(r => r.parent().type === "root")
.map(r =>({
record:r,
index:findIndexForRecord(indexes, r)
}))
.filter(r => r.index);
export const recordHomepages = ({ indexes, records }) =>
records
.filter(r => r.parent().type === "root")
.map(r => ({
record: r,
index: findIndexForRecord(indexes, r),
}))
.filter(r => r.index)
export const homepageComponentName = record =>
`${record.name}/${record.name} homepage`
export const homepageComponentName = (record) =>
`${record.name}/${record.name} homepage`;
const component = ({ record, index }) => ({
inherits: "@budibase/standard-components/div",
name: homepageComponentName(record),
props: {
className: "d-flex flex-column h-100",
children: [
{
component: {
_component: `${record.name}/homepage buttons`,
},
},
{
component: {
_component: getIndexTableName(index),
},
className: "flex-gow-1 overflow-auto",
},
],
onLoad: [
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: "",
},
},
{
"##eventHandlerType": "List Records",
parameters: {
statePath: index.nodeKey(),
indexKey: index.nodeKey(),
},
},
],
},
})
const component = ({record, index}) => ({
inherits: "@budibase/standard-components/div",
name: homepageComponentName(record),
props: {
className: "d-flex flex-column h-100",
children: [
const homePageButtons = ({ index, record }) => ({
inherits: "@budibase/standard-components/div",
name: `${record.name}/homepage buttons`,
props: {
className: "btn-toolbar mt-4 mb-2",
children: [
{
component: {
_component: "@budibase/standard-components/div",
className: "btn-group mr-3",
children: [
{
component: {
_component: `${record.name}/homepage buttons`,
}
component: {
_component: "common/Default Button",
contentText: `Create ${record.name}`,
onClick: [
{
"##eventHandlerType": "Get New Record",
parameters: {
statePath: record.name,
collectionKey: `/${record.collectionName}`,
childRecordType: record.name,
},
},
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: "true",
},
},
],
},
},
{
component: {
_component: getIndexTableName(index)
},
className: "flex-gow-1 overflow-auto"
}
],
onLoad: [
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: ""
}
component: {
_component: "common/Default Button",
contentText: `Refresh`,
onClick: [
{
"##eventHandlerType": "List Records",
parameters: {
statePath: index.nodeKey(),
indexKey: index.nodeKey(),
},
},
],
},
},
{
"##eventHandlerType": "List Records",
parameters: {
statePath: index.nodeKey(),
indexKey: index.nodeKey()
}
}
]
}
});
const homePageButtons = ({index, record}) => ({
inherits: "@budibase/standard-components/div",
name: `${record.name}/homepage buttons`,
props: {
className: "btn-toolbar mt-4 mb-2",
children: [
{
],
},
},
{
component: {
_component: "@budibase/standard-components/if",
condition: `$store.selectedrow_${index.name} && $store.selectedrow_${index.name}.length > 0`,
thenComponent: {
_component: "@budibase/standard-components/div",
className: "btn-group",
children: [
{
component: {
_component: "@budibase/standard-components/div",
className: "btn-group mr-3",
children: [
{
component: {
_component: "common/Default Button",
contentText: `Create ${record.name}`,
onClick: [
{
"##eventHandlerType": "Get New Record",
parameters: {
statePath: record.name,
collectionKey: `/${record.collectionName}`,
childRecordType: record.name
}
},
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: "true"
}
}
]
}
_component: "common/Default Button",
contentText: `Edit ${record.name}`,
onClick: [
{
"##eventHandlerType": "Load Record",
parameters: {
statePath: record.name,
recordKey: {
"##bbstate": `selectedrow_${index.name}`,
"##source": "store",
},
{
component: {
_component: "common/Default Button",
contentText: `Refresh`,
onClick: [
{
"##eventHandlerType": "List Records",
parameters: {
statePath: index.nodeKey(),
indexKey: index.nodeKey()
}
}
]
}
}
]
}
},
{
},
},
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: "true",
},
},
],
},
},
{
component: {
_component: "@budibase/standard-components/if",
condition: `$store.selectedrow_${index.name} && $store.selectedrow_${index.name}.length > 0`,
thenComponent: {
_component: "@budibase/standard-components/div",
className: "btn-group",
children: [
{
component: {
_component: "common/Default Button",
contentText: `Edit ${record.name}`,
onClick: [
{
"##eventHandlerType": "Load Record",
parameters: {
statePath: record.name,
recordKey: {
"##bbstate" : `selectedrow_${index.name}`,
"##source": "store"
}
}
},
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: "true"
}
}
]
}
},
{
component: {
_component: "common/Default Button",
contentText: `Delete ${record.name}`,
onClick: [
{
"##eventHandlerType": "Delete Record",
parameters: {
recordKey: {
"##bbstate" : `selectedrow_${index.name}`,
"##source": "store"
}
}
}
]
}
}
]
}
}
}
]
}
})
_component: "common/Default Button",
contentText: `Delete ${record.name}`,
onClick: [
{
"##eventHandlerType": "Delete Record",
parameters: {
recordKey: {
"##bbstate": `selectedrow_${index.name}`,
"##source": "store",
},
},
},
],
},
},
],
},
},
},
],
},
})

View File

@ -1,36 +1,32 @@
import {
recordHomepages,
homepageComponentName,
recordHomePageComponents
} from "./recordHomePageGenerator";
import { formName, forms } from "./formsGenerator";
import {
recordHomepages,
homepageComponentName,
recordHomePageComponents,
} from "./recordHomePageGenerator"
import { formName, forms } from "./formsGenerator"
export const selectNavContent = ({indexes, records, helpers}) =>
[
...recordHomepages({indexes, records})
.map(component),
export const selectNavContent = ({ indexes, records, helpers }) => [
...recordHomepages({ indexes, records }).map(component),
...recordHomePageComponents({indexes, records, helpers}),
...forms({indexes, records, helpers})
]
...recordHomePageComponents({ indexes, records, helpers }),
...forms({ indexes, records, helpers }),
]
export const navContentComponentName = record =>
`${record.name}/${record.name} Nav Content`;
`${record.name}/${record.name} Nav Content`
const component = ({record, index}) => ({
inherits: "@budibase/standard-components/if",
description: `the component that gets displayed when the ${record.collectionName} nav is selected`,
name: navContentComponentName(record),
props: {
condition: `$store.isEditing${record.name}`,
thenComponent: {
_component: formName(record)
},
elseComponent: {
_component: homepageComponentName(record)
}
}
});
const component = ({ record }) => ({
inherits: "@budibase/standard-components/if",
description: `the component that gets displayed when the ${record.collectionName} nav is selected`,
name: navContentComponentName(record),
props: {
condition: `$store.isEditing${record.name}`,
thenComponent: {
_component: formName(record),
},
elseComponent: {
_component: homepageComponentName(record),
},
},
})

View File

@ -1,3 +1,2 @@
export {default as form} from "./Form.svelte";
export {default as nav} from "./Nav.svelte";
export { default as form } from "./Form.svelte"
export { default as nav } from "./Nav.svelte"

View File

@ -1,12 +1,13 @@
module.exports = ({
"presets": ["@babel/preset-env"],
"sourceMaps": "inline",
"retainLines": true,
"plugins": [
["@babel/plugin-transform-runtime",
{
"regenerator": true
}
]
]
});
module.exports = {
presets: ["@babel/preset-env"],
sourceMaps: "inline",
retainLines: true,
plugins: [
[
"@babel/plugin-transform-runtime",
{
regenerator: true,
},
],
],
}

View File

@ -1,8 +1,8 @@
const ncp = require('ncp').ncp;
ncp("./dist", "../server/builder", function (err) {
if (err) {
return console.error(err);
}
console.log('Copied dist folder to ../server/builder');
})
const ncp = require("ncp").ncp
ncp("./dist", "../server/builder", function(err) {
if (err) {
return console.error(err)
}
console.log("Copied dist folder to ../server/builder")
})

View File

@ -1,126 +1,218 @@
import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import url from 'rollup-plugin-url';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import builtins from 'rollup-plugin-node-builtins';
import nodeglobals from 'rollup-plugin-node-globals';
import copy from 'rollup-plugin-copy';
import browsersync from "rollup-plugin-browsersync";
import proxy from "http-proxy-middleware";
import svelte from "rollup-plugin-svelte"
import resolve from "rollup-plugin-node-resolve"
import commonjs from "rollup-plugin-commonjs"
import url from "rollup-plugin-url"
import livereload from "rollup-plugin-livereload"
import { terser } from "rollup-plugin-terser"
import builtins from "rollup-plugin-node-builtins"
import nodeglobals from "rollup-plugin-node-globals"
import copy from "rollup-plugin-copy"
import browsersync from "rollup-plugin-browsersync"
import proxy from "http-proxy-middleware"
const target = 'http://localhost:4001';
const _builderProxy = proxy('/_builder', {
target: "http://localhost:3000",
pathRewrite: { '^/_builder': '' }
});
const target = "http://localhost:4001"
const _builderProxy = proxy("/_builder", {
target: "http://localhost:3000",
pathRewrite: { "^/_builder": "" },
})
const apiProxy = proxy(['/_builder/api/**', '/_builder/**/componentlibrary', '/_builder/**/componentlibraryGenerators'], {
target,
logLevel: "debug",
changeOrigin: true,
cookieDomainRewrite: true,
onProxyReq(proxyReq) {
if (proxyReq.getHeader("origin")) {
proxyReq.setHeader("origin", target)
}
}
});
const apiProxy = proxy(
[
"/_builder/api/**",
"/_builder/**/componentlibrary",
"/_builder/**/componentlibraryGenerators",
],
{
target,
logLevel: "debug",
changeOrigin: true,
cookieDomainRewrite: true,
onProxyReq(proxyReq) {
if (proxyReq.getHeader("origin")) {
proxyReq.setHeader("origin", target)
}
},
}
)
const production = !process.env.ROLLUP_WATCH;
const production = !process.env.ROLLUP_WATCH
const lodash_fp_exports = ["union", "reduce", "isUndefined", "cloneDeep", "split", "some", "map", "filter", "isEmpty", "countBy", "includes", "last", "find", "constant",
"take", "first", "intersection", "mapValues", "isNull", "has", "isInteger", "isNumber", "isString", "isBoolean", "isDate", "isArray", "isObject", "clone", "values", "keyBy", "isNaN",
"keys", "orderBy", "concat", "reverse", "difference", "merge", "flatten", "each", "pull", "join", "defaultCase", "uniqBy", "every", "uniqWith", "isFunction", "groupBy",
"differenceBy", "intersectionBy", "isEqual", "max", "sortBy", "assign", "uniq", "trimChars", "trimCharsStart", "isObjectLike", "flattenDeep", "indexOf", "isPlainObject",
"toNumber", "takeRight", "toPairs"];
const lodash_fp_exports = [
"union",
"reduce",
"isUndefined",
"cloneDeep",
"split",
"some",
"map",
"filter",
"isEmpty",
"countBy",
"includes",
"last",
"find",
"constant",
"take",
"first",
"intersection",
"mapValues",
"isNull",
"has",
"isInteger",
"isNumber",
"isString",
"isBoolean",
"isDate",
"isArray",
"isObject",
"clone",
"values",
"keyBy",
"isNaN",
"keys",
"orderBy",
"concat",
"reverse",
"difference",
"merge",
"flatten",
"each",
"pull",
"join",
"defaultCase",
"uniqBy",
"every",
"uniqWith",
"isFunction",
"groupBy",
"differenceBy",
"intersectionBy",
"isEqual",
"max",
"sortBy",
"assign",
"uniq",
"trimChars",
"trimCharsStart",
"isObjectLike",
"flattenDeep",
"indexOf",
"isPlainObject",
"toNumber",
"takeRight",
"toPairs",
]
const lodash_exports = ["flow", "join", "replace", "trim", "dropRight", "takeRight", "head", "reduce",
"tail", "startsWith", "findIndex", "merge",
"assign", "each", "find", "orderBy", "union"];
const lodash_exports = [
"flow",
"join",
"replace",
"trim",
"dropRight",
"takeRight",
"head",
"reduce",
"tail",
"startsWith",
"findIndex",
"merge",
"assign",
"each",
"find",
"orderBy",
"union",
]
const outputpath = "../server/builder";
const outputpath = "../server/builder"
const coreExternal = [
"lodash", "lodash/fp", "date-fns",
"lunr", "safe-buffer", "shortid",
"@nx-js/compiler-util"
];
"lodash",
"lodash/fp",
"date-fns",
"lunr",
"safe-buffer",
"shortid",
"@nx-js/compiler-util",
]
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: `${outputpath}/bundle.js`
},
plugins: [
copy({
targets: [
{ src: 'src/index.html', dest: outputpath },
{ src: 'src/favicon.png', dest: outputpath },
{ src: 'src/assets', dest: outputpath },
{ src: 'node_modules/@budibase/client/dist/budibase-client.esm.mjs', dest: outputpath },
]
}),
input: "src/main.js",
output: {
sourcemap: true,
format: "iife",
name: "app",
file: `${outputpath}/bundle.js`,
},
plugins: [
copy({
targets: [
{ src: "src/index.html", dest: outputpath },
{ src: "src/favicon.png", dest: outputpath },
{ src: "src/assets", dest: outputpath },
{
src: "node_modules/@budibase/client/dist/budibase-client.esm.mjs",
dest: outputpath,
},
],
}),
svelte({
// enable run-time checks when not in production
dev: !production,
include: 'src/**/*.svelte',
// we'll extract any component CSS out into
// a separate file — better for performance
css: css => {
css.write(`${outputpath}/bundle.css`);
}
}),
svelte({
// enable run-time checks when not in production
dev: !production,
include: "src/**/*.svelte",
// we'll extract any component CSS out into
// a separate file — better for performance
css: css => {
css.write(`${outputpath}/bundle.css`)
},
}),
resolve({
browser: true,
dedupe: importee => {
return importee === 'svelte'
|| importee.startsWith('svelte/')
|| coreExternal.includes(importee);
}
resolve({
browser: true,
dedupe: importee => {
return (
importee === "svelte" ||
importee.startsWith("svelte/") ||
coreExternal.includes(importee)
)
},
}),
commonjs({
namedExports: {
"lodash/fp": lodash_fp_exports,
lodash: lodash_exports,
shortid: ["generate"],
},
}),
url({
limit: 0,
include: ["**/*.woff2", "**/*.png"],
fileName: "[dirname][name][extname]",
emitFiles: true,
}),
url({
limit: 0,
include: ["**/*.css"],
fileName: "[name][extname]",
emitFiles: true,
}),
builtins(),
nodeglobals(),
}),
commonjs({
namedExports: {
"lodash/fp": lodash_fp_exports,
"lodash": lodash_exports,
"shortid": ["generate"]
}
}),
url({
limit: 0,
include: ["**/*.woff2", "**/*.png"],
fileName: "[dirname][name][extname]",
emitFiles: true
}),
url({
limit: 0,
include: ["**/*.css"],
fileName: "[name][extname]",
emitFiles: true
}),
builtins(),
nodeglobals(),
// Watch the `dist` directory and refresh the
// browser on changes when not in production
!production && livereload(outputpath),
!production &&
browsersync({
server: outputpath,
middleware: [apiProxy, _builderProxy],
}),
// Watch the `dist` directory and refresh the
// browser on changes when not in production
!production && livereload(outputpath),
!production && browsersync({
server: outputpath,
middleware: [apiProxy, _builderProxy]
}),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser(),
],
watch: {
clearScreen: false,
},
}

View File

@ -1,38 +1,33 @@
<script>
import NoPackage from "./NoPackage.svelte";
import PackageRoot from "./PackageRoot.svelte";
import Settings from "./Settings.svelte";
import {store, initialise} from "./builderStore";
import { onMount } from 'svelte';
import IconButton from "./common/IconButton.svelte";
let init = initialise();
import NoPackage from "./NoPackage.svelte"
import PackageRoot from "./PackageRoot.svelte"
import Settings from "./Settings.svelte"
import { store, initialise } from "./builderStore"
import { onMount } from "svelte"
import IconButton from "./common/IconButton.svelte"
let init = initialise()
</script>
<main>
{#await init}
<h1>loading</h1>
{#await init}
{:then result}
<h1>loading</h1>
{#if $store.hasAppPackage}
<PackageRoot />
{:then result}
{:else}
{#if $store.hasAppPackage}
<PackageRoot />
{:else}
<NoPackage />
{/if}
<NoPackage />
{/if}
{:catch err}
<h1 style="color:red">{err}</h1>
{/await}
{:catch err}
<h1 style="color:red">{err}</h1>
{/await}
<!--
<!--
<div class="settings">
<IconButton icon="settings"
on:click={store.showSettings}/>
@ -46,15 +41,15 @@
</main>
<style>
main {
height: 100%;
width: 100%;
font-family: "Roboto", Helvetica, Arial, sans-serif;
}
main {
height: 100%;
width: 100%;
font-family: "Roboto", Helvetica, Arial, sans-serif;
}
.settings {
position: absolute;
bottom: 25px;
right: 25px;
}
</style>
.settings {
position: absolute;
bottom: 25px;
right: 25px;
}
</style>

View File

@ -1,56 +1,47 @@
<script>
import BackendNav from "./nav/BackendNav.svelte"
import Database from "./database/DatabaseRoot.svelte"
import UserInterface from "./userInterface/UserInterfaceRoot.svelte"
import ActionsAndTriggers from "./actionsAndTriggers/ActionsAndTriggersRoot.svelte"
import AccessLevels from "./accessLevels/AccessLevelsRoot.svelte"
import ComingSoon from "./common/ComingSoon.svelte"
import BackendNav from "./nav/BackendNav.svelte";
import Database from "./database/DatabaseRoot.svelte" ;
import UserInterface from "./userInterface/UserInterfaceRoot.svelte" ;
import ActionsAndTriggers from "./actionsAndTriggers/ActionsAndTriggersRoot.svelte" ;
import AccessLevels from "./accessLevels/AccessLevelsRoot.svelte" ;
import ComingSoon from "./common/ComingSoon.svelte";
import {store} from "./builderStore";
export let navWidth = "50px";
import { store } from "./builderStore"
export let navWidth = "50px"
</script>
<div class="root">
<div class="nav">
<BackendNav />
</div>
<div class="content"
style="width: calc(100% - {navWidth}); left: {navWidth}">
{#if $store.activeNav === "database"}
<Database />
{:else if $store.activeNav === "actions"}
<ActionsAndTriggers />
{:else if $store.activeNav === "access levels"}
<AccessLevels />
<div class="content" style="width: calc(100% - {navWidth}); left: {navWidth}">
{#if $store.activeNav === 'database'}
<Database />
{:else if $store.activeNav === 'actions'}
<ActionsAndTriggers />
{:else if $store.activeNav === 'access levels'}
<AccessLevels />
{/if}
</div>
</div>
<style>
.root {
height: 100%;
display: flex;
}
.root {
height: 100%;
display: flex;
}
.content {
flex: 1 1 auto;
height: 100%;
background-color: var(--white);
margin: 0;
}
.content {
flex: 1 1 auto;
height: 100%;
background-color: var(--white);
margin:0;
}
.nav {
flex: 0 1 auto;
width: 300px;
height: 100%;
}
</style>
.nav {
flex: 0 1 auto;
width: 300px;
height: 100%;
}
</style>

View File

@ -1,56 +1,55 @@
<script>
import Button from "./common/Button.svelte"
import { store } from "./builderStore"
import Button from "./common/Button.svelte"
import { store } from "./builderStore";
let errors = [];
let errors = []
</script>
<div class="root">
<div class="inner">
<img src="/_builder/assets/budibase-logo.png" class="logo" alt="budibase logo"/>
<div>
<div>
<h4 style="margin-bottom: 20px">Choose an Application</h4>
{#each $store.apps as app}
<a href={`#/${app}`} class="app-link">{app}</a>
{/each}
</div>
</div>
<div class="inner">
<img
src="/_builder/assets/budibase-logo.png"
class="logo"
alt="budibase logo" />
<div>
<div>
<h4 style="margin-bottom: 20px">Choose an Application</h4>
{#each $store.apps as app}
<a href={`#/${app}`} class="app-link">{app}</a>
{/each}
</div>
</div>
</div>
</div>
<style>
.root {
.root {
position: fixed;
margin: 0 auto;
text-align: center;
top: 20%;
/*color: #333333;
background-color: #fdfdfd;*/
width:100%;
}
width: 100%;
}
.inner {
display:inline-block;
.inner {
display: inline-block;
margin: auto;
}
}
.logo {
.logo {
width: 300px;
margin-bottom: 40px;
}
}
.root :global(.option) {
width:250px;
}
.root :global(.option) {
width: 250px;
}
.app-link {
.app-link {
margin-top: 10px;
display: block;
}
</style>
}
</style>

View File

@ -1,57 +1,57 @@
<script>
import IconButton from "./common/IconButton.svelte";
import { store } from "./builderStore";
import UserInterfaceRoot from "./userInterface/UserInterfaceRoot.svelte";
import BackendRoot from "./BackendRoot.svelte";
import { fade } from "svelte/transition";
import IconButton from "./common/IconButton.svelte"
import { store } from "./builderStore"
import UserInterfaceRoot from "./userInterface/UserInterfaceRoot.svelte"
import BackendRoot from "./BackendRoot.svelte"
import { fade } from "svelte/transition"
</script>
<div class="root">
<div class="top-nav">
<button class="home-logo"><img src="/assets/budibase-logo-only.png"/></button>
<!-- <IconButton icon="home"
<div class="top-nav">
<button class="home-logo">
<img src="/assets/budibase-logo-only.png" />
</button>
<!-- <IconButton icon="home"
color="var(--slate)"
hoverColor="var(--secondary75)"/> -->
<span class:active={$store.isBackend}
class="topnavitem"
on:click={store.showBackend}>
Backend
</span>
<span class:active={!$store.isBackend}
class="topnavitem"
on:click={store.showFrontend}>
Frontend
</span>
</div>
<span
class:active={$store.isBackend}
class="topnavitem"
on:click={store.showBackend}>
Backend
</span>
<span
class:active={!$store.isBackend}
class="topnavitem"
on:click={store.showFrontend}>
Frontend
</span>
</div>
<div class="content">
{#if $store.isBackend}
<div in:fade out:fade>
<BackendRoot />
</div>
{:else}
<div in:fade out:fade>
<UserInterfaceRoot />
</div>
{/if}
</div>
<div class="content">
{#if $store.isBackend}
<div in:fade out:fade>
<BackendRoot />
</div>
{:else}
<div in:fade out:fade>
<UserInterfaceRoot />
</div>
{/if}
</div>
</div>
<style>
.root {
height:100%;
width:100%;
.root {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
}
.top-nav {
.top-nav {
flex: 0 0 auto;
height: 48px;
background: white;
@ -60,21 +60,20 @@ import { fade } from "svelte/transition";
display: flex;
align-items: center;
border-bottom: 1px solid #ddd;
}
}
.content {
.content {
flex: 1 1 auto;
width: 100%;
height: 100px;
}
}
.content > div {
height:100%;
width:100%;
.content > div {
height: 100%;
width: 100%;
}
}
.topnavitem {
.topnavitem {
cursor: pointer;
color: var(--secondary50);
margin: 0px 15px;
@ -85,41 +84,38 @@ import { fade } from "svelte/transition";
display: flex;
align-items: center;
box-sizing: border-box;
}
}
.topnavitem:hover {
.topnavitem:hover {
color: var(--secondary75);
font-weight: 600;
}
}
.active {
.active {
color: var(--primary100);
font-weight: 600;
border-bottom: 2px solid var(--primary100);
border-top: 2px solid transparent;
}
}
.home-logo {
.home-logo {
border-style: none;
background-color: rgba(0,0,0,0);
background-color: rgba(0, 0, 0, 0);
cursor: pointer;
outline: none;
height: 40px;
padding: 8px 10px;
}
}
.home-logo:hover {
.home-logo:hover {
color: var(--hovercolor);
}
}
.home-logo:active {
outline:none;
}
.home-logo:active {
outline: none;
}
.home-logo img {
.home-logo img {
height: 100%;
}
}
</style>

View File

@ -1,27 +1,26 @@
<script>
import IconButton from "./common/IconButton.svelte";
import { store } from "./builderStore";
import UserInterfaceRoot from "./userInterface/UserInterfaceRoot.svelte";
import { fade } from "svelte/transition";
import IconButton from "./common/IconButton.svelte"
import { store } from "./builderStore"
import UserInterfaceRoot from "./userInterface/UserInterfaceRoot.svelte"
import { fade } from "svelte/transition"
</script>
<div class="root">
<div class="content uk-container">
<div class="content uk-container">
<h1>Settings</h1>
<h1>Settings</h1>
<label>
<input type="checkbox"
class="uk-checkbox"
bind:checked={$store.useAnalytics}>
Send analytics
</label>
<label>
<input
type="checkbox"
class="uk-checkbox"
bind:checked={$store.useAnalytics} />
Send analytics
</label>
</div>
</div>
</div>
<style>
</style>
</style>

View File

@ -1,99 +1,91 @@
<script>
import { cloneDeep, map, some, filter } from "lodash/fp"
import Textbox from "../common/Textbox.svelte"
import Checkbox from "../common/Checkbox.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import Button from "../common/Button.svelte"
import { validateAccessLevels } from "../common/core"
import ErrorsBox from "../common/ErrorsBox.svelte"
import {cloneDeep, map, some, filter} from "lodash/fp";
import Textbox from "../common/Textbox.svelte";
import Checkbox from "../common/Checkbox.svelte";
import ButtonGroup from "../common/ButtonGroup.svelte";
import Button from "../common/Button.svelte";
import {validateAccessLevels} from "../common/core";
import ErrorsBox from "../common/ErrorsBox.svelte";
export let level
export let allPermissions
export let onFinished
export let isNew
export let allLevels
export let hierarchy
export let actions
export let level;
export let allPermissions;
export let onFinished;
export let isNew;
export let allLevels;
export let hierarchy;
export let actions;
let errors = []
let clonedLevel = cloneDeep(level)
let errors = [];
let clonedLevel = cloneDeep(level);
const matchPermissions = (p1, p2) =>
p1.type === p2.type &&
((!p2.nodeKey && !p1.nodeKey) || p2.nodeKey === p1.nodeKey)
const matchPermissions = (p1, p2) =>
p1.type === p2.type
&&
((!p2.nodeKey && !p1.nodeKey)
|| p2.nodeKey === p1.nodeKey);
const hasPermission = hasPerm =>
some(p => matchPermissions(p, hasPerm))(clonedLevel.permissions)
const hasPermission = hasPerm =>
some(p => matchPermissions(p, hasPerm))
(clonedLevel.permissions);
$: permissionMatrix = map(p => ({
permission: p,
hasPermission: hasPermission(p),
}))(allPermissions)
$: permissionMatrix =
map(p => ({permission:p, hasPermission: hasPermission(p)}))
(allPermissions)
const getPermissionName = perm =>
perm.nodeKey ? `${perm.type} - ${perm.nodeKey}` : perm.type
const getPermissionName = perm =>
perm.nodeKey
? `${perm.type} - ${perm.nodeKey}`
: perm.type;
const save = () => {
const newLevels = isNew
? [...allLevels, clonedLevel]
: [...filter(l => l.name !== level.name)(allLevels), clonedLevel]
const save = () => {
errors = validateAccessLevels(hierarchy, actions, newLevels)
const newLevels =
isNew
? [...allLevels, clonedLevel]
: [...filter(l => l.name !== level.name)(allLevels), clonedLevel];
if (errors.length > 0) return
errors = validateAccessLevels(
hierarchy,
actions,
newLevels
);
onFinished(clonedLevel)
}
if(errors.length > 0) return;
const permissionChanged = perm => ev => {
const hasPermission = ev.target.checked
onFinished(clonedLevel);
}
const permissionChanged = perm => ev => {
const hasPermission = ev.target.checked;
if(hasPermission) {
clonedLevel.permissions.push(perm);
if (hasPermission) {
clonedLevel.permissions.push(perm)
} else {
clonedLevel.permissions = filter(p => !matchPermissions(p, perm))(clonedLevel.permissions);
clonedLevel.permissions = filter(p => !matchPermissions(p, perm))(
clonedLevel.permissions
)
}
}
}
</script>
<div>
<ErrorsBox {errors} />
<ErrorsBox {errors} />
<form class="uk-form-horizontal">
<form class="uk-form-horizontal">
<Textbox label="Name" bind:text={clonedLevel.name} />
<Textbox label="Name" bind:text={clonedLevel.name} />
{#each permissionMatrix as permission}
<div>
<Checkbox label={getPermissionName(permission.permission)}
checked={permission.hasPermission}
on:change={permissionChanged(permission.permission)} />
</div>
{/each}
{#each permissionMatrix as permission}
<div>
<Checkbox
label={getPermissionName(permission.permission)}
checked={permission.hasPermission}
on:change={permissionChanged(permission.permission)} />
</div>
{/each}
</form>
<ButtonGroup style="margin-top: 10px">
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="secondary" grouped on:click={() => onFinished()}>Cancel</Button>
</ButtonGroup>
</form>
<ButtonGroup style="margin-top: 10px">
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="secondary" grouped on:click={() => onFinished()}>
Cancel
</Button>
</ButtonGroup>
</div>
<style>
</style>
</style>

View File

@ -1,119 +1,115 @@
<script>
import ButtonGroup from "../common/ButtonGroup.svelte"
import Button from "../common/Button.svelte"
import { store } from "../builderStore"
import { generateFullPermissions, getNewAccessLevel } from "../common/core"
import getIcon from "../common/icon"
import AccessLevelView from "./AccessLevelView.svelte"
import Modal from "../common/Modal.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte";
import Button from "../common/Button.svelte";
import {store} from "../builderStore";
import {generateFullPermissions, getNewAccessLevel} from "../common/core";
import getIcon from "../common/icon";
import AccessLevelView from "./AccessLevelView.svelte";
import Modal from "../common/Modal.svelte";
let editingLevel = null
let editingLevelIsNew = false
$: isEditing = editingLevel !== null
let editingLevel = null;
let editingLevelIsNew = false;
$: isEditing = (editingLevel !== null);
let allPermissions = []
store.subscribe(db => {
allPermissions = generateFullPermissions(db.hierarchy, db.actions)
})
let allPermissions = [];
store.subscribe(db => {
allPermissions = generateFullPermissions(db.hierarchy, db.actions);
})
let onLevelEdit = level => {
editingLevel = level
editingLevelIsNew = false
}
let onLevelEdit = (level) => {
editingLevel = level;
editingLevelIsNew = false;
};
let onLevelCancel = () => {
editingAction = null
}
let onLevelCancel = () => {
editingAction = null;
};
let onLevelDelete = level => {
store.deleteLevel(level)
}
let onLevelDelete = (level) => {
store.deleteLevel(level);
};
let createNewLevel = () => {
editingLevelIsNew = true
editingLevel = getNewAccessLevel()
}
let createNewLevel = () => {
editingLevelIsNew = true;
editingLevel = getNewAccessLevel();
}
let onEditingFinished = (level) => {
if(level) {
store.saveLevel(level, editingLevelIsNew, editingLevel);
let onEditingFinished = level => {
if (level) {
store.saveLevel(level, editingLevelIsNew, editingLevel)
}
editingLevel = null;
}
const getPermissionsString = perms => {
return `${perms.length} / ${allPermissions.length}`;
}
editingLevel = null
}
const getPermissionsString = perms => {
return `${perms.length} / ${allPermissions.length}`
}
</script>
<div class="root">
<ButtonGroup>
<Button grouped color="secondary" on:click={createNewLevel}>Create New Access Level</Button>
</ButtonGroup>
<ButtonGroup>
<Button grouped color="secondary" on:click={createNewLevel}>
Create New Access Level
</Button>
</ButtonGroup>
{#if $store.accessLevels}
<table class="fields-table uk-table uk-table-small">
<thead>
{#if $store.accessLevels}
<table class="fields-table uk-table uk-table-small">
<thead>
<tr>
<th>Name</th>
<th>Permissions</th>
<th></th>
<th>Name</th>
<th>Permissions</th>
<th />
</tr>
</thead>
<tbody>
</thead>
<tbody>
{#each $store.accessLevels.levels as level}
<tr>
<td >{level.name}</td>
<td >{getPermissionsString(level.permissions)}</td>
<tr>
<td>{level.name}</td>
<td>{getPermissionsString(level.permissions)}</td>
<td class="edit-button">
<span on:click={() => onLevelEdit(level)}>{@html getIcon("edit")}</span>
<span on:click={() => onLevelDelete(level)}>{@html getIcon("trash")}</span>
<span on:click={() => onLevelEdit(level)}>
{@html getIcon('edit')}
</span>
<span on:click={() => onLevelDelete(level)}>
{@html getIcon('trash')}
</span>
</td>
</tr>
</tr>
{/each}
</tbody>
</table>
{:else}
(no actions added)
{/if}
</tbody>
</table>
{:else}(no actions added){/if}
<Modal bind:isOpen={isEditing}>
<Modal bind:isOpen={isEditing}>
{#if isEditing}
<AccessLevelView level={editingLevel}
allPermissions={allPermissions}
onFinished={onEditingFinished}
isNew={editingLevelIsNew}
allLevels={$store.accessLevels.levels}
hierarchy={$store.hierarchy}
actions={$store.actions} />
{/if}
</Modal>
<AccessLevelView
level={editingLevel}
{allPermissions}
onFinished={onEditingFinished}
isNew={editingLevelIsNew}
allLevels={$store.accessLevels.levels}
hierarchy={$store.hierarchy}
actions={$store.actions} />
{/if}
</Modal>
</div>
<style>
.root {
.root {
height: 100%;
position: relative;
padding: 1.5rem;
}
}
.actions-header {
.actions-header {
flex: 0 1 auto;
}
}
.node-view {
.node-view {
overflow-y: auto;
flex: 1 1 auto;
}
</style>
}
</style>

View File

@ -1,123 +1,134 @@
<script>
import Textbox from "../common/Textbox.svelte"
import Button from "../common/Button.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import { cloneDeep, filter, keys, map, isUndefined } from "lodash/fp"
import ErrorsBox from "../common/ErrorsBox.svelte"
import { validateActions, pipe } from "../common/core"
import getIcon from "../common/icon"
import Textbox from "../common/Textbox.svelte";
import Button from "../common/Button.svelte";
import ButtonGroup from "../common/ButtonGroup.svelte";
import {cloneDeep, filter, keys,
map, isUndefined} from "lodash/fp";
import ErrorsBox from "../common/ErrorsBox.svelte";
import {validateActions, pipe} from "../common/core";
import getIcon from "../common/icon";
export let action
export let onFinished = action => {}
export let allActions
export let isNew = true
export let action;
export let onFinished = (action) => {};
export let allActions;
export let isNew = true;
let optKey = ""
let optValue = ""
let optKey = "";
let optValue = "";
let clonedAction = cloneDeep(action);
let initialOptions = pipe(action.initialOptions, [
let clonedAction = cloneDeep(action)
let initialOptions = pipe(action.initialOptions, [
keys,
map(k => ({key:k, value:action.initialOptions[k]}))
]);
let errors = [];
map(k => ({ key: k, value: action.initialOptions[k] })),
])
let errors = []
const addNewOption = () => {
if(optKey && optValue && isUndefined(clonedAction.initialOptions[optKey])) {
clonedAction.initialOptions[optKey] = optValue;
initialOptions = [...initialOptions, {
key:optKey, value: optValue
}];
optKey = "";
optValue = "";
const addNewOption = () => {
if (
optKey &&
optValue &&
isUndefined(clonedAction.initialOptions[optKey])
) {
clonedAction.initialOptions[optKey] = optValue
initialOptions = [
...initialOptions,
{
key: optKey,
value: optValue,
},
]
optKey = ""
optValue = ""
}
}
}
const removeOption = (opt) => {
if(opt) {
delete clonedAction.initialOptions[opt.key]
initialOptions = pipe(initialOptions, [
filter(o => o.key !== opt.key)
]);
const removeOption = opt => {
if (opt) {
delete clonedAction.initialOptions[opt.key]
initialOptions = pipe(initialOptions, [filter(o => o.key !== opt.key)])
}
}
const save = () => {
}
const save = () => {
const newActionsList = [
...pipe(allActions ,[filter(a => a !== action)]),
clonedAction]
...pipe(allActions, [filter(a => a !== action)]),
clonedAction,
]
errors = pipe(newActionsList ,[
validateActions,
map(e => e.error)
]);
errors = pipe(newActionsList, [validateActions, map(e => e.error)])
if(errors.length === 0)
onFinished(clonedAction);
}
const cancel = () => {
onFinished();
}
if (errors.length === 0) onFinished(clonedAction)
}
const cancel = () => {
onFinished()
}
</script>
<div class="root">
<ErrorsBox {errors} />
<ErrorsBox {errors} />
<form class="uk-form-horizontal">
<form class="uk-form-horizontal">
<Textbox label="Name" bind:text={clonedAction.name} />
<Textbox label="Behaviour Source" bind:text={clonedAction.behaviourSource} />
<Textbox label="Behaviour" bind:text={clonedAction.behaviourName} />
<Textbox label="Name" bind:text={clonedAction.name} />
<Textbox
label="Behaviour Source"
bind:text={clonedAction.behaviourSource} />
<Textbox label="Behaviour" bind:text={clonedAction.behaviourName} />
</form>
</form>
<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 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">
{#each initialOptions as option}
<span class="option-container">{option.key} : {option.value} <span style="font-size:10pt; cursor: pointer" on:click={() => removeOption(option)}>{@html getIcon("trash-2")}</span></span>
{/each}
</div>
<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 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">
{#each initialOptions as option}
<span class="option-container">
{option.key} : {option.value}
<span
style="font-size:10pt; cursor: pointer"
on:click={() => removeOption(option)}>
{@html getIcon('trash-2')}
</span>
</span>
{/each}
</div>
</div>
<ButtonGroup>
<Button color="secondary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button>
</ButtonGroup>
<ButtonGroup>
<Button color="secondary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button>
</ButtonGroup>
</div>
<style>
.root {
.root {
padding: 2rem;
border-radius: 2rem;
}
}
.uk-grid-small {
.uk-grid-small {
padding: 1rem;
}
}
.option-container {
.option-container {
border-style: dotted;
border-width: 1px;
border-color: var(--primary75);
padding: 3px;
margin-right: 5px;
}
</style>
}
</style>

View File

@ -1,112 +1,111 @@
<script>
import getIcon from "../common/icon"
import { store } from "../builderStore"
import Button from "../common/Button.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import ActionView from "./ActionView.svelte"
import Modal from "../common/Modal.svelte"
import { pipe } from "../common/core"
import { keys, map, join } from "lodash/fp"
import getIcon from "../common/icon";
import {store} from "../builderStore";
import Button from "../common/Button.svelte";
import ButtonGroup from "../common/ButtonGroup.svelte";
import ActionView from "./ActionView.svelte";
import Modal from "../common/Modal.svelte";
import {pipe} from "../common/core";
import {keys, map, join} from "lodash/fp";
export let editingActionIsNew = false
export let editingAction = null
export let onActionEdit = action => {}
export let onActionDelete = action => {}
export let onActionSave = action => {}
export let onActionCancel = () => {}
export let editingActionIsNew = false;
export let editingAction = null;
export let onActionEdit = (action) => {};
export let onActionDelete = (action) => {};
export let onActionSave = (action) => {};
export let onActionCancel = () => {};
$: isEditing = editingAction !== null
$: isEditing = (editingAction !== null);
let actionsArray = []
store.subscribe(s => {
actionsArray = pipe(s.actions, [keys, map(k => s.actions[k])])
})
let actionsArray = [];
store.subscribe(s => {
actionsArray = pipe(s.actions, [
keys,
map(k => s.actions[k])
]);
});
let getDefaultOptionsHtml = defaultOptions =>
let getDefaultOptionsHtml = defaultOptions =>
pipe(defaultOptions, [
keys,
map(k => `<span style="color:var(--slate)">${k}: </span>${JSON.stringify(defaultOptions[k])}`),
join("<br>")
]);
keys,
map(
k =>
`<span style="color:var(--slate)">${k}: </span>${JSON.stringify(
defaultOptions[k]
)}`
),
join("<br>"),
])
let actionEditingFinished = (action) => {
if(action) {
onActionSave(action)
let actionEditingFinished = action => {
if (action) {
onActionSave(action)
} else {
onActionCancel();
onActionCancel()
}
}
}
</script>
<h3 class="title">Actions</h3>
{#if actionsArray}
<table class="fields-table uk-table uk-table-small uk-table-striped">
<table class="fields-table uk-table uk-table-small uk-table-striped">
<thead>
<tr>
<th >Description</th>
<th>Behaviour Source</th>
<th>Behaviour Name</th>
<th>Default Options</th>
<th></th>
</tr>
<tr>
<th>Description</th>
<th>Behaviour Source</th>
<th>Behaviour Name</th>
<th>Default Options</th>
<th />
</tr>
</thead>
<tbody>
{#each actionsArray as action}
{#each actionsArray as action}
<tr>
<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>
</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>
</td>
</tr>
{/each}
{/each}
</tbody>
</table>
{:else}
(no actions added)
{/if}
</table>
{:else}(no actions added){/if}
<Modal bind:isOpen={isEditing}>
{#if isEditing}
<ActionView action={editingAction}
allActions={$store.actions}
onFinished={actionEditingFinished}
isNew={editingActionIsNew}/>
{/if}
{#if isEditing}
<ActionView
action={editingAction}
allActions={$store.actions}
onFinished={actionEditingFinished}
isNew={editingActionIsNew} />
{/if}
</Modal>
<style>
.edit-button {
cursor:pointer;
.edit-button {
cursor: pointer;
color: var(--secondary25);
}
}
tr:hover .edit-button {
tr:hover .edit-button {
color: var(--secondary75);
}
}
.title {
.title {
margin: 3rem 0rem 0rem 0rem;
font-weight: 700;
}
}
.table-content {
.table-content {
font-weight: 500;
font-size: .9rem;
}
</style>
font-size: 0.9rem;
}
</style>

View File

@ -1,129 +1,130 @@
<script>
import getIcon from "../common/icon"
import { store } from "../builderStore"
import Button from "../common/Button.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import Actions from "./Actions.svelte"
import Triggers from "./Triggers.svelte"
import { getNewAction, getNewTrigger } from "../common/core"
import getIcon from "../common/icon";
import {store} from "../builderStore";
import Button from "../common/Button.svelte";
import ButtonGroup from "../common/ButtonGroup.svelte";
import Actions from "./Actions.svelte";
import Triggers from "./Triggers.svelte";
import {getNewAction, getNewTrigger} from "../common/core";
let editingAction = null
let editingActionIsNew = true
let editingTrigger = null
let editingTriggerIsNew = true
let editingAction = null;
let editingActionIsNew = true;
let editingTrigger = null;
let editingTriggerIsNew = true;
let getDefaultOptionsHtml = defaultOptions =>
let getDefaultOptionsHtml = defaultOptions =>
pipe(defaultOptions, [
keys,
map(k => `<span style="color:var(--slate)">${k}: </span>${JSON.parse(typeOptions[k])}`),
join("<br>")
]);
keys,
map(
k =>
`<span style="color:var(--slate)">${k}: </span>${JSON.parse(
typeOptions[k]
)}`
),
join("<br>"),
])
let onActionEdit = (action) => {
editingAction = action;
editingActionIsNew = false;
}
let onActionEdit = action => {
editingAction = action
editingActionIsNew = false
}
let newAction = () => {
editingAction = getNewAction();
editingActionIsNew = true;
}
let newAction = () => {
editingAction = getNewAction()
editingActionIsNew = true
}
let onActionDelete = (action) => {
store.deleteAction(action);
}
let onActionDelete = action => {
store.deleteAction(action)
}
let deleteTrigger = () => {}
let deleteTrigger = () => {}
let editTrigger = (trigger) => {
editingTrigger = trigger;
editingTriggerIsNew = false;
}
let editTrigger = trigger => {
editingTrigger = trigger
editingTriggerIsNew = false
}
let newTrigger = () => {
editingTrigger = getNewTrigger();
editingTriggerIsNew = true;
}
let newTrigger = () => {
editingTrigger = getNewTrigger()
editingTriggerIsNew = true
}
let onActionSave = action => {
store.saveAction(
action,
editingActionIsNew,
editingAction);
let onActionSave = action => {
store.saveAction(action, editingActionIsNew, editingAction)
editingAction = null;
}
editingAction = null
}
let onActionCancel = () => {
editingAction = null;
}
let onActionCancel = () => {
editingAction = null
}
let onTriggerSave = trigger => {
store.saveTrigger(
trigger,
editingTriggerIsNew,
editingTrigger);
let onTriggerSave = trigger => {
store.saveTrigger(trigger, editingTriggerIsNew, editingTrigger)
editingTrigger = null;
}
editingTrigger = null
}
let onTriggerCancel = () => {
editingTrigger = null;
}
let onTriggerCancel = () => {
editingTrigger = null
}
let onTriggerEdit = (trigger) => {
editingTrigger = trigger;
editingTriggerIsNew = false;
}
let onTriggerDelete = (trigger) => {
store.deleteTrigger(trigger);
}
let onTriggerEdit = trigger => {
editingTrigger = trigger
editingTriggerIsNew = false
}
let onTriggerDelete = trigger => {
store.deleteTrigger(trigger)
}
</script>
<div class="root">
<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="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} />
<div class="node-view">
<Actions
{editingActionIsNew}
{editingAction}
{onActionEdit}
{onActionDelete}
{onActionSave}
{onActionCancel} />
<Triggers {editingTriggerIsNew} {editingTrigger}
{onTriggerEdit} {onTriggerDelete} {onTriggerSave}
{onTriggerCancel} />
</div>
<Triggers
{editingTriggerIsNew}
{editingTrigger}
{onTriggerEdit}
{onTriggerDelete}
{onTriggerSave}
{onTriggerCancel} />
</div>
</div>
<style>
.root {
.root {
height: 100%;
position: relative;
padding: 1.5rem;
}
}
.actions-header {
.actions-header {
flex: 0 1 auto;
}
}
.node-view {
.node-view {
overflow-y: auto;
flex: 1 1 auto;
}
</style>
}
</style>

View File

@ -1,68 +1,71 @@
<script>
import Textbox from "../common/Textbox.svelte"
import Button from "../common/Button.svelte"
import Dropdown from "../common/Dropdown.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import CodeArea from "../common/CodeArea.svelte"
import { cloneDeep, filter, keys, some, map, isUndefined } from "lodash/fp"
import ErrorsBox from "../common/ErrorsBox.svelte"
import { validateTriggers, pipe, events } from "../common/core"
import getIcon from "../common/icon"
import Textbox from "../common/Textbox.svelte";
import Button from "../common/Button.svelte";
import Dropdown from "../common/Dropdown.svelte";
import ButtonGroup from "../common/ButtonGroup.svelte";
import CodeArea from "../common/CodeArea.svelte";
import {cloneDeep, filter, keys, some,
map, isUndefined} from "lodash/fp";
import ErrorsBox from "../common/ErrorsBox.svelte";
import {validateTriggers, pipe, events} from "../common/core";
import getIcon from "../common/icon";
export let trigger
export let onFinished = action => {}
export let allTriggers
export let allActions
export let isNew = true
export let trigger;
export let onFinished = (action) => {};
export let allTriggers;
export let allActions;
export let isNew = true;
let clonedTrigger = cloneDeep(trigger)
let errors = []
$: actionNames = map(a => a.name)(allActions)
let clonedTrigger = cloneDeep(trigger);
let errors = [];
$: actionNames = map(a => a.name)(allActions);
let cancel = () => onFinished();
let save = () => {
let cancel = () => onFinished()
let save = () => {
const newTriggersList = [
...pipe(allTriggers ,[filter(t => t !== trigger)]),
clonedTrigger]
...pipe(allTriggers, [filter(t => t !== trigger)]),
clonedTrigger,
]
errors = validateTriggers(newTriggersList, allActions);
errors = validateTriggers(newTriggersList, allActions)
const test = map(t =>(!t.actionName || some(a => a.name === t.actionName)(allActions)))(newTriggersList)
if(errors.length === 0)
onFinished(clonedTrigger);
}
const test = map(
t => !t.actionName || some(a => a.name === t.actionName)(allActions)
)(newTriggersList)
if (errors.length === 0) onFinished(clonedTrigger)
}
</script>
<div>
<ErrorsBox {errors} style="margin-bottom:20px"/>
<ErrorsBox {errors} style="margin-bottom:20px" />
<form class="uk-form-horizontal">
<Dropdown label="Event"
options={["",...events]}
bind:selected={clonedTrigger.eventName} />
<Dropdown label="Action"
options={["",...actionNames]}
bind:selected={clonedTrigger.actionName} />
<CodeArea label="Condition (javascript)"
bind:text={clonedTrigger.condition} />
<CodeArea label="Action Options Creator (javascript)"
bind:text={clonedTrigger.optionsCreator} />
<form class="uk-form-horizontal">
</form>
<Dropdown
label="Event"
options={['', ...events]}
bind:selected={clonedTrigger.eventName} />
<Dropdown
label="Action"
options={['', ...actionNames]}
bind:selected={clonedTrigger.actionName} />
<CodeArea
label="Condition (javascript)"
bind:text={clonedTrigger.condition} />
<CodeArea
label="Action Options Creator (javascript)"
bind:text={clonedTrigger.optionsCreator} />
<ButtonGroup>
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button>
</ButtonGroup>
</form>
<ButtonGroup>
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button>
</ButtonGroup>
</div>
<style>
</style>
</style>

View File

@ -1,94 +1,90 @@
<script>
import { store } from "../builderStore"
import getIcon from "../common/icon"
import Button from "../common/Button.svelte"
import Modal from "../common/Modal.svelte"
import TriggerView from "./TriggerView.svelte"
import {store} from "../builderStore";
import getIcon from "../common/icon";
import Button from "../common/Button.svelte";
import Modal from "../common/Modal.svelte";
import TriggerView from "./TriggerView.svelte";
export let editingTrigger = null
export let editingTriggerIsNew = true
export let onTriggerEdit = trigger => {}
export let onTriggerDelete = trigger => {}
export let onTriggerSave = trigger => {}
export let onTriggerCancel = () => {}
$: isEditing = editingTrigger !== null
export let editingTrigger = null;
export let editingTriggerIsNew = true;
export let onTriggerEdit = (trigger) => {};
export let onTriggerDelete = (trigger) => {};
export let onTriggerSave = (trigger) => {};
export let onTriggerCancel = () => {};
$: isEditing = (editingTrigger !== null);
let triggerEditingFinished = (trigger) => {
if(trigger) {
onTriggerSave(trigger)
let triggerEditingFinished = trigger => {
if (trigger) {
onTriggerSave(trigger)
} else {
onTriggerCancel();
onTriggerCancel()
}
}
}
</script>
<h3 class="title">Triggers</h3>
{#if $store.triggers}
<table class="fields-table uk-table uk-table-small uk-table-striped">
<table class="fields-table uk-table uk-table-small uk-table-striped">
<thead>
<tr>
<th>Event</th>
<th>Action</th>
<th>Condition</th>
<th>Create Options</th>
<th></th>
</tr>
<tr>
<th>Event</th>
<th>Action</th>
<th>Condition</th>
<th>Create Options</th>
<th />
</tr>
</thead>
<tbody>
{#each $store.triggers as trigger}
{#each $store.triggers as trigger}
<tr>
<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>
</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>
</td>
</tr>
{/each}
{/each}
</tbody>
</table>
{:else}
(no triggers added)
{/if}
</table>
{:else}(no triggers added){/if}
<Modal bind:isOpen={isEditing}>
{#if isEditing}
<TriggerView trigger={editingTrigger}
allActions={$store.actions}
allTriggers={$store.triggers}
onFinished={triggerEditingFinished}
isNew={editingTriggerIsNew}/>
{/if}
{#if isEditing}
<TriggerView
trigger={editingTrigger}
allActions={$store.actions}
allTriggers={$store.triggers}
onFinished={triggerEditingFinished}
isNew={editingTriggerIsNew} />
{/if}
</Modal>
<style>
.edit-button {
cursor:pointer;
.edit-button {
cursor: pointer;
color: var(--secondary25);
}
}
.title {
.title {
margin: 3rem 0rem 0rem 0rem;
font-weight: 700;
}
}
.table-content {
.table-content {
font-weight: 500;
font-size: .9rem;
}
font-size: 0.9rem;
}
tr:hover .edit-button {
tr:hover .edit-button {
color: var(--secondary75);
}
</style>
}
</style>

View File

@ -1,17 +1,20 @@
const apiCall = (method) => (url, body) =>
fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
},
body: body && JSON.stringify(body),
});
const apiCall = method => (url, body) =>
fetch(url, {
method: method,
headers: {
"Content-Type": "application/json",
},
body: body && JSON.stringify(body),
})
const post = apiCall("POST");
const get = apiCall("GET");
const patch = apiCall("PATCH");
const del = apiCall("DELETE");
const post = apiCall("POST")
const get = apiCall("GET")
const patch = apiCall("PATCH")
const del = apiCall("DELETE")
export default {
post, get, patch, delete:del
};
post,
get,
patch,
delete: del,
}

View File

@ -1,35 +1,33 @@
const buildCodeForSingleScreen = (screen) => {
let code = "";
const walkProps = (props) => {
if(props._code && props._code.trim().length > 0) {
code += buildComponentCode(props)
}
if(!props._children) return;
for(let child of props._children) {
walkProps(child);
}
const buildCodeForSingleScreen = screen => {
let code = ""
const walkProps = props => {
if (props._code && props._code.trim().length > 0) {
code += buildComponentCode(props)
}
walkProps(screen.props);
if (!props._children) return
return code;
for (let child of props._children) {
walkProps(child)
}
}
walkProps(screen.props)
return code
}
export const buildCodeForScreens = screens => {
let allfunctions = "";
for(let screen of screens) {
allfunctions += buildCodeForSingleScreen(screen);
}
return (`return ({ ${allfunctions} });`);
let allfunctions = ""
for (let screen of screens) {
allfunctions += buildCodeForSingleScreen(screen)
}
return `return ({ ${allfunctions} });`
}
const buildComponentCode = (componentProps) =>
`"${componentProps._id}" : (render, context) => {
const buildComponentCode = componentProps =>
`"${componentProps._id}" : (render, context) => {
${componentProps._code}
},
`;
`

View File

@ -1,12 +1,12 @@
import {createNewHierarchy} from "../common/core";
import { createNewHierarchy } from "../common/core"
export const createPackage = (packageInfo, store) => {
packageInfo.createNewPackage("");
const root = createNewHierarchy();
store.importAppDefinition({
hierarchy:root,
actions:[],
triggers:[],
accessLevels: {version:0, levels:[]}
});
};
packageInfo.createNewPackage("")
const root = createNewHierarchy()
store.importAppDefinition({
hierarchy: root,
actions: [],
triggers: [],
accessLevels: { version: 0, levels: [] },
})
}

View File

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

View File

@ -1,29 +1,27 @@
import {createPackage} from "./createPackage";
import getStore from "./store";
import { createPackage } from "./createPackage"
import getStore from "./store"
export const store = getStore();
export const store = getStore()
export const createNewPackage = () =>
createPackage(packageInfo, store);
export const createNewPackage = () => createPackage(packageInfo, store)
export const initialise = async () => {
try {
setupRouter(store);
await store.initialise();
} catch(err) {
console.log(err);
}
}
const setupRouter = (writable) => {
const pushState = history.pushState;
history.pushState = () => {
pushState.apply(history, arguments);
//fireEvents('pushState', arguments);
writable.initialise();
}
window.addEventListener('hashchange',()=>{
writable.initialise();
})
try {
setupRouter(store)
await store.initialise()
} catch (err) {
console.log(err)
}
}
const setupRouter = writable => {
const pushState = history.pushState
history.pushState = () => {
pushState.apply(history, arguments)
//fireEvents('pushState', arguments);
writable.initialise()
}
window.addEventListener("hashchange", () => {
writable.initialise()
})
}

View File

@ -1,50 +1,47 @@
import { map } from "lodash/fp";
import { map } from "lodash/fp"
export const loadLibs = async (appName, appPackage) => {
const allLibraries = {}
for (let lib of appPackage.pages.componentLibraries) {
const libModule = await import(makeLibraryUrl(appName, lib))
allLibraries[lib] = libModule
}
const allLibraries = {};
for(let lib of appPackage.pages.componentLibraries) {
const libModule = await import(makeLibraryUrl(appName, lib));
allLibraries[lib] = libModule;
}
return allLibraries;
return allLibraries
}
export const loadGeneratorLibs = async (appName, appPackage) => {
const allGeneratorLibs = {}
for (let lib of appPackage.pages.componentLibraries) {
const generatorModule = await import(makeGeneratorLibraryUrl(appName, lib))
allGeneratorLibs[lib] = generatorModule
}
const allGeneratorLibs = {};
for(let lib of appPackage.pages.componentLibraries) {
const generatorModule = await import(makeGeneratorLibraryUrl(appName, lib));
allGeneratorLibs[lib] = generatorModule;
}
return allGeneratorLibs;
return allGeneratorLibs
}
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 })
}
const allLibraries = [];
for(let lib of appPackage.pages.componentLibraries) {
const libUrl = makeLibraryUrl(appName, lib);
allLibraries.push({libName:lib, importPath:libUrl});
}
return allLibraries;
return allLibraries
}
export const loadLib = async (appName, lib, allLibs) => {
allLibs[lib] = await import(makeLibraryUrl(appName, lib));
return allLibs;
allLibs[lib] = await import(makeLibraryUrl(appName, lib))
return allLibs
}
export const loadGeneratorLib = async (appName, lib, allGeneratorLibs) => {
allGeneratorLibs[lib] = await import(makeGeneratorLibraryUrl(appName, lib));
return allGeneratorLibs;
allGeneratorLibs[lib] = await import(makeGeneratorLibraryUrl(appName, lib))
return allGeneratorLibs
}
export const makeLibraryUrl = (appName, lib) =>
`/_builder/${appName}/componentlibrary?lib=${encodeURI(lib)}`
export const makeLibraryUrl = (appName, lib) =>
`/_builder/${appName}/componentlibrary?lib=${encodeURI(lib)}`
export const makeGeneratorLibraryUrl = (appName, lib) =>
`/_builder/${appName}/componentlibraryGenerators?lib=${encodeURI(lib)}`
export const makeGeneratorLibraryUrl = (appName, lib) =>
`/_builder/${appName}/componentlibraryGenerators?lib=${encodeURI(lib)}`

File diff suppressed because it is too large Load Diff

View File

@ -1,799 +0,0 @@
import {
hierarchy as hierarchyFunctions,
} from "../../../core/src";
import {
filter, cloneDeep, sortBy,
map, last, keys, concat, keyBy,
find, isEmpty, values,
} from "lodash/fp";
import {
pipe, getNode, validate,
constructHierarchy, templateApi
} from "../common/core";
import { writable } from "svelte/store";
import { defaultPagesObject } from "../userInterface/pagesParsing/defaultPagesObject"
import { buildPropsHierarchy } from "../userInterface/pagesParsing/buildPropsHierarchy"
import api from "./api";
import { isRootComponent, getExactComponent } from "../userInterface/pagesParsing/searchComponents";
import { rename } from "../userInterface/pagesParsing/renameScreen";
import {
getNewComponentInfo, getScreenInfo,
} from "../userInterface/pagesParsing/createProps";
import {
loadLibs, loadLibUrls, loadGeneratorLibs
} from "./loadComponentLibraries";
<<<<<<< HEAD
import { buildCodeForScreens } from "./buildCodeForScreens";
=======
import { uuid } from './uuid';
import { generate_screen_css } from './generate_css';
>>>>>>> master
let appname = "";
export const getStore = () => {
const initial = {
apps: [],
appname: "",
hierarchy: {},
actions: [],
triggers: [],
pages: defaultPagesObject(),
mainUi: {},
unauthenticatedUi: {},
components: [],
currentFrontEndItem: null,
currentComponentInfo: null,
currentFrontEndType: "none",
currentPageName: "",
currentComponentProps: null,
currentNodeIsNew: false,
errors: [],
activeNav: "database",
isBackend: true,
hasAppPackage: false,
accessLevels: { version: 0, levels: [] },
currentNode: null,
libraries: null,
showSettings: false,
useAnalytics: true,
};
const store = writable(initial);
store.initialise = initialise(store, initial);
store.newChildRecord = newRecord(store, false);
store.newRootRecord = newRecord(store, true);
store.selectExistingNode = selectExistingNode(store);
store.newChildIndex = newIndex(store, false);
store.newRootIndex = newIndex(store, true);
store.saveCurrentNode = saveCurrentNode(store);
store.importAppDefinition = importAppDefinition(store);
store.deleteCurrentNode = deleteCurrentNode(store);
store.saveField = saveField(store);
store.deleteField = deleteField(store);
store.saveAction = saveAction(store);
store.deleteAction = deleteAction(store);
store.saveTrigger = saveTrigger(store);
store.deleteTrigger = deleteTrigger(store);
store.saveLevel = saveLevel(store);
store.deleteLevel = deleteLevel(store);
store.setActiveNav = setActiveNav(store);
store.saveScreen = saveScreen(store);
store.refreshComponents = refreshComponents(store);
store.addComponentLibrary = addComponentLibrary(store);
store.renameScreen = renameScreen(store);
store.deleteScreen = deleteScreen(store);
store.setCurrentScreen = setCurrentScreen(store);
store.setCurrentPage = setCurrentPage(store);
store.createScreen = createScreen(store);
store.removeComponentLibrary = removeComponentLibrary(store);
store.addStylesheet = addStylesheet(store);
store.removeStylesheet = removeStylesheet(store);
store.savePage = savePage(store);
store.showFrontend = showFrontend(store);
store.showBackend = showBackend(store);
store.showSettings = showSettings(store);
store.useAnalytics = useAnalytics(store);
store.createGeneratedComponents = createGeneratedComponents(store);
store.addChildComponent = addChildComponent(store);
store.selectComponent = selectComponent(store);
store.setComponentProp = setComponentProp(store);
store.setComponentStyle = setComponentStyle(store);
store.setComponentCode = setComponentCode(store);
return store;
}
export default getStore;
const initialise = (store, initial) => async () => {
appname = window.location.hash
? last(window.location.hash.substr(1).split("/"))
: "";
if (!appname) {
initial.apps = await api.get(`/_builder/api/apps`).then(r => r.json());
initial.hasAppPackage = false;
store.set(initial);
return initial;
}
const pkg = await api.get(`/_builder/api/${appname}/appPackage`)
.then(r => r.json());
initial.libraries = await loadLibs(appname, pkg);
initial.generatorLibraries = await loadGeneratorLibs(appname, pkg);
initial.loadLibraryUrls = () => loadLibUrls(appname, pkg);
initial.appname = appname;
initial.pages = pkg.pages;
initial.hasAppPackage = true;
initial.hierarchy = pkg.appDefinition.hierarchy;
initial.accessLevels = pkg.accessLevels;
initial.screens = values(pkg.screens);
initial.generators = generatorsArray(pkg.components.generators);
initial.components = values(pkg.components.components);
initial.actions = values(pkg.appDefinition.actions);
initial.triggers = pkg.appDefinition.triggers;
if (!!initial.hierarchy && !isEmpty(initial.hierarchy)) {
initial.hierarchy = constructHierarchy(initial.hierarchy);
const shadowHierarchy = createShadowHierarchy(initial.hierarchy);
if (initial.currentNode !== null)
initial.currentNode = getNode(
shadowHierarchy, initial.currentNode.nodeId
);
}
store.set(initial);
return initial;
}
const generatorsArray = generators =>
pipe(generators, [
keys,
filter(k => k !== "_lib"),
map(k => generators[k])
]);
const showSettings = store => show => {
store.update(s => {
s.showSettings = !s.showSettings;
return s;
});
}
const useAnalytics = store => useAnalytics => {
store.update(s => {
s.useAnalytics = !s.useAnalytics;
return s;
});
}
const showBackend = store => () => {
store.update(s => {
s.isBackend = true;
return s;
})
}
const showFrontend = store => () => {
store.update(s => {
s.isBackend = false;
return s;
})
}
const newRecord = (store, useRoot) => () => {
store.update(s => {
s.currentNodeIsNew = true;
const shadowHierarchy = createShadowHierarchy(s.hierarchy);
parent = useRoot ? shadowHierarchy
: getNode(
shadowHierarchy,
s.currentNode.nodeId);
s.errors = [];
s.currentNode = templateApi(shadowHierarchy)
.getNewRecordTemplate(parent, "", true);
return s;
});
}
const selectExistingNode = (store) => (nodeId) => {
store.update(s => {
const shadowHierarchy = createShadowHierarchy(s.hierarchy);
s.currentNode = getNode(
shadowHierarchy, nodeId
);
s.currentNodeIsNew = false;
s.errors = [];
s.activeNav = "database";
return s;
})
}
const newIndex = (store, useRoot) => () => {
store.update(s => {
s.currentNodeIsNew = true;
s.errors = [];
const shadowHierarchy = createShadowHierarchy(s.hierarchy);
parent = useRoot ? shadowHierarchy
: getNode(
shadowHierarchy,
s.currentNode.nodeId);
s.currentNode = templateApi(shadowHierarchy)
.getNewIndexTemplate(parent);
return s;
});
}
const saveCurrentNode = (store) => () => {
store.update(s => {
const errors = validate.node(s.currentNode);
s.errors = errors;
if (errors.length > 0) {
return s;
}
const parentNode = getNode(
s.hierarchy, s.currentNode.parent().nodeId);
const existingNode = getNode(
s.hierarchy, s.currentNode.nodeId);
let index = parentNode.children.length;
if (!!existingNode) {
// remove existing
index = existingNode.parent().children.indexOf(existingNode);
existingNode.parent().children = pipe(existingNode.parent().children, [
filter(c => c.nodeId !== existingNode.nodeId)
]);
}
// should add node into existing hierarchy
const cloned = cloneDeep(s.currentNode);
templateApi(s.hierarchy).constructNode(
parentNode,
cloned
);
const newIndexOfchild = child => {
if (child === cloned) return index;
const currentIndex = parentNode.children.indexOf(child);
return currentIndex >= index ? currentIndex + 1 : currentIndex;
}
parentNode.children = pipe(parentNode.children, [
sortBy(newIndexOfchild)
]);
if (!existingNode && s.currentNode.type === "record") {
const defaultIndex = templateApi(s.hierarchy)
.getNewIndexTemplate(cloned.parent());
defaultIndex.name = `all_${cloned.collectionName}`;
defaultIndex.allowedRecordNodeIds = [cloned.nodeId];
}
s.currentNodeIsNew = false;
savePackage(store, s);
return s;
});
}
const importAppDefinition = store => appDefinition => {
store.update(s => {
s.hierarchy = appDefinition.hierarchy;
s.currentNode = appDefinition.hierarchy.children.length > 0
? appDefinition.hierarchy.children[0]
: null;
s.actions = appDefinition.actions;
s.triggers = appDefinition.triggers;
s.currentNodeIsNew = false;
return s;
});
}
const deleteCurrentNode = store => () => {
store.update(s => {
const nodeToDelete = getNode(s.hierarchy, s.currentNode.nodeId);
s.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent())
? find(n => n != s.currentNode)
(s.hierarchy.children)
: nodeToDelete.parent();
if (hierarchyFunctions.isRecord(nodeToDelete)) {
nodeToDelete.parent().children = filter(c => c.nodeId !== nodeToDelete.nodeId)
(nodeToDelete.parent().children);
} else {
nodeToDelete.parent().indexes = filter(c => c.nodeId !== nodeToDelete.nodeId)
(nodeToDelete.parent().indexes);
}
s.errors = [];
savePackage(store, s);
return s;
});
}
const saveField = databaseStore => (field) => {
databaseStore.update(db => {
db.currentNode.fields = filter(f => f.name !== field.name)
(db.currentNode.fields);
templateApi(db.hierarchy).addField(db.currentNode, field);
return db;
});
}
const deleteField = databaseStore => field => {
databaseStore.update(db => {
db.currentNode.fields = filter(f => f.name !== field.name)
(db.currentNode.fields);
return db;
});
}
const saveAction = store => (newAction, isNew, oldAction = null) => {
store.update(s => {
const existingAction = isNew
? null
: find(a => a.name === oldAction.name)(s.actions);
if (existingAction) {
s.actions = pipe(s.actions, [
map(a => a === existingAction ? newAction : a)
]);
} else {
s.actions.push(newAction);
}
savePackage(store, s);
return s;
});
}
const deleteAction = store => action => {
store.update(s => {
s.actions = filter(a => a.name !== action.name)(s.actions);
savePackage(store, s);
return s;
});
}
const saveTrigger = store => (newTrigger, isNew, oldTrigger = null) => {
store.update(s => {
const existingTrigger = isNew
? null
: find(a => a.name === oldTrigger.name)(s.triggers);
if (existingTrigger) {
s.triggers = pipe(s.triggers, [
map(a => a === existingTrigger ? newTrigger : a)
]);
} else {
s.triggers.push(newTrigger);
}
savePackage(store, s);
return s;
});
}
const deleteTrigger = store => trigger => {
store.update(s => {
s.triggers = filter(t => t.name !== trigger.name)(s.triggers);
return s;
});
}
const incrementAccessLevelsVersion = (s) =>
s.accessLevels.version = (s.accessLevels.version || 0) + 1;
const saveLevel = store => (newLevel, isNew, oldLevel = null) => {
store.update(s => {
const levels = s.accessLevels.levels;
const existingLevel = isNew
? null
: find(a => a.name === oldLevel.name)(levels);
if (existingLevel) {
s.accessLevels.levels = pipe(levels, [
map(a => a === existingLevel ? newLevel : a)
]);
} else {
s.accessLevels.levels.push(newLevel);
}
incrementAccessLevelsVersion(s);
savePackage(store, s);
return s;
});
}
const deleteLevel = store => level => {
store.update(s => {
s.accessLevels.levels = filter(t => t.name !== level.name)(s.accessLevels.levels);
incrementAccessLevelsVersion(s);
savePackage(store, s);
return s;
});
}
const setActiveNav = store => navName => {
store.update(s => {
s.activeNav = navName;
return s;
});
}
const createShadowHierarchy = hierarchy =>
constructHierarchy(JSON.parse(JSON.stringify(hierarchy)));
const saveScreen = store => (screen) => {
store.update(s => {
return _saveScreen(store, s, screen);
})
};
const _saveScreen = (store, s, screen) => {
const screens = pipe(s.screens, [
filter(c => c.name !== screen.name),
concat([screen])
]);
s.screens = screens;
s.currentFrontEndItem = screen;
s.currentComponentInfo = getScreenInfo(
s.components, screen);
api.post(`/_builder/api/${s.appname}/screen`, screen)
.then(() => savePackage(store, s));
return s;
}
const _save = (appname, screen, store, s) =>
api.post(`/_builder/api/${appname}/screen`, screen)
.then(() => savePackage(store, s));
const createScreen = store => (screenName, layoutComponentName) => {
store.update(s => {
const newComponentInfo = getNewComponentInfo(
s.components, layoutComponentName, screenName);
s.currentFrontEndItem = newComponentInfo.component;
s.currentComponentInfo = newComponentInfo;
s.currentFrontEndType = "screen";
return _saveScreen(store, s, newComponentInfo.component);
});
};
const createGeneratedComponents = store => components => {
store.update(s => {
s.components = [...s.components, ...components];
s.screens = [...s.screens, ...components];
const doCreate = async () => {
for (let c of components) {
await api.post(`/_builder/api/${s.appname}/screen`, c);
}
await savePackage(store, s);
}
doCreate();
return s;
});
};
const deleteScreen = store => name => {
store.update(s => {
const components = pipe(s.components, [
filter(c => c.name !== name)
]);
const screens = pipe(s.screens, [
filter(c => c.name !== name)
]);
s.components = components;
s.screens = screens;
if (s.currentFrontEndItem.name === name) {
s.currentFrontEndItem = null;
s.currentFrontEndType = "";
}
api.delete(`/_builder/api/${s.appname}/screen/${name}`);
return s;
})
}
const renameScreen = store => (oldname, newname) => {
store.update(s => {
const {
screens, pages, error, changedScreens
} = rename(s.pages, s.screens, oldname, newname);
if (error) {
// should really do something with this
return s;
}
s.screens = screens;
s.pages = pages;
if (s.currentFrontEndItem.name === oldname)
s.currentFrontEndItem.name = newname;
const saveAllChanged = async () => {
for (let screenName of changedScreens) {
const changedScreen
= getExactComponent(screens, screenName);
await api.post(`/_builder/api/${s.appname}/screen`, changedScreen);
}
}
api.patch(`/_builder/api/${s.appname}/screen`, {
oldname, newname
})
.then(() => saveAllChanged())
.then(() => {
savePackage(store, s);
});
return s;
})
}
const savePage = store => async page => {
store.update(s => {
if (s.currentFrontEndType !== "page" || !s.currentPageName) {
return s;
}
s.pages[s.currentPageName] = page;
savePackage(store, s);
return s;
});
}
const addComponentLibrary = store => async lib => {
const response =
await api.get(`/_builder/api/${appname}/componentlibrary?lib=${encodeURI(lib)}`, undefined, false);
const success = response.status === 200;
const error = response.status === 404
? `Could not find library ${lib}`
: success
? ""
: response.statusText;
const components = success
? await response.json()
: [];
store.update(s => {
if (success) {
const componentsArray = [];
for (let c in components) {
componentsArray.push(components[c]);
}
s.components = pipe(s.components, [
filter(c => !c.name.startsWith(`${lib}/`)),
concat(componentsArray)
]);
s.pages.componentLibraries.push(lib);
savePackage(store, s);
}
return s;
})
}
const removeComponentLibrary = store => lib => {
store.update(s => {
s.pages.componentLibraries = filter(l => l !== lib)(
s.pages.componentLibraries);
savePackage(store, s);
return s;
})
}
const addStylesheet = store => stylesheet => {
store.update(s => {
s.pages.stylesheets.push(stylesheet);
savePackage(store, s);
return s;
})
}
const removeStylesheet = store => stylesheet => {
store.update(s => {
s.pages.stylesheets = filter(s => s !== stylesheet)(s.pages.stylesheets);
savePackage(store, s);
return s;
});
}
const refreshComponents = store => async () => {
const componentsAndGenerators =
await api.get(`/_builder/api/${db.appname}/components`).then(r => r.json());
const components = pipe(componentsAndGenerators.components, [
keys,
map(k => ({ ...componentsAndGenerators[k], name: k }))
]);
store.update(s => {
s.components = pipe(s.components, [
filter(c => !isRootComponent(c)),
concat(components)
]);
s.generators = componentsAndGenerators.generators;
return s;
});
};
const savePackage = (store, s) => {
const appDefinition = {
hierarchy: s.hierarchy,
triggers: s.triggers,
actions: keyBy("name")(s.actions),
props: {
main: buildPropsHierarchy(
s.components,
s.screens,
s.pages.main.appBody),
unauthenticated: buildPropsHierarchy(
s.components,
s.screens,
s.pages.unauthenticated.appBody)
},
uiFunctions: buildCodeForScreens(s.screens)
};
const data = {
appDefinition,
accessLevels: s.accessLevels,
pages: s.pages,
}
return api.post(`/_builder/api/${s.appname}/appPackage`, data);
}
const setCurrentScreen = store => screenName => {
store.update(s => {
const screen = getExactComponent(s.screens, screenName);
s.currentFrontEndItem = screen;
s.currentFrontEndType = "screen";
s.currentComponentInfo = getScreenInfo(s.components, screen);
setCurrentScreenFunctions(s);
return s;
})
}
const setCurrentPage = store => pageName => {
store.update(s => {
s.currentFrontEndType = "page";
s.currentPageName = pageName;
setCurrentScreenFunctions(s);
return s;
});
}
const addChildComponent = store => component => {
store.update(s => {
const newComponent = getNewComponentInfo(
s.components, component);
let children = s.currentComponentInfo.component ?
s.currentComponentInfo.component.props._children :
s.currentComponentInfo._children;
const component_definition = Object.assign(
cloneDeep(newComponent.fullProps), {
_component: component,
_styles: { position: {}, layout: {} },
_id: uuid()
})
if (children) {
if (s.currentComponentInfo.component) {
s.currentComponentInfo.component.props._children = children.concat(component_definition);
} else {
s.currentComponentInfo._children = children.concat(component_definition)
}
} else {
if (s.currentComponentInfo.component) {
s.currentComponentInfo.component.props._children = [component_definition];
} else {
s.currentComponentInfo._children = [component_definition]
}
}
_saveScreen(store, s, s.currentFrontEndItem);
_saveScreen(store, s, s.currentFrontEndItem);
return s;
})
}
const selectComponent = store => component => {
store.update(s => {
s.currentComponentInfo = component;
return s;
})
}
const setComponentProp = store => (name, value) => {
store.update(s => {
const current_component = s.currentComponentInfo;
s.currentComponentInfo[name] = value;
_saveScreen(store, s, s.currentFrontEndItem);
s.currentComponentInfo = current_component;
return s;
})
}
const setComponentStyle = store => (type, name, value) => {
store.update(s => {
if (!s.currentComponentInfo._styles) {
s.currentComponentInfo._styles = {};
}
s.currentComponentInfo._styles[type][name] = value;
s.currentFrontEndItem._css = generate_screen_css(s.currentFrontEndItem.props._children)
// save without messing with the store
_save(s.appname, s.currentFrontEndItem, store, s)
return s;
})
}
const setComponentCode = store => (code) => {
store.update(s => {
s.currentComponentInfo._code = code;
setCurrentScreenFunctions(s);
// save without messing with the store
_save(s.appname, s.currentFrontEndItem, store, s)
return s;
})
}
const setCurrentScreenFunctions = (s) => {
s.currentScreenFunctions =
s.currentFrontEndItem === "screen"
? buildCodeForScreens([s.currentFrontEndItem])
: "({});";
}

View File

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

View File

@ -1,11 +1,22 @@
<script>
export let disabled = false;
export let hidden = false;
export let primary = true;
export let alert = false;
export let warning = false;
export let disabled = false
export let hidden = false
export let primary = true
export let alert = false
export let warning = false
</script>
<button
on:click
class="button"
class:hidden
class:primary
class:alert
class:warning
{disabled}>
<slot />
</button>
<style>
.primary {
color: #0055ff;
@ -14,7 +25,7 @@
.alert {
color: rgba(255, 0, 31, 1);
background: rgba(255, 0, 31, 0.1);;
background: rgba(255, 0, 31, 0.1);
}
.button {
@ -40,14 +51,3 @@
visibility: hidden;
}
</style>
<button
on:click
class="button"
class:hidden
class:primary
class:alert
class:warning
{disabled}>
<slot />
</button>

View File

@ -1,163 +1,167 @@
<script>
export let color = "primary"
export let className = ""
export let style = ""
export let groupPosition = ""
export let grouped = false
export let color = "primary";
export let className = "";
export let style = "";
export let groupPosition = "";
export let grouped = false;
$: borderClass = grouped
? ""
: "border-normal";
$: borderClass = grouped ? "" : "border-normal"
</script>
<button class="{color} {className} {borderClass} {grouped ? "grouped" : ""}"
style="{style}"
on:click >
<slot/>
<button
class="{color}
{className}
{borderClass}
{grouped ? 'grouped' : ''}"
{style}
on:click>
<slot />
</button>
<style>
.border-normal {
border-radius: var(--borderradiusall);
}
.border-left {
border-radius: var(--borderradius) 0 0 var(--borderradius);
}
.border-right {
border-radius: 0 var(--borderradius) var(--borderradius) 0;
}
.border-middle {
border-radius: 0;
}
.border-normal { border-radius: var(--borderradiusall); }
.border-left { border-radius: var(--borderradius) 0 0 var(--borderradius); }
.border-right { border-radius: 0 var(--borderradius) var(--borderradius) 0; }
.border-middle { border-radius: 0; }
button {
border-style: solid;
button {
border-style: solid;
padding: 7.5px 15px;
cursor:pointer;
margin:5px;
cursor: pointer;
margin: 5px;
border-radius: 5px;
}
}
/* ---- PRIMARY ----*/
.primary {
/* ---- PRIMARY ----*/
.primary {
background-color: var(--primary100);
border-color: var(--primary100);
color: var(--white);
}
}
.primary:hover {
.primary:hover {
background-color: var(--primary75);
border-color: var(--primary75);
}
}
.primary:active {
.primary:active {
background-color: var(--primarydark);
border-color: var(--primarydark);
}
}
.primary-outline {
.primary-outline {
background-color: var(--white);
border-color: var(--primary100);
color: var(--primary100);
}
}
.primary-outline:hover {
.primary-outline:hover {
background-color: var(--primary10);
}
}
.primary-outline:pressed {
.primary-outline:pressed {
background-color: var(--primary25);
}
}
/* ---- secondary ----*/
/* ---- secondary ----*/
.secondary {
.secondary {
background-color: var(--secondary100);
border-color: var(--secondary100);
color: var(--white);
}
}
.secondary:hover {
.secondary:hover {
background-color: var(--secondary75);
border-color: var(--secondary75);
}
}
.secondary:pressed {
.secondary:pressed {
background-color: var(--secondarydark);
border-color: var(--secondarydark);
}
}
.secondary-outline {
.secondary-outline {
background-color: var(--white);
border-color: var(--secondary100);
color: var(--secondary100);
}
}
.secondary-outline:hover {
.secondary-outline:hover {
background-color: var(--secondary10);
}
}
.secondary-outline:pressed {
.secondary-outline:pressed {
background-color: var(--secondary25);
}
}
/* ---- success ----*/
.success {
/* ---- success ----*/
.success {
background-color: var(--success100);
border-color: var(--success100);
color: var(--white);
}
}
.success:hover {
.success:hover {
background-color: var(--success75);
border-color: var(--success75);
}
}
.success:pressed {
.success:pressed {
background-color: var(--successdark);
border-color: var(--successdark);
}
}
.success-outline {
.success-outline {
background-color: var(--white);
border-color: var(--success100);
color: var(--success100);
}
}
.success-outline:hover {
.success-outline:hover {
background-color: var(--success10);
}
}
.success-outline:pressed {
.success-outline:pressed {
background-color: var(--success25);
}
}
/* ---- deletion ----*/
.deletion {
/* ---- deletion ----*/
.deletion {
background-color: var(--deletion100);
border-color: var(--deletion100);
color: var(--white);
}
}
.deletion:hover {
.deletion:hover {
background-color: var(--deletion75);
border-color: var(--deletion75);
}
}
.deletion:pressed {
.deletion:pressed {
background-color: var(--deletiondark);
border-color: var(--deletiondark);
}
}
.deletion-outline {
.deletion-outline {
background-color: var(--white);
border-color: var(--deletion100);
color: var(--deletion100);
}
}
.deletion-outline:hover {
.deletion-outline:hover {
background-color: var(--deletion10);
}
}
.deletion-outline:pressed {
.deletion-outline:pressed {
background-color: var(--deletion25);
}
</style>
}
</style>

View File

@ -1,27 +1,25 @@
<script>
export let style="";
export let style = ""
</script>
<div class="root" style={style}>
<slot />
<div class="root" {style}>
<slot />
</div>
<style>
.root {
.root {
display: flex;
}
}
.root:last-child {
.root:last-child {
border-radius: 0 var(--borderradius) var(--borderradius) 0;
}
}
.root:first-child {
border-radius: var(--borderradius) 0 0 var(--borderradius);
}
.root:first-child {
border-radius: var(--borderradius) 0 0 var(--borderradius);
}
.root:not(:first-child):not(:last-child) {
.root:not(:first-child):not(:last-child) {
border-radius: 0;
}
</style>
}
</style>

View File

@ -1,16 +1,13 @@
<script>
export let checked=false;
export let label="";
export let checked = false
export let label = ""
</script>
<input class="uk-checkbox" type="checkbox" bind:checked on:change />{label}
<input class="uk-checkbox" type="checkbox" bind:checked on:change />
{label}
<style>
input {
margin-right:7px;
}
</style>
input {
margin-right: 7px;
}
</style>

View File

@ -1,24 +1,22 @@
<script>
// todo: use https://ace.c9.io
export let text = "";
export let label = "";
// todo: use https://ace.c9.io
export let text = ""
export let label = ""
</script>
<div>{label}</div>
<textarea class="uk-textarea" bind:value={text}></textarea>
<textarea class="uk-textarea" bind:value={text} />
<style>
textarea {
padding:3px;
margin-top:5px;
margin-bottom:10px;
textarea {
padding: 3px;
margin-top: 5px;
margin-bottom: 10px;
background: var(--lightslate);
color: var(--white);
font-family: 'Courier New', Courier, monospace;
width:95%;
height:100px;
font-family: "Courier New", Courier, monospace;
width: 95%;
height: 100px;
border-radius: 5px;
}
</style>
}
</style>

View File

@ -1,17 +1,13 @@
<script>
export let name = "";
export let name = ""
</script>
<div>
<h4>Coming Sometime: {name}</h4>
<h4>Coming Sometime: {name}</h4>
</div>
<style>
h4 {
h4 {
margin-top: 20px;
}
</style>
}
</style>

View File

@ -1,36 +1,34 @@
<script>
import flatpickr from "flatpickr"
import "flatpickr/dist/flatpickr.css"
import { onMount } from "svelte"
import flatpickr from "flatpickr";
import "flatpickr/dist/flatpickr.css";
import { onMount } from 'svelte';
export let value
export let label
export let width = "medium"
export let size = "small"
export let value;
export let label;
export let width = "medium";
export let size = "small";
let input
let fpInstance
let input;
let fpInstance;
$: if (fpInstance) fpInstance.setDate(value)
$: if (fpInstance) fpInstance.setDate(value);
onMount(() => {
fpInstance = flatpickr(input, {});
onMount(() => {
fpInstance = flatpickr(input, {})
fpInstance.config.onChange.push(selectedDates => {
if(selectedDates.length > 0)
value = new Date(selectedDates[0]);
});
return fpInstance;
})
if (selectedDates.length > 0) value = new Date(selectedDates[0])
})
return fpInstance
})
</script>
<div class="uk-margin">
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<input class="uk-input uk-form-width-{width} uk-form-{size}" bind:this={input} >
</div>
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<input
class="uk-input uk-form-width-{width} uk-form-{size}"
bind:this={input} />
</div>
</div>

View File

@ -1,39 +1,44 @@
<script>
import {createEventDispatcher} from "svelte";
export let selected;
export let label;
export let options;
export let valueMember;
export let textMember;
export let multiple=false;
export let width = "medium";
export let size = "small";
const dispatch =createEventDispatcher();
import { createEventDispatcher } from "svelte"
export let selected
export let label
export let options
export let valueMember
export let textMember
export let multiple = false
export let width = "medium"
export let size = "small"
const dispatch = createEventDispatcher()
</script>
<div class="uk-margin">
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
{#if multiple}
<select class="uk-select uk-form-width-{width} uk-form-{size}" multiple bind:value={selected} on:change>
{#each options as option}
<option value={!valueMember ? option : valueMember(option)}>{!textMember ? option : textMember(option)}</option>
{/each}
</select>
{:else}
<select class="uk-select uk-form-width-{width} uk-form-{size}" bind:value={selected} on:change>
{#each options as option}
<option value={!valueMember ? option : valueMember(option)}>{!textMember ? option : textMember(option)}</option>
{/each}
</select>
{/if}
</div>
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
{#if multiple}
<select
class="uk-select uk-form-width-{width} uk-form-{size}"
multiple
bind:value={selected}
on:change>
{#each options as option}
<option value={!valueMember ? option : valueMember(option)}>
{!textMember ? option : textMember(option)}
</option>
{/each}
</select>
{:else}
<select
class="uk-select uk-form-width-{width} uk-form-{size}"
bind:value={selected}
on:change>
{#each options as option}
<option value={!valueMember ? option : valueMember(option)}>
{!textMember ? option : textMember(option)}
</option>
{/each}
</select>
{/if}
</div>
</div>

View File

@ -1,68 +1,65 @@
<script>
import getIcon from "./icon";
export let iconName;
export let actions = []; // [ {label: "Action Name", onclick: () => {...} } ]
let isDroppedDown = false;
import getIcon from "./icon"
export let iconName
export let actions = [] // [ {label: "Action Name", onclick: () => {...} } ]
let isDroppedDown = false
</script>
<div class="root" on:click={() => (isDroppedDown = !isDroppedDown)}>
{@html getIcon(iconName)}
<div class="root" on:click={() => isDroppedDown = !isDroppedDown}>
{@html getIcon(iconName)}
<div class="dropdown-background" on:click|stopPropagation={() => isDroppedDown = false} style="display: {isDroppedDown ? 'block' : 'none'}"></div>
<div
class="dropdown-background"
on:click|stopPropagation={() => (isDroppedDown = false)}
style="display: {isDroppedDown ? 'block' : 'none'}" />
<div
class="dropdown-content"
style="display: {isDroppedDown ? 'inline-block' : 'none'}">
{#each actions as action}
<div class="action-row" on:click={action.onclick}>{action.label}</div>
{/each}
</div>
<div class="dropdown-content" style="display: {isDroppedDown ? 'inline-block' : 'none'}">
{#each actions as action}
<div class="action-row" on:click={action.onclick}>
{action.label}
</div>
{/each}
</div>
</div>
<style>
.dropdown-background {
.dropdown-background {
position: fixed;
top:0;
left:0;
width:100vw;
height:100vh;
}
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
.root {
.root {
cursor: pointer;
z-index: 1;
}
}
.dropdown-content {
.dropdown-content {
position: absolute;
background-color: var(--white);
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
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:not(:focus) {
.dropdown-content:not(:focus) {
display: none;
}
}
.action-row {
.action-row {
padding: 7px 10px;
cursor:pointer;
}
cursor: pointer;
}
.action-row:hover {
.action-row:hover {
background-color: var(--primary100);
color:var(--white);
}
</style>
color: var(--white);
}
</style>

View File

@ -1,29 +1,29 @@
<script>
export let errors = [];
export let errors = []
$:hasErrors = errors.length > 0;
$: hasErrors = errors.length > 0
</script>
{#if hasErrors}
<div class="error-container">
<div class="error-container">
{#each errors as error}
<div class="error-row">{error.field ? `${error.field}: ` : ""}{error.error}</div>
<div class="error-row">
{error.field ? `${error.field}: ` : ''}{error.error}
</div>
{/each}
</div>
</div>
{/if}
<style>
.error-container {
padding:10px;
.error-container {
padding: 10px;
border-style: solid;
border-color: var(--deletion100);
border-radius: var(--borderradiusall);
background: var(--deletion75);
}
}
.error-row {
.error-row {
padding: 5px 0px;
}
</style>
}
</style>

View File

@ -1,63 +1,59 @@
<script>
import getIcon from "./icon";
import getIcon from "./icon"
export let size = 18;
export let icon = "";
export let style = "";
export let color = "var(--secondary100)";
export let hoverColor = "var(--secondary75)";
export let attributes = {};
export let size = 18
export let icon = ""
export let style = ""
export let color = "var(--secondary100)"
export let hoverColor = "var(--secondary75)"
export let attributes = {}
let currentAttributes = [];
const addAttributes = (node, attributes) => {
const add = (_attributes) => {
const attrs = [];
for(let attr in _attributes) {
node.setAttribute(attr, _attributes[attr]);
attrs.push("uk-toggle")
}
currentAttributes = attrs;
let currentAttributes = []
const addAttributes = (node, attributes) => {
const add = _attributes => {
const attrs = []
for (let attr in _attributes) {
node.setAttribute(attr, _attributes[attr])
attrs.push("uk-toggle")
}
currentAttributes = attrs
}
add(attributes);
add(attributes)
return {
// should implement update method
update(attributes) {
for(let attr of currentAttributes) {
node.removeAttribute(attr)
}
add(attributes);
},
destroy() {}
// should implement update method
update(attributes) {
for (let attr of currentAttributes) {
node.removeAttribute(attr)
}
add(attributes)
},
destroy() {},
}
}
}
</script>
<button style="{style}{style ? ";" : ""} color:{color}; --hovercolor:{hoverColor}"
on:click
use:addAttributes={attributes}>
{@html getIcon(icon, size)}
<button
style="{style}{style ? ';' : ''} color:{color}; --hovercolor:{hoverColor}"
on:click
use:addAttributes={attributes}>
{@html getIcon(icon, size)}
</button>
<style>
button {
button {
border-style: none;
background-color: rgba(0,0,0,0);
background-color: rgba(0, 0, 0, 0);
cursor: pointer;
outline:none;
}
outline: none;
}
button:hover {
button:hover {
color: var(--hovercolor);
}
}
button:active {
outline:none;
}
</style>
button:active {
outline: none;
}
</style>

View File

@ -1,4 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path fill="none" d="M0 0h24v24H0z"/>
<path fill="currentColor" d="M12 13.172l4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222z"/>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24">
<path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M12 13.172l4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222z" />
</svg>

Before

(image error) Size: 228 B

After

(image error) Size: 246 B

View File

@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8" width="8" height="8">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8" width="8" height="8">
<circle cx="4" cy="4" r="4" stroke-width="0" fill="currentColor" />
</svg>
</svg>

Before

(image error) Size: 158 B

After

(image error) Size: 157 B

View File

@ -1,4 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path fill="none" d="M0 0h24v24H0z"/>
<path fill="currentColor" d="M4.828 21l-.02.02-.021-.02H2.992A.993.993 0 0 1 2 20.007V3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H4.828zM20 15V5H4v14L14 9l6 6zm0 2.828l-6-6L6.828 19H20v-1.172zM8 11a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24">
<path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M4.828 21l-.02.02-.021-.02H2.992A.993.993 0 0 1 2 20.007V3.993A1 1 0 0 1
2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H4.828zM20
15V5H4v14L14 9l6 6zm0 2.828l-6-6L6.828 19H20v-1.172zM8 11a2 2 0 1 1 0-4 2 2
0 0 1 0 4z" />
</svg>

Before

(image error) Size: 400 B

After

(image error) Size: 430 B

View File

@ -1,4 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path fill="none" d="M0 0h24v24H0z"/>
<path fill="currentColor" d="M5 5v14h14V5H5zM4 3h16a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zm5.869 12l-.82 2H6.833L11 7h2l4.167 10H14.95l-.82-2H9.87zm.82-2h2.622L12 9.8 10.689 13z"/>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24">
<path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M5 5v14h14V5H5zM4 3h16a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4a1
1 0 0 1 1-1zm5.869 12l-.82 2H6.833L11 7h2l4.167
10H14.95l-.82-2H9.87zm.82-2h2.622L12 9.8 10.689 13z" />
</svg>

Before

(image error) Size: 339 B

After

(image error) Size: 365 B

View File

@ -1,3 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/>
<path fill="currentColor" d="M21 20a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v16zM11 5H5v14h6V5zm8 8h-6v6h6v-6zm0-8h-6v6h6V5z"/>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24">
<path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M21 20a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h16a1 1 0 0 1 1
1v16zM11 5H5v14h6V5zm8 8h-6v6h6v-6zm0-8h-6v6h6V5z" />
</svg>

Before

(image error) Size: 280 B

After

(image error) Size: 305 B

View File

@ -1,3 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/>
<path fill="currentColor" d="M19.228 18.732l1.768-1.768 1.767 1.768a2.5 2.5 0 1 1-3.535 0zM8.878 1.08l11.314 11.313a1 1 0 0 1 0 1.415l-8.485 8.485a1 1 0 0 1-1.414 0l-8.485-8.485a1 1 0 0 1 0-1.415l7.778-7.778-2.122-2.121L8.88 1.08zM11 6.03L3.929 13.1 11 20.173l7.071-7.071L11 6.029z"/>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24">
<path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M19.228 18.732l1.768-1.768 1.767 1.768a2.5 2.5 0 1 1-3.535 0zM8.878
1.08l11.314 11.313a1 1 0 0 1 0 1.415l-8.485 8.485a1 1 0 0 1-1.414
0l-8.485-8.485a1 1 0 0 1 0-1.415l7.778-7.778-2.122-2.121L8.88 1.08zM11
6.03L3.929 13.1 11 20.173l7.071-7.071L11 6.029z" />
</svg>

Before

(image error) Size: 415 B

After

(image error) Size: 448 B

View File

@ -16,4 +16,4 @@
svg:hover {
cursor: pointer;
}
</style>
</style>

Before

(image error) Size: 446 B

After

(image error) Size: 447 B

View File

@ -1,4 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path fill="none" d="M0 0h24v24H0z"/>
<path fill="currentColor" d="M3 3h18a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zm1 2v14h16V5H4zm8 10h6v2h-6v-2zm-3.333-3L5.838 9.172l1.415-1.415L11.495 12l-4.242 4.243-1.415-1.415L8.667 12z"/>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24">
<path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M3 3h18a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zm1
2v14h16V5H4zm8 10h6v2h-6v-2zm-3.333-3L5.838 9.172l1.415-1.415L11.495
12l-4.242 4.243-1.415-1.415L8.667 12z" />
</svg>

Before

(image error) Size: 346 B

After

(image error) Size: 372 B

View File

@ -1,9 +1,9 @@
export { default as LayoutIcon } from './Layout.svelte';
export { default as PaintIcon } from './Paint.svelte';
export { default as TerminalIcon } from './Terminal.svelte';
export { default as InputIcon } from './Input.svelte';
export { default as ImageIcon } from './Image.svelte';
export { default as ArrowDownIcon } from './ArrowDown.svelte';
export { default as CircleIndicator } from './CircleIndicator.svelte';
export { default as PencilIcon } from './Pencil.svelte';
export { default as EventsIcon } from './Events.svelte';
export { default as LayoutIcon } from "./Layout.svelte"
export { default as PaintIcon } from "./Paint.svelte"
export { default as TerminalIcon } from "./Terminal.svelte"
export { default as InputIcon } from "./Input.svelte"
export { default as ImageIcon } from "./Image.svelte"
export { default as ArrowDownIcon } from "./ArrowDown.svelte"
export { default as CircleIndicator } from "./CircleIndicator.svelte"
export { default as PencilIcon } from "./Pencil.svelte"
export { default as EventsIcon } from "./Events.svelte"

View File

@ -1,12 +0,0 @@
export { default as LayoutIcon } from './Layout.svelte';
export { default as PaintIcon } from './Paint.svelte';
export { default as TerminalIcon } from './Terminal.svelte';
export { default as InputIcon } from './Input.svelte';
export { default as ImageIcon } from './Image.svelte';
export { default as ArrowDownIcon } from './ArrowDown.svelte';
<<<<<<< HEAD
export { default as CircleIndicator } from './CircleIndicator.svelte';
=======
export { default as EventsIcon } from './Events.svelte';
export { default as PencilIcon } from './Pencil.svelte';
>>>>>>> master

View File

@ -1,7 +1,9 @@
<script>
export let value = "";
export let value = ""
</script>
<input type="text" on:change bind:value />
<style>
input {
display: block;
@ -23,5 +25,3 @@
height: 50px;
}
</style>
<input type="text" on:change bind:value />

View File

@ -1,29 +1,29 @@
<script>
export let meta = [];
export let size = '';
export let values = [];
export let type = "number";
export let onStyleChanged = () => {};
export let meta = []
export let size = ""
export let values = []
export let type = "number"
export let onStyleChanged = () => {}
let _values = values.map(v => v);
let _values = values.map(v => v)
$: onStyleChanged(_values);
$: onStyleChanged(_values)
</script>
<div class="inputs {size}">
{#each meta as { placeholder }, i}
<input {type}
placeholder="{placeholder}"
value={values[i]}
on:input={(e) => _values[i] = e.target.value} />
<input
{type}
{placeholder}
value={values[i]}
on:input={e => (_values[i] = e.target.value)} />
{/each}
</div>
<style>
.inputs {
.inputs {
display: flex;
justify-content: space-between;
}
input {
@ -34,18 +34,18 @@
opacity: 0.7;
padding: 5px 10px;
box-sizing: border-box;
border: 1px solid #DBDBDB;
border: 1px solid #dbdbdb;
border-radius: 2px;
outline: none;
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
margin: 0;
}
}
.small > input {
width: 38px;

View File

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

View File

@ -1,26 +1,21 @@
<script>
export let value
export let label
export let value;
export let label;
const inputChanged = ev => {
const inputChanged = ev => {
try {
value = Number(ev.target.value);
} catch(_) {
value = null;
value = Number(ev.target.value)
} catch (_) {
value = null
}
}
let numberText = value === null || value === undefined
? "" : value.toString();
}
let numberText = value === null || value === undefined ? "" : value.toString()
</script>
<div class="uk-margin">
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<input class="uk-input" value={value} on:change={inputChanged} >
</div>
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<input class="uk-input" {value} on:change={inputChanged} />
</div>
</div>

View File

@ -1,3 +1,5 @@
<button on:click>+</button>
<style>
button {
cursor: pointer;
@ -19,5 +21,3 @@
color: rgba(22, 48, 87, 1);
}
</style>
<button on:click>+</button>

View File

@ -1,8 +1,17 @@
<script>
import getIcon from "./icon";
export let value;
import getIcon from "./icon"
export let value
</script>
<div class="select-container">
<select on:change {value}>
<slot />
</select>
<span class="arrow">
{@html getIcon('chevron-down', '24')}
</span>
</div>
<style>
.select-container {
padding-bottom: 10px;
@ -44,12 +53,3 @@
color: var(--primary100);
}
</style>
<div class="select-container">
<select on:change {value}>
<slot />
</select>
<span class="arrow">
{@html getIcon('chevron-down', '24')}
</span>
</div>

View File

@ -1,32 +1,32 @@
<script>
export let text = "";
export let label = "";
export let width = "medium";
export let size = "small";
export let margin = true;
export let infoText = "";
export let hasError = false;
export let disabled = false;
export let text = ""
export let label = ""
export let width = "medium"
export let size = "small"
export let margin = true
export let infoText = ""
export let hasError = false
export let disabled = false
</script>
<div class:uk-margin={margin}>
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<input class="uk-input uk-form-width-{width} uk-form-{size}"
class:uk-form-danger={hasError}
on:change
bind:value={text}
{disabled}>
</div>
{#if infoText}
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<input
class="uk-input uk-form-width-{width} uk-form-{size}"
class:uk-form-danger={hasError}
on:change
bind:value={text}
{disabled} />
</div>
{#if infoText}
<div class="info-text">{infoText}</div>
{/if}
{/if}
</div>
<style>
.info-text {
.info-text {
font-size: 0.7rem;
color: var(--secondary50);
}
}
</style>

View File

@ -1,35 +1,30 @@
<script>
import {join} from "lodash/fp";
import { join } from "lodash/fp"
export let values;
export let label;
export let values
export let label
const inputChanged = ev => {
const inputChanged = ev => {
try {
values = ev.target.value.split("\n");
} catch(_) {
values = [];
values = ev.target.value.split("\n")
} catch (_) {
values = []
}
}
$: valuesText = join("\n")(values);
}
$: valuesText = join("\n")(values)
</script>
<div class="uk-margin">
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<textarea value={valuesText} on:change={inputChanged} ></textarea>
</div>
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<textarea value={valuesText} on:change={inputChanged} />
</div>
</div>
<style>
textarea {
width:300px;
height:200px;
}
</style>
textarea {
width: 300px;
height: 200px;
}
</style>

View File

@ -1,29 +1,28 @@
import {
isString
} from "lodash/fp";
import { isString } from "lodash/fp"
import {
BB_STATE_BINDINGPATH, BB_STATE_FALLBACK,
BB_STATE_BINDINGSOURCE
} from "@budibase/client/src/state/isState";
BB_STATE_BINDINGPATH,
BB_STATE_FALLBACK,
BB_STATE_BINDINGSOURCE,
} from "@budibase/client/src/state/isState"
export const isBinding = value =>
!isString(value)
&& value
&& isString(value[BB_STATE_BINDINGPATH])
&& value[BB_STATE_BINDINGPATH].length > 0;
export const isBinding = value =>
!isString(value) &&
value &&
isString(value[BB_STATE_BINDINGPATH]) &&
value[BB_STATE_BINDINGPATH].length > 0
export const setBinding = ({path, fallback, source}, binding={} ) => {
if(isNonEmptyString(path)) binding[BB_STATE_BINDINGPATH] = path;
if(isNonEmptyString(fallback)) binding[BB_STATE_FALLBACK] = fallback;
binding[BB_STATE_BINDINGSOURCE] = source || "store";
return binding
export const setBinding = ({ path, fallback, source }, binding = {}) => {
if (isNonEmptyString(path)) binding[BB_STATE_BINDINGPATH] = path
if (isNonEmptyString(fallback)) binding[BB_STATE_FALLBACK] = fallback
binding[BB_STATE_BINDINGSOURCE] = source || "store"
return binding
}
export const getBinding = binding => ({
path: binding[BB_STATE_BINDINGPATH] || "",
fallback: binding[BB_STATE_FALLBACK] || "",
source: binding[BB_STATE_BINDINGSOURCE] || "store"
});
path: binding[BB_STATE_BINDINGPATH] || "",
fallback: binding[BB_STATE_FALLBACK] || "",
source: binding[BB_STATE_BINDINGSOURCE] || "store",
})
const isNonEmptyString = s => isString(s) && s.length > 0;
const isNonEmptyString = s => isString(s) && s.length > 0

View File

@ -1,96 +1,108 @@
import {hierarchy as hierarchyFunctions,
common, getTemplateApi, getAuthApi } from "../../../core/src";
import {find, filter, includes, keyBy, some,
flatten, map} from "lodash/fp";
import {
generateSchema
} from "../../../core/src/indexing/indexSchemaCreator";
hierarchy as hierarchyFunctions,
common,
getTemplateApi,
getAuthApi,
} from "../../../core/src"
import { find, filter, includes, keyBy, some, flatten, map } from "lodash/fp"
export { userWithFullAccess } from "../../../core/src/index";
import { generateSchema } from "../../../core/src/indexing/indexSchemaCreator"
export const pipe = common.$;
export { userWithFullAccess } from "../../../core/src/index"
export const events = common.eventsList;
export const pipe = common.$
export const getNode = (hierarchy, nodeId) =>
pipe(hierarchy, [
hierarchyFunctions.getFlattenedHierarchy,
find(n => n.nodeId === nodeId || n.nodeKey() === nodeId)
]);
export const events = common.eventsList
export const getNode = (hierarchy, nodeId) =>
pipe(hierarchy, [
hierarchyFunctions.getFlattenedHierarchy,
find(n => n.nodeId === nodeId || n.nodeKey() === nodeId),
])
export const constructHierarchy = node => {
if(!node) return node;
return templateApi(node).constructHierarchy(node);
if (!node) return node
return templateApi(node).constructHierarchy(node)
}
export const createNewHierarchy = () => {
return templateApi().getNewRootLevel();
return templateApi().getNewRootLevel()
}
export const templateApi = hierarchy => getTemplateApi({hierarchy})
export const authApi = (hierarchy, actions) => getAuthApi({
hierarchy, actions: keyBy("name")(actions), publish:()=>{}})
export const templateApi = hierarchy => getTemplateApi({ hierarchy })
export const authApi = (hierarchy, actions) =>
getAuthApi({
hierarchy,
actions: keyBy("name")(actions),
publish: () => {},
})
export const allTypes = templateApi({}).allTypes;
export const allTypes = templateApi({}).allTypes
export const validate = {
all: templateApi({}).validateAll,
node: templateApi({}).validateNode,
field: templateApi({}).validateField
};
all: templateApi({}).validateAll,
node: templateApi({}).validateNode,
field: templateApi({}).validateField,
}
export const getPotentialReverseReferenceIndexes = (hierarchy, refIndex) => {
const res = pipe(hierarchy, [
hierarchyFunctions.getFlattenedHierarchy,
filter(n => hierarchyFunctions.isAncestor(refIndex)(n)
|| hierarchyFunctions.isAncestor(refIndex)(n.parent())),
map(n => n.indexes),
flatten,
filter(hierarchyFunctions.isReferenceIndex)
]);
const res = pipe(hierarchy, [
hierarchyFunctions.getFlattenedHierarchy,
filter(
n =>
hierarchyFunctions.isAncestor(refIndex)(n) ||
hierarchyFunctions.isAncestor(refIndex)(n.parent())
),
map(n => n.indexes),
flatten,
filter(hierarchyFunctions.isReferenceIndex),
])
return res;
return res
}
export const getPotentialReferenceIndexes = (hierarchy, record) =>
pipe(hierarchy, [
hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isAncestorIndex),
filter(i => hierarchyFunctions.isAncestor(record)(i.parent())
|| i.parent().nodeId === record.parent().nodeId
|| hierarchyFunctions.isRoot(i.parent()))
]);
pipe(hierarchy, [
hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isAncestorIndex),
filter(
i =>
hierarchyFunctions.isAncestor(record)(i.parent()) ||
i.parent().nodeId === record.parent().nodeId ||
hierarchyFunctions.isRoot(i.parent())
),
])
export const getDefaultTypeOptions = type =>
!type ? {} : allTypes[type].getDefaultOptions();
export const getDefaultTypeOptions = type =>
!type ? {} : allTypes[type].getDefaultOptions()
export const getNewAction = () => templateApi({}).createAction();
export const getNewTrigger = () => templateApi({}).createTrigger();
export const getNewAction = () => templateApi({}).createAction()
export const getNewTrigger = () => templateApi({}).createTrigger()
export const validateActions = actions => templateApi({}).validateActions(actions);
export const validateTriggers = (triggers, actions) => templateApi({}).validateTriggers(triggers, actions);
export const validateActions = actions =>
templateApi({}).validateActions(actions)
export const validateTriggers = (triggers, actions) =>
templateApi({}).validateTriggers(triggers, actions)
export const generateFullPermissions = (hierarchy, actions) =>
authApi(hierarchy,actions).generateFullPermissions();
export const generateFullPermissions = (hierarchy, actions) =>
authApi(hierarchy, actions).generateFullPermissions()
export const getNewAccessLevel = () =>
authApi().getNewAccessLevel();
export const getNewAccessLevel = () => authApi().getNewAccessLevel()
export const validateAccessLevels = (hierarchy, actions, accessLevels) =>
authApi(hierarchy, actions).validateAccessLevels(accessLevels);
export const validateAccessLevels = (hierarchy, actions, accessLevels) =>
authApi(hierarchy, actions).validateAccessLevels(accessLevels)
export const getIndexNodes = (hierarchy) =>
pipe(hierarchy, [
hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isIndex)
]);
export const getIndexNodes = hierarchy =>
pipe(hierarchy, [
hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isIndex),
])
export const getRecordNodes = (hierarchy) =>
pipe(hierarchy, [
hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isRecord)
]);
export const getRecordNodes = hierarchy =>
pipe(hierarchy, [
hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isRecord),
])
export const getIndexSchema = hierarchy => index =>
generateSchema(hierarchy, index);
export const getIndexSchema = hierarchy => index =>
generateSchema(hierarchy, index)

View File

@ -1,26 +1,21 @@
import {
eventHandlers
} from "../../../client/src/state/eventHandlers";
import {writable} from "svelte/store";
export {
EVENT_TYPE_MEMBER_NAME
} from "../../../client/src/state/eventHandlers";
import {
createCoreApi
} from "../../../client/src/core";
import { eventHandlers } from "../../../client/src/state/eventHandlers"
import { writable } from "svelte/store"
export { EVENT_TYPE_MEMBER_NAME } from "../../../client/src/state/eventHandlers"
import { createCoreApi } from "../../../client/src/core"
export const allHandlers = (appDefinition, user) => {
export const allHandlers = (appDefinition, user) => {
const coreApi = createCoreApi(appDefinition, user)
appDefinition.hierarchy = coreApi.templateApi.constructHierarchy(
appDefinition.hierarchy
)
const store = writable({
_bbuser: user,
})
const coreApi = createCoreApi(appDefinition, user);
appDefinition.hierarchy = coreApi.templateApi.constructHierarchy(appDefinition.hierarchy);
const store = writable({
_bbuser: user
});
const handlersObj = eventHandlers(store, coreApi);
const handlersArray = [];
for(let key in handlersObj) {
handlersArray.push({name:key, ...handlersObj[key]});
}
return handlersArray;
}
const handlersObj = eventHandlers(store, coreApi)
const handlersArray = []
for (let key in handlersObj) {
handlersArray.push({ name: key, ...handlersObj[key] })
}
return handlersArray
}

View File

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

View File

@ -1,62 +1,59 @@
<script>
import Button from "../common/Button.svelte";
import ButtonGroup from "../common/ButtonGroup.svelte";
import {store} from "../builderStore";
import Modal from "../common/Modal.svelte";
import ErrorsBox from "../common/ErrorsBox.svelte";
import Button from "../common/Button.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import { store } from "../builderStore"
import Modal from "../common/Modal.svelte"
import ErrorsBox from "../common/ErrorsBox.svelte"
export let left;
let confirmDelete = false;
const openConfirmDelete = () => {
confirmDelete = true;
}
const deleteCurrentNode = () => {
confirmDelete = false;
store.deleteCurrentNode();
}
export let left
let confirmDelete = false
const openConfirmDelete = () => {
confirmDelete = true
}
const deleteCurrentNode = () => {
confirmDelete = false
store.deleteCurrentNode()
}
</script>
<div class="root" style="left: {left}">
<ButtonGroup>
<Button color="secondary" grouped on:click={store.saveCurrentNode}>
{#if $store.currentNodeIsNew}
Create
{:else}
Update
{/if}
</Button>
<ButtonGroup>
<Button color="secondary" grouped on:click={store.saveCurrentNode}>
{#if $store.currentNodeIsNew}Create{:else}Update{/if}
</Button>
{#if !$store.currentNodeIsNew}
<Button color="tertiary" grouped on:click={openConfirmDelete}>
Delete
</Button>
{/if}
</ButtonGroup>
{#if !!$store.errors && $store.errors.length > 0}
<div style="width: 500px">
<ErrorsBox errors={$store.errors}/>
</div>
{#if !$store.currentNodeIsNew}
<Button color="tertiary" grouped on:click={openConfirmDelete}>
Delete
</Button>
{/if}
<Modal bind:isOpen={confirmDelete}>
<div style="margin: 10px 0px 20px 0px">Are you sure you want to delete {$store.currentNode.name} ?</div>
<div style="float:right">
<Button color="primary" on:click={deleteCurrentNode}>Yes</Button>
<Button color="secondary" on:click={() => confirmDelete = false}>No</Button>
</div>
</Modal>
</ButtonGroup>
{#if !!$store.errors && $store.errors.length > 0}
<div style="width: 500px">
<ErrorsBox errors={$store.errors} />
</div>
{/if}
<Modal bind:isOpen={confirmDelete}>
<div style="margin: 10px 0px 20px 0px">
Are you sure you want to delete {$store.currentNode.name} ?
</div>
<div style="float:right">
<Button color="primary" on:click={deleteCurrentNode}>Yes</Button>
<Button color="secondary" on:click={() => (confirmDelete = false)}>
No
</Button>
</div>
</Modal>
</div>
<style>
.root {
.root {
padding: 1.5rem;
width: 100%;
align-items: right;
}
</style>
}
</style>

View File

@ -1,20 +1,16 @@
<script>
import RecordCard from "./RecordCard.svelte"
import RecordCard from "./RecordCard.svelte";
export let record = {};
export let record = {}
</script>
<div class="root">
<div class="title">{record.name}</div>
<div class="inner">
<div class="node-path">{record.nodeKey()}</div>
</div>
<div class="title">{record.name}</div>
<div class="inner">
<div class="node-path">{record.nodeKey()}</div>
</div>
</div>
<style>
</style>
</style>

View File

@ -1,82 +1,85 @@
<script>
import HierarchyRow from "./HierarchyRow.svelte"
import RecordView from "./RecordView.svelte"
import IndexView from "./IndexView.svelte"
import ActionsHeader from "./ActionsHeader.svelte"
import { store } from "../builderStore"
import getIcon from "../common/icon"
import DropdownButton from "../common/DropdownButton.svelte"
import { hierarchy as hierarchyFunctions } from "../../../core/src"
import HierarchyRow from "./HierarchyRow.svelte";
import RecordView from "./RecordView.svelte";
import IndexView from "./IndexView.svelte";
import ActionsHeader from "./ActionsHeader.svelte";
import {store} from "../builderStore";
import getIcon from "../common/icon";
import DropdownButton from "../common/DropdownButton.svelte";
import {hierarchy as hierarchyFunctions} from "../../../core/src";
const hierarchyWidth = "200px"
const hierarchyWidth = "200px";
const defaultNewIndexActions = [
{
label: "New Root Index",
onclick: store.newRootIndex,
},
]
const defaultNewIndexActions = [{
label:"New Root Index",
onclick: store.newRootIndex
}];
const defaultNewRecordActions = [
{
label: "New Root Record",
onclick: store.newRootRecord,
},
]
const defaultNewRecordActions = [{
label:"New Root Record",
onclick: store.newRootRecord
}];
let newIndexActions = defaultNewIndexActions
let newRecordActions = defaultNewRecordActions
let newIndexActions = defaultNewIndexActions;
let newRecordActions = defaultNewRecordActions;
store.subscribe(db => {
if(!db.currentNode || hierarchyFunctions.isIndex(db.currentNode)) {
newRecordActions = defaultNewRecordActions;
newIndexActions = defaultNewIndexActions;
store.subscribe(db => {
if (!db.currentNode || hierarchyFunctions.isIndex(db.currentNode)) {
newRecordActions = defaultNewRecordActions
newIndexActions = defaultNewIndexActions
} else {
newRecordActions = [
...defaultNewRecordActions,
{label: `New Child Record of ${db.currentNode.name}`,
onclick: store.newChildRecord}
];
newRecordActions = [
...defaultNewRecordActions,
{
label: `New Child Record of ${db.currentNode.name}`,
onclick: store.newChildRecord,
},
]
newIndexActions = [
...defaultNewIndexActions,
{label: `New Index on ${db.currentNode.name}`,
onclick: store.newChildIndex}
];
newIndexActions = [
...defaultNewIndexActions,
{
label: `New Index on ${db.currentNode.name}`,
onclick: store.newChildIndex,
},
]
}
});
})
</script>
<div class="root">
<div class="actions-header">
{#if $store.currentNode}
<ActionsHeader left={hierarchyWidth}/>
{/if}
</div>
<div class="node-view">
{#if !$store.currentNode}
<h1 style="margin-left: 100px">:)</h1>
{:else if $store.currentNode.type === "record"}
<RecordView />
{:else}
<IndexView />
{/if}
</div>
<div class="actions-header">
{#if $store.currentNode}
<ActionsHeader left={hierarchyWidth} />
{/if}
</div>
<div class="node-view">
{#if !$store.currentNode}
<h1 style="margin-left: 100px">:)</h1>
{:else if $store.currentNode.type === 'record'}
<RecordView />
{:else}
<IndexView />
{/if}
</div>
</div>
<style>
.root {
.root {
height: 100%;
position: relative;
}
}
.actions-header {
.actions-header {
flex: 0 1 auto;
}
}
.node-view {
.node-view {
overflow-y: auto;
flex: 1 1 auto;
}
</style>
}
</style>

View File

@ -1,121 +1,158 @@
<script>
import Dropdown from "../common/Dropdown.svelte";
import Textbox from "../common/Textbox.svelte";
import Button from "../common/Button.svelte";
import ButtonGroup from "../common/ButtonGroup.svelte";
import NumberBox from "../common/NumberBox.svelte";
import ValuesList from "../common/ValuesList.svelte";
import ErrorsBox from "../common/ErrorsBox.svelte";
import Checkbox from "../common/Checkbox.svelte";
import DatePicker from "../common/DatePicker.svelte";
import {cloneDeep, assign, keys,
isNumber, includes, map, isBoolean} from "lodash/fp";
import {allTypes, validate, getPotentialReferenceIndexes,
getDefaultTypeOptions, getNode,
getPotentialReverseReferenceIndexes} from "../common/core";
import Dropdown from "../common/Dropdown.svelte"
import Textbox from "../common/Textbox.svelte"
import Button from "../common/Button.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import NumberBox from "../common/NumberBox.svelte"
import ValuesList from "../common/ValuesList.svelte"
import ErrorsBox from "../common/ErrorsBox.svelte"
import Checkbox from "../common/Checkbox.svelte"
import DatePicker from "../common/DatePicker.svelte"
import {
cloneDeep,
assign,
keys,
isNumber,
includes,
map,
isBoolean,
} from "lodash/fp"
import {
allTypes,
validate,
getPotentialReferenceIndexes,
getDefaultTypeOptions,
getNode,
getPotentialReverseReferenceIndexes,
} from "../common/core"
export let field;
export let allFields;
export let onFinished = () => {};
export let store;
export let field
export let allFields
export let onFinished = () => {}
export let store
let errors = [];
let clonedField = cloneDeep(field);
let errors = []
let clonedField = cloneDeep(field)
$: isNew = !!field && field.name.length === 0;
$: isNew = !!field && field.name.length === 0
$: possibleReferenceIndexes = getPotentialReferenceIndexes(
store.hierarchy, store.currentNode
);
$: possibleReferenceIndexes = getPotentialReferenceIndexes(
store.hierarchy,
store.currentNode
)
$: selectedReverseRefIndex =
!clonedField.typeOptions.indexNodeKey
$: selectedReverseRefIndex = !clonedField.typeOptions.indexNodeKey
? ""
: getNode(store.hierarchy, clonedField.typeOptions.indexNodeKey);
: getNode(store.hierarchy, clonedField.typeOptions.indexNodeKey)
$: possibleReverseReferenceIndexes =
!selectedReverseRefIndex
$: possibleReverseReferenceIndexes = !selectedReverseRefIndex
? []
: getPotentialReverseReferenceIndexes(
store.hierarchy, selectedReverseRefIndex);
store.hierarchy,
selectedReverseRefIndex
)
const typeChanged = (ev) =>
clonedField.typeOptions = getDefaultTypeOptions(ev.detail);
const save = () => {
errors = validate.field(allFields)(clonedField);
if(errors.length > 0) return;
field.typeOptions = cloneDeep(clonedField.typeOptions);
onFinished(
assign(field)(clonedField)
);
}
const typeChanged = ev =>
(clonedField.typeOptions = getDefaultTypeOptions(ev.detail))
const save = () => {
errors = validate.field(allFields)(clonedField)
if (errors.length > 0) return
field.typeOptions = cloneDeep(clonedField.typeOptions)
onFinished(assign(field)(clonedField))
}
</script>
<div class="root">
<ErrorsBox errors={errors} />
<ErrorsBox {errors} />
<form class="uk-form-horizontal">
<form class="uk-form-horizontal">
<Dropdown label="Type" bind:selected={clonedField.type} options={keys(allTypes)} on:change={typeChanged} />
<Dropdown
label="Type"
bind:selected={clonedField.type}
options={keys(allTypes)}
on:change={typeChanged} />
{#if isNew}
<Textbox label="Field Name" bind:text={clonedField.name} />
{:else}
<div style="font-weight: bold">{clonedField.name}</div>
{/if}
{#if isNew}
<Textbox label="Field Name" bind:text={clonedField.name} />
{:else}
<div style="font-weight: bold">{clonedField.name}</div>
{/if}
<Textbox label="Label" bind:text={clonedField.label} />
{#if clonedField.type === "string"}
<NumberBox label="Max Length" bind:value={clonedField.typeOptions.maxLength} />
<ValuesList label="Values (options)" bind:values={clonedField.typeOptions.values} />
<Checkbox label="Declared Values Only" bind:checked={clonedField.typeOptions.allowDeclaredValuesOnly} />
{:else if clonedField.type === "bool"}
<Checkbox label="Allow Null" bind:checked={clonedField.typeOptions.allowNulls} />
{:else if clonedField.type === "datetime"}
<DatePicker label="Min Value" bind:value={clonedField.typeOptions.minValue} />
<DatePicker label="Max Value" bind:value={clonedField.typeOptions.maxValue} />
{:else if clonedField.type === "number"}
<NumberBox label="Min Value" bind:value={clonedField.typeOptions.minValue} />
<NumberBox label="Max Value" bind:value={clonedField.typeOptions.maxValue} />
<NumberBox label="Decimal Places" bind:value={clonedField.typeOptions.decimalPlaces} />
{:else if clonedField.type === "reference"}
<Dropdown label="Lookup Index"
options={possibleReferenceIndexes}
valueMember={n => n.nodeKey()}
textMember={n => n.name}
bind:selected={clonedField.typeOptions.indexNodeKey} />
<Textbox label="Label" bind:text={clonedField.label} />
<Dropdown label="Reverse Reference Index"
options={possibleReverseReferenceIndexes}
multiple=true
valueMember={n => n.nodeKey()}
textMember={n => n.name}
bind:selected={clonedField.typeOptions.reverseIndexNodeKeys} />
{#if clonedField.type === 'string'}
<NumberBox
label="Max Length"
bind:value={clonedField.typeOptions.maxLength} />
<ValuesList
label="Values (options)"
bind:values={clonedField.typeOptions.values} />
<Checkbox
label="Declared Values Only"
bind:checked={clonedField.typeOptions.allowDeclaredValuesOnly} />
{:else if clonedField.type === 'bool'}
<Checkbox
label="Allow Null"
bind:checked={clonedField.typeOptions.allowNulls} />
{:else if clonedField.type === 'datetime'}
<DatePicker
label="Min Value"
bind:value={clonedField.typeOptions.minValue} />
<DatePicker
label="Max Value"
bind:value={clonedField.typeOptions.maxValue} />
{:else if clonedField.type === 'number'}
<NumberBox
label="Min Value"
bind:value={clonedField.typeOptions.minValue} />
<NumberBox
label="Max Value"
bind:value={clonedField.typeOptions.maxValue} />
<NumberBox
label="Decimal Places"
bind:value={clonedField.typeOptions.decimalPlaces} />
{:else if clonedField.type === 'reference'}
<Dropdown
label="Lookup Index"
options={possibleReferenceIndexes}
valueMember={n => n.nodeKey()}
textMember={n => n.name}
bind:selected={clonedField.typeOptions.indexNodeKey} />
<Textbox label="Display Value" bind:text={clonedField.typeOptions.displayValue} />
<Dropdown
label="Reverse Reference Index"
options={possibleReverseReferenceIndexes}
multiple="true"
valueMember={n => n.nodeKey()}
textMember={n => n.name}
bind:selected={clonedField.typeOptions.reverseIndexNodeKeys} />
{:else if clonedField.type.startsWith("array")}
<NumberBox label="Min Length" bind:value={clonedField.typeOptions.minLength} />
<NumberBox label="Max Length" bind:value={clonedField.typeOptions.maxLength} />
{/if}
<Textbox
label="Display Value"
bind:text={clonedField.typeOptions.displayValue} />
{:else if clonedField.type.startsWith('array')}
<NumberBox
label="Min Length"
bind:value={clonedField.typeOptions.minLength} />
<NumberBox
label="Max Length"
bind:value={clonedField.typeOptions.maxLength} />
{/if}
</form>
</form>
<ButtonGroup style="float: right;">
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={() => onFinished(false)}>Cancel</Button>
</ButtonGroup>
<ButtonGroup style="float: right;">
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={() => onFinished(false)}>
Cancel
</Button>
</ButtonGroup>
</div>
<style>
</style>
</style>

View File

@ -1,45 +1,42 @@
<script>
import {store} from "../builderStore";
import {cloneDeep} from "lodash/fp";
export let level = 0;
export let node;
import { store } from "../builderStore"
import { cloneDeep } from "lodash/fp"
export let level = 0
export let node
</script>
<div class="root">
<div class="title" on:click={() => store.selectExistingNode(node.nodeId)} style="padding-left: {20 + (level * 20)}px">
{node.name}
</div>
{#if node.children}
<div
class="title"
on:click={() => store.selectExistingNode(node.nodeId)}
style="padding-left: {20 + level * 20}px">
{node.name}
</div>
{#if node.children}
{#each node.children as child}
<svelte:self node={child}
level={level+1}/>
<svelte:self node={child} level={level + 1} />
{/each}
{/if}
{/if}
</div>
<style>
.root {
.root {
display: block;
font-size: .9rem;
font-size: 0.9rem;
width: 100%;
cursor: pointer;
font-weight: bold;
}
}
.title {
.title {
font: var(--fontblack);
padding-top: 10px;
padding-right: 5px;
padding-bottom: 10px;
color: var(--secondary100);
}
}
.title:hover {
.title:hover {
background-color: var(--secondary10);
}
</style>
}
</style>

View File

@ -1,76 +1,79 @@
<script>
import Textbox from "../common/Textbox.svelte"
import CodeArea from "../common/CodeArea.svelte"
import Button from "../common/Button.svelte"
import Dropdown from "../common/Dropdown.svelte"
import { store } from "../builderStore"
import { filter, some, map } from "lodash/fp"
import { hierarchy as hierarchyFunctions, common } from "../../../core/src"
import Textbox from "../common/Textbox.svelte";
import CodeArea from "../common/CodeArea.svelte";
import Button from "../common/Button.svelte";
import Dropdown from "../common/Dropdown.svelte";
import {store} from "../builderStore";
import {filter, some, map} from "lodash/fp";
import {hierarchy as hierarchyFunctions, common} from "../../../core/src";
const pipe = common.$
const pipe = common.$;
let index
let indexableRecords = []
let index;
let indexableRecords = [];
store.subscribe($store => {
index = $store.currentNode
indexableRecords = pipe($store.hierarchy, [
hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isDecendant(index.parent())),
filter(hierarchyFunctions.isRecord),
map(n => ({
node: n,
isallowed: some(id => n.nodeId === id)(index.allowedRecordNodeIds),
})),
])
})
store.subscribe($store => {
index = $store.currentNode;
indexableRecords = pipe($store.hierarchy,[
hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isDecendant(index.parent())),
filter(hierarchyFunctions.isRecord),
map(n => ({
node:n,
isallowed: some(id => n.nodeId === id)(index.allowedRecordNodeIds)
}))
]);
});
const toggleAllowedRecord = record => {
if(record.isallowed) {
index.allowedRecordNodeIds = filter(id => id !== record.node.nodeId)
(index.allowedRecordNodeIds);
const toggleAllowedRecord = record => {
if (record.isallowed) {
index.allowedRecordNodeIds = filter(id => id !== record.node.nodeId)(
index.allowedRecordNodeIds
)
} else {
index.allowedRecordNodeIds.push(record.node.nodeId);
index.allowedRecordNodeIds.push(record.node.nodeId)
}
};
}
</script>
<form class="uk-form-horizontal root">
<Textbox bind:text={index.name} label="Name"/>
<div class="allowed-records">
<div>Records to Index</div>
{#each indexableRecords as rec}
<input type="checkbox" checked={rec.isallowed} on:change={() => toggleAllowedRecord(rec)}/>
<span>{rec.node.name}</span>
{/each}
</div>
<Textbox bind:text={index.name} label="Name" />
<div class="allowed-records">
<div>Records to Index</div>
{#each indexableRecords as rec}
<input
type="checkbox"
checked={rec.isallowed}
on:change={() => toggleAllowedRecord(rec)} />
<span>{rec.node.name}</span>
{/each}
</div>
<Dropdown label="Index Type" bind:selected={index.indexType} options={["ancestor", "reference"]} />
<Dropdown
label="Index Type"
bind:selected={index.indexType}
options={['ancestor', 'reference']} />
<CodeArea bind:text={index.map} label="Map (javascript)"/>
<CodeArea bind:text={index.filter} label="Filter (javascript expression)"/>
<CodeArea bind:text={index.getShardName} label="Shard Name (javascript expression)"/>
<CodeArea bind:text={index.map} label="Map (javascript)" />
<CodeArea bind:text={index.filter} label="Filter (javascript expression)" />
<CodeArea
bind:text={index.getShardName}
label="Shard Name (javascript expression)" />
</form>
<style>
.root {
.root {
height: 100%;
padding: 15px;
}
}
.allowed-records {
.allowed-records {
margin: 20px 0px;
}
}
.allowed-records > span {
margin-right:30px;
}
</style>
.allowed-records > span {
margin-right: 30px;
}
</style>

View File

@ -1,300 +1,307 @@
<script>
import Textbox from "../common/Textbox.svelte"
import Button from "../common/Button.svelte"
import getIcon from "../common/icon"
import FieldView from "./FieldView.svelte"
import Modal from "../common/Modal.svelte"
import { map, join, filter, some, find, keys, isDate } from "lodash/fp"
import { store } from "../builderStore"
import { common, hierarchy as h } from "../../../core/src"
import { templateApi, pipe, validate } from "../common/core"
import Textbox from "../common/Textbox.svelte";
import Button from "../common/Button.svelte";
import getIcon from "../common/icon";
import FieldView from "./FieldView.svelte";
import Modal from "../common/Modal.svelte";
import {map, join, filter, some,
find, keys, isDate} from "lodash/fp";
import { store } from "../builderStore";
import {common, hierarchy as h} from "../../../core/src";
import {templateApi, pipe, validate} from "../common/core";
let record
let getIndexAllowedRecords
let editingField = false
let fieldToEdit
let isNewField = false
let newField
let editField
let deleteField
let onFinishedFieldEdit
let editIndex
let record;
let getIndexAllowedRecords;
let editingField = false;
let fieldToEdit;
let isNewField = false;
let newField;
let editField;
let deleteField;
let onFinishedFieldEdit;
let editIndex;
store.subscribe($store => {
record = $store.currentNode;
const flattened = h.getFlattenedHierarchy($store.hierarchy);
getIndexAllowedRecords = index =>
pipe(index.allowedRecordNodeIds, [
filter(id => some(n => n.nodeId === id)(flattened)),
map(id => find(n => n.nodeId === id)
(flattened).name),
join(", ")
]);
store.subscribe($store => {
record = $store.currentNode
const flattened = h.getFlattenedHierarchy($store.hierarchy)
getIndexAllowedRecords = index =>
pipe(index.allowedRecordNodeIds, [
filter(id => some(n => n.nodeId === id)(flattened)),
map(id => find(n => n.nodeId === id)(flattened).name),
join(", "),
])
newField = () => {
isNewField = true;
fieldToEdit = templateApi($store.hierarchy).getNewField("string");
editingField = true;
isNewField = true
fieldToEdit = templateApi($store.hierarchy).getNewField("string")
editingField = true
}
onFinishedFieldEdit = (field) => {
if(field) {
store.saveField(field);
}
editingField = false;
onFinishedFieldEdit = field => {
if (field) {
store.saveField(field)
}
editingField = false
}
editField = (field) => {
isNewField = false;
fieldToEdit = field;
editingField = true;
editField = field => {
isNewField = false
fieldToEdit = field
editingField = true
}
deleteField = (field) => {
store.deleteField(field);
deleteField = field => {
store.deleteField(field)
}
editIndex = index => {
store.selectExistingNode(index.nodeId);
store.selectExistingNode(index.nodeId)
}
})
})
let getTypeOptionsValueText = value => {
if (
value === Number.MAX_SAFE_INTEGER ||
value === Number.MIN_SAFE_INTEGER ||
new Date(value).getTime() === new Date(8640000000000000).getTime() ||
new Date(value).getTime() === new Date(-8640000000000000).getTime()
)
return "(any)"
let getTypeOptionsValueText = value => {
if(value === Number.MAX_SAFE_INTEGER
|| value === Number.MIN_SAFE_INTEGER
|| new Date(value).getTime() === new Date(8640000000000000).getTime()
|| new Date(value).getTime() === new Date(-8640000000000000).getTime()) return "(any)";
if(value === null) return "(not set)";
return value;
}
if (value === null) return "(not set)"
return value
}
let getTypeOptions = typeOptions =>
let getTypeOptions = typeOptions =>
pipe(typeOptions, [
keys,
map(k => `<span style="color:var(--slate)">${k}: </span>${getTypeOptionsValueText(typeOptions[k])}`),
join("<br>")
]);
keys,
map(
k =>
`<span style="color:var(--slate)">${k}: </span>${getTypeOptionsValueText(
typeOptions[k]
)}`
),
join("<br>"),
])
const nameChanged = ev => {
const pluralName = n => `${n}s`;
if(record.collectionName === "") {
record.collectionName = pluralName(ev.target.value);
const nameChanged = ev => {
const pluralName = n => `${n}s`
if (record.collectionName === "") {
record.collectionName = pluralName(ev.target.value)
}
}
}
</script>
<div class="root">
<form class="uk-form-horizontal">
<h3 class="settings-title">
Settings
</h3>
<Textbox label="Name:" bind:text={record.name} on:change={nameChanged}/>
{#if !record.isSingle}
<Textbox label="Collection Name:" bind:text={record.collectionName} />
<Textbox label="Shard Factor:" bind:text={record.allidsShardFactor} />
{/if}
<div class="recordkey">{record.nodeKey()}</div>
<form class="uk-form-horizontal">
<h3 class="settings-title">Settings</h3>
</form>
<h3 class="title">
Fields <span class="add-field-button" on:click={newField}>{@html getIcon("plus")}</span>
</h3>
<Textbox label="Name:" bind:text={record.name} on:change={nameChanged} />
{#if !record.isSingle}
<Textbox label="Collection Name:" bind:text={record.collectionName} />
<Textbox label="Shard Factor:" bind:text={record.allidsShardFactor} />
{/if}
<div class="recordkey">{record.nodeKey()}</div>
{#if record.fields.length > 0}
</form>
<h3 class="title">
Fields
<span class="add-field-button" on:click={newField}>
{@html getIcon('plus')}
</span>
</h3>
{#if record.fields.length > 0}
<table class="fields-table uk-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Options</th>
<th></th>
</tr>
</thead>
<tbody>
{#each record.fields as field}
<tr>
<td >
<div class="field-label">{field.label}</div>
<div style="font-size: 0.8em; color: var(--slate)">{field.name}</div>
</td>
<td >{field.type}</td>
<td >{@html getTypeOptions(field.typeOptions)}</td>
<td>
<span class="edit-button" on:click={() => editField(field)}>{@html getIcon("edit")}</span>
<span class="edit-button" on:click={() => deleteField(field)}>{@html getIcon("trash")}</span>
</td>
</tr>
{/each}
</tbody>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Options</th>
<th />
</tr>
</thead>
<tbody>
{#each record.fields as field}
<tr>
<td>
<div class="field-label">{field.label}</div>
<div style="font-size: 0.8em; color: var(--slate)">
{field.name}
</div>
</td>
<td>{field.type}</td>
<td>
{@html getTypeOptions(field.typeOptions)}
</td>
<td>
<span class="edit-button" on:click={() => editField(field)}>
{@html getIcon('edit')}
</span>
<span class="edit-button" on:click={() => deleteField(field)}>
{@html getIcon('trash')}
</span>
</td>
</tr>
{/each}
</tbody>
</table>
{:else}
(no fields added)
{/if}
{:else}(no fields added){/if}
{#if editingField}
<Modal bind:isOpen={editingField} onClosed={() => onFinishedFieldEdit(false) }>
<FieldView field={fieldToEdit}
onFinished={onFinishedFieldEdit}
allFields={record.fields}
store={$store}/>
{#if editingField}
<Modal
bind:isOpen={editingField}
onClosed={() => onFinishedFieldEdit(false)}>
<FieldView
field={fieldToEdit}
onFinished={onFinishedFieldEdit}
allFields={record.fields}
store={$store} />
</Modal>
{/if}
{/if}
<h3 class="title">
Indexes
</h3>
<h3 class="title">Indexes</h3>
{#each record.indexes as index}
{#each record.indexes as index}
<div class="index-container">
<div class="index-name">
{index.name}
<span style="margin-left: 7px" on:click={() => editIndex(index)}>{@html getIcon("edit")}</span>
</div>
<div class="index-name">
{index.name}
<span style="margin-left: 7px" on:click={() => editIndex(index)}>
{@html getIcon('edit')}
</span>
</div>
<div class="index-field-row">
<span class="index-label">records indexed:</span>
<span>{getIndexAllowedRecords(index)}</span>
<span class="index-label" style="margin-left: 15px">type:</span>
<span>{index.indexType}</span>
</div>
<div class="index-field-row">
<span class="index-label">map:</span>
<code class="index-mapfilter">{index.map}</code>
</div>
{#if index.filter}
<div class="index-field-row">
<span class="index-label">records indexed: </span>
<span>{getIndexAllowedRecords(index)}</span>
<span class="index-label" style="margin-left: 15px">type:</span>
<span>{index.indexType}</span>
<span class="index-label">filter:</span>
<code class="index-mapfilter">{index.filter}</code>
</div>
<div class="index-field-row">
<span class="index-label">map:</span>
<code class="index-mapfilter">{index.map}</code>
</div>
{#if index.filter}
<div class="index-field-row">
<span class="index-label">filter:</span>
<code class="index-mapfilter">{index.filter}</code>
</div>
{/if}
{/if}
</div>
{:else}
<div class="no-indexes">
No indexes added.
</div>
{/each}
{:else}
<div class="no-indexes">No indexes added.</div>
{/each}
</div>
<style>
.root {
.root {
height: 100%;
padding: 2rem;
}
}
.settings-title {
.settings-title {
font-weight: 700;
}
}
.title {
.title {
margin: 3rem 0rem 0rem 0rem;
font-weight: 700;
}
}
.recordkey {
.recordkey {
font-size: 14px;
font-weight: 600;
color: var(--primary100);
}
}
.fields-table {
.fields-table {
margin: 1rem 1rem 0rem 0rem;
border-collapse:collapse;
}
border-collapse: collapse;
}
.add-field-button {
cursor:pointer;
}
.add-field-button {
cursor: pointer;
}
.edit-button {
cursor:pointer;
.edit-button {
cursor: pointer;
color: var(--secondary25);
}
}
.edit-button:hover {
cursor:pointer;
.edit-button:hover {
cursor: pointer;
color: var(--secondary75);
}
}
th {
text-align: left;
}
th {
text-align: left;
}
td {
td {
padding: 1rem 5rem 1rem 0rem;
margin:0;
margin: 0;
font-size: 14px;
font-weight: 500;
}
}
.field-label {
font-size: 14px;
font-weight: 500;
}
.field-label {
font-size: 14px;
font-weight: 500;
}
thead > tr {
thead > tr {
border-width: 0px 0px 1px 0px;
border-style: solid;
border-color: var(--secondary75);
margin-bottom: 20px;
}
}
tbody > tr {
tbody > tr {
border-width: 0px 0px 1px 0px;
border-style: solid;
border-color: var(--primary10);
}
}
tbody > tr:hover {
tbody > tr:hover {
background-color: var(--primary10);
}
}
tbody > tr:hover .edit-button {
tbody > tr:hover .edit-button {
color: var(--secondary75);
}
}
.index-container {
.index-container {
border-style: solid;
border-width: 0 0 1px 0;
border-color: var(--secondary25);
padding: 10px;
margin-bottom: 5px;
}
}
.index-label {
.index-label {
color: var(--slate);
}
}
.index-name {
.index-name {
font-weight: bold;
color: var(--primary100);
}
}
.index-container code {
.index-container code {
margin: 0;
display: inline;
background-color: var(--primary10);
color: var(--secondary100);
padding:3px;
}
padding: 3px;
}
.index-field-row {
.index-field-row {
margin: 1rem 0rem 0rem 0rem;
}
}
.no-indexes {
.no-indexes {
margin: 1rem 0rem 0rem 0rem;
font-family: var(--fontnormal);
font-size: 14px;
}
</style>
}
</style>

View File

@ -1,20 +1,18 @@
import App from "./App.svelte";
import "./global.css";
import "./fonts.css";
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";
import "uikit/dist/js/uikit.min.js";
import "codemirror/lib/codemirror.css";
import 'codemirror/theme/monokai.css';
import App from "./App.svelte"
import "./global.css"
import "./fonts.css"
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"
import "uikit/dist/js/uikit.min.js"
import "codemirror/lib/codemirror.css"
import "codemirror/theme/monokai.css"
const app = new App({
target: document.getElementById("app")
});
target: document.getElementById("app"),
})

View File

@ -1,163 +1,153 @@
<script>
import { store } from "../builderStore"
import HierarchyRow from "./HierarchyRow.svelte"
import DropdownButton from "../common/DropdownButton.svelte"
import { hierarchy as hierarchyFunctions } from "../../../core/src"
import NavItem from "./NavItem.svelte"
import getIcon from "../common/icon"
import { store } from "../builderStore";
import HierarchyRow from "./HierarchyRow.svelte";
import DropdownButton from "../common/DropdownButton.svelte";
import {hierarchy as hierarchyFunctions} from "../../../core/src";
import NavItem from "./NavItem.svelte";
import getIcon from "../common/icon";
const newRootRecord = () => {
store.newRootRecord()
}
const newRootIndex = () => {
store.newRootIndex()
}
const newRootRecord = () => {
store.newRootRecord();
}
const newChildRecord = () => {
store.newChildRecord()
}
const newRootIndex = () => {
store.newRootIndex();
}
const newChildIndex = () => {
store.newChildIndex()
}
const newChildRecord = () => {
store.newChildRecord();
}
const newChildIndex = () => {
store.newChildIndex();
}
const defaultNewChildActions = [
const defaultNewChildActions = [
{
label:"New Root Record",
onclick: newRootRecord
label: "New Root Record",
onclick: newRootRecord,
},
{
label:"New Root Index",
onclick: newRootIndex
}
];
label: "New Root Index",
onclick: newRootIndex,
},
]
let newChildActions = defaultNewChildActions;
let newChildActions = defaultNewChildActions
const setActiveNav = (name) => () => {
store.setActiveNav(name);
}
const setActiveNav = name => () => {
store.setActiveNav(name)
}
store.subscribe(db => {
if(!db.currentNode || hierarchyFunctions.isIndex(db.currentNode)) {
newChildActions = defaultNewChildActions;
store.subscribe(db => {
if (!db.currentNode || hierarchyFunctions.isIndex(db.currentNode)) {
newChildActions = defaultNewChildActions
} else {
newChildActions = [
{
label:"New Root Record",
onclick: newRootRecord
},
{
label:"New Root Index",
onclick: newRootIndex
},
{
label: `New Child Record of ${db.currentNode.name}`,
onclick: newChildRecord
},
{
label: `New Index on ${db.currentNode.name}`,
onclick: newChildIndex
}
];
newChildActions = [
{
label: "New Root Record",
onclick: newRootRecord,
},
{
label: "New Root Index",
onclick: newRootIndex,
},
{
label: `New Child Record of ${db.currentNode.name}`,
onclick: newChildRecord,
},
{
label: `New Index on ${db.currentNode.name}`,
onclick: newChildIndex,
},
]
}
});
})
</script>
<div class="items-root">
<div class="hierarchy">
<div class="components-list-container">
<div class="nav-group-header">
<div>{@html getIcon("database","18")}</div>
<div class="hierarchy-title">Database</div>
<DropdownButton iconName="plus" actions={newChildActions} />
</div>
</div>
<div class="hierarchy-items-container">
{#each $store.hierarchy.children as record}
<HierarchyRow node={record}
type="record" />
{/each}
{#each $store.hierarchy.indexes as index}
<HierarchyRow node={index}
type="index" />
{/each}
<div class="hierarchy">
<div class="components-list-container">
<div class="nav-group-header">
<div>
{@html getIcon('database', '18')}
</div>
<div class="hierarchy-title">Database</div>
<DropdownButton iconName="plus" actions={newChildActions} />
</div>
</div>
<NavItem name="actions" label="Actions & Triggers"/>
<NavItem name="access levels" label="User Levels"/>
<div class="hierarchy-items-container">
{#each $store.hierarchy.children as record}
<HierarchyRow node={record} type="record" />
{/each}
{#each $store.hierarchy.indexes as index}
<HierarchyRow node={index} type="index" />
{/each}
</div>
</div>
<NavItem name="actions" label="Actions & Triggers" />
<NavItem name="access levels" label="User Levels" />
</div>
<style>
.items-root {
.items-root {
display: flex;
flex-direction: column;
max-height: 100%;
height: 100%;
background-color: var(--secondary5);
}
}
.nav-group-header {
display:grid;
.nav-group-header {
display: grid;
grid-template-columns: [icon] auto [title] 1fr [button] auto;
padding: 2rem 1rem 0rem 1rem;
font-size: .9rem;
font-size: 0.9rem;
font-weight: bold;
}
}
.nav-group-header>div:nth-child(1) {
padding: 0rem .7rem 0rem 0rem;
.nav-group-header > div:nth-child(1) {
padding: 0rem 0.7rem 0rem 0rem;
vertical-align: bottom;
grid-column-start: icon;
margin-right: 5px;
}
}
.nav-group-header>div:nth-child(2) {
margin-left:5px;
.nav-group-header > div:nth-child(2) {
margin-left: 5px;
vertical-align: bottom;
grid-column-start: title;
margin-top:auto;
}
margin-top: auto;
}
.nav-group-header>div:nth-child(3) {
.nav-group-header > div:nth-child(3) {
vertical-align: bottom;
grid-column-start: button;
cursor: pointer;
color: var(--primary75);
}
}
.nav-group-header>div:nth-child(3):hover {
color: var(--primary75);
}
.nav-group-header > div:nth-child(3):hover {
color: var(--primary75);
}
.hierarchy-title {
.hierarchy-title {
flex: auto 1 1;
}
}
.hierarchy {
display:flex;
.hierarchy {
display: flex;
flex-direction: column;
flex: 1 0 auto;
height: 100px;
}
}
.hierarchy-items-container {
.hierarchy-items-container {
flex: 1 1 auto;
overflow-y:auto;
}
</style>
overflow-y: auto;
}
</style>

View File

@ -1,66 +1,63 @@
<script>
import { store } from "../builderStore"
import { cloneDeep } from "lodash/fp"
import getIcon from "../common/icon"
export let level = 0
export let node
export let type
import {store} from "../builderStore";
import {cloneDeep} from "lodash/fp";
import getIcon from "../common/icon";
export let level = 0;
export let node;
export let type;
let navActive = "";
$:icon = type==="index" ? "list" : "file";
store.subscribe(s => {
if(s.currentNode)
navActive = (s.activeNav === "database" && node.nodeId === s.currentNode.nodeId
? "active" : "")
});
let navActive = ""
$: icon = type === "index" ? "list" : "file"
store.subscribe(s => {
if (s.currentNode)
navActive =
s.activeNav === "database" && node.nodeId === s.currentNode.nodeId
? "active"
: ""
})
</script>
<div class="root">
<div class="title {navActive}" on:click={() => store.selectExistingNode(node.nodeId)} style="padding-left: {20 + (level * 20)}px">
{@html getIcon(icon, 12)} <span style="margin-left: 1rem">{node.name}</span>
</div>
{#if node.children}
{#each node.children as child}
<svelte:self node={child}
level={level+1}
type="record"/>
{/each}
{/if}
{#if node.indexes}
{#each node.indexes as index}
<svelte:self node={index}
level={level+1}
type="index"/>
{/each}
{/if}
<div
class="title {navActive}"
on:click={() => store.selectExistingNode(node.nodeId)}
style="padding-left: {20 + level * 20}px">
{@html getIcon(icon, 12)}
<span style="margin-left: 1rem">{node.name}</span>
</div>
{#if node.children}
{#each node.children as child}
<svelte:self node={child} level={level + 1} type="record" />
{/each}
{/if}
{#if node.indexes}
{#each node.indexes as index}
<svelte:self node={index} level={level + 1} type="index" />
{/each}
{/if}
</div>
<style>
.root {
.root {
display: block;
font-size: .9rem;
font-size: 0.9rem;
width: 100%;
cursor: pointer;
color: var(--secondary50);
font-weight: 500;
}
}
.title {
padding-top: .5rem;
padding-right: .5rem;
}
.title {
padding-top: 0.5rem;
padding-right: 0.5rem;
}
.title:hover {
.title:hover {
background-color: var(--secondary10);
}
}
.active {
.active {
background-color: var(--primary10);
}
</style>
}
</style>

View File

@ -1,43 +1,35 @@
<script>
import { store } from "../builderStore"
import getIcon from "../common/icon"
import {store} from "../builderStore";
import getIcon from "../common/icon";
export let name = ""
export let label = ""
export let name = "";
export let label = "";
let navActive = ""
let navActive = "";
store.subscribe(db => {
navActive = (db.activeNav === name ? "active" : "")
});
const setActive = () =>
store.setActiveNav(name);
store.subscribe(db => {
navActive = db.activeNav === name ? "active" : ""
})
const setActive = () => store.setActiveNav(name)
</script>
<div class="nav-item {navActive}" on:click={setActive}>
{label}
</div>
<div class="nav-item {navActive}" on:click={setActive}>{label}</div>
<style>
.nav-item {
.nav-item {
padding: 1.5rem 1rem 0rem 1rem;
font-size: .9rem;
font-size: 0.9rem;
font-weight: bold;
cursor: pointer;
flex: 0 0 auto;
}
}
.nav-item:hover {
.nav-item:hover {
background-color: var(--primary10);
}
}
.active {
.active {
background-color: var(--primary10);
}
</style>
}
</style>

View File

@ -1,83 +1,84 @@
<script>
import { store } from "../builderStore/store";
import UIkit from "uikit";
import Button from "../common/Button.svelte";
import ButtonGroup from "../common/ButtonGroup.svelte";
import CodeMirror from "codemirror";
import "codemirror/mode/javascript/javascript.js";
import { store } from "../builderStore/store"
import UIkit from "uikit"
import Button from "../common/Button.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import CodeMirror from "codemirror"
import "codemirror/mode/javascript/javascript.js"
export let onCodeChanged;
export let code;
export let onCodeChanged
export let code
export const show = () => {
UIkit.modal(codeModal).show();
}
let codeModal;
let editor;
let cmInstance;
$: currentCode = code;
$: originalCode = code;
$: {
if(editor) {
if(!cmInstance) {
cmInstance = CodeMirror.fromTextArea(editor, {
mode: 'javascript',
lineNumbers: false,
lineWrapping: true,
smartIndent: true,
matchBrackets: true,
readOnly: false
});
cmInstance.on("change", () => currentCode = cmInstance.getValue());
}
cmInstance.focus();
cmInstance.setValue(code || "");
export const show = () => {
UIkit.modal(codeModal).show()
}
}
const cancel = () => {
UIkit.modal(codeModal).hide();
currentCode = originalCode;
}
let codeModal
let editor
let cmInstance
const save = () => {
originalCode = currentCode;
onCodeChanged(currentCode);
UIkit.modal(codeModal).hide();
}
$: currentCode = code
$: originalCode = code
$: {
if (editor) {
if (!cmInstance) {
cmInstance = CodeMirror.fromTextArea(editor, {
mode: "javascript",
lineNumbers: false,
lineWrapping: true,
smartIndent: true,
matchBrackets: true,
readOnly: false,
})
cmInstance.on("change", () => (currentCode = cmInstance.getValue()))
}
cmInstance.focus()
cmInstance.setValue(code || "")
}
}
const cancel = () => {
UIkit.modal(codeModal).hide()
currentCode = originalCode
}
const save = () => {
originalCode = currentCode
onCodeChanged(currentCode)
UIkit.modal(codeModal).hide()
}
</script>
<div bind:this={codeModal} uk-modal>
<div class="uk-modal-dialog" uk-overflow-auto>
<div class="uk-modal-dialog" uk-overflow-auto>
<div class="uk-modal-header">
<h3>Code</h3>
</div>
<div class="uk-modal-body uk-form-horizontal" >
<p>Use the code box below to control how this component is displayed, with javascript.</p>
<div>
<div class="editor-code-surround">function(render, context, store) {"{"}</div>
<div class="editor">
<textarea bind:this={editor}></textarea>
</div>
<div class="editor-code-surround">
{"}"}
</div>
</div>
</div>
<ButtonGroup style="float: right;">
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={cancel}>Close</Button>
</ButtonGroup>
<div class="uk-modal-header">
<h3>Code</h3>
</div>
<div class="uk-modal-body uk-form-horizontal">
<p>
Use the code box below to control how this component is displayed, with
javascript.
</p>
<div>
<div class="editor-code-surround">
function(render, context, store) {'{'}
</div>
<div class="editor">
<textarea bind:this={editor} />
</div>
<div class="editor-code-surround">{'}'}</div>
</div>
</div>
<ButtonGroup style="float: right;">
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={cancel}>Close</Button>
</ButtonGroup>
</div>
</div>
<style>
@ -105,5 +106,4 @@ const save = () => {
.editor-code-surround {
font-family: "Courier New", Courier, monospace;
}
</style>

View File

@ -1,119 +1,129 @@
<script>
import PropsView from "./PropsView.svelte";
import { store } from "../builderStore";
import IconButton from "../common/IconButton.svelte";
import { LayoutIcon, PaintIcon, TerminalIcon, CircleIndicator, EventsIcon } from '../common/Icons/';
import CodeEditor from './CodeEditor.svelte';
import LayoutEditor from './LayoutEditor.svelte';
import EventsEditor from "./EventsEditor";
import PropsView from "./PropsView.svelte"
import { store } from "../builderStore"
import IconButton from "../common/IconButton.svelte"
import {
LayoutIcon,
PaintIcon,
TerminalIcon,
CircleIndicator,
EventsIcon,
} from "../common/Icons/"
import CodeEditor from "./CodeEditor.svelte"
import LayoutEditor from "./LayoutEditor.svelte"
import EventsEditor from "./EventsEditor"
let current_view = 'props';
let codeEditor;
let current_view = "props"
let codeEditor
$: component = $store.currentComponentInfo;
$: originalName = component.name;
$: name = component.name;
$: description = component.description;
$: componentInfo = $store.currentComponentInfo;
$: components = $store.components;
const onPropChanged = store.setComponentProp;
const onStyleChanged = store.setComponentStyle;
$: component = $store.currentComponentInfo
$: originalName = component.name
$: name = component.name
$: description = component.description
$: componentInfo = $store.currentComponentInfo
$: components = $store.components
const onPropChanged = store.setComponentProp
const onStyleChanged = store.setComponentStyle
</script>
<div class="root">
<ul>
<li>
<button class:selected={current_view === 'props'} on:click={() => current_view = 'props'}>
<PaintIcon />
</button>
</li>
<li>
<button class:selected={current_view === 'layout'} on:click={() => current_view = 'layout'}>
<LayoutIcon />
</button>
</li>
<li>
<button class:selected={current_view === 'code'} on:click={() => codeEditor && codeEditor.show()}>
{#if componentInfo._code && componentInfo._code.trim().length > 0}
<div class="button-indicator">
<CircleIndicator />
</div>
{/if}
<TerminalIcon />
</button>
</li>
<li>
<button class:selected={current_view === 'events'} on:click={() => current_view = 'events'}>
<EventsIcon />
</button>
</li>
</ul>
{#if !componentInfo.component}
<div class="component-props-container">
{#if current_view === 'props'}
<PropsView {componentInfo} {components} {onPropChanged} />
{:else if current_view === 'layout'}
<LayoutEditor {onStyleChanged} {componentInfo}/>
{:else if current_view === 'events'}
<EventsEditor {componentInfo} {components} {onPropChanged} />
<ul>
<li>
<button
class:selected={current_view === 'props'}
on:click={() => (current_view = 'props')}>
<PaintIcon />
</button>
</li>
<li>
<button
class:selected={current_view === 'layout'}
on:click={() => (current_view = 'layout')}>
<LayoutIcon />
</button>
</li>
<li>
<button
class:selected={current_view === 'code'}
on:click={() => codeEditor && codeEditor.show()}>
{#if componentInfo._code && componentInfo._code.trim().length > 0}
<div class="button-indicator">
<CircleIndicator />
</div>
{/if}
<TerminalIcon />
</button>
</li>
<li>
<button
class:selected={current_view === 'events'}
on:click={() => (current_view = 'events')}>
<EventsIcon />
</button>
</li>
</ul>
<CodeEditor
bind:this={codeEditor}
code={$store.currentComponentInfo._code}
onCodeChanged={store.setComponentCode} />
{#if !componentInfo.component}
<div class="component-props-container">
</div>
{:else}
<h1> This is a screen, this will be dealt with later</h1>
{/if}
{#if current_view === 'props'}
<PropsView {componentInfo} {components} {onPropChanged} />
{:else if current_view === 'layout'}
<LayoutEditor {onStyleChanged} {componentInfo} />
{:else if current_view === 'events'}
<EventsEditor {componentInfo} {components} {onPropChanged} />
{/if}
<CodeEditor
bind:this={codeEditor}
code={$store.currentComponentInfo._code}
onCodeChanged={store.setComponentCode} />
</div>
{:else}
<h1>This is a screen, this will be dealt with later</h1>
{/if}
</div>
<style>
.root {
.root {
height: 100%;
display: flex;
flex-direction: column;
}
}
.title > div:nth-child(1) {
.title > div:nth-child(1) {
grid-column-start: name;
color: var(--secondary100);
}
}
.title > div:nth-child(2) {
.title > div:nth-child(2) {
grid-column-start: actions;
}
}
.component-props-container {
margin-top: 10px;
.component-props-container {
margin-top: 10px;
flex: 1 1 auto;
overflow-y: auto;
}
}
ul {
ul {
list-style: none;
display: flex;
padding: 0;
}
}
li {
li {
margin-right: 20px;
background: none;
border-radius: 5px;
width: 48px;
height: 48px;
}
}
li button {
li button {
width: 100%;
height: 100%;
background: none;
@ -123,18 +133,17 @@ li button {
outline: none;
cursor: pointer;
position: relative;
}
}
.selected {
.selected {
color: var(--button-text);
background: var(--background-button)!important;
}
background: var(--background-button) !important;
}
.button-indicator {
.button-indicator {
position: absolute;
top: 8px;
right: 10px;
color: var(--button-text);
}
}
</style>

View File

@ -1,149 +0,0 @@
<script>
import PropsView from "./PropsView.svelte";
import { store } from "../builderStore";
import IconButton from "../common/IconButton.svelte";
<<<<<<< HEAD
import { LayoutIcon, PaintIcon, TerminalIcon, CircleIndicator } from '../common/Icons/';
=======
import { LayoutIcon, PaintIcon, TerminalIcon, EventsIcon } from '../common/Icons/';
>>>>>>> master
import CodeEditor from './CodeEditor.svelte';
import LayoutEditor from './LayoutEditor.svelte';
import EventsEditor from "./EventsEditor";
let current_view = 'props';
let codeEditor;
$: component = $store.currentComponentInfo;
$: originalName = component.name;
$: name = component.name;
$: description = component.description;
$: componentInfo = $store.currentComponentInfo;
$: components = $store.components;
const onPropChanged = store.setComponentProp;
const onStyleChanged = store.setComponentStyle;
</script>
<div class="root">
<ul>
<li>
<button class:selected={current_view === 'props'} on:click={() => current_view = 'props'}>
<PaintIcon />
</button>
</li>
<li>
<button class:selected={current_view === 'layout'} on:click={() => current_view = 'layout'}>
<LayoutIcon />
</button>
</li>
<li>
<button class:selected={current_view === 'code'} on:click={() => codeEditor && codeEditor.show()}>
{#if componentInfo._code && componentInfo._code.trim().length > 0}
<div class="button-indicator">
<CircleIndicator />
</div>
{/if}
<TerminalIcon />
</button>
</li>
<li>
<button class:selected={current_view === 'events'} on:click={() => current_view = 'events'}>
<EventsIcon />
</button>
</li>
</ul>
{#if !componentInfo.component}
<div class="component-props-container">
{#if current_view === 'props'}
<PropsView {componentInfo} {components} {onPropChanged} />
{:else if current_view === 'layout'}
<LayoutEditor {onStyleChanged} {componentInfo}/>
<<<<<<< HEAD
=======
{:else if current_view === 'events'}
<EventsEditor {componentInfo} {components} {onPropChanged} />
{:else}
<CodeEditor />
>>>>>>> master
{/if}
<CodeEditor
bind:this={codeEditor}
code={$store.currentComponentInfo._code}
onCodeChanged={store.setComponentCode} />
</div>
{:else}
<h1> This is a screen, this will be dealt with later</h1>
{/if}
</div>
<style>
.root {
height: 100%;
display: flex;
flex-direction: column;
}
.title > div:nth-child(1) {
grid-column-start: name;
color: var(--secondary100);
}
.title > div:nth-child(2) {
grid-column-start: actions;
}
.component-props-container {
margin-top: 10px;
flex: 1 1 auto;
overflow-y: auto;
}
ul {
list-style: none;
display: flex;
padding: 0;
}
li {
margin-right: 20px;
background: none;
border-radius: 5px;
width: 48px;
height: 48px;
}
li button {
width: 100%;
height: 100%;
background: none;
border: none;
border-radius: 5px;
padding: 12px;
outline: none;
cursor: pointer;
position: relative;
}
.selected {
color: var(--button-text);
background: var(--background-button)!important;
}
.button-indicator {
position: absolute;
top: 6px;
right: 10px;
color: var(--button-text);
}
</style>

View File

@ -1,64 +1,59 @@
<script>
import { searchAllComponents } from "./pagesParsing/searchComponents"
import { store } from "../builderStore"
import { searchAllComponents } from "./pagesParsing/searchComponents";
import { store } from "../builderStore";
export let onComponentChosen = () => {}
export let onComponentChosen = () => {};
let phrase = ""
let phrase = "";
components = $store.components
components = $store.components;
$: filteredComponents =
!phrase
? []
: searchAllComponents(components, phrase);
$: filteredComponents = !phrase ? [] : searchAllComponents(components, phrase)
</script>
<div class="root">
<form class="uk-search uk-search-large">
<span uk-search-icon></span>
<input class="uk-search-input"
type="search"
placeholder="Based on component..."
bind:value={phrase}>
</form>
<form class="uk-search uk-search-large">
<span uk-search-icon />
<input
class="uk-search-input"
type="search"
placeholder="Based on component..."
bind:value={phrase} />
</form>
<div>
{#each filteredComponents as component}
<div class="component" on:click={() => onComponentChosen(component)}>
<div class="title">{component.name}</div>
<div class="description">{component.description}</div>
</div>
{/each}
</div>
<div>
{#each filteredComponents as component}
<div class="component" on:click={() => onComponentChosen(component)}>
<div class="title">{component.name}</div>
<div class="description">{component.description}</div>
</div>
{/each}
</div>
</div>
<style>
.component {
padding:5px;
.component {
padding: 5px;
border-style: solid;
border-width: 0 0 1px 0;
border-color: var(--lightslate);
cursor: pointer;
}
}
.component:hover {
.component:hover {
background-color: var(--primary10);
}
}
.component > .title {
.component > .title {
font-size: 13pt;
color: var(--secondary100);
}
}
.component > .description {
.component > .description {
font-size: 10pt;
color: var(--primary75);
font-style: italic;
}
}
</style>

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