Remove validation, use references rather than clones where possible, prioritise side-panel working with components for now.

This commit is contained in:
pngwn 2020-01-24 14:30:17 +00:00
parent d78f8013b5
commit 044edb1aca
9 changed files with 73 additions and 385 deletions

View File

@ -93,7 +93,8 @@ export const getStore = () => {
store.createGeneratedComponents = createGeneratedComponents(store);
store.addChildComponent = addChildComponent(store);
store.selectComponent = selectComponent(store);
store.saveComponent = saveComponent(store);
store.updateComponentProp = updateComponentProp(store);
return store;
}
@ -137,6 +138,7 @@ const initialise = (store, initial) => async () => {
shadowHierarchy, initial.currentNode.nodeId
);
}
console.log(initial)
store.set(initial);
return initial;
}
@ -701,19 +703,16 @@ const addChildComponent = store => component => {
const children = s.currentFrontEndItem.props._children;
const component_definition = {
...newComponent.fullProps,
const component_definition = Object.assign(
cloneDeep(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];
console.log(component_definition)
return s;
})
@ -721,15 +720,20 @@ const addChildComponent = store => component => {
const selectComponent = store => component => {
store.update(s => {
s.currentComponentInfo = getComponentInfo(s.components, component);
s.currentComponentInfo = component;
console.log(s)
return s;
})
}
const saveComponent = store => component => {
const updateComponentProp = store => (name, value) => {
store.update(s => {
s.currentComponentInfo = getComponentInfo(s.components, component);
console.log(s.currentFrontEndItem, s.screens)
return _saveScreen(store, s, s.currentFrontEndItem);
const current_component = s.currentComponentInfo;
s.currentComponentInfo[name] = value;
_saveScreen(store, s, s.currentFrontEndItem);
s.currentComponentInfo = current_component;
return s;
})
}

View File

@ -5,13 +5,10 @@ import { store } from "../builderStore";
import { isRootComponent } from "./pagesParsing/searchComponents";
import IconButton from "../common/IconButton.svelte";
import Textbox from "../common/Textbox.svelte";
// import UIkit from "uikit";
import { pipe } from "../common/core";
import {
getScreenInfo
} from "./pagesParsing/createProps";
// import Button from "../common/Button.svelte";
// import ButtonGroup from "../common/ButtonGroup.svelte";
import { LayoutIcon, PaintIcon, TerminalIcon } from '../common/Icons/';
import CodeEditor from './CodeEditor.svelte';
import LayoutEditor from './LayoutEditor.svelte';
@ -32,18 +29,18 @@ let name = "";
let description = "";
let tagsString = "";
let nameInvalid = "";
let componentInfo;
let componentInfo = {};
let modalElement
let propsValidationErrors = [];
let originalName="";
let components;
let ignoreStore = false;
$: shortName = last(name.split("/"));
// $: shortName = last(name.split("/"));
store.subscribe(s => {
if(ignoreStore) return;
component = s.currentComponentInfo.component;
component = s.currentComponentInfo;
if(!component) return;
originalName = component.name;
name = component.name;
@ -53,100 +50,12 @@ store.subscribe(s => {
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.saveComponent(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 newComponent = cloneDeep(component);
component = doChange(newComponent);
console.log(component, $store.screens[0].props._children[1])
componentInfo = getScreenInfo(components, newComponent);
}
const onPropsChanged = newProps => {
updateComponent(newComponent =>
assign(newComponent, newProps))
save();
}
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();
// }
const onPropsChanged = store.updateComponentProp;
let current_view = 'props';
</script>
<div class="root">
<!-- <div class="title">
<div>{shortName}</div>
<div>
<IconButton icon="save"
on:click={save}
color="var(--secondary100)"
hoverColor="var(--primary100)"/>
<IconButton icon="trash"
on:click={deleteComponent}
color="var(--secondary100)"
hoverColor="var(--primary100)"/>
</div>
</div> -->
<ul>
<li>
<button class:selected={current_view === 'props'} on:click={() => current_view = 'props'}>
@ -165,52 +74,25 @@ let current_view = 'props';
</li>
</ul>
<div class="component-props-container">
{#if !componentInfo.component}
<div class="component-props-container">
{#if current_view === 'props'}
<PropsView onValidate={onPropsValidate}
{componentInfo}
{onPropsChanged} />
{:else if current_view === 'layout'}
<LayoutEditor />
{:else}
<CodeEditor />
{/if}
{#if current_view === 'props'}
<PropsView {componentInfo} {components} {onPropsChanged} />
{:else if current_view === 'layout'}
<LayoutEditor />
{:else}
<CodeEditor />
{/if}
</div>
</div>
{:else}
<h1> This is a screen, this will be dealt with later</h1>
{/if}
</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> -->
<style>
.root {

View File

@ -1,5 +1,5 @@
<script>
import ComponentHierarchyChildren from './ComponentHierarchyChildren.svelte';
import ComponentsHierarchyChildren from './ComponentsHierarchyChildren.svelte';
import {
last,
@ -19,14 +19,8 @@ import getIcon from "../common/icon";
import { store } from "../builderStore";
export let components = []
export let thisLevel = "";
let pathPartsThisLevel;
let componentsThisLevel;
let _components;
let subfolders;
let expandedFolders = [];
const joinPath = join("/");
@ -37,40 +31,9 @@ const normalizedName = name => pipe(name, [
trimChars(" ")
]);
const isOnThisLevel = (c) =>
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 ? c.name.split("/") : c._component.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 expandedFolder = {...folder};
if(expandedFolder.isExpanded) {
@ -99,42 +62,21 @@ const isFolderSelected = (current, folder) =>
$: {
pathPartsThisLevel = !thisLevel
? 1
: normalizedName(thisLevel).split("/").length + 1;
_components =
$: _components =
pipe(components, [
// filter(isOnThisLevel),
map(c => ({component: c, title:lastPartOfName(c)})),
sortBy("title")
]);
// subfolders =
// pipe(components, [
// filter(notOnThisLevel),
// sortBy("name"),
// map(subFolder),
// uniqWith((f1,f2) => f1.path === f2.path)
// ]);
function select_component(screen, component) {
store.setCurrentScreen(screen);
store.selectComponent(component);
}
</script>
<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 _components as component}
<div class="hierarchy-item component"
@ -144,7 +86,8 @@ $: {
<span class="title">{component.title}</span>
</div>
{#if component.component.props && component.component.props._children}
<ComponentHierarchyChildren components={component.component.props._children} onSelect={store.selectComponent}/>
<ComponentsHierarchyChildren components={component.component.props._children}
onSelect={component =>select_component(component.component.name, component)} />
{/if}
{/each}

View File

@ -13,7 +13,7 @@
{#each components as component}
<ul>
<li on:click|stopPropagation={() => onSelect(component)}>
{get_capitalised_name(component.name)}
{get_capitalised_name(component._component)}
{#if component._children}
<svelte:self components={component._children}/>

View File

@ -81,9 +81,6 @@ let current_view = 'text';
<div class="name">
{splitName(component.name).componentName}
</div>
<!-- <div class="description">
{component.description}
</div> -->
</div>
{/each}

View File

@ -51,43 +51,6 @@ store.subscribe(s => {
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 newComponent = cloneDeep(component);
doChange(newComponent);
@ -98,47 +61,12 @@ const updateComponent = doChange => {
const onPropsChanged = newProps => {
updateComponent(newComponent =>
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>
<div class="root">
<!-- <div class="title">
<div>{shortName}</div>
<div>
<IconButton icon="save"
on:click={save}
color="var(--secondary100)"
hoverColor="var(--primary100)"/>
<IconButton icon="trash"
on:click={deleteComponent}
color="var(--secondary100)"
hoverColor="var(--primary100)"/>
</div>
</div> -->
<ul>
<li><button><PaintIcon /></button></li>
<li><button><LayoutIcon /></button></li>
@ -148,7 +76,7 @@ const showDialog = () => {
<div class="component-props-container">
<PropsView onValidate={onPropsValidate}
<PropsView
{componentInfo}
{onPropsChanged} />
@ -157,36 +85,6 @@ const showDialog = () => {
</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>
<style>
.root {

View File

@ -5,6 +5,7 @@ import {
filter
} from "lodash/fp";
import {EVENT_TYPE_MEMBER_NAME} from "../common/eventHandlers";
export let parentProps;
export let propDef;
export let onValueChanged;
@ -58,7 +59,7 @@ const removeHandler = (index) => () => {
<div class="addelement-container"
on:click={addHandler}>
<IconButton icon="plus"
<IconButton icon="plus"
size="12"/>
</div>
</div>

View File

@ -6,13 +6,12 @@ import Dropdown from "../common/Dropdown.svelte";
import EventListSelector from "./EventListSelector.svelte";
import StateBindingControl from "./StateBindingControl.svelte";
export let errors = [];
export let setProp = () => {};
export let fieldHasError =() => {};
export let propDef = {};
export let props = {};
export let disabled;
export let index;
export let prop_name;
export let prop_value;
export let prop_type = {};
$: isOdd = (index % 2 !== 0);
@ -25,20 +24,20 @@ const setComponentProp = (props) => {
<div class="root" >
{#if propDef.type === "event"}
{#if prop_type === "event"}
<h5>{propDef.____name}</h5>
<!-- <h5>{prop_name}</h5>
<EventListSelector parentProps={props}
{propDef}
onValueChanged={setComponentProp} />
onValueChanged={setComponentProp} /> -->
{:else }
<h5>{propDef.____name}</h5>
<StateBindingControl value={props[propDef.____name]}
type={propDef.type}
options={propDef.options}
onChanged={v => setProp(propDef.____name, v)}/>
<h5>{prop_name}</h5>
<StateBindingControl value={prop_value}
type={prop_type}
options={prop_type.options}
onChanged={v => setProp(prop_name, v)}/>
{/if}

View File

@ -10,66 +10,30 @@ import { getInstanceProps } from "./pagesParsing/createProps";
import Checkbox from "../common/Checkbox.svelte";
import Textbox from "../common/Textbox.svelte";
import Dropdown from "../common/Dropdown.svelte";
import { validateProps } from "./pagesParsing/validateProps";
import PropControl from "./PropControl.svelte";
import IconButton from "../common/IconButton.svelte";
export let shouldValidate = true;
export let onValidate = () => {};
export let componentInfo;
export let instanceProps = null;
export let onPropsChanged = () => {};
export let components;
let errors = [];
let props = {};
let propsDefinitions = [];
let isInstance = false;
$: {
if(componentInfo)
{
isInstance = !!instanceProps;
props = isInstance
? getInstanceProps(componentInfo, instanceProps)
: cloneDeep(componentInfo.fullProps);
const props_to_ignore = ['_component','_children', '_layout'];
propsDefinitions = pipe(componentInfo.propsDefinition.props, [
keys,
map(k => ({...componentInfo.propsDefinition[k], ____name:k})),
sortBy("____name")
]);
}
$: propDefs = componentInfo && Object.entries(componentInfo).filter(([name])=> !props_to_ignore.includes(name));
function find_type(prop_name) {
if(!componentInfo._component) return;
return components.find(({name}) => name === componentInfo._component).props[prop_name];
}
let setProp = (name, value) => {
const newProps = cloneDeep(props);
let finalProps = isInstance ? newProps : cloneDeep(componentInfo.component.props ? componentInfo.component.props : componentInfo.component);
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;
onPropsChanged(name, value);
}
const fieldHasError = (propName) =>
@ -80,18 +44,18 @@ const fieldHasError = (propName) =>
<div class="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">
<div class="prop-container">
<PropControl {setProp}
{fieldHasError}
{propDef}
{props}
{index}
disabled={false} />
<PropControl {setProp}
{prop_name}
{prop_value}
prop_type={find_type(prop_name)}
{index}
disabled={false} />
</div>
</div>
{/each}