pass field values in binding drawer

This commit is contained in:
Martin McKeaveney 2021-01-14 14:22:24 +00:00
parent 267e85c2bf
commit 1b51113c44
10 changed files with 121 additions and 114 deletions

View File

@ -9,6 +9,7 @@ const INITIAL_BACKEND_UI_STATE = {
roles: [], roles: [],
datasources: [], datasources: [],
queries: [], queries: [],
integrations: {},
selectedDatabase: {}, selectedDatabase: {},
selectedTable: {}, selectedTable: {},
draftTable: {}, draftTable: {},
@ -27,11 +28,15 @@ export const getBackendUiStore = () => {
const datasources = await datasourcesResponse.json() const datasources = await datasourcesResponse.json()
const queriesResponse = await api.get(`/api/queries`) const queriesResponse = await api.get(`/api/queries`)
const queries = await queriesResponse.json() const queries = await queriesResponse.json()
const integrationsResponse = await api.get("/api/integrations")
const integrations = await integrationsResponse.json()
store.update(state => { store.update(state => {
state.selectedDatabase = db state.selectedDatabase = db
state.tables = tables state.tables = tables
state.datasources = datasources state.datasources = datasources
state.queries = queries state.queries = queries
state.integrations = integrations
return state return state
}) })
}, },
@ -132,6 +137,7 @@ export const getBackendUiStore = () => {
state.selectedQueryId = json._id state.selectedQueryId = json._id
return state return state
}) })
return json
}, },
select: queryId => select: queryId =>
store.update(state => { store.update(state => {

View File

@ -1,26 +1,33 @@
<script> <script>
import { onMount } from "svelte" import { onMount } from "svelte"
import { backendUiStore } from "builderStore"
import { Input, TextArea, Spacer } from "@budibase/bbui" import { Input, TextArea, Spacer } from "@budibase/bbui"
import api from "builderStore/api"
import ICONS from "../icons" import ICONS from "../icons"
const INTEGRATION_ICON_MAP = {
POSTGRES: "ri-database-2-line",
}
export let integration = {} export let integration = {}
let integrationsPromise = fetchIntegrations() let schema
let selectedIntegrationConfig
let integrations = [] let integrations = []
async function fetchIntegrations() { async function fetchIntegrations() {
const response = await api.get("/api/integrations") const response = await api.get("/api/integrations")
const json = await response.json() const json = await response.json()
integrations = json integrations = json
return json return json
} }
function selectIntegration(integrationType) {
schema = integrations[integrationType].datasource
integration = {
type: integrationType,
...Object.keys(schema).reduce(
(acc, next) => ({ ...acc, [next]: schema[next].default }),
{}
),
}
}
onMount(() => { onMount(() => {
fetchIntegrations() fetchIntegrations()
}) })
@ -32,18 +39,7 @@
<div <div
class="integration hoverable" class="integration hoverable"
class:selected={integration.type === integrationType} class:selected={integration.type === integrationType}
on:click={() => { on:click={() => selectIntegration(integrationType)}>
selectedIntegrationConfig = integrations[integrationType].datasource
integration = { type: integrationType, ...Object.keys(selectedIntegrationConfig).reduce(
(acc, next) => {
return {
...acc,
[next]: selectedIntegrationConfig[next].default,
}
},
{}
) }
}}>
<svelte:component <svelte:component
this={ICONS[integrationType]} this={ICONS[integrationType]}
height="100" height="100"
@ -53,11 +49,11 @@
{/each} {/each}
</div> </div>
{#if selectedIntegrationConfig} {#if schema}
{#each Object.keys(selectedIntegrationConfig) as configKey} {#each Object.keys(schema) as configKey}
<Input <Input
thin thin
type={selectedIntegrationConfig[configKey].type} type={schema[configKey].type}
label={configKey} label={configKey}
bind:value={integration[configKey]} /> bind:value={integration[configKey]} />
<Spacer medium /> <Spacer medium />

View File

@ -11,6 +11,7 @@
export let fields = {} export let fields = {}
export let schema export let schema
export let editable
let customSchema = {} let customSchema = {}
let draftField = {} let draftField = {}
@ -29,12 +30,13 @@
{#each Object.keys(schema.fields) as field} {#each Object.keys(schema.fields) as field}
<Label extraSmall grey>{field}</Label> <Label extraSmall grey>{field}</Label>
<Input <Input
disabled={!editable}
type={schema.fields[field]?.type} type={schema.fields[field]?.type}
required={schema.fields[field]?.required} required={schema.fields[field]?.required}
bind:value={fields[field]} /> bind:value={fields[field]} />
<Spacer medium /> <Spacer medium />
{/each} {/each}
{#if schema.customisable} {#if schema.customisable && editable}
<Spacer large /> <Spacer large />
<Label>Add Custom Field</Label> <Label>Add Custom Field</Label>
{#each Object.keys(customSchema) as field} {#each Object.keys(customSchema) as field}

View File

@ -40,8 +40,8 @@
<div /> <div />
{/if} {/if}
{#each parameters as parameter, idx} {#each parameters as parameter, idx}
<Input thin bind:value={parameter.name} /> <Input thin disabled={bindable} bind:value={parameter.name} />
<Input thin bind:value={parameter.default} /> <Input thin disabled={bindable} bind:value={parameter.default} />
{#if bindable} {#if bindable}
<BindableInput <BindableInput
type="string" type="string"

View File

@ -1,5 +1,6 @@
<script> <script>
import { onMount } from "svelte" import { onMount } from "svelte"
import { goto } from "@sveltech/routify"
import { import {
Select, Select,
Button, Button,
@ -55,8 +56,9 @@
{} {}
) )
$: datasourceType = datasource.source $: datasourceType = datasource?.source
$: datasourceType && fetchQueryConfig()
$: config = $backendUiStore.integrations[datasourceType]?.query
$: shouldShowQueryConfig = config && query.queryVerb && query.queryType $: shouldShowQueryConfig = config && query.queryVerb && query.queryType
@ -69,17 +71,6 @@
fields = fields fields = fields
} }
async function fetchQueryConfig() {
try {
const response = await api.get(`/api/integrations/${datasource.source}`)
const json = await response.json()
config = json.query
} catch (err) {
notifier.danger("Error fetching integration configuration.")
console.error(err)
}
}
async function previewQuery() { async function previewQuery() {
try { try {
const response = await api.post(`/api/queries/preview`, { const response = await api.post(`/api/queries/preview`, {
@ -115,8 +106,12 @@
async function saveQuery() { async function saveQuery() {
try { try {
await backendUiStore.actions.queries.save(query.datasourceId, query) const { _id } = await backendUiStore.actions.queries.save(
query.datasourceId,
query
)
notifier.success(`Query saved successfully.`) notifier.success(`Query saved successfully.`)
$goto(`../../${_id}`)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
notifier.danger(`Error creating query. ${err.message}`) notifier.danger(`Error creating query. ${err.message}`)
@ -161,9 +156,10 @@
<Spacer medium /> <Spacer medium />
<IntegrationQueryEditor <IntegrationQueryEditor
schema={config[query.queryVerb][query.queryType]}
{query} {query}
bind:parameters /> schema={config[query.queryVerb][query.queryType]}
bind:parameters
/>
<Spacer medium /> <Spacer medium />

View File

@ -1,18 +1,23 @@
<script> <script>
import CodeMirror from "./codemirror" import CodeMirror from "./codemirror"
import { onMount, createEventDispatcher } from "svelte" import { onMount, createEventDispatcher } from "svelte"
import { themeStore } from "builderStore"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const THEMES = {
DARK: "tomorrow-night-eighties",
LIGHT: "default",
}
export let value = "" export let value = ""
export let readonly = false export let readOnly = false
export let errorLoc = null
export let lineNumbers = true export let lineNumbers = true
export let tab = true export let tab = true
export let mode export let mode
let w let width
let h let height
// We have to expose set and update methods, rather // We have to expose set and update methods, rather
// than making this state-driven through props, // than making this state-driven through props,
@ -72,43 +77,10 @@
let error_line let error_line
let destroyed = false let destroyed = false
$: if (editor && w && h) { $: if (editor && width && height) {
editor.refresh() editor.refresh()
} }
$: {
if (marker) marker.clear()
if (errorLoc) {
const line = errorLoc.line - 1
const ch = errorLoc.column
marker = editor.markText(
{ line, ch },
{ line, ch: ch + 1 },
{
className: "error-loc",
}
)
error_line = line
} else {
error_line = null
}
}
let previous_error_line
$: if (editor) {
if (previous_error_line != null) {
editor.removeLineClass(previous_error_line, "wrap", "error-line")
}
if (error_line && error_line !== previous_error_line) {
editor.addLineClass(error_line, "wrap", "error-line")
previous_error_line = error_line
}
}
onMount(() => { onMount(() => {
createEditor(mode).then(() => { createEditor(mode).then(() => {
if (editor) editor.setValue(value || "") if (editor) editor.setValue(value || "")
@ -137,9 +109,10 @@
mode: modes[mode] || { mode: modes[mode] || {
name: mode, name: mode,
}, },
readOnly: readonly, readOnly,
autoCloseBrackets: true, autoCloseBrackets: true,
autoCloseTags: true, autoCloseTags: true,
theme: $themeStore.darkMode ? THEMES.DARK : THEMES.LIGHT,
} }
if (!tab) if (!tab)
@ -182,6 +155,7 @@
} }
:global(.CodeMirror) { :global(.CodeMirror) {
height: auto !important;
border-radius: var(--border-radius-m); border-radius: var(--border-radius-m);
font-family: var(--font-sans) !important; font-family: var(--font-sans) !important;
} }

View File

@ -1,5 +1,7 @@
import CodeMirror from "codemirror" import CodeMirror from "codemirror"
import "codemirror/lib/codemirror.css" import "codemirror/lib/codemirror.css"
import "codemirror/theme/tomorrow-night-eighties.css"
import "codemirror/theme/neo.css"
import "codemirror/mode/sql/sql" import "codemirror/mode/sql/sql"
import "codemirror/mode/css/css" import "codemirror/mode/css/css"
import "codemirror/mode/handlebars/handlebars" import "codemirror/mode/handlebars/handlebars"

View File

@ -1,4 +1,5 @@
<script> <script>
import { onMount } from "svelte"
import { TextArea, Label, Input, Heading, Spacer } from "@budibase/bbui" import { TextArea, Label, Input, Heading, Spacer } from "@budibase/bbui"
import Editor from "./SvelteEditor.svelte" import Editor from "./SvelteEditor.svelte"
import ParameterBuilder from "./QueryParameterBuilder.svelte" import ParameterBuilder from "./QueryParameterBuilder.svelte"
@ -12,14 +13,17 @@
export let query export let query
export let schema export let schema
export let editable = true
function updateQuery({ detail }) { function updateQuery({ detail }) {
query.fields[schema.type] = detail.value query.fields[schema.type] = detail.value
} }
</script> </script>
<ParameterBuilder bind:parameters={query.parameters} bindable={false} /> {#if editable}
<Spacer large /> <ParameterBuilder bind:parameters={query.parameters} bindable={false} />
<Spacer large />
{/if}
<Heading extraSmall black>Query</Heading> <Heading extraSmall black>Query</Heading>
<Spacer large /> <Spacer large />
@ -30,6 +34,7 @@
label="Query" label="Query"
mode="sql" mode="sql"
on:change={updateQuery} on:change={updateQuery}
readOnly={!editable}
value={query.fields.sql} /> value={query.fields.sql} />
{:else if schema.type === QueryTypes.JSON} {:else if schema.type === QueryTypes.JSON}
<Spacer large /> <Spacer large />
@ -37,8 +42,9 @@
label="Query" label="Query"
mode="json" mode="json"
on:change={updateQuery} on:change={updateQuery}
readOnly={!editable}
value={query.fields.json} /> value={query.fields.json} />
{:else if schema.type === QueryTypes.FIELDS} {:else if schema.type === QueryTypes.FIELDS}
<FieldsBuilder bind:fields={query.fields} {schema} /> <FieldsBuilder bind:fields={query.fields} {schema} {editable} />
{/if} {/if}
{/if} {/if}

View File

@ -5,6 +5,7 @@
import { notifier } from "builderStore/store/notifications" import { notifier } from "builderStore/store/notifications"
import BottomDrawer from "components/common/BottomDrawer.svelte" import BottomDrawer from "components/common/BottomDrawer.svelte"
import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte" import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte"
import IntegrationQueryEditor from "components/integration/index.svelte"
import fetchBindableProperties from "../../builderStore/fetchBindableProperties" import fetchBindableProperties from "../../builderStore/fetchBindableProperties"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -13,18 +14,6 @@
export let value = {} export let value = {}
function handleSelected(selected) {
dispatch("change", selected)
dropdownRight.hide()
}
function openBindingDrawer() {
bindingDrawerOpen = true
}
function closeDatabindingDrawer() {
bindingDrawerOpen = false
}
$: tables = $backendUiStore.tables.map(m => ({ $: tables = $backendUiStore.tables.map(m => ({
label: m.name, label: m.name,
@ -78,6 +67,24 @@
type: "link", type: "link",
} }
}) })
function handleSelected(selected) {
dispatch("change", selected)
dropdownRight.hide()
}
function openBindingDrawer() {
bindingDrawerOpen = true
}
function closeDatabindingDrawer() {
bindingDrawerOpen = false
}
function fetchDatasourceSchema(query) {
const source = $backendUiStore.datasources.find(ds => ds._id === query.datasourceId).source
return $backendUiStore.integrations[source].query[query.queryVerb][query.queryType];
}
</script> </script>
<div <div
@ -98,11 +105,18 @@
}}>Save</Button> }}>Save</Button>
</div> </div>
<div class="drawer-contents" slot="body"> <div class="drawer-contents" slot="body">
<pre>{value.queryString}</pre> <IntegrationQueryEditor
query={value}
schema={fetchDatasourceSchema(value)}
editable={false}
/>
<Spacer large />
{#if value.parameters.length > 0}
<ParameterBuilder <ParameterBuilder
bind:customParams={value.queryParams} bind:customParams={value.queryParams}
parameters={value.parameters || []} parameters={value.parameters}
bindings={queryBindableProperties} /> bindings={queryBindableProperties} />
{/if}
</div> </div>
</BottomDrawer> </BottomDrawer>
{/if} {/if}
@ -229,6 +243,8 @@
.drawer-contents { .drawer-contents {
padding: var(--spacing-xl); padding: var(--spacing-xl);
height: 40vh;
overflow-y: auto;
} }
i { i {

View File

@ -17,24 +17,33 @@
} }
} }
$: { $: selectedQuery = $backendUiStore.queries.find(
if ($params.query !== "new") { query => query._id === $backendUiStore.selectedQueryId
query = $backendUiStore.queries.find(query => query._id === $params.query) ) || {
} else {
// New query
query = {
datasourceId: $params.selectedDatasource, datasourceId: $params.selectedDatasource,
name: "New Query", name: "New Query",
parameters: [], parameters: [],
fields: {}, fields: {},
} }
}
} // $: {
// if ($params.query !== "new") {
// query = $backendUiStore.queries.find(query => query._id === $params.query)
// } else {
// // New query
// query = {
// datasourceId: $params.selectedDatasource,
// name: "New Query",
// parameters: [],
// fields: {},
// }
// }
// }
</script> </script>
<section> <section>
{#if $backendUiStore.selectedDatabase._id && query} {#if $backendUiStore.selectedDatabase._id && selectedQuery}
<QueryInterface {query} /> <QueryInterface query={selectedQuery} />
{/if} {/if}
</section> </section>