1
0
Fork 0
mirror of synced 2024-09-20 19:33:10 +12:00
budibase/packages/builder/src/userInterface/EditComponent.svelte

309 lines
8.1 KiB
Svelte
Raw Normal View History

2019-08-17 02:48:45 +12:00
<script>
import PropsView from "./PropsView.svelte";
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 {
getComponentInfo
} from "./pagesParsing/createProps";
import Button from "../common/Button.svelte";
import ButtonGroup from "../common/ButtonGroup.svelte";
2019-08-19 19:51:01 +12:00
import ComponentInstanceEditor from "./ComponentInstanceEditor.svelte";
2019-08-17 02:48:45 +12:00
import {
cloneDeep,
join,
split,
map,
keys,
isUndefined,
last
} from "lodash/fp";
import { assign } from "lodash";
let component;
let name = "";
let description = "";
let tagsString = "";
let nameInvalid = "";
let componentDetailsExpanded = false;
let componentInfo;
let modalElement
let propsValidationErrors = [];
2019-08-19 19:51:01 +12:00
let editingComponentInstance;
let editingComponentInstancePropName="";
2019-09-22 16:02:33 +12:00
let editingComponentArrayIndex;
let editingComponentArrayPropName;
let editingComponentInstanceTitle;
2019-10-03 18:12:13 +13:00
let originalName="";
2019-08-19 19:51:01 +12:00
let allComponents;
2019-10-03 18:12:13 +13:00
let ignoreStore = false;
2019-08-19 19:51:01 +12:00
2019-08-17 02:48:45 +12:00
$: shortName = last(name.split("/"));
store.subscribe(s => {
2019-10-03 18:12:13 +13:00
if(ignoreStore) return;
2019-08-17 02:48:45 +12:00
component = s.currentFrontEndItem;
if(!component) return;
2019-10-03 18:12:13 +13:00
originalName = component.name;
2019-08-17 02:48:45 +12:00
name = component.name;
description = component.description;
tagsString = join(", ")(component.tags);
componentInfo = s.currentComponentInfo;
componentDetailsExpanded = s.currentComponentIsNew;
2019-08-19 19:51:01 +12:00
allComponents = s.allComponents;
2019-08-17 02:48:45 +12:00
});
const save = () => {
2019-10-03 18:12:13 +13:00
ignoreStore = true;
if(!validate()) {
ignoreStore = false;
return;
}
2019-08-17 02:48:45 +12:00
2019-10-03 18:12:13 +13:00
component.name = originalName;
2019-08-17 02:48:45 +12:00
component.description = description;
component.tags = pipe(tagsString, [
split(","),
map(s => s.trim())
]);
store.saveDerivedComponent(component);
2019-10-03 18:12:13 +13:00
ignoreStore = false;
// now do the rename
if(name !== originalName) {
store.renameDerivedComponent(originalName, name);
}
2019-08-17 02:48:45 +12:00
}
const deleteComponent = () => {
showDialog();
}
const confirmDeleteComponent = () => {
store.deleteDerivedComponent(component.name);
hideDialog();
}
const onPropsValidate = result => {
propsValidationErrors = result;
}
2019-08-19 19:51:01 +12:00
const updateComponent = doChange => {
const newComponent = cloneDeep(component);
doChange(newComponent);
component = newComponent;
componentInfo = getComponentInfo(allComponents, newComponent);
}
const onPropsChanged = newProps => {
updateComponent(newComponent =>
assign(newComponent.props, newProps));
2019-08-17 02:48:45 +12:00
}
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();
}
2019-09-03 21:42:19 +12:00
const onEditComponentProp = (propName, arrayIndex, arrayPropName) => {
editingComponentInstance = isUndefined(arrayIndex)
? component.props[propName]
: component.props[propName][arrayIndex][arrayPropName];
2019-09-22 16:02:33 +12:00
editingComponentInstancePropName = propName;
editingComponentInstanceTitle = isUndefined(arrayIndex)
2019-09-03 21:42:19 +12:00
? propName
: `${propName}[${arrayIndex}].${arrayPropName}`;
2019-09-22 16:02:33 +12:00
editingComponentArrayIndex = arrayIndex;
editingComponentArrayPropName = arrayPropName;
2019-08-19 19:51:01 +12:00
}
const componentInstanceCancelEdit = () => {
editingComponentInstance = null;
editingComponentInstancePropName = "";
}
const componentInstancePropsChanged = (instanceProps) => {
2019-09-22 16:02:33 +12:00
updateComponent(newComponent => {
if(isUndefined(editingComponentArrayIndex)) {
newComponent.props[editingComponentInstancePropName] = instanceProps;
} else {
newComponent.props[editingComponentInstancePropName]
[editingComponentArrayIndex]
[editingComponentArrayPropName] = instanceProps;
}
});
2019-08-19 19:51:01 +12:00
}
2019-08-17 02:48:45 +12:00
</script>
<div class="root">
<div class="title">
<div>{shortName}</div>
<div>
<IconButton icon="save"
on:click={save}
color="var(--secondary100)"
hoverColor="var(--primary100)"/>
2019-08-17 02:48:45 +12:00
<IconButton icon="trash"
on:click={deleteComponent}
color="var(--secondary100)"
hoverColor="var(--primary100)"/>
2019-08-17 02:48:45 +12:00
</div>
</div>
2019-08-19 19:51:01 +12:00
{#if editingComponentInstance}
2019-10-03 18:12:13 +13:00
<div class="component-props-container">
<ComponentInstanceEditor onGoBack={componentInstanceCancelEdit}
title={editingComponentInstanceTitle}
instanceProps={editingComponentInstance}
onPropsChanged={componentInstancePropsChanged}/>
</div>
2019-08-19 19:51:01 +12:00
{:else}
2019-09-20 20:02:22 +12:00
<div class="component-props-container">
2019-08-17 02:48:45 +12:00
2019-08-19 19:51:01 +12:00
<div class="section-header padding" on:click={() => componentDetailsExpanded = !componentDetailsExpanded}>
2019-08-17 02:48:45 +12:00
<span style="margin-right: 7px">Component Details</span>
<IconButton icon={componentDetailsExpanded ? "chevron-down" : "chevron-right"}/>
</div>
{#if componentDetailsExpanded}
2019-08-19 19:51:01 +12:00
<div class="padding">
<div class="info-text">
<Textbox label="Name"
infoText="use forward slash to store in subfolders"
2019-10-03 18:12:13 +13:00
text={name}
on:change={ev => name = ev.target.value}
hasError={!!nameInvalid}/>
<Textbox label="Description"
2019-10-03 18:12:13 +13:00
on:change={ev => description = ev.target.value}
text={description}/>
<Textbox label="Tags"
2019-10-03 18:12:13 +13:00
infoText="comma separated"
on:change={ev => tagsString = ev.target.value}
text={tagsString}/>
</div>
2019-08-17 02:48:45 +12:00
</div>
{/if}
2019-08-19 19:51:01 +12:00
<div class="section-header padding">
<span>Properties</span>
</div>
2019-08-17 02:48:45 +12:00
<PropsView onValidate={onPropsValidate}
{componentInfo}
2019-08-19 19:51:01 +12:00
{onPropsChanged}
{onEditComponentProp}/>
2019-08-17 02:48:45 +12:00
</div>
2019-08-19 19:51:01 +12:00
{/if}
2019-08-17 02:48:45 +12:00
</div>
<div bind:this={modalElement} uk-modal>
<div class="uk-modal-dialog">
<div class="uk-modal-header">
2019-10-03 18:12:13 +13:00
Delete {name} ?
2019-08-17 02:48:45 +12:00
</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 {
height: 100%;
display: flex;
2019-09-20 20:02:22 +12:00
flex-direction: column;
2019-08-17 02:48:45 +12:00
}
2019-08-19 19:51:01 +12:00
.padding {
padding: 1rem 1rem 0rem 1rem;
}
.info-text {
color: var(--secondary100);
font-size: .8rem !important;
font-weight: bold;
2019-08-17 02:48:45 +12:00
}
.title {
padding: 2rem 1rem 1rem 1rem;
2019-08-17 02:48:45 +12:00
display: grid;
grid-template-columns: [name] 1fr [actions] auto;
color: var(--secondary100);
font-size: .9rem;
font-weight: bold;
2019-08-17 02:48:45 +12:00
}
.title > div:nth-child(1) {
grid-column-start: name;
color: var(--secondary100);
}
.title > div:nth-child(2) {
grid-column-start: actions;
}
.section-header {
display: grid;
grid-template-columns: [name] 1fr [actions] auto;
color: var(--secondary50);
font-size: .9rem;
font-weight: bold;
2019-08-17 02:48:45 +12:00
vertical-align: middle;
}
2019-09-20 20:02:22 +12:00
.component-props-container {
flex: 1 1 auto;
overflow-y: auto;
}
2019-08-17 02:48:45 +12:00
</style>