Update entire builder backend UI to work with new spectrum components and fix multiple issues

This commit is contained in:
Andrew Kingston 2021-04-20 11:53:19 +01:00
parent 25a90faf52
commit 17d031eeed
13 changed files with 105 additions and 195 deletions

View File

@ -1,14 +1,16 @@
<script> <script>
import "@spectrum-css/divider/dist/index-vars.css" import "@spectrum-css/divider/dist/index-vars.css"
export let l = false export let l = false
export let m = false export let m = false
export let s = false export let s = false
export let vertical = false export let vertical = false
$: useDefault = ![l, m, s].includes(true)
</script> </script>
<hr <hr
class:spectrum-Divider--sizeL={l} class:spectrum-Divider--sizeL={l}
class:spectrum-Divider--sizeM={m} class:spectrum-Divider--sizeM={m || useDefault}
class:spectrum-Divider--sizeS={s} class:spectrum-Divider--sizeS={s}
class="spectrum-Divider spectrum-Divider--{vertical ? 'vertical' : 'horizontal'} spectrum-Dialog-divider"> class="spectrum-Divider spectrum-Divider--{vertical ? 'vertical' : 'horizontal'} spectrum-Dialog-divider" />

View File

@ -72,6 +72,7 @@
placeholder={placeholder || ''} placeholder={placeholder || ''}
on:blur={onBlur} on:blur={onBlur}
on:focus={onFocus} on:focus={onFocus}
on:input
{type} {type}
class="spectrum-Textfield-input" /> class="spectrum-Textfield-input" />
</div> </div>

View File

@ -28,5 +28,6 @@
{placeholder} {placeholder}
{type} {type}
on:change={onChange} on:change={onChange}
on:click /> on:click
on:input />
</Field> </Field>

View File

