merge
This commit is contained in:
parent
6aa6c4d433
commit
e54fd6a0d9
|
@ -0,0 +1,8 @@
|
|||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24">
|
||||
<path fill="none" d="M0 0h24v24H0z" />
|
||||
<path d="M13 10h7l-9 13v-9H4l9-13z" />
|
||||
</svg>
|
After Width: | Height: | Size: 181 B |
|
@ -0,0 +1,19 @@
|
|||
<svg
|
||||
on:click
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24">
|
||||
<path fill="none" d="M0 0h24v24H0z" />
|
||||
<path
|
||||
d="M15.728 9.686l-1.414-1.414L5
|
||||
17.586V19h1.414l9.314-9.314zm1.414-1.414l1.414-1.414-1.414-1.414-1.414 1.414
|
||||
1.414 1.414zM7.242 21H3v-4.243L16.435 3.322a1 1 0 0 1 1.414 0l2.829 2.829a1
|
||||
1 0 0 1 0 1.414L7.243 21z" />
|
||||
</svg>
|
||||
|
||||
<style>
|
||||
svg:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
After Width: | Height: | Size: 446 B |
|
@ -4,3 +4,5 @@ export { default as TerminalIcon } from './Terminal.svelte';
|
|||
export { default as InputIcon } from './Input.svelte';
|
||||
export { default as ImageIcon } from './Image.svelte';
|
||||
export { default as ArrowDownIcon } from './ArrowDown.svelte';
|
||||
export { default as EventsIcon } from './Events.svelte';
|
||||
export { default as PencilIcon } from './Pencil.svelte';
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
import PropsView from "./PropsView.svelte";
|
||||
import { store } from "../builderStore";
|
||||
import IconButton from "../common/IconButton.svelte";
|
||||
import { LayoutIcon, PaintIcon, TerminalIcon } from '../common/Icons/';
|
||||
import { LayoutIcon, PaintIcon, TerminalIcon, EventsIcon } from '../common/Icons/';
|
||||
import CodeEditor from './CodeEditor.svelte';
|
||||
import LayoutEditor from './LayoutEditor.svelte';
|
||||
import EventsEditor from "./EventsEditor";
|
||||
|
||||
let current_view = 'props';
|
||||
|
||||
|
@ -36,6 +37,11 @@
|
|||
<TerminalIcon />
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class:selected={current_view === 'events'} on:click={() => current_view = 'events'}>
|
||||
<EventsIcon />
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{#if !componentInfo.component}
|
||||
|
@ -45,6 +51,8 @@
|
|||
<PropsView {componentInfo} {components} {onPropChanged} />
|
||||
{:else if current_view === 'layout'}
|
||||
<LayoutEditor {onStyleChanged} {componentInfo}/>
|
||||
{:else if current_view === 'events'}
|
||||
<EventsEditor {componentInfo} {components} {onPropChanged} />
|
||||
{:else}
|
||||
<CodeEditor />
|
||||
{/if}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<script>
|
||||
import Modal from "../../common/Modal.svelte";
|
||||
import EventSelector from "../EventSelector.svelte";
|
||||
|
||||
export let event;
|
||||
export let open;
|
||||
export let closeModal;
|
||||
|
||||
$: action = open && event ? "Edit" : "Create";
|
||||
|
||||
</script>
|
||||
|
||||
<Modal isOpen={open} onClosed={closeModal}>
|
||||
<h2>{action} Event</h2>
|
||||
<EventSelector
|
||||
onChanged={console.log}
|
||||
onRemoved={console.log}
|
||||
{event}
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
h3 {
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #8997ab;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.root {
|
||||
font-size: 10pt;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-root {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.prop-container {
|
||||
flex: 1 1 auto;
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
.edit-icon:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,110 @@
|
|||
<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}
|
|
@ -0,0 +1,149 @@
|
|||
<script>
|
||||
import {
|
||||
keys,
|
||||
map,
|
||||
some,
|
||||
includes,
|
||||
cloneDeep,
|
||||
isEqual,
|
||||
sortBy,
|
||||
filter,
|
||||
difference
|
||||
} from "lodash/fp";
|
||||
import { pipe } from "../../common/core";
|
||||
import Checkbox from "../../common/Checkbox.svelte";
|
||||
import Textbox from "../../common/Textbox.svelte";
|
||||
import Dropdown from "../../common/Dropdown.svelte";
|
||||
import IconButton from "../../common/IconButton.svelte";
|
||||
import Modal from "../../common/Modal.svelte";
|
||||
import EventSelector from "./EventSelector.svelte";
|
||||
|
||||
import { PencilIcon } from "../../common/Icons";
|
||||
import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers";
|
||||
|
||||
export const EVENT_TYPE = "event";
|
||||
|
||||
export let componentInfo;
|
||||
export let onPropChanged = () => {};
|
||||
export let components;
|
||||
|
||||
let modalOpen = false;
|
||||
let events = [];
|
||||
let selectedEvent = null;
|
||||
let newEventType = "onClick";
|
||||
|
||||
// TODO: only show events that have handlers
|
||||
$: events =
|
||||
componentInfo &&
|
||||
Object.entries(componentInfo).filter(
|
||||
([name]) => findType(name) == EVENT_TYPE
|
||||
);
|
||||
|
||||
$: action = selectedEvent ? "Edit" : "Create";
|
||||
|
||||
function findType(propName) {
|
||||
if (!componentInfo._component) return;
|
||||
return components.find(({ name }) => name === componentInfo._component)
|
||||
.props[propName];
|
||||
}
|
||||
|
||||
console.log(componentInfo, events, components);
|
||||
|
||||
const openModal = event => {
|
||||
selectedEvent = event;
|
||||
modalOpen = true;
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
selectedEvent = null;
|
||||
modalOpen = false;
|
||||
};
|
||||
|
||||
const addEventHandler = event => {
|
||||
const newEventHandler = {
|
||||
parameters: {},
|
||||
[EVENT_TYPE_MEMBER_NAME]: ""
|
||||
};
|
||||
events = [...events, newEventHandler];
|
||||
onPropChanged(newEventType, events);
|
||||
};
|
||||
|
||||
const changeEventHandler = newEvent => {
|
||||
console.log({ events, newEventType, newEvent });
|
||||
onPropChanged(newEventType, events);
|
||||
};
|
||||
|
||||
const removeEventHandler = index => () => {
|
||||
events = filter(e => e !== events[index])(events);
|
||||
onPropChanged(newEventType, []);
|
||||
};
|
||||
|
||||
console.log(events);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
h3 {
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #8997ab;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.root {
|
||||
font-size: 10pt;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-root {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.prop-container {
|
||||
flex: 1 1 auto;
|
||||
min-width: 250px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h3>Events</h3>
|
||||
|
||||
<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}
|
||||
</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>
|
||||
{/if}
|
||||
</Modal>
|
|
@ -0,0 +1,177 @@
|
|||
<script>
|
||||
import {
|
||||
isString
|
||||
} from "lodash/fp";
|
||||
import IconButton from "../../common/IconButton.svelte";
|
||||
import {
|
||||
isBinding, getBinding, setBinding
|
||||
} from "../../common/binding";
|
||||
|
||||
export let value="";
|
||||
export let onChanged= () => {};
|
||||
export let type="";
|
||||
export let options=[];
|
||||
|
||||
let isBound=false;
|
||||
let bindingPath="";
|
||||
let bindingFallbackValue="";
|
||||
let bindingSource="store";
|
||||
let isExpanded = false;
|
||||
let forceIsBound = false;
|
||||
let canOnlyBind = false;
|
||||
|
||||
$: {
|
||||
canOnlyBind = type === "state";
|
||||
if(!forceIsBound && canOnlyBind)
|
||||
forceIsBound = true;
|
||||
|
||||
isBound= forceIsBound || isBinding(value);
|
||||
|
||||
if(isBound) {
|
||||
const binding = getBinding(value);
|
||||
bindingPath= binding.path;
|
||||
bindingFallbackValue= binding.fallback;
|
||||
bindingSource = binding.source || "store";
|
||||
} else {
|
||||
bindingPath="";
|
||||
bindingFallbackValue="";
|
||||
bindingSource="store";
|
||||
}
|
||||
}
|
||||
|
||||
const clearBinding = () => {
|
||||
forceIsBound = false;
|
||||
onChanged("");
|
||||
}
|
||||
|
||||
const bind = (path, fallback, source) => {
|
||||
if(!path) {
|
||||
clearBinding("");
|
||||
return;
|
||||
}
|
||||
const binding = setBinding({path, fallback, source});
|
||||
onChanged(binding);
|
||||
}
|
||||
|
||||
const setBindingPath = ev => {
|
||||
forceIsBound = canOnlyBind;
|
||||
bind(ev.target.value, bindingFallbackValue, bindingSource)
|
||||
}
|
||||
|
||||
const setBindingFallback = ev => {
|
||||
bind(bindingPath, ev.target.value, bindingSource);
|
||||
}
|
||||
|
||||
const setBindingSource = ev => {
|
||||
bind(bindingPath, bindingFallbackValue, ev.target.value);
|
||||
}
|
||||
|
||||
// const makeBinding = () => {
|
||||
// forceIsBound=true;
|
||||
// isExpanded=true;
|
||||
// }
|
||||
|
||||
</script>
|
||||
|
||||
{#if isBound}
|
||||
<div>
|
||||
<div class="bound-header">
|
||||
<div>{isExpanded ? "" : bindingPath}</div>
|
||||
<IconButton icon={isExpanded ? "chevron-up" : "chevron-down"}
|
||||
size="12"
|
||||
on:click={() => isExpanded=!isExpanded}/>
|
||||
{#if !canOnlyBind}
|
||||
<IconButton icon="trash"
|
||||
size="12"
|
||||
on:click={clearBinding}/>
|
||||
{/if}
|
||||
</div>
|
||||
{#if isExpanded}
|
||||
<div>
|
||||
<div class="binding-prop-label">Binding Path</div>
|
||||
<input class="uk-input uk-form-small"
|
||||
value={bindingPath}
|
||||
on:change={setBindingPath} >
|
||||
<div class="binding-prop-label">Fallback Value</div>
|
||||
<input class="uk-input uk-form-small"
|
||||
value={bindingFallbackValue}
|
||||
on:change={setBindingFallback} >
|
||||
<div class="binding-prop-label">Binding Source</div>
|
||||
<select class="uk-select uk-form-small"
|
||||
value={bindingSource}
|
||||
on:change={setBindingSource}>
|
||||
|
||||
<option>store</option>
|
||||
<option>context</option>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
{:else}
|
||||
<div class="unbound-container">
|
||||
|
||||
{#if type === "bool"}
|
||||
|
||||
<div>
|
||||
<IconButton icon={value == true ? "check-square" : "square"}
|
||||
size="19"
|
||||
on:click={() => onChanged(!value)} />
|
||||
</div>
|
||||
|
||||
{:else if type === "options"}
|
||||
|
||||
<select class="uk-select uk-form-small"
|
||||
value={value}
|
||||
on:change={ev => onChanged(ev.target.value)}>
|
||||
{#each options as option}
|
||||
<option value={option}>{option}</option>
|
||||
{/each}
|
||||
</select>
|
||||
|
||||
{:else}
|
||||
|
||||
<input on:change={ev => onChanged(ev.target.value)}
|
||||
bind:value={value}
|
||||
style="flex: 1 0 auto;" />
|
||||
|
||||
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
<style>
|
||||
.unbound-container {
|
||||
display:flex;
|
||||
}
|
||||
|
||||
.bound-header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.bound-header > div:nth-child(1) {
|
||||
flex: 1 0 auto;
|
||||
width: 30px;
|
||||
color: var(--secondary50);
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.binding-prop-label {
|
||||
color: var(--secondary50);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1 @@
|
|||
export { default } from "./EventsEditor.svelte";
|
|
@ -8,7 +8,7 @@
|
|||
"build": "cd appPackages/_master && yarn && cd ../testApp && yarn && cd ../testApp2 && yarn",
|
||||
"initialise": "node ./initialise/initialiseBudibase init -d ./myapps -c contributors -u admin -p admin",
|
||||
"budi": "node ../cli/bin/budi",
|
||||
"dev:builder": "nodemon index"
|
||||
"dev:builder": "node index"
|
||||
},
|
||||
"keywords": [
|
||||
"budibase"
|
||||
|
|
Loading…
Reference in New Issue