Variables UI WIP

This commit is contained in:
Rory Powell 2021-12-14 12:30:26 +00:00
parent 077c9ef434
commit 42279e67e8
5 changed files with 175 additions and 5 deletions

View File

@ -1,9 +1,18 @@
<script> <script>
import { Divider, Heading, ActionButton, Badge, Body } from "@budibase/bbui" import {
Divider,
Heading,
ActionButton,
Badge,
Body,
Layout,
} from "@budibase/bbui"
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte" import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
import RestAuthenticationBuilder from "./auth/RestAuthenticationBuilder.svelte" import RestAuthenticationBuilder from "./auth/RestAuthenticationBuilder.svelte"
import ViewDynamicVariables from "./variables/ViewDynamicVariables.svelte"
export let datasource export let datasource
export let queries
let addHeader let addHeader
</script> </script>
@ -43,6 +52,32 @@
</Body> </Body>
<RestAuthenticationBuilder bind:configs={datasource.config.authConfigs} /> <RestAuthenticationBuilder bind:configs={datasource.config.authConfigs} />
<Divider size="S" />
<div class="section-header">
<div class="badge">
<Heading size="S">Variables</Heading>
<Badge quiet grey>Optional</Badge>
</div>
</div>
<Body size="S"
>Variables enabled you to store and reuse values in queries. Static variables
use constant values while dynamic values can be bound to the response headers
or body of a query</Body
>
<Heading size="XS">Static</Heading>
<Layout noPadding gap="XS">
<KeyValueBuilder
name="Variable"
keyPlaceholder="Name"
headings
bind:object={datasource.config.staticVariables}
on:change
/>
</Layout>
<div />
<Heading size="XS">Dynamic</Heading>
<ViewDynamicVariables {queries} {datasource} />
<style> <style>
.section-header { .section-header {
display: flex; display: flex;

View File

@ -0,0 +1,40 @@
<script>
import { Body, Table } from "@budibase/bbui"
import { onMount } from "svelte"
export let datasource
export let queries
let dynamicVariables = []
const dynamicVariableSchema = {
name: "",
value: "",
query: "",
}
/**
* Add the query name to the dynamic variables
*/
const enrichDynamicVariables = () => {
datasource.config.dynamicVariables?.forEach(dv => {
const query = queries.find(query => query._id === dv.queryId)
if (query) {
dynamicVariables.push({ ...dv, query: query.name })
}
})
}
onMount(() => {
enrichDynamicVariables()
})
</script>
<Table
schema={dynamicVariableSchema}
data={dynamicVariables}
allowEditColumns={false}
allowEditRows={false}
allowSelectRows={false}
/>
<Body size="S" />

View File

@ -6,6 +6,8 @@
Label, Label,
Toggle, Toggle,
Select, Select,
ActionMenu,
MenuItem,
} from "@budibase/bbui" } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { lowercase } from "helpers" import { lowercase } from "helpers"
@ -23,7 +25,9 @@
export let toggle export let toggle
export let keyPlaceholder = "Key" export let keyPlaceholder = "Key"
export let valuePlaceholder = "Value" export let valuePlaceholder = "Value"
export let valueHeading
export let tooltip export let tooltip
export let menuItems
let fields = Object.entries(object).map(([name, value]) => ({ name, value })) let fields = Object.entries(object).map(([name, value]) => ({ name, value }))
let fieldActivity = [] let fieldActivity = []
@ -80,13 +84,18 @@
{#if headings} {#if headings}
<div class="container" class:container-active={toggle}> <div class="container" class:container-active={toggle}>
<Label {tooltip}>{keyPlaceholder}</Label> <Label {tooltip}>{keyPlaceholder}</Label>
<Label>{valuePlaceholder}</Label> <Label>{valueHeading || valuePlaceholder}</Label>
{#if toggle} {#if toggle}
<Label>Active</Label> <Label>Active</Label>
{/if} {/if}
</div> </div>
{/if} {/if}
<div class="container" class:container-active={toggle} class:readOnly> <div
class="container"
class:container-active={toggle}
class:container-menu={menuItems}
class:readOnly
>
{#each fields as field, idx} {#each fields as field, idx}
<Input <Input
placeholder={keyPlaceholder} placeholder={keyPlaceholder}
@ -112,6 +121,18 @@
{#if !readOnly} {#if !readOnly}
<Icon hoverable name="Close" on:click={() => deleteEntry(idx)} /> <Icon hoverable name="Close" on:click={() => deleteEntry(idx)} />
{/if} {/if}
{#if menuItems?.length > 0}
<ActionMenu>
<div slot="control" class="icon">
<Icon size="S" hoverable name="MoreSmallList" />
</div>
{#each menuItems as item}
<MenuItem on:click={item.onClick}>
{item.text}
</MenuItem>
{/each}
</ActionMenu>
{/if}
{/each} {/each}
</div> </div>
{/if} {/if}
@ -134,6 +155,9 @@
.container-active { .container-active {
grid-template-columns: 1fr 1fr 50px 20px; grid-template-columns: 1fr 1fr 50px 20px;
} }
.container-menu {
grid-template-columns: 1fr 1fr 20px 20px;
}
.readOnly { .readOnly {
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
} }

View File

@ -142,7 +142,11 @@
</div> </div>
{/if} {/if}
{#if datasource?.source === IntegrationTypes.REST} {#if datasource?.source === IntegrationTypes.REST}
<RestExtraConfigForm bind:datasource on:change={hasChanged} /> <RestExtraConfigForm
queries={queryList}
bind:datasource
on:change={hasChanged}
/>
{/if} {/if}
</Layout> </Layout>
</section> </section>

View File

@ -51,6 +51,7 @@
let response, schema, isGet let response, schema, isGet
let datasourceType, integrationInfo, queryConfig, responseSuccess let datasourceType, integrationInfo, queryConfig, responseSuccess
let authConfigId let authConfigId
let dynamicVariables
$: datasource = $datasources.list.find(ds => ds._id === query?.datasourceId) $: datasource = $datasources.list.find(ds => ds._id === query?.datasourceId)
$: datasourceType = datasource?.source $: datasourceType = datasource?.source
@ -62,6 +63,7 @@
$: responseSuccess = $: responseSuccess =
response?.info?.code >= 200 && response?.info?.code <= 206 response?.info?.code >= 200 && response?.info?.code <= 206
$: authConfigs = buildAuthConfigs(datasource) $: authConfigs = buildAuthConfigs(datasource)
$: dynamicVariables = buildDynamicVariables(datasource)
function getSelectedQuery() { function getSelectedQuery() {
return cloneDeep( return cloneDeep(
@ -125,8 +127,14 @@
saveId = _id saveId = _id
query = getSelectedQuery() query = getSelectedQuery()
notifications.success(`Request saved successfully.`) notifications.success(`Request saved successfully.`)
if (dynamicVariables) {
const dynamicVars = mapDynamicVariables(saveId)
datasource.config.dynamicVariables = dynamicVars
await datasources.save(datasource)
}
} catch (err) { } catch (err) {
notifications.error(`Error creating query. ${err.message}`) notifications.error(`Error saving query. ${err.message}`)
} }
} }
@ -181,6 +189,45 @@
query.fields.bodyType = "none" query.fields.bodyType = "none"
} }
}) })
/**
* Convert the dynamic variables list to a simple name / value object
*/
const buildDynamicVariables = datasource => {
const variablesList = datasource?.config?.dynamicVariables
let variables = {}
if (variablesList) {
variables = variablesList.reduce(
(acc, next) => ({ ...acc, [next.name]: next.value }),
{}
)
}
return variables
}
/**
* Convert the dynamic variables object back to a list
*/
const mapDynamicVariables = queryId => {
let variables = []
if (dynamicVariables) {
variables = Object.values(dynamicVariables).map((name, value) => ({
name,
value,
queryId,
}))
}
return variables
}
const schemaMenuItems = [
{
text: "Create dynamic variable",
onClick: () => {
console.log("create variable")
},
},
]
</script> </script>
{#if query} {#if query}
@ -318,6 +365,7 @@
name="schema" name="schema"
headings headings
options={SchemaTypeOptions} options={SchemaTypeOptions}
menuItems={schemaMenuItems}
/> />
</Tab> </Tab>
{/if} {/if}
@ -341,6 +389,25 @@
{/if} {/if}
</div> </div>
</Tab> </Tab>
{/if}
{#if dynamicVariables || response}
<Tab title="Dynamic Variables">
<Layout noPadding gap="S">
<Body size="S"
>{"Create dynamic variables to use body and headers results in other queries"}</Body
>
<KeyValueBuilder
bind:object={dynamicVariables}
name="Variable"
headings
keyPlaceholder="Name"
valuePlaceholder={`e.g. {{ headers.cookie }}`}
valueHeading={`Value`}
/>
</Layout>
</Tab>
{/if}
{#if response}
<div class="stats"> <div class="stats">
<Label size="L"> <Label size="L">
Status: <span class={responseSuccess ? "green" : "red"} Status: <span class={responseSuccess ? "green" : "red"}