Merge pull request #1448 from Budibase/admin/basic-settings-page
Admin/basic settings page
This commit is contained in:
commit
d644507149
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
function getInitials(name) {
|
function getInitials(name) {
|
||||||
let parts = name.split(" ")
|
let parts = name.split(" ")
|
||||||
return parts.map((name) => name[0]).join("")
|
return parts.map(name => name[0]).join("")
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
</h2>
|
</h2>
|
||||||
{/if}
|
{/if}
|
||||||
<a
|
<a
|
||||||
target={external ? "_blank" : "_self"}
|
target={external ? "_blank" : ""}
|
||||||
{href}
|
{href}
|
||||||
class="spectrum-SideNav-itemLink"
|
class="spectrum-SideNav-itemLink"
|
||||||
aria-current="page"
|
aria-current="page"
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { getFrontendStore } from "./store/frontend"
|
||||||
import { getAutomationStore } from "./store/automation"
|
import { getAutomationStore } from "./store/automation"
|
||||||
import { getHostingStore } from "./store/hosting"
|
import { getHostingStore } from "./store/hosting"
|
||||||
import { getThemeStore } from "./store/theme"
|
import { getThemeStore } from "./store/theme"
|
||||||
import { getAdminStore } from "./store/admin"
|
|
||||||
import { derived, writable } from "svelte/store"
|
import { derived, writable } from "svelte/store"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
import { FrontendTypes, LAYOUT_NAMES } from "../constants"
|
import { FrontendTypes, LAYOUT_NAMES } from "../constants"
|
||||||
|
@ -12,7 +11,6 @@ export const store = getFrontendStore()
|
||||||
export const automationStore = getAutomationStore()
|
export const automationStore = getAutomationStore()
|
||||||
export const themeStore = getThemeStore()
|
export const themeStore = getThemeStore()
|
||||||
export const hostingStore = getHostingStore()
|
export const hostingStore = getHostingStore()
|
||||||
export const adminPanelStore = getAdminStore()
|
|
||||||
|
|
||||||
export const currentAsset = derived(store, $store => {
|
export const currentAsset = derived(store, $store => {
|
||||||
const type = $store.currentFrontEndType
|
const type = $store.currentFrontEndType
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
import { writable } from "svelte/store"
|
|
||||||
|
|
||||||
const INITIAL_ADMIN_STATE = {
|
|
||||||
oauth: [],
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getAdminStore = () => {
|
|
||||||
const store = writable({ ...INITIAL_ADMIN_STATE })
|
|
||||||
store.actions = {}
|
|
||||||
return store
|
|
||||||
}
|
|
|
@ -10,15 +10,12 @@
|
||||||
SideNavigation as Navigation,
|
SideNavigation as Navigation,
|
||||||
SideNavigationItem as Item,
|
SideNavigationItem as Item,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
|
import { organisation } from "stores/portal"
|
||||||
|
organisation.init()
|
||||||
|
|
||||||
let orgName, orgLogo, onBoardingProgress, user
|
let onBoardingProgress, user
|
||||||
|
|
||||||
async function getInfo() {
|
async function getInfo() {
|
||||||
// fetch orgInfo
|
|
||||||
orgName = "ACME Inc."
|
|
||||||
orgLogo = "https://via.placeholder.com/150"
|
|
||||||
|
|
||||||
// set onBoardingProgress
|
|
||||||
onBoardingProgress = 20
|
onBoardingProgress = 20
|
||||||
user = { name: "John Doe" }
|
user = { name: "John Doe" }
|
||||||
}
|
}
|
||||||
|
@ -26,13 +23,13 @@
|
||||||
onMount(getInfo)
|
onMount(getInfo)
|
||||||
|
|
||||||
let menu = [
|
let menu = [
|
||||||
{ title: "Apps", href: "/portal" },
|
{ title: "Apps", href: "/portal/" },
|
||||||
{ title: "Drafts", href: "/portal/drafts" },
|
{ title: "Drafts", href: "/portal/drafts" },
|
||||||
{ title: "Users", href: "/portal/users", heading: "Manage" },
|
{ title: "Users", href: "/portal/users", heading: "Manage" },
|
||||||
{ title: "Groups", href: "/portal/groups" },
|
{ title: "Groups", href: "/portal/groups" },
|
||||||
{ title: "Auth", href: "/portal/oauth" },
|
{ title: "Auth", href: "/portal/oauth" },
|
||||||
{ title: "Email", href: "/portal/email" },
|
{ title: "Email", href: "/portal/email" },
|
||||||
{ title: "General", href: "/portal/general", heading: "Settings" },
|
{ title: "General", href: "/portal/settings/general", heading: "Settings" },
|
||||||
{ title: "Theming", href: "/portal/theming" },
|
{ title: "Theming", href: "/portal/theming" },
|
||||||
{ title: "Account", href: "/portal/account" },
|
{ title: "Account", href: "/portal/account" },
|
||||||
]
|
]
|
||||||
|
@ -43,8 +40,11 @@
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
<div class="branding">
|
<div class="branding">
|
||||||
<div class="name">
|
<div class="name">
|
||||||
<img src={orgLogo} alt="Logotype" />
|
<img
|
||||||
<span>{orgName}</span>
|
src={$organisation?.logoUrl || "https://via.placeholder.com/50"}
|
||||||
|
alt="Logotype"
|
||||||
|
/>
|
||||||
|
<span>{$organisation?.company}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="onboarding">
|
<div class="onboarding">
|
||||||
<ProgressCircle size="S" value={onBoardingProgress} />
|
<ProgressCircle size="S" value={onBoardingProgress} />
|
||||||
|
@ -88,6 +88,7 @@
|
||||||
}
|
}
|
||||||
.branding {
|
.branding {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
grid-gap: var(--spacing-s);
|
||||||
grid-template-columns: auto auto;
|
grid-template-columns: auto auto;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -100,7 +101,11 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
padding: var(--spacing-m);
|
display: grid;
|
||||||
|
padding: calc(var(--spacing-xl) * 2) var(--spacing-m) var(--spacing-m)
|
||||||
|
var(--spacing-m);
|
||||||
|
max-width: 80ch;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
.avatar {
|
.avatar {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
@ -123,4 +128,8 @@
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
span {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="container">
|
<section>
|
||||||
<header>
|
<header>
|
||||||
<Heading size="M">OAuth</Heading>
|
<Heading size="M">OAuth</Heading>
|
||||||
<Body size="S">
|
<Body size="S">
|
||||||
|
@ -91,10 +91,6 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
section {
|
|
||||||
margin: 60px 320px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.config-form {
|
.config-form {
|
||||||
margin-top: 42px;
|
margin-top: 42px;
|
||||||
margin-bottom: 42px;
|
margin-bottom: 42px;
|
||||||
|
|
|
@ -3,32 +3,37 @@
|
||||||
height="18"
|
height="18"
|
||||||
viewBox="0 0 268 268"
|
viewBox="0 0 268 268"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
<g clip-path="url(#clip0)">
|
<g clip-path="url(#clip0)">
|
||||||
<path
|
<path
|
||||||
d="M58.8037 109.043C64.0284 93.2355 74.1116 79.4822 87.615 69.7447C101.118
|
d="M58.8037 109.043C64.0284 93.2355 74.1116 79.4822 87.615 69.7447C101.118
|
||||||
60.0073 117.352 54.783 134 54.8172C152.872 54.8172 169.934 61.5172 183.334
|
60.0073 117.352 54.783 134 54.8172C152.872 54.8172 169.934 61.5172 183.334
|
||||||
72.4828L222.328 33.5C198.566 12.7858 168.114 0 134 0C81.1817 0 35.711
|
72.4828L222.328 33.5C198.566 12.7858 168.114 0 134 0C81.1817 0 35.711
|
||||||
30.1277 13.8467 74.2583L58.8037 109.043Z"
|
30.1277 13.8467 74.2583L58.8037 109.043Z"
|
||||||
fill="#EA4335" />
|
fill="#EA4335"
|
||||||
|
/>
|
||||||
<path
|
<path
|
||||||
d="M179.113 201.145C166.942 208.995 151.487 213.183 134 213.183C117.418
|
d="M179.113 201.145C166.942 208.995 151.487 213.183 134 213.183C117.418
|
||||||
213.217 101.246 208.034 87.7727 198.369C74.2993 188.703 64.2077 175.044
|
213.217 101.246 208.034 87.7727 198.369C74.2993 188.703 64.2077 175.044
|
||||||
58.9265 159.326L13.8132 193.574C24.8821 215.978 42.012 234.828 63.2572
|
58.9265 159.326L13.8132 193.574C24.8821 215.978 42.012 234.828 63.2572
|
||||||
247.984C84.5024 261.14 109.011 268.075 134 268C166.752 268 198.041 256.353
|
247.984C84.5024 261.14 109.011 268.075 134 268C166.752 268 198.041 256.353
|
||||||
221.48 234.5L179.125 201.145H179.113Z"
|
221.48 234.5L179.125 201.145H179.113Z"
|
||||||
fill="#34A853" />
|
fill="#34A853"
|
||||||
|
/>
|
||||||
<path
|
<path
|
||||||
d="M221.48 234.5C245.991 211.631 261.903 177.595 261.903 134C261.903
|
d="M221.48 234.5C245.991 211.631 261.903 177.595 261.903 134C261.903
|
||||||
126.072 260.686 117.552 258.866 109.634H134V161.414H205.869C202.329
|
126.072 260.686 117.552 258.866 109.634H134V161.414H205.869C202.329
|
||||||
178.823 192.804 192.301 179.125 201.145L221.48 234.5Z"
|
178.823 192.804 192.301 179.125 201.145L221.48 234.5Z"
|
||||||
fill="#4A90E2" />
|
fill="#4A90E2"
|
||||||
|
/>
|
||||||
<path
|
<path
|
||||||
d="M58.9265 159.326C56.1947 151.162 54.8068 142.609 54.8172 134C54.8172
|
d="M58.9265 159.326C56.1947 151.162 54.8068 142.609 54.8172 134C54.8172
|
||||||
125.268 56.213 116.882 58.8037 109.043L13.8467 74.2584C4.64957 92.825
|
125.268 56.213 116.882 58.8037 109.043L13.8467 74.2584C4.64957 92.825
|
||||||
-0.0915078 113.28 1.86708e-05 134C1.86708e-05 155.44 4.96919 175.652
|
-0.0915078 113.28 1.86708e-05 134C1.86708e-05 155.44 4.96919 175.652
|
||||||
13.8132 193.574L58.9265 159.326Z"
|
13.8132 193.574L58.9265 159.326Z"
|
||||||
fill="#FBBC05" />
|
fill="#FBBC05"
|
||||||
|
/>
|
||||||
</g>
|
</g>
|
||||||
<defs>
|
<defs>
|
||||||
<clipPath id="clip0">
|
<clipPath id="clip0">
|
||||||
|
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,111 @@
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
Layout,
|
||||||
|
Heading,
|
||||||
|
Body,
|
||||||
|
Button,
|
||||||
|
Divider,
|
||||||
|
Label,
|
||||||
|
Input,
|
||||||
|
Toggle,
|
||||||
|
Dropzone,
|
||||||
|
notifications,
|
||||||
|
} from "@budibase/bbui"
|
||||||
|
import { organisation } from "stores/portal"
|
||||||
|
import analytics from "analytics"
|
||||||
|
let analyticsDisabled = analytics.disabled()
|
||||||
|
|
||||||
|
function toggleAnalytics() {
|
||||||
|
if (analyticsDisabled) {
|
||||||
|
analytics.optIn()
|
||||||
|
} else {
|
||||||
|
analytics.optOut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let loading = false
|
||||||
|
|
||||||
|
$: company = $organisation?.company
|
||||||
|
$: logoUrl = $organisation.logoUrl
|
||||||
|
|
||||||
|
async function saveConfig() {
|
||||||
|
loading = true
|
||||||
|
await toggleAnalytics()
|
||||||
|
const res = await organisation.save({ ...$organisation, company })
|
||||||
|
if (res.status === 200) {
|
||||||
|
notifications.success("General settings saved.")
|
||||||
|
} else {
|
||||||
|
notifications.danger("Error when saving settings.")
|
||||||
|
}
|
||||||
|
loading = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<Layout noPadding>
|
||||||
|
<div class="intro">
|
||||||
|
<Heading size="M">General</Heading>
|
||||||
|
<Body
|
||||||
|
>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Hic vero, aut
|
||||||
|
culpa provident sunt ratione! Voluptas doloremque, dicta nisi velit
|
||||||
|
perspiciatis, ratione vel blanditiis totam, nam voluptate repellat
|
||||||
|
aperiam fuga!</Body
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<Divider size="S" />
|
||||||
|
<div class="information">
|
||||||
|
<Heading size="S">Information</Heading>
|
||||||
|
<Body>Here you can update your logo and organization name.</Body>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="field">
|
||||||
|
<Label>Organization name</Label>
|
||||||
|
<Input thin bind:value={company} />
|
||||||
|
</div>
|
||||||
|
<!-- <div class="field">
|
||||||
|
<Label>Logo</Label>
|
||||||
|
<div class="file">
|
||||||
|
<Dropzone />
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Divider size="S" />
|
||||||
|
<div class="analytics">
|
||||||
|
<Heading size="S">Analytics</Heading>
|
||||||
|
<Body
|
||||||
|
>If you would like to send analytics that help us make Budibase better,
|
||||||
|
please let us know below.</Body
|
||||||
|
>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="field">
|
||||||
|
<Label>Send Analytics to Budibase</Label>
|
||||||
|
<Toggle text="" value={!analyticsDisabled} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="save">
|
||||||
|
<Button disabled={loading} on:click={saveConfig} cta>Save</Button>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.fields {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: var(--spacing-m);
|
||||||
|
margin-top: var(--spacing-xl);
|
||||||
|
}
|
||||||
|
.field {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 30% 1fr;
|
||||||
|
}
|
||||||
|
.file {
|
||||||
|
max-width: 30ch;
|
||||||
|
}
|
||||||
|
.intro {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
.save {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<script>
|
||||||
|
import { goto } from "@roxi/routify"
|
||||||
|
$goto("./general")
|
||||||
|
</script>
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { writable } from "svelte/store"
|
||||||
|
|
||||||
|
const INITIAL_ADMIN_STATE = {
|
||||||
|
oauth: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
export const admin = writable({ ...INITIAL_ADMIN_STATE })
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { organisation } from "./organisation"
|
||||||
|
export { admin } from "./admin"
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { writable } from "svelte/store"
|
||||||
|
import api from "builderStore/api"
|
||||||
|
|
||||||
|
export function createOrganisationStore() {
|
||||||
|
const { subscribe, set } = writable({})
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
try {
|
||||||
|
const response = await api.get(`/api/admin/configs/settings`)
|
||||||
|
const json = await response.json()
|
||||||
|
set(json)
|
||||||
|
} catch (error) {
|
||||||
|
set({
|
||||||
|
platformUrl: "",
|
||||||
|
logoUrl: "",
|
||||||
|
docsUrl: "",
|
||||||
|
company: "",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
save: async config => {
|
||||||
|
try {
|
||||||
|
await api.post("/api/admin/configs", { type: "settings", config })
|
||||||
|
await init()
|
||||||
|
return { status: 200 }
|
||||||
|
} catch (error) {
|
||||||
|
return { error }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
init,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const organisation = createOrganisationStore()
|
|
@ -74,6 +74,4 @@ for (let route of mainRoutes) {
|
||||||
router.use(staticRoutes.routes())
|
router.use(staticRoutes.routes())
|
||||||
router.use(staticRoutes.allowedMethods())
|
router.use(staticRoutes.allowedMethods())
|
||||||
|
|
||||||
router.redirect("/", "/builder")
|
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router
|
||||||
|
|
Loading…
Reference in New Issue