Merge branch 'spectrum-bbui' of github.com:Budibase/budibase into spectrum-bbui

This commit is contained in:
mike12345567 2021-04-28 14:58:18 +01:00
commit 04d1fca3f2
23 changed files with 308 additions and 412 deletions

View File

@ -1,10 +1,16 @@
<div class="drawer-contents"> <div class="drawer-contents">
<div class="container" data-cy="binding-dropdown-modal"> <div
<div class="sidebar"> class:no-sidebar={!$$slots.sidebar}
<slot name="sidebar" /> class="container"
</div> data-cy="binding-dropdown-modal"
>
{#if $$slots.sidebar}
<div class="sidebar">
<slot name="sidebar" />
</div>
{/if}
<div class="main"> <div class="main">
<slot name="main" /> <slot />
</div> </div>
</div> </div>
</div> </div>
@ -19,6 +25,9 @@
display: grid; display: grid;
grid-template-columns: 290px 1fr; grid-template-columns: 290px 1fr;
} }
.no-sidebar {
grid-template-columns: 1fr;
}
.sidebar { .sidebar {
border-right: var(--border-light); border-right: var(--border-light);
overflow: auto; overflow: auto;

View File

@ -1,49 +0,0 @@
<script>
export let extraSmall = false
export let small = false
export let medium = false
export let large = false
export let extraLarge = false
</script>
<spacer
class:extraSmall
class:small
class:medium
class:large
class:extraLarge />
<style>
spacer {
display: block;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.extraSmall {
height: var(--spacing-xs);
width: var(--spacing-xs);
}
.small {
height: var(--spacing-s);
width: var(--spacing-s);
}
.medium {
height: var(--spacing-m);
width: var(--spacing-m);
}
.large {
height: var(--spacing-l);
width: var(--spacing-l);
}
.extraLarge {
height: var(--spacing-xl);
width: var(--spacing-xl);
}
</style>

View File

@ -1,51 +0,0 @@
<script>
import { View } from "svench";
import Spacer from "./Spacer.svelte";
</script>
<style>
.block {
background: black;
height: 100px;
width: 100px;
border-radius: var(--border-radius-s);
}
.horizontal {
display: flex;
}
</style>
<View name="extraSmall">
<div class="block"></div>
<Spacer extraSmall />
<div class="block"></div>
</View>
<View name="Small">
<div class="block"></div>
<Spacer small />
<div class="block"></div>
</View>
<View name="Medium">
<div class="block"></div>
<Spacer medium />
<div class="block"></div>
</View>
<View name="Large">
<div class="horizontal">
<div class="block"></div>
<Spacer large />
<div class="block"></div>
</div>
</View>
<View name="extraLarge">
<div class="horizontal">
<div class="block"></div>
<Spacer extraLarge />
<div class="block"></div>
</div>
</View>

View File

@ -10,7 +10,7 @@ export { default as Select } from "./Form/Select.svelte"
export { default as Combobox } from "./Form/Combobox.svelte" export { default as Combobox } from "./Form/Combobox.svelte"
export { default as Dropzone } from "./Form/Dropzone.svelte" export { default as Dropzone } from "./Form/Dropzone.svelte"
export { default as Drawer } from "./Drawer/Drawer.svelte" export { default as Drawer } from "./Drawer/Drawer.svelte"
export { default as DrawerContentWithSidebar } from "./Drawer/DrawerContentWithSidebar.svelte" export { default as DrawerContent } from "./Drawer/DrawerContent.svelte"
export { default as Avatar } from "./Avatar/Avatar.svelte" export { default as Avatar } from "./Avatar/Avatar.svelte"
export { default as ActionButton } from "./ActionButton/ActionButton.svelte" export { default as ActionButton } from "./ActionButton/ActionButton.svelte"
export { default as ActionGroup } from "./ActionGroup/ActionGroup.svelte" export { default as ActionGroup } from "./ActionGroup/ActionGroup.svelte"
@ -36,7 +36,6 @@ export { default as MenuItem } from "./Menu/Item.svelte"
export { default as Modal } from "./Modal/Modal.svelte" export { default as Modal } from "./Modal/Modal.svelte"
export { default as ModalContent } from "./Modal/ModalContent.svelte" export { default as ModalContent } from "./Modal/ModalContent.svelte"
export { default as NotificationDisplay } from "./Notification/NotificationDisplay.svelte" export { default as NotificationDisplay } from "./Notification/NotificationDisplay.svelte"
export { default as Spacer } from "./Spacer/Spacer.svelte"
export { default as SideNavigation } from "./SideNavigation/Navigation.svelte" export { default as SideNavigation } from "./SideNavigation/Navigation.svelte"
export { default as SideNavigationItem } from "./SideNavigation/Item.svelte" export { default as SideNavigationItem } from "./SideNavigation/Item.svelte"
export { default as DatePicker } from "./Form/DatePicker.svelte" export { default as DatePicker } from "./Form/DatePicker.svelte"

View File

@ -252,7 +252,7 @@ export const getSchemaForDatasource = (datasource, isForm = false) => {
if (datasource) { if (datasource) {
const { type } = datasource const { type } = datasource
if (type === "query") { if (type === "query") {
const queries = get(queriesStores).queries const queries = get(queriesStores).list
table = queries.find(query => query._id === datasource._id) table = queries.find(query => query._id === datasource._id)
} else { } else {
const tables = get(tablesStore).list const tables = get(tablesStore).list

View File

@ -1,6 +1,12 @@
<script> <script>
import groupBy from "lodash/fp/groupBy" import groupBy from "lodash/fp/groupBy"
import { Input, TextArea, Heading, Layout } from "@budibase/bbui" import {
Input,
TextArea,
Heading,
Layout,
DrawerContent,
} from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { isValid } from "@budibase/string-templates" import { isValid } from "@budibase/string-templates"
import { handlebarsCompletions } from "constants/completions" import { handlebarsCompletions } from "constants/completions"
@ -44,8 +50,8 @@
} }
</script> </script>
<div class="container"> <DrawerContent>
<div class="list"> <div slot="sidebar" class="list">
<Layout> <Layout>
<div class="section"> <div class="section">
<Heading s h3>Available bindings</Heading> <Heading s h3>Available bindings</Heading>
@ -98,16 +104,9 @@
</p> </p>
{/if} {/if}
</div> </div>
</div> </DrawerContent>
<style> <style>
.container {
height: 40vh;
overflow-y: auto;
display: grid;
grid-template-columns: 290px 1fr;
}
.list { .list {
grid-gap: var(--spacing-s); grid-gap: var(--spacing-s);
border-right: var(--border-light); border-right: var(--border-light);

View File

@ -4,7 +4,6 @@
Label, Label,
Input, Input,
Select, Select,
Spacer,
notifications, notifications,
Body, Body,
ModalContent, ModalContent,
@ -39,10 +38,11 @@
<Input value={capitalise(level)} disabled /> <Input value={capitalise(level)} disabled />
<Select <Select
value={permissions[level]} value={permissions[level]}
on:change={e => changePermission(level, e.detail)} on:change={(e) => changePermission(level, e.detail)}
options={$roles} options={$roles}
getOptionLabel={x => x.name} getOptionLabel={(x) => x.name}
getOptionValue={x => x._id} /> getOptionValue={(x) => x._id}
/>
{/each} {/each}
</div> </div>
</ModalContent> </ModalContent>

View File

@ -1,34 +1,33 @@
<script> <script>
import { Label, Input, Spacer } from "@budibase/bbui" import { Label, Input, Layout } from "@budibase/bbui"
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte" import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
import { capitalise } from "../../../../helpers" import { capitalise } from "../../../../helpers"
export let integration export let integration
export let schema export let schema
let unsaved = false
</script> </script>
<form> <form>
{#each Object.keys(schema) as configKey} <Layout gap="S">
{#if schema[configKey].type === "object"} {#each Object.keys(schema) as configKey}
<Label>{capitalise(configKey)}</Label> {#if schema[configKey].type === "object"}
<Spacer small />
<KeyValueBuilder
defaults={schema[configKey].default}
bind:object={integration[configKey]}
/>
{:else}
<div class="form-row">
<Label>{capitalise(configKey)}</Label> <Label>{capitalise(configKey)}</Label>
<Input <KeyValueBuilder
type={schema[configKey].type} defaults={schema[configKey].default}
on:change bind:object={integration[configKey]}
bind:value={integration[configKey]}
/> />
</div> {:else}
{/if} <div class="form-row">
{/each} <Label>{capitalise(configKey)}</Label>
<Input
type={schema[configKey].type}
on:change
bind:value={integration[configKey]}
/>
</div>
{/if}
{/each}
</Layout>
</form> </form>
<style> <style>
@ -37,6 +36,5 @@
grid-template-columns: 20% 1fr; grid-template-columns: 20% 1fr;
grid-gap: var(--spacing-l); grid-gap: var(--spacing-l);
align-items: center; align-items: center;
margin-bottom: var(--spacing-m);
} }
</style> </style>

View File

@ -1,6 +1,6 @@
<script> <script>
import groupBy from "lodash/fp/groupBy" import groupBy from "lodash/fp/groupBy"
import { Search, TextArea, Heading, Label, DrawerContentWithSidebar, Layout } from "@budibase/bbui" import { Search, TextArea, Heading, Label, DrawerContent, Layout } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { isValid } from "@budibase/string-templates" import { isValid } from "@budibase/string-templates"
import { import {
@ -57,7 +57,7 @@
} }
</script> </script>
<DrawerContentWithSidebar> <DrawerContent>
<svelte:fragment slot="sidebar"> <svelte:fragment slot="sidebar">
<Layout> <Layout>
<Search placeholder="Search" bind:value={search} /> <Search placeholder="Search" bind:value={search} />
@ -107,7 +107,7 @@
</section> </section>
</Layout> </Layout>
</svelte:fragment> </svelte:fragment>
<div class="main" slot="main"> <div class="main">
<TextArea <TextArea
bind:getCaretPosition bind:getCaretPosition
bind:value bind:value
@ -121,7 +121,7 @@
</p> </p>
{/if} {/if}
</div> </div>
</DrawerContentWithSidebar> </DrawerContent>
<style> <style>
.main { .main {

View File

@ -2,13 +2,13 @@
import { getBindableProperties } from "builderStore/dataBinding" import { getBindableProperties } from "builderStore/dataBinding"
import { import {
Button, Button,
Icon,
Popover, Popover,
Divider, Divider,
Select, Select,
Spacer, Layout,
Heading, Heading,
Drawer, Drawer,
DrawerContent,
} from "@budibase/bbui" } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { store, currentAsset } from "builderStore" import { store, currentAsset } from "builderStore"
@ -30,7 +30,7 @@
export let showAllQueries export let showAllQueries
$: text = value?.label ?? "Choose an option" $: text = value?.label ?? "Choose an option"
$: tables = $tablesStore.list.map(m => ({ $: tables = $tablesStore.list.map((m) => ({
label: m.name, label: m.name,
tableId: m._id, tableId: m._id,
type: "table", type: "table",
@ -46,9 +46,9 @@
}, []) }, [])
$: queries = $queriesStore.list $: queries = $queriesStore.list
.filter( .filter(
query => showAllQueries || query.queryVerb === "read" || query.readable (query) => showAllQueries || query.queryVerb === "read" || query.readable
) )
.map(query => ({ .map((query) => ({
label: query.name, label: query.name,
name: query.name, name: query.name,
tableId: query._id, tableId: query._id,
@ -61,15 +61,15 @@
$currentAsset, $currentAsset,
$store.selectedComponentId $store.selectedComponentId
) )
$: queryBindableProperties = bindableProperties.map(property => ({ $: queryBindableProperties = bindableProperties.map((property) => ({
...property, ...property,
category: property.type === "instance" ? "Component" : "Table", category: property.type === "instance" ? "Component" : "Table",
label: property.readableBinding, label: property.readableBinding,
path: property.readableBinding, path: property.readableBinding,
})) }))
$: links = bindableProperties $: links = bindableProperties
.filter(x => x.fieldSchema?.type === "link") .filter((x) => x.fieldSchema?.type === "link")
.map(property => { .map((property) => {
return { return {
providerId: property.providerId, providerId: property.providerId,
label: property.readableBinding, label: property.readableBinding,
@ -89,7 +89,7 @@
} }
function fetchQueryDefinition(query) { function fetchQueryDefinition(query) {
const source = $datasources.list.find(ds => ds._id === query.datasourceId) const source = $datasources.list.find((ds) => ds._id === query.datasourceId)
.source .source
return $integrations[source].query[query.queryVerb] return $integrations[source].query[query.queryVerb]
} }
@ -100,38 +100,43 @@
readonly readonly
value={text} value={text}
options={[text]} options={[text]}
on:click={dropdownRight.show} /> on:click={dropdownRight.show}
{#if value?.type === 'query'} />
{#if value?.type === "query"}
<i class="ri-settings-5-line" on:click={drawer.show} /> <i class="ri-settings-5-line" on:click={drawer.show} />
<Drawer title={'Query Parameters'} bind:this={drawer}> <Drawer title={"Query Parameters"} bind:this={drawer}>
<div slot="buttons"> <Button
<Button slot="buttons"
blue cta
thin on:click={() => {
on:click={() => { notifications.success("Query parameters saved.")
notifications.success('Query parameters saved.') handleSelected(value)
handleSelected(value) drawer.hide()
drawer.hide() }}
}}> >
Save Save
</Button> </Button>
</div> <DrawerContent slot="body">
<div class="drawer-contents" slot="body"> <Layout>
{#if value.parameters.length > 0} {#if value.parameters.length > 0}
<ParameterBuilder <ParameterBuilder
bind:customParams={value.queryParams} bind:customParams={value.queryParams}
parameters={queries.find(query => query._id === value._id).parameters} parameters={queries.find((query) => query._id === value._id)
bindings={queryBindableProperties} /> .parameters}
{/if} bindings={queryBindableProperties}
<!-- <Spacer large />--> />
<IntegrationQueryEditor {/if}
height={200} <IntegrationQueryEditor
query={value} height={200}
schema={fetchQueryDefinition(value)} query={value}
datasource={$datasources.list.find(ds => ds._id === value.datasourceId)} schema={fetchQueryDefinition(value)}
editable={false} /> datasource={$datasources.list.find(
<Spacer large /> (ds) => ds._id === value.datasourceId
</div> )}
editable={false}
/>
</Layout>
</DrawerContent>
</Drawer> </Drawer>
{/if} {/if}
</div> </div>
@ -144,7 +149,8 @@
{#each tables as table} {#each tables as table}
<li <li
class:selected={value === table} class:selected={value === table}
on:click={() => handleSelected(table)}> on:click={() => handleSelected(table)}
>
{table.label} {table.label}
</li> </li>
{/each} {/each}
@ -157,7 +163,8 @@
{#each views as view} {#each views as view}
<li <li
class:selected={value === view} class:selected={value === view}
on:click={() => handleSelected(view)}> on:click={() => handleSelected(view)}
>
{view.label} {view.label}
</li> </li>
{/each} {/each}
@ -170,7 +177,8 @@
{#each links as link} {#each links as link}
<li <li
class:selected={value === link} class:selected={value === link}
on:click={() => handleSelected(link)}> on:click={() => handleSelected(link)}
>
{link.label} {link.label}
</li> </li>
{/each} {/each}
@ -183,7 +191,8 @@
{#each queries as query} {#each queries as query}
<li <li
class:selected={value === query} class:selected={value === query}
on:click={() => handleSelected(query)}> on:click={() => handleSelected(query)}
>
{query.label} {query.label}
</li> </li>
{/each} {/each}
@ -198,7 +207,8 @@
{#each otherSources as source} {#each otherSources as source}
<li <li
class:selected={value === source} class:selected={value === source}
on:click={() => handleSelected(source)}> on:click={() => handleSelected(source)}
>
{source.label} {source.label}
</li> </li>
{/each} {/each}

View File

@ -1,7 +1,7 @@
<script> <script>
import { flip } from "svelte/animate" import { flip } from "svelte/animate"
import { dndzone } from "svelte-dnd-action" import { dndzone } from "svelte-dnd-action"
import { Icon, Button, Popover, Spacer } from "@budibase/bbui" import { Icon, Button, Popover, Layout, DrawerContent } from "@budibase/bbui"
import actionTypes from "./actions" import actionTypes from "./actions"
import { generate } from "shortid" import { generate } from "shortid"
@ -68,14 +68,13 @@
} }
</script> </script>
<div class="actions-container"> <DrawerContent>
<div class="actions-list"> <div class="actions-list" slot="sidebar">
<div> <Layout>
<div bind:this={addActionButton}> <div bind:this={addActionButton}>
<Button wide secondary on:click={addActionDropdown.show}> <Button wide secondary on:click={addActionDropdown.show}>
Add Action Add Action
</Button> </Button>
<Spacer small />
</div> </div>
<Popover <Popover
bind:this={addActionDropdown} bind:this={addActionDropdown}
@ -90,44 +89,44 @@
{/each} {/each}
</div> </div>
</Popover> </Popover>
</div>
{#if actions && actions.length > 0} {#if actions && actions.length > 0}
<div <div
class="action-dnd-container" class="action-dnd-container"
use:dndzone={{ use:dndzone={{
items: actions, items: actions,
flipDurationMs, flipDurationMs,
dropTargetStyle: { outline: "none" }, dropTargetStyle: { outline: "none" },
}} }}
on:consider={handleDndConsider} on:consider={handleDndConsider}
on:finalize={handleDndFinalize} on:finalize={handleDndFinalize}
> >
{#each actions as action, index (action.id)} {#each actions as action, index (action.id)}
<div
class="action-container"
animate:flip={{ duration: flipDurationMs }}
>
<div <div
class="action-header" class="action-container"
class:selected={action === selectedAction} animate:flip={{ duration: flipDurationMs }}
on:click={selectAction(action)}
> >
{index + 1}. <div
{action[EVENT_TYPE_KEY]} class="action-header"
class:selected={action === selectedAction}
on:click={selectAction(action)}
>
{index + 1}.
{action[EVENT_TYPE_KEY]}
</div>
<div
on:click={() => deleteAction(index)}
style="margin-left: auto;"
>
<Icon size="S" hoverable name="Close" />
</div>
</div> </div>
<div {/each}
on:click={() => deleteAction(index)} </div>
style="margin-left: auto;" {/if}
> </Layout>
<Icon size="S" hoverable name="Close" />
</div>
</div>
{/each}
</div>
{/if}
</div> </div>
<div class="action-config"> <Layout>
{#if selectedAction} {#if selectedAction}
<div class="selected-action-container"> <div class="selected-action-container">
<svelte:component <svelte:component
@ -136,15 +135,15 @@
/> />
</div> </div>
{/if} {/if}
</div> </Layout>
</div> </DrawerContent>
<style> <style>
.action-header { .action-header {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
margin-top: var(--spacing-m); margin-top: var(--spacing-s);
} }
.action-header { .action-header {
@ -160,11 +159,6 @@
color: var(--ink); color: var(--ink);
} }
.actions-list {
border-right: var(--border-light);
padding: var(--spacing-l);
}
.available-action { .available-action {
padding: var(--spacing-s); padding: var(--spacing-s);
font-size: var(--font-size-xs); font-size: var(--font-size-xs);
@ -175,16 +169,6 @@
background: var(--grey-2); background: var(--grey-2);
} }
.actions-container {
height: 40vh;
display: grid;
grid-template-columns: 260px 1fr;
grid-auto-flow: column;
min-height: 0;
padding-top: 0;
overflow-y: auto;
}
.action-container { .action-container {
border-bottom: 1px solid var(--grey-1); border-bottom: 1px solid var(--grey-1);
display: flex; display: flex;
@ -194,10 +178,6 @@
border-bottom: none; border-bottom: none;
} }
.selected-action-container {
padding: var(--spacing-l);
}
i:hover { i:hover {
color: var(--red); color: var(--red);
cursor: pointer; cursor: pointer;

View File

@ -1,5 +1,5 @@
<script> <script>
import { Select, Label, Spacer } from "@budibase/bbui" import { Select, Label, Layout } from "@budibase/bbui"
import { store, currentAsset } from "builderStore" import { store, currentAsset } from "builderStore"
import { datasources, integrations, queries } from "stores/backend" import { datasources, integrations, queries } from "stores/backend"
import { getBindableProperties } from "builderStore/dataBinding" import { getBindableProperties } from "builderStore/dataBinding"
@ -8,9 +8,9 @@
export let parameters export let parameters
$: query = $queries.list.find(q => q._id === parameters.queryId) $: query = $queries.list.find((q) => q._id === parameters.queryId)
$: datasource = $datasources.list.find( $: datasource = $datasources.list.find(
ds => ds._id === parameters.datasourceId (ds) => ds._id === parameters.datasourceId
) )
$: bindableProperties = getBindableProperties( $: bindableProperties = getBindableProperties(
$currentAsset, $currentAsset,
@ -18,40 +18,44 @@
) )
function fetchQueryDefinition(query) { function fetchQueryDefinition(query) {
const source = $datasources.list.find(ds => ds._id === query.datasourceId) const source = $datasources.list.find((ds) => ds._id === query.datasourceId)
.source .source
return $integrations[source].query[query.queryVerb] return $integrations[source].query[query.queryVerb]
} }
</script> </script>
<Label>Datasource</Label> <Layout noGap noPadding>
<Select <Label>Datasource</Label>
bind:value={parameters.datasourceId}
option={$datasources.list}
getOptionLabel={source => source.name}
getOptionValue={source => source._id} />
<Spacer medium />
{#if parameters.datasourceId}
<Label>Query</Label>
<Select <Select
bind:value={parameters.queryId} bind:value={parameters.datasourceId}
options={$queries.list.filter(query => query.datasourceId === datasource._id)} option={$datasources.list}
getOptionLabel={query => query.name} getOptionLabel={(source) => source.name}
getOptionValue={query => query._id} /> getOptionValue={(source) => source._id}
{/if} />
<Spacer medium /> {#if parameters.datasourceId}
<Label>Query</Label>
<Select
bind:value={parameters.queryId}
options={$queries.list.filter(
(query) => query.datasourceId === datasource._id
)}
getOptionLabel={(query) => query.name}
getOptionValue={(query) => query._id}
/>
{/if}
{#if query?.parameters?.length > 0} {#if query?.parameters?.length > 0}
<ParameterBuilder <ParameterBuilder
bind:customParams={parameters.queryParams} bind:customParams={parameters.queryParams}
parameters={query.parameters} parameters={query.parameters}
bindings={bindableProperties} /> bindings={bindableProperties}
<IntegrationQueryEditor />
height={200} <IntegrationQueryEditor
{query} height={200}
schema={fetchQueryDefinition(query)} {query}
editable={false} /> schema={fetchQueryDefinition(query)}
{/if} editable={false}
/>
{/if}
</Layout>

View File

@ -1,5 +1,5 @@
<script> <script>
import { Label, ActionButton, Button, Spacer, Select, Input } from "@budibase/bbui" import { Label, ActionButton, Button, Select, Input } from "@budibase/bbui"
import { store, currentAsset } from "builderStore" import { store, currentAsset } from "builderStore"
import { getBindableProperties } from "builderStore/dataBinding" import { getBindableProperties } from "builderStore/dataBinding"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
@ -20,11 +20,11 @@
) )
const addField = () => { const addField = () => {
fields = [...fields.filter(field => field[0]), ["", ""]] fields = [...fields.filter((field) => field[0]), ["", ""]]
} }
const removeField = name => { const removeField = (name) => {
fields = fields.filter(field => field[0] !== name) fields = fields.filter((field) => field[0] !== name)
} }
const updateFieldValue = (idx, value) => { const updateFieldValue = (idx, value) => {
@ -37,10 +37,10 @@
fields = fields fields = fields
} }
const onChange = fields => { const onChange = (fields) => {
const newParamFields = {} const newParamFields = {}
fields fields
.filter(field => field[0]) .filter((field) => field[0])
.forEach(([field, value]) => { .forEach(([field, value]) => {
newParamFields[field] = value newParamFields[field] = value
}) })
@ -54,32 +54,35 @@
{#if schemaFields} {#if schemaFields}
<Select <Select
value={field[0]} value={field[0]}
on:change={event => updateFieldName(idx, event.detail)} on:change={(event) => updateFieldName(idx, event.detail)}
options={schemaFields.map(field => field.name)} /> options={schemaFields.map((field) => field.name)}
/>
{:else} {:else}
<Input <Input
thin thin
secondary secondary
value={field[0]} value={field[0]}
on:change={event => updateFieldName(idx, event.detail)} /> on:change={(event) => updateFieldName(idx, event.detail)}
/>
{/if} {/if}
<Label small>{valueLabel}</Label> <Label small>{valueLabel}</Label>
<DrawerBindableInput <DrawerBindableInput
title={`Value for "${field[0]}"`} title={`Value for "${field[0]}"`}
value={field[1]} value={field[1]}
bindings={bindableProperties} bindings={bindableProperties}
on:change={event => updateFieldValue(idx, event.detail)} /> on:change={(event) => updateFieldValue(idx, event.detail)}
/>
<ActionButton <ActionButton
size="S" size="S"
quiet quiet
icon="Delete" icon="Delete"
on:click={() => removeField(field[0])} /> on:click={() => removeField(field[0])}
/>
{/each} {/each}
<div> <div>
<Spacer small />
<Button icon="AddCircle" size="S" cta on:click={addField}> <Button icon="AddCircle" size="S" cta on:click={addField}>
Add Add
{fieldLabel} {fieldLabel}
</Button> </Button>
</div> </div>
{/if} {/if}

View File

@ -1,5 +1,5 @@
<script> <script>
import { Button, Drawer, Spacer, Body } from "@budibase/bbui" import { Button, Drawer, Body, DrawerContent, Layout } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { notifications } from "@budibase/bbui" import { notifications } from "@budibase/bbui"
import { import {
@ -18,7 +18,7 @@
$: schemaFields = getSchemaFields(componentInstance) $: schemaFields = getSchemaFields(componentInstance)
const getSchemaFields = component => { const getSchemaFields = (component) => {
const datasource = getDatasourceForProvider($currentAsset, component) const datasource = getDatasourceForProvider($currentAsset, component)
const { schema } = getSchemaForDatasource(datasource) const { schema } = getSchemaForDatasource(datasource)
return Object.values(schema || {}) return Object.values(schema || {})
@ -30,42 +30,37 @@
drawer.hide() drawer.hide()
} }
const onFieldsChanged = event => { const onFieldsChanged = (event) => {
tempValue = event.detail tempValue = event.detail
} }
</script> </script>
<Button secondary wide on:click={drawer.show}>Define Filters</Button> <Button secondary wide on:click={drawer.show}>Define Filters</Button>
<Drawer bind:this={drawer} title='Filtering'> <Drawer bind:this={drawer} title="Filtering">
<Button cta slot="buttons" on:click={saveFilter}>Save</Button> <Button cta slot="buttons" on:click={saveFilter}>Save</Button>
<div class="root" slot="body"> <DrawerContent slot="body">
<Body s> <Layout>
{#if !Object.keys(tempValue || {}).length} <Body s>
Add your first filter column. {#if !Object.keys(tempValue || {}).length}
{:else} Add your first filter column.
Results are filtered to only those which match all of the following {:else}
constaints. Results are filtered to only those which match all of the following
{/if} constaints.
</Body> {/if}
<Spacer medium /> </Body>
<div class="fields"> <div class="fields">
<SaveFields <SaveFields
parameterFields={value} parameterFields={value}
{schemaFields} {schemaFields}
valueLabel="Equals" valueLabel="Equals"
on:change={onFieldsChanged} /> on:change={onFieldsChanged}
</div> />
</div> </div>
</Layout>
</DrawerContent>
</Drawer> </Drawer>
<style> <style>
.root {
padding: var(--spacing-l);
min-height: calc(40vh - 2 * var(--spacing-l));
max-width: 800px;
margin: 0 auto;
}
.fields { .fields {
display: grid; display: grid;
column-gap: var(--spacing-l); column-gap: var(--spacing-l);

View File

@ -33,7 +33,7 @@
{/each} {/each}
</div> </div>
{#if !readOnly} {#if !readOnly}
<Button secondary thin outline on:click={addEntry}>Add</Button> <div><Button secondary thin outline on:click={addEntry}>Add</Button></div>
{/if} {/if}
<style> <style>

View File

@ -1,6 +1,6 @@
<script> <script>
import CodeMirror from "./codemirror" import CodeMirror from "./codemirror"
import { Label, Spacer } from "@budibase/bbui" import { Label } from "@budibase/bbui"
import { onMount, createEventDispatcher } from "svelte" import { onMount, createEventDispatcher } from "svelte"
import { themeStore } from "builderStore" import { themeStore } from "builderStore"
@ -134,7 +134,7 @@
editor = CodeMirror.fromTextArea(refs.editor, opts) editor = CodeMirror.fromTextArea(refs.editor, opts)
editor.on("change", instance => { editor.on("change", (instance) => {
if (!updating_externally) { if (!updating_externally) {
const value = instance.getValue() const value = instance.getValue()
dispatch("change", { value }) dispatch("change", { value })
@ -160,13 +160,12 @@
} }
function sleep(ms) { function sleep(ms) {
return new Promise(fulfil => setTimeout(fulfil, ms)) return new Promise((fulfil) => setTimeout(fulfil, ms))
} }
</script> </script>
{#if label} {#if label}
<Label small>{label}</Label> <Label small>{label}</Label>
<Spacer medium />
{/if} {/if}
<div style={`--code-mirror-height: ${editorHeight}px`}> <div style={`--code-mirror-height: ${editorHeight}px`}>
<textarea tabindex="0" bind:this={refs.editor} readonly {value} /> <textarea tabindex="0" bind:this={refs.editor} readonly {value} />
@ -177,6 +176,10 @@
visibility: hidden; visibility: hidden;
} }
div {
margin-top: var(--spacing-s);
}
div :global(.CodeMirror) { div :global(.CodeMirror) {
height: var(--code-mirror-height) !important; height: var(--code-mirror-height) !important;
border-radius: var(--border-radius-s); border-radius: var(--border-radius-s);

View File

@ -1,5 +1,5 @@
<script> <script>
import { Label, Spacer, Input } from "@budibase/bbui" import { Label, Layout, Input } from "@budibase/bbui"
import Editor from "./QueryEditor.svelte" import Editor from "./QueryEditor.svelte"
import KeyValueBuilder from "./KeyValueBuilder.svelte" import KeyValueBuilder from "./KeyValueBuilder.svelte"
@ -15,22 +15,22 @@
</script> </script>
<form on:submit|preventDefault> <form on:submit|preventDefault>
<div class="field"> <Layout noPadding gap="S">
{#each schemaKeys as field} {#each schemaKeys as field}
{#if schema.fields[field]?.type === 'object'} {#if schema.fields[field]?.type === "object"}
<div> <div>
<Label small>{field}</Label> <Label small>{field}</Label>
<Spacer small />
<KeyValueBuilder readOnly={!editable} bind:object={fields[field]} /> <KeyValueBuilder readOnly={!editable} bind:object={fields[field]} />
</div> </div>
{:else if schema.fields[field]?.type === 'json'} {:else if schema.fields[field]?.type === "json"}
<div> <div>
<Label extraSmall grey>{field}</Label> <Label extraSmall grey>{field}</Label>
<Editor <Editor
mode="json" mode="json"
on:change={({ detail }) => (fields[field] = detail.value)} on:change={({ detail }) => (fields[field] = detail.value)}
readOnly={!editable} readOnly={!editable}
value={fields[field]} /> value={fields[field]}
/>
</div> </div>
{:else} {:else}
<div class="horizontal"> <div class="horizontal">
@ -41,11 +41,12 @@
disabled={!editable} disabled={!editable}
type={schema.fields[field]?.type} type={schema.fields[field]?.type}
required={schema.fields[field]?.required} required={schema.fields[field]?.required}
bind:value={fields[field]} /> bind:value={fields[field]}
/>
</div> </div>
{/if} {/if}
{/each} {/each}
</div> </Layout>
</form> </form>
{#if schema.customisable} {#if schema.customisable}
<Editor <Editor
@ -53,7 +54,8 @@
mode="json" mode="json"
on:change={updateCustomFields} on:change={updateCustomFields}
readOnly={!editable} readOnly={!editable}
value={fields.customData} /> value={fields.customData}
/>
{/if} {/if}
<style> <style>

View File

@ -1,5 +1,5 @@
<script> <script>
import { Icon, Body, Button, Input, Heading, Spacer } from "@budibase/bbui" import { Icon, Body, Button, Input, Heading, Layout } from "@budibase/bbui"
import { import {
readableToRuntimeBinding, readableToRuntimeBinding,
runtimeToReadableBinding, runtimeToReadableBinding,
@ -29,7 +29,7 @@
} }
</script> </script>
<section> <Layout paddingX="none" gap="S">
<div class="controls"> <div class="controls">
<Heading s>Parameters</Heading> <Heading s>Parameters</Heading>
{#if !bindable} {#if !bindable}
@ -45,7 +45,6 @@
values left blank. values left blank.
{/if} {/if}
</Body> </Body>
<Spacer large />
<div class="parameters" class:bindable> <div class="parameters" class:bindable>
{#each parameters as parameter, idx} {#each parameters as parameter, idx}
<Input <Input
@ -81,7 +80,7 @@
{/if} {/if}
{/each} {/each}
</div> </div>
</section> </Layout>
<style> <style>
.parameters.bindable { .parameters.bindable {

View File

@ -4,12 +4,12 @@
Icon, Icon,
Select, Select,
Button, Button,
ButtonGroup,
Body, Body,
Label, Label,
Layout, Layout,
Input, Input,
Heading, Heading,
Spacer,
Tabs, Tabs,
Tab, Tab,
} from "@budibase/bbui" } from "@budibase/bbui"
@ -149,29 +149,26 @@
</div> </div>
<div class="viewer-controls"> <div class="viewer-controls">
<Heading s>Results</Heading> <Heading s>Results</Heading>
<div class="button-container"> <ButtonGroup>
<Button <Button
secondary cta
thin
disabled={data.length === 0 || !query.name} disabled={data.length === 0 || !query.name}
on:click={saveQuery} on:click={saveQuery}
> >
Save Query Save Query
</Button> </Button>
<Spacer medium /> <Button secondary on:click={previewQuery}>Run Query</Button>
<Button thin secondary on:click={previewQuery}>Run Query</Button> </ButtonGroup>
</div>
</div> </div>
<Body s> <Body s>
Below, you can preview the results from your query and change the Below, you can preview the results from your query and change the schema.
schema. </Body>
</Body> <section class="viewer">
<section class="viewer"> {#if data}
{#if data} <Tabs selected="JSON">
<Tabs selected="JSON"> <Tab title="JSON">
<Tab title="JSON"> <pre
<pre class="preview">
class="preview">
<!-- prettier-ignore --> <!-- prettier-ignore -->
{#if !data[0]} {#if !data[0]}
Please run your query to fetch some data. Please run your query to fetch some data.
@ -179,25 +176,27 @@
{JSON.stringify(data[0], undefined, 2)} {JSON.stringify(data[0], undefined, 2)}
{/if} {/if}
</pre> </pre>
</Tab> </Tab>
<Tab title="Schema"> <Tab title="Schema">
<Layout gap="S">
{#each fields as field, idx} {#each fields as field, idx}
<Spacer small />
<div class="field"> <div class="field">
<Input placeholder="Field Name" bind:value={field.name} /> <Input placeholder="Field Name" bind:value={field.name} />
<Select bind:value={field.type} options={typeOptions} /> <Select bind:value={field.type} options={typeOptions} />
<Icon name="bleClose" on:click={() => deleteField(idx)} /> <Icon name="bleClose" on:click={() => deleteField(idx)} />
</div> </div>
{/each} {/each}
<Spacer extraLarge /> <div>
<Button thin secondary on:click={newField}>Add Field</Button> <Button secondary on:click={newField}>Add Field</Button>
</Tab> </div>
<Tab title="Preview"> </Layout>
<ExternalDataSourceTable {query} {data} /> </Tab>
</Tab> <Tab title="Preview">
</Tabs> <ExternalDataSourceTable {query} {data} />
{/if} </Tab>
</section> </Tabs>
{/if}
</section>
{/if} {/if}
</Layout> </Layout>

View File

@ -1,6 +1,6 @@
<script> <script>
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { ActionButton, Heading, Spacer, Icon } from "@budibase/bbui" import { ActionButton, Heading } from "@budibase/bbui"
import { notifications } from "@budibase/bbui" import { notifications } from "@budibase/bbui"
import Spinner from "components/common/Spinner.svelte" import Spinner from "components/common/Spinner.svelte"
import download from "downloadjs" import download from "downloadjs"
@ -27,7 +27,6 @@
<div class="apps-card"> <div class="apps-card">
<Heading s>{name}</Heading> <Heading s>{name}</Heading>
<Spacer medium />
<div class="card-footer" data-cy={`app-${name}`}> <div class="card-footer" data-cy={`app-${name}`}>
<ActionButton on:click={() => $goto(`/builder/${_id}`)}> <ActionButton on:click={() => $goto(`/builder/${_id}`)}>
Open Open
@ -58,6 +57,7 @@
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-top: var(--spacing-m);
} }
i { i {

View File

@ -1,5 +1,5 @@
<script> <script>
import { Button, Heading, Body, Spacer } from "@budibase/bbui" import { Button, Heading, Body } from "@budibase/bbui"
import AppCard from "./AppCard.svelte" import AppCard from "./AppCard.svelte"
import Spinner from "components/common/Spinner.svelte" import Spinner from "components/common/Spinner.svelte"
import api from "builderStore/api" import api from "builderStore/api"
@ -25,7 +25,6 @@
{#each templates as template} {#each templates as template}
<div class="templates-card"> <div class="templates-card">
<Heading black small>{template.name}</Heading> <Heading black small>{template.name}</Heading>
<Spacer small />
<Body medium grey>{template.category}</Body> <Body medium grey>{template.category}</Body>
<Body lh small black>{template.description}</Body> <Body lh small black>{template.description}</Body>
<div><img src={template.image} width="100%" /></div> <div><img src={template.image} width="100%" /></div>

View File

@ -1,6 +1,6 @@
<script> <script>
import { goto, beforeUrlChange } from "@roxi/routify" import { goto, beforeUrlChange } from "@roxi/routify"
import { Button, Heading, Body, Spacer, Divider } from "@budibase/bbui" import { Button, Heading, Body, Divider, Layout } from "@budibase/bbui"
import { datasources, integrations, queries } from "stores/backend" import { datasources, integrations, queries } from "stores/backend"
import { notifications } from "@budibase/bbui" import { notifications } from "@budibase/bbui"
import IntegrationConfigForm from "components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte" import IntegrationConfigForm from "components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte"
@ -43,39 +43,36 @@
{#if datasource} {#if datasource}
<section> <section>
<Spacer extraLarge /> <Layout>
<header> <header>
<svelte:component <svelte:component
this={ICONS[datasource.source]} this={ICONS[datasource.source]}
height="26" height="26"
width="26" width="26"
/> />
<Heading m>{datasource.name}</Heading> <Heading m>{datasource.name}</Heading>
</header> </header>
<Body small grey lh>{integration.description}</Body> <Body small grey lh>{integration.description}</Body>
<Spacer extraLarge /> <Divider />
<Divider /> <div class="container">
<Spacer extraLarge /> <div class="config-header">
<div class="container"> <Heading s>Configuration</Heading>
<div class="config-header"> <Button secondary on:click={saveDatasource}>Save</Button>
<Heading s>Configuration</Heading> </div>
<Button secondary on:click={saveDatasource}>Save</Button> <Body size="S"
</div> >Connect your database to Budibase using the config below.</Body
<Body s>Connect your database to Budibase using the config below.</Body> >
<Spacer extraLarge /> <IntegrationConfigForm
<IntegrationConfigForm schema={integration.datasource}
schema={integration.datasource} integration={datasource.config}
integration={datasource.config} on:change={setUnsaved}
on:change={setUnsaved} />
/> </div>
<Spacer extraLarge />
<Divider /> <Divider />
<Spacer extraLarge />
<div class="query-header"> <div class="query-header">
<Heading s>Queries</Heading> <Heading s>Queries</Heading>
<Button secondary on:click={() => $goto("./new")}>Add Query</Button> <Button secondary on:click={() => $goto("./new")}>Add Query</Button>
</div> </div>
<Spacer extraLarge />
<div class="query-list"> <div class="query-list">
{#each $queries.list.filter((query) => query.datasourceId === datasource._id) as query} {#each $queries.list.filter((query) => query.datasourceId === datasource._id) as query}
<div class="query-list-item" on:click={() => onClickQuery(query)}> <div class="query-list-item" on:click={() => onClickQuery(query)}>
@ -85,7 +82,7 @@
</div> </div>
{/each} {/each}
</div> </div>
</div> </Layout>
</section> </section>
{/if} {/if}
@ -109,6 +106,7 @@
} }
.container { .container {
width: 100%;
border-radius: var(--border-radius-m); border-radius: var(--border-radius-m);
margin: 0 auto; margin: 0 auto;
} }

View File

@ -3,7 +3,7 @@
import AppList from "components/start/AppList.svelte" import AppList from "components/start/AppList.svelte"
import { get } from "builderStore/api" import { get } from "builderStore/api"
import CreateAppModal from "components/start/CreateAppModal.svelte" import CreateAppModal from "components/start/CreateAppModal.svelte"
import { Button, Heading, Modal, Spacer, ButtonGroup } from "@budibase/bbui" import { Button, Heading, Modal, ButtonGroup } from "@budibase/bbui"
import TemplateList from "components/start/TemplateList.svelte" import TemplateList from "components/start/TemplateList.svelte"
import analytics from "analytics" import analytics from "analytics"
import Banner from "/assets/orange-landscape.png" import Banner from "/assets/orange-landscape.png"
@ -58,11 +58,10 @@
<div class="container"> <div class="container">
<div class="header"> <div class="header">
<Heading m h1>Welcome to the Budibase Beta</Heading> <Heading m h1>Welcome to the Budibase Beta</Heading>
<div class="button-group"> <ButtonGroup>
<Button secondary on:click={initiateAppImport}>Import Web App</Button> <Button secondary on:click={initiateAppImport}>Import Web App</Button>
<Spacer medium />
<Button cta on:click={modal.show}>Create New Web App</Button> <Button cta on:click={modal.show}>Create New Web App</Button>
</div> </ButtonGroup>
</div> </div>
<div class="banner"> <div class="banner">