forked from tsai/budibase
committed by
GitHub
14 changed files with 347 additions and 92 deletions
@ -1,74 +1,160 @@ |
|||||
<script> |
<script> |
||||
import { goto } from "@roxi/routify" |
import { ModalContent, Modal, Body, Layout, Detail } from "@budibase/bbui" |
||||
import { datasources } from "stores/backend" |
import { onMount } from "svelte" |
||||
import { notifications } from "@budibase/bbui" |
import ICONS from "../icons" |
||||
import { Input, Label, ModalContent, Modal, Context } from "@budibase/bbui" |
import api from "builderStore/api" |
||||
import TableIntegrationMenu from "../TableIntegrationMenu/index.svelte" |
import { IntegrationNames } from "constants" |
||||
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte" |
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte" |
||||
import analytics, { Events } from "analytics" |
import DatasourceConfigModal from "components/backend/DatasourceNavigator/modals/DatasourceConfigModal.svelte" |
||||
import { getContext } from "svelte" |
|
||||
|
|
||||
const modalContext = getContext(Context.Modal) |
export let modal |
||||
|
let integrations = [] |
||||
|
let integration = {} |
||||
|
let internalTableModal |
||||
|
let externalDatasourceModal |
||||
|
|
||||
let tableModal |
const INTERNAL = "BUDIBASE" |
||||
let name |
|
||||
let error = "" |
|
||||
let integration |
|
||||
|
|
||||
$: checkOpenModal(integration && integration.type === "BUDIBASE") |
onMount(() => { |
||||
|
fetchIntegrations() |
||||
|
}) |
||||
|
|
||||
function checkValid(evt) { |
function selectIntegration(integrationType) { |
||||
const datasourceName = evt.target.value |
const selected = integrations[integrationType] |
||||
if ( |
|
||||
$datasources?.list.some(datasource => datasource.name === datasourceName) |
// build the schema |
||||
) { |
const config = {} |
||||
error = `Datasource with name ${datasourceName} already exists. Please choose another name.` |
for (let key of Object.keys(selected.datasource)) { |
||||
return |
config[key] = selected.datasource[key].default |
||||
|
} |
||||
|
integration = { |
||||
|
type: integrationType, |
||||
|
plus: selected.plus, |
||||
|
config, |
||||
|
schema: selected.datasource, |
||||
} |
} |
||||
error = "" |
|
||||
} |
} |
||||
|
|
||||
function checkOpenModal(isInternal) { |
function chooseNextModal() { |
||||
if (isInternal) { |
if (integration.type === INTERNAL) { |
||||
tableModal.show() |
externalDatasourceModal.hide() |
||||
|
internalTableModal.show() |
||||
|
} else { |
||||
|
externalDatasourceModal.show() |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
async function saveDatasource() { |
async function fetchIntegrations() { |
||||
const { type, plus, ...config } = integration |
const response = await api.get("/api/integrations") |
||||
|
const json = await response.json() |
||||
// Create datasource |
integrations = { |
||||
const response = await datasources.save({ |
[INTERNAL]: { datasource: {}, name: "INTERNAL/CSV" }, |
||||
name, |
...json, |
||||
source: type, |
} |
||||
config, |
return json |
||||
plus, |
|
||||
}) |
|
||||
notifications.success(`Datasource ${name} created successfully.`) |
|
||||
analytics.captureEvent(Events.DATASOURCE.CREATED, { name, type }) |
|
||||
|
|
||||
// Navigate to new datasource |
|
||||
$goto(`./datasource/${response._id}`) |
|
||||
} |
} |
||||
</script> |
</script> |
||||
|
|
||||
<Modal bind:this={tableModal} on:hide={modalContext.hide}> |
<Modal bind:this={internalTableModal}> |
||||
<CreateTableModal bind:name /> |
<CreateTableModal /> |
||||
|
</Modal> |
||||
|
|
||||
|
<Modal bind:this={externalDatasourceModal}> |
||||
|
<DatasourceConfigModal {integration} /> |
||||
</Modal> |
</Modal> |
||||
<ModalContent |
|
||||
title="Create Datasource" |
<Modal bind:this={modal}> |
||||
size="L" |
<ModalContent |
||||
confirmText="Create" |
disabled={!Object.keys(integration).length} |
||||
onConfirm={saveDatasource} |
title="Data" |
||||
disabled={error || !name || !integration?.type} |
confirmText="Continue" |
||||
> |
showCancelButton={false} |
||||
<Input |
size="M" |
||||
data-cy="datasource-name-input" |
onConfirm={() => { |
||||
label="Datasource Name" |
chooseNextModal() |
||||
on:input={checkValid} |
}} |
||||
bind:value={name} |
> |
||||
{error} |
<Layout noPadding> |
||||
/> |
<Body size="XS" |
||||
<Label>Datasource Type</Label> |
>All apps need data. You can connect to a data source below, or add data |
||||
<TableIntegrationMenu bind:integration /> |
to your app using Budibase's built-in database. |
||||
</ModalContent> |
</Body> |
||||
|
<div |
||||
|
class:selected={integration.type === INTERNAL} |
||||
|
on:click={() => selectIntegration(INTERNAL)} |
||||
|
class="item hoverable" |
||||
|
> |
||||
|
<div class="item-body"> |
||||
|
<svelte:component this={ICONS.BUDIBASE} height="18" width="18" /> |
||||
|
<span class="icon-spacing"> <Body size="S">Budibase DB</Body></span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</Layout> |
||||
|
|
||||
|
<Layout gap="XS" noPadding> |
||||
|
<div class="title-spacing"> |
||||
|
<Detail size="S">Connect to data source</Detail> |
||||
|
</div> |
||||
|
<div class="item-list"> |
||||
|
{#each Object.entries(integrations).filter(([key]) => key !== INTERNAL) as [integrationType, schema]} |
||||
|
<div |
||||
|
class:selected={integration.type === integrationType} |
||||
|
on:click={() => selectIntegration(integrationType)} |
||||
|
class="item hoverable" |
||||
|
> |
||||
|
<div class="item-body"> |
||||
|
<svelte:component |
||||
|
this={ICONS[integrationType]} |
||||
|
height="18" |
||||
|
width="18" |
||||
|
/> |
||||
|
|
||||
|
<span class="icon-spacing"> |
||||
|
<Body size="S" |
||||
|
>{schema.name || IntegrationNames[integrationType]}</Body |
||||
|
></span |
||||
|
> |
||||
|
</div> |
||||
|
</div> |
||||
|
{/each} |
||||
|
</div> |
||||
|
</Layout> |
||||
|
</ModalContent> |
||||
|
</Modal> |
||||
|
|
||||
|
<style> |
||||
|
.icon-spacing { |
||||
|
margin-left: var(--spacing-m); |
||||
|
} |
||||
|
.item-body { |
||||
|
display: flex; |
||||
|
margin-left: var(--spacing-m); |
||||
|
} |
||||
|
.item-list { |
||||
|
display: grid; |
||||
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); |
||||
|
grid-gap: var(--spectrum-alias-grid-baseline); |
||||
|
} |
||||
|
|
||||
|
.item { |
||||
|
cursor: pointer; |
||||
|
display: grid; |
||||
|
grid-gap: var(--spectrum-alias-grid-margin-xsmall); |
||||
|
padding: var(--spectrum-alias-item-padding-s); |
||||
|
background: var(--spectrum-alias-background-color-secondary); |
||||
|
transition: 0.3s all; |
||||
|
border: solid var(--spectrum-alias-border-color); |
||||
|
border-radius: 5px; |
||||
|
box-sizing: border-box; |
||||
|
border-width: 2px; |
||||
|
} |
||||
|
|
||||
|
.selected { |
||||
|
background: var(--spectrum-alias-background-color-tertiary); |
||||
|
} |
||||
|
|
||||
|
.item:hover, |
||||
|
.selected { |
||||
|
background: var(--spectrum-alias-background-color-tertiary); |
||||
|
} |
||||
|
</style> |
||||
|
|||||
@ -0,0 +1,72 @@ |
|||||
|
<script> |
||||
|
import { goto } from "@roxi/routify" |
||||
|
import { ModalContent, notifications, Body, Layout } from "@budibase/bbui" |
||||
|
import analytics, { Events } from "analytics" |
||||
|
import IntegrationConfigForm from "components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte" |
||||
|
import { datasources } from "stores/backend" |
||||
|
import { IntegrationNames } from "constants" |
||||
|
|
||||
|
export let integration |
||||
|
|
||||
|
function prepareData() { |
||||
|
let datasource = {} |
||||
|
let existingTypeCount = $datasources.list.filter( |
||||
|
ds => ds.source == integration.type |
||||
|
).length |
||||
|
|
||||
|
let baseName = IntegrationNames[integration.type] |
||||
|
let name = |
||||
|
existingTypeCount == 0 ? baseName : `${baseName}-${existingTypeCount + 1}` |
||||
|
|
||||
|
datasource.type = "datasource" |
||||
|
datasource.source = integration.type |
||||
|
datasource.config = integration.config |
||||
|
datasource.name = name |
||||
|
datasource.plus = integration.plus |
||||
|
|
||||
|
return datasource |
||||
|
} |
||||
|
async function saveDatasource() { |
||||
|
const datasource = prepareData() |
||||
|
try { |
||||
|
// Create datasource |
||||
|
const resp = await datasources.save(datasource, datasource.plus) |
||||
|
|
||||
|
await datasources.select(resp._id) |
||||
|
$goto(`./datasource/${resp._id}`) |
||||
|
notifications.success(`Datasource updated successfully.`) |
||||
|
analytics.captureEvent(Events.DATASOURCE.CREATED, { |
||||
|
name: resp.name, |
||||
|
source: resp.source, |
||||
|
}) |
||||
|
return true |
||||
|
} catch (err) { |
||||
|
notifications.error(`Error saving datasource: ${err}`) |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<ModalContent |
||||
|
title={`Connect to ${IntegrationNames[integration.type]}`} |
||||
|
onConfirm={() => saveDatasource()} |
||||
|
confirmText={integration.plus |
||||
|
? "Fetch tables from database" |
||||
|
: "Save and continue to query"} |
||||
|
cancelText="Back" |
||||
|
size="M" |
||||
|
> |
||||
|
<Layout noPadding> |
||||
|
<Body size="XS" |
||||
|
>Connect your database to Budibase using the config below. |
||||
|
</Body> |
||||
|
</Layout> |
||||
|
|
||||
|
<IntegrationConfigForm |
||||
|
schema={integration.schema} |
||||
|
bind:integration={integration.config} |
||||
|
/> |
||||
|
</ModalContent> |
||||
|
|
||||
|
<style> |
||||
|
</style> |
||||
@ -1,6 +1,22 @@ |
|||||
<script> |
<script> |
||||
import { goto } from "@roxi/routify" |
import { goto } from "@roxi/routify" |
||||
$goto("./table") |
import { onMount } from "svelte" |
||||
|
import CreateDatasourceModal from "components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte" |
||||
|
import { datasources } from "stores/backend" |
||||
|
|
||||
|
let modal |
||||
|
$: setupComplete = |
||||
|
$datasources.list.find(x => (x._id = "bb_internal")).entities.length > 1 || |
||||
|
$datasources.list.length > 1 |
||||
|
|
||||
|
onMount(() => { |
||||
|
if (!setupComplete) { |
||||
|
modal.show() |
||||
|
} else { |
||||
|
$goto("./table") |
||||
|
} |
||||
|
}) |
||||
</script> |
</script> |
||||
|
|
||||
|
<CreateDatasourceModal bind:modal /> |
||||
<!-- routify:options index=false --> |
<!-- routify:options index=false --> |
||||
|
|||||
Loading…
Reference in new issue