Merge pull request #126 from shogunpurple/backend-design

Backend design
This commit is contained in:
Martin McKeaveney 2020-02-24 17:06:02 +00:00 committed by GitHub
commit e88d3e821a
35 changed files with 409 additions and 316 deletions

View File

@ -5,6 +5,7 @@
import { store, initialise } from "./builderStore"
import { onMount } from "svelte"
import IconButton from "./common/IconButton.svelte"
import Spinner from "./common/Spinner.svelte"
let init = initialise()
</script>
@ -12,9 +13,9 @@
<main>
{#await init}
<h1>loading</h1>
<div class="spinner-container">
<Spinner />
</div>
{:then result}
{#if $store.hasAppPackage}
@ -52,4 +53,13 @@
bottom: 25px;
right: 25px;
}
.spinner-container {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
</style>

View File

@ -4,6 +4,7 @@
import Checkbox from "../common/Checkbox.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import Button from "../common/Button.svelte"
import ActionButton from "../common/ActionButton.svelte"
import { validateAccessLevels } from "../common/core"
import ErrorsBox from "../common/ErrorsBox.svelte"
@ -64,10 +65,11 @@
<form class="uk-form-horizontal">
<Textbox label="Name" bind:text={clonedLevel.name} />
<Textbox label="Access Level Name" bind:text={clonedLevel.name} />
<h4 class="budibase__title--4">Permissions</h4>
{#each permissionMatrix as permission}
<div>
<div class="permission-container">
<Checkbox
label={getPermissionName(permission.permission)}
checked={permission.hasPermission}
@ -77,15 +79,19 @@
</form>
<ButtonGroup style="margin-top: 10px">
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="secondary" grouped on:click={() => onFinished()}>
Cancel
</Button>
</ButtonGroup>
<div class="uk-modal-footer uk-text-right">
<ButtonGroup>
<ActionButton primary grouped on:click={save}>Save</ActionButton>
<ActionButton alert grouped on:click={() => onFinished()}>
Cancel
</ActionButton>
</ButtonGroup>
</div>
</div>
<style>
.permission-container {
margin-bottom: 10px;
}
</style>

View File

@ -1,6 +1,7 @@
<script>
import ButtonGroup from "../common/ButtonGroup.svelte"
import Button from "../common/Button.svelte"
import ActionButton from "../common/ActionButton.svelte"
import { store } from "../builderStore"
import { generateFullPermissions, getNewAccessLevel } from "../common/core"
import getIcon from "../common/icon"
@ -47,11 +48,10 @@
</script>
<div class="root">
<ButtonGroup>
<Button grouped color="secondary" on:click={createNewLevel}>
<ActionButton primary on:click={createNewLevel}>
Create New Access Level
</Button>
</ActionButton>
</ButtonGroup>
{#if $store.accessLevels}
@ -82,7 +82,11 @@
</table>
{:else}(no actions added){/if}
<Modal bind:isOpen={isEditing}>
<Modal
onClosed={() => isEditing = false}
bind:isOpen={isEditing}
title={isEditing ? "Edit Access Level" : "Create Access Level"}
>
{#if isEditing}
<AccessLevelView
level={editingLevel}

View File

@ -1,6 +1,7 @@
<script>
import Textbox from "../common/Textbox.svelte"
import Button from "../common/Button.svelte"
import ActionButton from "../common/ActionButton.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import { cloneDeep, filter, keys, map, isUndefined } from "lodash/fp"
import ErrorsBox from "../common/ErrorsBox.svelte"
@ -10,16 +11,15 @@
export let action
export let onFinished = action => {}
export let allActions
export let isNew = true
let optKey = ""
let optValue = ""
let clonedAction = cloneDeep(action)
let initialOptions = pipe(action.initialOptions, [
keys,
map(k => ({ key: k, value: action.initialOptions[k] })),
])
let initialOptions = pipe(
action.initialOptions,
[keys, map(k => ({ key: k, value: action.initialOptions[k] }))]
)
let errors = []
const addNewOption = () => {
@ -44,17 +44,26 @@
const removeOption = opt => {
if (opt) {
delete clonedAction.initialOptions[opt.key]
initialOptions = pipe(initialOptions, [filter(o => o.key !== opt.key)])
initialOptions = pipe(
initialOptions,
[filter(o => o.key !== opt.key)]
)
}
}
const save = () => {
const newActionsList = [
...pipe(allActions, [filter(a => a !== action)]),
...pipe(
allActions,
[filter(a => a !== action)]
),
clonedAction,
]
errors = pipe(newActionsList, [validateActions, map(e => e.error)])
errors = pipe(
newActionsList,
[validateActions, map(e => e.error)]
)
if (errors.length === 0) onFinished(clonedAction)
}
@ -89,9 +98,7 @@
class="uk-input uk-width-1-4 uk-margin-right"
placeholder="value"
bind:value={optValue} />
<Button color="primary-outline uk-width-1-4" on:click={addNewOption}>
Add
</Button>
<ActionButton primary on:click={addNewOption}>Add</ActionButton>
</div>
<div style="margin-top: 10px">
{#each initialOptions as option}
@ -107,11 +114,12 @@
</div>
</div>
<ButtonGroup>
<Button color="secondary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button>
</ButtonGroup>
<div class="uk-modal-footer uk-text-right">
<ButtonGroup>
<ActionButton primary grouped on:click={save}>Save</ActionButton>
<ActionButton alert grouped on:click={cancel}>Cancel</ActionButton>
</ButtonGroup>
</div>
</div>
<style>

View File

@ -19,20 +19,26 @@
let actionsArray = []
store.subscribe(s => {
actionsArray = pipe(s.actions, [keys, map(k => s.actions[k])])
actionsArray = pipe(
s.actions,
[keys, map(k => s.actions[k])]
)
})
let getDefaultOptionsHtml = defaultOptions =>
pipe(defaultOptions, [
keys,
map(
k =>
`<span style="color:var(--slate)">${k}: </span>${JSON.stringify(
defaultOptions[k]
)}`
),
join("<br>"),
])
pipe(
defaultOptions,
[
keys,
map(
k =>
`<span style="color:var(--slate)">${k}: </span>${JSON.stringify(
defaultOptions[k]
)}`
),
join("<br>"),
]
)
let actionEditingFinished = action => {
if (action) {
@ -43,7 +49,7 @@
}
</script>
<h3 class="title">Actions</h3>
<h3 class="budibase__title--3">Actions</h3>
{#if actionsArray}
<table class="fields-table uk-table uk-table-small uk-table-striped">
@ -79,7 +85,9 @@
</table>
{:else}(no actions added){/if}
<Modal bind:isOpen={isEditing}>
<Modal
title={editingActionIsNew ? 'Create Action' : 'Edit Action'}
bind:isOpen={isEditing}>
{#if isEditing}
<ActionView
action={editingAction}
@ -99,11 +107,6 @@
color: var(--secondary75);
}
.title {
margin: 3rem 0rem 0rem 0rem;
font-weight: 700;
}
.table-content {
font-weight: 500;
font-size: 0.9rem;

View File

@ -2,6 +2,7 @@
import getIcon from "../common/icon"
import { store } from "../builderStore"
import Button from "../common/Button.svelte"
import ActionButton from "../common/ActionButton.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import Actions from "./Actions.svelte"
import Triggers from "./Triggers.svelte"
@ -83,12 +84,12 @@
<div class="root">
<div class="actions-header">
<ButtonGroup>
<Button color="secondary" grouped on:click={newAction}>
<ActionButton color="secondary" grouped on:click={newAction}>
Create New Action
</Button>
<Button color="tertiary" grouped on:click={newTrigger}>
</ActionButton>
<ActionButton color="tertiary" grouped on:click={newTrigger}>
Create New Trigger
</Button>
</ActionButton>
</ButtonGroup>
</div>
@ -121,6 +122,7 @@
.actions-header {
flex: 0 1 auto;
margin-bottom: 10px;
}
.node-view {

View File

@ -1,6 +1,7 @@
<script>
import Textbox from "../common/Textbox.svelte"
import Button from "../common/Button.svelte"
import ActionButton from "../common/ActionButton.svelte"
import Dropdown from "../common/Dropdown.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import CodeArea from "../common/CodeArea.svelte"
@ -13,7 +14,6 @@
export let onFinished = action => {}
export let allTriggers
export let allActions
export let isNew = true
let clonedTrigger = cloneDeep(trigger)
let errors = []
@ -22,7 +22,10 @@
let cancel = () => onFinished()
let save = () => {
const newTriggersList = [
...pipe(allTriggers, [filter(t => t !== trigger)]),
...pipe(
allTriggers,
[filter(t => t !== trigger)]
),
clonedTrigger,
]
@ -51,19 +54,22 @@
options={['', ...actionNames]}
bind:selected={clonedTrigger.actionName} />
<CodeArea
label="Condition (javascript)"
label="Condition"
javascript
bind:text={clonedTrigger.condition} />
<CodeArea
label="Action Options Creator (javascript)"
label="Action Options Creator"
javascript
bind:text={clonedTrigger.optionsCreator} />
</form>
<ButtonGroup>
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button>
</ButtonGroup>
<div class="uk-modal-footer uk-text-right">
<ButtonGroup>
<ActionButton primary on:click={save}>Save</ActionButton>
<ActionButton alert on:click={cancel}>Cancel</ActionButton>
</ButtonGroup>
</div>
</div>
<style>

View File

@ -23,7 +23,7 @@
}
</script>
<h3 class="title">Triggers</h3>
<h3 class="budibase__title--3">Triggers</h3>
{#if $store.triggers}
<table class="fields-table uk-table uk-table-small uk-table-striped">
@ -57,7 +57,10 @@
</table>
{:else}(no triggers added){/if}
<Modal bind:isOpen={isEditing}>
<Modal
title={editingTriggerIsNew ? 'Create Trigger' : 'Edit Trigger'}
onClosed={() => (isEditing = false)}
bind:isOpen={isEditing}>
{#if isEditing}
<TriggerView
trigger={editingTrigger}

View File

@ -0,0 +1,93 @@
/* Budibase Component Styles */
.header {
font-size: 0.75rem;
color: #999;
text-transform: uppercase;
margin-top: 1rem;
font-weight: 500;
}
.budibase__title {
font-weight: 900;
font-size: 42px;
}
.budibase__title--2 {
font-weight: 700;
font-size: 32px;
}
.budibase__title--3 {
font-weight: 700;
font-size: 24px;
}
.budibase__title--4 {
font-weight: 700;
font-size: 18px;
}
.budibase__label--big {
font-weight: 400;
font-size: 14px;
opacity: 0.6;
text-transform: uppercase;
}
.budibase__label--medium {
font-weight: 500;
font-size: 12px;
opacity: 0.6;
text-transform: uppercase;
}
.budibase__label--small {
font-weight: 500;
font-size: 10px;
opacity: 0.6;
text-transform: uppercase;
}
.budibase__sub-heading {
font-weight: 500;
font-size: 16px;
opacity: 0.6;
}
.budibase__nav-item {
cursor: pointer;
padding: 0 7px 0 3px;
height: 35px;
margin: 5px 0;
border-radius: 0 5px 5px 0;
display: flex;
align-items: center;
font-weight: 500;
font-size: 0.8em;
}
.budibase__nav-item.selected {
color: var(--button-text);
background: var(--background-button) !important;
}
.budibase__nav-item:hover {
background: #fafafa;
}
.budibase__input {
width: 250px;
height: 35px;
border-radius: 3px;
border: 1px solid #DBDBDB;
text-align: left;
letter-spacing: 0.7px;
color: #163057;
font-size: 16px;
padding-left: 5px;
}
.uk-text-right {
display: flex;
justify-content: flex-start;
}

View File

@ -29,12 +29,12 @@
}
.button {
font-size: 18px;
font-size: 14px;
font-weight: bold;
border-radius: 5px;
border: none;
width: 167px;
height: 64px;
min-width: 120px;
height: 45px;
}
.button:hover {

View File

@ -8,18 +8,9 @@
<style>
.root {
display: flex;
}
.root:last-child {
border-radius: 0 var(--borderradius) var(--borderradius) 0;
}
.root:first-child {
border-radius: var(--borderradius) 0 0 var(--borderradius);
}
.root:not(:first-child):not(:last-child) {
border-radius: 0;
display: grid;
grid-auto-flow: column;
grid-gap: 5px;
width: 50%;
}
</style>

View File

@ -1,10 +1,17 @@
<script>
import { JavaScriptIcon } from "../common/Icons"
// todo: use https://ace.c9.io
export let text = ""
export let label = ""
export let javascript = false
</script>
<div>{label}</div>
<div class="header">
{#if javascript}
<JavaScriptIcon />
{/if}
<span>{label}</span>
</div>
<textarea class="uk-textarea" bind:value={text} />
<style>
@ -13,10 +20,18 @@
margin-top: 5px;
margin-bottom: 10px;
background: var(--lightslate);
color: var(--white);
font-family: "Courier New", Courier, monospace;
width: 95%;
height: 100px;
border-radius: 5px;
}
span {
margin-left: 5px;
}
.header {
display: flex;
align-items: center;
}
</style>

View File

@ -1,57 +1,51 @@
<script>
import Button from "./Button.svelte"
import ButtonGroup from "./ButtonGroup.svelte"
import UIkit from "uikit"
import Button from "./Button.svelte"
import ActionButton from "./ActionButton.svelte"
import ButtonGroup from "./ButtonGroup.svelte"
import UIkit from "uikit"
export let title=""
export let body=""
export let okText = "OK"
export let cancelText = "Cancel"
export let onOk = ()=> {}
export let onCancel = ()=> {}
export let title = ""
export let body = ""
export let okText = "OK"
export let cancelText = "Cancel"
export let onOk = () => {}
export let onCancel = () => {}
export const show = () => {
UIkit.modal(theModal).show()
}
export const show = () => {
UIkit.modal(theModal).show()
}
export const hide = () => {
UIkit.modal(theModal).hide()
}
export const hide = () => {
UIkit.modal(theModal).hide()
}
let theModal;
let theModal
const cancel = () => {
hide()
onCancel()
}
const ok = () => {
hide()
onOk()
}
const cancel = () => {
hide()
onCancel()
}
const ok = () => {
hide()
onOk()
}
</script>
<div id="my-id" uk-modal bind:this={theModal}>
<div class="uk-modal-dialog">
<button class="uk-modal-close-default" type="button" uk-close></button>
<button class="uk-modal-close-default" type="button" uk-close />
<div class="uk-modal-header">
<h2 class="uk-modal-title">{title}</h2>
<h4 class="budibase__title--4">{title}</h4>
</div>
<div class="uk-modal-body">
<slot>{body}</slot>
</div>
<div class="uk-modal-footer">
<ButtonGroup>
<Button grouped color="primary" on:click={ok}>
{okText}
</Button>
<Button grouped color="secondary" on:click={cancel}>
{cancelText}
</Button>
</ButtonGroup>
<ActionButton alert on:click={ok}>{okText}</ActionButton>
<ActionButton primary on:click={cancel}>{cancelText}</ActionButton>
</ButtonGroup>
</div>
</div>
</div>

View File

@ -1,5 +1,6 @@
<script>
import { createEventDispatcher } from "svelte"
import Select from "../common/Select.svelte";
export let selected
export let label
@ -17,7 +18,7 @@
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
{#if multiple}
<select
<Select
class="uk-select uk-form-width-{width} uk-form-{size}"
multiple
bind:value={selected}
@ -27,9 +28,9 @@
{!textMember ? option : textMember(option)}
</option>
{/each}
</select>
</Select>
{:else}
<select
<Select
class="uk-select uk-form-width-{width} uk-form-{size}"
bind:value={selected}
on:change>
@ -38,7 +39,7 @@
{!textMember ? option : textMember(option)}
</option>
{/each}
</select>
</Select>
{/if}
</div>
</div>

View File

@ -17,7 +17,7 @@
class="dropdown-content"
style="display: {isDroppedDown ? 'inline-block' : 'none'}">
{#each actions as action}
<div class="action-row" on:click={action.onclick}>{action.label}</div>
<div class="budibase__nav-item" on:click={action.onclick}>{action.label}</div>
{/each}
</div>

View File

@ -0,0 +1,31 @@
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M0.220001 0.220001H19.78V19.7802H0.220001V0.220001Z"
fill="#F0DB4F" />
<path
d="M18.1792 15.115C18.0359 14.2227 17.4541 13.4731 15.7305 12.7742C15.1317
12.4991 14.4642 12.302 14.2653 11.8483C14.1947 11.5842 14.1853 11.4355 14.23
11.2756C14.3583 10.7569 14.9775 10.5952 15.4683 10.7439C15.7844 10.8499
16.0836 11.0934 16.2641 11.482C17.1081 10.9355 17.1064 10.9391 17.6958
10.5634C17.48 10.2289 17.3648 10.0745 17.2236 9.93142C16.7159 9.36439
16.0242 9.07235 14.918 9.0947L14.3417 9.16923C13.7895 9.30876 13.2633 9.5986
12.9547 9.9872C12.0287 11.0378 12.2928 12.8766 13.4195 13.6333C14.5295
14.4664 16.1601 14.6559 16.3684 15.435C16.5711 16.3888 15.6675 16.6975
14.7694 16.5878C14.1075 16.4502 13.7394 16.1138 13.3414 15.502C12.6089
15.926 12.6089 15.926 11.8558 16.3591C12.0344 16.7495 12.222 16.9263 12.5214
17.2645C13.9383 18.7017 17.4839 18.6311 18.1198 16.4558C18.1456 16.3811
18.3169 15.883 18.1792 15.115V15.115ZM10.8534 9.20985H9.0239L9.0164
13.9399C9.0164 14.9458 9.06843 15.868 8.90484 16.1506C8.63718 16.7066
7.94359 16.6377 7.62749 16.5299C7.30578 16.3717 7.14218 16.1469 6.95265
15.8291C6.90062 15.7378 6.86156 15.6672 6.84843 15.6617L5.36093
16.5727C5.60828 17.0803 5.97265 17.521 6.43937 17.8072C7.13656 18.2256
8.07359 18.3539 9.05359 18.1289C9.6914 17.9431 10.2417 17.5583 10.5298
16.9725C10.9464 16.2045 10.857 15.275 10.8533 14.2469C10.8626 12.5695
10.8534 10.8925 10.8534 9.20985Z"
fill="#323330" />
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -15,3 +15,4 @@ export { default as CheckIcon } from "./Check.svelte"
export { default as GridIcon } from "./Grid.svelte"
export { default as ShapeIcon } from "./Shape.svelte"
export { default as AddIcon } from "./Add.svelte"
export { default as JavaScriptIcon } from "./JavaScript.svelte"

View File

@ -1,9 +1,11 @@
<script>
import UIkit from "uikit"
import ActionButton from "../common/ActionButton.svelte"
export let isOpen = false
export let onClosed = () => {}
export let id = ""
export let title
let ukModal
let listenerAdded = false
@ -25,11 +27,18 @@
</script>
<div bind:this={ukModal} uk-modal {id}>
<div class="uk-modal-dialog uk-modal-body" uk-overflow-auto>
{#if onClosed}
<button class="uk-modal-close-default" type="button" uk-close />
<div class="uk-modal-dialog" uk-overflow-auto>
{#if title}
<div class="uk-modal-header">
<h4 class="budibase__title--4">{title}</h4>
</div>
{/if}
<slot />
<div class="uk-modal-body">
{#if onClosed}
<button class="uk-modal-close-default" type="button" uk-close />
{/if}
<slot />
</div>
</div>
</div>

View File

@ -16,6 +16,6 @@
<div class="uk-margin">
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<input class="uk-input" {value} on:change={inputChanged} />
<input class="budibase__input" {value} on:change={inputChanged} />
</div>
</div>

View File

@ -19,6 +19,7 @@
color: var(--secondary50);
font-weight: bold;
position: relative;
max-width: 300px;
}
select {

View File

@ -0,0 +1,5 @@
<script>
export let ratio = "4.5"
</script>
<span uk-spinner={`ratio: ${ratio}`} />

View File

@ -13,7 +13,7 @@
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<input
class="uk-input uk-form-width-{width} uk-form-{size}"
class="budibase__input"
class:uk-form-danger={hasError}
on:change
bind:value={text}

View File

@ -1,5 +1,6 @@
<script>
import Button from "../common/Button.svelte"
import ActionButton from "../common/ActionButton.svelte"
import ButtonGroup from "../common/ButtonGroup.svelte"
import { store } from "../builderStore"
import Modal from "../common/Modal.svelte"
@ -20,14 +21,14 @@
<div class="root" style="left: {left}">
<ButtonGroup>
<Button color="secondary" grouped on:click={store.saveCurrentNode}>
<ActionButton color="secondary" grouped on:click={store.saveCurrentNode}>
{#if $store.currentNodeIsNew}Create{:else}Update{/if}
</Button>
</ActionButton>
{#if !$store.currentNodeIsNew}
<Button color="tertiary" grouped on:click={openConfirmDelete}>
<ActionButton alert grouped on:click={openConfirmDelete}>
Delete
</Button>
</ActionButton>
{/if}
</ButtonGroup>
@ -37,15 +38,17 @@
</div>
{/if}
<Modal bind:isOpen={confirmDelete}>
<div style="margin: 10px 0px 20px 0px">
Are you sure you want to delete {$store.currentNode.name} ?
</div>
<div style="float:right">
<Button color="primary" on:click={deleteCurrentNode}>Yes</Button>
<Button color="secondary" on:click={() => (confirmDelete = false)}>
No
</Button>
<Modal onClosed={() => (confirmDelete = false)} bind:isOpen={confirmDelete}>
<span>
Are you sure you want to delete {$store.currentNode.name}?
</span>
<div class="uk-modal-footer uk-text-right">
<ButtonGroup>
<ActionButton alert on:click={deleteCurrentNode}>Yes</ActionButton>
<ActionButton primary on:click={() => (confirmDelete = false)}>
No
</ActionButton>
</ButtonGroup>
</div>
</Modal>
</div>
@ -56,4 +59,11 @@
width: 100%;
align-items: right;
}
.actions-modal-body {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
</style>

View File

@ -7,6 +7,7 @@
import ValuesList from "../common/ValuesList.svelte"
import ErrorsBox from "../common/ErrorsBox.svelte"
import Checkbox from "../common/Checkbox.svelte"
import ActionButton from "../common/ActionButton.svelte"
import DatePicker from "../common/DatePicker.svelte"
import {
cloneDeep,
@ -141,18 +142,14 @@
label="Max Length"
bind:value={clonedField.typeOptions.maxLength} />
{/if}
</form>
<ButtonGroup style="float: right;">
<Button color="primary" grouped on:click={save}>Save</Button>
<Button color="tertiary" grouped on:click={() => onFinished(false)}>
Cancel
</Button>
</ButtonGroup>
</div>
<style>
</style>
<div class="uk-modal-footer uk-text-right">
<ButtonGroup>
<ActionButton primary on:click={save}>Save</ActionButton>
<ActionButton alert on:click={() => onFinished(false)}>
Cancel
</ActionButton>
</ButtonGroup>
</div>
</div>

View File

@ -14,15 +14,18 @@
store.subscribe($store => {
index = $store.currentNode
indexableRecords = pipe($store.hierarchy, [
hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isDecendant(index.parent())),
filter(hierarchyFunctions.isRecord),
map(n => ({
node: n,
isallowed: some(id => n.nodeId === id)(index.allowedRecordNodeIds),
})),
])
indexableRecords = pipe(
$store.hierarchy,
[
hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isDecendant(index.parent())),
filter(hierarchyFunctions.isRecord),
map(n => ({
node: n,
isallowed: some(id => n.nodeId === id)(index.allowedRecordNodeIds),
})),
]
)
})
const toggleAllowedRecord = record => {
@ -40,7 +43,7 @@
<Textbox bind:text={index.name} label="Name" />
<div class="allowed-records">
<div>Records to Index</div>
<div class="index-label">Records to Index</div>
{#each indexableRecords as rec}
<input
type="checkbox"
@ -55,11 +58,9 @@
bind:selected={index.indexType}
options={['ancestor', 'reference']} />
<CodeArea bind:text={index.map} label="Map (javascript)" />
<CodeArea bind:text={index.filter} label="Filter (javascript expression)" />
<CodeArea
bind:text={index.getShardName}
label="Shard Name (javascript expression)" />
<CodeArea bind:text={index.map} javascript label="Map" />
<CodeArea bind:text={index.filter} javascript label="Filter" />
<CodeArea javascript bind:text={index.getShardName} label="Shard Name" />
</form>
@ -76,4 +77,9 @@
.allowed-records > span {
margin-right: 30px;
}
.index-label {
color: #333;
font-size: 0.875rem;
}
</style>

View File

@ -94,7 +94,7 @@
<div class="root">
<form class="uk-form-horizontal">
<h3 class="settings-title">Settings</h3>
<h3 class="budibase__title--3">Settings</h3>
<Textbox label="Name:" bind:text={record.name} on:change={nameChanged} />
{#if !record.isSingle}
@ -104,7 +104,7 @@
<div class="recordkey">{record.nodeKey()}</div>
</form>
<h3 class="title">
<h3 class="budibase__title--3">
Fields
<span class="add-field-button" on:click={newField}>
{@html getIcon('plus')}
@ -150,6 +150,7 @@
{#if editingField}
<Modal
title="Manage Index Fields"
bind:isOpen={editingField}
onClosed={() => onFinishedFieldEdit(false)}>
<FieldView
@ -160,7 +161,7 @@
</Modal>
{/if}
<h3 class="title">Indexes</h3>
<h3 class="budibase__title--3">Indexes</h3>
{#each record.indexes as index}
<div class="index-container">
@ -199,15 +200,6 @@
padding: 2rem;
}
.settings-title {
font-weight: 700;
}
.title {
margin: 3rem 0rem 0rem 0rem;
font-weight: 700;
}
.recordkey {
font-size: 14px;
font-weight: 600;

View File

@ -1,3 +1,5 @@
@import "./budibase.css";
:root {
--primary100: #173157FF;
--primary75: #454CA0BF;
@ -100,4 +102,4 @@ h5 {
font-family: var(--fontblack);
font-size: 12pt;
color: var(--darkslate);
}
}

View File

@ -105,9 +105,8 @@
.nav-group-header {
display: grid;
grid-template-columns: [icon] auto [title] 1fr [button] auto;
padding: 2rem 1rem 0rem 1rem;
padding: 2rem 1rem 1rem 1rem;
font-size: 0.9rem;
font-weight: bold;
}
.nav-group-header > div:nth-child(1) {
@ -137,13 +136,12 @@
.hierarchy-title {
flex: auto 1 1;
text-transform: uppercase;
}
.hierarchy {
display: flex;
flex-direction: column;
flex: 1 0 auto;
height: 100px;
}
.hierarchy-items-container {

View File

@ -13,16 +13,14 @@
if (s.currentNode)
navActive =
s.activeNav === "database" && node.nodeId === s.currentNode.nodeId
? "active"
: ""
})
</script>
<div class="root">
<div
class="title {navActive}"
on:click={() => store.selectExistingNode(node.nodeId)}
style="padding-left: {20 + level * 20}px">
<div
class="budibase__nav-item"
on:click={() => store.selectExistingNode(node.nodeId)}
class:selected={navActive}>
<div style="padding-left: {20 + level * 20}px">
{@html getIcon(icon, 12)}
<span style="margin-left: 1rem">{node.name}</span>
</div>
@ -36,28 +34,4 @@
<svelte:self node={index} level={level + 1} type="index" />
{/each}
{/if}
</div>
<style>
.root {
display: block;
font-size: 0.9rem;
width: 100%;
cursor: pointer;
color: var(--secondary50);
font-weight: 500;
}
.title {
padding-top: 0.5rem;
padding-right: 0.5rem;
}
.title:hover {
background-color: var(--secondary10);
}
.active {
background-color: var(--primary10);
}
</style>
</div>

View File

@ -8,28 +8,16 @@
let navActive = ""
store.subscribe(db => {
navActive = db.activeNav === name ? "active" : ""
navActive = db.activeNav === name
})
const setActive = () => store.setActiveNav(name)
</script>
<div class="nav-item {navActive}" on:click={setActive}>{label}</div>
<div class="budibase__nav-item backend-nav-item" class:selected={navActive} on:click={setActive}>{label}</div>
<style>
.nav-item {
padding: 1.5rem 1rem 0rem 1rem;
font-size: 0.9rem;
font-weight: bold;
cursor: pointer;
flex: 0 0 auto;
.backend-nav-item {
padding-left: 25px;
}
.nav-item:hover {
background-color: var(--primary10);
}
.active {
background-color: var(--primary10);
}
</style>
</style>

View File

@ -56,7 +56,7 @@
{#each _screens as screen}
<div
class="hierarchy-item component"
class="budibase__nav-item component"
class:selected={$store.currentComponentInfo._id === screen.component.props._id}
on:click|stopPropagation={() => store.setCurrentScreen(screen.title)}>
@ -92,37 +92,16 @@
<ConfirmDialog
bind:this={confirmDeleteDialog}
title="Confirm Delete"
body={`Are you sure you wish to delete this '${lastPartOfName(componentToDelete)}' component`}
body={`Are you sure you wish to delete this '${lastPartOfName(componentToDelete)}' component?`}
okText="Delete Component"
onOk={() => store.deleteComponent(componentToDelete)} />
<style>
.root {
font-weight: 400;
font-size: 0.8rem;
color: #333;
}
.hierarchy-item {
cursor: pointer;
padding: 0 7px 0 3px;
height: 35px;
margin: 5px 0;
border-radius: 0 5px 5px 0;
display: flex;
align-items: center;
font-weight: 500;
}
.hierarchy-item:hover {
background: #fafafa;
}
.selected {
color: var(--button-text);
background: var(--background-button) !important;
}
.title {
margin-left: 10px;
margin-top: 2px;

View File

@ -38,7 +38,7 @@
{#each components as component, index (component._id)}
<li on:click|stopPropagation={() => onSelect(component)}>
<div
class="item"
class="budibase__nav-item item"
class:selected={currentComponent === component}
style="padding-left: {level * 20 + 53}px">
<div>{get_capitalised_name(component._component)}</div>
@ -98,7 +98,6 @@
border-radius: 3px;
height: 35px;
align-items: center;
font-size: 0.8rem;
font-weight: normal;
}
@ -129,12 +128,6 @@
color: var(--button-text);
}
.selected {
color: var(--button-text);
background: var(--background-button) !important;
font-weight: 500;
}
.reorder-buttons {
display: flex;
flex-direction: column;

View File

@ -34,10 +34,17 @@
let selectedEvent = null
$: {
const componentDefinition = components.find(c => c.name === component._component)
const componentDefinition = components.find(
c => c.name === component._component
)
events = Object.keys(componentDefinition.props)
.filter(propName => componentDefinition.props[propName].type === EVENT_TYPE)
.map(propName => ({ name: propName, handlers: (component[propName] || []) }))
.filter(
propName => componentDefinition.props[propName].type === EVENT_TYPE
)
.map(propName => ({
name: propName,
handlers: component[propName] || [],
}))
}
const openModal = event => {
@ -61,7 +68,8 @@
{#each events as event, index}
{#if event.handlers.length > 0}
<div
class="handler-container hierarchy-item {selectedEvent && selectedEvent.index === index ? 'selected' : ''}"
class:selected={selectedEvent && selectedEvent.index === index}
class="handler-container budibase__nav-item"
on:click={() => openModal({ ...event, index })}>
<span class="event-name">{event.name}</span>
<span class="edit-text">EDIT</span>
@ -107,21 +115,9 @@
grid-template-columns: repeat(2, 1fr);
border: 2px solid #f9f9f9;
height: 80px;
}
.hierarchy-item {
cursor: pointer;
padding: 11px 7px;
margin: 5px 0;
border-radius: 5px;
font-size: 1.5em;
width: 100%;
}
.hierarchy-item:hover {
background: #f9f9f9;
}
.event-name {
margin-top: 5px;
font-weight: bold;

View File

@ -51,12 +51,12 @@
}
</script>
<div class="root">
<div
class="hierarchy-item component"
class:selected={$store.currentComponentInfo._id === _layout.component.props._id}
on:click|stopPropagation={() => store.setScreenType('page')}>
<div
class="budibase__nav-item"
class:selected={$store.currentComponentInfo._id === _layout.component.props._id}
on:click|stopPropagation={() => store.setScreenType('page')}>
<div class="component">
<span
class="icon"
class:rotate={$store.currentPreviewItem.name !== _layout.title}>
@ -87,37 +87,11 @@
<ConfirmDialog
bind:this={confirmDeleteDialog}
title="Confirm Delete"
body={`Are you sure you wish to delete this '${lastPartOfName(componentToDelete)}' component`}
body={`Are you sure you wish to delete this '${lastPartOfName(componentToDelete)}' component?`}
okText="Delete Component"
onOk={() => store.deleteComponent(componentToDelete)} />
<style>
.root {
font-weight: 400;
font-size: 0.8rem;
color: #333;
}
.hierarchy-item {
cursor: pointer;
padding: 0 7px 0 3px;
height: 35px;
margin: 5px 0;
border-radius: 0 5px 5px 0;
display: flex;
align-items: center;
font-weight: 500;
}
.hierarchy-item:hover {
background: #fafafa;
}
.selected {
color: var(--button-text);
background: var(--background-button) !important;
}
.title {
margin-left: 10px;
margin-top: 2px;

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path fill="#F0DB4F" d="M1.408 1.408h125.184v125.185h-125.184z"/><path fill="#323330" d="M116.347 96.736c-.917-5.711-4.641-10.508-15.672-14.981-3.832-1.761-8.104-3.022-9.377-5.926-.452-1.69-.512-2.642-.226-3.665.821-3.32 4.784-4.355 7.925-3.403 2.023.678 3.938 2.237 5.093 4.724 5.402-3.498 5.391-3.475 9.163-5.879-1.381-2.141-2.118-3.129-3.022-4.045-3.249-3.629-7.676-5.498-14.756-5.355l-3.688.477c-3.534.893-6.902 2.748-8.877 5.235-5.926 6.724-4.236 18.492 2.975 23.335 7.104 5.332 17.54 6.545 18.873 11.531 1.297 6.104-4.486 8.08-10.234 7.378-4.236-.881-6.592-3.034-9.139-6.949-4.688 2.713-4.688 2.713-9.508 5.485 1.143 2.499 2.344 3.63 4.26 5.795 9.068 9.198 31.76 8.746 35.83-5.176.165-.478 1.261-3.666.38-8.581zm-46.885-37.793h-11.709l-.048 30.272c0 6.438.333 12.34-.714 14.149-1.713 3.558-6.152 3.117-8.175 2.427-2.059-1.012-3.106-2.451-4.319-4.485-.333-.584-.583-1.036-.667-1.071l-9.52 5.83c1.583 3.249 3.915 6.069 6.902 7.901 4.462 2.678 10.459 3.499 16.731 2.059 4.082-1.189 7.604-3.652 9.448-7.401 2.666-4.915 2.094-10.864 2.07-17.444.06-10.735.001-21.468.001-32.237z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB