mirror of https://github.com/Budibase/budibase.git
17 changed files with 416 additions and 4 deletions
@ -0,0 +1,32 @@ |
|||
<script> |
|||
import { backendUiStore } from "builderStore" |
|||
import * as api from "./api" |
|||
import Table from "./Table.svelte" |
|||
import EditIntegrationConfigButton from "./buttons/EditIntegrationConfigButton.svelte" |
|||
|
|||
let data = [] |
|||
let loading = false |
|||
|
|||
$: table = $backendUiStore.selectedTable |
|||
$: title = table.name |
|||
$: schema = table.schema |
|||
$: tableView = { |
|||
schema, |
|||
name: $backendUiStore.selectedView.name, |
|||
} |
|||
|
|||
// Fetch rows for specified table |
|||
$: { |
|||
if ($backendUiStore.selectedView?.name?.startsWith("all_")) { |
|||
loading = true |
|||
api.fetchDataForView($backendUiStore.selectedView).then(rows => { |
|||
data = rows || [] |
|||
loading = false |
|||
}) |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<Table {title} {schema} {data} allowEditing={true} {loading}> |
|||
<EditIntegrationConfigButton {table} /> |
|||
</Table> |
|||
@ -0,0 +1,43 @@ |
|||
<script> |
|||
import { |
|||
DropdownMenu, |
|||
TextButton as Button, |
|||
Icon, |
|||
Modal, |
|||
ModalContent, |
|||
} from "@budibase/bbui" |
|||
import { backendUiStore } from "builderStore" |
|||
import api from "builderStore/api" |
|||
import EditIntegrationConfig from "../modals/EditIntegrationConfig.svelte" |
|||
|
|||
export let table |
|||
|
|||
$: console.log("The table config is", table) |
|||
|
|||
let modal |
|||
|
|||
// TODO: revisit |
|||
async function saveTable() { |
|||
const SAVE_TABLE_URL = `/api/tables` |
|||
const response = await api.post(SAVE_TABLE_URL, table) |
|||
const savedTable = await response.json() |
|||
await backendUiStore.actions.tables.fetch() |
|||
backendUiStore.actions.tables.select(savedTable) |
|||
} |
|||
</script> |
|||
|
|||
<div> |
|||
<Button text small on:click={modal.show}> |
|||
<Icon name="edit" /> |
|||
Configure Datasource |
|||
</Button> |
|||
</div> |
|||
<Modal bind:this={modal}> |
|||
<ModalContent |
|||
confirmText="Save" |
|||
cancelText="Cancel" |
|||
onConfirm={saveTable} |
|||
title={'Edit Datasource Configuration'}> |
|||
<EditIntegrationConfig onClosed={modal.hide} bind:table /> |
|||
</ModalContent> |
|||
</Modal> |
|||
@ -0,0 +1,69 @@ |
|||
<script> |
|||
import { Select, Button, Input, TextArea, Heading } from "@budibase/bbui" |
|||
import { FIELDS } from "constants/backend" |
|||
import { backendUiStore } from "builderStore" |
|||
|
|||
export let table |
|||
|
|||
let fields = [] |
|||
|
|||
$: { |
|||
const schema = {} |
|||
for (let field of fields) { |
|||
if (!field.name) continue |
|||
schema[field.name] = FIELDS[field.type] |
|||
} |
|||
table.schema = schema |
|||
} |
|||
|
|||
function newField() { |
|||
fields = [...fields, {}] |
|||
} |
|||
|
|||
function deleteField(idx) { |
|||
fields.splice(idx, 1) |
|||
fields = fields |
|||
} |
|||
</script> |
|||
|
|||
<form> |
|||
<Heading extraSmall black>Schema</Heading> |
|||
<!-- {#each Object.keys(table.schema) as schemaKey, idx} |
|||
<Input |
|||
thin |
|||
type={'text'} |
|||
label={schemaKey} |
|||
bind:value={table.schema[schemaKey]} /> |
|||
{/each} --> |
|||
{#each fields as field} |
|||
<div class="field"> |
|||
<Input thin type={'text'} bind:value={field.name} /> |
|||
<Select secondary thin bind:value={field.type}> |
|||
<option value={''}>Select an option</option> |
|||
<option value={'STRING'}>Text</option> |
|||
<option value={'NUMBER'}>Number</option> |
|||
<option value={'BOOLEAN'}>Boolean</option> |
|||
<option value={'DATETIME'}>Datetime</option> |
|||
</Select> |
|||
</div> |
|||
{/each} |
|||
|
|||
<Button thin secondary on:click={newField}>Add Field</Button> |
|||
<Heading extraSmall black>Datasource</Heading> |
|||
{#each Object.keys(table.integration) as configKey} |
|||
<Input |
|||
thin |
|||
type={configKey.type} |
|||
label={configKey} |
|||
bind:value={table.integration[configKey]} /> |
|||
{/each} |
|||
</form> |
|||
|
|||
<style> |
|||
.field { |
|||
display: grid; |
|||
grid-gap: 10px; |
|||
grid-template-columns: 1fr 1fr; |
|||
margin-bottom: var(--spacing-xs); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,15 @@ |
|||
<script> |
|||
import { Input, TextArea } from "@budibase/bbui" |
|||
|
|||
export let integration |
|||
</script> |
|||
|
|||
<form> |
|||
{#each Object.keys(integration) as configKey} |
|||
<Input |
|||
thin |
|||
type={configKey.type} |
|||
label={configKey} |
|||
bind:value={integration[configKey]} /> |
|||
{/each} |
|||
</form> |
|||
@ -0,0 +1,52 @@ |
|||
<script> |
|||
import { onMount } from "svelte" |
|||
import { Input, TextArea } from "@budibase/bbui" |
|||
import api from "builderStore/api" |
|||
|
|||
export let integration = {} |
|||
|
|||
let integrationsPromise = fetchIntegrations() |
|||
let selectedIntegration |
|||
|
|||
async function fetchIntegrations() { |
|||
const INTEGRATIONS_URL = `/api/integrations` |
|||
const response = await api.get(INTEGRATIONS_URL) |
|||
const json = await response.json() |
|||
return json |
|||
} |
|||
</script> |
|||
|
|||
<section> |
|||
{#await integrationsPromise} |
|||
Loading integrations... |
|||
{:then integrations} |
|||
{#each Object.keys(integrations) as integrationType} |
|||
<div |
|||
on:click={() => { |
|||
selectedIntegration = integrations[integrationType] |
|||
integration.type = integrationType |
|||
}}> |
|||
<h6>{integrationType}</h6> |
|||
</div> |
|||
{/each} |
|||
{:catch} |
|||
shit itself |
|||
{/await} |
|||
|
|||
{#if selectedIntegration} |
|||
{#each Object.keys(selectedIntegration) as configKey} |
|||
<Input |
|||
thin |
|||
type={configKey.type} |
|||
label={configKey} |
|||
bind:value={integration[configKey]} /> |
|||
{/each} |
|||
<TextArea label={'Query'} bind:value={integration.query} /> |
|||
{/if} |
|||
</section> |
|||
|
|||
<style> |
|||
section { |
|||
display: grid; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,8 @@ |
|||
const { definitions } = require("../../integrations") |
|||
|
|||
exports.fetch = async function(ctx) { |
|||
// TODO: fetch these from a github repo etc
|
|||
console.log(definitions) |
|||
ctx.status = 200 |
|||
ctx.body = definitions |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/integration") |
|||
const authorized = require("../../middleware/authorized") |
|||
const { BUILDER } = require("../../utilities/security/permissions") |
|||
|
|||
const router = Router() |
|||
|
|||
router.get("/api/integrations", authorized(BUILDER), controller.fetch) |
|||
|
|||
module.exports = router |
|||
@ -0,0 +1,7 @@ |
|||
class Integration { |
|||
definition() { |
|||
return this.options |
|||
} |
|||
} |
|||
|
|||
module.exports = Integration |
|||
@ -0,0 +1,14 @@ |
|||
const postgres = require("./postgres") |
|||
|
|||
const DEFINITIONS = { |
|||
POSTGRES: postgres.schema, |
|||
} |
|||
|
|||
const INTEGRATIONS = { |
|||
POSTGRES: postgres.integration, |
|||
} |
|||
|
|||
module.exports = { |
|||
definitions: DEFINITIONS, |
|||
integrations: INTEGRATIONS, |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
const { Client } = require("pg") |
|||
|
|||
const POSTGRES_OPTIONS = { |
|||
host: { |
|||
type: "string", |
|||
required: true, |
|||
default: "localhost", |
|||
}, |
|||
port: { |
|||
type: "number", |
|||
required: true, |
|||
default: 5432, |
|||
}, |
|||
database: { |
|||
type: "string", |
|||
default: "postgres", |
|||
}, |
|||
username: { |
|||
type: "string", |
|||
default: "root", |
|||
}, |
|||
password: { |
|||
type: "password", |
|||
default: "root", |
|||
}, |
|||
} |
|||
|
|||
class PostgresIntegration { |
|||
constructor(config) { |
|||
this.config = config |
|||
this.client = new Client(config) |
|||
this.connect() |
|||
} |
|||
|
|||
async connect() { |
|||
return this.client.connect() |
|||
} |
|||
|
|||
async query() { |
|||
const response = await this.client.query(this.config.query) |
|||
return response.rows |
|||
} |
|||
} |
|||
|
|||
module.exports = { |
|||
schema: POSTGRES_OPTIONS, |
|||
integration: PostgresIntegration, |
|||
} |
|||
Loading…
Reference in new issue