Variables UI WIP
This commit is contained in:
parent
077c9ef434
commit
42279e67e8
|
@ -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;
|
||||||
|
|
|
@ -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" />
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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"}
|
||||||
|
|
Loading…
Reference in New Issue