@ -1,78 +1,28 @@
<script> <script>
import "@spectrum-css/typography/dist/index-vars.css" import "@spectrum-css/typography/dist/index-vars.css"
// Level // Sizes
export let h1 = false; export let xxxl = false
export let h2 = false; export let xxl = false
export let h3 = false; export let xl = false
export let h4 = false; export let l = false
export let m = false
// Sizes export let s = false
export let xxxl = false; export let xs = false
export let xxl = false; export let xxs = false
export let xl = false;
export let l = false;
export let m = false;
export let s = false;
export let xs = false;
export let xxs = false;
export let serif = false;
$: useDefault = ![xxxl, xxl, xl, l, m, s, xs, xxs].includes(true)
</script> </script>
{#if h1} <h1
<h1 class="spectrum-Heading" class="spectrum-Heading"
class:spectrum-Heading--serif={serif} class:spectrum-Heading--sizeXXXL={xxxl}
class:spectrum-Heading--sizeXXXL={xxxl} class:spectrum-Heading--sizeXXL={xxl}
class:spectrum-Heading--sizeXXL={xxl} class:spectrum-Heading--sizeXL={xl}
class:spectrum-Heading--sizeXL={xl} class:spectrum-Heading--sizeL={l}
class:spectrum-Heading--sizeL={l} class:spectrum-Heading--sizeM={m || useDefault}
class:spectrum-Heading--sizeM={m} class:spectrum-Heading--sizeS={s}
class:spectrum-Heading--sizeS={s} class:spectrum-Heading--sizeXS={xs}
class:spectrum-Heading--sizeXS={xs} class:spectrum-Heading--sizeXXS={xxs}>
class:spectrum-Heading--sizeXXS={xxs}> <slot />
<slot /> </h1>
</h1>
{:else if h2}
<h2 class="spectrum-Heading"
class:spectrum-Heading--serif={serif}
class:spectrum-Heading--sizeXXXL={xxxl}
class:spectrum-Heading--sizeXXL={xxl}
class:spectrum-Heading--sizeXL={xl}
class:spectrum-Heading--sizeL={l}
class:spectrum-Heading--sizeM={m}
class:spectrum-Heading--sizeS={s}
class:spectrum-Heading--sizeXS={xs}
class:spectrum-Heading--sizeXXS={xxs}>
<slot />
</h2>
{:else if h3}
<h3 class="spectrum-Heading"
class:spectrum-Heading--serif={serif}
class:spectrum-Heading--sizeXXXL={xxxl}
class:spectrum-Heading--sizeXXL={xxl}
class:spectrum-Heading--sizeXL={xl}
class:spectrum-Heading--sizeL={l}
class:spectrum-Heading--sizeM={m}
class:spectrum-Heading--sizeS={s}
class:spectrum-Heading--sizeXS={xs}
class:spectrum-Heading--sizeXXS={xxs}>
<slot />
</h3>
{:else if h4}
<h4 class="spectrum-Heading"
class:spectrum-Heading--serif={serif}
class:spectrum-Heading--sizeXXXL={xxxl}
class:spectrum-Heading--sizeXXL={xxl}
class:spectrum-Heading--sizeXL={xl}
class:spectrum-Heading--sizeL={l}
class:spectrum-Heading--sizeM={m}
class:spectrum-Heading--sizeS={s}
class:spectrum-Heading--sizeXS={xs}
class:spectrum-Heading--sizeXXS={xxs}>
<slot />
</h4>
{:else}
SPECIFY HEADING SIZE!
{/if}

View File

@ -11,7 +11,7 @@
{#if error} {#if error}
<div class="errors">{error}</div> <div class="errors">{error}</div>
{/if} {/if}
<Table title={''} schema={query.schema} {data} {loading} /> <Table schema={query.schema} {data} {loading} rowCount={5} />
<style> <style>
.errors { .errors {

View File

@ -22,6 +22,7 @@
export let loading = false export let loading = false
export let theme = "alpine" export let theme = "alpine"
export let hideAutocolumns export let hideAutocolumns
export let rowCount
let selectedRows = [] let selectedRows = []
let editableColumn let editableColumn
@ -91,7 +92,9 @@
<div> <div>
<div class="table-title"> <div class="table-title">
<h1>{title}</h1> {#if title}
<h1>{title}</h1>
{/if}
{#if loading} {#if loading}
<div transition:fade> <div transition:fade>
<Spinner size="10" /> <Spinner size="10" />
@ -111,6 +114,7 @@
{schema} {schema}
{loading} {loading}
{customRenderers} {customRenderers}
{rowCount}
bind:selectedRows bind:selectedRows
allowSelectRows={allowEditing} allowSelectRows={allowEditing}
allowEditRows={allowEditing} allowEditRows={allowEditing}

View File

@ -1,6 +1,7 @@
<script> <script>
import { Label, Input, TextArea, Spacer } from "@budibase/bbui" import { Label, Input, Spacer } from "@budibase/bbui"
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte" import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
import { capitalise } from "../../../../helpers"
export let integration export let integration
export let schema export let schema
@ -11,16 +12,15 @@
<form> <form>
{#each Object.keys(schema) as configKey} {#each Object.keys(schema) as configKey}
{#if schema[configKey].type === 'object'} {#if schema[configKey].type === 'object'}
<Label small>{configKey}</Label> <Label>{capitalise(configKey)}</Label>
<Spacer small /> <Spacer small />
<KeyValueBuilder <KeyValueBuilder
defaults={schema[configKey].default} defaults={schema[configKey].default}
bind:object={integration[configKey]} /> bind:object={integration[configKey]} />
{:else} {:else}
<div class="form-row"> <div class="form-row">
<Label small>{configKey}</Label> <Label>{capitalise(configKey)}</Label>
<Input <Input
outline
type={schema[configKey].type} type={schema[configKey].type}
on:change on:change
bind:value={integration[configKey]} /> bind:value={integration[configKey]} />

View File

@ -47,11 +47,10 @@
disabled={error || !name}> disabled={error || !name}>
<Input <Input
data-cy="datasource-name-input" data-cy="datasource-name-input"
thin
label="Datasource Name" label="Datasource Name"
on:input={checkValid} on:input={checkValid}
bind:value={name} bind:value={name}
{error} /> {error} />
<Label grey extraSmall>Source</Label> <Label>Source</Label>
<TableIntegrationMenu bind:integration /> <TableIntegrationMenu bind:integration />
</ModalContent> </ModalContent>

View File

@ -25,8 +25,8 @@
<!-- Builds Objects with Key Value Pairs. Useful for building things like Request Headers. --> <!-- Builds Objects with Key Value Pairs. Useful for building things like Request Headers. -->
<div class="container" class:readOnly> <div class="container" class:readOnly>
{#each fields as field, idx} {#each fields as field, idx}
<Input placeholder="Key" thin outline bind:value={field.name} /> <Input placeholder="Key" bind:value={field.name} />
<Input placeholder="Value" thin outline bind:value={field.value} /> <Input placeholder="Value" bind:value={field.value} />
{#if !readOnly} {#if !readOnly}
<i class="ri-close-circle-fill" on:click={() => deleteEntry(idx)} /> <i class="ri-close-circle-fill" on:click={() => deleteEntry(idx)} />
{/if} {/if}

View File

@ -31,9 +31,9 @@
<section> <section>
<div class="controls"> <div class="controls">
<Heading small lh>Parameters</Heading> <Heading>Parameters</Heading>
{#if !bindable} {#if !bindable}
<Button on:click={newQueryParameter}>Add Param</Button> <Button secondary on:click={newQueryParameter}>Add Param</Button>
{/if} {/if}
</div> </div>
<Body small grey> <Body small grey>

View File

@ -10,12 +10,13 @@
Spacer, Spacer,
Switcher, Switcher,
} from "@budibase/bbui" } from "@budibase/bbui"
import { notifications } from "@budibase/bbui" import { notifications, Divider } from "@budibase/bbui"
import api from "builderStore/api" import api from "builderStore/api"
import IntegrationQueryEditor from "components/integration/index.svelte" import IntegrationQueryEditor from "components/integration/index.svelte"
import ExternalDataSourceTable from "components/backend/DataTable/ExternalDataSourceTable.svelte" import ExternalDataSourceTable from "components/backend/DataTable/ExternalDataSourceTable.svelte"
import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte" import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte"
import { datasources, integrations, queries } from "stores/backend" import { datasources, integrations, queries } from "stores/backend"
import { capitalise } from "../../helpers"
const PREVIEW_HEADINGS = [ const PREVIEW_HEADINGS = [
{ {
@ -38,9 +39,14 @@
let tab = "JSON" let tab = "JSON"
let parameters let parameters
let data = [] let data = []
const typeOptions = [
{ label: "Text", value: "STRING" },
{ label: "Number", value: "NUMBER" },
{ label: "Boolean", value: "BOOLEAN" },
{ label: "Datetime", value: "DATETIME" },
]
$: datasource = $datasources.list.find(ds => ds._id === query.datasourceId) $: datasource = $datasources.list.find(ds => ds._id === query.datasourceId)
$: query.schema = fields.reduce( $: query.schema = fields.reduce(
(acc, next) => ({ (acc, next) => ({
...acc, ...acc,
@ -51,12 +57,9 @@
}), }),
{} {}
) )
$: datasourceType = datasource?.source $: datasourceType = datasource?.source
$: integrationInfo = $integrations[datasourceType] $: integrationInfo = $integrations[datasourceType]
$: queryConfig = integrationInfo?.query $: queryConfig = integrationInfo?.query
$: shouldShowQueryConfig = queryConfig && query.queryVerb $: shouldShowQueryConfig = queryConfig && query.queryVerb
function newField() { function newField() {
@ -113,7 +116,7 @@
try { try {
const { _id } = await queries.save(query.datasourceId, query) const { _id } = await queries.save(query.datasourceId, query)
notifications.success(`Query saved successfully.`) notifications.success(`Query saved successfully.`)
$goto(`../../${_id}`) $goto(`../${_id}`)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
notifications.error(`Error creating query. ${err.message}`) notifications.error(`Error creating query. ${err.message}`)
@ -122,57 +125,53 @@
</script> </script>
<section class="config"> <section class="config">
<Heading medium lh>Query {integrationInfo?.friendlyName}</Heading>
<hr />
<Spacer extraLarge /> <Spacer extraLarge />
<Heading small lh>Config</Heading> <Heading>Query {integrationInfo?.friendlyName}</Heading>
<Spacer extraLarge />
<Divider />
<Spacer extraLarge />
<Heading>Config</Heading>
<Body small grey>Provide a name for your query and select its function.</Body> <Body small grey>Provide a name for your query and select its function.</Body>
<Spacer large /> <Spacer medium />
<div class="config-field"> <div class="config-field">
<Label small>Query Name</Label> <Label>Query Name</Label>
<Input thin outline bind:value={query.name} /> <Input bind:value={query.name} />
</div> </div>
<Spacer extraLarge /> <Spacer medium />
{#if queryConfig} {#if queryConfig}
<div class="config-field"> <div class="config-field">
<Label small>Function</Label> <Label>Function</Label>
<Select primary outline thin bind:value={query.queryVerb}> <Select
{#each Object.keys(queryConfig) as queryVerb} bind:value={query.queryVerb}
<option value={queryVerb}> options={Object.keys(queryConfig)}
{queryConfig[queryVerb]?.displayName || queryVerb} getOptionLabel={verb => queryConfig[verb]?.displayName || capitalise(verb)} />
</option>
{/each}
</Select>
</div> </div>
<Spacer extraLarge /> <Spacer extraLarge />
<hr /> <Divider />
<Spacer extraLarge /> <Spacer extraLarge />
<Spacer small />
<ParameterBuilder bind:parameters={query.parameters} bindable={false} /> <ParameterBuilder bind:parameters={query.parameters} bindable={false} />
<hr /> <Divider />
{/if} {/if}
</section> </section>
{#if shouldShowQueryConfig} {#if shouldShowQueryConfig}
<section> <section>
<Spacer extraLarge /> <Spacer extraLarge />
<Spacer small />
<div class="config"> <div class="config">
<Heading small lh>Fields</Heading> <Heading>Fields</Heading>
<Body small grey>Fill in the fields specific to this query.</Body> <Body small grey>Fill in the fields specific to this query.</Body>
<Spacer medium /> <Spacer medium />
<Spacer extraLarge />
<IntegrationQueryEditor <IntegrationQueryEditor
{datasource} {datasource}
{query} {query}
height={300}
schema={queryConfig[query.queryVerb]} schema={queryConfig[query.queryVerb]}
bind:parameters /> bind:parameters />
<Spacer extraLarge /> <Spacer extraLarge />
<hr /> <Divider />
<Spacer extraLarge /> <Spacer extraLarge />
<Spacer medium />
<div class="viewer-controls"> <div class="viewer-controls">
<Heading small lh>Results</Heading> <Heading>Results</Heading>
<div class="button-container"> <div class="button-container">
<Button <Button
secondary secondary
@ -182,17 +181,14 @@
Save Query Save Query
</Button> </Button>
<Spacer medium /> <Spacer medium />
<Button thin primary on:click={previewQuery}>Run Query</Button> <Button thin secondary on:click={previewQuery}>Run Query</Button>
</div> </div>
</div> </div>
<Body small grey> <Body small grey>
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>
<Spacer extraLarge />
<Spacer medium /> <Spacer medium />
<section class="viewer"> <section class="viewer">
{#if data} {#if data}
<Switcher headings={PREVIEW_HEADINGS} bind:value={tab}> <Switcher headings={PREVIEW_HEADINGS} bind:value={tab}>
@ -201,9 +197,7 @@
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.
{:else} {:else}
{JSON.stringify(data[0], undefined, 2)} {JSON.stringify(data[0], undefined, 2)}
{/if} {/if}
@ -214,24 +208,14 @@
{#each fields as field, idx} {#each fields as field, idx}
<Spacer small /> <Spacer small />
<div class="field"> <div class="field">
<Input <Input placeholder="Field Name" bind:value={field.name} />
outline <Select bind:value={field.type} options={typeOptions} />
placeholder="Field Name"
type={'text'}
bind:value={field.name} />
<Select thin border bind:value={field.type}>
<option value={''}>Select a field type</option>
<option value={'STRING'}>Text</option>
<option value={'NUMBER'}>Number</option>
<option value={'BOOLEAN'}>Boolean</option>
<option value={'DATETIME'}>Datetime</option>
</Select>
<i <i
class="ri-close-circle-line delete" class="ri-close-circle-line delete"
on:click={() => deleteField(idx)} /> on:click={() => deleteField(idx)} />
</div> </div>
{/each} {/each}
<Spacer small /> <Spacer extraLarge />
<Button thin secondary on:click={newField}>Add Field</Button> <Button thin secondary on:click={newField}>Add Field</Button>
{/if} {/if}
</Switcher> </Switcher>
@ -241,7 +225,6 @@
</section> </section>
{/if} {/if}
<Spacer extraLarge /> <Spacer extraLarge />
<Spacer extraLarge />
<style> <style>
.config-field { .config-field {
@ -261,11 +244,6 @@
display: flex; display: flex;
} }
hr {
margin-top: var(--layout-m);
border: 1px solid var(--grey-2);
}
.config { .config {
margin-bottom: var(--spacing-s); margin-bottom: var(--spacing-s);
} }
@ -285,10 +263,10 @@
overflow-y: auto; overflow-y: auto;
overflow-wrap: break-word; overflow-wrap: break-word;
white-space: pre-wrap; white-space: pre-wrap;
background-color: var(--grey-1); background-color: var(--grey-2);
padding: var(--spacing-m); padding: var(--spacing-m);
border-radius: 8px; border-radius: 8px;
color: var(--grey-6); color: var(--ink);
} }
.viewer-controls { .viewer-controls {

View File

@ -33,14 +33,6 @@
</section> </section>
<style> <style>
section {
overflow: scroll;
}
::-webkit-scrollbar {
width: 0px;
background: transparent; /* make scrollbar transparent */
}
.inner { .inner {
width: 640px; width: 640px;
margin: 0 auto; margin: 0 auto;

View File

@ -1,10 +1,11 @@
<script> <script>
import { goto, beforeUrlChange } from "@roxi/routify" import { goto, beforeUrlChange } from "@roxi/routify"
import { Button, Heading, Body, Spacer } from "@budibase/bbui" import { Button, Heading, Body, Spacer, Divider } 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"
import ICONS from "components/backend/DatasourceNavigator/icons" import ICONS from "components/backend/DatasourceNavigator/icons"
import { capitalise } from "../../../../../../helpers"
let unsaved = false let unsaved = false
@ -19,11 +20,8 @@
} }
function onClickQuery(query) { function onClickQuery(query) {
if ($queries.selected === query._id) {
return
}
queries.select(query) queries.select(query)
$goto(`../${query._id}`) $goto(`./${query._id}`)
} }
function setUnsaved() { function setUnsaved() {
@ -45,50 +43,42 @@
<section> <section>
<Spacer extraLarge /> <Spacer extraLarge />
<header> <header>
<div class="datasource-icon"> <svelte:component
<svelte:component this={ICONS[datasource.source]}
this={ICONS[datasource.source]} height="26"
height="26" width="26" />
width="26" /> <Heading l>{datasource.name}</Heading>
</div>
<h3 class="section-title">{datasource.name}</h3>
</header> </header>
<Body small grey lh>{integration.description}</Body> <Body small grey lh>{integration.description}</Body>
<Spacer extraLarge /> <Spacer extraLarge />
<hr /> <Divider />
<Spacer large />
<Spacer extraLarge /> <Spacer extraLarge />
<div class="container"> <div class="container">
<div class="config-header"> <div class="config-header">
<Heading small>Configuration</Heading> <Heading>Configuration</Heading>
<Button secondary on:click={saveDatasource}>Save</Button> <Button secondary on:click={saveDatasource}>Save</Button>
</div> </div>
<Body small grey> <Body small grey>
Connect your database to Budibase using the config below. Connect your database to Budibase using the config below.
</Body> </Body>
<Spacer extraLarge /> <Spacer extraLarge />
<IntegrationConfigForm <IntegrationConfigForm
schema={integration.datasource} schema={integration.datasource}
integration={datasource.config} integration={datasource.config}
on:change={setUnsaved} /> on:change={setUnsaved} />
<Spacer extraLarge /> <Spacer extraLarge />
<hr /> <Divider />
<Spacer large />
<Spacer extraLarge /> <Spacer extraLarge />
<div class="query-header"> <div class="query-header">
<Heading small>Queries</Heading> <Heading>Queries</Heading>
<Button secondary on:click={() => $goto('../new')}>Add Query</Button> <Button secondary on:click={() => $goto('./new')}>Add Query</Button>
</div> </div>
<Spacer extraLarge /> <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)}>
<p class="query-name">{query.name}</p> <p class="query-name">{query.name}</p>
<p>{query.queryVerb}</p> <p>{capitalise(query.queryVerb)}</p>
<p></p> <p></p>
</div> </div>
{/each} {/each}
@ -108,18 +98,11 @@
width: 640px; width: 640px;
} }
hr {
border: 1px solid var(--grey-2);
}
header { header {
margin: 0 0 var(--spacing-xs) 0; margin: 0 0 var(--spacing-xs) 0;
display: flex; display: flex;
gap: var(--spacing-m); gap: var(--spacing-l);
} align-items: center;
.section-title {
text-transform: capitalize;
} }
.config-header { .config-header {
@ -150,7 +133,7 @@
.query-list-item { .query-list-item {
border-radius: var(--border-radius-m); border-radius: var(--border-radius-m);
background: var(--background); background: var(--background);
border: var(--border-grey); border: var(--border-dark);
display: grid; display: grid;
grid-template-columns: 2fr 0.75fr 20px; grid-template-columns: 2fr 0.75fr 20px;
align-items: center; align-items: center;