Merge branch 'master' of https://github.com/Budibase/budibase
This commit is contained in:
commit
02b512ffd9
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -75,4 +75,4 @@ typings/
|
||||||
.vuepress/dist
|
.vuepress/dist
|
||||||
|
|
||||||
# Serverless directories
|
# Serverless directories
|
||||||
.serverless
|
.serverless
|
||||||
|
|
File diff suppressed because one or more lines are too long
8
packages/builder/.vscode/settings.json
vendored
Normal file
8
packages/builder/.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"javascript.format.enable": false,
|
||||||
|
"svelte.plugin.svelte.format.enable": false,
|
||||||
|
"html.format.enable": false,
|
||||||
|
"json.format.enable": false,
|
||||||
|
"editor.trimAutoWhitespace": false,
|
||||||
|
"sass.format.deleteWhitespace": false
|
||||||
|
}
|
|
@ -11,9 +11,10 @@ import { fade } from "svelte/transition";
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
|
||||||
<div class="top-nav">
|
<div class="top-nav">
|
||||||
<IconButton icon="home"
|
<button class="home-logo"><img src="/assets/budibase-logo-only.png"/></button>
|
||||||
|
<!-- <IconButton icon="home"
|
||||||
color="var(--slate)"
|
color="var(--slate)"
|
||||||
hoverColor="var(--secondary75)"/>
|
hoverColor="var(--secondary75)"/> -->
|
||||||
<span class:active={$store.isBackend}
|
<span class:active={$store.isBackend}
|
||||||
class="topnavitem"
|
class="topnavitem"
|
||||||
on:click={store.showBackend}>
|
on:click={store.showBackend}>
|
||||||
|
@ -37,7 +38,7 @@ import { fade } from "svelte/transition";
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -47,14 +48,18 @@ import { fade } from "svelte/transition";
|
||||||
width:100%;
|
width:100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-nav {
|
.top-nav {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
height: 25px;
|
height: 48px;
|
||||||
background: white;
|
background: white;
|
||||||
padding: 5px;
|
padding: 0px 15px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
@ -66,14 +71,20 @@ import { fade } from "svelte/transition";
|
||||||
.content > div {
|
.content > div {
|
||||||
height:100%;
|
height:100%;
|
||||||
width:100%;
|
width:100%;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.topnavitem {
|
.topnavitem {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--secondary50);
|
color: var(--secondary50);
|
||||||
padding: 0px 15px;
|
margin: 0px 15px;
|
||||||
|
padding-top: 4px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: .9rem;
|
font-size: 1rem;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topnavitem:hover {
|
.topnavitem:hover {
|
||||||
|
@ -84,8 +95,31 @@ import { fade } from "svelte/transition";
|
||||||
|
|
||||||
.active {
|
.active {
|
||||||
color: var(--primary100);
|
color: var(--primary100);
|
||||||
font-weight: 900;
|
font-weight: 600;
|
||||||
|
border-bottom: 2px solid var(--primary100);
|
||||||
|
border-top: 2px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-logo {
|
||||||
|
border-style: none;
|
||||||
|
background-color: rgba(0,0,0,0);
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
height: 40px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-logo:hover {
|
||||||
|
color: var(--hovercolor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-logo:active {
|
||||||
|
outline:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
.home-logo img {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import {
|
import {
|
||||||
hierarchy as hierarchyFunctions,
|
hierarchy as hierarchyFunctions,
|
||||||
} from "../../../core/src";
|
} from "../../../core/src";
|
||||||
import {
|
import {
|
||||||
filter, cloneDeep, sortBy,
|
filter, cloneDeep, sortBy,
|
||||||
map, last, keys, concat, keyBy,
|
map, last, keys, concat, keyBy,
|
||||||
find, isEmpty, reduce, values
|
find, isEmpty, reduce, values
|
||||||
} from "lodash/fp";
|
} from "lodash/fp";
|
||||||
|
@ -10,16 +10,16 @@ import {
|
||||||
pipe, getNode, validate,
|
pipe, getNode, validate,
|
||||||
constructHierarchy, templateApi
|
constructHierarchy, templateApi
|
||||||
} from "../common/core";
|
} from "../common/core";
|
||||||
import {writable} from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
import { defaultPagesObject } from "../userInterface/pagesParsing/defaultPagesObject"
|
import { defaultPagesObject } from "../userInterface/pagesParsing/defaultPagesObject"
|
||||||
import { buildPropsHierarchy } from "../userInterface/pagesParsing/buildPropsHierarchy"
|
import { buildPropsHierarchy } from "../userInterface/pagesParsing/buildPropsHierarchy"
|
||||||
import api from "./api";
|
import api from "./api";
|
||||||
import { isRootComponent, getExactComponent } from "../userInterface/pagesParsing/searchComponents";
|
import { isRootComponent, getExactComponent } from "../userInterface/pagesParsing/searchComponents";
|
||||||
import { rename } from "../userInterface/pagesParsing/renameScreen";
|
import { rename } from "../userInterface/pagesParsing/renameScreen";
|
||||||
import {
|
import {
|
||||||
getNewComponentInfo, getScreenInfo
|
getNewComponentInfo, getScreenInfo, getComponentInfo
|
||||||
} from "../userInterface/pagesParsing/createProps";
|
} from "../userInterface/pagesParsing/createProps";
|
||||||
import {
|
import {
|
||||||
loadLibs, loadLibUrls, loadGeneratorLibs
|
loadLibs, loadLibUrls, loadGeneratorLibs
|
||||||
} from "./loadComponentLibraries";
|
} from "./loadComponentLibraries";
|
||||||
|
|
||||||
|
@ -28,30 +28,30 @@ let appname = "";
|
||||||
export const getStore = () => {
|
export const getStore = () => {
|
||||||
|
|
||||||
const initial = {
|
const initial = {
|
||||||
apps:[],
|
apps: [],
|
||||||
appname:"",
|
appname: "",
|
||||||
hierarchy: {},
|
hierarchy: {},
|
||||||
actions: [],
|
actions: [],
|
||||||
triggers: [],
|
triggers: [],
|
||||||
pages:defaultPagesObject(),
|
pages: defaultPagesObject(),
|
||||||
mainUi:{},
|
mainUi: {},
|
||||||
unauthenticatedUi:{},
|
unauthenticatedUi: {},
|
||||||
components:[],
|
components: [],
|
||||||
currentFrontEndItem:null,
|
currentFrontEndItem: null,
|
||||||
currentComponentInfo:null,
|
currentComponentInfo: null,
|
||||||
currentFrontEndType:"none",
|
currentFrontEndType: "none",
|
||||||
currentPageName: "",
|
currentPageName: "",
|
||||||
currentComponentProps:null,
|
currentComponentProps: null,
|
||||||
currentNodeIsNew: false,
|
currentNodeIsNew: false,
|
||||||
errors: [],
|
errors: [],
|
||||||
activeNav: "database",
|
activeNav: "database",
|
||||||
isBackend:true,
|
isBackend: true,
|
||||||
hasAppPackage: false,
|
hasAppPackage: false,
|
||||||
accessLevels: {version:0, levels:[]},
|
accessLevels: { version: 0, levels: [] },
|
||||||
currentNode: null,
|
currentNode: null,
|
||||||
libraries:null,
|
libraries: null,
|
||||||
showSettings:false,
|
showSettings: false,
|
||||||
useAnalytics:true,
|
useAnalytics: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const store = writable(initial);
|
const store = writable(initial);
|
||||||
|
@ -82,7 +82,7 @@ export const getStore = () => {
|
||||||
store.setCurrentScreen = setCurrentScreen(store);
|
store.setCurrentScreen = setCurrentScreen(store);
|
||||||
store.setCurrentPage = setCurrentPage(store);
|
store.setCurrentPage = setCurrentPage(store);
|
||||||
store.createScreen = createScreen(store);
|
store.createScreen = createScreen(store);
|
||||||
store.removeComponentLibrary =removeComponentLibrary(store);
|
store.removeComponentLibrary = removeComponentLibrary(store);
|
||||||
store.addStylesheet = addStylesheet(store);
|
store.addStylesheet = addStylesheet(store);
|
||||||
store.removeStylesheet = removeStylesheet(store);
|
store.removeStylesheet = removeStylesheet(store);
|
||||||
store.savePage = savePage(store);
|
store.savePage = savePage(store);
|
||||||
|
@ -91,18 +91,22 @@ export const getStore = () => {
|
||||||
store.showSettings = showSettings(store);
|
store.showSettings = showSettings(store);
|
||||||
store.useAnalytics = useAnalytics(store);
|
store.useAnalytics = useAnalytics(store);
|
||||||
store.createGeneratedComponents = createGeneratedComponents(store);
|
store.createGeneratedComponents = createGeneratedComponents(store);
|
||||||
|
store.addChildComponent = addChildComponent(store);
|
||||||
|
store.selectComponent = selectComponent(store);
|
||||||
|
store.updateComponentProp = updateComponentProp(store);
|
||||||
|
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default getStore;
|
export default getStore;
|
||||||
|
|
||||||
const initialise = (store, initial) => async () => {
|
const initialise = (store, initial) => async () => {
|
||||||
|
|
||||||
appname = window.location.hash
|
appname = window.location.hash
|
||||||
? last(window.location.hash.substr(1).split("/"))
|
? last(window.location.hash.substr(1).split("/"))
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
if(!appname) {
|
if (!appname) {
|
||||||
initial.apps = await api.get(`/_builder/api/apps`).then(r => r.json());
|
initial.apps = await api.get(`/_builder/api/apps`).then(r => r.json());
|
||||||
initial.hasAppPackage = false;
|
initial.hasAppPackage = false;
|
||||||
store.set(initial);
|
store.set(initial);
|
||||||
|
@ -110,7 +114,7 @@ const initialise = (store, initial) => async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const pkg = await api.get(`/_builder/api/${appname}/appPackage`)
|
const pkg = await api.get(`/_builder/api/${appname}/appPackage`)
|
||||||
.then(r => r.json());
|
.then(r => r.json());
|
||||||
|
|
||||||
initial.libraries = await loadLibs(appname, pkg);
|
initial.libraries = await loadLibs(appname, pkg);
|
||||||
initial.generatorLibraries = await loadGeneratorLibs(appname, pkg);
|
initial.generatorLibraries = await loadGeneratorLibs(appname, pkg);
|
||||||
|
@ -126,19 +130,20 @@ const initialise = (store, initial) => async () => {
|
||||||
initial.actions = values(pkg.appDefinition.actions);
|
initial.actions = values(pkg.appDefinition.actions);
|
||||||
initial.triggers = pkg.appDefinition.triggers;
|
initial.triggers = pkg.appDefinition.triggers;
|
||||||
|
|
||||||
if(!!initial.hierarchy && !isEmpty(initial.hierarchy)) {
|
if (!!initial.hierarchy && !isEmpty(initial.hierarchy)) {
|
||||||
initial.hierarchy = constructHierarchy(initial.hierarchy);
|
initial.hierarchy = constructHierarchy(initial.hierarchy);
|
||||||
const shadowHierarchy = createShadowHierarchy(initial.hierarchy);
|
const shadowHierarchy = createShadowHierarchy(initial.hierarchy);
|
||||||
if(initial.currentNode !== null)
|
if (initial.currentNode !== null)
|
||||||
initial.currentNode = getNode(
|
initial.currentNode = getNode(
|
||||||
shadowHierarchy, initial.currentNode.nodeId
|
shadowHierarchy, initial.currentNode.nodeId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
store.set(initial);
|
store.set(initial);
|
||||||
return initial;
|
return initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
const generatorsArray = generators =>
|
const generatorsArray = generators =>
|
||||||
pipe(generators, [
|
pipe(generators, [
|
||||||
keys,
|
keys,
|
||||||
filter(k => k !== "_lib"),
|
filter(k => k !== "_lib"),
|
||||||
|
@ -179,12 +184,12 @@ const newRecord = (store, useRoot) => () => {
|
||||||
s.currentNodeIsNew = true;
|
s.currentNodeIsNew = true;
|
||||||
const shadowHierarchy = createShadowHierarchy(s.hierarchy);
|
const shadowHierarchy = createShadowHierarchy(s.hierarchy);
|
||||||
parent = useRoot ? shadowHierarchy
|
parent = useRoot ? shadowHierarchy
|
||||||
: getNode(
|
: getNode(
|
||||||
shadowHierarchy,
|
shadowHierarchy,
|
||||||
s.currentNode.nodeId);
|
s.currentNode.nodeId);
|
||||||
s.errors = [];
|
s.errors = [];
|
||||||
s.currentNode = templateApi(shadowHierarchy)
|
s.currentNode = templateApi(shadowHierarchy)
|
||||||
.getNewRecordTemplate(parent, "", true);
|
.getNewRecordTemplate(parent, "", true);
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -209,12 +214,12 @@ const newIndex = (store, useRoot) => () => {
|
||||||
s.errors = [];
|
s.errors = [];
|
||||||
const shadowHierarchy = createShadowHierarchy(s.hierarchy);
|
const shadowHierarchy = createShadowHierarchy(s.hierarchy);
|
||||||
parent = useRoot ? shadowHierarchy
|
parent = useRoot ? shadowHierarchy
|
||||||
: getNode(
|
: getNode(
|
||||||
shadowHierarchy,
|
shadowHierarchy,
|
||||||
s.currentNode.nodeId);
|
s.currentNode.nodeId);
|
||||||
|
|
||||||
s.currentNode = templateApi(shadowHierarchy)
|
s.currentNode = templateApi(shadowHierarchy)
|
||||||
.getNewIndexTemplate(parent);
|
.getNewIndexTemplate(parent);
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -224,7 +229,7 @@ const saveCurrentNode = (store) => () => {
|
||||||
|
|
||||||
const errors = validate.node(s.currentNode);
|
const errors = validate.node(s.currentNode);
|
||||||
s.errors = errors;
|
s.errors = errors;
|
||||||
if(errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,23 +240,23 @@ const saveCurrentNode = (store) => () => {
|
||||||
s.hierarchy, s.currentNode.nodeId);
|
s.hierarchy, s.currentNode.nodeId);
|
||||||
|
|
||||||
let index = parentNode.children.length;
|
let index = parentNode.children.length;
|
||||||
if(!!existingNode) {
|
if (!!existingNode) {
|
||||||
// remove existing
|
// remove existing
|
||||||
index = existingNode.parent().children.indexOf(existingNode);
|
index = existingNode.parent().children.indexOf(existingNode);
|
||||||
existingNode.parent().children = pipe(existingNode.parent().children, [
|
existingNode.parent().children = pipe(existingNode.parent().children, [
|
||||||
filter(c => c.nodeId !== existingNode.nodeId)
|
filter(c => c.nodeId !== existingNode.nodeId)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// should add node into existing hierarchy
|
// should add node into existing hierarchy
|
||||||
const cloned = cloneDeep(s.currentNode);
|
const cloned = cloneDeep(s.currentNode);
|
||||||
templateApi(s.hierarchy).constructNode(
|
templateApi(s.hierarchy).constructNode(
|
||||||
parentNode,
|
parentNode,
|
||||||
cloned
|
cloned
|
||||||
);
|
);
|
||||||
|
|
||||||
const newIndexOfchild = child => {
|
const newIndexOfchild = child => {
|
||||||
if(child === cloned) return index;
|
if (child === cloned) return index;
|
||||||
const currentIndex = parentNode.children.indexOf(child);
|
const currentIndex = parentNode.children.indexOf(child);
|
||||||
return currentIndex >= index ? currentIndex + 1 : currentIndex;
|
return currentIndex >= index ? currentIndex + 1 : currentIndex;
|
||||||
}
|
}
|
||||||
|
@ -260,15 +265,15 @@ const saveCurrentNode = (store) => () => {
|
||||||
sortBy(newIndexOfchild)
|
sortBy(newIndexOfchild)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if(!existingNode && s.currentNode.type === "record") {
|
if (!existingNode && s.currentNode.type === "record") {
|
||||||
const defaultIndex = templateApi(s.hierarchy)
|
const defaultIndex = templateApi(s.hierarchy)
|
||||||
.getNewIndexTemplate(cloned.parent());
|
.getNewIndexTemplate(cloned.parent());
|
||||||
defaultIndex.name = `all_${cloned.collectionName}`;
|
defaultIndex.name = `all_${cloned.collectionName}`;
|
||||||
defaultIndex.allowedRecordNodeIds = [cloned.nodeId];
|
defaultIndex.allowedRecordNodeIds = [cloned.nodeId];
|
||||||
}
|
}
|
||||||
|
|
||||||
s.currentNodeIsNew = false;
|
s.currentNodeIsNew = false;
|
||||||
|
|
||||||
savePackage(store, s);
|
savePackage(store, s);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
@ -279,28 +284,28 @@ const importAppDefinition = store => appDefinition => {
|
||||||
store.update(s => {
|
store.update(s => {
|
||||||
s.hierarchy = appDefinition.hierarchy;
|
s.hierarchy = appDefinition.hierarchy;
|
||||||
s.currentNode = appDefinition.hierarchy.children.length > 0
|
s.currentNode = appDefinition.hierarchy.children.length > 0
|
||||||
? appDefinition.hierarchy.children[0]
|
? appDefinition.hierarchy.children[0]
|
||||||
: null;
|
: null;
|
||||||
s.actions = appDefinition.actions;
|
s.actions = appDefinition.actions;
|
||||||
s.triggers = appDefinition.triggers;
|
s.triggers = appDefinition.triggers;
|
||||||
s.currentNodeIsNew = false;
|
s.currentNodeIsNew = false;
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteCurrentNode = store => () => {
|
const deleteCurrentNode = store => () => {
|
||||||
store.update(s => {
|
store.update(s => {
|
||||||
const nodeToDelete = getNode(s.hierarchy, s.currentNode.nodeId);
|
const nodeToDelete = getNode(s.hierarchy, s.currentNode.nodeId);
|
||||||
s.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent())
|
s.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent())
|
||||||
? find(n => n != s.currentNode)
|
? find(n => n != s.currentNode)
|
||||||
(s.hierarchy.children)
|
(s.hierarchy.children)
|
||||||
: nodeToDelete.parent();
|
: nodeToDelete.parent();
|
||||||
if(hierarchyFunctions.isRecord(nodeToDelete)) {
|
if (hierarchyFunctions.isRecord(nodeToDelete)) {
|
||||||
nodeToDelete.parent().children = filter(c => c.nodeId !== nodeToDelete.nodeId)
|
nodeToDelete.parent().children = filter(c => c.nodeId !== nodeToDelete.nodeId)
|
||||||
(nodeToDelete.parent().children);
|
(nodeToDelete.parent().children);
|
||||||
} else {
|
} else {
|
||||||
nodeToDelete.parent().indexes = filter(c => c.nodeId !== nodeToDelete.nodeId)
|
nodeToDelete.parent().indexes = filter(c => c.nodeId !== nodeToDelete.nodeId)
|
||||||
(nodeToDelete.parent().indexes);
|
(nodeToDelete.parent().indexes);
|
||||||
}
|
}
|
||||||
s.errors = [];
|
s.errors = [];
|
||||||
savePackage(store, s);
|
savePackage(store, s);
|
||||||
|
@ -311,8 +316,8 @@ const deleteCurrentNode = store => () => {
|
||||||
const saveField = databaseStore => (field) => {
|
const saveField = databaseStore => (field) => {
|
||||||
databaseStore.update(db => {
|
databaseStore.update(db => {
|
||||||
db.currentNode.fields = filter(f => f.name !== field.name)
|
db.currentNode.fields = filter(f => f.name !== field.name)
|
||||||
(db.currentNode.fields);
|
(db.currentNode.fields);
|
||||||
|
|
||||||
templateApi(db.hierarchy).addField(db.currentNode, field);
|
templateApi(db.hierarchy).addField(db.currentNode, field);
|
||||||
return db;
|
return db;
|
||||||
});
|
});
|
||||||
|
@ -322,21 +327,21 @@ const saveField = databaseStore => (field) => {
|
||||||
const deleteField = databaseStore => field => {
|
const deleteField = databaseStore => field => {
|
||||||
databaseStore.update(db => {
|
databaseStore.update(db => {
|
||||||
db.currentNode.fields = filter(f => f.name !== field.name)
|
db.currentNode.fields = filter(f => f.name !== field.name)
|
||||||
(db.currentNode.fields);
|
(db.currentNode.fields);
|
||||||
|
|
||||||
return db;
|
return db;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const saveAction = store => (newAction, isNew, oldAction=null) => {
|
const saveAction = store => (newAction, isNew, oldAction = null) => {
|
||||||
store.update(s => {
|
store.update(s => {
|
||||||
|
|
||||||
const existingAction = isNew
|
const existingAction = isNew
|
||||||
? null
|
? null
|
||||||
: find(a => a.name === oldAction.name)(s.actions);
|
: find(a => a.name === oldAction.name)(s.actions);
|
||||||
|
|
||||||
if(existingAction) {
|
if (existingAction) {
|
||||||
s.actions = pipe(s.actions, [
|
s.actions = pipe(s.actions, [
|
||||||
map(a => a === existingAction ? newAction : a)
|
map(a => a === existingAction ? newAction : a)
|
||||||
]);
|
]);
|
||||||
|
@ -348,7 +353,7 @@ const saveAction = store => (newAction, isNew, oldAction=null) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteAction = store => action => {
|
const deleteAction = store => action => {
|
||||||
store.update(s => {
|
store.update(s => {
|
||||||
s.actions = filter(a => a.name !== action.name)(s.actions);
|
s.actions = filter(a => a.name !== action.name)(s.actions);
|
||||||
savePackage(store, s);
|
savePackage(store, s);
|
||||||
|
@ -356,14 +361,14 @@ const deleteAction = store => action => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveTrigger = store => (newTrigger, isNew, oldTrigger=null) => {
|
const saveTrigger = store => (newTrigger, isNew, oldTrigger = null) => {
|
||||||
store.update(s => {
|
store.update(s => {
|
||||||
|
|
||||||
const existingTrigger = isNew
|
const existingTrigger = isNew
|
||||||
? null
|
? null
|
||||||
: find(a => a.name === oldTrigger.name)(s.triggers);
|
: find(a => a.name === oldTrigger.name)(s.triggers);
|
||||||
|
|
||||||
if(existingTrigger) {
|
if (existingTrigger) {
|
||||||
s.triggers = pipe(s.triggers, [
|
s.triggers = pipe(s.triggers, [
|
||||||
map(a => a === existingTrigger ? newTrigger : a)
|
map(a => a === existingTrigger ? newTrigger : a)
|
||||||
]);
|
]);
|
||||||
|
@ -375,7 +380,7 @@ const saveTrigger = store => (newTrigger, isNew, oldTrigger=null) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteTrigger = store => trigger => {
|
const deleteTrigger = store => trigger => {
|
||||||
store.update(s => {
|
store.update(s => {
|
||||||
s.triggers = filter(t => t.name !== trigger.name)(s.triggers);
|
s.triggers = filter(t => t.name !== trigger.name)(s.triggers);
|
||||||
return s;
|
return s;
|
||||||
|
@ -383,18 +388,18 @@ const deleteTrigger = store => trigger => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const incrementAccessLevelsVersion = (s) =>
|
const incrementAccessLevelsVersion = (s) =>
|
||||||
s.accessLevels.version = (s.accessLevels.version || 0) + 1;
|
s.accessLevels.version = (s.accessLevels.version || 0) + 1;
|
||||||
|
|
||||||
const saveLevel = store => (newLevel, isNew, oldLevel=null) => {
|
const saveLevel = store => (newLevel, isNew, oldLevel = null) => {
|
||||||
store.update(s => {
|
store.update(s => {
|
||||||
|
|
||||||
const levels = s.accessLevels.levels;
|
const levels = s.accessLevels.levels;
|
||||||
|
|
||||||
const existingLevel = isNew
|
const existingLevel = isNew
|
||||||
? null
|
? null
|
||||||
: find(a => a.name === oldLevel.name)(levels);
|
: find(a => a.name === oldLevel.name)(levels);
|
||||||
|
|
||||||
if(existingLevel) {
|
if (existingLevel) {
|
||||||
s.accessLevels.levels = pipe(levels, [
|
s.accessLevels.levels = pipe(levels, [
|
||||||
map(a => a === existingLevel ? newLevel : a)
|
map(a => a === existingLevel ? newLevel : a)
|
||||||
]);
|
]);
|
||||||
|
@ -425,7 +430,7 @@ const setActiveNav = store => navName => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const createShadowHierarchy = hierarchy =>
|
const createShadowHierarchy = hierarchy =>
|
||||||
constructHierarchy(JSON.parse(JSON.stringify(hierarchy)));
|
constructHierarchy(JSON.parse(JSON.stringify(hierarchy)));
|
||||||
|
|
||||||
const saveScreen = store => (screen) => {
|
const saveScreen = store => (screen) => {
|
||||||
|
@ -448,7 +453,7 @@ const _saveScreen = (store, s, screen) => {
|
||||||
api.post(`/_builder/api/${s.appname}/screen`, screen)
|
api.post(`/_builder/api/${s.appname}/screen`, screen)
|
||||||
.then(() => savePackage(store, s));
|
.then(() => savePackage(store, s));
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createScreen = store => (screenName, layoutComponentName) => {
|
const createScreen = store => (screenName, layoutComponentName) => {
|
||||||
|
@ -470,13 +475,13 @@ const createGeneratedComponents = store => components => {
|
||||||
s.screens = [...s.screens, ...components];
|
s.screens = [...s.screens, ...components];
|
||||||
|
|
||||||
const doCreate = async () => {
|
const doCreate = async () => {
|
||||||
for(let c of components) {
|
for (let c of components) {
|
||||||
await api.post(`/_builder/api/${s.appname}/screen`, c);
|
await api.post(`/_builder/api/${s.appname}/screen`, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
await savePackage(store, s);
|
await savePackage(store, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
doCreate();
|
doCreate();
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
@ -496,7 +501,7 @@ const deleteScreen = store => name => {
|
||||||
|
|
||||||
s.components = components;
|
s.components = components;
|
||||||
s.screens = screens;
|
s.screens = screens;
|
||||||
if(s.currentFrontEndItem.name === name) {
|
if (s.currentFrontEndItem.name === name) {
|
||||||
s.currentFrontEndItem = null;
|
s.currentFrontEndItem = null;
|
||||||
s.currentFrontEndType = "";
|
s.currentFrontEndType = "";
|
||||||
}
|
}
|
||||||
|
@ -514,20 +519,20 @@ const renameScreen = store => (oldname, newname) => {
|
||||||
screens, pages, error, changedScreens
|
screens, pages, error, changedScreens
|
||||||
} = rename(s.pages, s.screens, oldname, newname);
|
} = rename(s.pages, s.screens, oldname, newname);
|
||||||
|
|
||||||
if(error) {
|
if (error) {
|
||||||
// should really do something with this
|
// should really do something with this
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
s.screens = screens;
|
s.screens = screens;
|
||||||
s.pages = pages;
|
s.pages = pages;
|
||||||
if(s.currentFrontEndItem.name === oldname)
|
if (s.currentFrontEndItem.name === oldname)
|
||||||
s.currentFrontEndItem.name = newname;
|
s.currentFrontEndItem.name = newname;
|
||||||
|
|
||||||
const saveAllChanged = async () => {
|
const saveAllChanged = async () => {
|
||||||
for(let screenName of changedScreens) {
|
for (let screenName of changedScreens) {
|
||||||
const changedScreen
|
const changedScreen
|
||||||
= getExactComponent(screens, screenName);
|
= getExactComponent(screens, screenName);
|
||||||
await api.post(`/_builder/api/${s.appname}/screen`, changedScreen);
|
await api.post(`/_builder/api/${s.appname}/screen`, changedScreen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -535,10 +540,10 @@ const renameScreen = store => (oldname, newname) => {
|
||||||
api.patch(`/_builder/api/${s.appname}/screen`, {
|
api.patch(`/_builder/api/${s.appname}/screen`, {
|
||||||
oldname, newname
|
oldname, newname
|
||||||
})
|
})
|
||||||
.then(() => saveAllChanged())
|
.then(() => saveAllChanged())
|
||||||
.then(() => {
|
.then(() => {
|
||||||
savePackage(store, s);
|
savePackage(store, s);
|
||||||
});
|
});
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
})
|
})
|
||||||
|
@ -546,7 +551,7 @@ const renameScreen = store => (oldname, newname) => {
|
||||||
|
|
||||||
const savePage = store => async page => {
|
const savePage = store => async page => {
|
||||||
store.update(s => {
|
store.update(s => {
|
||||||
if(s.currentFrontEndType !== "page" || !s.currentPageName) {
|
if (s.currentFrontEndType !== "page" || !s.currentPageName) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,26 +563,26 @@ const savePage = store => async page => {
|
||||||
|
|
||||||
const addComponentLibrary = store => async lib => {
|
const addComponentLibrary = store => async lib => {
|
||||||
|
|
||||||
const response =
|
const response =
|
||||||
await api.get(`/_builder/api/${appname}/componentlibrary?lib=${encodeURI(lib)}`,undefined, false);
|
await api.get(`/_builder/api/${appname}/componentlibrary?lib=${encodeURI(lib)}`, undefined, false);
|
||||||
|
|
||||||
const success = response.status === 200;
|
const success = response.status === 200;
|
||||||
|
|
||||||
const error = response.status === 404
|
const error = response.status === 404
|
||||||
? `Could not find library ${lib}`
|
? `Could not find library ${lib}`
|
||||||
: success
|
: success
|
||||||
? ""
|
? ""
|
||||||
: response.statusText;
|
: response.statusText;
|
||||||
|
|
||||||
const components = success
|
const components = success
|
||||||
? await response.json()
|
? await response.json()
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
store.update(s => {
|
store.update(s => {
|
||||||
if(success) {
|
if (success) {
|
||||||
|
|
||||||
const componentsArray = [];
|
const componentsArray = [];
|
||||||
for(let c in components) {
|
for (let c in components) {
|
||||||
componentsArray.push(components[c]);
|
componentsArray.push(components[c]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,18 +597,18 @@ const addComponentLibrary = store => async lib => {
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeComponentLibrary = store => lib => {
|
const removeComponentLibrary = store => lib => {
|
||||||
store.update(s => {
|
store.update(s => {
|
||||||
|
|
||||||
|
|
||||||
s.pages.componentLibraries = filter(l => l !== lib)(
|
s.pages.componentLibraries = filter(l => l !== lib)(
|
||||||
s.pages.componentLibraries);
|
s.pages.componentLibraries);
|
||||||
savePackage(store, s);
|
savePackage(store, s);
|
||||||
|
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
})
|
})
|
||||||
|
@ -627,12 +632,12 @@ const removeStylesheet = store => stylesheet => {
|
||||||
|
|
||||||
const refreshComponents = store => async () => {
|
const refreshComponents = store => async () => {
|
||||||
|
|
||||||
const componentsAndGenerators =
|
const componentsAndGenerators =
|
||||||
await api.get(`/_builder/api/${db.appname}/components`).then(r => r.json());
|
await api.get(`/_builder/api/${db.appname}/components`).then(r => r.json());
|
||||||
|
|
||||||
const components = pipe(componentsAndGenerators.components, [
|
const components = pipe(componentsAndGenerators.components, [
|
||||||
keys,
|
keys,
|
||||||
map(k => ({...componentsAndGenerators[k], name:k}))
|
map(k => ({ ...componentsAndGenerators[k], name: k }))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
store.update(s => {
|
store.update(s => {
|
||||||
|
@ -648,25 +653,25 @@ const refreshComponents = store => async () => {
|
||||||
const savePackage = (store, s) => {
|
const savePackage = (store, s) => {
|
||||||
|
|
||||||
const appDefinition = {
|
const appDefinition = {
|
||||||
hierarchy:s.hierarchy,
|
hierarchy: s.hierarchy,
|
||||||
triggers:s.triggers,
|
triggers: s.triggers,
|
||||||
actions: keyBy("name")(s.actions),
|
actions: keyBy("name")(s.actions),
|
||||||
props: {
|
props: {
|
||||||
main: buildPropsHierarchy(
|
main: buildPropsHierarchy(
|
||||||
s.components,
|
s.components,
|
||||||
s.screens,
|
s.screens,
|
||||||
s.pages.main.appBody),
|
s.pages.main.appBody),
|
||||||
unauthenticated: buildPropsHierarchy(
|
unauthenticated: buildPropsHierarchy(
|
||||||
s.components,
|
s.components,
|
||||||
s.screens,
|
s.screens,
|
||||||
s.pages.unauthenticated.appBody)
|
s.pages.unauthenticated.appBody)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
appDefinition,
|
appDefinition,
|
||||||
accessLevels:s.accessLevels,
|
accessLevels: s.accessLevels,
|
||||||
pages:s.pages,
|
pages: s.pages,
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.post(`/_builder/api/${s.appname}/appPackage`, data);
|
return api.post(`/_builder/api/${s.appname}/appPackage`, data);
|
||||||
|
@ -689,3 +694,44 @@ const setCurrentPage = store => pageName => {
|
||||||
return s;
|
return s;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const addChildComponent = store => component => {
|
||||||
|
|
||||||
|
store.update(s => {
|
||||||
|
const newComponent = getNewComponentInfo(
|
||||||
|
s.components, component);
|
||||||
|
|
||||||
|
const children = s.currentFrontEndItem.props._children;
|
||||||
|
|
||||||
|
const component_definition = Object.assign(
|
||||||
|
cloneDeep(newComponent.fullProps), {
|
||||||
|
_component: component,
|
||||||
|
})
|
||||||
|
|
||||||
|
s.currentFrontEndItem.props._children =
|
||||||
|
children ?
|
||||||
|
children.concat(component_definition) :
|
||||||
|
[component_definition];
|
||||||
|
|
||||||
|
return s;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectComponent = store => component => {
|
||||||
|
store.update(s => {
|
||||||
|
s.currentComponentInfo = component;
|
||||||
|
return s;
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateComponentProp = 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;
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
4
packages/builder/src/common/Icons/Image.svelte
Normal file
4
packages/builder/src/common/Icons/Image.svelte
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<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>
|
After Width: | Height: | Size: 400 B |
4
packages/builder/src/common/Icons/Input.svelte
Normal file
4
packages/builder/src/common/Icons/Input.svelte
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<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>
|
After Width: | Height: | Size: 339 B |
3
packages/builder/src/common/Icons/Layout.svelte
Normal file
3
packages/builder/src/common/Icons/Layout.svelte
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<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>
|
After Width: | Height: | Size: 280 B |
3
packages/builder/src/common/Icons/Paint.svelte
Normal file
3
packages/builder/src/common/Icons/Paint.svelte
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<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>
|
After Width: | Height: | Size: 415 B |
4
packages/builder/src/common/Icons/Terminal.svelte
Normal file
4
packages/builder/src/common/Icons/Terminal.svelte
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<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>
|
After Width: | Height: | Size: 346 B |
5
packages/builder/src/common/Icons/index.js
Normal file
5
packages/builder/src/common/Icons/index.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
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';
|
54
packages/builder/src/common/Inputs/InputGroup.svelte
Normal file
54
packages/builder/src/common/Inputs/InputGroup.svelte
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<script>
|
||||||
|
export let meta = [];
|
||||||
|
export let size = '';
|
||||||
|
export let values = [];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="inputs {size}">
|
||||||
|
{#each meta as { placeholder }, i}
|
||||||
|
<input type="number" placeholder="{placeholder}" bind:value={values[i]}/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.inputs {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 83px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #163057;
|
||||||
|
opacity: 0.7;
|
||||||
|
padding: 5px 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #DBDBDB;
|
||||||
|
border-radius: 2px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
height: 38px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small > input::placeholder {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,29 +1,29 @@
|
||||||
:root {
|
:root {
|
||||||
--primary100: #454CA0FF;
|
--primary100: #173157FF;
|
||||||
--primary75: #454CA0BF;
|
--primary75: #454CA0BF;
|
||||||
--primary50: #454CA080;
|
--primary50: #454CA080;
|
||||||
--primary25: #454CA040;
|
--primary25: #454CA040;
|
||||||
--primary10: #454CA01A;
|
--primary10: #454CA01A;
|
||||||
--primary5: #454ca00c;
|
--primary5: #454ca00c;
|
||||||
--primarydark: #3F448A;
|
--primarydark: #3F448A;
|
||||||
|
|
||||||
--secondary100: #162B4DFF;
|
--secondary100:#828fa5;
|
||||||
--secondary75: #162B4DBF;
|
--secondary75: #162B4DBF;
|
||||||
--secondary50: #162B4D80;
|
--secondary50: #162B4D80;
|
||||||
--secondary25: #162B4D40;
|
--secondary25: #162B4D40;
|
||||||
--secondary10: #162B4D1A;
|
--secondary10: #162B4D1A;
|
||||||
--secondary5: rgba(22, 43, 77, 0.068);
|
--secondary5:#fff;
|
||||||
--secondarydark: #3F448A;
|
--secondarydark: #3F448A;
|
||||||
|
|
||||||
--tertiary: #F2F5F7;
|
--tertiary: #F2F5F7;
|
||||||
|
|
||||||
--success100: #49C39EFF;
|
--success100: #49C39EFF;
|
||||||
--success75: #49C39EBF;
|
--success75: #49C39EBF;
|
||||||
--success50: #49C39E80;
|
--success50: #49C39E80;
|
||||||
--success25: #49C39E40;
|
--success25: #49C39E40;
|
||||||
--success10: #49C39E1A;
|
--success10: #49C39E1A;
|
||||||
--successdark: #44B492;
|
--successdark: #44B492;
|
||||||
|
|
||||||
--deletion100: #F2545BFF;
|
--deletion100: #F2545BFF;
|
||||||
--deletion75: #F2545BBF;
|
--deletion75: #F2545BBF;
|
||||||
--deletion50: #F2545B80;
|
--deletion50: #F2545B80;
|
||||||
|
@ -52,6 +52,9 @@
|
||||||
--heavybodytext: var(--fontbold) "regular" var(--secondary100) 16pt;
|
--heavybodytext: var(--fontbold) "regular" var(--secondary100) 16pt;
|
||||||
--quotation: var(--fontnormal) "italics" var(--darkslate) 16pt;
|
--quotation: var(--fontnormal) "italics" var(--darkslate) 16pt;
|
||||||
--smallheavybodytext: var(--fontbold) "regular" var(--secondary100) 14pt;
|
--smallheavybodytext: var(--fontbold) "regular" var(--secondary100) 14pt;
|
||||||
|
|
||||||
|
--background-button: #e6eeff;
|
||||||
|
--button-text: #0055ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
|
@ -97,4 +100,4 @@ h5 {
|
||||||
font-family: var(--fontblack);
|
font-family: var(--fontblack);
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
color: var(--darkslate);
|
color: var(--darkslate);
|
||||||
}
|
}
|
||||||
|
|
119
packages/builder/src/userInterface/CodeEditor.svelte
Normal file
119
packages/builder/src/userInterface/CodeEditor.svelte
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
<script>
|
||||||
|
let snippets = [];
|
||||||
|
let current_snippet = 0;
|
||||||
|
let snippet_text = ''
|
||||||
|
let id = 0;
|
||||||
|
|
||||||
|
function save_snippet() {
|
||||||
|
if (!snippet_text) return;
|
||||||
|
|
||||||
|
const index = snippets.findIndex(({ id }) => current_snippet === id);
|
||||||
|
|
||||||
|
if (index > -1) {
|
||||||
|
snippets[index].snippet = snippet_text;
|
||||||
|
} else {
|
||||||
|
snippets = snippets.concat({ snippet: snippet_text , id: id });
|
||||||
|
}
|
||||||
|
snippet_text = '';
|
||||||
|
current_snippet = ++id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function edit_snippet(id) {
|
||||||
|
const { snippet, id: _id } = snippets.find(({ id:_id }) => _id === id);
|
||||||
|
current_snippet = id
|
||||||
|
snippet_text = snippet;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h3>Code</h3>
|
||||||
|
|
||||||
|
<p>Use the code box below to add snippets of javascript to enhance your webapp</p>
|
||||||
|
|
||||||
|
<div class="editor">
|
||||||
|
<textarea class="code" bind:value={snippet_text} />
|
||||||
|
<button on:click={save_snippet}>Save</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="snippets">
|
||||||
|
<h3>Snippets added</h3>
|
||||||
|
{#each snippets as { id, snippet } }
|
||||||
|
<div class="snippet">
|
||||||
|
<pre class="code">{snippet}</pre>
|
||||||
|
<button on:click={() => edit_snippet(id)}>Edit</button>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h3 {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #8997ab;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code {
|
||||||
|
width: 100%;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
background: #173157;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
white-space: pre;
|
||||||
|
color: #eee;
|
||||||
|
padding: 10px;
|
||||||
|
font-family: monospace;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor textarea {
|
||||||
|
resize: none;
|
||||||
|
height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
position: absolute;
|
||||||
|
box-shadow: 0 0 black;
|
||||||
|
color: #eee;
|
||||||
|
right: 5px;
|
||||||
|
bottom: 10px;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: 600;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippets {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet pre {
|
||||||
|
background: #f9f9f9;
|
||||||
|
color: #333;
|
||||||
|
max-height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet button {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
150
packages/builder/src/userInterface/ComponentPanel.svelte
Normal file
150
packages/builder/src/userInterface/ComponentPanel.svelte
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import PropsView from "./PropsView.svelte";
|
||||||
|
import { store } from "../builderStore";
|
||||||
|
import { isRootComponent } from "./pagesParsing/searchComponents";
|
||||||
|
import IconButton from "../common/IconButton.svelte";
|
||||||
|
import Textbox from "../common/Textbox.svelte";
|
||||||
|
import { pipe } from "../common/core";
|
||||||
|
import {
|
||||||
|
getScreenInfo
|
||||||
|
} from "./pagesParsing/createProps";
|
||||||
|
import { LayoutIcon, PaintIcon, TerminalIcon } from '../common/Icons/';
|
||||||
|
import CodeEditor from './CodeEditor.svelte';
|
||||||
|
import LayoutEditor from './LayoutEditor.svelte';
|
||||||
|
|
||||||
|
import {
|
||||||
|
cloneDeep,
|
||||||
|
join,
|
||||||
|
split,
|
||||||
|
map,
|
||||||
|
keys,
|
||||||
|
isUndefined,
|
||||||
|
last
|
||||||
|
} from "lodash/fp";
|
||||||
|
import { assign } from "lodash";
|
||||||
|
|
||||||
|
let component;
|
||||||
|
let name = "";
|
||||||
|
let description = "";
|
||||||
|
let tagsString = "";
|
||||||
|
let nameInvalid = "";
|
||||||
|
let componentInfo = {};
|
||||||
|
let modalElement
|
||||||
|
let propsValidationErrors = [];
|
||||||
|
let originalName="";
|
||||||
|
let components;
|
||||||
|
let ignoreStore = false;
|
||||||
|
|
||||||
|
// $: shortName = last(name.split("/"));
|
||||||
|
|
||||||
|
store.subscribe(s => {
|
||||||
|
if(ignoreStore) return;
|
||||||
|
component = s.currentComponentInfo;
|
||||||
|
if(!component) return;
|
||||||
|
originalName = component.name;
|
||||||
|
name = component.name;
|
||||||
|
description = component.description;
|
||||||
|
tagsString = join(", ")(component.tags);
|
||||||
|
componentInfo = s.currentComponentInfo;
|
||||||
|
components = s.components;
|
||||||
|
});
|
||||||
|
|
||||||
|
const onPropsChanged = store.updateComponentProp;
|
||||||
|
|
||||||
|
let current_view = 'props';
|
||||||
|
</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={() => current_view = 'code'}>
|
||||||
|
<TerminalIcon />
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{#if !componentInfo.component}
|
||||||
|
<div class="component-props-container">
|
||||||
|
|
||||||
|
{#if current_view === 'props'}
|
||||||
|
<PropsView {componentInfo} {components} {onPropsChanged} />
|
||||||
|
{:else if current_view === 'layout'}
|
||||||
|
<LayoutEditor />
|
||||||
|
{:else}
|
||||||
|
<CodeEditor />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
</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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
color: var(--button-text);
|
||||||
|
background: var(--background-button)!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -1,9 +1,10 @@
|
||||||
<script>
|
<script>
|
||||||
|
import ComponentsHierarchyChildren from './ComponentsHierarchyChildren.svelte';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
last,
|
last,
|
||||||
sortBy,
|
sortBy,
|
||||||
filter,
|
filter,
|
||||||
map,
|
map,
|
||||||
uniqWith,
|
uniqWith,
|
||||||
isEqual,
|
isEqual,
|
||||||
|
@ -18,13 +19,6 @@ import getIcon from "../common/icon";
|
||||||
import { store } from "../builderStore";
|
import { store } from "../builderStore";
|
||||||
|
|
||||||
export let components = []
|
export let components = []
|
||||||
export let thisLevel = "";
|
|
||||||
|
|
||||||
let pathPartsThisLevel;
|
|
||||||
let componentsThisLevel;
|
|
||||||
let subfolders;
|
|
||||||
|
|
||||||
let expandedFolders = [];
|
|
||||||
|
|
||||||
const joinPath = join("/");
|
const joinPath = join("/");
|
||||||
|
|
||||||
|
@ -35,39 +29,8 @@ const normalizedName = name => pipe(name, [
|
||||||
trimChars(" ")
|
trimChars(" ")
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const lastPartOfName = (c) =>
|
||||||
const isOnThisLevel = (c) =>
|
last(c.name ? c.name.split("/") : c._component.split("/"))
|
||||||
normalizedName(c.name).split("/").length === pathPartsThisLevel
|
|
||||||
&&
|
|
||||||
(!thisLevel || normalizedName(c.name).startsWith(normalizedName(thisLevel)));
|
|
||||||
|
|
||||||
const notOnThisLevel = (c) => !isOnThisLevel(c);
|
|
||||||
|
|
||||||
const isInSubfolder = (subfolder, c) =>
|
|
||||||
normalizedName(c.name).startsWith(
|
|
||||||
trimCharsStart("/")(
|
|
||||||
joinPath([thisLevel, subfolder])));
|
|
||||||
|
|
||||||
const isOnNextLevel = (c) =>
|
|
||||||
normalizedName(c.name).split("/").length === pathPartsThisLevel + 1
|
|
||||||
|
|
||||||
const lastPartOfName = (c) =>
|
|
||||||
last(c.name.split("/"))
|
|
||||||
|
|
||||||
const subFolder = (c) => {
|
|
||||||
const cname = normalizedName(c.name);
|
|
||||||
const folderName = cname.substring(thisLevel.length, cname.length).split("/")[0];
|
|
||||||
|
|
||||||
return ({
|
|
||||||
name: folderName,
|
|
||||||
isExpanded: includes(folderName)(expandedFolders),
|
|
||||||
path: thisLevel + "/" + folderName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const subComponents = (subfolder) => pipe(components, [
|
|
||||||
filter(c => isInSubfolder(subfolder, c))
|
|
||||||
]);
|
|
||||||
|
|
||||||
const expandFolder = folder => {
|
const expandFolder = folder => {
|
||||||
const expandedFolder = {...folder};
|
const expandedFolder = {...folder};
|
||||||
|
@ -84,62 +47,46 @@ const expandFolder = folder => {
|
||||||
1,
|
1,
|
||||||
expandedFolder);
|
expandedFolder);
|
||||||
subfolders = newFolders;
|
subfolders = newFolders;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const isComponentSelected = (type, current,c) =>
|
const isComponentSelected = (type, current,c) =>
|
||||||
type==="screen"
|
type==="screen"
|
||||||
&& current
|
&& current
|
||||||
&& current.name === c.name
|
&& current.name === c.name
|
||||||
|
|
||||||
const isFolderSelected = (current, folder) =>
|
const isFolderSelected = (current, folder) =>
|
||||||
isInSubfolder(current, folder)
|
isInSubfolder(current, folder)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$: {
|
$: _components =
|
||||||
pathPartsThisLevel = !thisLevel
|
|
||||||
? 1
|
|
||||||
: normalizedName(thisLevel).split("/").length + 1;
|
|
||||||
|
|
||||||
componentsThisLevel =
|
|
||||||
pipe(components, [
|
pipe(components, [
|
||||||
filter(isOnThisLevel),
|
map(c => ({component: c, title:lastPartOfName(c)})),
|
||||||
map(c => ({component:c, title:lastPartOfName(c)})),
|
|
||||||
sortBy("title")
|
sortBy("title")
|
||||||
]);
|
]);
|
||||||
|
|
||||||
subfolders =
|
function select_component(screen, component) {
|
||||||
pipe(components, [
|
store.setCurrentScreen(screen);
|
||||||
filter(notOnThisLevel),
|
store.selectComponent(component);
|
||||||
sortBy("name"),
|
|
||||||
map(subFolder),
|
|
||||||
uniqWith((f1,f2) => f1.path === f2.path)
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root" style={`padding-left: calc(10px * ${pathPartsThisLevel})`}>
|
<div class="root">
|
||||||
|
|
||||||
{#each subfolders as folder}
|
|
||||||
<div class="hierarchy-item folder"
|
|
||||||
on:click|stopPropagation={() => expandFolder(folder)}>
|
|
||||||
<span>{@html getIcon(folder.isExpanded ? "chevron-down" : "chevron-right", "16")}</span>
|
|
||||||
<span class="title" class:currentfolder={$store.currentFrontEndItem && isInSubfolder(folder.name, $store.currentFrontEndItem)}>{folder.name}</span>
|
|
||||||
{#if folder.isExpanded}
|
|
||||||
<svelte:self components={subComponents(folder.name)}
|
|
||||||
thisLevel={folder.path} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
|
|
||||||
{#each componentsThisLevel as component}
|
|
||||||
<div class="hierarchy-item component" class:selected={isComponentSelected($store.currentFrontEndType, $store.currentFrontEndItem, component.component)}
|
{#each _components as component}
|
||||||
|
<div class="hierarchy-item component"
|
||||||
|
class:selected={isComponentSelected($store.currentFrontEndType, $store.currentFrontEndItem, component.component)}
|
||||||
on:click|stopPropagation={() => store.setCurrentScreen(component.component.name)}>
|
on:click|stopPropagation={() => store.setCurrentScreen(component.component.name)}>
|
||||||
<span>{@html getIcon("circle", "7")}</span>
|
|
||||||
<span class="title">{component.title}</span>
|
<span class="title">{component.title}</span>
|
||||||
</div>
|
</div>
|
||||||
|
{#if component.component.props && component.component.props._children}
|
||||||
|
<ComponentsHierarchyChildren components={component.component.props._children}
|
||||||
|
onSelect={child => select_component(component.component.name, child)} />
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -147,31 +94,33 @@ $: {
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
color: var(--secondary50);
|
font-weight: 500;
|
||||||
font-size: .9rem;
|
font-size: 0.9rem;
|
||||||
font-weight: bold;
|
color: #828fa5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hierarchy-item {
|
.hierarchy-item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 5px 0px;
|
padding: 11px 7px;
|
||||||
|
|
||||||
|
margin: 5px 0;
|
||||||
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hierarchy-item:hover {
|
.hierarchy-item:hover {
|
||||||
color: var(--secondary);
|
/* color: var(--secondary); */
|
||||||
|
background: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.component {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.currentfolder {
|
.currentfolder {
|
||||||
color: var(--secondary100);
|
color: var(--secondary100);
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected {
|
.selected {
|
||||||
color: var(--primary100);
|
color: var(--button-text);
|
||||||
font-weight: bold;
|
background: var(--background-button)!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
@ -179,4 +128,4 @@ $: {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
<script>
|
||||||
|
import { last } from "lodash/fp";
|
||||||
|
import { pipe } from "../common/core";
|
||||||
|
|
||||||
|
export let components = [];
|
||||||
|
export let onSelect = () => {};
|
||||||
|
|
||||||
|
const capitalise = s => s.substring(0,1).toUpperCase() + s.substring(1);
|
||||||
|
const get_name = s => last(s.split('/'));
|
||||||
|
const get_capitalised_name = name => pipe(name, [get_name,capitalise]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each components as component}
|
||||||
|
<ul>
|
||||||
|
<li on:click|stopPropagation={() => onSelect(component)}>
|
||||||
|
{get_capitalised_name(component._component)}
|
||||||
|
|
||||||
|
{#if component._children}
|
||||||
|
<svelte:self components={component._children}/>
|
||||||
|
{/if}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
{/each}
|
|
@ -8,6 +8,7 @@ import {
|
||||||
groupBy, keys, find, sortBy
|
groupBy, keys, find, sortBy
|
||||||
} from "lodash/fp";
|
} from "lodash/fp";
|
||||||
import { pipe } from "../common/core";
|
import { pipe } from "../common/core";
|
||||||
|
import { ImageIcon, InputIcon, LayoutIcon } from '../common/Icons/';
|
||||||
|
|
||||||
let componentLibraries=[];
|
let componentLibraries=[];
|
||||||
|
|
||||||
|
@ -26,12 +27,10 @@ const addRootComponent = (c, all) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
group.components.push(c)
|
group.components.push(c)
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onComponentChosen = (component) => {
|
const onComponentChosen = store.addChildComponent;
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
store.subscribe(s => {
|
store.subscribe(s => {
|
||||||
|
|
||||||
|
@ -39,16 +38,14 @@ store.subscribe(s => {
|
||||||
|
|
||||||
for(let comp of sortBy(["name"])(s.components)) {
|
for(let comp of sortBy(["name"])(s.components)) {
|
||||||
addRootComponent(
|
addRootComponent(
|
||||||
comp,
|
comp,
|
||||||
newComponentLibraries);
|
newComponentLibraries);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentLibraries = newComponentLibraries;
|
componentLibraries = newComponentLibraries;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let current_view = 'text';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -59,22 +56,31 @@ store.subscribe(s => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="library-container">
|
<div class="library-container">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<button class:selected={current_view === 'text'} on:click={() => current_view = 'text'}>
|
||||||
|
<InputIcon />
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class:selected={current_view === 'layout'} on:click={() => current_view = 'layout'}>
|
||||||
|
<LayoutIcon />
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class:selected={current_view === 'media'} on:click={() => current_view = 'media'}>
|
||||||
|
<ImageIcon />
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{#each lib.components.filter(_ => true) as component}
|
||||||
<div class="inner-header">
|
|
||||||
Components
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#each lib.components as component}
|
|
||||||
|
|
||||||
<div class="component"
|
<div class="component"
|
||||||
on:click={() => onComponentChosen(component)}>
|
on:click={() => onComponentChosen(component.name)}>
|
||||||
<div class="name">
|
<div class="name">
|
||||||
{splitName(component.name).componentName}
|
{splitName(component.name).componentName}
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
|
||||||
{component.description}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -117,8 +123,16 @@ store.subscribe(s => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.component {
|
.component {
|
||||||
padding: 2px 0px;
|
padding: 0 15px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin: 10px 0;
|
||||||
|
height: 40px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #163057;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.component:hover {
|
.component:hover {
|
||||||
|
@ -126,8 +140,11 @@ store.subscribe(s => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.component > .name {
|
.component > .name {
|
||||||
color: var(--secondary100);
|
color: #163057;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.component > .description {
|
.component > .description {
|
||||||
|
@ -137,6 +154,34 @@ store.subscribe(s => {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
color: var(--button-text);
|
||||||
|
background: var(--background-button)!important;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<script>
|
<script>
|
||||||
import EditComponentProps from "./EditComponentProps.svelte";
|
import ComponentPanel from "./ComponentPanel.svelte";
|
||||||
import ComponentsList from "./ComponentsList.svelte";
|
import ComponentsList from "./ComponentsList.svelte";
|
||||||
|
|
||||||
let selected="properties";
|
let selected="properties";
|
||||||
|
|
||||||
const isSelected = tab =>
|
const isSelected = tab =>
|
||||||
selected === tab;
|
selected === tab;
|
||||||
|
|
||||||
const selectTab = tab =>
|
const selectTab = tab =>
|
||||||
selected = tab;
|
selected = tab;
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,13 +17,13 @@ const selectTab = tab =>
|
||||||
|
|
||||||
<div class="switcher">
|
<div class="switcher">
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class:selected={selected==="properties"}
|
class:selected={selected==="properties"}
|
||||||
on:click={() => selectTab("properties")}>
|
on:click={() => selectTab("properties")}>
|
||||||
Properties
|
Properties
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class:selected={selected==="components"}
|
class:selected={selected==="components"}
|
||||||
on:click={() => selectTab("components")}>
|
on:click={() => selectTab("components")}>
|
||||||
Components
|
Components
|
||||||
|
@ -33,11 +33,11 @@ const selectTab = tab =>
|
||||||
|
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
{#if selected==="properties"}
|
{#if selected==="properties"}
|
||||||
<EditComponentProps />
|
<ComponentPanel />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if selected==="components"}
|
{#if selected==="components"}
|
||||||
<ComponentsList />
|
<ComponentsList />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -50,24 +50,29 @@ const selectTab = tab =>
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
padding: 2rem 1.5rem 2rem 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.switcher {
|
.switcher {
|
||||||
flex: 0 0 auto;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.switcher > button {
|
.switcher > button {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background-color: rgba(0,0,0,0);
|
border: none;
|
||||||
border-style: solid;
|
margin: 0;
|
||||||
border-color: var(--slate);
|
padding: 0;
|
||||||
margin: 5px;
|
|
||||||
padding: 5px;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.switcher > .selected {
|
.switcher > .selected {
|
||||||
background-color: red;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
|
@ -76,4 +81,4 @@ const selectTab = tab =>
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -17,7 +17,7 @@ let appDefinition = {};
|
||||||
|
|
||||||
store.subscribe(s => {
|
store.subscribe(s => {
|
||||||
hasComponent = !!s.currentFrontEndItem;
|
hasComponent = !!s.currentFrontEndItem;
|
||||||
|
|
||||||
stylesheetLinks = pipe(s.pages.stylesheets, [
|
stylesheetLinks = pipe(s.pages.stylesheets, [
|
||||||
map(s => `<link rel="stylesheet" href="${s}"/>`),
|
map(s => `<link rel="stylesheet" href="${s}"/>`),
|
||||||
join("\n")
|
join("\n")
|
||||||
|
@ -25,8 +25,8 @@ store.subscribe(s => {
|
||||||
appDefinition = {
|
appDefinition = {
|
||||||
componentLibraries: s.loadLibraryUrls(),
|
componentLibraries: s.loadLibraryUrls(),
|
||||||
props: buildPropsHierarchy(
|
props: buildPropsHierarchy(
|
||||||
s.components,
|
s.components,
|
||||||
s.screens,
|
s.screens,
|
||||||
s.currentFrontEndItem),
|
s.currentFrontEndItem),
|
||||||
hierarchy: s.hierarchy,
|
hierarchy: s.hierarchy,
|
||||||
appRootPath: ""
|
appRootPath: ""
|
||||||
|
@ -45,15 +45,16 @@ store.subscribe(s => {
|
||||||
title="componentPreview"
|
title="componentPreview"
|
||||||
srcdoc={
|
srcdoc={
|
||||||
`<html>
|
`<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
${stylesheetLinks}
|
${stylesheetLinks}
|
||||||
<script>
|
<script>
|
||||||
window["##BUDIBASE_APPDEFINITION##"] = ${JSON.stringify(appDefinition)};
|
window["##BUDIBASE_APPDEFINITION##"] = ${JSON.stringify(appDefinition)};
|
||||||
import('/_builder/budibase-client.esm.mjs')
|
import('/_builder/budibase-client.esm.mjs')
|
||||||
.then(module => {
|
.then(module => {
|
||||||
module.loadBudibase();
|
console.log(module, window);
|
||||||
})
|
module.loadBudibase({ window, localStorage });
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
|
@ -91,4 +92,4 @@ store.subscribe(s => {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -12,9 +12,10 @@ import {
|
||||||
} from "./pagesParsing/createProps";
|
} from "./pagesParsing/createProps";
|
||||||
import Button from "../common/Button.svelte";
|
import Button from "../common/Button.svelte";
|
||||||
import ButtonGroup from "../common/ButtonGroup.svelte";
|
import ButtonGroup from "../common/ButtonGroup.svelte";
|
||||||
|
import { LayoutIcon, PaintIcon, TerminalIcon } from '../common/Icons/';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
cloneDeep,
|
cloneDeep,
|
||||||
join,
|
join,
|
||||||
split,
|
split,
|
||||||
map,
|
map,
|
||||||
|
@ -50,43 +51,6 @@ store.subscribe(s => {
|
||||||
components = s.components;
|
components = s.components;
|
||||||
});
|
});
|
||||||
|
|
||||||
const save = () => {
|
|
||||||
|
|
||||||
ignoreStore = true;
|
|
||||||
if(!validate()) {
|
|
||||||
ignoreStore = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
component.name = originalName || name;
|
|
||||||
component.description = description;
|
|
||||||
component.tags = pipe(tagsString, [
|
|
||||||
split(","),
|
|
||||||
map(s => s.trim())
|
|
||||||
]);
|
|
||||||
|
|
||||||
store.saveScreen(component);
|
|
||||||
|
|
||||||
ignoreStore = false;
|
|
||||||
// now do the rename
|
|
||||||
if(name !== originalName) {
|
|
||||||
store.renameScreen(originalName, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const deleteComponent = () => {
|
|
||||||
showDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
const confirmDeleteComponent = () => {
|
|
||||||
store.deleteScreen(component.name);
|
|
||||||
hideDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
const onPropsValidate = result => {
|
|
||||||
propsValidationErrors = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateComponent = doChange => {
|
const updateComponent = doChange => {
|
||||||
const newComponent = cloneDeep(component);
|
const newComponent = cloneDeep(component);
|
||||||
doChange(newComponent);
|
doChange(newComponent);
|
||||||
|
@ -95,86 +59,27 @@ const updateComponent = doChange => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPropsChanged = newProps => {
|
const onPropsChanged = newProps => {
|
||||||
updateComponent(newComponent =>
|
updateComponent(newComponent =>
|
||||||
assign(newComponent.props, newProps));
|
assign(newComponent.props, newProps));
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const validate = () => {
|
|
||||||
const fieldInvalid = (field, err) =>
|
|
||||||
errors[field] = err;
|
|
||||||
const fieldValid = field =>
|
|
||||||
errors[field] && delete errors[field];
|
|
||||||
|
|
||||||
if(!name) nameInvalid = "component name i not supplied";
|
|
||||||
else nameInvalid = "";
|
|
||||||
|
|
||||||
return (!nameInvalid && propsValidationErrors.length === 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const hideDialog = () => {
|
|
||||||
UIkit.modal(modalElement).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
const showDialog = () => {
|
|
||||||
UIkit.modal(modalElement).show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
|
||||||
<div class="title">
|
<ul>
|
||||||
<div>{shortName}</div>
|
<li><button><PaintIcon /></button></li>
|
||||||
<div>
|
<li><button><LayoutIcon /></button></li>
|
||||||
<IconButton icon="save"
|
<li><button><TerminalIcon /></button></li>
|
||||||
on:click={save}
|
</ul>
|
||||||
color="var(--secondary100)"
|
|
||||||
hoverColor="var(--primary100)"/>
|
|
||||||
<IconButton icon="trash"
|
|
||||||
on:click={deleteComponent}
|
|
||||||
color="var(--secondary100)"
|
|
||||||
hoverColor="var(--primary100)"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="component-props-container">
|
<div class="component-props-container">
|
||||||
|
|
||||||
|
|
||||||
<PropsView onValidate={onPropsValidate}
|
<PropsView
|
||||||
{componentInfo}
|
{componentInfo}
|
||||||
{onPropsChanged} />
|
{onPropsChanged} />
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div bind:this={modalElement} uk-modal>
|
|
||||||
<div class="uk-modal-dialog">
|
|
||||||
|
|
||||||
<div class="uk-modal-header">
|
|
||||||
Delete {name} ?
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="uk-modal-body">
|
|
||||||
Are you sure you want to delete this component ?
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="uk-modal-footer">
|
|
||||||
<ButtonGroup>
|
|
||||||
<Button grouped
|
|
||||||
on:click={confirmDeleteComponent}>
|
|
||||||
OK
|
|
||||||
</Button>
|
|
||||||
<Button grouped
|
|
||||||
on:click={hideDialog}
|
|
||||||
color="secondary" >
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
</ButtonGroup>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -186,9 +91,7 @@ const showDialog = () => {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-style: solid;
|
|
||||||
border-width: 1px 0 0 0;
|
|
||||||
border-color: var(--slate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
@ -213,4 +116,32 @@ const showDialog = () => {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-right: 20px;
|
||||||
|
background: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 45px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li button {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
background: lightblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
filter
|
filter
|
||||||
} from "lodash/fp";
|
} from "lodash/fp";
|
||||||
import {EVENT_TYPE_MEMBER_NAME} from "../common/eventHandlers";
|
import {EVENT_TYPE_MEMBER_NAME} from "../common/eventHandlers";
|
||||||
|
|
||||||
export let parentProps;
|
export let parentProps;
|
||||||
export let propDef;
|
export let propDef;
|
||||||
export let onValueChanged;
|
export let onValueChanged;
|
||||||
|
@ -58,7 +59,7 @@ const removeHandler = (index) => () => {
|
||||||
|
|
||||||
<div class="addelement-container"
|
<div class="addelement-container"
|
||||||
on:click={addHandler}>
|
on:click={addHandler}>
|
||||||
<IconButton icon="plus"
|
<IconButton icon="plus"
|
||||||
size="12"/>
|
size="12"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
116
packages/builder/src/userInterface/LayoutEditor.svelte
Normal file
116
packages/builder/src/userInterface/LayoutEditor.svelte
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
<script>
|
||||||
|
import InputGroup from '../common/Inputs/InputGroup.svelte';
|
||||||
|
|
||||||
|
let grid_values = ['', '', '', ''];
|
||||||
|
let column_values = ['', ''];
|
||||||
|
let row_values = ['', ''];
|
||||||
|
let gap_values = [''];
|
||||||
|
let margin_values = ['', '', '', ''];
|
||||||
|
let padding_values = ['', '', '', ''];
|
||||||
|
let zindex_values = [''];
|
||||||
|
|
||||||
|
const tbrl = [
|
||||||
|
{ placeholder: 'T' },
|
||||||
|
{ placeholder: 'R' },
|
||||||
|
{ placeholder: 'B' },
|
||||||
|
{ placeholder: 'L' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const se = [
|
||||||
|
{ placeholder: 'START' },
|
||||||
|
{ placeholder: 'END' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const single = [{ placeholder: '' }];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Layout</h3>
|
||||||
|
|
||||||
|
<h4>Positioning</h4>
|
||||||
|
|
||||||
|
<div class="layout-pos">
|
||||||
|
<div class="grid">
|
||||||
|
<h5>Grid Area:</h5>
|
||||||
|
<InputGroup meta={tbrl} bind:values={grid_values} size="small"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<h5>Column:</h5>
|
||||||
|
<InputGroup meta={se} bind:values={column_values} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<h5>Row:</h5>
|
||||||
|
<InputGroup meta={se} bind:values={row_values} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<h5>Gap:</h5>
|
||||||
|
<InputGroup meta={single} bind:values={gap_values} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4>Spacing</h4>
|
||||||
|
|
||||||
|
<div class="layout-spacing">
|
||||||
|
<div class="grid">
|
||||||
|
<h5>Margin:</h5>
|
||||||
|
<InputGroup meta={tbrl} bind:values={margin_values} size="small"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<h5>Padding:</h5>
|
||||||
|
<InputGroup meta={tbrl} bind:values={padding_values} size="small"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4>Z-Index</h4>
|
||||||
|
|
||||||
|
<div class="layout-layer">
|
||||||
|
<div class="grid">
|
||||||
|
<h5>Z-Index:</h5>
|
||||||
|
<InputGroup meta={single} bind:values={zindex_values}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h3 {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #8997ab;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #163057;
|
||||||
|
opacity: 0.3;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #163057;
|
||||||
|
opacity: 0.6;
|
||||||
|
padding-top: 12px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div > div {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
grid-gap: 10px;
|
||||||
|
height: 40px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
grid-template-columns: 70px 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -11,7 +11,7 @@ import UIkit from "uikit";
|
||||||
import { isRootComponent } from "./pagesParsing/searchComponents";
|
import { isRootComponent } from "./pagesParsing/searchComponents";
|
||||||
import { splitName } from "./pagesParsing/splitRootComponentName.js"
|
import { splitName } from "./pagesParsing/splitRootComponentName.js"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
find, filter, some, map, includes
|
find, filter, some, map, includes
|
||||||
} from "lodash/fp";
|
} from "lodash/fp";
|
||||||
import { assign } from "lodash";
|
import { assign } from "lodash";
|
||||||
|
@ -29,13 +29,12 @@ let name="";
|
||||||
let saveAttempted=false;
|
let saveAttempted=false;
|
||||||
|
|
||||||
store.subscribe(s => {
|
store.subscribe(s => {
|
||||||
|
|
||||||
layoutComponents = pipe(s.components, [
|
layoutComponents = pipe(s.components, [
|
||||||
filter(c => c.container),
|
filter(c => c.container),
|
||||||
map(c => ({name:c.name, ...splitName(c.name)}))
|
map(c => ({name:c.name, ...splitName(c.name)}))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
layoutComponent = layoutComponent
|
layoutComponent = layoutComponent
|
||||||
? find(c => c.name === layoutComponent.name)(layoutComponents)
|
? find(c => c.name === layoutComponent.name)(layoutComponents)
|
||||||
: layoutComponents[0];
|
: layoutComponents[0];
|
||||||
|
|
||||||
|
@ -48,7 +47,7 @@ const save = () => {
|
||||||
const isValid = name.length > 0
|
const isValid = name.length > 0
|
||||||
&& !screenNameExists(name)
|
&& !screenNameExists(name)
|
||||||
&& layoutComponent;
|
&& layoutComponent;
|
||||||
|
|
||||||
if(!isValid) return;
|
if(!isValid) return;
|
||||||
|
|
||||||
store.createScreen(name, layoutComponent.name);
|
store.createScreen(name, layoutComponent.name);
|
||||||
|
@ -59,7 +58,7 @@ const cancel = () => {
|
||||||
UIkit.modal(componentSelectorModal).hide();
|
UIkit.modal(componentSelectorModal).hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
const screenNameExists = (name) =>
|
const screenNameExists = (name) =>
|
||||||
some(s => s.name.toLowerCase() === name.toLowerCase())(screens)
|
some(s => s.name.toLowerCase() === name.toLowerCase())(screens)
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -84,7 +83,7 @@ const screenNameExists = (name) =>
|
||||||
<div class="uk-margin">
|
<div class="uk-margin">
|
||||||
<label class="uk-form-label">Layout Component</label>
|
<label class="uk-form-label">Layout Component</label>
|
||||||
<div class="uk-form-controls">
|
<div class="uk-form-controls">
|
||||||
<select class="uk-select uk-form-small"
|
<select class="uk-select uk-form-small"
|
||||||
bind:value={layoutComponent}
|
bind:value={layoutComponent}
|
||||||
class:uk-form-danger={saveAttempted && !layoutComponent}>
|
class:uk-form-danger={saveAttempted && !layoutComponent}>
|
||||||
{#each layoutComponents as comp}
|
{#each layoutComponents as comp}
|
||||||
|
@ -130,4 +129,4 @@ h1 {
|
||||||
font-size: 9pt;
|
font-size: 9pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,54 +7,70 @@ const getPage = (s, name) => {
|
||||||
return ({name, props});
|
return ({name, props});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pages = [{
|
||||||
|
title: 'Main',
|
||||||
|
id: 'main'
|
||||||
|
}, {
|
||||||
|
title: 'Login',
|
||||||
|
id: 'unauthenticated'
|
||||||
|
}]
|
||||||
|
|
||||||
|
store.setCurrentPage('main')
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<div class="hierarchy-item component" class:selected={$store.currentFrontEndType === "page" && $store.currentPageName === "main"}
|
<select id="page" name="select" on:change={({target}) => store.setCurrentPage(target.value)}>
|
||||||
on:click|stopPropagation={() => store.setCurrentPage("main")}>
|
|
||||||
<span>{@html getIcon("circle", "7")}</span>
|
|
||||||
<span class="title">Main</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hierarchy-item component" class:selected={$store.currentFrontEndType === "page" && $store.currentPageName === "unauthenticated"}
|
{#each pages as {title, id}}
|
||||||
on:click|stopPropagation={() => store.setCurrentPage("unauthenticated")}>
|
<option value="{id}">Page: {title}</option>
|
||||||
<span>{@html getIcon("circle", "7")}</span>
|
{/each}
|
||||||
<span class="title">Login</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
</select>
|
||||||
|
<span class="arrow">{@html getIcon("chevron-down","24")}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
padding-left: 10px;
|
|
||||||
font-size: .9rem;
|
font-size: .9rem;
|
||||||
color: var(--secondary50);
|
color: var(--secondary50);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hierarchy-item {
|
|
||||||
cursor: pointer;
|
select {
|
||||||
padding: 5px 0px;
|
display: block;
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #444;
|
||||||
|
line-height: 1.3;
|
||||||
|
padding: 1em 2.6em 0.9em 1.4em;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
border-radius: .5em;
|
||||||
|
-moz-appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
background-color: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hierarchy-item:hover {
|
.arrow {
|
||||||
color: var(--secondary100);
|
position: absolute;
|
||||||
}
|
right: 10px;
|
||||||
|
top: 0;
|
||||||
.component {
|
bottom: 0;
|
||||||
margin-left: 5px;
|
margin: auto;
|
||||||
}
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
.selected {
|
pointer-events: none;
|
||||||
color: var(--primary100);
|
color: var(--primary100);
|
||||||
font-weight: bold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
.title {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -6,13 +6,12 @@ import Dropdown from "../common/Dropdown.svelte";
|
||||||
import EventListSelector from "./EventListSelector.svelte";
|
import EventListSelector from "./EventListSelector.svelte";
|
||||||
import StateBindingControl from "./StateBindingControl.svelte";
|
import StateBindingControl from "./StateBindingControl.svelte";
|
||||||
|
|
||||||
export let errors = [];
|
|
||||||
export let setProp = () => {};
|
export let setProp = () => {};
|
||||||
export let fieldHasError =() => {};
|
|
||||||
export let propDef = {};
|
|
||||||
export let props = {};
|
|
||||||
export let disabled;
|
export let disabled;
|
||||||
export let index;
|
export let index;
|
||||||
|
export let prop_name;
|
||||||
|
export let prop_value;
|
||||||
|
export let prop_type = {};
|
||||||
|
|
||||||
$: isOdd = (index % 2 !== 0);
|
$: isOdd = (index % 2 !== 0);
|
||||||
|
|
||||||
|
@ -25,35 +24,43 @@ const setComponentProp = (props) => {
|
||||||
|
|
||||||
<div class="root" >
|
<div class="root" >
|
||||||
|
|
||||||
{#if propDef.type === "event"}
|
{#if prop_type === "event"}
|
||||||
|
|
||||||
<div class="prop-label">{propDef.____name}</div>
|
<!-- <h5>{prop_name}</h5>
|
||||||
<EventListSelector parentProps={props}
|
<EventListSelector parentProps={props}
|
||||||
{propDef}
|
{propDef}
|
||||||
onValueChanged={setComponentProp} />
|
onValueChanged={setComponentProp} /> -->
|
||||||
|
|
||||||
{:else }
|
{:else }
|
||||||
|
|
||||||
<div class="prop-label">{propDef.____name}</div>
|
<h5>{prop_name}</h5>
|
||||||
<StateBindingControl value={props[propDef.____name]}
|
<StateBindingControl value={prop_value}
|
||||||
type={propDef.type}
|
type={prop_type}
|
||||||
options={propDef.options}
|
options={prop_type.options}
|
||||||
onChanged={v => setProp(propDef.____name, v)}/>
|
onChanged={v => setProp(prop_name, v)}/>
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
padding: 1rem 1rem 0rem 1rem;
|
height: 40px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
grid-template-columns: 70px 1fr;
|
||||||
|
grid-gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prop-label {
|
h5 {
|
||||||
font-size: 0.8rem;
|
font-size: 12px;
|
||||||
color: var(--secondary100);
|
font-weight: 700;
|
||||||
font-weight: bold;
|
color: #163057;
|
||||||
}
|
opacity: 0.6;
|
||||||
|
padding-top: 12px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -10,70 +10,33 @@ import { getInstanceProps } from "./pagesParsing/createProps";
|
||||||
import Checkbox from "../common/Checkbox.svelte";
|
import Checkbox from "../common/Checkbox.svelte";
|
||||||
import Textbox from "../common/Textbox.svelte";
|
import Textbox from "../common/Textbox.svelte";
|
||||||
import Dropdown from "../common/Dropdown.svelte";
|
import Dropdown from "../common/Dropdown.svelte";
|
||||||
import { validateProps } from "./pagesParsing/validateProps";
|
|
||||||
import PropControl from "./PropControl.svelte";
|
import PropControl from "./PropControl.svelte";
|
||||||
import IconButton from "../common/IconButton.svelte";
|
import IconButton from "../common/IconButton.svelte";
|
||||||
|
|
||||||
export let shouldValidate = true;
|
|
||||||
export let onValidate = () => {};
|
|
||||||
export let componentInfo;
|
export let componentInfo;
|
||||||
export let instanceProps = null;
|
export let instanceProps = null;
|
||||||
export let onPropsChanged = () => {};
|
export let onPropsChanged = () => {};
|
||||||
|
export let components;
|
||||||
|
|
||||||
let errors = [];
|
let errors = [];
|
||||||
let props = {};
|
let props = {};
|
||||||
let propsDefinitions = [];
|
let propsDefinitions = [];
|
||||||
let isInstance = false;
|
let isInstance = false;
|
||||||
|
|
||||||
|
const props_to_ignore = ['_component','_children', '_layout'];
|
||||||
|
|
||||||
$: {
|
$: propDefs = componentInfo && Object.entries(componentInfo).filter(([name])=> !props_to_ignore.includes(name));
|
||||||
if(componentInfo)
|
|
||||||
{
|
|
||||||
isInstance = !!instanceProps;
|
|
||||||
props = isInstance
|
|
||||||
? getInstanceProps(componentInfo, instanceProps)
|
|
||||||
: cloneDeep(componentInfo.fullProps);
|
|
||||||
|
|
||||||
propsDefinitions = pipe(componentInfo.propsDefinition, [
|
function find_type(prop_name) {
|
||||||
keys,
|
if(!componentInfo._component) return;
|
||||||
map(k => ({...componentInfo.propsDefinition[k], ____name:k})),
|
return components.find(({name}) => name === componentInfo._component).props[prop_name];
|
||||||
sortBy("____name")
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let setProp = (name, value) => {
|
let setProp = (name, value) => {
|
||||||
const newProps = cloneDeep(props);
|
onPropsChanged(name, value);
|
||||||
|
|
||||||
let finalProps = isInstance ? newProps : cloneDeep(componentInfo.component.props);
|
|
||||||
|
|
||||||
if(!isInstance) {
|
|
||||||
const nowSet = [];
|
|
||||||
for(let p of componentInfo.unsetProps) {
|
|
||||||
if(!isEqual(newProps[p])(componentInfo.rootDefaultProps[p])) {
|
|
||||||
finalProps[p] = newProps[p];
|
|
||||||
nowSet.push(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
componentInfo.unsetProps = difference(nowSet)(componentInfo.unsetProps);
|
|
||||||
}
|
|
||||||
|
|
||||||
newProps[name] = value;
|
|
||||||
finalProps[name] = value;
|
|
||||||
props = newProps;
|
|
||||||
if(validate(finalProps))
|
|
||||||
onPropsChanged(finalProps);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const validate = (finalProps) => {
|
|
||||||
errors = validateProps(componentInfo.rootComponent, finalProps, [], false);
|
|
||||||
onValidate(errors);
|
|
||||||
return errors.length === 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const fieldHasError = (propName) =>
|
const fieldHasError = (propName) =>
|
||||||
some(e => e.propName === propName)(errors);
|
some(e => e.propName === propName)(errors);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -81,26 +44,23 @@ const fieldHasError = (propName) =>
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
|
||||||
<form class="uk-form-stacked form-root">
|
<form class="uk-form-stacked form-root">
|
||||||
{#each propsDefinitions as propDef, index}
|
{#each propDefs as [prop_name, prop_value], index}
|
||||||
|
|
||||||
<div class="prop-container">
|
|
||||||
|
|
||||||
<PropControl {setProp}
|
<div class="prop-container">
|
||||||
{fieldHasError}
|
|
||||||
{propDef}
|
<PropControl {setProp}
|
||||||
{props}
|
{prop_name}
|
||||||
{index}
|
{prop_value}
|
||||||
disabled={false} />
|
prop_type={find_type(prop_name)}
|
||||||
|
{index}
|
||||||
|
disabled={false} />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,4 +81,4 @@ const fieldHasError = (propName) =>
|
||||||
min-width: 250px;
|
min-width: 250px;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -66,10 +66,10 @@ const setBindingSource = ev => {
|
||||||
bind(bindingPath, bindingFallbackValue, ev.target.value);
|
bind(bindingPath, bindingFallbackValue, ev.target.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const makeBinding = () => {
|
// const makeBinding = () => {
|
||||||
forceIsBound=true;
|
// forceIsBound=true;
|
||||||
isExpanded=true;
|
// isExpanded=true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -77,11 +77,11 @@ const makeBinding = () => {
|
||||||
<div>
|
<div>
|
||||||
<div class="bound-header">
|
<div class="bound-header">
|
||||||
<div>{isExpanded ? "" : bindingPath}</div>
|
<div>{isExpanded ? "" : bindingPath}</div>
|
||||||
<IconButton icon={isExpanded ? "chevron-up" : "chevron-down"}
|
<IconButton icon={isExpanded ? "chevron-up" : "chevron-down"}
|
||||||
size="12"
|
size="12"
|
||||||
on:click={() => isExpanded=!isExpanded}/>
|
on:click={() => isExpanded=!isExpanded}/>
|
||||||
{#if !canOnlyBind}
|
{#if !canOnlyBind}
|
||||||
<IconButton icon="trash"
|
<IconButton icon="trash"
|
||||||
size="12"
|
size="12"
|
||||||
on:click={clearBinding}/>
|
on:click={clearBinding}/>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -97,8 +97,8 @@ const makeBinding = () => {
|
||||||
value={bindingFallbackValue}
|
value={bindingFallbackValue}
|
||||||
on:change={setBindingFallback} >
|
on:change={setBindingFallback} >
|
||||||
<div class="binding-prop-label">Binding Source</div>
|
<div class="binding-prop-label">Binding Source</div>
|
||||||
<select class="uk-select uk-form-small"
|
<select class="uk-select uk-form-small"
|
||||||
value={bindingSource}
|
value={bindingSource}
|
||||||
on:change={setBindingSource}>
|
on:change={setBindingSource}>
|
||||||
|
|
||||||
<option>store</option>
|
<option>store</option>
|
||||||
|
@ -117,13 +117,13 @@ const makeBinding = () => {
|
||||||
<div>
|
<div>
|
||||||
<IconButton icon={value == true ? "check-square" : "square"}
|
<IconButton icon={value == true ? "check-square" : "square"}
|
||||||
size="19"
|
size="19"
|
||||||
on:click={() => onChanged(!value)}/>
|
on:click={() => onChanged(!value)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{:else if type === "options"}
|
{:else if type === "options"}
|
||||||
|
|
||||||
<select class="uk-select uk-form-small"
|
<select class="uk-select uk-form-small"
|
||||||
value={value}
|
value={value}
|
||||||
on:change={ev => onChanged(ev.target.value)}>
|
on:change={ev => onChanged(ev.target.value)}>
|
||||||
{#each options as option}
|
{#each options as option}
|
||||||
<option value={option}>{option}</option>
|
<option value={option}>{option}</option>
|
||||||
|
@ -132,49 +132,46 @@ const makeBinding = () => {
|
||||||
|
|
||||||
{:else}
|
{:else}
|
||||||
|
|
||||||
<input class="uk-input uk-form-small"
|
<input on:change={ev => onChanged(ev.target.value)}
|
||||||
on:change={ev => onChanged(ev.target.value)}
|
bind:value={value}
|
||||||
bind:value={value}
|
style="flex: 1 0 auto;" />
|
||||||
style="flex: 1 0 auto;" >
|
|
||||||
|
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
<IconButton icon="link"
|
|
||||||
size="12"
|
|
||||||
on:click={makeBinding} />
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.unbound-container {
|
||||||
|
display:flex;
|
||||||
|
}
|
||||||
|
|
||||||
.unbound-container {
|
.bound-header {
|
||||||
display:flex;
|
display: flex;
|
||||||
margin: .5rem 0rem .5rem 0rem;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.unbound-container > *:nth-child(1) {
|
.bound-header > div:nth-child(1) {
|
||||||
width:auto;
|
flex: 1 0 auto;
|
||||||
flex: 1 0 auto;
|
width: 30px;
|
||||||
font-size: 0.8rem;
|
color: var(--secondary50);
|
||||||
color: var(--secondary100);
|
padding-left: 5px;
|
||||||
border-radius: .2rem;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.bound-header {
|
.binding-prop-label {
|
||||||
display: flex;
|
color: var(--secondary50);
|
||||||
}
|
}
|
||||||
|
|
||||||
.bound-header > div:nth-child(1) {
|
input {
|
||||||
flex: 1 0 auto;
|
font-size: 12px;
|
||||||
width: 30px;
|
font-weight: 700;
|
||||||
color: var(--secondary50);
|
color: #163057;
|
||||||
padding-left: 5px;
|
opacity: 0.7;
|
||||||
}
|
padding: 5px 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
.binding-prop-label {
|
border: 1px solid #DBDBDB;
|
||||||
color: var(--secondary50);
|
border-radius: 2px;
|
||||||
}
|
outline: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</style>
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import SettingsView from "./SettingsView.svelte";
|
||||||
import PageView from "./PageView.svelte";
|
import PageView from "./PageView.svelte";
|
||||||
import ComponentsPaneSwitcher from "./ComponentsPaneSwitcher.svelte";
|
import ComponentsPaneSwitcher from "./ComponentsPaneSwitcher.svelte";
|
||||||
|
|
||||||
let newComponentPicker;
|
let newComponentPicker;
|
||||||
const newComponent = () => {
|
const newComponent = () => {
|
||||||
newComponentPicker.show();
|
newComponentPicker.show();
|
||||||
}
|
}
|
||||||
|
@ -26,19 +26,30 @@ const settings = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
|
||||||
<div class="ui-nav">
|
<div class="ui-nav">
|
||||||
|
|
||||||
|
<div class="pages-list-container">
|
||||||
|
<div class="nav-group-header">
|
||||||
|
|
||||||
|
<span class="navigator-title">Navigator</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-items-container">
|
||||||
|
<PagesList />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="components-list-container">
|
<div class="components-list-container">
|
||||||
<div class="nav-group-header">
|
<div class="nav-group-header">
|
||||||
<div>{@html getIcon("sidebar","18")}</div>
|
|
||||||
<span class="components-nav-header">Screens</span>
|
<span class="components-nav-header">Screens</span>
|
||||||
<div>
|
<div>
|
||||||
<IconButton icon="settings"
|
<!-- <IconButton icon="settings"
|
||||||
size="14px"
|
size="14px"
|
||||||
on:click={settings}/>
|
on:click={settings}/> -->
|
||||||
<IconButton icon="plus"
|
<!-- <IconButton icon="plus"
|
||||||
on:click={newComponent}/>
|
on:click={newComponent}/> -->
|
||||||
|
<button on:click={newComponent}>+</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-items-container">
|
<div class="nav-items-container">
|
||||||
|
@ -46,16 +57,6 @@ const settings = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pages-list-container">
|
|
||||||
<div class="nav-group-header">
|
|
||||||
<div>{@html getIcon("grid","18")}</div>
|
|
||||||
<span>Pages</span>
|
|
||||||
</div>
|
|
||||||
<div class="nav-items-container">
|
|
||||||
<PagesList />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="preview-pane">
|
<div class="preview-pane">
|
||||||
|
@ -63,7 +64,7 @@ const settings = () => {
|
||||||
<CurrentItemPreview />
|
<CurrentItemPreview />
|
||||||
{:else if $store.currentFrontEndType === "page"}
|
{:else if $store.currentFrontEndType === "page"}
|
||||||
<PageView />
|
<PageView />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if $store.currentFrontEndType === "screen"}
|
{#if $store.currentFrontEndType === "screen"}
|
||||||
|
@ -80,22 +81,47 @@ const settings = () => {
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
background: var(--background-button);
|
||||||
|
|
||||||
|
width: 1.8rem;
|
||||||
|
height: 1.8rem;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--button-text);
|
||||||
|
}
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 250px 1fr 300px;
|
grid-template-columns: 290px 1fr 300px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
background: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-nav {
|
.ui-nav {
|
||||||
grid-column: 1;
|
grid-column: 1;
|
||||||
background-color: var(--secondary5);
|
background-color: var(--secondary5);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
padding: 0 1.5rem 0rem 1.5rem
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-pane {
|
.preview-pane {
|
||||||
grid-column: 2;
|
grid-column: 2;
|
||||||
|
margin: 80px 60px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 0px 6px rgba(0,0,0,0.05)
|
||||||
}
|
}
|
||||||
|
|
||||||
.components-pane {
|
.components-pane {
|
||||||
|
@ -105,12 +131,10 @@ const settings = () => {
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pages-list-container {
|
|
||||||
padding-top: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.components-nav-header {
|
.components-nav-header {
|
||||||
font-size: .9rem;
|
font-size: 0.75rem;
|
||||||
|
color: #999;
|
||||||
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-group-header {
|
.nav-group-header {
|
||||||
|
@ -119,15 +143,16 @@ const settings = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-items-container {
|
.nav-items-container {
|
||||||
padding: 1rem 1rem 0rem 1rem;
|
padding: 1rem 0rem 0rem 0rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-group-header {
|
.nav-group-header {
|
||||||
display:grid;
|
display: flex;
|
||||||
grid-template-columns: [icon] auto [title] 1fr [button] auto;
|
padding: 2rem 0 0 0;
|
||||||
padding: 2rem 1rem 0rem 1rem;
|
|
||||||
font-size: .9rem;
|
font-size: .9rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-group-header>div:nth-child(1) {
|
.nav-group-header>div:nth-child(1) {
|
||||||
|
@ -152,7 +177,13 @@ const settings = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-group-header>div:nth-child(3):hover {
|
.nav-group-header>div:nth-child(3):hover {
|
||||||
color: var(--primary75);
|
color: var(--primary75);
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
.navigator-title {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {
|
import {
|
||||||
isString, isUndefined, find, keys, uniq,
|
isString, isUndefined, find, keys, uniq,
|
||||||
some, filter, reduce, cloneDeep, includes,last
|
some, filter, reduce, cloneDeep, includes, last
|
||||||
} from "lodash/fp";
|
} from "lodash/fp";
|
||||||
import { types, expandComponentDefinition } from "./types";
|
import { types, expandComponentDefinition } from "./types";
|
||||||
import { assign } from "lodash";
|
import { assign } from "lodash";
|
||||||
|
@ -11,7 +11,7 @@ import { ensureShardNameIsInShardMap } from "../../../../core/src/indexing/shard
|
||||||
export const getInstanceProps = (componentInfo, props) => {
|
export const getInstanceProps = (componentInfo, props) => {
|
||||||
const finalProps = cloneDeep(componentInfo.fullProps);
|
const finalProps = cloneDeep(componentInfo.fullProps);
|
||||||
|
|
||||||
for(let p in props) {
|
for (let p in props) {
|
||||||
finalProps[p] = props[p];
|
finalProps[p] = props[p];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,9 +20,9 @@ export const getInstanceProps = (componentInfo, props) => {
|
||||||
|
|
||||||
export const getNewComponentInfo = (components, rootComponent, name) => {
|
export const getNewComponentInfo = (components, rootComponent, name) => {
|
||||||
const component = {
|
const component = {
|
||||||
name: name || "",
|
name: name || "",
|
||||||
description:"",
|
description: "",
|
||||||
props:{
|
props: {
|
||||||
_component: rootComponent
|
_component: rootComponent
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -34,22 +34,22 @@ export const getNewComponentInfo = (components, rootComponent, name) => {
|
||||||
|
|
||||||
export const getScreenInfo = (components, screen) => {
|
export const getScreenInfo = (components, screen) => {
|
||||||
return getComponentInfo(
|
return getComponentInfo(
|
||||||
components,
|
components,
|
||||||
screen);
|
screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getComponentInfo = (components, comp) => {
|
export const getComponentInfo = (components, comp) => {
|
||||||
const targetComponent = isString(comp)
|
const targetComponent = isString(comp)
|
||||||
? find(c => c.name === comp)(components)
|
? find(c => c.name === comp)(components)
|
||||||
: comp;
|
: comp;
|
||||||
let component;
|
let component;
|
||||||
let subComponent;
|
let subComponent;
|
||||||
if(isRootComponent(targetComponent)) {
|
if (isRootComponent(targetComponent)) {
|
||||||
component = targetComponent;
|
component = targetComponent;
|
||||||
} else {
|
} else {
|
||||||
subComponent = targetComponent;
|
subComponent = targetComponent;
|
||||||
component = find(c => c.name === subComponent.props._component)(
|
component = find(c => c.name === (subComponent.props ? subComponent.props._component : subComponent._component))(
|
||||||
components);
|
components);
|
||||||
}
|
}
|
||||||
|
|
||||||
const subComponentProps = subComponent ? subComponent.props : {};
|
const subComponentProps = subComponent ? subComponent.props : {};
|
||||||
|
@ -65,7 +65,7 @@ export const getComponentInfo = (components, comp) => {
|
||||||
fullProps._component = targetComponent.name;
|
fullProps._component = targetComponent.name;
|
||||||
|
|
||||||
return ({
|
return ({
|
||||||
propsDefinition:expandComponentDefinition(component),
|
propsDefinition: expandComponentDefinition(component),
|
||||||
rootDefaultProps: rootProps.props,
|
rootDefaultProps: rootProps.props,
|
||||||
unsetProps,
|
unsetProps,
|
||||||
fullProps: fullProps,
|
fullProps: fullProps,
|
||||||
|
@ -78,7 +78,7 @@ export const getComponentInfo = (components, comp) => {
|
||||||
export const createProps = (componentDefinition, derivedFromProps) => {
|
export const createProps = (componentDefinition, derivedFromProps) => {
|
||||||
|
|
||||||
const error = (propName, error) =>
|
const error = (propName, error) =>
|
||||||
errors.push({propName, error});
|
errors.push({ propName, error });
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
_component: componentDefinition.name
|
_component: componentDefinition.name
|
||||||
|
@ -86,24 +86,24 @@ export const createProps = (componentDefinition, derivedFromProps) => {
|
||||||
|
|
||||||
const errors = [];
|
const errors = [];
|
||||||
|
|
||||||
if(!componentDefinition.name)
|
if (!componentDefinition.name)
|
||||||
error("_component", "Component name not supplied");
|
error("_component", "Component name not supplied");
|
||||||
|
|
||||||
const propsDef = componentDefinition.props;
|
const propsDef = componentDefinition.props;
|
||||||
for(let propDef in propsDef) {
|
for (let propDef in propsDef) {
|
||||||
const parsedPropDef = parsePropDef(propsDef[propDef]);
|
const parsedPropDef = parsePropDef(propsDef[propDef]);
|
||||||
if(parsedPropDef.error)
|
if (parsedPropDef.error)
|
||||||
error(propDef, parsedPropDef.error);
|
error(propDef, parsedPropDef.error);
|
||||||
else
|
else
|
||||||
props[propDef] = parsedPropDef;
|
props[propDef] = parsedPropDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(derivedFromProps) {
|
if (derivedFromProps) {
|
||||||
assign(props, derivedFromProps);
|
assign(props, derivedFromProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(componentDefinition.children !== false
|
if (componentDefinition.children !== false
|
||||||
&& isUndefined(props._children)) {
|
&& isUndefined(props._children)) {
|
||||||
props._children = [];
|
props._children = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,37 +114,37 @@ export const createProps = (componentDefinition, derivedFromProps) => {
|
||||||
|
|
||||||
|
|
||||||
const parsePropDef = propDef => {
|
const parsePropDef = propDef => {
|
||||||
const error = message => ({error:message, propDef});
|
const error = message => ({ error: message, propDef });
|
||||||
|
|
||||||
if(isString(propDef)) {
|
if (isString(propDef)) {
|
||||||
if(!types[propDef])
|
if (!types[propDef])
|
||||||
return error(`Do not recognise type ${propDef}`);
|
return error(`Do not recognise type ${propDef}`);
|
||||||
|
|
||||||
return types[propDef].default();
|
return types[propDef].default();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!propDef.type)
|
if (!propDef.type)
|
||||||
return error("Property Definition must declare a type");
|
return error("Property Definition must declare a type");
|
||||||
|
|
||||||
const type = types[propDef.type];
|
const type = types[propDef.type];
|
||||||
if(!type)
|
if (!type)
|
||||||
return error(`Do not recognise type ${propDef.type}`);
|
return error(`Do not recognise type ${propDef.type}`);
|
||||||
|
|
||||||
if(isUndefined(propDef.default))
|
if (isUndefined(propDef.default))
|
||||||
return type.default(propDef);
|
return type.default(propDef);
|
||||||
|
|
||||||
if(!type.isOfType(propDef.default))
|
if (!type.isOfType(propDef.default))
|
||||||
return error(`${propDef.default} is not of type ${type}`);
|
return error(`${propDef.default} is not of type ${type}`);
|
||||||
|
|
||||||
return propDef.default;
|
return propDef.default;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const arrayElementComponentName = (parentComponentName, arrayPropName) =>
|
export const arrayElementComponentName = (parentComponentName, arrayPropName) =>
|
||||||
`${parentComponentName}:${arrayPropName}`;
|
`${parentComponentName}:${arrayPropName}`;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Allowed propDefOptions
|
Allowed propDefOptions
|
||||||
- type: string, bool, number, array
|
- type: string, bool, number, array
|
||||||
- default: default value, when undefined
|
- default: default value, when undefined
|
||||||
- required: field is required
|
- required: field is required
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { recursivelyValidate } from "./validateProps";
|
import {
|
||||||
import {
|
isString,
|
||||||
isString,
|
keys,
|
||||||
keys,
|
|
||||||
flatten,
|
flatten,
|
||||||
isArray,
|
isArray,
|
||||||
map,
|
map,
|
||||||
|
@ -15,12 +14,12 @@ export const validatePage = (page, getComponent) => {
|
||||||
const error = message => errors.push(message);
|
const error = message => errors.push(message);
|
||||||
|
|
||||||
const noIndex = !page.index;
|
const noIndex = !page.index;
|
||||||
if(noIndex) {
|
if (noIndex) {
|
||||||
error("Page does not define an index member");
|
error("Page does not define an index member");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!page.appBody
|
if (!page.appBody
|
||||||
|| !isString(page.appBody)
|
|| !isString(page.appBody)
|
||||||
|| !page.appBody.endsWith(".json")) {
|
|| !page.appBody.endsWith(".json")) {
|
||||||
error("App body must be set toa valid JSON file");
|
error("App body must be set toa valid JSON file");
|
||||||
}
|
}
|
||||||
|
@ -28,7 +27,7 @@ export const validatePage = (page, getComponent) => {
|
||||||
/* Commenting this for now
|
/* Commenting this for now
|
||||||
* index is a load of static members just now, but maybe useful
|
* index is a load of static members just now, but maybe useful
|
||||||
for pageLayout props (which is just a pipe dream at time of writing)
|
for pageLayout props (which is just a pipe dream at time of writing)
|
||||||
const indexHtmlErrors = noIndex
|
const indexHtmlErrors = noIndex
|
||||||
? []
|
? []
|
||||||
: pipe(
|
: pipe(
|
||||||
recursivelyValidate(page.index, getComponent), [
|
recursivelyValidate(page.index, getComponent), [
|
||||||
|
@ -44,17 +43,17 @@ export const validatePages = (pages, getComponent) => {
|
||||||
let errors = [];
|
let errors = [];
|
||||||
const error = message => errors.push(message);
|
const error = message => errors.push(message);
|
||||||
|
|
||||||
if(!pages.main) {
|
if (!pages.main) {
|
||||||
error("must have a 'main' page");
|
error("must have a 'main' page");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!pages.unauthenticated) {
|
if (!pages.unauthenticated) {
|
||||||
error("must have a 'unauthenticated' (login) page");
|
error("must have a 'unauthenticated' (login) page");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!pages.componentLibraries
|
if (!pages.componentLibraries
|
||||||
|| !isArray(pages.componentLibraries)
|
|| !isArray(pages.componentLibraries)
|
||||||
|| pages.componentLibraries.length === 0) {
|
|| pages.componentLibraries.length === 0) {
|
||||||
|
|
||||||
error("componentLibraries must be set to a non-empty array of strings");
|
error("componentLibraries must be set to a non-empty array of strings");
|
||||||
}
|
}
|
||||||
|
@ -67,4 +66,4 @@ export const validatePages = (pages, getComponent) => {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return [...errors, ...pageErrors];
|
return [...errors, ...pageErrors];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,143 +0,0 @@
|
||||||
import { types } from "./types";
|
|
||||||
import {
|
|
||||||
createProps, arrayElementComponentName
|
|
||||||
} from "./createProps";
|
|
||||||
import { isString } from "util";
|
|
||||||
import {
|
|
||||||
includes, filter, map, keys,
|
|
||||||
flatten, flattenDeep, each,
|
|
||||||
indexOf, isUndefined
|
|
||||||
} from "lodash/fp";
|
|
||||||
import { common } from "../../../../core/src";
|
|
||||||
import {
|
|
||||||
isBinding
|
|
||||||
} from "../../common/binding";
|
|
||||||
|
|
||||||
const pipe = common.$;
|
|
||||||
|
|
||||||
const makeError = (errors, propName, stack) => (message) =>
|
|
||||||
errors.push({
|
|
||||||
stack,
|
|
||||||
propName,
|
|
||||||
error:message});
|
|
||||||
|
|
||||||
export const recursivelyValidate = (rootProps, getComponent, stack=[]) => {
|
|
||||||
|
|
||||||
if(!rootProps._component) {
|
|
||||||
const errs = [];
|
|
||||||
makeError(errs, "_component", stack)("Component is not set");
|
|
||||||
return errs;
|
|
||||||
// this would break everything else anyway
|
|
||||||
}
|
|
||||||
|
|
||||||
const componentDef = getComponent(
|
|
||||||
rootProps._component);
|
|
||||||
|
|
||||||
|
|
||||||
const errors = validateProps(
|
|
||||||
componentDef,
|
|
||||||
rootProps,
|
|
||||||
stack,
|
|
||||||
true);
|
|
||||||
|
|
||||||
const validateChildren = (_props, _stack) =>
|
|
||||||
!_props._children
|
|
||||||
? []
|
|
||||||
: pipe(_props._children, [
|
|
||||||
map(child => recursivelyValidate(
|
|
||||||
child,
|
|
||||||
getComponent,
|
|
||||||
[..._stack, _props._children.indexOf(child)]))
|
|
||||||
]);
|
|
||||||
|
|
||||||
const childErrors = validateChildren(
|
|
||||||
rootProps, stack);
|
|
||||||
|
|
||||||
return flattenDeep([errors, ...childErrors]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const expandPropDef = propDef =>
|
|
||||||
isString(propDef)
|
|
||||||
? types[propDef].defaultDefinition()
|
|
||||||
: propDef;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const validateProps = (componentDefinition, props, stack=[], isFinal=true) => {
|
|
||||||
|
|
||||||
const errors = [];
|
|
||||||
|
|
||||||
if(isFinal && !props._component) {
|
|
||||||
makeError(errors, "_component", stack)("Component is not set");
|
|
||||||
return errors;
|
|
||||||
// this would break everything else anyway
|
|
||||||
}
|
|
||||||
|
|
||||||
const propsDefinition = componentDefinition.props;
|
|
||||||
|
|
||||||
for(let propDefName in props) {
|
|
||||||
|
|
||||||
if(propDefName === "_component") continue;
|
|
||||||
if(propDefName === "_children") continue;
|
|
||||||
if(propDefName === "_layout") continue;
|
|
||||||
|
|
||||||
const propDef = expandPropDef(propsDefinition[propDefName]);
|
|
||||||
|
|
||||||
const type = types[propDef.type];
|
|
||||||
|
|
||||||
const error = makeError(errors, propDefName, stack);
|
|
||||||
|
|
||||||
const propValue = props[propDefName];
|
|
||||||
|
|
||||||
// component declarations dont need to define al props.
|
|
||||||
if(!isFinal && isUndefined(propValue)) continue;
|
|
||||||
|
|
||||||
if(isFinal && propDef.required && propValue) {
|
|
||||||
error(`Property ${propDefName} is required`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isBinding(propValue)) {
|
|
||||||
if(propDef.type === "event") {
|
|
||||||
error(`Cannot apply binding to type ${propDef.type}`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(!type.isOfType(propValue)) {
|
|
||||||
error(`Property ${propDefName} is not of type ${propDef.type}. Actual value ${propValue}`)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(propDef.type === "options"
|
|
||||||
&& propValue
|
|
||||||
&& !isBinding(propValue)
|
|
||||||
&& !includes(propValue)(propDef.options)) {
|
|
||||||
error(`Property ${propDefName} is not one of allowed options. Acutal value is ${propValue}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const validateComponentDefinition = (componentDefinition) => {
|
|
||||||
const { errors } = createProps(componentDefinition);
|
|
||||||
|
|
||||||
const propDefinitions = expandPropDef(componentDefinition.props);
|
|
||||||
|
|
||||||
pipe(propDefinitions, [
|
|
||||||
keys,
|
|
||||||
map(k => ({
|
|
||||||
propDef:propDefinitions[k],
|
|
||||||
propName:k
|
|
||||||
})),
|
|
||||||
filter(d => d.propDef.type === "options"
|
|
||||||
&& (!d.propDef.options || d.propDef.options.length === 0)),
|
|
||||||
each(d => makeError(errors, d.propName)(`${d.propName} does not have any options`))
|
|
||||||
]);
|
|
||||||
|
|
||||||
return errors;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,232 +0,0 @@
|
||||||
import {
|
|
||||||
validateComponentDefinition,
|
|
||||||
validateProps,
|
|
||||||
recursivelyValidate
|
|
||||||
} from "../src/userInterface/pagesParsing/validateProps";
|
|
||||||
import { createProps } from "../src/userInterface/pagesParsing/createProps";
|
|
||||||
import {
|
|
||||||
setBinding
|
|
||||||
} from "../src/common/binding";
|
|
||||||
|
|
||||||
// not that allot of this functionality is covered
|
|
||||||
// in createDefaultProps - as validate props uses that.
|
|
||||||
|
|
||||||
describe("validateComponentDefinition", () => {
|
|
||||||
|
|
||||||
|
|
||||||
it("should return error when no options for options field", () => {
|
|
||||||
|
|
||||||
const compDef = {
|
|
||||||
name:"some_component",
|
|
||||||
props: {
|
|
||||||
size: {
|
|
||||||
type: "options",
|
|
||||||
options: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const errors = validateComponentDefinition(compDef);
|
|
||||||
|
|
||||||
expect(errors.length).toEqual(1);
|
|
||||||
expect(errors[0].propName).toBe("size");
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not return error when options field has options", () => {
|
|
||||||
|
|
||||||
const compDef = {
|
|
||||||
name: "some_component",
|
|
||||||
props: {
|
|
||||||
size: {
|
|
||||||
type: "options",
|
|
||||||
options: ["small", "medium", "large"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const errors = validateComponentDefinition(compDef);
|
|
||||||
|
|
||||||
expect(errors).toEqual([]);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
const validComponentDef = {
|
|
||||||
name: "some_component",
|
|
||||||
props: {
|
|
||||||
size: {
|
|
||||||
type: "options",
|
|
||||||
options: ["small", "medium", "large"],
|
|
||||||
default:"medium"
|
|
||||||
},
|
|
||||||
rowCount : "number"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const childComponentDef = {
|
|
||||||
name: "child_component",
|
|
||||||
props: {
|
|
||||||
width: "number",
|
|
||||||
units: {
|
|
||||||
type: "string",
|
|
||||||
default: "px"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const validProps = () => {
|
|
||||||
|
|
||||||
const { props } = createProps(validComponentDef);
|
|
||||||
props._children.push(
|
|
||||||
createProps(childComponentDef));
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("validateProps", () => {
|
|
||||||
|
|
||||||
it("should have no errors with a big list of valid props", () => {
|
|
||||||
|
|
||||||
const errors = validateProps(validComponentDef, validProps(), [], true);
|
|
||||||
expect(errors).toEqual([]);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return error with invalid value", () => {
|
|
||||||
|
|
||||||
const props = validProps();
|
|
||||||
props.rowCount = "1";
|
|
||||||
const errors = validateProps(validComponentDef, props, [], true);
|
|
||||||
expect(errors.length).toEqual(1);
|
|
||||||
expect(errors[0].propName).toBe("rowCount");
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return error with invalid option", () => {
|
|
||||||
|
|
||||||
const props = validProps();
|
|
||||||
props.size = "really_small";
|
|
||||||
const errors = validateProps(validComponentDef, props, [], true);
|
|
||||||
expect(errors.length).toEqual(1);
|
|
||||||
expect(errors[0].propName).toBe("size");
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not return error when has binding", () => {
|
|
||||||
const props = validProps();
|
|
||||||
props._children[0].width = setBinding({path:"some_path"});
|
|
||||||
props.size = setBinding({path:"other path", fallback:"small"});
|
|
||||||
const errors = validateProps(validComponentDef, props, [], true);
|
|
||||||
expect(errors.length).toEqual(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("recursivelyValidateProps", () => {
|
|
||||||
|
|
||||||
const rootComponent = {
|
|
||||||
name: "rootComponent",
|
|
||||||
children: true,
|
|
||||||
props: {
|
|
||||||
width: "number"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const todoListComponent = {
|
|
||||||
name: "todoListComponent",
|
|
||||||
props:{
|
|
||||||
showTitle: "bool"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const headerComponent = {
|
|
||||||
name: "headerComponent",
|
|
||||||
props: {
|
|
||||||
text: "string"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const iconComponent = {
|
|
||||||
name: "iconComponent",
|
|
||||||
props: {
|
|
||||||
iconName: "string"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const navItemComponent = {
|
|
||||||
name: "navItemComponent",
|
|
||||||
props: {
|
|
||||||
text: "string"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getComponent = name => ({
|
|
||||||
rootComponent,
|
|
||||||
todoListComponent,
|
|
||||||
headerComponent,
|
|
||||||
iconComponent,
|
|
||||||
navItemComponent
|
|
||||||
})[name];
|
|
||||||
|
|
||||||
const rootProps = () => ({
|
|
||||||
_component: "rootComponent",
|
|
||||||
width: 100,
|
|
||||||
_children: [{
|
|
||||||
_component: "todoListComponent",
|
|
||||||
showTitle: true,
|
|
||||||
_children : [
|
|
||||||
{
|
|
||||||
_component: "navItemComponent",
|
|
||||||
text: "todos"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_component: "headerComponent",
|
|
||||||
text: "Your todo list"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_component: "iconComponent",
|
|
||||||
iconName: "fa fa-list"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_component: "iconComponent",
|
|
||||||
iconName:"fa fa-cog"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return no errors for valid structure", () => {
|
|
||||||
const result = recursivelyValidate(
|
|
||||||
rootProps(),
|
|
||||||
getComponent);
|
|
||||||
|
|
||||||
expect(result).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return error on root component", () => {
|
|
||||||
const root = rootProps();
|
|
||||||
root.width = "yeeeoooo";
|
|
||||||
const result = recursivelyValidate(root, getComponent);
|
|
||||||
expect(result.length).toBe(1);
|
|
||||||
expect(result[0].propName).toBe("width");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return error on first nested child component", () => {
|
|
||||||
const root = rootProps();
|
|
||||||
root._children[0].showTitle = "yeeeoooo";
|
|
||||||
const result = recursivelyValidate(root, getComponent);
|
|
||||||
expect(result.length).toBe(1);
|
|
||||||
expect(result[0].stack).toEqual([0]);
|
|
||||||
expect(result[0].propName).toBe("showTitle");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return error on second nested child component", () => {
|
|
||||||
const root = rootProps();
|
|
||||||
root._children[0]._children[0].text = false;
|
|
||||||
const result = recursivelyValidate(root, getComponent);
|
|
||||||
expect(result.length).toBe(1);
|
|
||||||
expect(result[0].stack).toEqual([0,0]);
|
|
||||||
expect(result[0].propName).toBe("text");
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
1
packages/core/.gitignore
vendored
1
packages/core/.gitignore
vendored
|
@ -40,3 +40,4 @@ flow-typed/npm/*
|
||||||
|
|
||||||
.idea
|
.idea
|
||||||
npm-debug.log.*
|
npm-debug.log.*
|
||||||
|
dist
|
||||||
|
|
8297
packages/core/dist/budibase-core.cjs.js
vendored
8297
packages/core/dist/budibase-core.cjs.js
vendored
File diff suppressed because one or more lines are too long
8276
packages/core/dist/budibase-core.esm.mjs
vendored
8276
packages/core/dist/budibase-core.esm.mjs
vendored
File diff suppressed because one or more lines are too long
8296
packages/core/dist/budibase-core.umd.js
vendored
8296
packages/core/dist/budibase-core.umd.js
vendored
File diff suppressed because one or more lines are too long
|
@ -59,7 +59,7 @@ export default {
|
||||||
external: [
|
external: [
|
||||||
"lodash", "lodash/fp", "date-fns",
|
"lodash", "lodash/fp", "date-fns",
|
||||||
"lunr", "safe-buffer", "shortid",
|
"lunr", "safe-buffer", "shortid",
|
||||||
"@nx-js/compiler-util"
|
"@nx-js/compiler-util", "bcryptjs"
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
{
|
{
|
||||||
"_lib": "./dist/index.js",
|
"_lib": "./dist/index.js",
|
||||||
"h1": {
|
"h1": {
|
||||||
"name": "H1",
|
"name": "H1",
|
||||||
"description": "An HTML H1 tag",
|
"description": "An HTML H1 tag",
|
||||||
"props" : {
|
"props": {
|
||||||
"text": "string",
|
"text": "string",
|
||||||
"className":"string"
|
"className": "string"
|
||||||
},
|
},
|
||||||
"tags": []
|
"tags": []
|
||||||
}
|
},
|
||||||
}
|
"button": {
|
||||||
|
"name": "Button",
|
||||||
|
"description": "A button",
|
||||||
|
"props": {
|
||||||
|
"raised": "bool"
|
||||||
|
},
|
||||||
|
"tags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -13,18 +13,22 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@budibase/client": "^0.0.16",
|
"@budibase/client": "^0.0.16",
|
||||||
|
"@material/button": "^4.0.0",
|
||||||
"@nx-js/compiler-util": "^2.0.0",
|
"@nx-js/compiler-util": "^2.0.0",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"fs-extra": "^8.1.0",
|
"fs-extra": "^8.1.0",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"rollup": "^1.11.0",
|
"rollup": "^1.11.0",
|
||||||
|
"rollup-plugin-alias": "^2.2.0",
|
||||||
"rollup-plugin-commonjs": "^10.0.2",
|
"rollup-plugin-commonjs": "^10.0.2",
|
||||||
"rollup-plugin-json": "^4.0.0",
|
"rollup-plugin-json": "^4.0.0",
|
||||||
"rollup-plugin-livereload": "^1.0.1",
|
"rollup-plugin-livereload": "^1.0.1",
|
||||||
"rollup-plugin-node-resolve": "^5.0.0",
|
"rollup-plugin-node-resolve": "^5.0.0",
|
||||||
|
"rollup-plugin-postcss": "^2.0.5",
|
||||||
"rollup-plugin-svelte": "^5.0.0",
|
"rollup-plugin-svelte": "^5.0.0",
|
||||||
"rollup-plugin-terser": "^5.1.1",
|
"rollup-plugin-terser": "^5.1.1",
|
||||||
|
"sass": "^1.25.1-test.1",
|
||||||
"shortid": "^2.2.15",
|
"shortid": "^2.2.15",
|
||||||
"sirv-cli": "^0.4.4",
|
"sirv-cli": "^0.4.4",
|
||||||
"svelte": "^3.12.1"
|
"svelte": "^3.12.1"
|
||||||
|
|
|
@ -1,20 +1,37 @@
|
||||||
import svelte from 'rollup-plugin-svelte';
|
import svelte from "rollup-plugin-svelte";
|
||||||
import resolve from 'rollup-plugin-node-resolve';
|
import postcss from "rollup-plugin-postcss";
|
||||||
|
import resolve from "rollup-plugin-node-resolve";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
const postcssOptions = () => ({
|
||||||
|
extensions: [".scss", ".sass"],
|
||||||
|
extract: false,
|
||||||
|
minimize: true,
|
||||||
|
use: [
|
||||||
|
[
|
||||||
|
"sass",
|
||||||
|
{
|
||||||
|
includePaths: ["./node_modules"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
input: 'src/index.js',
|
input: "src/index.js",
|
||||||
output: [
|
output: [
|
||||||
{
|
{
|
||||||
file: "dist/index.js",
|
file: "dist/index.js",
|
||||||
format: 'esm',
|
format: "esm",
|
||||||
name:"budibaseStandardComponents",
|
name: "budibaseStandardComponents",
|
||||||
sourcemap: "inline"
|
sourcemap: "inline"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
svelte({
|
svelte({
|
||||||
hydratable:true
|
hydratable: true
|
||||||
}),
|
}),
|
||||||
resolve()
|
resolve(),
|
||||||
]
|
postcss(postcssOptions())
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,93 +1,149 @@
|
||||||
import svelte from 'rollup-plugin-svelte';
|
import svelte from "rollup-plugin-svelte";
|
||||||
import resolve from 'rollup-plugin-node-resolve';
|
import resolve from "rollup-plugin-node-resolve";
|
||||||
import commonjs from 'rollup-plugin-commonjs';
|
import commonjs from "rollup-plugin-commonjs";
|
||||||
import livereload from 'rollup-plugin-livereload';
|
import livereload from "rollup-plugin-livereload";
|
||||||
import { terser } from 'rollup-plugin-terser';
|
import { terser } from "rollup-plugin-terser";
|
||||||
import json from 'rollup-plugin-json';
|
import json from "rollup-plugin-json";
|
||||||
|
import alias from "rollup-plugin-alias";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
const aliases = {
|
||||||
|
resolve: [".js", ".svelte"],
|
||||||
|
entries: [
|
||||||
|
{ find: "@BBMD", replacement: path.resolve(__dirname, "dist/index.js") }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
const production = !process.env.ROLLUP_WATCH;
|
const production = !process.env.ROLLUP_WATCH;
|
||||||
|
|
||||||
const lodash_fp_exports = [
|
const lodash_fp_exports = [
|
||||||
"find", "isUndefined", "split", "max",
|
"find",
|
||||||
"last", "union", "reduce", "isObject",
|
"isUndefined",
|
||||||
"cloneDeep", "some", "isArray", "map",
|
"split",
|
||||||
"filter", "keys", "isFunction", "isEmpty",
|
"max",
|
||||||
"countBy", "join", "includes", "flatten",
|
"last",
|
||||||
"constant", "first", "intersection", "take",
|
"union",
|
||||||
"has", "mapValues", "isString", "isBoolean",
|
"reduce",
|
||||||
"isNull", "isNumber", "isObjectLike", "isDate",
|
"isObject",
|
||||||
"clone", "values", "keyBy", "isNaN",
|
"cloneDeep",
|
||||||
"isInteger", "toNumber"];
|
"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 = [
|
const lodash_exports = [
|
||||||
"flow", "head", "find","each",
|
"flow",
|
||||||
"tail", "findIndex", "startsWith",
|
"head",
|
||||||
"dropRight", "takeRight",
|
"find",
|
||||||
"trim", "split", "replace",
|
"each",
|
||||||
"merge", "assign"];
|
"tail",
|
||||||
|
"findIndex",
|
||||||
|
"startsWith",
|
||||||
|
"dropRight",
|
||||||
|
"takeRight",
|
||||||
|
"trim",
|
||||||
|
"split",
|
||||||
|
"replace",
|
||||||
|
"merge",
|
||||||
|
"assign"
|
||||||
|
];
|
||||||
|
|
||||||
const coreExternal = [
|
const coreExternal = [
|
||||||
"lodash", "lodash/fp", "date-fns",
|
"lodash",
|
||||||
"lunr", "safe-buffer", "shortid",
|
"lodash/fp",
|
||||||
"@nx-js/compiler-util", "bcryptjs"
|
"date-fns",
|
||||||
|
"lunr",
|
||||||
|
"safe-buffer",
|
||||||
|
"shortid",
|
||||||
|
"@nx-js/compiler-util",
|
||||||
|
"bcryptjs"
|
||||||
];
|
];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
input: 'src/Test/testMain.js',
|
input: "src/Test/testMain.js",
|
||||||
output: {
|
output: {
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
format: 'iife',
|
format: "iife",
|
||||||
name: 'app',
|
name: "app",
|
||||||
file: 'public/bundle.js',
|
file: "public/bundle.js",
|
||||||
globals: {
|
globals: {
|
||||||
"crypto": "crypto"
|
crypto: "crypto"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
svelte({
|
alias(aliases),
|
||||||
// enable run-time checks when not in production
|
svelte({
|
||||||
dev: !production,
|
// enable run-time checks when not in production
|
||||||
// we'll extract any component CSS out into
|
dev: !production,
|
||||||
// a separate file — better for performance
|
// we'll extract any component CSS out into
|
||||||
css: css => {
|
// a separate file — better for performance
|
||||||
css.write('public/bundle.css');
|
css: css => {
|
||||||
},
|
css.write("public/bundle.css");
|
||||||
|
},
|
||||||
hydratable:true
|
|
||||||
}),
|
|
||||||
|
|
||||||
// If you have external dependencies installed from
|
hydratable: true
|
||||||
// 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);
|
|
||||||
},
|
|
||||||
preferBuiltins: true
|
|
||||||
}),
|
|
||||||
commonjs({
|
|
||||||
namedExports: {
|
|
||||||
"lodash/fp": lodash_fp_exports,
|
|
||||||
"lodash":lodash_exports,
|
|
||||||
"shortid": ["generate"]
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
json(),
|
|
||||||
|
|
||||||
// Watch the `public` directory and refresh the
|
// If you have external dependencies installed from
|
||||||
// browser on changes when not in production
|
// npm, you'll most likely need these plugins. In
|
||||||
!production && livereload('public'),
|
// 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)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
preferBuiltins: true
|
||||||
|
}),
|
||||||
|
commonjs({
|
||||||
|
namedExports: {
|
||||||
|
"lodash/fp": lodash_fp_exports,
|
||||||
|
lodash: lodash_exports,
|
||||||
|
shortid: ["generate"]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
json(),
|
||||||
|
|
||||||
// If we're building for production (npm run build
|
// Watch the `public` directory and refresh the
|
||||||
// instead of npm run dev), minify
|
// browser on changes when not in production
|
||||||
production && terser()
|
!production && livereload("public"),
|
||||||
],
|
|
||||||
watch: {
|
// If we're building for production (npm run build
|
||||||
clearScreen: false
|
// instead of npm run dev), minify
|
||||||
}
|
production && terser()
|
||||||
|
],
|
||||||
|
watch: {
|
||||||
|
clearScreen: false
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
12
packages/materialdesign-components/src/Button.svelte
Normal file
12
packages/materialdesign-components/src/Button.svelte
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<script>
|
||||||
|
import "@material/button/mdc-button.scss";
|
||||||
|
export let raised = false;
|
||||||
|
|
||||||
|
let c = raised ? "mdc-button mdc-button--raised" : "mdc-button";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button class={c}>
|
||||||
|
<div class="mdc-button__ripple" />
|
||||||
|
|
||||||
|
<span class="mdc-button__label">Button</span>
|
||||||
|
</button>
|
|
@ -1,40 +1,35 @@
|
||||||
<script>
|
<script>
|
||||||
import createApp from "./createApp";
|
import createApp from "./createApp";
|
||||||
import { props } from "./props";
|
import { props } from "./props";
|
||||||
|
|
||||||
let _bb;
|
let _bb;
|
||||||
|
|
||||||
const _appPromise = createApp();
|
const _appPromise = createApp();
|
||||||
_appPromise.then(a => _bb = a);
|
_appPromise.then(a => (_bb = a));
|
||||||
|
|
||||||
const testProps = props.justAnH1;
|
const testProps = props.justAnH1;
|
||||||
|
const button = props.button;
|
||||||
|
|
||||||
let currentComponent;
|
let currentComponent;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if(_bb && currentComponent) {
|
if (_bb && currentComponent) {
|
||||||
_bb.hydrateChildren([testProps], currentComponent);
|
_bb.hydrateChildren([testProps, button], currentComponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#await _appPromise}
|
|
||||||
loading
|
|
||||||
{:then _bb}
|
|
||||||
|
|
||||||
<div id="current_component" bind:this={currentComponent}>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/await}
|
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#current_component {
|
#current_component {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
{#await _appPromise}
|
||||||
|
loading
|
||||||
|
{:then _bb}
|
||||||
|
|
||||||
|
<div id="current_component" bind:this={currentComponent} />
|
||||||
|
|
||||||
|
{/await}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
|
||||||
export const props = {
|
export const props = {
|
||||||
|
justAnH1: {
|
||||||
justAnH1 : {
|
_component: "@budibase/materialdesign-components/h1",
|
||||||
_component:"@budibase/materialdesign-components/h1",
|
_children: [],
|
||||||
_children: [],
|
text: "This is a Header"
|
||||||
text: "This is a Header"
|
},
|
||||||
}
|
button: {
|
||||||
|
_component: "@budibase/materialdesign-components/button",
|
||||||
}
|
_children: [],
|
||||||
|
raised: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
import h1 from "../H1.svelte";
|
import h1 from "../H1.svelte";
|
||||||
|
import { button } from "@BBMD";
|
||||||
|
|
||||||
export default {h1};
|
export default { h1, button };
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
export {default as h1} from "./H1.svelte";
|
export { default as h1 } from "./H1.svelte";
|
||||||
|
export { default as button } from "./Button.svelte";
|
||||||
|
|
||||||
|
|
5
packages/server/.gitignore
vendored
5
packages/server/.gitignore
vendored
|
@ -1,3 +1,8 @@
|
||||||
myapps/
|
myapps/
|
||||||
config.js
|
config.js
|
||||||
|
<<<<<<< HEAD
|
||||||
|
/builder/*
|
||||||
|
!/builder/assets/
|
||||||
|
=======
|
||||||
builder/
|
builder/
|
||||||
|
>>>>>>> ee5a4e8c962b29242152cbbd8065d8f3ccf65eaf
|
||||||
|
|
Binary file not shown.
|
@ -3,27 +3,27 @@
|
||||||
|
|
||||||
|
|
||||||
"@budibase/client@file:../../../client":
|
"@budibase/client@file:../../../client":
|
||||||
version "0.0.3"
|
version "0.0.16"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@nx-js/compiler-util" "^2.0.0"
|
"@nx-js/compiler-util" "^2.0.0"
|
||||||
date-fns "^1.29.0"
|
bcryptjs "^2.4.3"
|
||||||
lodash "^4.17.15"
|
lodash "^4.17.15"
|
||||||
lunr "^2.3.5"
|
lunr "^2.3.5"
|
||||||
shortid "^2.2.8"
|
shortid "^2.2.8"
|
||||||
svelte "^3.9.2"
|
svelte "^3.9.2"
|
||||||
|
|
||||||
"@budibase/standard-components@file:../../../standard-components":
|
"@budibase/standard-components@file:../../../standard-components":
|
||||||
version "0.0.5"
|
version "0.0.16"
|
||||||
|
|
||||||
"@nx-js/compiler-util@^2.0.0":
|
"@nx-js/compiler-util@^2.0.0":
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@nx-js/compiler-util/-/compiler-util-2.0.0.tgz#c74c12165fa2f017a292bb79af007e8fce0af297"
|
resolved "https://registry.yarnpkg.com/@nx-js/compiler-util/-/compiler-util-2.0.0.tgz#c74c12165fa2f017a292bb79af007e8fce0af297"
|
||||||
integrity sha512-AxSQbwj9zqt8DYPZ6LwZdytqnwfiOEdcFdq4l8sdjkZmU2clTht7RDLCI8xvkp7KqgcNaOGlTeCM55TULWruyQ==
|
integrity sha512-AxSQbwj9zqt8DYPZ6LwZdytqnwfiOEdcFdq4l8sdjkZmU2clTht7RDLCI8xvkp7KqgcNaOGlTeCM55TULWruyQ==
|
||||||
|
|
||||||
date-fns@^1.29.0:
|
bcryptjs@^2.4.3:
|
||||||
version "1.30.1"
|
version "2.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
|
resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb"
|
||||||
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
|
integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=
|
||||||
|
|
||||||
lodash@^4.17.15:
|
lodash@^4.17.15:
|
||||||
version "4.17.15"
|
version "4.17.15"
|
||||||
|
|
|
@ -131,29 +131,6 @@
|
||||||
lodash "^4.17.13"
|
lodash "^4.17.13"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@budibase/client@^0.0.16":
|
|
||||||
version "0.0.16"
|
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.0.16.tgz#4eef9373816448e99cafd2714f417c6610af5e69"
|
|
||||||
integrity sha512-fx4ptePj7+IehM37xdNPHdu5jEUgAFmDx23jI0yb4sI6Z5U4gxH10FZYyoJ/A9KdzmShsIfgrmudV5ffvoehdg==
|
|
||||||
dependencies:
|
|
||||||
"@nx-js/compiler-util" "^2.0.0"
|
|
||||||
lodash "^4.17.15"
|
|
||||||
lunr "^2.3.5"
|
|
||||||
shortid "^2.2.8"
|
|
||||||
svelte "^3.9.2"
|
|
||||||
|
|
||||||
"@budibase/core@^0.0.16":
|
|
||||||
version "0.0.16"
|
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/core/-/core-0.0.16.tgz#efff16876f906b2aa59803c3312ec7593664b623"
|
|
||||||
integrity sha512-DvzfurHHp9KkSjkvbGbKsVczR5ne38bMLRA2hHEJxAmC0Tshld06cEq7HMy2BmPb6kaC1URYHlFs/gPhW2cSFQ==
|
|
||||||
dependencies:
|
|
||||||
"@nx-js/compiler-util" "^2.0.0"
|
|
||||||
date-fns "^1.29.0"
|
|
||||||
lodash "^4.17.13"
|
|
||||||
lunr "^2.3.5"
|
|
||||||
safe-buffer "^5.1.2"
|
|
||||||
shortid "^2.2.8"
|
|
||||||
|
|
||||||
"@cnakazawa/watch@^1.0.3":
|
"@cnakazawa/watch@^1.0.3":
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef"
|
resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef"
|
||||||
|
@ -322,11 +299,6 @@
|
||||||
path-to-regexp "^1.1.1"
|
path-to-regexp "^1.1.1"
|
||||||
urijs "^1.19.0"
|
urijs "^1.19.0"
|
||||||
|
|
||||||
"@nx-js/compiler-util@^2.0.0":
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@nx-js/compiler-util/-/compiler-util-2.0.0.tgz#c74c12165fa2f017a292bb79af007e8fce0af297"
|
|
||||||
integrity sha512-AxSQbwj9zqt8DYPZ6LwZdytqnwfiOEdcFdq4l8sdjkZmU2clTht7RDLCI8xvkp7KqgcNaOGlTeCM55TULWruyQ==
|
|
||||||
|
|
||||||
"@types/babel__core@^7.1.0":
|
"@types/babel__core@^7.1.0":
|
||||||
version "7.1.2"
|
version "7.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.2.tgz#608c74f55928033fce18b99b213c16be4b3d114f"
|
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.2.tgz#608c74f55928033fce18b99b213c16be4b3d114f"
|
||||||
|
@ -1073,11 +1045,6 @@ data-urls@^1.0.0:
|
||||||
whatwg-mimetype "^2.2.0"
|
whatwg-mimetype "^2.2.0"
|
||||||
whatwg-url "^7.0.0"
|
whatwg-url "^7.0.0"
|
||||||
|
|
||||||
date-fns@^1.29.0:
|
|
||||||
version "1.30.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
|
|
||||||
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
|
|
||||||
|
|
||||||
debug@^2.2.0, debug@^2.3.3:
|
debug@^2.2.0, debug@^2.3.3:
|
||||||
version "2.6.9"
|
version "2.6.9"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||||
|
@ -2785,7 +2752,7 @@ lodash.sortby@^4.7.0:
|
||||||
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||||
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
|
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
|
||||||
|
|
||||||
lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.15:
|
lodash@^4.17.11, lodash@^4.17.13:
|
||||||
version "4.17.15"
|
version "4.17.15"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||||
|
@ -2810,11 +2777,6 @@ lru-cache@^4.0.1:
|
||||||
pseudomap "^1.0.2"
|
pseudomap "^1.0.2"
|
||||||
yallist "^2.1.2"
|
yallist "^2.1.2"
|
||||||
|
|
||||||
lunr@^2.3.5:
|
|
||||||
version "2.3.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.8.tgz#a8b89c31f30b5a044b97d2d28e2da191b6ba2072"
|
|
||||||
integrity sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==
|
|
||||||
|
|
||||||
make-dir@^1.0.0:
|
make-dir@^1.0.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
|
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
|
||||||
|
@ -2976,11 +2938,6 @@ nan@^2.12.1:
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
||||||
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
|
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
|
||||||
|
|
||||||
nanoid@^2.1.0:
|
|
||||||
version "2.1.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.8.tgz#2dbb0224231b246e3b4c819de7bfea6384dabf08"
|
|
||||||
integrity sha512-g1z+n5s26w0TGKh7gjn7HCqurNKMZWzH08elXzh/gM/csQHd/UqDV6uxMghQYg9IvqRPm1QpeMk50YMofHvEjQ==
|
|
||||||
|
|
||||||
nanomatch@^1.2.9:
|
nanomatch@^1.2.9:
|
||||||
version "1.2.13"
|
version "1.2.13"
|
||||||
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
|
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
|
||||||
|
@ -3816,13 +3773,6 @@ shellwords@^0.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
|
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
|
||||||
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
|
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
|
||||||
|
|
||||||
shortid@^2.2.8:
|
|
||||||
version "2.2.15"
|
|
||||||
resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.15.tgz#2b902eaa93a69b11120373cd42a1f1fe4437c122"
|
|
||||||
integrity sha512-5EaCy2mx2Jgc/Fdn9uuDuNIIfWBpzY4XIlhoqtXF6qsf+/+SGZ+FxDdX/ZsMZiWupIWNqAEmiNY4RC+LSmCeOw==
|
|
||||||
dependencies:
|
|
||||||
nanoid "^2.1.0"
|
|
||||||
|
|
||||||
signal-exit@^3.0.0, signal-exit@^3.0.2:
|
signal-exit@^3.0.0, signal-exit@^3.0.2:
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||||
|
@ -4100,11 +4050,6 @@ supports-color@^6.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
has-flag "^3.0.0"
|
has-flag "^3.0.0"
|
||||||
|
|
||||||
svelte@^3.9.2:
|
|
||||||
version "3.16.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.16.7.tgz#9ade80a4bbbac95595c676dd817222f632fa2c07"
|
|
||||||
integrity sha512-egrva1UklB1n7KAv179IhDpQzMGAvubJUlOQ9PitmmZmAfrCUEgrQnx2vPxn2s+mGV3aYegXvJ/yQ35N2SfnYQ==
|
|
||||||
|
|
||||||
symbol-tree@^3.2.2:
|
symbol-tree@^3.2.2:
|
||||||
version "3.2.4"
|
version "3.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -8,7 +8,7 @@ export let _bb;
|
||||||
let rootDiv;
|
let rootDiv;
|
||||||
$:{
|
$:{
|
||||||
if(_bb && rootDiv && _children && _children.length)
|
if(_bb && rootDiv && _children && _children.length)
|
||||||
_bb.hydrateChildren(_children, theButton);
|
_bb.hydrateChildren(_children, rootDiv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,4 +16,3 @@ $:{
|
||||||
|
|
||||||
<div class="{className}" bind:this={rootDiv}>
|
<div class="{className}" bind:this={rootDiv}>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue