diff --git a/packages/builder/src/builderStore/store.js b/packages/builder/src/builderStore/store.js index cc074d450b..ce35cf1f29 100644 --- a/packages/builder/src/builderStore/store.js +++ b/packages/builder/src/builderStore/store.js @@ -1,8 +1,8 @@ import { - hierarchy as hierarchyFunctions, + hierarchy as hierarchyFunctions, } from "../../../core/src"; import { - filter, cloneDeep, sortBy, + filter, cloneDeep, sortBy, map, last, keys, concat, keyBy, find, isEmpty, reduce, values } from "lodash/fp"; @@ -10,16 +10,16 @@ import { pipe, getNode, validate, constructHierarchy, templateApi } from "../common/core"; -import {writable} from "svelte/store"; +import { writable } from "svelte/store"; import { defaultPagesObject } from "../userInterface/pagesParsing/defaultPagesObject" import { buildPropsHierarchy } from "../userInterface/pagesParsing/buildPropsHierarchy" import api from "./api"; import { isRootComponent, getExactComponent } from "../userInterface/pagesParsing/searchComponents"; import { rename } from "../userInterface/pagesParsing/renameScreen"; -import { - getNewComponentInfo, getScreenInfo +import { + getNewComponentInfo, getScreenInfo, getComponentInfo } from "../userInterface/pagesParsing/createProps"; -import { +import { loadLibs, loadLibUrls, loadGeneratorLibs } from "./loadComponentLibraries"; @@ -28,30 +28,30 @@ let appname = ""; export const getStore = () => { const initial = { - apps:[], - appname:"", + apps: [], + appname: "", hierarchy: {}, actions: [], triggers: [], - pages:defaultPagesObject(), - mainUi:{}, - unauthenticatedUi:{}, - components:[], - currentFrontEndItem:null, - currentComponentInfo:null, - currentFrontEndType:"none", + pages: defaultPagesObject(), + mainUi: {}, + unauthenticatedUi: {}, + components: [], + currentFrontEndItem: null, + currentComponentInfo: null, + currentFrontEndType: "none", currentPageName: "", - currentComponentProps:null, + currentComponentProps: null, currentNodeIsNew: false, errors: [], activeNav: "database", - isBackend:true, + isBackend: true, hasAppPackage: false, - accessLevels: {version:0, levels:[]}, + accessLevels: { version: 0, levels: [] }, currentNode: null, - libraries:null, - showSettings:false, - useAnalytics:true, + libraries: null, + showSettings: false, + useAnalytics: true, }; const store = writable(initial); @@ -82,7 +82,7 @@ export const getStore = () => { store.setCurrentScreen = setCurrentScreen(store); store.setCurrentPage = setCurrentPage(store); store.createScreen = createScreen(store); - store.removeComponentLibrary =removeComponentLibrary(store); + store.removeComponentLibrary = removeComponentLibrary(store); store.addStylesheet = addStylesheet(store); store.removeStylesheet = removeStylesheet(store); store.savePage = savePage(store); @@ -91,18 +91,21 @@ export const getStore = () => { store.showSettings = showSettings(store); store.useAnalytics = useAnalytics(store); store.createGeneratedComponents = createGeneratedComponents(store); + store.addChildComponent = addChildComponent(store); + store.selectComponent = selectComponent(store); + store.saveComponent = saveComponent(store); return store; -} +} export default getStore; const initialise = (store, initial) => async () => { - appname = window.location.hash - ? last(window.location.hash.substr(1).split("/")) - : ""; + appname = window.location.hash + ? last(window.location.hash.substr(1).split("/")) + : ""; - if(!appname) { + if (!appname) { initial.apps = await api.get(`/_builder/api/apps`).then(r => r.json()); initial.hasAppPackage = false; store.set(initial); @@ -110,7 +113,7 @@ const initialise = (store, initial) => async () => { } const pkg = await api.get(`/_builder/api/${appname}/appPackage`) - .then(r => r.json()); + .then(r => r.json()); initial.libraries = await loadLibs(appname, pkg); initial.generatorLibraries = await loadGeneratorLibs(appname, pkg); @@ -126,10 +129,10 @@ const initialise = (store, initial) => async () => { initial.actions = values(pkg.appDefinition.actions); initial.triggers = pkg.appDefinition.triggers; - if(!!initial.hierarchy && !isEmpty(initial.hierarchy)) { + if (!!initial.hierarchy && !isEmpty(initial.hierarchy)) { initial.hierarchy = constructHierarchy(initial.hierarchy); const shadowHierarchy = createShadowHierarchy(initial.hierarchy); - if(initial.currentNode !== null) + if (initial.currentNode !== null) initial.currentNode = getNode( shadowHierarchy, initial.currentNode.nodeId ); @@ -138,7 +141,7 @@ const initialise = (store, initial) => async () => { return initial; } -const generatorsArray = generators => +const generatorsArray = generators => pipe(generators, [ keys, filter(k => k !== "_lib"), @@ -179,12 +182,12 @@ const newRecord = (store, useRoot) => () => { s.currentNodeIsNew = true; const shadowHierarchy = createShadowHierarchy(s.hierarchy); parent = useRoot ? shadowHierarchy - : getNode( - shadowHierarchy, - s.currentNode.nodeId); + : getNode( + shadowHierarchy, + s.currentNode.nodeId); s.errors = []; s.currentNode = templateApi(shadowHierarchy) - .getNewRecordTemplate(parent, "", true); + .getNewRecordTemplate(parent, "", true); return s; }); } @@ -209,12 +212,12 @@ const newIndex = (store, useRoot) => () => { s.errors = []; const shadowHierarchy = createShadowHierarchy(s.hierarchy); parent = useRoot ? shadowHierarchy - : getNode( - shadowHierarchy, - s.currentNode.nodeId); + : getNode( + shadowHierarchy, + s.currentNode.nodeId); s.currentNode = templateApi(shadowHierarchy) - .getNewIndexTemplate(parent); + .getNewIndexTemplate(parent); return s; }); } @@ -224,7 +227,7 @@ const saveCurrentNode = (store) => () => { const errors = validate.node(s.currentNode); s.errors = errors; - if(errors.length > 0) { + if (errors.length > 0) { return s; } @@ -235,23 +238,23 @@ const saveCurrentNode = (store) => () => { s.hierarchy, s.currentNode.nodeId); let index = parentNode.children.length; - if(!!existingNode) { + if (!!existingNode) { // remove existing index = existingNode.parent().children.indexOf(existingNode); existingNode.parent().children = pipe(existingNode.parent().children, [ filter(c => c.nodeId !== existingNode.nodeId) ]); - } + } // should add node into existing hierarchy const cloned = cloneDeep(s.currentNode); templateApi(s.hierarchy).constructNode( - parentNode, + parentNode, cloned ); const newIndexOfchild = child => { - if(child === cloned) return index; + if (child === cloned) return index; const currentIndex = parentNode.children.indexOf(child); return currentIndex >= index ? currentIndex + 1 : currentIndex; } @@ -260,15 +263,15 @@ const saveCurrentNode = (store) => () => { sortBy(newIndexOfchild) ]); - if(!existingNode && s.currentNode.type === "record") { + if (!existingNode && s.currentNode.type === "record") { const defaultIndex = templateApi(s.hierarchy) - .getNewIndexTemplate(cloned.parent()); + .getNewIndexTemplate(cloned.parent()); defaultIndex.name = `all_${cloned.collectionName}`; defaultIndex.allowedRecordNodeIds = [cloned.nodeId]; } s.currentNodeIsNew = false; - + savePackage(store, s); return s; @@ -279,28 +282,28 @@ const importAppDefinition = store => appDefinition => { store.update(s => { s.hierarchy = appDefinition.hierarchy; s.currentNode = appDefinition.hierarchy.children.length > 0 - ? appDefinition.hierarchy.children[0] - : null; + ? appDefinition.hierarchy.children[0] + : null; s.actions = appDefinition.actions; s.triggers = appDefinition.triggers; - s.currentNodeIsNew = false; + s.currentNodeIsNew = false; return s; }); -} +} const deleteCurrentNode = store => () => { store.update(s => { const nodeToDelete = getNode(s.hierarchy, s.currentNode.nodeId); s.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent()) - ? find(n => n != s.currentNode) - (s.hierarchy.children) - : nodeToDelete.parent(); - if(hierarchyFunctions.isRecord(nodeToDelete)) { + ? find(n => n != s.currentNode) + (s.hierarchy.children) + : nodeToDelete.parent(); + if (hierarchyFunctions.isRecord(nodeToDelete)) { nodeToDelete.parent().children = filter(c => c.nodeId !== nodeToDelete.nodeId) - (nodeToDelete.parent().children); + (nodeToDelete.parent().children); } else { nodeToDelete.parent().indexes = filter(c => c.nodeId !== nodeToDelete.nodeId) - (nodeToDelete.parent().indexes); + (nodeToDelete.parent().indexes); } s.errors = []; savePackage(store, s); @@ -311,8 +314,8 @@ const deleteCurrentNode = store => () => { const saveField = databaseStore => (field) => { databaseStore.update(db => { db.currentNode.fields = filter(f => f.name !== field.name) - (db.currentNode.fields); - + (db.currentNode.fields); + templateApi(db.hierarchy).addField(db.currentNode, field); return db; }); @@ -322,21 +325,21 @@ const saveField = databaseStore => (field) => { const deleteField = databaseStore => field => { databaseStore.update(db => { db.currentNode.fields = filter(f => f.name !== field.name) - (db.currentNode.fields); + (db.currentNode.fields); return db; }); } -const saveAction = store => (newAction, isNew, oldAction=null) => { +const saveAction = store => (newAction, isNew, oldAction = null) => { store.update(s => { - const existingAction = isNew - ? null - : find(a => a.name === oldAction.name)(s.actions); - - if(existingAction) { + const existingAction = isNew + ? null + : find(a => a.name === oldAction.name)(s.actions); + + if (existingAction) { s.actions = pipe(s.actions, [ map(a => a === existingAction ? newAction : a) ]); @@ -348,7 +351,7 @@ const saveAction = store => (newAction, isNew, oldAction=null) => { }); } -const deleteAction = store => action => { +const deleteAction = store => action => { store.update(s => { s.actions = filter(a => a.name !== action.name)(s.actions); 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 => { - const existingTrigger = isNew - ? null - : find(a => a.name === oldTrigger.name)(s.triggers); - - if(existingTrigger) { + const existingTrigger = isNew + ? null + : find(a => a.name === oldTrigger.name)(s.triggers); + + if (existingTrigger) { s.triggers = pipe(s.triggers, [ map(a => a === existingTrigger ? newTrigger : a) ]); @@ -375,7 +378,7 @@ const saveTrigger = store => (newTrigger, isNew, oldTrigger=null) => { }); } -const deleteTrigger = store => trigger => { +const deleteTrigger = store => trigger => { store.update(s => { s.triggers = filter(t => t.name !== trigger.name)(s.triggers); return s; @@ -383,18 +386,18 @@ const deleteTrigger = store => trigger => { } 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 => { const levels = s.accessLevels.levels; - const existingLevel = isNew - ? null - : find(a => a.name === oldLevel.name)(levels); - - if(existingLevel) { + const existingLevel = isNew + ? null + : find(a => a.name === oldLevel.name)(levels); + + if (existingLevel) { s.accessLevels.levels = pipe(levels, [ map(a => a === existingLevel ? newLevel : a) ]); @@ -425,7 +428,7 @@ const setActiveNav = store => navName => { }); } -const createShadowHierarchy = hierarchy => +const createShadowHierarchy = hierarchy => constructHierarchy(JSON.parse(JSON.stringify(hierarchy))); const saveScreen = store => (screen) => { @@ -448,7 +451,7 @@ const _saveScreen = (store, s, screen) => { api.post(`/_builder/api/${s.appname}/screen`, screen) .then(() => savePackage(store, s)); - return s; + return s; } const createScreen = store => (screenName, layoutComponentName) => { @@ -470,13 +473,13 @@ const createGeneratedComponents = store => components => { s.screens = [...s.screens, ...components]; const doCreate = async () => { - for(let c of components) { + for (let c of components) { await api.post(`/_builder/api/${s.appname}/screen`, c); } await savePackage(store, s); } - + doCreate(); return s; @@ -496,7 +499,7 @@ const deleteScreen = store => name => { s.components = components; s.screens = screens; - if(s.currentFrontEndItem.name === name) { + if (s.currentFrontEndItem.name === name) { s.currentFrontEndItem = null; s.currentFrontEndType = ""; } @@ -514,20 +517,20 @@ const renameScreen = store => (oldname, newname) => { screens, pages, error, changedScreens } = rename(s.pages, s.screens, oldname, newname); - if(error) { + if (error) { // should really do something with this return s; } s.screens = screens; s.pages = pages; - if(s.currentFrontEndItem.name === oldname) + if (s.currentFrontEndItem.name === oldname) s.currentFrontEndItem.name = newname; const saveAllChanged = async () => { - for(let screenName of changedScreens) { + for (let screenName of changedScreens) { const changedScreen - = getExactComponent(screens, screenName); + = getExactComponent(screens, screenName); 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`, { oldname, newname }) - .then(() => saveAllChanged()) - .then(() => { - savePackage(store, s); - }); + .then(() => saveAllChanged()) + .then(() => { + savePackage(store, s); + }); return s; }) @@ -546,7 +549,7 @@ const renameScreen = store => (oldname, newname) => { const savePage = store => async page => { store.update(s => { - if(s.currentFrontEndType !== "page" || !s.currentPageName) { + if (s.currentFrontEndType !== "page" || !s.currentPageName) { return s; } @@ -558,26 +561,26 @@ const savePage = store => async page => { const addComponentLibrary = store => async lib => { - const response = - await api.get(`/_builder/api/${appname}/componentlibrary?lib=${encodeURI(lib)}`,undefined, false); + const response = + await api.get(`/_builder/api/${appname}/componentlibrary?lib=${encodeURI(lib)}`, undefined, false); const success = response.status === 200; - const error = response.status === 404 - ? `Could not find library ${lib}` - : success - ? "" - : response.statusText; - + const error = response.status === 404 + ? `Could not find library ${lib}` + : success + ? "" + : response.statusText; + const components = success - ? await response.json() - : []; + ? await response.json() + : []; store.update(s => { - if(success) { - + if (success) { + const componentsArray = []; - for(let c in components) { + for (let c in components) { componentsArray.push(components[c]); } @@ -592,18 +595,18 @@ const addComponentLibrary = store => async lib => { return s; }) - + } const removeComponentLibrary = store => lib => { store.update(s => { - - + + s.pages.componentLibraries = filter(l => l !== lib)( - s.pages.componentLibraries); + s.pages.componentLibraries); savePackage(store, s); - + return s; }) @@ -627,12 +630,12 @@ const removeStylesheet = store => stylesheet => { const refreshComponents = store => async () => { - const componentsAndGenerators = + const componentsAndGenerators = await api.get(`/_builder/api/${db.appname}/components`).then(r => r.json()); const components = pipe(componentsAndGenerators.components, [ keys, - map(k => ({...componentsAndGenerators[k], name:k})) + map(k => ({ ...componentsAndGenerators[k], name: k })) ]); store.update(s => { @@ -648,25 +651,25 @@ const refreshComponents = store => async () => { const savePackage = (store, s) => { const appDefinition = { - hierarchy:s.hierarchy, - triggers:s.triggers, + hierarchy: s.hierarchy, + triggers: s.triggers, actions: keyBy("name")(s.actions), props: { main: buildPropsHierarchy( - s.components, - s.screens, - s.pages.main.appBody), - unauthenticated: buildPropsHierarchy( - s.components, - s.screens, - s.pages.unauthenticated.appBody) + s.components, + s.screens, + s.pages.main.appBody), + unauthenticated: buildPropsHierarchy( + s.components, + s.screens, + s.pages.unauthenticated.appBody) } }; const data = { appDefinition, - accessLevels:s.accessLevels, - pages:s.pages, + accessLevels: s.accessLevels, + pages: s.pages, } return api.post(`/_builder/api/${s.appname}/appPackage`, data); @@ -689,3 +692,44 @@ const setCurrentPage = store => pageName => { 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); + }) +} diff --git a/packages/builder/src/common/Icons/Image.svelte b/packages/builder/src/common/Icons/Image.svelte new file mode 100644 index 0000000000..8a07fedbdc --- /dev/null +++ b/packages/builder/src/common/Icons/Image.svelte @@ -0,0 +1,4 @@ + diff --git a/packages/builder/src/common/Icons/Input.svelte b/packages/builder/src/common/Icons/Input.svelte new file mode 100644 index 0000000000..58c44466cf --- /dev/null +++ b/packages/builder/src/common/Icons/Input.svelte @@ -0,0 +1,4 @@ + diff --git a/packages/builder/src/common/Icons/index.js b/packages/builder/src/common/Icons/index.js index 73f4500f7b..7ab39dfdd0 100644 --- a/packages/builder/src/common/Icons/index.js +++ b/packages/builder/src/common/Icons/index.js @@ -1,3 +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'; diff --git a/packages/builder/src/userInterface/ComponentHierarchyChildren.svelte b/packages/builder/src/userInterface/ComponentHierarchyChildren.svelte new file mode 100644 index 0000000000..fc9c664325 --- /dev/null +++ b/packages/builder/src/userInterface/ComponentHierarchyChildren.svelte @@ -0,0 +1,24 @@ + + +{#each components as component} +