Merge pull request #1448 from Budibase/admin/basic-settings-page

Admin/basic settings page
This commit is contained in:
Kevin Åberg Kultalahti 2021-05-06 09:40:37 +02:00 committed by GitHub
commit d644507149
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 194 additions and 38 deletions

View File

@ -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>

View File

@ -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"

View File

@ -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

View File

@ -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
}

View File

@ -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>

View File

@ -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;

View File

@ -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

View File

@ -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>

View File

@ -0,0 +1,4 @@
<script>
import { goto } from "@roxi/routify"
$goto("./general")
</script>

View File

@ -0,0 +1,7 @@
import { writable } from "svelte/store"
const INITIAL_ADMIN_STATE = {
oauth: [],
}
export const admin = writable({ ...INITIAL_ADMIN_STATE })

View File

@ -0,0 +1,2 @@
export { organisation } from "./organisation"
export { admin } from "./admin"

View File

@ -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()

View File

@ -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