Fixes for datasource authentication parsing. Mapping UX updates

This commit is contained in:
Dean 2022-07-01 17:27:24 +01:00
parent ac8513bd4c
commit 31b51e1ecf
8 changed files with 165 additions and 59 deletions

View File

@ -40,5 +40,6 @@
on:change={onChange} on:change={onChange}
on:pick on:pick
on:type on:type
on:blur
/> />
</Field> </Field>

View File

@ -52,7 +52,10 @@
{id} {id}
type="text" type="text"
on:focus={() => (focus = true)} on:focus={() => (focus = true)}
on:blur={() => (focus = false)} on:blur={() => {
focus = false
dispatch("blur")
}}
on:change={onType} on:change={onType}
value={value || ""} value={value || ""}
placeholder={placeholder || ""} placeholder={placeholder || ""}

View File

@ -54,7 +54,56 @@ export const getBindableProperties = (asset, componentId) => {
*/ */
export const getRestBindings = () => { export const getRestBindings = () => {
const userBindings = getUserBindings() const userBindings = getUserBindings()
return [...userBindings] return [...userBindings, ...getAuthBindings()]
}
/**
* Gets all rest bindable auth fields
*/
export const getAuthBindings = () => {
let bindings = []
const safeUser = makePropSafe("user")
const safeOAuth2 = makePropSafe("oauth2")
const safeAccessToken = makePropSafe("accessToken")
const authBindings = [
{
runtime: `${safeUser}.${safeOAuth2}.${safeAccessToken}`,
readable: `Current User.OAuthToken`,
key: "accessToken",
},
]
bindings = Object.keys(authBindings).map(key => {
const fieldBinding = authBindings[key]
return {
type: "context",
runtimeBinding: fieldBinding.runtime,
readableBinding: fieldBinding.readable,
fieldSchema: { type: "string", name: fieldBinding.key },
providerId: "user",
}
})
return bindings
}
/**
* Utility - convert a key/value map to an array of custom 'context' bindings
* @param {object} valueMap Key/value pairings
* @param {string} prefix A contextual string prefix/path for a user readable binding
* @return {object[]} An array containing readable/runtime binding objects
*/
export const toBindingsArray = (valueMap, prefix) => {
if (!valueMap) {
return []
}
return Object.keys(valueMap).map(binding => {
return {
type: "context",
runtimeBinding: binding,
readableBinding: `${prefix}.${binding}`,
}
})
} }
/** /**

View File

@ -2,6 +2,8 @@
import { onMount } from "svelte" import { onMount } from "svelte"
import { ModalContent, Layout, Select, Body, Input } from "@budibase/bbui" import { ModalContent, Layout, Select, Body, Input } from "@budibase/bbui"
import { AUTH_TYPE_LABELS, AUTH_TYPES } from "./authTypes" import { AUTH_TYPE_LABELS, AUTH_TYPES } from "./authTypes"
import DrawerBindableCombobox from "components/common/bindings/DrawerBindableCombobox.svelte"
import { getAuthBindings } from "builderStore/dataBinding"
export let configs export let configs
export let currentConfig export let currentConfig
@ -203,11 +205,23 @@
/> />
{/if} {/if}
{#if form.type === AUTH_TYPES.BEARER} {#if form.type === AUTH_TYPES.BEARER}
<Input <DrawerBindableCombobox
label="Token" label="Token"
bind:value={form.bearer.token} value={form.bearer.token}
on:change={onFieldChange} bindings={getAuthBindings()}
on:blur={() => (blurred.bearer.token = true)} on:change={e => {
form.bearer.token = e.detail
console.log(e.detail)
onFieldChange()
}}
on:blur={() => {
blurred.bearer.token = true
onFieldChange()
}}
allowJS={false}
placeholder="Token"
appendBindingsAsOptions={true}
drawerEnabled={false}
error={blurred.bearer.token ? errors.bearer.token : null} error={blurred.bearer.token ? errors.bearer.token : null}
/> />
{/if} {/if}

View File

@ -18,6 +18,8 @@
export let options export let options
export let allowJS = true export let allowJS = true
export let appendBindingsAsOptions = true export let appendBindingsAsOptions = true
export let drawerEnabled = false
export let error
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
let bindingDrawer let bindingDrawer
@ -59,10 +61,12 @@
value={isJS ? "(JavaScript function)" : readableValue} value={isJS ? "(JavaScript function)" : readableValue}
on:type={e => onChange(e.detail, false)} on:type={e => onChange(e.detail, false)}
on:pick={e => onChange(e.detail, true)} on:pick={e => onChange(e.detail, true)}
on:blur={() => dispatch("blur")}
{placeholder} {placeholder}
options={allOptions} options={allOptions}
{error}
/> />
{#if !disabled} {#if !disabled && drawerEnabled}
<div <div
class="icon" class="icon"
on:click={bindingDrawer.show} on:click={bindingDrawer.show}
@ -72,7 +76,8 @@
</div> </div>
{/if} {/if}
</div> </div>
<Drawer bind:this={bindingDrawer} {title}> {#if !drawerEnabled}
<Drawer bind:this={bindingDrawer} {title}>
<svelte:fragment slot="description"> <svelte:fragment slot="description">
Add the objects on the left to enrich your text. Add the objects on the left to enrich your text.
</svelte:fragment> </svelte:fragment>
@ -86,7 +91,8 @@
{bindings} {bindings}
{allowJS} {allowJS}
/> />
</Drawer> </Drawer>
{/if}
<style> <style>
.control { .control {

View File

@ -11,6 +11,7 @@
} from "@budibase/bbui" } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { lowercase } from "helpers" import { lowercase } from "helpers"
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
let dispatch = createEventDispatcher() let dispatch = createEventDispatcher()
@ -30,6 +31,7 @@
export let tooltip export let tooltip
export let menuItems export let menuItems
export let showMenu = false export let showMenu = false
export let bindings = []
let fields = Object.entries(object || {}).map(([name, value]) => ({ let fields = Object.entries(object || {}).map(([name, value]) => ({
name, name,
@ -108,6 +110,16 @@
/> />
{#if options} {#if options}
<Select bind:value={field.value} on:change={changed} {options} /> <Select bind:value={field.value} on:change={changed} {options} />
{:else if bindings && bindings.length}
<DrawerBindableInput
{bindings}
placeholder="Value"
on:change={e => (field.value = e.detail)}
disabled={readOnly}
value={field.value}
allowJS={false}
fillWidth={true}
/>
{:else} {:else}
<Input <Input
placeholder={valuePlaceholder} placeholder={valuePlaceholder}

View File

@ -42,8 +42,9 @@
import { import {
getRestBindings, getRestBindings,
readableToRuntimeBinding, toBindingsArray,
runtimeToReadableBinding, runtimeToReadableBinding,
readableToRuntimeBinding,
runtimeToReadableMap, runtimeToReadableMap,
readableToRuntimeMap, readableToRuntimeMap,
} from "builderStore/dataBinding" } from "builderStore/dataBinding"
@ -57,6 +58,25 @@
let dynamicVariables, addVariableModal, varBinding let dynamicVariables, addVariableModal, varBinding
let restBindings = getRestBindings() let restBindings = getRestBindings()
$: staticVariables = datasource?.config?.staticVariables || {}
$: customRequestBindings = toBindingsArray(requestBindings, "Binding")
$: dynamicRequestBindings = toBindingsArray(dynamicVariables, "Dynamic")
$: dataSourceStaticBindings = toBindingsArray(
staticVariables,
"Datasource.Static"
)
$: mergedBindings = [
...restBindings,
...customRequestBindings,
...dynamicRequestBindings,
...dataSourceStaticBindings,
]
$: mergedAndCompleteBindings = mergedBindings.filter(binding => {
return binding.runtimeBinding && binding.readableBinding
})
$: datasourceType = datasource?.source $: datasourceType = datasource?.source
$: integrationInfo = $integrations[datasourceType] $: integrationInfo = $integrations[datasourceType]
$: queryConfig = integrationInfo?.query $: queryConfig = integrationInfo?.query
@ -72,7 +92,10 @@
Object.keys(schema || {}).length !== 0 || Object.keys(schema || {}).length !== 0 ||
Object.keys(query?.schema || {}).length !== 0 Object.keys(query?.schema || {}).length !== 0
$: runtimeUrlQueries = readableToRuntimeMap(restBindings, breakQs) $: runtimeUrlQueries = readableToRuntimeMap(
mergedAndCompleteBindings,
breakQs
)
function getSelectedQuery() { function getSelectedQuery() {
const cloneQuery = cloneDeep( const cloneQuery = cloneDeep(
@ -87,32 +110,18 @@
queryVerb: "read", queryVerb: "read",
} }
) )
if (cloneQuery?.fields?.headers) {
cloneQuery.fields.headers = runtimeToReadableMap(
restBindings,
cloneQuery.fields.headers
)
}
if (cloneQuery?.fields?.requestBody) { if (cloneQuery?.fields?.requestBody) {
cloneQuery.fields.requestBody = cloneQuery.fields.requestBody =
typeof cloneQuery.fields.requestBody === "object" typeof cloneQuery.fields.requestBody === "object"
? runtimeToReadableMap(restBindings, cloneQuery.fields.requestBody) ? runtimeToReadableMap(
mergedAndCompleteBindings,
cloneQuery.fields.requestBody
)
: runtimeToReadableBinding( : runtimeToReadableBinding(
restBindings, mergedAndCompleteBindings,
cloneQuery.fields.requestBody cloneQuery.fields.requestBody
) )
} }
if (cloneQuery?.parameters) {
const flatParams = restUtils.queryParametersToKeyValue(
cloneQuery.parameters
)
const updatedParams = runtimeToReadableMap(restBindings, flatParams)
cloneQuery.parameters = restUtils.keyValueToQueryParameters(updatedParams)
}
return cloneQuery return cloneQuery
} }
@ -128,7 +137,7 @@
return base return base
} }
const qs = restUtils.buildQueryString( const qs = restUtils.buildQueryString(
runtimeToReadableMap(restBindings, qsObj) runtimeToReadableMap(mergedAndCompleteBindings, qsObj)
) )
let newUrl = base let newUrl = base
if (base.includes("?")) { if (base.includes("?")) {
@ -140,14 +149,17 @@
function buildQuery() { function buildQuery() {
const newQuery = cloneDeep(query) const newQuery = cloneDeep(query)
const queryString = restUtils.buildQueryString(runtimeUrlQueries) const queryString = restUtils.buildQueryString(runtimeUrlQueries)
newQuery.fields.headers = readableToRuntimeMap(
restBindings,
newQuery.fields.headers
)
newQuery.fields.requestBody = newQuery.fields.requestBody =
typeof newQuery.fields.requestBody === "object" typeof newQuery.fields.requestBody === "object"
? readableToRuntimeMap(restBindings, newQuery.fields.requestBody) ? readableToRuntimeMap(
: readableToRuntimeBinding(restBindings, newQuery.fields.requestBody) mergedAndCompleteBindings,
newQuery.fields.requestBody
)
: readableToRuntimeBinding(
mergedAndCompleteBindings,
newQuery.fields.requestBody
)
newQuery.fields.path = url.split("?")[0] newQuery.fields.path = url.split("?")[0]
newQuery.fields.queryString = queryString newQuery.fields.queryString = queryString
@ -155,14 +167,6 @@
newQuery.fields.disabledHeaders = restUtils.flipHeaderState(enabledHeaders) newQuery.fields.disabledHeaders = restUtils.flipHeaderState(enabledHeaders)
newQuery.schema = restUtils.fieldsToSchema(schema) newQuery.schema = restUtils.fieldsToSchema(schema)
const parsedRequestBindings = readableToRuntimeMap(
restBindings,
requestBindings
)
newQuery.parameters = restUtils.keyValueToQueryParameters(
parsedRequestBindings
)
return newQuery return newQuery
} }
@ -409,10 +413,20 @@
headings headings
keyPlaceholder="Binding name" keyPlaceholder="Binding name"
valuePlaceholder="Default" valuePlaceholder="Default"
bindings={[
...restBindings,
...dynamicRequestBindings,
...dataSourceStaticBindings,
]}
/> />
</Tab> </Tab>
<Tab title="Params"> <Tab title="Params">
<KeyValueBuilder bind:object={breakQs} name="param" headings /> <KeyValueBuilder
bind:object={breakQs}
name="param"
headings
bindings={mergedAndCompleteBindings}
/>
</Tab> </Tab>
<Tab title="Headers"> <Tab title="Headers">
<KeyValueBuilder <KeyValueBuilder
@ -421,6 +435,7 @@
toggle toggle
name="header" name="header"
headings headings
bindings={mergedAndCompleteBindings}
/> />
</Tab> </Tab>
<Tab title="Body"> <Tab title="Body">

View File

@ -36,6 +36,12 @@ class QueryRunner {
if (!Integration) { if (!Integration) {
throw "Integration type does not exist." throw "Integration type does not exist."
} }
datasource.config.authConfigs = enrichQueryFields(
datasource.config.authConfigs,
this.ctx
)
const integration = new Integration(datasource.config) const integration = new Integration(datasource.config)
// pre-query, make sure datasource variables are added to parameters // pre-query, make sure datasource variables are added to parameters