Merge pull request #80 from shogunpurple/housekeeping
running prettier over codebase, removing merge files
|
@ -2,7 +2,8 @@
|
|||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"jest": true
|
||||
"jest": true,
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2019,
|
||||
|
|
|
@ -3,5 +3,6 @@
|
|||
"semi": false,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"plugins": ["prettier-plugin-svelte"]
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"svelteSortOrder" : "scripts-markup-styles"
|
||||
}
|
|
@ -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}\""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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: {},
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
],
|
||||
}
|
||||
|
|
|
@ -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()],
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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"))
|
||||
}
|
||||
})()
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
export const emptyProps = () => ({_component:""});
|
||||
export const emptyProps = () => ({ _component: "" })
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
@ -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",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
|
|
@ -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("/")
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
},
|
||||
})
|
||||
|
|
|
@ -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",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
],
|
||||
],
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
})
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
},
|
||||
`;
|
||||
`
|
||||
|
|
|
@ -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: [] },
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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)}`
|
||||
|
|
|
@ -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])
|
||||
: "({});";
|
||||
}
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -16,4 +16,4 @@
|
|||
svg:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
Before (image error) Size: 446 B After (image error) Size: 447 B |
|
@ -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 |
|
@ -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"
|
||||
|
|
|
@ -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
|
|
@ -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 />
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"),
|
||||
})
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|