allow execution of external connector queries from button clicks
This commit is contained in:
parent
d27a264c96
commit
755fa0ac4a
|
@ -1,7 +1,6 @@
|
|||
import { writable, get } from "svelte/store"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import api from "../api"
|
||||
import { backendUiStore } from ".."
|
||||
|
||||
const INITIAL_BACKEND_UI_STATE = {
|
||||
tables: [],
|
||||
|
@ -63,6 +62,7 @@ export const getBackendUiStore = () => {
|
|||
select: async datasourceId => {
|
||||
store.update(state => {
|
||||
state.selectedDatasourceId = datasourceId
|
||||
state.selectedQueryId = null
|
||||
return state
|
||||
})
|
||||
},
|
||||
|
@ -123,6 +123,7 @@ export const getBackendUiStore = () => {
|
|||
queries: {
|
||||
select: queryId =>
|
||||
store.update(state => {
|
||||
state.selectedDatasourceId = null
|
||||
state.selectedQueryId = queryId
|
||||
return state
|
||||
}),
|
||||
|
|
|
@ -6,21 +6,13 @@
|
|||
import Table from "./Table.svelte"
|
||||
import CreateQueryButton from "components/backend/DataTable/buttons/CreateQueryButton.svelte"
|
||||
|
||||
export let datasourceId
|
||||
export let datasource
|
||||
export let query = {}
|
||||
|
||||
let data = []
|
||||
let loading = false
|
||||
let error = false
|
||||
|
||||
$: datasourceId = $params.selectedDatasource
|
||||
// TODO: refactor
|
||||
// $: query = $backendUiStore.datasources.find(
|
||||
// ds => ds._id === $params.selectedDatasource
|
||||
// ).queries[$params.query]
|
||||
$: title = query.name
|
||||
$: schema = query.schema
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
loading = true
|
||||
|
@ -46,8 +38,8 @@
|
|||
{#if error}
|
||||
<div class="errors">{error}</div>
|
||||
{/if}
|
||||
<Table {title} {schema} {data} {loading}>
|
||||
<CreateQueryButton {query} />
|
||||
<Table title={query.name} schema={query.schema} {data} {loading}>
|
||||
<CreateQueryButton {query} {datasource} />
|
||||
</Table>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -236,6 +236,7 @@
|
|||
}
|
||||
|
||||
:global(.ag-filter) {
|
||||
background: var(--background);
|
||||
padding: var(--spacing-s);
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
import CreateEditQuery from "components/backend/DataTable/modals/CreateEditQuery.svelte"
|
||||
|
||||
export let datasource
|
||||
export let query = {}
|
||||
|
||||
let modal
|
||||
let query = {}
|
||||
let fields = []
|
||||
|
||||
async function saveQuery() {
|
||||
|
@ -30,14 +30,12 @@
|
|||
notifier.danger(`Error creating query. ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
$: console.log(query)
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<Button text small on:click={modal.show}>
|
||||
<Icon name="filter" />
|
||||
{query ? 'Edit' : 'Create'} Query
|
||||
{$backendUiStore.selectedQueryId ? 'Edit' : 'Create'} Query
|
||||
</Button>
|
||||
</div>
|
||||
<Modal bind:this={modal}>
|
||||
|
@ -45,7 +43,7 @@
|
|||
confirmText="Save"
|
||||
cancelText="Cancel"
|
||||
onConfirm={saveQuery}
|
||||
title="Create New Query">
|
||||
title={query ? 'Edit Query' : 'Create New Query'}>
|
||||
<CreateEditQuery {datasource} bind:query />
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
export let query
|
||||
export let fields = []
|
||||
|
||||
console.log(query)
|
||||
|
||||
let config = {}
|
||||
let queryType
|
||||
let previewTab = "PREVIEW"
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
import { Modal, Switcher } from "@budibase/bbui"
|
||||
import NavItem from "components/common/NavItem.svelte"
|
||||
|
||||
let modal
|
||||
|
||||
$: selectedView =
|
||||
$backendUiStore.selectedView && $backendUiStore.selectedView.name
|
||||
|
||||
|
@ -34,12 +32,6 @@
|
|||
</script>
|
||||
|
||||
{#if $backendUiStore.selectedDatabase && $backendUiStore.selectedDatabase._id}
|
||||
<div class="title">
|
||||
<i
|
||||
data-cy="new-datasource"
|
||||
on:click={modal.show}
|
||||
class="ri-add-circle-fill" />
|
||||
</div>
|
||||
<div class="hierarchy-items-container">
|
||||
{#each $backendUiStore.datasources as datasource, idx}
|
||||
<NavItem
|
||||
|
@ -64,23 +56,3 @@
|
|||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<Modal bind:this={modal}>
|
||||
<CreateDatasourceModal />
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title i {
|
||||
font-size: 20px;
|
||||
}
|
||||
.title i:hover {
|
||||
cursor: pointer;
|
||||
color: var(--blue);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,14 +2,11 @@
|
|||
import { goto } from "@sveltech/routify"
|
||||
import { backendUiStore } from "builderStore"
|
||||
import { TableNames } from "constants"
|
||||
import CreateTableModal from "./modals/CreateTableModal.svelte"
|
||||
import EditTablePopover from "./popovers/EditTablePopover.svelte"
|
||||
import EditViewPopover from "./popovers/EditViewPopover.svelte"
|
||||
import { Modal, Switcher } from "@budibase/bbui"
|
||||
import { Switcher } from "@budibase/bbui"
|
||||
import NavItem from "components/common/NavItem.svelte"
|
||||
|
||||
let modal
|
||||
|
||||
$: selectedView =
|
||||
$backendUiStore.selectedView && $backendUiStore.selectedView.name
|
||||
|
||||
|
@ -35,9 +32,6 @@
|
|||
</script>
|
||||
|
||||
{#if $backendUiStore.selectedDatabase && $backendUiStore.selectedDatabase._id}
|
||||
<div class="title">
|
||||
<i data-cy="new-table" on:click={modal.show} class="ri-add-circle-fill" />
|
||||
</div>
|
||||
<div class="hierarchy-items-container">
|
||||
{#each $backendUiStore.tables as table, idx}
|
||||
<NavItem
|
||||
|
@ -64,27 +58,3 @@
|
|||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<Modal bind:this={modal}>
|
||||
<CreateTableModal />
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.title h1 {
|
||||
font-size: var(--font-size-m);
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
}
|
||||
.title i {
|
||||
font-size: 20px;
|
||||
}
|
||||
.title i:hover {
|
||||
cursor: pointer;
|
||||
color: var(--blue);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -13,9 +13,6 @@
|
|||
tables: $backendUiStore.tables,
|
||||
})
|
||||
|
||||
// just wraps binding in {{ ... }}
|
||||
const toBindingExpression = bindingPath => `{{ ${bindingPath} }}`
|
||||
|
||||
const tableFields = tableId => {
|
||||
const table = $backendUiStore.tables.find(m => m._id === tableId)
|
||||
|
||||
|
@ -63,12 +60,4 @@
|
|||
grid-column-start: 2;
|
||||
grid-column-end: 6;
|
||||
}
|
||||
|
||||
.cannot-use {
|
||||
color: var(--red);
|
||||
font-size: var(--font-size-s);
|
||||
text-align: center;
|
||||
width: 70%;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -42,8 +42,6 @@
|
|||
typeof tableInfo === "string" ? tableInfo : tableInfo.tableId
|
||||
}
|
||||
}
|
||||
|
||||
console.log(parameters)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<script>
|
||||
import { Select, Label, Spacer } from "@budibase/bbui"
|
||||
import { backendUiStore } from "builderStore"
|
||||
|
||||
export let parameters
|
||||
|
||||
$: datasource = $backendUiStore.datasources.find(
|
||||
ds => ds._id === parameters.datasourceId
|
||||
)
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
<Label size="m" color="dark">Datasource</Label>
|
||||
<Select secondary bind:value={parameters.datasourceId}>
|
||||
<option value="" />
|
||||
{#each $backendUiStore.datasources as datasource}
|
||||
<option value={datasource._id}>{datasource.name}</option>
|
||||
{/each}
|
||||
</Select>
|
||||
|
||||
<Spacer medium />
|
||||
|
||||
{#if parameters.datasourceId}
|
||||
<Label size="m" color="dark">Query</Label>
|
||||
<Select secondary bind:value={parameters.queryId}>
|
||||
<option value="" />
|
||||
{#each Object.keys(datasource.queries) as query}
|
||||
<option value={query}>{datasource.queries[query].name}</option>
|
||||
{/each}
|
||||
</Select>
|
||||
{/if}
|
||||
</div>
|
|
@ -1,6 +1,7 @@
|
|||
import NavigateTo from "./NavigateTo.svelte"
|
||||
import SaveRow from "./SaveRow.svelte"
|
||||
import DeleteRow from "./DeleteRow.svelte"
|
||||
import ExecuteQuery from "./ExecuteQuery.svelte"
|
||||
|
||||
// defines what actions are available, when adding a new one
|
||||
// the component is the setup panel for the action
|
||||
|
@ -20,4 +21,8 @@ export default [
|
|||
name: "Navigate To",
|
||||
component: NavigateTo,
|
||||
},
|
||||
{
|
||||
name: "Execute Query",
|
||||
component: ExecuteQuery,
|
||||
},
|
||||
]
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
<script>
|
||||
import { Switcher } from "@budibase/bbui"
|
||||
import { params } from "@sveltech/routify"
|
||||
import { Switcher, Modal } from "@budibase/bbui"
|
||||
import TableNavigator from "components/backend/TableNavigator/TableNavigator.svelte"
|
||||
import DatasourceNavigator from "components/backend/DatasourceNavigator/DatasourceNavigator.svelte"
|
||||
import CreateDatasourceModal from "components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte"
|
||||
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte"
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
|
@ -14,17 +17,31 @@
|
|||
},
|
||||
]
|
||||
|
||||
let tab = "table"
|
||||
let tab = $params.selectedDatasource ? "datasource" : "table"
|
||||
|
||||
let modal
|
||||
</script>
|
||||
|
||||
<!-- routify:options index=0 -->
|
||||
<div class="root">
|
||||
<div class="nav">
|
||||
<Switcher headings={tabs} bind:value={tab}>
|
||||
<div class="title">
|
||||
<i
|
||||
data-cy={`new-${tab}`}
|
||||
class="ri-add-circle-fill"
|
||||
on:click={modal.show} />
|
||||
</div>
|
||||
{#if tab === 'table'}
|
||||
<TableNavigator />
|
||||
<Modal bind:this={modal}>
|
||||
<CreateTableModal />
|
||||
</Modal>
|
||||
{:else if tab === 'datasource'}
|
||||
<DatasourceNavigator />
|
||||
<Modal bind:this={modal}>
|
||||
<CreateDatasourceModal />
|
||||
</Modal>
|
||||
{/if}
|
||||
</Switcher>
|
||||
</div>
|
||||
|
@ -40,6 +57,7 @@
|
|||
grid-template-columns: 260px minmax(0, 1fr);
|
||||
background: var(--grey-2);
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1 1 auto;
|
||||
padding: var(--spacing-l) 40px;
|
||||
|
@ -50,6 +68,7 @@
|
|||
align-items: stretch;
|
||||
gap: var(--spacing-l);
|
||||
}
|
||||
|
||||
.nav {
|
||||
overflow-y: auto;
|
||||
background: var(--background);
|
||||
|
@ -59,5 +78,18 @@
|
|||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
gap: var(--spacing-l);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 20px;
|
||||
position: absolute;
|
||||
top: var(--spacing-l);
|
||||
right: var(--spacing-xl);
|
||||
}
|
||||
|
||||
i:hover {
|
||||
cursor: pointer;
|
||||
color: var(--blue);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
$: query = datasource && datasource.queries[$params.query]
|
||||
</script>
|
||||
|
||||
{#if $backendUiStore.selectedDatabase._id && datasource}
|
||||
<ExternalDataSourceTable {query} datasourceId={datasource._id} />
|
||||
{#if $backendUiStore.selectedDatabase._id && datasource && query}
|
||||
<ExternalDataSourceTable {query} {datasource} />
|
||||
{/if}
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
margin-bottom: var(--spacing-s);
|
||||
}
|
||||
section {
|
||||
background: white;
|
||||
background: var(--background);
|
||||
border-radius: var(--border-radius-m);
|
||||
padding: var(--spacing-xl);
|
||||
}
|
||||
|
|
|
@ -9,3 +9,14 @@ export const fetchQueryData = async ({ datasourceId, queryId }) => {
|
|||
})
|
||||
return response.rows
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a query against an external data connector.
|
||||
*/
|
||||
export const executeQuery = async ({ datasourceId, queryId }) => {
|
||||
const response = await API.post({
|
||||
url: `/api/datasources/${datasourceId}/queries/${queryId}`,
|
||||
// body: params,
|
||||
})
|
||||
return response.rows
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { enrichDataBinding } from "./enrichDataBinding"
|
||||
import { enrichDataBinding, enrichDataBindings } from "./enrichDataBinding"
|
||||
import { routeStore } from "../store"
|
||||
import { saveRow, deleteRow } from "../api"
|
||||
import { saveRow, deleteRow, executeQuery } from "../api"
|
||||
|
||||
const saveRowHandler = async (action, context) => {
|
||||
let draft = context[`${action.parameters.contextPath}_draft`]
|
||||
|
@ -25,10 +25,27 @@ const navigationHandler = action => {
|
|||
routeStore.actions.navigate(action.parameters.url)
|
||||
}
|
||||
|
||||
const queryExecutionHandler = async (action, context) => {
|
||||
const { datasourceId, queryId, params } = action.parameters
|
||||
console.log(context)
|
||||
// TODO: allow context based bindings for query params
|
||||
// const enrichedQueryParameters = enrichDataBindings(params, context)
|
||||
|
||||
// console.log({
|
||||
// action,
|
||||
// context,
|
||||
// // enrichedQueryParameters,
|
||||
// datasourceId,
|
||||
// // queryId
|
||||
// })
|
||||
await executeQuery({ datasourceId, queryId })
|
||||
}
|
||||
|
||||
const handlerMap = {
|
||||
["Save Row"]: saveRowHandler,
|
||||
["Delete Row"]: deleteRowHandler,
|
||||
["Navigate To"]: navigationHandler,
|
||||
["Execute Query"]: queryExecutionHandler,
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -115,7 +115,7 @@ exports.previewQuery = async function(ctx) {
|
|||
ctx.body = await new Integration(config, query).query()
|
||||
}
|
||||
|
||||
exports.executeQuery = async function(ctx) {
|
||||
exports.fetchQuery = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
const datasource = await db.get(ctx.params.datasourceId)
|
||||
|
@ -139,3 +139,28 @@ exports.executeQuery = async function(ctx) {
|
|||
rows,
|
||||
}
|
||||
}
|
||||
|
||||
exports.executeQuery = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
const datasource = await db.get(ctx.params.datasourceId)
|
||||
|
||||
const query = datasource.queries[ctx.params.queryId]
|
||||
|
||||
const Integration = integrations[datasource.source]
|
||||
|
||||
if (!Integration) {
|
||||
ctx.throw(400, "Integration type does not exist.")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: allow the ability to POST parameters down when executing the query
|
||||
// const customParams = ctx.request.body
|
||||
|
||||
const response = await new Integration(
|
||||
datasource.config,
|
||||
query.queryString
|
||||
).query()
|
||||
|
||||
ctx.body = response
|
||||
}
|
||||
|
|
|
@ -28,6 +28,11 @@ router
|
|||
datasourceController.previewQuery
|
||||
)
|
||||
.get(
|
||||
"/api/datasources/:datasourceId/queries/:queryId",
|
||||
authorized(BUILDER),
|
||||
datasourceController.fetchQuery
|
||||
)
|
||||
.post(
|
||||
"/api/datasources/:datasourceId/queries/:queryId",
|
||||
authorized(BUILDER),
|
||||
datasourceController.executeQuery
|
||||
|
|
Loading…
Reference in New Issue