Merge branch 'master' of https://github.com/Budibase/budibase into property-panel/screen-page-testing

This commit is contained in:
Conor_Mack 2020-06-08 10:48:57 +01:00
commit 2911ccc8ba
44 changed files with 833 additions and 425 deletions

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 115 40" style="enable-background:new 0 0 115 40;" xml:space="preserve">
<style type="text/css">
.st0{fill:#393C44;}
.st1{fill:#FFFFFF;}
</style>
<path class="st0" d="M111.16,40H3.91c-2.15,0-3.89-1.74-3.89-3.89V4.04c0-2.15,1.74-3.89,3.89-3.89h107.25
c2.15,0,3.89,1.74,3.89,3.89v32.07C115.05,38.26,113.31,40,111.16,40z"/>
<path class="st1" d="M10.37,10.03v8.57c0.93-1.26,2.33-1.67,3.61-1.67c1.58,0,3.01,0.59,4.02,1.54c1.12,1.05,1.82,2.62,1.82,4.53
c0,1.78-0.62,3.42-1.82,4.61c-1.01,1.03-2.26,1.57-3.97,1.57c-2.05,0-3.09-0.95-3.66-1.78v1.39H6.63V10.03H10.37z M10.97,20.98
c-0.44,0.46-0.82,1.13-0.82,2.11c0,0.95,0.41,1.64,0.85,2.05c0.59,0.57,1.41,0.85,2.11,0.85c0.64,0,1.36-0.26,1.93-0.8
c0.54-0.51,0.9-1.26,0.9-2.11c0-0.92-0.36-1.67-0.9-2.18c-0.59-0.57-1.23-0.77-1.98-0.77C12.26,20.14,11.56,20.37,10.97,20.98z"/>
<path class="st1" d="M25.08,17.35v6.32c0,0.51,0.05,1.31,0.64,1.85c0.26,0.23,0.72,0.54,1.54,0.54c0.69,0,1.23-0.23,1.56-0.54
c0.54-0.51,0.62-1.28,0.62-1.85v-6.32h3.74v6.68c0,1.31-0.13,2.54-1.28,3.67c-1.31,1.28-3.23,1.49-4.59,1.49
c-1.41,0-3.31-0.21-4.62-1.49c-1.05-1.03-1.26-2.18-1.26-3.44v-6.91H25.08z"/>
<path class="st1" d="M47.88,28.79h-3.74V27.4c-0.57,0.82-1.61,1.78-3.66,1.78c-1.71,0-2.96-0.54-3.97-1.57
c-1.19-1.18-1.82-2.83-1.82-4.61c0-1.9,0.7-3.47,1.82-4.53c1.01-0.95,2.44-1.54,4.02-1.54c1.27,0,2.67,0.41,3.61,1.67v-8.57h3.74
V28.79z M39.53,20.91c-0.54,0.51-0.9,1.26-0.9,2.18c0,0.85,0.36,1.59,0.9,2.11c0.57,0.54,1.28,0.8,1.93,0.8
c0.69,0,1.52-0.28,2.11-0.85c0.44-0.41,0.85-1.1,0.85-2.05c0-0.98-0.39-1.64-0.82-2.11c-0.59-0.62-1.28-0.85-2.08-0.85
C40.77,20.14,40.12,20.34,39.53,20.91z"/>
<path class="st1" d="M52.32,10.3c1.21,0,2.16,0.95,2.16,2.16c0,1.21-0.95,2.16-2.16,2.16c-1.21,0-2.16-0.95-2.16-2.16
C50.17,11.25,51.12,10.3,52.32,10.3z M54.19,17.35v11.44h-3.74V17.35H54.19z"/>
<path class="st1" d="M60.49,10.03v8.57c0.93-1.26,2.33-1.67,3.61-1.67c1.58,0,3.01,0.59,4.02,1.54c1.12,1.05,1.82,2.62,1.82,4.53
c0,1.78-0.62,3.42-1.82,4.61c-1.01,1.03-2.26,1.57-3.97,1.57c-2.05,0-3.09-0.95-3.66-1.78v1.39h-3.74V10.03H60.49z M61.06,20.98
c-0.44,0.46-0.82,1.13-0.82,2.11c0,0.95,0.41,1.64,0.85,2.05c0.59,0.57,1.41,0.85,2.11,0.85c0.64,0,1.36-0.26,1.93-0.8
c0.54-0.51,0.9-1.26,0.9-2.11c0-0.92-0.36-1.67-0.9-2.18c-0.59-0.57-1.23-0.77-1.98-0.77C62.34,20.14,61.65,20.37,61.06,20.98z"/>
<path class="st1" d="M80.26,17.35H84v11.44h-3.74v-1.39c-1.01,1.54-2.46,1.77-3.42,1.77c-1.66,0-3.06-0.41-4.33-1.74
c-1.22-1.28-1.69-2.77-1.69-4.28c0-1.92,0.73-3.57,1.79-4.62c1.01-1,2.41-1.56,4.02-1.56c0.99,0,2.57,0.23,3.63,1.67V17.35z
M75.57,20.96c-0.39,0.39-0.85,1.05-0.85,2.08c0,1.03,0.44,1.7,0.77,2.05c0.51,0.54,1.31,0.9,2.18,0.9c0.74,0,1.44-0.31,1.93-0.8
c0.49-0.46,0.9-1.18,0.9-2.16c0-0.82-0.31-1.59-0.85-2.11c-0.57-0.54-1.39-0.8-2.05-0.8C76.8,20.14,76.06,20.47,75.57,20.96z"/>
<path class="st1" d="M93.21,20.26c-0.57-0.33-1.31-0.64-2.03-0.64c-0.39,0-0.82,0.1-1.05,0.33c-0.13,0.13-0.23,0.33-0.23,0.51
c0,0.26,0.18,0.41,0.36,0.51c0.26,0.15,0.64,0.23,1.1,0.39l0.98,0.31c0.64,0.21,1.31,0.46,1.9,1c0.67,0.62,0.9,1.31,0.9,2.18
c0,1.52-0.67,2.49-1.18,3.01c-1.13,1.13-2.52,1.31-3.72,1.31c-1.54,0-3.21-0.33-4.7-1.64l1.57-2.49c0.36,0.31,0.87,0.67,1.26,0.85
c0.51,0.26,1.05,0.36,1.54,0.36c0.23,0,0.82,0,1.16-0.26c0.23-0.18,0.39-0.46,0.39-0.74c0-0.21-0.08-0.46-0.41-0.67
c-0.26-0.15-0.59-0.26-1.13-0.41l-0.92-0.28c-0.67-0.21-1.36-0.57-1.85-1.05c-0.54-0.57-0.82-1.21-0.82-2.08
c0-1.1,0.44-2.03,1.1-2.65c1.03-0.95,2.41-1.16,3.47-1.16c1.7,0,2.88,0.44,3.8,0.98L93.21,20.26z"/>
<path class="st1" d="M108.43,23.73h-8.55c0,0.62,0.23,1.44,0.69,1.95c0.57,0.62,1.34,0.72,1.9,0.72c0.54,0,1.1-0.1,1.49-0.33
c0.05-0.03,0.49-0.31,0.8-0.95l3.49,0.36c-0.51,1.62-1.54,2.47-2.21,2.88c-1.1,0.67-2.34,0.85-3.62,0.85
c-1.72,0-3.24-0.31-4.57-1.64c-1-1-1.72-2.52-1.72-4.42c0-1.64,0.59-3.34,1.75-4.52c1.39-1.39,3.11-1.64,4.39-1.64
c1.28,0,3.13,0.23,4.55,1.72c1.36,1.44,1.62,3.24,1.62,4.65V23.73z M105.03,21.48c-0.03-0.1-0.21-0.82-0.74-1.34
c-0.41-0.39-1-0.64-1.75-0.64c-0.95,0-1.52,0.39-1.87,0.74c-0.28,0.31-0.54,0.72-0.64,1.23H105.03z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

View File

@ -76,15 +76,14 @@
} }
.budibase__input { .budibase__input {
width: 100%;
max-width: 250px;
height: 35px; height: 35px;
width: 220px;
border-radius: 3px; border-radius: 3px;
border: 1px solid var(--grey-dark); border: 1px solid var(--grey-dark);
text-align: left; text-align: left;
color: var(--ink); color: var(--ink);
font-size: 16px; font-size: 14px;
padding-left: 5px; padding-left: 12px;
} }
.uk-text-right { .uk-text-right {

View File

@ -22,7 +22,6 @@
font-size: 14px; font-size: 14px;
position: relative; position: relative;
border: var(--grey-dark) 1px solid; border: var(--grey-dark) 1px solid;
max-width: 256px;
} }
.adjusted { .adjusted {

View File

@ -10,7 +10,6 @@
<h3 class="app-title">{name}</h3> <h3 class="app-title">{name}</h3>
<p class="app-desc">{description}</p> <p class="app-desc">{description}</p>
<div class="card-footer"> <div class="card-footer">
<div class="modified-date">Last Edited - 25th May 2020</div>
<a href={`/_builder/${_id}`} class="app-button">Open Web App</a> <a href={`/_builder/${_id}`} class="app-button">Open Web App</a>
</div> </div>
</div> </div>
@ -18,7 +17,7 @@
<style> <style>
.apps-card { .apps-card {
background-color: var(--white); background-color: var(--white);
padding: 20px; padding: 20px 20px 30px 20px;
max-width: 400px; max-width: 400px;
max-height: 150px; max-height: 150px;
border-radius: 5px; border-radius: 5px;
@ -48,14 +47,13 @@
justify-content: space-between; justify-content: space-between;
} }
.modified-date {
font-size: 14px;
color: var(--ink-light);
}
.app-button { .app-button {
align-items: center;
display: flex;
background-color: var(--white); background-color: var(--white);
color: var(--ink); color: var(--ink);
width: 100%;
justify-content: center;
padding: 12px 20px; padding: 12px 20px;
border-radius: 5px; border-radius: 5px;
border: 1px var(--grey) solid; border: 1px var(--grey) solid;

View File

@ -12,7 +12,6 @@
<div class="inner"> <div class="inner">
<div> <div>
<div> <div>
<div class="app-section-title">Your Web Apps</div>
<div class="apps"> <div class="apps">
{#each apps as app} {#each apps as app}
<AppCard {...app} /> <AppCard {...app} />
@ -26,18 +25,12 @@
<style> <style>
.apps { .apps {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, 400px); grid-template-columns: repeat(auto-fill, 380px);
grid-gap: 40px 85px; grid-gap: 20px 40px;
justify-content: start; justify-content: start;
} }
.root {
margin: 40px 80px;
}
.app-section-title { .root {
font-size: 20px; margin: 20px 80px;
color: var(--ink);
font-weight: 700;
margin-bottom: 20px;
} }
</style> </style>

View File

@ -1,5 +1,6 @@
<script> <script>
import { store } from "builderStore" import { store } from "builderStore"
import { Button } from "@budibase/bbui"
import Modal from "../../common/Modal.svelte" import Modal from "../../common/Modal.svelte"
import HandlerSelector from "./HandlerSelector.svelte" import HandlerSelector from "./HandlerSelector.svelte"
import IconButton from "../../common/IconButton.svelte" import IconButton from "../../common/IconButton.svelte"
@ -8,12 +9,12 @@
import Select from "../../common/Select.svelte" import Select from "../../common/Select.svelte"
import Input from "../../common/Input.svelte" import Input from "../../common/Input.svelte"
import getIcon from "../../common/icon" import getIcon from "../../common/icon"
import { CloseIcon } from "components/common/Icons/"
import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers" import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers"
export let event export let event
export let eventOptions = [] export let eventOptions = []
export let open
export let onClose export let onClose
let eventType = "" let eventType = ""
@ -62,105 +63,111 @@
} }
</script> </script>
<Modal bind:isOpen={open} onClosed={closeModal}> <div class="container">
<h2> <div class="body">
{eventData.name ? `${eventData.name} Event` : 'Create a New Component Event'} <div class="heading">
</h2> <h3>
<a href="https://docs.budibase.com/" target="_blank"> {eventData.name ? `${eventData.name} Event` : 'Create a New Component Event'}
Click here to learn more about component events </h3>
</a> </div>
<div class="event-options">
<div class="section">
<h4>Event Type</h4>
<Select bind:value={eventType}>
{#each eventOptions as option}
<option value={option.name}>{option.name}</option>
{/each}
</Select>
</div>
</div>
<div class="event-options"> <div class="section">
<div> <h4>Event Action(s)</h4>
<header> <HandlerSelector
<h5>Event Type</h5> newHandler
{@html getIcon('info', 20)} onChanged={updateDraftEventHandler}
</header> onCreate={() => {
<Select bind:value={eventType}> createNewEventHandler(draftEventHandler)
{#each eventOptions as option} draftEventHandler = { parameters: [] }
<option value={option.name}>{option.name}</option> }}
{/each} handler={draftEventHandler} />
</Select> </div>
{#if eventData}
{#each eventData.handlers as handler, index}
<HandlerSelector
{index}
onChanged={updateEventHandler}
onRemoved={() => deleteEventHandler(index)}
{handler} />
{/each}
{/if}
</div>
<div class="footer">
{#if eventData.name}
<Button
outline
on:click={deleteEvent}
disabled={eventData.handlers.length === 0}>
Delete
</Button>
{/if}
<div class="save">
<Button
primary
on:click={saveEventData}
disabled={eventData.handlers.length === 0}>
Save
</Button>
</div> </div>
</div> </div>
<div class="close-button" on:click={closeModal}>
<header> <CloseIcon />
<h5>Event Action(s)</h5>
{@html getIcon('info', 20)}
</header>
<HandlerSelector
newHandler
onChanged={updateDraftEventHandler}
onCreate={() => {
createNewEventHandler(draftEventHandler)
draftEventHandler = { parameters: [] }
}}
handler={draftEventHandler} />
{#if eventData}
{#each eventData.handlers as handler, index}
<HandlerSelector
{index}
onChanged={updateEventHandler}
onRemoved={() => deleteEventHandler(index)}
{handler} />
{/each}
{/if}
<div class="actions">
<ActionButton
alert
disabled={eventData.handlers.length === 0}
hidden={!eventData.name}
on:click={deleteEvent}>
Delete
</ActionButton>
<ActionButton
disabled={eventData.handlers.length === 0}
on:click={saveEventData}>
Save
</ActionButton>
</div> </div>
</Modal> </div>
<style> <style>
h2 { .container {
color: var(--primary100); position: relative;
font-size: 20px; }
font-weight: bold; .heading {
margin-bottom: 0; margin-bottom: 20px;
} }
h5 { .close-button {
color: rgba(22, 48, 87, 0.6); cursor: pointer;
font-size: 15px; position: absolute;
margin: 0; top: 20px;
right: 20px;
}
.close-button :global(svg) {
width: 24px;
height: 24px;
} }
.event-options { h4 {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
}
.actions,
header {
display: flex;
justify-content: space-between;
align-items: center;
}
.actions {
margin-top: auto;
}
header {
margin-top: 30px;
margin-bottom: 10px; margin-bottom: 10px;
} }
a { h3 {
color: rgba(22, 48, 87, 0.6); margin: 0;
font-size: 13px; font-size: 24px;
margin-top: 0; font-weight: bold;
}
.body {
padding: 40px;
display: grid;
grid-gap: 20px;
}
.footer {
display: flex;
justify-content: flex-end;
padding: 30px 40px;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 50px;
background-color: var(--grey-light);
}
.save {
margin-left: 20px;
} }
</style> </style>

View File

@ -1,4 +1,5 @@
<script> <script>
import { getContext } from "svelte"
import { import {
keys, keys,
map, map,
@ -17,7 +18,6 @@
import PlusButton from "components/common/PlusButton.svelte" import PlusButton from "components/common/PlusButton.svelte"
import IconButton from "components/common/IconButton.svelte" import IconButton from "components/common/IconButton.svelte"
import EventEditorModal from "./EventEditorModal.svelte" import EventEditorModal from "./EventEditorModal.svelte"
import HandlerSelector from "./HandlerSelector.svelte"
import { PencilIcon } from "components/common/Icons" import { PencilIcon } from "components/common/Icons"
import { EVENT_TYPE_MEMBER_NAME } from "components/common/eventHandlers" import { EVENT_TYPE_MEMBER_NAME } from "components/common/eventHandlers"
@ -26,7 +26,6 @@
export let component export let component
let modalOpen = false
let events = [] let events = []
let selectedEvent = null let selectedEvent = null
@ -40,21 +39,35 @@
})) }))
} }
// Handle create app modal
const { open, close } = getContext("simple-modal")
const openModal = event => { const openModal = event => {
selectedEvent = event selectedEvent = event
modalOpen = true open(
} EventEditorModal,
{
const closeModal = () => { eventOptions: events,
selectedEvent = null event: selectedEvent,
modalOpen = false onClose: () => {
close()
selectedEvent = null
},
},
{
closeButton: false,
closeOnEsc: false,
styleContent: { padding: 0 },
closeOnOuterClick: true,
}
)
} }
</script> </script>
<header> <button class="newevent" on:click={() => openModal()}>
<h3>Events</h3> <i class="icon ri-add-circle-fill" />
<PlusButton on:click={() => openModal()} /> Create New Event
</header> </button>
<div class="root"> <div class="root">
<form on:submit|preventDefault class="uk-form-stacked form-root"> <form on:submit|preventDefault class="uk-form-stacked form-root">
@ -71,26 +84,40 @@
{/each} {/each}
</form> </form>
</div> </div>
<EventEditorModal
open={modalOpen}
onClose={closeModal}
eventOptions={events}
event={selectedEvent} />
<style> <style>
h3 {
text-transform: uppercase;
font-size: 13px;
font-weight: 700;
color: #8997ab;
margin-bottom: 10px;
}
.root { .root {
font-size: 10pt; font-size: 10pt;
width: 100%; width: 100%;
} }
.newevent {
cursor: pointer;
border: 1px solid var(--grey-dark);
border-radius: 3px;
width: 100%;
padding: 8px 16px;
margin: 0px 0px 12px 0px;
display: flex;
justify-content: center;
align-items: center;
background: white;
color: var(--ink);
font-size: 14px;
font-weight: 500;
transition: all 2ms;
}
.newevent:hover {
background: var(--grey-light);
}
.icon {
color: var(--ink);
font-size: 16px;
margin-right: 4px;
}
.form-root { .form-root {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;

View File

@ -1,4 +1,5 @@
<script> <script>
import { Button } from "@budibase/bbui"
import IconButton from "components/common/IconButton.svelte" import IconButton from "components/common/IconButton.svelte"
import PlusButton from "components/common/PlusButton.svelte" import PlusButton from "components/common/PlusButton.svelte"
import Select from "components/common/Select.svelte" import Select from "components/common/Select.svelte"
@ -85,27 +86,28 @@
</Select> </Select>
</div> </div>
{#if parameters} {#if parameters}
<br />
{#each parameters as parameter, idx} {#each parameters as parameter, idx}
<StateBindingCascader onChange={onParameterChanged(idx)} {parameter} /> <StateBindingCascader on:change={onParameterChanged(idx)} {parameter} />
{/each} {/each}
{/if} {/if}
</div>
<div class="event-action-button">
{#if parameters.length > 0} {#if parameters.length > 0}
{#if newHandler} <div class="button-container">
<PlusButton on:click={onCreate} /> {#if newHandler}
{:else} <Button primary thin on:click={onCreate}>Add Action</Button>
<IconButton icon="x" on:click={onRemoved} /> {:else}
{/if} <Button outline thin on:click={onRemoved}>Remove Action</Button>
{/if}
</div>
{/if} {/if}
</div> </div>
</div> </div>
<style> <style>
.type-selector-container { .type-selector-container {
display: flex; display: grid;
justify-content: space-between; grid-gap: 20px;
align-items: center; width: 100%;
background: rgba(223, 223, 223, 0.5); background: rgba(223, 223, 223, 0.5);
border: 1px solid #dfdfdf; border: 1px solid #dfdfdf;
margin-bottom: 18px; margin-bottom: 18px;
@ -122,17 +124,19 @@
.handler-controls { .handler-controls {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: 1fr;
grid-gap: 10px; grid-gap: 20px;
padding: 22px; padding: 22px;
} }
.event-action-button { .button-container {
margin-right: 20px; display: grid;
justify-items: end;
} }
span { span {
font-size: 13px; font-size: 18px;
margin-bottom: 5px; margin-bottom: 10px;
font-weight: 500;
} }
</style> </style>

View File

@ -1,8 +1,8 @@
<script> <script>
import { Input } from "@budibase/bbui"
import IconButton from "components/common/IconButton.svelte" import IconButton from "components/common/IconButton.svelte"
import PlusButton from "components/common/PlusButton.svelte" import PlusButton from "components/common/PlusButton.svelte"
import Select from "components/common/Select.svelte" import Select from "components/common/Select.svelte"
import Input from "components/common/Input.svelte"
import { find, map, keys, reduce, keyBy } from "lodash/fp" import { find, map, keys, reduce, keyBy } from "lodash/fp"
import { pipe } from "components/common/core" import { pipe } from "components/common/core"
import { EVENT_TYPE_MEMBER_NAME } from "components/common/eventHandlers" import { EVENT_TYPE_MEMBER_NAME } from "components/common/eventHandlers"
@ -10,64 +10,43 @@
import { ArrowDownIcon } from "components/common/Icons/" import { ArrowDownIcon } from "components/common/Icons/"
export let parameter export let parameter
export let onChange
let isOpen = false let isOpen = false
const capitalize = s => {
if (typeof s !== "string") return ""
return s.charAt(0).toUpperCase() + s.slice(1)
}
</script> </script>
<div class="handler-option"> <div class="handler-option">
<span>{parameter.name}</span> {#if parameter.name === 'workflow'}
<div class="handler-input"> <span>{parameter.name}</span>
{#if parameter.name === 'workflow'} {/if}
<select {#if parameter.name === 'workflow'}
class="budibase__input" <Select on:change bind:value={parameter.value}>
on:change={onChange} {#each $workflowStore.workflows.filter(wf => wf.live) as workflow}
bind:value={parameter.value}> <option value={workflow._id}>{workflow.name}</option>
{#each $workflowStore.workflows.filter(wf => wf.live) as workflow} {/each}
<option value={workflow._id}>{workflow.name}</option> </Select>
{/each} {:else}
</select> <Input
{:else} name={parameter.name}
<Input {onChange} value={parameter.value} /> label={capitalize(parameter.name)}
<button on:click={() => (isOpen = !isOpen)}> on:change
<div class="icon" style={`transform: rotate(${isOpen ? 0 : 90}deg);`}> value={parameter.value} />
<ArrowDownIcon size={36} /> {/if}
</div>
</button>
{/if}
</div>
</div> </div>
<style> <style>
button {
cursor: pointer;
outline: none;
border: none;
border-radius: 5px;
background: rgba(249, 249, 249, 1);
font-size: 1.6rem;
font-weight: 700;
color: rgba(22, 48, 87, 1);
margin-left: 5px;
}
.icon {
width: 24px;
}
.handler-option { .handler-option {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.handler-input {
position: relative;
display: flex;
}
span { span {
font-size: 13px; font-size: 18px;
margin-bottom: 5px; margin-bottom: 10px;
font-weight: 500;
} }
</style> </style>

View File

@ -299,7 +299,19 @@ export const typography = [
}, },
], ],
}, },
{ label: "style", key: "font-style", control: Input }, {
label: "Decoration",
key: "text-decoration-line",
control: OptionSelect,
defaultValue: "Underline",
options: [
{ label: "Underline", value: "underline" },
{ label: "None", value: "none" },
{ label: "Overline", value: "overline" },
{ label: "Line-through", value: "line-through" },
{ label: "Under Over", value: "underline overline" },
],
},
] ]
export const background = [ export const background = [
@ -405,7 +417,7 @@ export const transitions = [
}, },
{ {
label: "Duration", label: "Duration",
key: "transition-timing-function", key: "transition-duration",
control: Input, control: Input,
width: "48px", width: "48px",
textAlign: "center", textAlign: "center",
@ -413,7 +425,7 @@ export const transitions = [
}, },
{ {
label: "Ease", label: "Ease",
key: "transition-ease", key: "transition-timing-function:",
control: OptionSelect, control: OptionSelect,
options: ["linear", "ease", "ease-in", "ease-out", "ease-in-out"], options: ["linear", "ease", "ease-in", "ease-out", "ease-in-out"],
}, },

View File

@ -343,7 +343,7 @@ export default {
children: [], children: [],
}, },
{ {
name: "List", name: "Data List",
_component: "@budibase/standard-components/datalist", _component: "@budibase/standard-components/datalist",
description: "Shiny list", description: "Shiny list",
icon: "ri-file-list-fill", icon: "ri-file-list-fill",
@ -353,6 +353,17 @@ export default {
}, },
children: [], children: [],
}, },
{
name: "List",
_component: "@budibase/standard-components/list",
description: "Shiny list",
icon: "ri-file-list-fill",
properties: {
design: { ...all },
settings: [{ label: "Model", key: "model", control: ModelSelect }],
},
children: [],
},
{ {
name: "Map", name: "Map",
_component: "@budibase/standard-components/datamap", _component: "@budibase/standard-components/datamap",

View File

@ -45,6 +45,15 @@
function testWorkflow() { function testWorkflow() {
testResult = "PASSED" testResult = "PASSED"
} }
async function saveWorkflow() {
const workflow = $workflowStore.currentWorkflow.workflow
await workflowStore.actions.save({
instanceId: $backendUiStore.selectedDatabase._id,
workflow,
})
notifier.success(`Workflow ${workflow.name} saved.`)
}
</script> </script>
<section> <section>
@ -60,7 +69,7 @@
</span> </span>
{#if !workflowBlock} {#if !workflowBlock}
<span <span
class="hoverable" class="test-tab"
class:selected={selectedTab === 'TEST'} class:selected={selectedTab === 'TEST'}
on:click={() => (selectedTab = 'TEST')}> on:click={() => (selectedTab = 'TEST')}>
Test Test
@ -86,36 +95,47 @@
{#if selectedTab === 'SETUP'} {#if selectedTab === 'SETUP'}
{#if workflowBlock} {#if workflowBlock}
<WorkflowBlockSetup {workflowBlock} /> <WorkflowBlockSetup {workflowBlock} />
<button class="workflow-button hoverable" on:click={deleteWorkflowBlock}> <div class="buttons">
Delete Block <button class="workflow-button hoverable" on:click={saveWorkflow}>
</button> Save Workflow
</button>
<button
class="delete-workflow-button hoverable"
on:click={deleteWorkflowBlock}>
Delete Block
</button>
</div>
{:else if $workflowStore.currentWorkflow} {:else if $workflowStore.currentWorkflow}
<div class="panel-body"> <div class="panel">
<label class="uk-form-label">Workflow: {workflow.name}</label> <div class="panel-body">
<div class="uk-margin config-item"> <div class="block-label">Workflow: {workflow.name}</div>
<label class="uk-form-label">Name</label> <div class="config-item">
<div class="uk-form-controls"> <label>Name</label>
<input <div class="form">
type="text" <input
class="budibase__input" type="text"
bind:value={workflow.name} /> class="budibase_input"
bind:value={workflow.name} />
</div>
</div>
<div class="config-item">
<label class="uk-form-label">User Access</label>
<div class="access-levels">
{#each ACCESS_LEVELS as { name, key }}
<span class="access-level">
<label>{name}</label>
<input class="uk-checkbox" type="checkbox" />
</span>
{/each}
</div>
</div> </div>
</div> </div>
<div class="uk-margin config-item"> <div class="buttons">
<label class="uk-form-label">User Access</label> <button class="delete-workflow-button" on:click={deleteWorkflow}>
<div class="access-levels"> Delete Workflow
{#each ACCESS_LEVELS as { name, key }} </button>
<span class="access-level">
<label>{name}</label>
<input class="uk-checkbox" type="checkbox" />
</span>
{/each}
</div>
</div> </div>
</div> </div>
<button class="workflow-button hoverable" on:click={deleteWorkflow}>
Delete Workflow
</button>
{/if} {/if}
{/if} {/if}
</section> </section>
@ -125,53 +145,119 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
justify-content: space-between;
} }
.panel-body { .panel-body {
flex: 1; flex: 1;
} }
.panel {
display: flex;
flex-direction: column;
justify-content: space-between;
}
header { header {
font-size: 20px; font-size: 20px;
font-weight: bold; font-weight: 700;
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 20px; margin-bottom: 18px;
color: var(--ink);
} }
.selected { .selected {
color: var(--font); color: var(--ink);
}
.block-label {
font-weight: 500;
font-size: 14px;
color: var(--ink);
margin: 0px 0px 16px 0px;
} }
.config-item { .config-item {
padding: 20px; margin: 0px 0px 4px 0px;
padding: 12px;
background: var(--light-grey); background: var(--light-grey);
} }
.budibase_input {
height: 35px;
width: 220px;
border-radius: 3px;
border: 1px solid var(--grey-dark);
text-align: left;
color: var(--ink);
font-size: 14px;
padding-left: 12px;
}
header > span { header > span {
color: var(--dark-grey); color: var(--ink-lighter);
margin-right: 20px; margin-right: 20px;
} }
.form {
margin-top: 12px;
}
label { label {
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
color: var(--font); color: var(--ink);
}
.buttons {
position: absolute;
bottom: 10px;
}
.delete-workflow-button {
cursor: pointer;
border: 1px solid var(--red);
border-radius: 3px;
width: 260px;
padding: 8px 16px;
display: flex;
justify-content: center;
align-items: center;
background: var(--white);
color: var(--red);
font-size: 14px;
font-weight: 500;
transition: all 2ms;
align-self: flex-end;
margin-bottom: 10px;
}
.delete-workflow-button:hover {
background: var(--red);
border: 1px solid var(--red);
color: var(--white);
} }
.workflow-button { .workflow-button {
font-family: Roboto; cursor: pointer;
border: 1px solid var(--grey-dark);
border-radius: 3px;
width: 100%; width: 100%;
border: solid 1px #f2f2f2; padding: 8px 16px;
border-radius: 2px; display: flex;
background: var(--white); justify-content: center;
height: 32px; align-items: center;
font-size: 12px; background: white;
color: var(--ink);
font-size: 14px;
font-weight: 500; font-weight: 500;
transition: all 2ms;
margin-bottom: 10px;
} }
.workflow-button:hover { .workflow-button:hover {
background: var(--light-grey); background: var(--grey-light);
} }
.access-level { .access-level {
@ -183,14 +269,15 @@
.access-level label { .access-level label {
font-weight: normal; font-weight: normal;
color: var(--ink);
} }
.test-result { .test-result {
border: none; border: none;
width: 100%; width: 100%;
border-radius: 2px; border-radius: 3px;
height: 32px; height: 32px;
font-size: 12px; font-size: 14px;
font-weight: 500; font-weight: 500;
color: var(--white); color: var(--white);
text-align: center; text-align: center;
@ -202,6 +289,6 @@
} }
.failed { .failed {
background: var(--coral); background: var(--red);
} }
</style> </style>

View File

@ -15,12 +15,12 @@
<label class="uk-form-label">{workflowBlock.type}: {workflowBlock.name}</label> <label class="uk-form-label">{workflowBlock.type}: {workflowBlock.name}</label>
{#each workflowParams as [parameter, type]} {#each workflowParams as [parameter, type]}
<div class="uk-margin block-field"> <div class="block-field">
<label class="uk-form-label">{parameter}</label> <label class="uk-form-label">{parameter}</label>
<div class="uk-form-controls"> <div class="uk-form-controls">
{#if Array.isArray(type)} {#if Array.isArray(type)}
<select <select
class="budibase__input" class="budibase_input"
bind:value={workflowBlock.args[parameter]}> bind:value={workflowBlock.args[parameter]}>
{#each type as option} {#each type as option}
<option value={option}>{option}</option> <option value={option}>{option}</option>
@ -67,8 +67,20 @@
<style> <style>
.block-field { .block-field {
border-radius: 3px; border-radius: 3px;
background: var(--light-grey); background: var(--grey-light);
padding: 20px; padding: 12px;
margin: 0px 0px 4px 0px;
}
.budibase_input {
height: 35px;
width: 220px;
border-radius: 3px;
border: 1px solid var(--grey-dark);
text-align: left;
color: var(--ink);
font-size: 14px;
padding-left: 12px;
} }
label { label {

View File

@ -35,7 +35,7 @@
<i class="ri-information-line" /> <i class="ri-information-line" />
Learn about workflows Learn about workflows
</a> </a>
<ActionButton alert on:click={onClosed}>Cancel</ActionButton> <ActionButton secondary on:click={onClosed}>Cancel</ActionButton>
<ActionButton disabled={!valid} on:click={createWorkflow}>Save</ActionButton> <ActionButton disabled={!valid} on:click={createWorkflow}>Save</ActionButton>
</footer> </footer>

View File

@ -25,19 +25,11 @@
onMount(() => { onMount(() => {
workflowStore.actions.fetch($backendUiStore.selectedDatabase._id) workflowStore.actions.fetch($backendUiStore.selectedDatabase._id)
}) })
async function saveWorkflow() {
const workflow = $workflowStore.currentWorkflow.workflow
await workflowStore.actions.save({
instanceId: $backendUiStore.selectedDatabase._id,
workflow,
})
notifier.success(`Workflow ${workflow.name} saved.`)
}
</script> </script>
<section> <section>
<button class="new-workflow-button hoverable" on:click={newWorkflow}> <button class="new-workflow-button hoverable" on:click={newWorkflow}>
<i class="icon ri-add-circle-fill" />
Create New Workflow Create New Workflow
</button> </button>
<ul> <ul>
@ -51,11 +43,6 @@
</li> </li>
{/each} {/each}
</ul> </ul>
{#if $workflowStore.currentWorkflow}
<button class="new-workflow-button hoverable" on:click={saveWorkflow}>
Save Workflow
</button>
{/if}
</section> </section>
<style> <style>
@ -87,12 +74,13 @@
} }
.workflow-item { .workflow-item {
padding: 20px;
display: flex; display: flex;
align-items: center;
border-radius: 3px; border-radius: 3px;
height: 32px; padding-left: 12px;
font-weight: 500; align-items: center;
height: 40px;
margin-bottom: 4px;
color: var(--ink);
} }
.workflow-item i { .workflow-item i {
@ -102,25 +90,36 @@
.workflow-item:hover { .workflow-item:hover {
cursor: pointer; cursor: pointer;
background: var(--secondary); background: var(--grey-light);
} }
.workflow-item.selected { .workflow-item.selected {
background: var(--secondary); background: var(--blue-light);
} }
.new-workflow-button { .new-workflow-button {
font-family: Roboto; cursor: pointer;
border: 1px solid var(--grey-dark);
border-radius: 3px;
width: 100%; width: 100%;
border: solid 1px #f2f2f2; padding: 8px 16px;
border-radius: 2px; display: flex;
background: var(--white); justify-content: center;
height: 32px; align-items: center;
font-size: 12px; background: white;
color: var(--ink);
font-size: 14px;
font-weight: 500; font-weight: 500;
transition: all 2ms;
} }
.new-workflow-button:hover { .new-workflow-button:hover {
background: var(--light-grey); background: var(--grey-light);
}
.icon {
color: var(--ink);
font-size: 16px;
margin-right: 4px;
} }
</style> </style>

View File

@ -33,8 +33,9 @@
<style> <style>
header { header {
font-size: 20px; font-size: 18px;
font-weight: bold; font-weight: 700;
background: none;
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 20px; margin-bottom: 20px;
@ -45,6 +46,10 @@
} }
span:not(.selected) { span:not(.selected) {
color: var(--dark-grey); color: var(--ink-lighter);
}
span:not(.selected):hover {
color: var(--ink);
} }
</style> </style>

View File

@ -16,6 +16,10 @@
--grey-medium: #e8e8ef; --grey-medium: #e8e8ef;
--grey-dark: #E6E6E6; --grey-dark: #E6E6E6;
--red: #E26D69;
--red-light:#FFE6E6;
--red-dark: #800400;
--primary100: #0055ff; --primary100: #0055ff;
--primary80: rgba(0, 85, 255, 0.8); --primary80: rgba(0, 85, 255, 0.8);
--primary60: #rgba(0, 85, 255, 0.6); --primary60: #rgba(0, 85, 255, 0.6);

View File

@ -106,45 +106,6 @@
overflow-y: hidden; overflow-y: hidden;
} }
.components-nav-page {
font-size: 13px;
color: var(--ink);
padding-left: 20px;
margin-top: 20px;
font-weight: 600;
opacity: 0.4;
letter-spacing: 1px;
}
.components-nav-header {
font-size: 13px;
color: var(--ink);
margin-top: 20px;
font-weight: 600;
opacity: 0.4;
letter-spacing: 1px;
}
.nav-header {
display: flex;
flex-direction: column;
margin-top: 20px;
}
.nav-items-container {
padding: 1rem 0rem 0rem 0rem;
}
.nav-group-header {
display: flex;
padding: 0px 20px 0px 20px;
font-size: 0.9rem;
font-weight: bold;
justify-content: space-between;
align-items: center;
min-height: 0;
}
.nav-group-header > div:nth-child(1) { .nav-group-header > div:nth-child(1) {
padding: 0rem 0.5rem 0rem 0rem; padding: 0rem 0.5rem 0rem 0rem;
vertical-align: bottom; vertical-align: bottom;

View File

@ -5,13 +5,17 @@
<div class="root"> <div class="root">
<div class="nav"> <div class="nav">
<WorkflowPanel /> <div class="inner">
<WorkflowPanel />
</div>
</div> </div>
<div class="content"> <div class="content">
<slot /> <slot />
</div> </div>
<div class="nav"> <div class="nav">
<SetupPanel /> <div class="inner">
<SetupPanel />
</div>
</div> </div>
</div> </div>
@ -24,7 +28,7 @@
.root { .root {
height: 100%; height: 100%;
display: flex; display: flex;
background: #fafafa; background: var(--grey-light);
} }
.content { .content {
@ -33,10 +37,13 @@
} }
.nav { .nav {
padding: 20px;
overflow: auto; overflow: auto;
width: 275px; width: 300px;
border: 1px solid var(--medium-grey); border-right: 1px solid var(--grey);
background: var(--white); background: var(--white);
} }
.inner {
padding: 20px;
}
</style> </style>

View File

@ -19,7 +19,7 @@
<div class="root"> <div class="root">
<div class="ui-nav"> <div class="ui-nav">
<div class="home-logo"> <div class="home-logo">
<img src="/_builder/assets/bb-logo.svg" alt="Budibase icon" /> <img src="/_builder/assets/budibase-logo.svg" alt="Budibase icon" />
</div> </div>
<div class="nav-section"> <div class="nav-section">

View File

@ -44,20 +44,21 @@
</script> </script>
<div class="welcome">Welcome to Budibase</div> <div class="welcome">Welcome to Budibase</div>
<div class="banner"> <div class="banner">
<img src="/_builder/assets/rocket.jpg" alt="rocket" />
<div class="banner-content"> <div class="banner-content">
<div class="banner-header"> Every accomplishment starts with a decision to try.
Every accomplishment starts with a decision to try.
</div>
<button class="banner-button" type="button" on:click={showCreateAppModal}>
<i class="ri-add-circle-fill" />
Create New Web App
</button>
</div>
<div class="banner-image">
<img src="/_builder/assets/banner-image.png" alt="Bannerimage" />
</div> </div>
</div> </div>
<div class="app-section-header">
<div class="app-section-title">Your Web Apps</div>
<button class="banner-button" type="button" on:click={showCreateAppModal}>
<i class="ri-add-circle-fill" />
Create New Web App
</button>
</div>
{#await promise} {#await promise}
<div class="spinner-container"> <div class="spinner-container">
<Spinner /> <Spinner />
@ -70,53 +71,34 @@
<style> <style>
.welcome { .welcome {
margin: 60px 80px 0px 80px;
font-size: 42px; font-size: 42px;
color: var(--ink); color: var(--ink);
font-weight: 900; font-weight: 900;
margin: 40px 0px 0px 80px;
} }
.banner { .banner {
display: grid; display: flex;
grid-template-columns: 1fr 1fr; align-items: center;
justify-content: center;
position: relative;
text-align: center;
color: white;
margin: 20px 80px 40px 80px; margin: 20px 80px 40px 80px;
background-image: linear-gradient(-45deg, #7f9ceb, #1d2f77);
border-radius: 10px; border-radius: 10px;
max-height: 280px; }
.banner img {
height: 250px;
width: 100%;
border-radius: 5px;
} }
.banner-content { .banner-content {
padding: 60px; position: absolute;
}
@media only screen and (min-width: 1800px) {
.banner-content {
padding: 80px;
}
}
.banner-header {
font-size: 24px; font-size: 24px;
color: var(--white); color: var(--white);
font-weight: 500; font-weight: 500;
margin-bottom: 20px;
}
@media only screen and (min-width: 1800px) {
.banner-header {
font-size: 36px;
color: var(--white);
font-weight: 500;
margin-bottom: 20px;
}
}
.banner-image {
z-index: 1;
}
.banner-image img {
max-height: 400px;
} }
.spinner-container { .spinner-container {
@ -128,18 +110,22 @@
} }
.banner-button { .banner-button {
background-color: var(--white); background-color: var(--ink);
color: var(--ink); color: var(--white);
padding: 12px 20px; padding: 12px 24px;
border-radius: 5px; border-radius: 5px;
border: 0px transparent solid; border: var(--ink) 1px solid;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
cursor: pointer;
transition: all 0.2s;
box-sizing: border-box; box-sizing: border-box;
align-items: center; align-items: center;
display: flex; display: flex;
cursor: pointer;
transition: all 0.2s ease 0s;
overflow: hidden;
outline: none;
user-select: none;
white-space: nowrap;
} }
.ri-add-circle-fill { .ri-add-circle-fill {
@ -148,6 +134,22 @@
} }
.banner-button:hover { .banner-button:hover {
background-color: var(--grey); background-color: var(--white);
color: var(--ink);
border: var(--grey-dark) 1px solid;
}
.app-section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin: 40px 80px 0px 80px;
}
.app-section-title {
font-size: 20px;
color: var(--ink);
font-weight: 700;
margin-bottom: 20px;
} }
</style> </style>

View File

@ -14,6 +14,7 @@ export const attachChildren = initialiseOpts => (htmlElement, options) => {
const anchor = options && options.anchor ? options.anchor : null const anchor = options && options.anchor ? options.anchor : null
const force = options ? options.force : false const force = options ? options.force : false
const hydrate = options ? options.hydrate : true const hydrate = options ? options.hydrate : true
const context = options && options.context
if (!force && treeNode.children.length > 0) return treeNode.children if (!force && treeNode.children.length > 0) return treeNode.children
@ -37,16 +38,27 @@ export const attachChildren = initialiseOpts => (htmlElement, options) => {
const ComponentConstructor = componentLibraries[libName][componentName] const ComponentConstructor = componentLibraries[libName][componentName]
const childNodesThisIteration = prepareRenderComponent({ const prepareNodes = ctx => {
props: childProps, const childNodesThisIteration = prepareRenderComponent({
parentNode: treeNode, props: childProps,
ComponentConstructor, parentNode: treeNode,
htmlElement, ComponentConstructor,
anchor, htmlElement,
}) anchor,
context: ctx,
})
for (let childNode of childNodesThisIteration) { for (let childNode of childNodesThisIteration) {
childNodes.push(childNode) childNodes.push(childNode)
}
}
if (Array.isArray(context)) {
for (let singleCtx of context) {
prepareNodes(singleCtx)
}
} else {
prepareNodes(context)
} }
} }

View File

@ -7,11 +7,12 @@ export const prepareRenderComponent = ({
anchor, anchor,
props, props,
parentNode, parentNode,
context,
}) => { }) => {
const parentContext = (parentNode && parentNode.context) || {} const parentContext = (parentNode && parentNode.context) || {}
let nodesToRender = [] let nodesToRender = []
const createNodeAndRender = context => { const createNodeAndRender = () => {
let componentContext = parentContext let componentContext = parentContext
if (context) { if (context) {
componentContext = { ...context } componentContext = { ...context }
@ -48,6 +49,7 @@ export const prepareRenderComponent = ({
if (typeof propValue === "string") { if (typeof propValue === "string") {
storeBoundProps[prop] = mustache.render(propValue, { storeBoundProps[prop] = mustache.render(propValue, {
state, state,
context: componentContext,
}) })
} }
} }

View File

@ -56,8 +56,30 @@ export const screenRouter = ({ screens, onScreenSelected, appRootPath }) => {
} }
} }
function click(e) {
const x = e.target.closest("a")
const y = x && x.getAttribute("href")
if (
e.ctrlKey ||
e.metaKey ||
e.altKey ||
e.shiftKey ||
e.button ||
e.defaultPrevented
)
return
const target = x.target || "_self"
if (!y || target !== "_self" || x.host !== location.host) return
e.preventDefault()
route(y)
}
addEventListener("popstate", route) addEventListener("popstate", route)
addEventListener("pushstate", route) addEventListener("pushstate", route)
addEventListener("click", click)
return route return route
} }

View File

@ -23,7 +23,7 @@ export const bbFactory = ({
} }
const apiCall = method => (url, body) => const apiCall = method => (url, body) =>
fetch(relativeUrl(url), { fetch(url, {
method: method, method: method,
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",

View File

@ -15,7 +15,4 @@ JWT_SECRET={{cookieKey1}}
PORT=4001 PORT=4001
# error level for koa-pino # error level for koa-pino
LOG_LEVEL=error LOG_LEVEL=error
# Budibase app directory
BUDIBASE_DIR=~/.budibase

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 115 40" style="enable-background:new 0 0 115 40;" xml:space="preserve">
<style type="text/css">
.st0{fill:#393C44;}
.st1{fill:#FFFFFF;}
</style>
<path class="st0" d="M111.16,40H3.91c-2.15,0-3.89-1.74-3.89-3.89V4.04c0-2.15,1.74-3.89,3.89-3.89h107.25
c2.15,0,3.89,1.74,3.89,3.89v32.07C115.05,38.26,113.31,40,111.16,40z"/>
<path class="st1" d="M10.37,10.03v8.57c0.93-1.26,2.33-1.67,3.61-1.67c1.58,0,3.01,0.59,4.02,1.54c1.12,1.05,1.82,2.62,1.82,4.53
c0,1.78-0.62,3.42-1.82,4.61c-1.01,1.03-2.26,1.57-3.97,1.57c-2.05,0-3.09-0.95-3.66-1.78v1.39H6.63V10.03H10.37z M10.97,20.98
c-0.44,0.46-0.82,1.13-0.82,2.11c0,0.95,0.41,1.64,0.85,2.05c0.59,0.57,1.41,0.85,2.11,0.85c0.64,0,1.36-0.26,1.93-0.8
c0.54-0.51,0.9-1.26,0.9-2.11c0-0.92-0.36-1.67-0.9-2.18c-0.59-0.57-1.23-0.77-1.98-0.77C12.26,20.14,11.56,20.37,10.97,20.98z"/>
<path class="st1" d="M25.08,17.35v6.32c0,0.51,0.05,1.31,0.64,1.85c0.26,0.23,0.72,0.54,1.54,0.54c0.69,0,1.23-0.23,1.56-0.54
c0.54-0.51,0.62-1.28,0.62-1.85v-6.32h3.74v6.68c0,1.31-0.13,2.54-1.28,3.67c-1.31,1.28-3.23,1.49-4.59,1.49
c-1.41,0-3.31-0.21-4.62-1.49c-1.05-1.03-1.26-2.18-1.26-3.44v-6.91H25.08z"/>
<path class="st1" d="M47.88,28.79h-3.74V27.4c-0.57,0.82-1.61,1.78-3.66,1.78c-1.71,0-2.96-0.54-3.97-1.57
c-1.19-1.18-1.82-2.83-1.82-4.61c0-1.9,0.7-3.47,1.82-4.53c1.01-0.95,2.44-1.54,4.02-1.54c1.27,0,2.67,0.41,3.61,1.67v-8.57h3.74
V28.79z M39.53,20.91c-0.54,0.51-0.9,1.26-0.9,2.18c0,0.85,0.36,1.59,0.9,2.11c0.57,0.54,1.28,0.8,1.93,0.8
c0.69,0,1.52-0.28,2.11-0.85c0.44-0.41,0.85-1.1,0.85-2.05c0-0.98-0.39-1.64-0.82-2.11c-0.59-0.62-1.28-0.85-2.08-0.85
C40.77,20.14,40.12,20.34,39.53,20.91z"/>
<path class="st1" d="M52.32,10.3c1.21,0,2.16,0.95,2.16,2.16c0,1.21-0.95,2.16-2.16,2.16c-1.21,0-2.16-0.95-2.16-2.16
C50.17,11.25,51.12,10.3,52.32,10.3z M54.19,17.35v11.44h-3.74V17.35H54.19z"/>
<path class="st1" d="M60.49,10.03v8.57c0.93-1.26,2.33-1.67,3.61-1.67c1.58,0,3.01,0.59,4.02,1.54c1.12,1.05,1.82,2.62,1.82,4.53
c0,1.78-0.62,3.42-1.82,4.61c-1.01,1.03-2.26,1.57-3.97,1.57c-2.05,0-3.09-0.95-3.66-1.78v1.39h-3.74V10.03H60.49z M61.06,20.98
c-0.44,0.46-0.82,1.13-0.82,2.11c0,0.95,0.41,1.64,0.85,2.05c0.59,0.57,1.41,0.85,2.11,0.85c0.64,0,1.36-0.26,1.93-0.8
c0.54-0.51,0.9-1.26,0.9-2.11c0-0.92-0.36-1.67-0.9-2.18c-0.59-0.57-1.23-0.77-1.98-0.77C62.34,20.14,61.65,20.37,61.06,20.98z"/>
<path class="st1" d="M80.26,17.35H84v11.44h-3.74v-1.39c-1.01,1.54-2.46,1.77-3.42,1.77c-1.66,0-3.06-0.41-4.33-1.74
c-1.22-1.28-1.69-2.77-1.69-4.28c0-1.92,0.73-3.57,1.79-4.62c1.01-1,2.41-1.56,4.02-1.56c0.99,0,2.57,0.23,3.63,1.67V17.35z
M75.57,20.96c-0.39,0.39-0.85,1.05-0.85,2.08c0,1.03,0.44,1.7,0.77,2.05c0.51,0.54,1.31,0.9,2.18,0.9c0.74,0,1.44-0.31,1.93-0.8
c0.49-0.46,0.9-1.18,0.9-2.16c0-0.82-0.31-1.59-0.85-2.11c-0.57-0.54-1.39-0.8-2.05-0.8C76.8,20.14,76.06,20.47,75.57,20.96z"/>
<path class="st1" d="M93.21,20.26c-0.57-0.33-1.31-0.64-2.03-0.64c-0.39,0-0.82,0.1-1.05,0.33c-0.13,0.13-0.23,0.33-0.23,0.51
c0,0.26,0.18,0.41,0.36,0.51c0.26,0.15,0.64,0.23,1.1,0.39l0.98,0.31c0.64,0.21,1.31,0.46,1.9,1c0.67,0.62,0.9,1.31,0.9,2.18
c0,1.52-0.67,2.49-1.18,3.01c-1.13,1.13-2.52,1.31-3.72,1.31c-1.54,0-3.21-0.33-4.7-1.64l1.57-2.49c0.36,0.31,0.87,0.67,1.26,0.85
c0.51,0.26,1.05,0.36,1.54,0.36c0.23,0,0.82,0,1.16-0.26c0.23-0.18,0.39-0.46,0.39-0.74c0-0.21-0.08-0.46-0.41-0.67
c-0.26-0.15-0.59-0.26-1.13-0.41l-0.92-0.28c-0.67-0.21-1.36-0.57-1.85-1.05c-0.54-0.57-0.82-1.21-0.82-2.08
c0-1.1,0.44-2.03,1.1-2.65c1.03-0.95,2.41-1.16,3.47-1.16c1.7,0,2.88,0.44,3.8,0.98L93.21,20.26z"/>
<path class="st1" d="M108.43,23.73h-8.55c0,0.62,0.23,1.44,0.69,1.95c0.57,0.62,1.34,0.72,1.9,0.72c0.54,0,1.1-0.1,1.49-0.33
c0.05-0.03,0.49-0.31,0.8-0.95l3.49,0.36c-0.51,1.62-1.54,2.47-2.21,2.88c-1.1,0.67-2.34,0.85-3.62,0.85
c-1.72,0-3.24-0.31-4.57-1.64c-1-1-1.72-2.52-1.72-4.42c0-1.64,0.59-3.34,1.75-4.52c1.39-1.39,3.11-1.64,4.39-1.64
c1.28,0,3.13,0.23,4.55,1.72c1.36,1.44,1.62,3.24,1.62,4.65V23.73z M105.03,21.48c-0.03-0.1-0.21-0.82-0.74-1.34
c-0.41-0.39-1-0.64-1.75-0.64c-0.95,0-1.52,0.39-1.87,0.74c-0.28,0.31-0.54,0.72-0.64,1.23H105.03z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

View File

@ -6,6 +6,7 @@ const env = require("../../environment")
const instanceController = require("./instance") const instanceController = require("./instance")
const { resolve, join } = require("path") const { resolve, join } = require("path")
const { copy, exists, readFile, writeFile } = require("fs-extra") const { copy, exists, readFile, writeFile } = require("fs-extra")
const { budibaseAppsDir } = require("../../utilities/budibaseDir")
const { exec } = require("child_process") const { exec } = require("child_process")
const sqrl = require("squirrelly") const sqrl = require("squirrelly")
@ -73,7 +74,7 @@ const createEmptyAppPackage = async (ctx, app) => {
"appDirectoryTemplate" "appDirectoryTemplate"
) )
const appsFolder = env.BUDIBASE_DIR const appsFolder = budibaseAppsDir()
const newAppFolder = resolve(appsFolder, app._id) const newAppFolder = resolve(appsFolder, app._id)
if (await exists(newAppFolder)) { if (await exists(newAppFolder)) {

View File

@ -22,7 +22,7 @@ async function executeRelevantWorkflows(event, eventType) {
} }
} }
emitter.on("action", async function(event) { emitter.on("record:save", async function(event) {
await executeRelevantWorkflows(event, "record:save") await executeRelevantWorkflows(event, "record:save")
}) })

View File

@ -40,7 +40,7 @@ exports.serverStrategy = () => ({
if (block.type === "CLIENT") continue if (block.type === "CLIENT") continue
const action = require(`../api/controllers/workflow/actions/${block.actionId}`) const action = require(`../api/controllers/workflow/actions/${block.actionId}`)
const response = await action(this.bindContextArgs(block.args)) const response = await action({ args: this.bindContextArgs(block.args) })
this.context = { this.context = {
...this.context, ...this.context,

View File

@ -45,7 +45,7 @@ const copyClientLib = async (appPath, pageName) => {
const buildIndexHtml = async (config, appId, pageName, appPath, pkg) => { const buildIndexHtml = async (config, appId, pageName, appPath, pkg) => {
const appPublicPath = publicPath(appPath, pageName) const appPublicPath = publicPath(appPath, pageName)
const appRootPath = appId const appRootPath = rootPath(config, appId)
const stylesheetUrl = s => const stylesheetUrl = s =>
s.startsWith("http") ? s : `/${rootPath(config, appId)}/${s}` s.startsWith("http") ? s : `/${rootPath(config, appId)}/${s}`

View File

@ -217,6 +217,21 @@
} }
} }
}, },
"list": {
"description": "A configurable data list that attaches to your backend models.",
"data": true,
"props": {
"model": "models",
"layout": {
"type": "options",
"default": "list",
"options": [
"list",
"grid"
]
}
}
},
"datamap": { "datamap": {
"description": "shiny chart", "description": "shiny chart",
"data": true, "data": true,

View File

@ -17,7 +17,7 @@
<button <button
bind:this={theButton} bind:this={theButton}
class={className} class="default"
disabled={disabled || false} disabled={disabled || false}
on:click={clickHandler}> on:click={clickHandler}>
{#if !_bb.props._children || _bb.props._children.length === 0}{text}{/if} {#if !_bb.props._children || _bb.props._children.length === 0}{text}{/if}
@ -25,23 +25,21 @@
<style> <style>
.default { .default {
font-family: inherit; align-items: center;
font-size: inherit; font-family: Inter;
padding: 0.4em; font-size: 16px;
margin: 0 0 0.5em 0; padding: 0px 16px;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid #ccc; border-radius: 4px;
border-radius: 2px;
color: #000333;
outline: none; outline: none;
} height: 40px;
cursor: pointer;
.default:active { transition: all 0.2s ease 0s;
background-color: #f9f9f9; overflow: hidden;
} outline: none;
user-select: none;
.default:focus { white-space: nowrap;
border-color: #666; text-align: center;
} }
.border { .border {

View File

@ -58,24 +58,96 @@
} }
</script> </script>
<form class="uk-form" on:submit|preventDefault> <form class="form" on:submit|preventDefault>
<h4>{modelDef.name}</h4> <h1>{modelDef.name} Form</h1>
<div> <div class="form-content">
{#each fields as field} {#each fields as field}
<div class="uk-margin"> <div class="form-item">
<label class="form-label" for="form-stacked-text">{field}</label> <label class="form-label" for="form-stacked-text">{field}</label>
<input <input
class="uk-input" class="input"
placeholder={field}
type={schema[field].type === 'string' ? 'text' : schema[field].type} type={schema[field].type === 'string' ? 'text' : schema[field].type}
on:change={handleInput(field)} /> on:change={handleInput(field)} />
</div> </div>
<hr />
{/each} {/each}
<div class="button-block">
<button on:click={save}>Submit Form</button>
</div>
</div> </div>
<button on:click={save}>SAVE</button>
</form> </form>
<style> <style>
.form {
display: flex;
flex-direction: column;
align-items: center;
}
.form-content {
margin-bottom: 20px;
}
.input {
width: 600px;
height: 40px;
border-radius: 5px;
border: 1px solid #e6e6e6;
padding: 6px 12px 6px 12px;
font-size: 16px;
}
.form-item {
display: flex;
flex-direction: column;
margin-bottom: 16px;
}
.form-label { .form-label {
font-weight: bold; font-weight: bold;
margin-bottom: 12px;
}
hr {
border: 1px solid #fafafa;
margin: 20px 0px;
}
hr:nth-last-child(2) {
border: 1px solid #fff;
margin: 20px 0px;
}
.button-block {
display: flex;
justify-content: flex-end;
}
button {
font-family: roboto;
font-size: 16px;
padding: 0.4em;
box-sizing: border-box;
border-radius: 4px;
color: white;
background-color: #393c44;
outline: none;
width: 300px;
height: 40px;
cursor: pointer;
transition: all 0.2s ease 0s;
overflow: hidden;
outline: none;
user-select: none;
white-space: nowrap;
text-align: center;
}
button:hover {
background-color: white;
border-color: #393c44;
color: #393c44;
} }
</style> </style>

View File

@ -65,24 +65,31 @@
} }
thead { thead {
background: #f9f9f9; background: #393C44;
border: 1px solid #ccc; border: 1px solid #ccc;
height: 40px;
text-align: left;
margin-right: 60px;
} }
thead th { thead th {
color: var(--button-text); color: #ffffff;
text-transform: capitalize; text-transform: capitalize;
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
letter-spacing: 1px; letter-spacing: 1px;
justify-content: left;
padding: 16px 20px 16px 8px;
margin-right: 20px;
} }
tbody tr { tbody tr {
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
transition: 0.3s background-color; transition: 0.3s background-color;
color: var(--secondary100); color: #393C44;
font-size: 14px; font-size: 14px;
height: 40px;
} }
tbody tr:hover { tbody tr:hover {

View File

@ -13,7 +13,7 @@
$: target = openInNewTab ? "_blank" : "_self" $: target = openInNewTab ? "_blank" : "_self"
</script> </script>
<a href={_bb.relativeUrl(url)} bind:this={anchorElement} {target}>{text}</a> <a href={url} bind:this={anchorElement} {target}>{text}</a>
<style> <style>
.textDecoration { .textDecoration {

View File

@ -0,0 +1,72 @@
<script>
import { onMount } from "svelte"
export let _bb
export let _instanceId
export let model
export let layout = "list"
let headers = []
let store = _bb.store
let target
async function fetchData() {
if (!model || !model.length) return
const FETCH_RECORDS_URL = `/api/${_instanceId}/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
_bb.attachChildren(target, {
hydrate: false,
context: json,
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
$: if (model) fetchData()
onMount(async () => {
await fetchData()
})
</script>
<section class:grid={layout === 'grid'} class:list={layout === 'list'}>
<div class="data-card" bind:this={target} />
</section>
<style>
.list {
display: flex;
flex-direction: column;
font-family: Roboto;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
ul {
list-style-type: none;
}
li {
margin: 5px 0 5px 0;
}
.data-card {
border: 1px solid #ccc;
border-radius: 5px;
padding: 10px;
}
.data-key {
font-weight: bold;
font-size: 20px;
text-transform: capitalize;
}
</style>

View File

@ -25,9 +25,16 @@
const login = async () => { const login = async () => {
loading = true loading = true
const response = await _bb.api.post("/api/authenticate", { const response = await fetch(_bb.relativeUrl("/api/authenticate"), {
username, body: JSON.stringify({
password, username,
password,
}),
headers: {
"Content-Type": "application/json",
"x-user-agent": "Budibase Builder",
},
method: "POST",
}) })
if (response.status === 200) { if (response.status === 200) {
@ -72,7 +79,7 @@
<div class="login-button-container"> <div class="login-button-container">
<button disabled={loading} on:click={login} class={_buttonClass}> <button disabled={loading} on:click={login} class={_buttonClass}>
{loginButtonLabel} Log in to {name}
</button> </button>
</div> </div>

View File

@ -18,5 +18,6 @@ export { default as datatable } from "./DataTable.svelte"
export { default as dataform } from "./DataForm.svelte" export { default as dataform } from "./DataForm.svelte"
export { default as datachart } from "./DataChart.svelte" export { default as datachart } from "./DataChart.svelte"
export { default as datalist } from "./DataList.svelte" export { default as datalist } from "./DataList.svelte"
export { default as list } from "./List.svelte"
export { default as datasearch } from "./DataSearch.svelte" export { default as datasearch } from "./DataSearch.svelte"
export { default as datamap } from "./DataMap.svelte" export { default as datamap } from "./DataMap.svelte"

8
pull_request_template.md Normal file
View File

@ -0,0 +1,8 @@
## Description
_Describe the problem or feature in addition to a link to the relevant github issues._
## Screenshots
_If a UI facing feature, some screenshots of the new functionality._