basic architecture complete
This commit is contained in:
parent
e54fd6a0d9
commit
f0e07cdfca
|
@ -0,0 +1,23 @@
|
|||
<style>
|
||||
button {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
background: var(--background-button);
|
||||
|
||||
width: 1.8rem;
|
||||
height: 1.8rem;
|
||||
padding-bottom: 10px;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
color: var(--button-text);
|
||||
}
|
||||
</style>
|
||||
|
||||
<button on:click>+</button>
|
|
@ -1,110 +0,0 @@
|
|||
<script>
|
||||
import IconButton from "../../common/IconButton.svelte";
|
||||
import StateBindingControl from "./StateBindingControl.svelte";
|
||||
import { find, map, keys, reduce, keyBy } from "lodash/fp";
|
||||
import { pipe, userWithFullAccess } from "../../common/core";
|
||||
import {
|
||||
EVENT_TYPE_MEMBER_NAME,
|
||||
allHandlers
|
||||
} from "../../common/eventHandlers";
|
||||
import { store } from "../../builderStore";
|
||||
|
||||
export let event;
|
||||
export let onChanged;
|
||||
export let onRemoved;
|
||||
|
||||
let events;
|
||||
let eventType;
|
||||
let parameters = [];
|
||||
|
||||
store.subscribe(s => {
|
||||
events = allHandlers(
|
||||
{ hierarchy: s.hierarchy },
|
||||
userWithFullAccess({
|
||||
hierarchy: s.hierarchy,
|
||||
actions: keyBy("name")(s.actions)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// TODO: refactor
|
||||
$: {
|
||||
if (event) {
|
||||
eventType = event[EVENT_TYPE_MEMBER_NAME];
|
||||
|
||||
parameters = pipe(
|
||||
event.parameters,
|
||||
[keys, map(key => ({ name: key, value: event.parameters[key] }))]
|
||||
);
|
||||
} else {
|
||||
eventType = "";
|
||||
parameters = [];
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: refactor
|
||||
const eventChanged = (type, parameters) => {
|
||||
const paramsAsObject = reduce((obj, p) => {
|
||||
obj[p.name] = p.value;
|
||||
return obj;
|
||||
}, {})(parameters);
|
||||
|
||||
const ev = {};
|
||||
ev[EVENT_TYPE_MEMBER_NAME] = type;
|
||||
ev.parameters = paramsAsObject;
|
||||
|
||||
onChanged(ev);
|
||||
};
|
||||
|
||||
// TODO: refactor
|
||||
const eventTypeChanged = ev => {
|
||||
const eType = find(e => e.name === ev.target.value)(events);
|
||||
const emptyParameters = map(p => ({ name: p, value: "" }))(
|
||||
eType.parameters
|
||||
);
|
||||
eventChanged(eType.name, emptyParameters);
|
||||
};
|
||||
|
||||
const onParameterChanged = index => val => {
|
||||
const newparameters = [...parameters];
|
||||
newparameters[index].value = val;
|
||||
eventChanged(eventType, newparameters);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.type-selector-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.type-selector {
|
||||
border-color: var(--primary50);
|
||||
border-radius: 2px;
|
||||
width: 50px;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="type-selector-container">
|
||||
<select
|
||||
class="type-selector uk-select uk-form-small "
|
||||
value={eventType}
|
||||
on:change={eventTypeChanged}>
|
||||
<option />
|
||||
{#each events as ev}
|
||||
<option value={ev.name}>{ev.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
|
||||
<IconButton icon="trash" size="12" on:click={onRemoved} />
|
||||
|
||||
</div>
|
||||
|
||||
{#if parameters}
|
||||
{#each parameters as p, index}
|
||||
<div>{p.name}</div>
|
||||
<StateBindingControl
|
||||
onChanged={onParameterChanged(index)}
|
||||
value={p.value} />
|
||||
{/each}
|
||||
{/if}
|
|
@ -14,9 +14,10 @@
|
|||
import Checkbox from "../../common/Checkbox.svelte";
|
||||
import Textbox from "../../common/Textbox.svelte";
|
||||
import Dropdown from "../../common/Dropdown.svelte";
|
||||
import PlusButton from "../../common/PlusButton.svelte";
|
||||
import IconButton from "../../common/IconButton.svelte";
|
||||
import Modal from "../../common/Modal.svelte";
|
||||
import EventSelector from "./EventSelector.svelte";
|
||||
import HandlerSelector from "./HandlerSelector.svelte";
|
||||
|
||||
import { PencilIcon } from "../../common/Icons";
|
||||
import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers";
|
||||
|
@ -27,12 +28,28 @@
|
|||
export let onPropChanged = () => {};
|
||||
export let components;
|
||||
|
||||
// Structure
|
||||
// {
|
||||
// [eventName]: [{eventHandler}, {eventHandler1}],
|
||||
// [eventName1]: [{eventHandler}, {eventHandler1}],
|
||||
// }
|
||||
|
||||
let modalOpen = false;
|
||||
let events = [];
|
||||
let selectedEvent = null;
|
||||
let selectedEvent = {};
|
||||
let newEventType = "onClick";
|
||||
|
||||
// TODO: only show events that have handlers
|
||||
|
||||
// $: {
|
||||
// let componentEvents = {};
|
||||
// for (let propName in componentInfo) {
|
||||
// const isEventProp = findType(propName) === EVENT_TYPE;
|
||||
// if (isEventProp) componentEvents[propName] = componentInfo[propName];
|
||||
// }
|
||||
// events = componentEvents;
|
||||
// }
|
||||
|
||||
$: events =
|
||||
componentInfo &&
|
||||
Object.entries(componentInfo).filter(
|
||||
|
@ -47,7 +64,7 @@
|
|||
.props[propName];
|
||||
}
|
||||
|
||||
console.log(componentInfo, events, components);
|
||||
console.log({ componentInfo, events, components });
|
||||
|
||||
const openModal = event => {
|
||||
selectedEvent = event;
|
||||
|
@ -55,30 +72,47 @@
|
|||
};
|
||||
|
||||
const closeModal = () => {
|
||||
selectedEvent = null;
|
||||
selectedEvent = {};
|
||||
modalOpen = false;
|
||||
};
|
||||
|
||||
const addEventHandler = event => {
|
||||
const addEventHandler = eventType => {
|
||||
const newEventHandler = {
|
||||
parameters: {},
|
||||
[EVENT_TYPE_MEMBER_NAME]: ""
|
||||
};
|
||||
events = [...events, newEventHandler];
|
||||
onPropChanged(newEventType, events);
|
||||
// TODO: improve - just pass the event from props
|
||||
selectedEvent = {
|
||||
...selectedEvent,
|
||||
handlers: [...(selectedEvent.handlers || []), newEventHandler]
|
||||
};
|
||||
// events = [...events, newEventHandler];
|
||||
onPropChanged(newEventType, [...selectedEvent.handlers, newEventHandler]);
|
||||
};
|
||||
|
||||
const changeEventHandler = newEvent => {
|
||||
console.log({ events, newEventType, newEvent });
|
||||
onPropChanged(newEventType, events);
|
||||
const changeEventHandler = (updatedHandler, index) => {
|
||||
// TODO: Improve
|
||||
const handlers = [...selectedEvent.handlers];
|
||||
handlers[index] = updatedHandler;
|
||||
|
||||
console.log("CHANGED HANDLERS", handlers);
|
||||
|
||||
selectedEvent = {
|
||||
...selectedEvent,
|
||||
handlers
|
||||
};
|
||||
|
||||
onPropChanged(newEventType, handlers);
|
||||
};
|
||||
|
||||
const removeEventHandler = index => () => {
|
||||
events = filter(e => e !== events[index])(events);
|
||||
onPropChanged(newEventType, []);
|
||||
// TODO: verify
|
||||
const removeEventHandler = index => {
|
||||
const handlers = [...selectedEvent.handlers];
|
||||
handlers.splice(index, 1);
|
||||
onPropChanged(newEventType, handlers);
|
||||
};
|
||||
|
||||
console.log(events);
|
||||
console.log("DA HANDLERS", selectedEvent.handlers);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -104,46 +138,119 @@
|
|||
flex: 1 1 auto;
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
.heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.handler-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-gap: 10px;
|
||||
border: 2px solid #fafafa;
|
||||
}
|
||||
|
||||
.hierarchy-item {
|
||||
cursor: pointer;
|
||||
padding: 11px 7px;
|
||||
margin: 5px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.hierarchy-item:hover {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.selected {
|
||||
color: var(--button-text);
|
||||
background: var(--background-button) !important;
|
||||
}
|
||||
|
||||
.event-name {
|
||||
}
|
||||
|
||||
.handler-identifier {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: var(--primary100);
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* TODO: Should be it's own component */
|
||||
input {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #163057;
|
||||
opacity: 0.7;
|
||||
padding: 5px 10px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #dbdbdb;
|
||||
border-radius: 2px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.event-action {
|
||||
background: #fafafa;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h3>Events</h3>
|
||||
<div class="heading">
|
||||
<h3>Events</h3>
|
||||
<PlusButton on:click={() => openModal({})} />
|
||||
</div>
|
||||
|
||||
<div class="root">
|
||||
|
||||
<form class="uk-form-stacked form-root">
|
||||
{#each events as event, index}
|
||||
<div class="prop-container">
|
||||
{event[0]}
|
||||
<PencilIcon on:click={() => openModal({ ...event, index })} />
|
||||
</div>
|
||||
{#each events as [name, handlers], index}
|
||||
{#if handlers.length > 0}
|
||||
<div
|
||||
class="handler-container hierarchy-item"
|
||||
on:click={() => openModal({ name, handlers, index })}>
|
||||
<span class="event-name">{name}</span>
|
||||
<span class="edit-text">EDIT</span>
|
||||
<span class="handler-identifier">updateState</span>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</form>
|
||||
<button on:click={() => openModal()}>Create Event</button>
|
||||
</div>
|
||||
<Modal bind:isOpen={modalOpen} onClosed={closeModal}>
|
||||
<h2>{action} Event</h2>
|
||||
{#if selectedEvent}
|
||||
{JSON.stringify(selectedEvent)}
|
||||
<!-- <EventSelector
|
||||
onChanged={onEventHandlerChanged(selectedEvent)}
|
||||
onRemoved={removeHandler(selectedEvent && selectedEvent.index)}
|
||||
event={selectedEvent} />
|
||||
<div class="addelement-container" on:click={addHandler}>
|
||||
<IconButton icon="plus" size="12" />
|
||||
</div> -->
|
||||
{:else}
|
||||
<select bind:value={newEventType}>
|
||||
{#each events as [name]}
|
||||
<option value={name}>{name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<EventSelector
|
||||
onChanged={changeEventHandler}
|
||||
onRemoved={removeEventHandler}
|
||||
event={selectedEvent} />
|
||||
<div class="addelement-container" on:click={addEventHandler}>
|
||||
<IconButton icon="plus" size="12" />
|
||||
</div>
|
||||
<button>Save</button>
|
||||
<h2>Create a New Component Event</h2>
|
||||
<span>Click here to learn more about component events</span>
|
||||
|
||||
<h4>Event Name</h4>
|
||||
<input type="text" />
|
||||
|
||||
<h4>Event Type</h4>
|
||||
<select
|
||||
class="type-selector uk-select uk-form-small"
|
||||
bind:value={newEventType}>
|
||||
{#each events as [name]}
|
||||
<option value={name}>{name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
|
||||
<h4>Event Action(s)</h4>
|
||||
{#if selectedEvent.handlers}
|
||||
{#each selectedEvent.handlers as handler, index}
|
||||
<HandlerSelector
|
||||
{index}
|
||||
onChanged={changeEventHandler}
|
||||
onRemoved={removeEventHandler}
|
||||
{handler} />
|
||||
<hr />
|
||||
{/each}
|
||||
{/if}
|
||||
<div
|
||||
class="addelement-container"
|
||||
on:click={() => addEventHandler(newEventType)}>
|
||||
<IconButton icon="plus" size="12" />
|
||||
Add Handler
|
||||
</div>
|
||||
</Modal>
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
<script>
|
||||
import IconButton from "../../common/IconButton.svelte";
|
||||
import StateBindingControl from "./StateBindingControl.svelte";
|
||||
import { find, map, keys, reduce, keyBy } from "lodash/fp";
|
||||
import { pipe, userWithFullAccess } from "../../common/core";
|
||||
import {
|
||||
EVENT_TYPE_MEMBER_NAME,
|
||||
allHandlers
|
||||
} from "../../common/eventHandlers";
|
||||
import { store } from "../../builderStore";
|
||||
|
||||
export let handler;
|
||||
export let onChanged;
|
||||
export let onRemoved;
|
||||
export let index;
|
||||
|
||||
let eventOptions;
|
||||
let handlerType;
|
||||
let parameters = [];
|
||||
|
||||
$: eventOptions = allHandlers(
|
||||
{ hierarchy: $store.hierarchy },
|
||||
userWithFullAccess({
|
||||
hierarchy: $store.hierarchy,
|
||||
actions: keyBy("name")($store.actions)
|
||||
})
|
||||
);
|
||||
|
||||
// TODO: refactor
|
||||
$: {
|
||||
if (handler) {
|
||||
handlerType = handler[EVENT_TYPE_MEMBER_NAME];
|
||||
parameters = Object.entries(handler.parameters).map(([name, value]) => ({
|
||||
name,
|
||||
value
|
||||
}));
|
||||
} else {
|
||||
handlerType = "";
|
||||
parameters = [];
|
||||
}
|
||||
}
|
||||
|
||||
const handlerChanged = (type, params) => {
|
||||
const handlerParams = {};
|
||||
for (let param of params) {
|
||||
handlerParams[param.name] = param.value;
|
||||
}
|
||||
|
||||
const updatedHandler = {
|
||||
[EVENT_TYPE_MEMBER_NAME]: type,
|
||||
parameters: handlerParams
|
||||
};
|
||||
|
||||
onChanged(updatedHandler, index);
|
||||
};
|
||||
|
||||
const handlerTypeChanged = e => {
|
||||
const handlerType = eventOptions.find(
|
||||
handler => handler.name === e.target.value
|
||||
);
|
||||
// Set default params for handler
|
||||
const defaultParams = handlerType.parameters.map(param => ({
|
||||
name: param,
|
||||
value: ""
|
||||
}));
|
||||
handlerChanged(handlerType.name, defaultParams);
|
||||
};
|
||||
|
||||
const onParameterChanged = index => value => {
|
||||
const newParams = [...parameters];
|
||||
newParams[index].value = value;
|
||||
handlerChanged(handlerType, newParams);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.type-selector-container {
|
||||
display: grid;
|
||||
grid-template-rows: repeat(3, 1fr);
|
||||
background: #fafafa;
|
||||
padding: 22px;
|
||||
border: 1px solid var(--primary75);
|
||||
}
|
||||
|
||||
.type-selector {
|
||||
border-color: var(--primary50);
|
||||
border-radius: 2px;
|
||||
width: 50px;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="type-selector-container">
|
||||
Action
|
||||
<select
|
||||
class="type-selector uk-select uk-form-small "
|
||||
value={handlerType}
|
||||
on:change={handlerTypeChanged}>
|
||||
<option />
|
||||
{#each eventOptions as option}
|
||||
<option value={option.name}>{option.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{#if parameters}
|
||||
{#each parameters as param, index}
|
||||
<div>{param.name}</div>
|
||||
<StateBindingControl
|
||||
onChanged={onParameterChanged(index)}
|
||||
value={param.value} />
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
|
@ -1 +1,7 @@
|
|||
export const deleteElement = (array, index) => {
|
||||
const arr = [...array];
|
||||
array.splice(index, 1);
|
||||
return arr;
|
||||
};
|
||||
|
||||
export { default } from "./EventsEditor.svelte";
|
|
@ -14,7 +14,7 @@ module.exports = async (budibaseContext) => {
|
|||
app.context.master,
|
||||
config.latestPackagesFolder
|
||||
);
|
||||
app.use(koaBody({ multipart : true }));
|
||||
app.use(koaBody({ multipart: true }));
|
||||
app.use(router(config, app).routes());
|
||||
return app.listen(config.port);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue