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

This commit is contained in:
Andrew Kingston 2021-04-28 15:08:54 +01:00
commit 85466fb7da
24 changed files with 317 additions and 413 deletions

View File

@ -1,10 +1,16 @@
<div class="drawer-contents">
<div class="container" data-cy="binding-dropdown-modal">
<div class="sidebar">
<slot name="sidebar" />
</div>
<div
class:no-sidebar={!$$slots.sidebar}
class="container"
data-cy="binding-dropdown-modal"
>
{#if $$slots.sidebar}
<div class="sidebar">
<slot name="sidebar" />
</div>
{/if}
<div class="main">
<slot name="main" />
<slot />
</div>
</div>
</div>
@ -19,6 +25,9 @@
display: grid;
grid-template-columns: 290px 1fr;
}
.no-sidebar {
grid-template-columns: 1fr;
}
.sidebar {
border-right: var(--border-light);
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 Dropzone } from "./Form/Dropzone.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 ActionButton } from "./ActionButton/ActionButton.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 ModalContent } from "./Modal/ModalContent.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 SideNavigationItem } from "./SideNavigation/Item.svelte"
export { default as DatePicker } from "./Form/DatePicker.svelte"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -62,8 +62,11 @@ const SCHEMA_MAP = {
function parseFilterExpression(filters) {
const expression = []
let first = true
for (let filter of filters) {
if (filter.conjunction) expression.push(TOKEN_MAP[filter.conjunction])
if (!first && filter.conjunction) {
expression.push(TOKEN_MAP[filter.conjunction])
}
if (filter.condition === "CONTAINS") {
expression.push(
@ -77,6 +80,7 @@ function parseFilterExpression(filters) {
`doc["${filter.key}"] ${TOKEN_MAP[filter.condition]} ${value}`
)
}
first = false
}
return expression.join(" ")
@ -104,6 +108,10 @@ function parseEmitExpression(field, groupBy) {
* calculation: an optional calculation to be performed over the view data.
*/
function viewTemplate({ field, tableId, groupBy, filters = [], calculation }) {
// first filter can't have a conjuction
if (filters && filters.length > 0 && filters[0].conjunction) {
delete filters[0].conjunction
}
const parsedFilters = parseFilterExpression(filters)
const filterExpression = parsedFilters ? `&& ${parsedFilters}` : ""