Implement updating of individual component props
This commit is contained in:
parent
05a32f25f0
commit
d78f8013b5
|
@ -10,14 +10,14 @@ 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
|
||||||
|
@ -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,6 +91,9 @@ 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.saveComponent = saveComponent(store);
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,10 +102,10 @@ 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 +113,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,10 +129,10 @@ 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
|
||||||
);
|
);
|
||||||
|
@ -179,12 +182,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 +212,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 +227,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,7 +238,7 @@ 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, [
|
||||||
|
@ -251,7 +254,7 @@ const saveCurrentNode = (store) => () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
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,9 +263,9 @@ 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];
|
||||||
}
|
}
|
||||||
|
@ -279,8 +282,8 @@ 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;
|
||||||
|
@ -292,15 +295,15 @@ 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,7 +314,7 @@ 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 +325,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 +351,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 +359,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 +378,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;
|
||||||
|
@ -385,16 +388,16 @@ 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)
|
||||||
]);
|
]);
|
||||||
|
@ -470,7 +473,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,7 +499,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 +517,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 +538,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 +549,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,25 +562,25 @@ 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]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,7 +604,7 @@ const removeComponentLibrary = store => lib => {
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
||||||
|
@ -632,7 +635,7 @@ const refreshComponents = store => async () => {
|
||||||
|
|
||||||
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 +651,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 +692,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 = {
|
||||||
|
...newComponent.fullProps,
|
||||||
|
_component: component,
|
||||||
|
name: component,
|
||||||
|
description: '',
|
||||||
|
location: (s.currentFrontEndItem.location ? s.currentFrontEndItem.location : [])
|
||||||
|
.concat(children && children.length || 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.currentFrontEndItem.props._children =
|
||||||
|
children ?
|
||||||
|
children.concat(component_definition) :
|
||||||
|
[component_definition];
|
||||||
|
|
||||||
|
return s;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectComponent = store => component => {
|
||||||
|
store.update(s => {
|
||||||
|
s.currentComponentInfo = getComponentInfo(s.components, component);
|
||||||
|
return s;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveComponent = store => component => {
|
||||||
|
store.update(s => {
|
||||||
|
s.currentComponentInfo = getComponentInfo(s.components, component);
|
||||||
|
console.log(s.currentFrontEndItem, s.screens)
|
||||||
|
return _saveScreen(store, s, s.currentFrontEndItem);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -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 |
|
@ -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 |
|
@ -1,3 +1,5 @@
|
||||||
export { default as LayoutIcon } from './Layout.svelte';
|
export { default as LayoutIcon } from './Layout.svelte';
|
||||||
export { default as PaintIcon } from './Paint.svelte';
|
export { default as PaintIcon } from './Paint.svelte';
|
||||||
export { default as TerminalIcon } from './Terminal.svelte';
|
export { default as TerminalIcon } from './Terminal.svelte';
|
||||||
|
export { default as InputIcon } from './Input.svelte';
|
||||||
|
export { default as ImageIcon } from './Image.svelte';
|
||||||
|
|
|
@ -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.name)}
|
||||||
|
|
||||||
|
{#if component._children}
|
||||||
|
<svelte:self components={component._children}/>
|
||||||
|
{/if}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
{/each}
|
|
@ -43,7 +43,7 @@ $: shortName = last(name.split("/"));
|
||||||
|
|
||||||
store.subscribe(s => {
|
store.subscribe(s => {
|
||||||
if(ignoreStore) return;
|
if(ignoreStore) return;
|
||||||
component = s.currentFrontEndItem;
|
component = s.currentComponentInfo.component;
|
||||||
if(!component) return;
|
if(!component) return;
|
||||||
originalName = component.name;
|
originalName = component.name;
|
||||||
name = component.name;
|
name = component.name;
|
||||||
|
@ -68,7 +68,7 @@ const save = () => {
|
||||||
map(s => s.trim())
|
map(s => s.trim())
|
||||||
]);
|
]);
|
||||||
|
|
||||||
store.saveScreen(component);
|
store.saveComponent(component);
|
||||||
|
|
||||||
ignoreStore = false;
|
ignoreStore = false;
|
||||||
// now do the rename
|
// now do the rename
|
||||||
|
@ -92,14 +92,15 @@ const onPropsValidate = result => {
|
||||||
|
|
||||||
const updateComponent = doChange => {
|
const updateComponent = doChange => {
|
||||||
const newComponent = cloneDeep(component);
|
const newComponent = cloneDeep(component);
|
||||||
doChange(newComponent);
|
|
||||||
component = newComponent;
|
component = doChange(newComponent);
|
||||||
|
console.log(component, $store.screens[0].props._children[1])
|
||||||
componentInfo = getScreenInfo(components, newComponent);
|
componentInfo = getScreenInfo(components, newComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPropsChanged = newProps => {
|
const onPropsChanged = newProps => {
|
||||||
updateComponent(newComponent =>
|
updateComponent(newComponent =>
|
||||||
assign(newComponent.props, newProps));
|
assign(newComponent, newProps))
|
||||||
save();
|
save();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
|
import ComponentHierarchyChildren from './ComponentHierarchyChildren.svelte';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
last,
|
last,
|
||||||
|
@ -22,6 +23,7 @@ export let thisLevel = "";
|
||||||
|
|
||||||
let pathPartsThisLevel;
|
let pathPartsThisLevel;
|
||||||
let componentsThisLevel;
|
let componentsThisLevel;
|
||||||
|
let _components;
|
||||||
let subfolders;
|
let subfolders;
|
||||||
|
|
||||||
let expandedFolders = [];
|
let expandedFolders = [];
|
||||||
|
@ -52,7 +54,7 @@ const isOnNextLevel = (c) =>
|
||||||
normalizedName(c.name).split("/").length === pathPartsThisLevel + 1
|
normalizedName(c.name).split("/").length === pathPartsThisLevel + 1
|
||||||
|
|
||||||
const lastPartOfName = (c) =>
|
const lastPartOfName = (c) =>
|
||||||
last(c.name.split("/"))
|
last(c.name ? c.name.split("/") : c._component.split("/"))
|
||||||
|
|
||||||
const subFolder = (c) => {
|
const subFolder = (c) => {
|
||||||
const cname = normalizedName(c.name);
|
const cname = normalizedName(c.name);
|
||||||
|
@ -102,27 +104,27 @@ $: {
|
||||||
? 1
|
? 1
|
||||||
: normalizedName(thisLevel).split("/").length + 1;
|
: normalizedName(thisLevel).split("/").length + 1;
|
||||||
|
|
||||||
componentsThisLevel =
|
_components =
|
||||||
pipe(components, [
|
pipe(components, [
|
||||||
filter(isOnThisLevel),
|
// filter(isOnThisLevel),
|
||||||
map(c => ({component:c, title:lastPartOfName(c)})),
|
map(c => ({component: c, title:lastPartOfName(c)})),
|
||||||
sortBy("title")
|
sortBy("title")
|
||||||
]);
|
]);
|
||||||
|
|
||||||
subfolders =
|
// subfolders =
|
||||||
pipe(components, [
|
// pipe(components, [
|
||||||
filter(notOnThisLevel),
|
// filter(notOnThisLevel),
|
||||||
sortBy("name"),
|
// sortBy("name"),
|
||||||
map(subFolder),
|
// map(subFolder),
|
||||||
uniqWith((f1,f2) => f1.path === f2.path)
|
// uniqWith((f1,f2) => f1.path === f2.path)
|
||||||
]);
|
// ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
|
||||||
{#each subfolders as folder}
|
<!-- {#each subfolders as folder}
|
||||||
<div class="hierarchy-item folder"
|
<div class="hierarchy-item folder"
|
||||||
on:click|stopPropagation={() => expandFolder(folder)}>
|
on:click|stopPropagation={() => expandFolder(folder)}>
|
||||||
<span>{@html getIcon(folder.isExpanded ? "chevron-down" : "chevron-right", "16")}</span>
|
<span>{@html getIcon(folder.isExpanded ? "chevron-down" : "chevron-right", "16")}</span>
|
||||||
|
@ -132,14 +134,18 @@ $: {
|
||||||
thisLevel={folder.path} />
|
thisLevel={folder.path} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each} -->
|
||||||
|
|
||||||
{#each componentsThisLevel as component}
|
{#each _components as component}
|
||||||
<div class="hierarchy-item component" class:selected={isComponentSelected($store.currentFrontEndType, $store.currentFrontEndItem, component.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}
|
||||||
|
<ComponentHierarchyChildren components={component.component.props._children} onSelect={store.selectComponent}/>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -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=[];
|
||||||
|
|
||||||
|
@ -29,9 +30,7 @@ const addRootComponent = (c, all) => {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onComponentChosen = (component) => {
|
const onComponentChosen = store.addChildComponent;
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
store.subscribe(s => {
|
store.subscribe(s => {
|
||||||
|
|
||||||
|
@ -46,6 +45,8 @@ store.subscribe(s => {
|
||||||
componentLibraries = newComponentLibraries;
|
componentLibraries = newComponentLibraries;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let current_view = 'text';
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
@ -55,22 +56,34 @@ 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">
|
<!-- <div class="description">
|
||||||
{component.description}
|
{component.description}
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -113,8 +126,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 {
|
||||||
|
@ -122,8 +143,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 {
|
||||||
|
@ -133,6 +157,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>
|
||||||
|
|
|
@ -29,7 +29,6 @@ let name="";
|
||||||
let saveAttempted=false;
|
let saveAttempted=false;
|
||||||
|
|
||||||
store.subscribe(s => {
|
store.subscribe(s => {
|
||||||
console.log(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)}))
|
||||||
|
|
|
@ -25,7 +25,6 @@ let props = {};
|
||||||
let propsDefinitions = [];
|
let propsDefinitions = [];
|
||||||
let isInstance = false;
|
let isInstance = false;
|
||||||
|
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if(componentInfo)
|
if(componentInfo)
|
||||||
{
|
{
|
||||||
|
@ -46,7 +45,7 @@ $: {
|
||||||
let setProp = (name, value) => {
|
let setProp = (name, value) => {
|
||||||
const newProps = cloneDeep(props);
|
const newProps = cloneDeep(props);
|
||||||
|
|
||||||
let finalProps = isInstance ? newProps : cloneDeep(componentInfo.component.props);
|
let finalProps = isInstance ? newProps : cloneDeep(componentInfo.component.props ? componentInfo.component.props : componentInfo.component);
|
||||||
|
|
||||||
if(!isInstance) {
|
if(!isInstance) {
|
||||||
const nowSet = [];
|
const nowSet = [];
|
||||||
|
@ -98,9 +97,6 @@ const fieldHasError = (propName) =>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ 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
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -40,16 +40,16 @@ export const getScreenInfo = (components, 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,26 +114,26 @@ 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;
|
||||||
|
|
|
@ -19,11 +19,12 @@ const makeError = (errors, propName, stack) => (message) =>
|
||||||
errors.push({
|
errors.push({
|
||||||
stack,
|
stack,
|
||||||
propName,
|
propName,
|
||||||
error:message});
|
error: message
|
||||||
|
});
|
||||||
|
|
||||||
export const recursivelyValidate = (rootProps, getComponent, stack=[]) => {
|
export const recursivelyValidate = (rootProps, getComponent, stack = []) => {
|
||||||
|
|
||||||
if(!rootProps._component) {
|
if (!rootProps._component) {
|
||||||
const errs = [];
|
const errs = [];
|
||||||
makeError(errs, "_component", stack)("Component is not set");
|
makeError(errs, "_component", stack)("Component is not set");
|
||||||
return errs;
|
return errs;
|
||||||
|
@ -42,32 +43,32 @@ export const recursivelyValidate = (rootProps, getComponent, stack=[]) => {
|
||||||
|
|
||||||
const validateChildren = (_props, _stack) =>
|
const validateChildren = (_props, _stack) =>
|
||||||
!_props._children
|
!_props._children
|
||||||
? []
|
? []
|
||||||
: pipe(_props._children, [
|
: pipe(_props._children, [
|
||||||
map(child => recursivelyValidate(
|
map(child => recursivelyValidate(
|
||||||
child,
|
child,
|
||||||
getComponent,
|
getComponent,
|
||||||
[..._stack, _props._children.indexOf(child)]))
|
[..._stack, _props._children.indexOf(child)]))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const childErrors = validateChildren(
|
const childErrors = validateChildren(
|
||||||
rootProps, stack);
|
rootProps, stack);
|
||||||
|
|
||||||
return flattenDeep([errors, ...childErrors]);
|
return flattenDeep([errors, ...childErrors]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const expandPropDef = propDef =>
|
const expandPropDef = propDef =>
|
||||||
isString(propDef)
|
isString(propDef)
|
||||||
? types[propDef].defaultDefinition()
|
? types[propDef].defaultDefinition()
|
||||||
: propDef;
|
: propDef;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const validateProps = (componentDefinition, props, stack=[], isFinal=true) => {
|
export const validateProps = (componentDefinition, props, stack = [], isFinal = true) => {
|
||||||
|
|
||||||
const errors = [];
|
const errors = [];
|
||||||
|
|
||||||
if(isFinal && !props._component) {
|
if (isFinal && !props._component) {
|
||||||
makeError(errors, "_component", stack)("Component is not set");
|
makeError(errors, "_component", stack)("Component is not set");
|
||||||
return errors;
|
return errors;
|
||||||
// this would break everything else anyway
|
// this would break everything else anyway
|
||||||
|
@ -75,11 +76,11 @@ export const validateProps = (componentDefinition, props, stack=[], isFinal=true
|
||||||
|
|
||||||
const propsDefinition = componentDefinition.props;
|
const propsDefinition = componentDefinition.props;
|
||||||
|
|
||||||
for(let propDefName in props) {
|
for (let propDefName in props) {
|
||||||
|
|
||||||
if(propDefName === "_component") continue;
|
const ignore = ['_component', "_children", '_layout', 'name', 'description', 'location'];
|
||||||
if(propDefName === "_children") continue;
|
|
||||||
if(propDefName === "_layout") continue;
|
if (ignore.includes(propDefName)) continue;
|
||||||
|
|
||||||
const propDef = expandPropDef(propsDefinition[propDefName]);
|
const propDef = expandPropDef(propsDefinition[propDefName]);
|
||||||
|
|
||||||
|
@ -90,29 +91,29 @@ export const validateProps = (componentDefinition, props, stack=[], isFinal=true
|
||||||
const propValue = props[propDefName];
|
const propValue = props[propDefName];
|
||||||
|
|
||||||
// component declarations dont need to define al props.
|
// component declarations dont need to define al props.
|
||||||
if(!isFinal && isUndefined(propValue)) continue;
|
if (!isFinal && isUndefined(propValue)) continue;
|
||||||
|
|
||||||
if(isFinal && propDef.required && propValue) {
|
if (isFinal && propDef.required && propValue) {
|
||||||
error(`Property ${propDefName} is required`);
|
error(`Property ${propDefName} is required`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isBinding(propValue)) {
|
if (isBinding(propValue)) {
|
||||||
if(propDef.type === "event") {
|
if (propDef.type === "event") {
|
||||||
error(`Cannot apply binding to type ${propDef.type}`);
|
error(`Cannot apply binding to type ${propDef.type}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(!type.isOfType(propValue)) {
|
else if (!type.isOfType(propValue)) {
|
||||||
error(`Property ${propDefName} is not of type ${propDef.type}. Actual value ${propValue}`)
|
error(`Property ${propDefName} is not of type ${propDef.type}. Actual value ${propValue}`)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(propDef.type === "options"
|
if (propDef.type === "options"
|
||||||
&& propValue
|
&& propValue
|
||||||
&& !isBinding(propValue)
|
&& !isBinding(propValue)
|
||||||
&& !includes(propValue)(propDef.options)) {
|
&& !includes(propValue)(propDef.options)) {
|
||||||
error(`Property ${propDefName} is not one of allowed options. Acutal value is ${propValue}`);
|
error(`Property ${propDefName} is not one of allowed options. Acutal value is ${propValue}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,15 +130,14 @@ export const validateComponentDefinition = (componentDefinition) => {
|
||||||
pipe(propDefinitions, [
|
pipe(propDefinitions, [
|
||||||
keys,
|
keys,
|
||||||
map(k => ({
|
map(k => ({
|
||||||
propDef:propDefinitions[k],
|
propDef: propDefinitions[k],
|
||||||
propName:k
|
propName: k
|
||||||
})),
|
})),
|
||||||
filter(d => d.propDef.type === "options"
|
filter(d => d.propDef.type === "options"
|
||||||
&& (!d.propDef.options || d.propDef.options.length === 0)),
|
&& (!d.propDef.options || d.propDef.options.length === 0)),
|
||||||
each(d => makeError(errors, d.propName)(`${d.propName} does not have any options`))
|
each(d => makeError(errors, d.propName)(`${d.propName} does not have any options`))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 New Issue