Adding feature to allow configured the builder to point at a self hosted system instead of production (for deployment).

This commit is contained in:
mike12345567 2020-12-15 16:41:55 +00:00
parent f5a9c68c69
commit 21978007cf
8 changed files with 156 additions and 25 deletions

View File

@ -1,6 +1,8 @@
import { getFrontendStore } from "./store/frontend" import { getFrontendStore } from "./store/frontend"
import { getBackendUiStore } from "./store/backend" import { getBackendUiStore } from "./store/backend"
import { getAutomationStore } from "./store/automation/" import { getAutomationStore } from "./store/automation"
import { getHostingStore } from "./store/hosting"
import { getThemeStore } from "./store/theme" import { getThemeStore } from "./store/theme"
import { derived } from "svelte/store" import { derived } from "svelte/store"
import analytics from "analytics" import analytics from "analytics"
@ -11,6 +13,7 @@ export const store = getFrontendStore()
export const backendUiStore = getBackendUiStore() export const backendUiStore = getBackendUiStore()
export const automationStore = getAutomationStore() export const automationStore = getAutomationStore()
export const themeStore = getThemeStore() export const themeStore = getThemeStore()
export const hostingStore = getHostingStore()
export const currentAsset = derived(store, $store => { export const currentAsset = derived(store, $store => {
const layout = $store.layouts const layout = $store.layouts

View File

@ -0,0 +1,35 @@
import { writable } from "svelte/store"
import api from "../api"
const INITIAL_BACKEND_UI_STATE = {
hostingInfo: {},
appUrl: "",
}
export const getHostingStore = () => {
const store = writable({...INITIAL_BACKEND_UI_STATE})
store.actions = {
fetch: async () => {
const response = await api.get("/api/hosting/")
const info = await response.json()
store.update(state => {
state.hostingInfo = info
return state
})
return info
},
save: async hostingInfo => {
const response = await api.post("/api/hosting", hostingInfo)
const revision = (await response.json()).rev
store.update(state => {
state.hostingInfo = {
...hostingInfo,
_rev: revision,
}
return state
})
}
}
return store
}

View File

@ -0,0 +1,32 @@
<script>
import { TextButton as Button, Modal } from "@budibase/bbui"
import BuilderSettingsModal from "./BuilderSettingsModal.svelte"
let modal
</script>
<div>
<Button text on:click={modal.show}>
<i class="ri-settings-3-fill"></i>
<p>Settings</p>
</Button>
</div>
<Modal bind:this={modal} width="30%">
<BuilderSettingsModal />
</Modal>
<style>
div i {
font-size: 26px;
color: var(--grey-7);
margin-left: 12px;
}
div p {
font-family: var(--font-sans);
font-size: var(--font-size-s);
color: var(--ink);
font-weight: 400;
margin: 0 0 0 12px;
}
</style>

View File

@ -0,0 +1,51 @@
<script>
import { notifier } from "builderStore/store/notifications"
import { hostingStore } from "builderStore"
import { Input, ModalContent, Toggle } from "@budibase/bbui"
import analytics from "analytics"
import { onMount } from "svelte"
let selfhosted = false
let hostingInfo
async function save() {
if (!selfhosted) {
return
}
hostingInfo.type = selfhosted ? "self" : "cloud"
try {
await hostingStore.actions.save(hostingInfo)
notifier.success(`Settings saved.`)
} catch (err) {
notifier.danger(`Failed to update builder settings.`)
}
}
onMount(async () => {
hostingInfo = await hostingStore.actions.fetch()
selfhosted = hostingInfo.type === "self"
})
</script>
<ModalContent title="Builder settings" confirmText="Save" onConfirm={save} showConfirmButton={selfhosted}>
<h5>Hosting</h5>
<p>This section contains settings that relate to the deployment and hosting of apps made in this builder.</p>
<Toggle thin text="Self hosted" bind:checked={selfhosted} />
{#if selfhosted}
<Input bind:value={hostingInfo.appServerUrl} label="Apps URL" />
<Input bind:value={hostingInfo.objectStoreUrl} label="Object store URL" />
<Toggle thin text="HTTPS" bind:checked={hostingInfo.useHttps} />
{/if}
</ModalContent>
<style>
h5 {
margin: 0;
font-size: 14px;
}
p {
margin: 0;
font-size: 12px;
}
</style>

View File

@ -7,6 +7,9 @@
CommunityIcon, CommunityIcon,
BugIcon, BugIcon,
} from "components/common/Icons" } from "components/common/Icons"
import BuilderSettingsButton from "components/start/BuilderSettingsButton.svelte"
let modal
</script> </script>
<div class="root"> <div class="root">
@ -16,27 +19,30 @@
</div> </div>
<div class="nav-section"> <div class="nav-section">
<Link icon={AppsIcon} title="Apps" href="/" active /> <div class="nav-top">
<Link <Link icon={AppsIcon} title="Apps" href="/" active />
icon={HostingIcon} <Link
title="Hosting" icon={HostingIcon}
href="https://portal.budi.live/" /> title="Hosting"
<Link href="https://portal.budi.live/" />
icon={DocumentationIcon} <Link
title="Documentation" icon={DocumentationIcon}
href="https://docs.budibase.com/" /> title="Documentation"
<Link href="https://docs.budibase.com/" />
icon={CommunityIcon} <Link
title="Community" icon={CommunityIcon}
href="https://github.com/Budibase/budibase/discussions" /> title="Community"
href="https://github.com/Budibase/budibase/discussions" />
<Link <Link
icon={BugIcon} icon={BugIcon}
title="Raise an issue" title="Raise an issue"
href="https://github.com/Budibase/budibase/issues/new/choose" /> href="https://github.com/Budibase/budibase/issues/new/choose" />
</div>
<div class="nav-bottom">
<BuilderSettingsButton/>
</div>
</div> </div>
</div> </div>
<div class="main"> <div class="main">
<slot /> <slot />
</div> </div>
@ -76,8 +82,10 @@
} }
.nav-section { .nav-section {
margin: 20px 0px; margin: 20px 0 0 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between;
height: 100%;
} }
</style> </style>

View File

@ -18,14 +18,14 @@ exports.save = async ctx => {
if (type === HostingTypes.CLOUD) { if (type === HostingTypes.CLOUD) {
ctx.throw(400, "Cannot update Cloud hosting information") ctx.throw(400, "Cannot update Cloud hosting information")
} }
await db.put({ const response = await db.put({
_id: HOSTING_DOC, _id: HOSTING_DOC,
type, type,
appServerUrl, appServerUrl,
objectStoreUrl, objectStoreUrl,
useHttps, useHttps,
}) })
ctx.body = "Hosting information saved successfully" ctx.body = response
} }
exports.fetch = async ctx => { exports.fetch = async ctx => {

View File

@ -6,8 +6,8 @@ const { BUILDER } = require("../../utilities/security/permissions")
const router = Router() const router = Router()
router router
.fetch("/api/hosting/info", authorized(BUILDER), controller.fetchInfo) .get("/api/hosting/info", authorized(BUILDER), controller.fetchInfo)
.fetch("/api/hosting", authorized(BUILDER), controller.fetch) .get("/api/hosting", authorized(BUILDER), controller.fetch)
.post("/api/hosting", authorized(BUILDER), controller.save) .post("/api/hosting", authorized(BUILDER), controller.save)
module.exports = router module.exports = router

View File

@ -17,6 +17,7 @@ const templatesRoutes = require("./templates")
const analyticsRoutes = require("./analytics") const analyticsRoutes = require("./analytics")
const routingRoutes = require("./routing") const routingRoutes = require("./routing")
const permissionRoutes = require("./permission") const permissionRoutes = require("./permission")
const hostingRoutes = require("./hosting")
exports.mainRoutes = [ exports.mainRoutes = [
deployRoutes, deployRoutes,
@ -34,6 +35,7 @@ exports.mainRoutes = [
webhookRoutes, webhookRoutes,
routingRoutes, routingRoutes,
permissionRoutes, permissionRoutes,
hostingRoutes,
// these need to be handled last as they still use /api/:tableId // these need to be handled last as they still use /api/:tableId
// this could be breaking as koa may recognise other routes as this // this could be breaking as koa may recognise other routes as this
tableRoutes, tableRoutes,