design updates, changing query verb names to HTTP verbs

This commit is contained in:
Martin McKeaveney 2021-02-18 16:58:10 +00:00
parent 6dfc4a4de5
commit d99e1a5a53
25 changed files with 224 additions and 189 deletions

View File

@ -30,7 +30,9 @@
<div class="popover"> <div class="popover">
<h5>Who Can Access This Data?</h5> <h5>Who Can Access This Data?</h5>
<div class="note"> <div class="note">
<Label extraSmall grey>Specify the minimum access level role for this data.</Label> <Label extraSmall grey>
Specify the minimum access level role for this data.
</Label>
</div> </div>
<Spacer large /> <Spacer large />
<div class="row"> <div class="row">

View File

@ -1,15 +1,33 @@
<script> <script>
import { Input, TextArea, Spacer } from "@budibase/bbui" import { Label, Input, TextArea, Spacer } from "@budibase/bbui"
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
export let integration export let integration
</script> </script>
<form> <form>
{#each Object.keys(integration) as configKey} {#each Object.keys(integration) as configKey}
<Input <div class="form-row">
type={integration[configKey].type} {#if typeof integration[configKey] === 'object'}
label={configKey} <Label small>{configKey}</Label>
bind:value={integration[configKey]} /> <KeyValueBuilder bind:object={integration[configKey]} />
<Spacer large /> {:else}
<Label small>{configKey}</Label>
<Input
outline
type={integration[configKey].type}
bind:value={integration[configKey]} />
{/if}
</div>
{/each} {/each}
</form> </form>
<style>
.form-row {
display: grid;
grid-template-columns: 20% 1fr;
grid-gap: var(--spacing-l);
align-items: center;
margin-bottom: var(--spacing-m);
}
</style>

View File

@ -2,7 +2,8 @@
import { onMount } from "svelte" import { onMount } from "svelte"
import { backendUiStore } from "builderStore" import { backendUiStore } from "builderStore"
import api from "builderStore/api" import api from "builderStore/api"
import { Input, TextArea, Spacer } from "@budibase/bbui" import { Input, Label, TextArea, Spacer } from "@budibase/bbui"
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
import ICONS from "../icons" import ICONS from "../icons"
export let integration = {} export let integration = {}
@ -50,16 +51,21 @@
{/each} {/each}
</div> </div>
{#if schema} <!-- {#if schema}
{#each Object.keys(schema) as configKey} {#each Object.keys(schema) as configKey}
<Input {#if schema[configKey].type === 'object'}
thin <Label small>{configKey}</Label>
type={schema[configKey].type} <KeyValueBuilder bind:object={integration[configKey]} />
label={configKey} {:else}
bind:value={integration[configKey]} /> <Label small>{configKey}</Label>
<Input
outline
type={integration[configKey].type}
bind:value={integration[configKey]} />
{/if}
<Spacer medium /> <Spacer medium />
{/each} {/each}
{/if} {/if} -->
</section> </section>
<style> <style>

View File

@ -1,61 +0,0 @@
<script>
import { goto, params } from "@sveltech/routify"
import { backendUiStore, store } from "builderStore"
import { notifier } from "builderStore/store/notifications"
import { Input, Label, ModalContent, Button, Spacer } from "@budibase/bbui"
import TableIntegrationMenu from "../TableIntegrationMenu/index.svelte"
import analytics from "analytics"
let modal
let error = ""
let name
let source
let integration
let datasource
function checkValid(evt) {
const datasourceName = evt.target.value
if (
$backendUiStore.datasources?.some(
datasource => datasource.name === datasourceName
)
) {
error = `Datasource with name ${tableName} already exists. Please choose another name.`
return
}
error = ""
}
async function saveDatasource() {
const { type, ...config } = integration
// Create datasource
await backendUiStore.actions.datasources.save({
name,
source: type,
config,
})
notifier.success(`Datasource ${name} created successfully.`)
analytics.captureEvent("Datasource Created", { name })
// Navigate to new datasource
$goto(`./datasource/${datasource._id}`)
}
</script>
<ModalContent
title="Create Datasource"
confirmText="Create"
onConfirm={saveDatasource}
disabled={error || !name}>
<Input
data-cy="datasource-name-input"
thin
label="Datasource Name"
on:input={checkValid}
bind:value={name}
{error} />
<Label grey extraSmall>Create Integrated Table from External Source</Label>
<TableIntegrationMenu bind:integration />
</ModalContent>

View File

@ -3,7 +3,6 @@
import { notifier } from "builderStore/store/notifications" import { notifier } from "builderStore/store/notifications"
import { DropdownMenu, Button, Input } from "@budibase/bbui" import { DropdownMenu, Button, Input } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import IntegrationConfigForm from "../TableIntegrationMenu//IntegrationConfigForm.svelte"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
export let datasource export let datasource

View File

@ -1,4 +1,4 @@
<script> <!--<script>
import { backendUiStore, store, allScreens } from "builderStore" import { backendUiStore, store, allScreens } from "builderStore"
import { notifier } from "builderStore/store/notifications" import { notifier } from "builderStore/store/notifications"
import { DropdownMenu, Button, Input, TextButton, Icon } from "@budibase/bbui" import { DropdownMenu, Button, Input, TextButton, Icon } from "@budibase/bbui"
@ -17,9 +17,7 @@
function hideEditor() { function hideEditor() {
dropdown?.hide() dropdown?.hide()
} }
</script> </script><div on:click|stopPropagation bind:this={anchor}>
<div on:click|stopPropagation bind:this={anchor}>
<TextButton text on:click={dropdown.show} active={false}> <TextButton text on:click={dropdown.show} active={false}>
<Icon name="add" /> <Icon name="add" />
Add Parameters Add Parameters
@ -29,11 +27,9 @@
<ParameterBuilder bind:parameters {bindable} /> <ParameterBuilder bind:parameters {bindable} />
</div> </div>
</DropdownMenu> </DropdownMenu>
</div> </div><style>
<style>
.wrapper { .wrapper {
padding: var(--spacing-xl); padding: var(--spacing-xl);
min-width: 600px; min-width: 600px;
} }
</style> </style>-->

View File

@ -3,7 +3,6 @@
import { notifier } from "builderStore/store/notifications" import { notifier } from "builderStore/store/notifications"
import { DropdownMenu, Button, Input } from "@budibase/bbui" import { DropdownMenu, Button, Input } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import IntegrationConfigForm from "../TableIntegrationMenu//IntegrationConfigForm.svelte"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
export let query export let query

View File

@ -3,7 +3,7 @@
export let object = {} export let object = {}
let fields = [] let fields = Object.entries(object).map(([name, value]) => ({ name, value }))
$: object = fields.reduce( $: object = fields.reduce(
(acc, next) => ({ ...acc, [next.name]: next.value }), (acc, next) => ({ ...acc, [next.name]: next.value }),

View File

@ -22,35 +22,36 @@
function updateCustomFields({ detail }) { function updateCustomFields({ detail }) {
fields.customData = detail.value fields.customData = detail.value
} }
</script> </script>
<form on:submit|preventDefault> <form on:submit|preventDefault>
<div class="field"> <div class="field">
{#each schemaKeys as field} {#each schemaKeys as field}
{#if schema.fields[field]?.type === "object"} {#if schema.fields[field]?.type === 'object'}
<div> <div>
<Label extraSmall grey>{field}</Label> <Label extraSmall grey>{field}</Label>
<KeyValueBuilder bind:object={fields[field]} /> <KeyValueBuilder bind:object={fields[field]} />
</div> </div>
{:else if schema.fields[field]?.type === "json"} {:else if schema.fields[field]?.type === 'json'}
<div> <div>
<Label extraSmall grey>{field}</Label> <Label extraSmall grey>{field}</Label>
<Editor <Editor
mode="json" mode="json"
on:change={({ detail }) => fields[field] = detail.value} on:change={({ detail }) => (fields[field] = detail.value)}
readOnly={!editable} readOnly={!editable}
value={fields[field]} /> value={fields[field]} />
</div> </div>
{:else} {:else}
<Input <div class="horizontal">
label={field} <Label small>{field}</Label>
placeholder="Enter {field} name" <Input
outline placeholder="Enter {field} name"
disabled={!editable} outline
type={schema.fields[field]?.type} disabled={!editable}
required={schema.fields[field]?.required} type={schema.fields[field]?.type}
bind:value={fields[field]} /> required={schema.fields[field]?.required}
bind:value={fields[field]} />
</div>
{/if} {/if}
{/each} {/each}
</div> </div>
@ -73,4 +74,10 @@
align-items: center; align-items: center;
} }
.horizontal {
display: grid;
grid-template-columns: 20% 1fr;
grid-gap: var(--spacing-l);
align-items: center;
}
</style> </style>

View File

@ -1,5 +1,5 @@
<script> <script>
import { Button, Input, Heading, Spacer } from "@budibase/bbui" import { Body, Button, Input, Heading, Spacer } from "@budibase/bbui"
import BindableInput from "components/common/BindableInput.svelte" import BindableInput from "components/common/BindableInput.svelte"
import { import {
readableToRuntimeBinding, readableToRuntimeBinding,
@ -30,7 +30,16 @@
</script> </script>
<section> <section>
<Heading extraSmall black>Parameters</Heading> <div class="controls">
<Heading small>Parameters</Heading>
{#if !bindable}
<Button secondary on:click={newQueryParameter}>Add Param</Button>
{/if}
</div>
<Body small grey>
Parameters come in two parts: the parameter name, and a default/fallback
value.
</Body>
<Spacer large /> <Spacer large />
<div class="parameters" class:bindable> <div class="parameters" class:bindable>
{#each parameters as parameter, idx} {#each parameters as parameter, idx}
@ -59,9 +68,6 @@
{/if} {/if}
{/each} {/each}
</div> </div>
{#if !bindable}
<Button secondary on:click={newQueryParameter}>Add Parameter</Button>
{/if}
</section> </section>
<style> <style>
@ -69,6 +75,11 @@
grid-template-columns: 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr;
} }
.controls {
display: flex;
justify-content: space-between;
}
.parameters { .parameters {
display: grid; display: grid;
grid-template-columns: 1fr 1fr 5%; grid-template-columns: 1fr 1fr 5%;

View File

@ -4,6 +4,7 @@
import { import {
Select, Select,
Button, Button,
Body,
Label, Label,
Input, Input,
TextArea, TextArea,
@ -16,7 +17,7 @@
import { FIELDS } from "constants/backend" import { FIELDS } from "constants/backend"
import IntegrationQueryEditor from "components/integration/index.svelte" import IntegrationQueryEditor from "components/integration/index.svelte"
import ExternalDataSourceTable from "components/backend/DataTable/ExternalDataSourceTable.svelte" import ExternalDataSourceTable from "components/backend/DataTable/ExternalDataSourceTable.svelte"
import EditQueryParamsPopover from "components/backend/DatasourceNavigator/popovers/EditQueryParamsPopover.svelte" import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte"
import { backendUiStore } from "builderStore" import { backendUiStore } from "builderStore"
const PREVIEW_HEADINGS = [ const PREVIEW_HEADINGS = [
@ -60,8 +61,8 @@
$: datasourceType = datasource?.source $: datasourceType = datasource?.source
$: config = $backendUiStore.integrations[datasourceType]?.query $: integrationInfo = $backendUiStore.integrations[datasourceType]
$: docsLink = $backendUiStore.integrations[datasourceType]?.docs $: queryConfig = integrationInfo?.query
$: shouldShowQueryConfig = config && query.queryVerb $: shouldShowQueryConfig = config && query.queryVerb
@ -130,63 +131,99 @@
} }
</script> </script>
<header> <section class="config">
<div class="input"> <Heading medium>Query {integrationInfo.friendlyName}</Heading>
<hr />
<Spacer medium />
<Heading small>Config</Heading>
<Spacer medium />
<Body small grey>Provide a name for your query and select its function.</Body>
<Spacer medium />
<div class="config-field">
<Label small>Query Name</Label>
<Input thin bind:value={query.name} />
</div>
<Spacer medium />
{#if queryConfig}
<div class="config-field">
<Label small>Function</Label>
<Select primary outline thin bind:value={query.queryVerb}>
{#each Object.keys(queryConfig) as queryVerb}
<option value={queryVerb}>{queryConfig[queryVerb]?.displayName || queryVerb}</option>
{/each}
</Select>
</div>
<Spacer medium />
<hr />
<ParameterBuilder bind:parameters={query.parameters} bindable={false} />
<hr />
{/if}
<!-- <div class="input">
<div class="label">Enter query name:</div> <div class="label">Enter query name:</div>
<Input outline border bind:value={query.name} /> <Input outline border bind:value={query.name} />
</div> </div> -->
{#if config} <!-- {#if config} -->
<div class="props"> <!-- <div class="props"> -->
<div class="query-type"> <!-- <div class="query-type">
Query type: Query type:
<span class="query-type-span">{config[query.queryVerb].type}</span> <span class="query-type-span">{config[query.queryVerb].type}</span>
</div> </div> -->
<div class="select"> <!-- <div class="select">
<Select primary thin bind:value={query.queryVerb}> <Select primary thin bind:value={query.queryVerb}>
{#each Object.keys(config) as queryVerb} {#each Object.keys(config) as queryVerb}
<option value={queryVerb}>{queryVerb}</option> <option value={queryVerb}>{queryVerb}</option>
{/each} {/each}
</Select> </Select>
</div> </div> -->
</div> <!-- </div>
<EditQueryParamsPopover <EditQueryParamsPopover
bind:parameters={query.parameters} bind:parameters={query.parameters}
bindable={false} /> bindable={false} /> -->
{/if} <!-- {/if} -->
</header> </section>
<Spacer extraLarge /> <Spacer large />
{#if shouldShowQueryConfig} {#if shouldShowQueryConfig}
<section> <section>
<div class="config"> <div class="config">
<Heading small>Fields</Heading>
<Spacer medium />
<IntegrationQueryEditor <IntegrationQueryEditor
{query} {query}
schema={config[query.queryVerb]} schema={config[query.queryVerb]}
bind:parameters /> bind:parameters />
<Spacer extraLarge /> <Spacer medium />
<Spacer large /> <hr />
<Spacer medium />
<div class="viewer-controls"> <div class="viewer-controls">
<Heading small>Query Results</Heading>
<Button <Button
blue secondary
thin
disabled={data.length === 0 || !query.name} disabled={data.length === 0 || !query.name}
on:click={saveQuery}> on:click={saveQuery}>
Save Query Save Query
</Button> </Button>
<Button primary on:click={previewQuery}>Run Query</Button> <Button thin primary on:click={previewQuery}>Run Query</Button>
</div> </div>
<Body small grey>
Below, you can preview the results from your query and change the
schema.
</Body>
<section class="viewer"> <section class="viewer">
{#if data} {#if data}
<Switcher headings={PREVIEW_HEADINGS} bind:value={tab}> <Switcher headings={PREVIEW_HEADINGS} bind:value={tab}>
{#if tab === 'JSON'} {#if tab === 'JSON'}
<pre class="preview"> <pre class="preview">
{#if !data[0]} {#if !data[0]}
Please run your query to fetch some data. Please run your query to fetch some data.
{:else}
{JSON.stringify(data[0], undefined, 2)} {:else}
{/if} {JSON.stringify(data[0], undefined, 2)}
{/if}
</pre> </pre>
{:else if tab === 'PREVIEW'} {:else if tab === 'PREVIEW'}
<ExternalDataSourceTable {query} {data} /> <ExternalDataSourceTable {query} {data} />
@ -222,28 +259,16 @@
{/if} {/if}
<style> <style>
.input { .config-field {
width: 500px; display: grid;
display: flex; grid-template-columns: 20% 1fr;
grid-gap: var(--spacing-l);
align-items: center; align-items: center;
} }
.select {
width: 200px;
margin-right: 40px;
}
.props {
display: flex;
flex-direction: row;
margin-left: auto;
align-items: center;
gap: var(--layout-l);
}
.field { .field {
display: grid; display: grid;
grid-template-columns: 1fr 1fr 50px; grid-template-columns: 1fr 1fr 5%;
gap: var(--spacing-l); gap: var(--spacing-l);
} }
@ -260,12 +285,6 @@
cursor: pointer; cursor: pointer;
} }
.query-type {
font-family: var(--font-sans);
color: var(--grey-8);
font-size: var(--font-size-s);
}
.query-type-span { .query-type-span {
text-transform: uppercase; text-transform: uppercase;
} }
@ -278,31 +297,18 @@
white-space: pre-wrap; white-space: pre-wrap;
} }
header {
display: flex;
align-items: center;
}
.viewer-controls { .viewer-controls {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
margin-left: auto; /* margin-left: auto; */
direction: rtl; /* direction: rtl; */
z-index: 5; /* z-index: 5; */
gap: var(--spacing-m); gap: var(--spacing-m);
min-width: 150px; min-width: 150px;
} }
.viewer { .viewer {
margin-top: -28px; /* margin-top: -28px; */
z-index: -2; /* z-index: -2; */
}
.label {
font-family: var(--font-sans);
color: var(--grey-8);
font-size: var(--font-size-s);
margin-right: 8px;
font-weight: 600;
} }
</style> </style>

View File

@ -8,11 +8,11 @@
const tabs = [ const tabs = [
{ {
title: "Tables", title: "Internal",
key: "table", key: "table",
}, },
{ {
title: "Data Sources", title: "External",
key: "datasource", key: "datasource",
}, },
] ]
@ -67,6 +67,7 @@
justify-content: flex-start; justify-content: flex-start;
align-items: stretch; align-items: stretch;
gap: var(--spacing-l); gap: var(--spacing-l);
background: var(--background);
} }
.nav { .nav {

View File

@ -36,6 +36,8 @@
<style> <style>
section { section {
overflow: scroll; overflow: scroll;
width: 800px;
margin: 0 auto;
} }
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 0px; width: 0px;

View File

@ -1,9 +1,10 @@
<script> <script>
import { goto } from "@sveltech/routify" import { goto } from "@sveltech/routify"
import { Button, Spacer, Icon } from "@budibase/bbui" import { Button, Heading, Body, Spacer, Icon } from "@budibase/bbui"
import { backendUiStore } from "builderStore" import { backendUiStore } from "builderStore"
import { notifier } from "builderStore/store/notifications" import { notifier } from "builderStore/store/notifications"
import IntegrationConfigForm from "components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte" import IntegrationConfigForm from "components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte"
import ICONS from "components/backend/DatasourceNavigator/icons"
$: datasource = $backendUiStore.datasources.find( $: datasource = $backendUiStore.datasources.find(
ds => ds._id === $backendUiStore.selectedDatasourceId ds => ds._id === $backendUiStore.selectedDatasourceId
@ -28,22 +29,35 @@
<section> <section>
<Spacer medium /> <Spacer medium />
<header> <header>
<div class="datasource-icon">
<svelte:component
this={ICONS[datasource.source]}
height="30"
width="30" />
</div>
<h3 class="section-title">{datasource.name}</h3> <h3 class="section-title">{datasource.name}</h3>
</header> </header>
<Spacer extraLarge /> <Spacer extraLarge />
<div class="container"> <div class="container">
<div class="config-header"> <div class="config-header">
<h5>Configuration</h5> <Heading small>Configuration</Heading>
<Button secondary on:click={saveDatasource}>Save</Button> <Button secondary on:click={saveDatasource}>Save</Button>
</div> </div>
<Body small grey>
Connect your database to Budibase using the config below.
</Body>
<Spacer medium /> <Spacer medium />
<IntegrationConfigForm integration={datasource.config} /> <IntegrationConfigForm integration={datasource.config} />
</div>
<Spacer extraLarge /> <hr />
<div class="container">
<Spacer extraLarge />
<div class="query-header"> <div class="query-header">
<h5>Queries</h5> <Heading small>Queries</Heading>
<Button blue on:click={() => $goto('../new')}>Create Query</Button> <Button secondary on:click={() => $goto('../new')}>Add Query</Button>
</div> </div>
<Spacer extraLarge /> <Spacer extraLarge />
<div class="query-list"> <div class="query-list">
@ -54,7 +68,6 @@
<p></p> <p></p>
</div> </div>
{/each} {/each}
<Spacer medium />
</div> </div>
</div> </div>
</section> </section>
@ -71,6 +84,8 @@
header { header {
margin: 0 0 var(--spacing-xs) 0; margin: 0 0 var(--spacing-xs) 0;
display: flex;
gap: var(--spacing-m);
} }
.section-title { .section-title {
@ -85,13 +100,12 @@
.container { .container {
border-radius: var(--border-radius-m); border-radius: var(--border-radius-m);
background: var(--background);
padding: var(--layout-s);
margin: 0 auto; margin: 0 auto;
} }
h5 { h5 {
margin: 0 !important; margin: 0 !important;
font-size: var(--font-size-l);
} }
.query-header { .query-header {
@ -115,7 +129,8 @@
display: grid; display: grid;
grid-template-columns: 2fr 0.75fr 20px; grid-template-columns: 2fr 0.75fr 20px;
align-items: center; align-items: center;
padding: var(--spacing-m) var(--layout-xs); padding-left: var(--spacing-m);
padding-right: var(--spacing-m);
gap: var(--layout-xs); gap: var(--layout-xs);
transition: 200ms background ease; transition: 200ms background ease;
} }

View File

@ -3,6 +3,7 @@ const { FIELD_TYPES, QUERY_TYPES } = require("./Integration")
const SCHEMA = { const SCHEMA = {
docs: "https://airtable.com/api", docs: "https://airtable.com/api",
friendlyName: "Airtable",
datasource: { datasource: {
apiKey: { apiKey: {
type: FIELD_TYPES.STRING, type: FIELD_TYPES.STRING,

View File

@ -3,6 +3,7 @@ const { FIELD_TYPES, QUERY_TYPES } = require("./Integration")
const SCHEMA = { const SCHEMA = {
docs: "https://github.com/arangodb/arangojs", docs: "https://github.com/arangodb/arangojs",
friendlyName: "ArangoDB",
datasource: { datasource: {
url: { url: {
type: FIELD_TYPES.STRING, type: FIELD_TYPES.STRING,

View File

@ -3,6 +3,7 @@ const { FIELD_TYPES, QUERY_TYPES } = require("./Integration")
const SCHEMA = { const SCHEMA = {
docs: "https://docs.couchdb.org/en/stable/", docs: "https://docs.couchdb.org/en/stable/",
friendlyName: "CouchDB",
datasource: { datasource: {
url: { url: {
type: FIELD_TYPES.STRING, type: FIELD_TYPES.STRING,

View File

@ -3,6 +3,7 @@ const { FIELD_TYPES, QUERY_TYPES } = require("./Integration")
const SCHEMA = { const SCHEMA = {
docs: "https://github.com/dabit3/dynamodb-documentclient-cheat-sheet", docs: "https://github.com/dabit3/dynamodb-documentclient-cheat-sheet",
friendlyName: "DynamoDB",
datasource: { datasource: {
region: { region: {
type: FIELD_TYPES.STRING, type: FIELD_TYPES.STRING,

View File

@ -4,6 +4,7 @@ const { QUERY_TYPES, FIELD_TYPES } = require("./Integration")
const SCHEMA = { const SCHEMA = {
docs: docs:
"https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/index.html", "https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/index.html",
friendlyName: "ElasticSearch",
datasource: { datasource: {
url: { url: {
type: "string", type: "string",

View File

@ -3,6 +3,7 @@ const { FIELD_TYPES } = require("./Integration")
const SCHEMA = { const SCHEMA = {
docs: "https://github.com/tediousjs/node-mssql", docs: "https://github.com/tediousjs/node-mssql",
friendlyName: "MS SQL Server",
datasource: { datasource: {
user: { user: {
type: FIELD_TYPES.STRING, type: FIELD_TYPES.STRING,

View File

@ -3,6 +3,9 @@ const { FIELD_TYPES, QUERY_TYPES } = require("./Integration")
const SCHEMA = { const SCHEMA = {
docs: "https://github.com/mongodb/node-mongodb-native", docs: "https://github.com/mongodb/node-mongodb-native",
friendlyName: "MongoDB",
description:
"MongoDB is a general purpose, document-based, distributed database built for modern application developers and for the cloud era.",
datasource: { datasource: {
connectionString: { connectionString: {
type: FIELD_TYPES.STRING, type: FIELD_TYPES.STRING,

View File

@ -3,6 +3,7 @@ const { FIELD_TYPES, QUERY_TYPES } = require("./Integration")
const SCHEMA = { const SCHEMA = {
docs: "https://github.com/mysqljs/mysql", docs: "https://github.com/mysqljs/mysql",
friendlyName: "MySQL",
datasource: { datasource: {
host: { host: {
type: FIELD_TYPES.STRING, type: FIELD_TYPES.STRING,

View File

@ -2,6 +2,7 @@ const { Client } = require("pg")
const SCHEMA = { const SCHEMA = {
docs: "https://node-postgres.com", docs: "https://node-postgres.com",
friendlyName: "PostgreSQL",
datasource: { datasource: {
host: { host: {
type: "string", type: "string",

View File

@ -3,15 +3,22 @@ const { FIELD_TYPES, QUERY_TYPES } = require("./Integration")
const SCHEMA = { const SCHEMA = {
docs: "https://github.com/node-fetch/node-fetch", docs: "https://github.com/node-fetch/node-fetch",
friendlyName: "REST API",
datasource: { datasource: {
url: { url: {
type: FIELD_TYPES.STRING, type: FIELD_TYPES.STRING,
default: "localhost", default: "localhost",
required: true, required: true,
}, },
defaultHeaders: {
type: FIELD_TYPES.OBJECT,
required: false,
default: {},
},
}, },
query: { query: {
create: { create: {
displayName: "POST",
type: QUERY_TYPES.FIELDS, type: QUERY_TYPES.FIELDS,
fields: { fields: {
path: { path: {
@ -26,6 +33,7 @@ const SCHEMA = {
}, },
}, },
read: { read: {
displayName: "GET",
type: QUERY_TYPES.FIELDS, type: QUERY_TYPES.FIELDS,
fields: { fields: {
path: { path: {
@ -37,6 +45,7 @@ const SCHEMA = {
}, },
}, },
update: { update: {
displayName: "PUT",
type: QUERY_TYPES.FIELDS, type: QUERY_TYPES.FIELDS,
fields: { fields: {
path: { path: {
@ -51,6 +60,7 @@ const SCHEMA = {
}, },
}, },
delete: { delete: {
displayName: "DELETE",
type: QUERY_TYPES.FIELDS, type: QUERY_TYPES.FIELDS,
fields: { fields: {
path: { path: {
@ -75,7 +85,10 @@ class RestIntegration {
async create({ path, headers = {}, json }) { async create({ path, headers = {}, json }) {
const response = await fetch(this.config.url + path, { const response = await fetch(this.config.url + path, {
method: "POST", method: "POST",
headers, headers: {
...this.config.defaultHeaders,
...headers,
},
body: JSON.stringify(json), body: JSON.stringify(json),
}) })
@ -84,7 +97,10 @@ class RestIntegration {
async read({ path, headers = {} }) { async read({ path, headers = {} }) {
const response = await fetch(this.config.url + path, { const response = await fetch(this.config.url + path, {
headers, headers: {
...this.config.defaultHeaders,
...headers,
},
}) })
return await response.json() return await response.json()
@ -93,7 +109,10 @@ class RestIntegration {
async update({ path, headers = {}, json }) { async update({ path, headers = {}, json }) {
const response = await fetch(this.config.url + path, { const response = await fetch(this.config.url + path, {
method: "POST", method: "POST",
headers, headers: {
...this.config.defaultHeaders,
...headers,
},
body: JSON.stringify(json), body: JSON.stringify(json),
}) })
@ -103,7 +122,10 @@ class RestIntegration {
async delete({ path, headers = {} }) { async delete({ path, headers = {} }) {
const response = await fetch(this.config.url + path, { const response = await fetch(this.config.url + path, {
method: "DELETE", method: "DELETE",
headers, headers: {
...this.config.defaultHeaders,
...headers,
},
}) })
return await response.json() return await response.json()

View File

@ -2,6 +2,7 @@ const AWS = require("aws-sdk")
const SCHEMA = { const SCHEMA = {
docs: "https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html", docs: "https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html",
friendlyName: "Amazon S3",
datasource: { datasource: {
region: { region: {
type: "string", type: "string",