add base wizard for datasources
This commit is contained in:
parent
c91e5ea39c
commit
0de6b55438
|
@ -1,74 +1,159 @@
|
|||
<script>
|
||||
import { goto } from "@roxi/routify"
|
||||
import { datasources } from "stores/backend"
|
||||
import { notifications } from "@budibase/bbui"
|
||||
import { Input, Label, ModalContent, Modal, Context } from "@budibase/bbui"
|
||||
import TableIntegrationMenu from "../TableIntegrationMenu/index.svelte"
|
||||
import { ModalContent, Modal, Body, Layout, Label } from "@budibase/bbui"
|
||||
import { onMount } from "svelte"
|
||||
import ICONS from "../icons"
|
||||
import api from "builderStore/api"
|
||||
import { IntegrationNames } from "constants"
|
||||
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte"
|
||||
import analytics from "analytics"
|
||||
import { getContext } from "svelte"
|
||||
import DatasourceDetailsModal from "components/backend/DatasourceNavigator/modals/DatasourceDetailsModal.svelte"
|
||||
|
||||
const modalContext = getContext(Context.Modal)
|
||||
export let modal
|
||||
let integrations = []
|
||||
let integration = {}
|
||||
let internalTableModal
|
||||
let externalDatasourceModal
|
||||
|
||||
let tableModal
|
||||
let name
|
||||
let error = ""
|
||||
let integration
|
||||
const INTERNAL = "BUDIBASE"
|
||||
|
||||
$: checkOpenModal(integration && integration.type === "BUDIBASE")
|
||||
|
||||
function checkValid(evt) {
|
||||
const datasourceName = evt.target.value
|
||||
if (
|
||||
$datasources?.list.some(datasource => datasource.name === datasourceName)
|
||||
) {
|
||||
error = `Datasource with name ${datasourceName} already exists. Please choose another name.`
|
||||
return
|
||||
}
|
||||
error = ""
|
||||
}
|
||||
|
||||
function checkOpenModal(isInternal) {
|
||||
if (isInternal) {
|
||||
tableModal.show()
|
||||
}
|
||||
}
|
||||
|
||||
async function saveDatasource() {
|
||||
const { type, plus, ...config } = integration
|
||||
|
||||
// Create datasource
|
||||
const response = await datasources.save({
|
||||
name,
|
||||
source: type,
|
||||
config,
|
||||
plus,
|
||||
onMount(() => {
|
||||
fetchIntegrations()
|
||||
})
|
||||
notifications.success(`Datasource ${name} created successfully.`)
|
||||
analytics.captureEvent("Datasource Created", { name, type })
|
||||
|
||||
// Navigate to new datasource
|
||||
$goto(`./datasource/${response._id}`)
|
||||
function selectIntegration(integrationType) {
|
||||
const selected = integrations[integrationType]
|
||||
|
||||
// build the schema
|
||||
const config = {}
|
||||
for (let key of Object.keys(selected.datasource)) {
|
||||
config[key] = selected.datasource[key].default
|
||||
}
|
||||
integration = {
|
||||
type: integrationType,
|
||||
plus: selected.plus,
|
||||
config,
|
||||
schema: selected.datasource,
|
||||
}
|
||||
}
|
||||
|
||||
function chooseNextModal() {
|
||||
if (integration.type === INTERNAL) {
|
||||
externalDatasourceModal.hide()
|
||||
internalTableModal.show()
|
||||
} else {
|
||||
externalDatasourceModal.show()
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchIntegrations() {
|
||||
const response = await api.get("/api/integrations")
|
||||
const json = await response.json()
|
||||
integrations = {
|
||||
[INTERNAL]: { datasource: {}, name: "INTERNAL/CSV" },
|
||||
...json,
|
||||
}
|
||||
return json
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal bind:this={tableModal} on:hide={modalContext.hide}>
|
||||
<CreateTableModal bind:name />
|
||||
<Modal bind:this={internalTableModal}>
|
||||
<CreateTableModal />
|
||||
</Modal>
|
||||
|
||||
<Modal bind:this={externalDatasourceModal}>
|
||||
<DatasourceDetailsModal {integration} />
|
||||
</Modal>
|
||||
|
||||
<Modal bind:this={modal}>
|
||||
<ModalContent
|
||||
title="Create Datasource"
|
||||
size="L"
|
||||
confirmText="Create"
|
||||
onConfirm={saveDatasource}
|
||||
disabled={error || !name || !integration?.type}
|
||||
disabled={!Object.keys(integration).length}
|
||||
title="Add Data"
|
||||
confirmText="Continue"
|
||||
cancelText="Start from scratch"
|
||||
size="M"
|
||||
onConfirm={() => {
|
||||
chooseNextModal()
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
data-cy="datasource-name-input"
|
||||
label="Datasource Name"
|
||||
on:input={checkValid}
|
||||
bind:value={name}
|
||||
{error}
|
||||
<Body size="XS"
|
||||
>All apps need data. You can connect to a data source below, or add data
|
||||
to your app using Budibase's built-in database - it's simple!
|
||||
</Body>
|
||||
|
||||
<Layout noPadding>
|
||||
<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 (no prior data required)</Body></span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<Label size="S">Connect to data source</Label>
|
||||
|
||||
<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"
|
||||
/>
|
||||
<Label>Datasource Type</Label>
|
||||
<TableIntegrationMenu bind:integration />
|
||||
|
||||
<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,51 @@
|
|||
<script>
|
||||
import { ModalContent, notifications } from "@budibase/bbui"
|
||||
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.type == 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
|
||||
|
||||
return datasource
|
||||
}
|
||||
async function saveDatasource() {
|
||||
try {
|
||||
// Create datasource
|
||||
await datasources.save(prepareData())
|
||||
notifications.success(`Datasource updated successfully.`)
|
||||
} catch (err) {
|
||||
notifications.error(`Error saving datasource: ${err}`)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<ModalContent
|
||||
title="Add Data"
|
||||
onConfirm={() => saveDatasource()}
|
||||
confirmText="Continue"
|
||||
cancelText="Start from scratch"
|
||||
size="M"
|
||||
>
|
||||
<IntegrationConfigForm
|
||||
schema={integration.schema}
|
||||
bind:integration={integration.config}
|
||||
/>
|
||||
</ModalContent>
|
||||
|
||||
<style>
|
||||
</style>
|
|
@ -15,6 +15,20 @@ export const AppStatus = {
|
|||
DEPLOYED: "published",
|
||||
}
|
||||
|
||||
export const IntegrationNames = {
|
||||
POSTGRES: "PostgreSQL",
|
||||
MONGODB: "MongoDB",
|
||||
COUCHDB: "CouchDB",
|
||||
S3: "S3",
|
||||
MYSQL: "MySQL",
|
||||
REST: "REST",
|
||||
DYNAMODB: "DynamoDB",
|
||||
ELASTICSEARCH: "ElasticSearch",
|
||||
SQL_SERVER: "SQL Server",
|
||||
AIRTABLE: "Airtable",
|
||||
ARANGODB: "ArangoDB",
|
||||
}
|
||||
|
||||
// fields on the user table that cannot be edited
|
||||
export const UNEDITABLE_USER_FIELDS = [
|
||||
"email",
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
<script>
|
||||
import { goto, params } from "@roxi/routify"
|
||||
import { Icon, Modal, Tabs, Tab } from "@budibase/bbui"
|
||||
import { Icon, Tabs, Tab } from "@budibase/bbui"
|
||||
import { BUDIBASE_INTERNAL_DB } from "constants"
|
||||
import DatasourceNavigator from "components/backend/DatasourceNavigator/DatasourceNavigator.svelte"
|
||||
import CreateDatasourceModal from "components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte"
|
||||
|
||||
let selected = "Sources"
|
||||
|
||||
let modal
|
||||
|
||||
$: isExternal =
|
||||
$params.selectedDatasource &&
|
||||
$params.selectedDatasource !== BUDIBASE_INTERNAL_DB
|
||||
|
@ -23,9 +25,7 @@
|
|||
<Tab title="Sources">
|
||||
<div class="tab-content-padding">
|
||||
<DatasourceNavigator />
|
||||
<Modal bind:this={modal}>
|
||||
<CreateDatasourceModal />
|
||||
</Modal>
|
||||
<CreateDatasourceModal bind:modal />
|
||||
</div>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
<script>
|
||||
import { goto } from "@roxi/routify"
|
||||
$goto("./table")
|
||||
import CreateDatasourceModal from "components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte"
|
||||
import { datasources } from "stores/backend"
|
||||
|
||||
$: setupComplete =
|
||||
$datasources.list.find(x => (x._id = "bb_internal")).entities.length > 1 ||
|
||||
$datasources.list > 1
|
||||
</script>
|
||||
|
||||
{#if !setupComplete}
|
||||
<CreateDatasourceModal />
|
||||
{/if}
|
||||
<!-- routify:options index=false -->
|
||||
|
|
Loading…
Reference in New Issue