budibase/packages/builder/src/components/integration/QueryViewer.svelte

229 lines
6.2 KiB
Svelte
Raw Normal View History

2020-12-18 19:19:43 +01:00
<script>
2021-03-17 12:40:24 +01:00
import { goto } from "@roxi/routify"
2020-12-18 19:19:43 +01:00
import {
2021-04-23 11:55:27 +02:00
Icon,
2020-12-18 19:19:43 +01:00
Select,
Button,
2021-04-28 15:46:11 +02:00
ButtonGroup,
Body,
2020-12-18 19:19:43 +01:00
Label,
Layout,
2020-12-18 19:19:43 +01:00
Input,
Heading,
2021-04-21 13:41:44 +02:00
Tabs,
2021-04-23 11:55:27 +02:00
Tab,
2020-12-18 19:19:43 +01:00
} from "@budibase/bbui"
import { notifications, Divider } from "@budibase/bbui"
import ExtraQueryConfig from "./ExtraQueryConfig.svelte"
2020-12-18 19:19:43 +01:00
import IntegrationQueryEditor from "components/integration/index.svelte"
2021-01-07 14:13:46 +01:00
import ExternalDataSourceTable from "components/backend/DataTable/ExternalDataSourceTable.svelte"
import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte"
import { datasources, integrations, queries } from "stores/backend"
import { capitalise } from "../../helpers"
import CodeMirrorEditor from "components/common/CodeMirrorEditor.svelte"
2021-12-06 18:39:51 +01:00
import JSONPreview from "./JSONPreview.svelte"
import { SchemaTypeOptions } from "constants/backend"
2021-12-06 18:39:51 +01:00
import KeyValueBuilder from "./KeyValueBuilder.svelte"
import { fieldsToSchema, schemaToFields } from "helpers/data/utils"
import AccessLevelSelect from "./AccessLevelSelect.svelte"
2020-12-18 19:19:43 +01:00
export let query
2021-12-06 18:39:51 +01:00
let fields = query?.schema ? schemaToFields(query.schema) : []
2021-01-07 14:13:46 +01:00
let parameters
2021-01-15 18:29:46 +01:00
let data = []
let saveId
2021-10-13 17:42:07 +02:00
const transformerDocs =
"https://docs.budibase.com/building-apps/data/transformers"
2020-12-18 19:19:43 +01:00
2021-06-08 18:14:46 +02:00
$: datasource = $datasources.list.find(ds => ds._id === query.datasourceId)
$: query.schema = fieldsToSchema(fields)
2021-01-14 15:22:24 +01:00
$: datasourceType = datasource?.source
$: integrationInfo = $integrations[datasourceType]
$: queryConfig = integrationInfo?.query
2021-02-18 19:55:08 +01:00
$: shouldShowQueryConfig = queryConfig && query.queryVerb
$: readQuery = query.queryVerb === "read" || query.readable
2021-06-08 18:14:46 +02:00
$: queryInvalid = !query.name || (readQuery && data.length === 0)
2021-01-13 15:11:53 +01:00
// seed the transformer
if (query && !query.transformer) {
query.transformer = "return data"
}
function resetDependentFields() {
if (query.fields.extra) {
query.fields.extra = {}
}
}
function populateExtraQuery(extraQueryFields) {
query.fields.extra = extraQueryFields
}
2020-12-18 19:19:43 +01:00
async function previewQuery() {
try {
2021-12-06 18:39:51 +01:00
const response = await queries.preview(query)
if (response.rows.length === 0) {
notifications.info(
2021-01-18 16:40:26 +01:00
"Query results empty. Please execute a query with results to create your schema."
)
2021-01-15 18:29:46 +01:00
return
2021-01-18 16:40:26 +01:00
}
2021-12-06 18:39:51 +01:00
data = response.rows
fields = response.schema
notifications.success("Query executed successfully.")
2020-12-18 19:19:43 +01:00
} catch (err) {
2021-12-06 18:39:51 +01:00
notifications.error(err)
2020-12-18 19:19:43 +01:00
}
}
2021-01-07 14:13:46 +01:00
async function saveQuery() {
try {
2021-04-01 11:29:47 +02:00
const { _id } = await queries.save(query.datasourceId, query)
saveId = _id
notifications.success(`Query saved successfully.`)
$goto(`../${_id}`)
2021-01-07 14:13:46 +01:00
} catch (err) {
console.error(err)
notifications.error(`Error creating query. ${err.message}`)
2021-01-07 14:13:46 +01:00
}
}
2020-12-18 19:19:43 +01:00
</script>
<Layout gap="S" noPadding>
<Heading size="M">Query {integrationInfo?.friendlyName}</Heading>
<Divider />
<Heading size="S">Config</Heading>
<div class="config">
<div class="config-field">
<Label>Query Name</Label>
<Input bind:value={query.name} />
</div>
{#if queryConfig}
<div class="config-field">
<Label>Function</Label>
<Select
bind:value={query.queryVerb}
on:change={resetDependentFields}
options={Object.keys(queryConfig)}
2021-05-04 12:32:22 +02:00
getOptionLabel={verb =>
queryConfig[verb]?.displayName || capitalise(verb)}
/>
</div>
<div class="config-field">
<AccessLevelSelect {saveId} {query} label="Access Level" />
</div>
{#if integrationInfo?.extra && query.queryVerb}
<ExtraQueryConfig
{query}
{populateExtraQuery}
config={integrationInfo.extra}
/>
{/if}
<ParameterBuilder bind:parameters={query.parameters} bindable={false} />
{/if}
</div>
{#if shouldShowQueryConfig}
<Divider />
2021-01-12 17:49:11 +01:00
<div class="config">
<Heading size="S">Fields</Heading>
<Body size="S">Fill in the fields specific to this query.</Body>
2021-01-13 15:11:53 +01:00
<IntegrationQueryEditor
2021-02-18 19:55:08 +01:00
{datasource}
2021-01-13 15:11:53 +01:00
{query}
height={200}
2021-02-18 19:55:08 +01:00
schema={queryConfig[query.queryVerb]}
2021-04-23 11:55:27 +02:00
bind:parameters
/>
<Divider />
</div>
<div class="config">
2021-10-13 17:42:07 +02:00
<div class="help-heading">
<Heading size="S">Transformer</Heading>
<Icon
on:click={() => window.open(transformerDocs)}
hoverable
name="Help"
size="L"
/>
</div>
<Body size="S"
2021-10-13 17:42:07 +02:00
>Add a JavaScript function to transform the query result.</Body
>
<CodeMirrorEditor
height={200}
label="Transformer"
value={query.transformer}
2021-10-13 17:42:07 +02:00
resize="vertical"
on:change={e => (query.transformer = e.detail)}
/>
<Divider />
</div>
<div class="viewer-controls">
<Heading size="S">Results</Heading>
2021-04-28 15:46:11 +02:00
<ButtonGroup>
2021-06-08 18:14:46 +02:00
<Button cta disabled={queryInvalid} on:click={saveQuery}>
Save Query
</Button>
2021-04-28 15:46:11 +02:00
<Button secondary on:click={previewQuery}>Run Query</Button>
</ButtonGroup>
</div>
<Body size="S">
2021-04-28 15:46:11 +02:00
Below, you can preview the results from your query and change the schema.
</Body>
<section class="viewer">
{#if data}
<Tabs selected="JSON">
<Tab title="JSON">
2021-12-06 18:39:51 +01:00
<JSONPreview data={data[0]} minHeight="120" />
2021-04-28 15:46:11 +02:00
</Tab>
<Tab title="Schema">
2021-12-06 18:39:51 +01:00
<KeyValueBuilder
bind:object={fields}
name="field"
headings
options={SchemaTypeOptions}
/>
2021-04-28 15:46:11 +02:00
</Tab>
<Tab title="Preview">
<ExternalDataSourceTable {query} {data} />
</Tab>
</Tabs>
{/if}
</section>
{/if}
</Layout>
2020-12-18 19:19:43 +01:00
<style>
.config {
display: grid;
grid-gap: var(--spacing-s);
}
2021-10-13 17:42:07 +02:00
.config-field {
display: grid;
grid-template-columns: 20% 1fr;
grid-gap: var(--spacing-l);
align-items: center;
}
2021-10-13 17:42:07 +02:00
.help-heading {
display: flex;
justify-content: space-between;
}
.viewer {
min-height: 200px;
width: 640px;
}
.viewer-controls {
2021-01-12 17:49:11 +01:00
display: flex;
flex-direction: row;
2021-02-18 19:55:08 +01:00
justify-content: space-between;
gap: var(--spacing-m);
min-width: 150px;
2021-02-19 15:31:07 +01:00
align-items: center;
}
2020-12-18 19:19:43 +01:00
</style>