diff --git a/packages/builder/src/builderStore/store.js b/packages/builder/src/builderStore/store.js index a6a681b469..a810f36afb 100644 --- a/packages/builder/src/builderStore/store.js +++ b/packages/builder/src/builderStore/store.js @@ -26,6 +26,10 @@ import {writable} from "svelte/store"; import { defaultPagesObject } from "../userInterface/pagesParsing/defaultPagesObject" import api from "./api"; import { isRootComponent } from "../userInterface/pagesParsing/searchComponents"; +import { + getComponentInfo, + getNewComponentInfo +} from "../userInterface/pagesParsing/createProps"; export const getStore = () => { @@ -40,6 +44,8 @@ export const getStore = () => { unauthenticatedUi:{}, allComponents:[], currentFrontEndItem:null, + currentComponentInfo:null, + currentComponentIsNew:false, currentNodeIsNew: false, errors: [], activeNav: "database", @@ -75,6 +81,7 @@ export const getStore = () => { store.deleteDerivedComponent = deleteDerivedComponent(store); store.setCurrentComponent = setCurrentComponent(store); store.setCurrentPage = setCurrentPage(store); + store.createDerivedComponent = createDerivedComponent(store); return store; } @@ -384,6 +391,18 @@ const saveDerivedComponent = store => (derivedComponent) => { }) }; +const createDerivedComponent = store => (componentName) => { + store.update(s => { + const newComponentInfo = getNewComponentInfo( + s.allComponents, componentName); + + s.currentFrontEndItem = newComponentInfo.component; + s.currentComponentInfo = newComponentInfo; + s.currentComponentIsNew = true; + return s; + }); +} + const deleteDerivedComponent = store => name => { store.update(s => { @@ -392,6 +411,9 @@ const deleteDerivedComponent = store => name => { ]); s.allComponents = allComponents; + if(s.currentFrontEndItem.name === name) { + s.currentFrontEndItem = null; + } api.delete(`/_builder/api/${s.appname}/derivedcomponent/${name}`); @@ -502,6 +524,8 @@ const setCurrentComponent = store => component => { store.update(s => { s.currentFrontEndItem = component; s.currentFrontEndIsComponent = true; + s.currentComponentIsNew = false; + s.currentComponentInfo = getComponentInfo(s.allComponents, component.name); return s; }) } diff --git a/packages/builder/src/common/IconButton.svelte b/packages/builder/src/common/IconButton.svelte index 5880cd90bc..ea520cfa17 100644 --- a/packages/builder/src/common/IconButton.svelte +++ b/packages/builder/src/common/IconButton.svelte @@ -40,7 +40,7 @@ const addAttributes = (node, attributes) => { - + + + + {/if} + + + + + + \ No newline at end of file diff --git a/packages/builder/src/userInterface/ComponentSearch.svelte b/packages/builder/src/userInterface/ComponentSearch.svelte index fb182ec722..f580dbb604 100644 --- a/packages/builder/src/userInterface/ComponentSearch.svelte +++ b/packages/builder/src/userInterface/ComponentSearch.svelte @@ -1,12 +1,17 @@ + +
+ +
+
{shortName}
+
+ + +
+
+ +
+ +
componentDetailsExpanded = !componentDetailsExpanded}> + Component Details + +
+ + {#if componentDetailsExpanded} +
+ +
+ + + +
+ {/if} + +

Properties

+ + + + + +
+ +
+ + +
+
+ +
+ Delete {component.name} ? +
+ +
+ Are you sure you want to delete this component ? +
+ + + +
+ +
+ + \ No newline at end of file diff --git a/packages/builder/src/userInterface/NewComponent.svelte b/packages/builder/src/userInterface/NewComponent.svelte index b3e5d0ec38..2ba79f2da2 100644 --- a/packages/builder/src/userInterface/NewComponent.svelte +++ b/packages/builder/src/userInterface/NewComponent.svelte @@ -23,66 +23,26 @@ import { } from "lodash/fp"; import { assign } from "lodash"; -let component; + + let modalElement; -let errors = {}; -let componentInfo; +let allComponents; -let name = ""; -let description = ""; -let tagsString = ""; -let propsValidationErrors = []; -let inheritedProps; -let nameInvalid = ""; -let propsDefinition; +store.subscribe(s => { + allComponents = s.allComponents; +}) -const onBasedOnChosen = (allComponents) => (c) => { - componentInfo = getNewComponentInfo(allComponents, c.name); - tagsString = join(", ")(componentInfo.component.tags); - inheritedProps = componentInfo.inheritedProps; - propsDefinition = componentInfo.propsDefinition; - component = componentInfo.component; -} - -const createComponent = () => { - - if(!validate()) return; - - component.name = name; - component.description = description; - component.tags = pipe(tagsString, [ - split(","), - map(s => s.trim()) - ]); - - store.saveDerivedComponent(component); - close(); -} - -const close = () => { - component = null; - componentInfo = null; +export const close = () => { UIkit.modal(modalElement).hide(); } -const onPropsValidate = result => { - propsValidationErrors = result; +export const show = () => { + UIkit.modal(modalElement).show(); } -const onPropsChanged = props => { - assign(component.props, props); -} - -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 onComponentChosen = (c) => { + store.createDerivedComponent(c.name); + close(); } @@ -95,49 +55,8 @@ const validate = () => {
-
- {#if componentInfo} - - -
- - -

Properties

- - - - {:else} - - - - - - {/if} - +
- {#if component} - - {/if} @@ -146,8 +65,4 @@ h1 { font-size:1.2em; } -.props-header { - font-style: italic; -} - \ No newline at end of file diff --git a/packages/builder/src/userInterface/PropControl.svelte b/packages/builder/src/userInterface/PropControl.svelte new file mode 100644 index 0000000000..009fd9d780 --- /dev/null +++ b/packages/builder/src/userInterface/PropControl.svelte @@ -0,0 +1,54 @@ + + + +
+ + + {#if propDef.type === "bool"} + setProp(propDef.____name, ev.target.checked)} + hasError={fieldHasError(propDef.____name)} /> + {:else if propDef.type === "options"} + setProp(propDef.____name, ev.target.value)} + hasError={fieldHasError(propDef.____name)}/> + {:else if propDef.type === "component"} + setProp(propDef.____name, props)}/> + {:else} + setProp(propDef.____name, ev.target.value)} + margin={false} + hasError={fieldHasError(propDef.____name)} + {disabled}/> + {/if} + +
+ + \ No newline at end of file diff --git a/packages/builder/src/userInterface/PropsView.svelte b/packages/builder/src/userInterface/PropsView.svelte index 112ca0c8fc..e0d191bbd9 100644 --- a/packages/builder/src/userInterface/PropsView.svelte +++ b/packages/builder/src/userInterface/PropsView.svelte @@ -6,58 +6,66 @@ import { some, includes, cloneDeep, - isEqual + isEqual, + sortBy, + filter } from "lodash/fp"; import { pipe } from "../common/core"; -import { getComponentInfo } from "./pagesParsing/createProps"; +import { + getComponentInfo , + getInstanceProps +} from "./pagesParsing/createProps"; import { getExactComponent } from "./pagesParsing/searchComponents"; import Checkbox from "../common/Checkbox.svelte"; import Textbox from "../common/Textbox.svelte"; import Dropdown from "../common/Dropdown.svelte"; import { validateProps } from "./pagesParsing/validateProps"; +import ComponentPropSelector from "./ComponentPropSelector.svelte"; +import PropControl from "./PropControl.svelte"; +import IconButton from "../common/IconButton.svelte"; -export let allComponents; export let shouldValidate = true; export let onValidate = () => {}; -export let showTitle = true; export let componentInfo; -export let component; +export let instanceProps = null; export let onPropsChanged = () => {}; let errors = []; -let fields = []; let props = {}; -let propsDefinitionArray = []; - -$: { - if(componentInfo || component) - { - if(!componentInfo || (component && - component.name !== componentInfo.component.name)) { - componentInfo = getComponentInfo(allComponents, component.name); - } - - props = cloneDeep(componentInfo.fullProps); - - propsDefinitionArray = pipe(componentInfo.propsDefinition, [ - keys, - map(k => ({...componentInfo.propsDefinition[k], ____name:k})) - ]); - - fields = pipe(componentInfo.propsDefinition,[ - keys, - map(k => componentInfo.propsDefinition[k]) - ]); - } -} +let propsDefinitions = []; +let inheritedPropsDefinitions = []; +let inheritedExpanded = false; const isPropInherited = name => includes(name)(componentInfo.inheritedProps); -let setProp = (name) => (ev, targetValue="value") => { +$: { + if(componentInfo) + { + props = instanceProps + ? getInstanceProps(componentInfo, instanceProps) + : cloneDeep(componentInfo.fullProps); + + propsDefinitions = pipe(componentInfo.propsDefinition, [ + keys, + filter(k => !isPropInherited(k)), + map(k => ({...componentInfo.propsDefinition[k], ____name:k})), + sortBy("____name") + ]); + + inheritedPropsDefinitions = pipe(componentInfo.propsDefinition, [ + keys, + filter(k => isPropInherited(k)), + map(k => ({...componentInfo.propsDefinition[k], ____name:k})), + sortBy("____name") + ]); + } +} + + +let setProp = (name, value) => { const newProps = cloneDeep(props); - newProps[name] = ev.target[targetValue]; - + newProps[name] = value; const finalProps = {}; @@ -82,37 +90,48 @@ const validate = (finalProps) => { const fieldHasError = (propName) => some(e => e.propName === propName)(errors); +
- {#if showTitle=true} -
{componentInfo.component.name}
-
{componentInfo.component.description || ""}
- {/if} - {#each propsDefinitionArray as propDef} -
- {#if propDef.type === "bool"} - - {:else if propDef.type === "options"} - - {:else} - - {/if} + + {#each propsDefinitions as propDef} + + + + {/each} + + {#if inheritedPropsDefinitions.length > 0} +
+
Inherited
+
+ inheritedExpanded = !inheritedExpanded}/> +
+
+ {/if} + + {#if inheritedExpanded} + {#each inheritedPropsDefinitions as propDef} + + + + {/each} + {/if} - {/each} + +
@@ -124,19 +143,24 @@ const fieldHasError = (propName) => font-size:10pt; } -.title { - font-size: 1.2em; - font-weight: bold; +.inherited-title { + margin-top: 40px; + display: grid; + grid-template-columns: [name] 1fr [actions] auto; + border-style: solid; + border-width: 0px 0px 1px 0px; + border-color: var(--lightslate); + font-style: italic; } -.prop-row { - padding: 7px 3px; -} - -.component-description { - font-size: 0.9em; +.inherited-title > div:nth-child(1) { + grid-column-start: name; color: var(--slate); - margin-bottom: 10px; +} + +.inherited-title > div:nth-child(2) { + grid-column-start: actions; + color: var(--secondary100); } \ No newline at end of file diff --git a/packages/builder/src/userInterface/UserInterfaceRoot.svelte b/packages/builder/src/userInterface/UserInterfaceRoot.svelte index 3f082b5510..04d7e1e1d6 100644 --- a/packages/builder/src/userInterface/UserInterfaceRoot.svelte +++ b/packages/builder/src/userInterface/UserInterfaceRoot.svelte @@ -2,7 +2,7 @@ import ComponentsHierarchy from "./ComponentsHierarchy.svelte"; import PagesList from "./PagesList.svelte" -import PropsView from "./PropsView.svelte"; +import EditComponent from "./EditComponent.svelte"; import { store } from "../builderStore"; import getIcon from "../common/icon"; import { isRootComponent } from "./pagesParsing/searchComponents"; @@ -10,9 +10,9 @@ import IconButton from "../common/IconButton.svelte"; import Modal from "../common/Modal.svelte"; import NewComponent from "./NewComponent.svelte"; -let isCreatingNewComponent = false; +let newComponentPicker; const newComponent = () => { - isCreatingNewComponent = true; + newComponentPicker.show(); } @@ -27,8 +27,7 @@ const newComponent = () => { COMPONENTS
+ on:click={newComponent}/>
- +