Merge pull request #10751 from Budibase/chore/split_auth_components

Chore - split google auth components
This commit is contained in:
Adria Navarro 2023-06-06 11:10:54 +02:00 committed by GitHub
commit 6dce5e85cd
2 changed files with 237 additions and 152 deletions

View File

@ -0,0 +1,235 @@
<script>
import GoogleLogo from "./_logos/Google.svelte"
import { isEqual, cloneDeep } from "lodash/fp"
import {
Button,
Heading,
Divider,
Label,
notifications,
Layout,
Input,
Body,
Toggle,
Icon,
Helpers,
Link,
} from "@budibase/bbui"
import { onMount } from "svelte"
import { API } from "api"
import { organisation, admin } from "stores/portal"
const ConfigTypes = {
Google: "google",
}
// Some older google configs contain a manually specified value - retain the functionality to edit the field
// When there is no value or we are in the cloud - prohibit editing the field, must use platform url to change
$: googleCallbackUrl = undefined
$: googleCallbackReadonly = $admin.cloud || !googleCallbackUrl
// Indicate to user that callback is based on platform url
// If there is an existing value, indicate that it may be removed to return to default behaviour
$: googleCallbackTooltip = $admin.cloud
? null
: googleCallbackReadonly
? "Visit the organisation page to update the platform URL"
: "Leave blank to use the default callback URL"
$: googleSheetsCallbackUrl = `${$organisation.platformUrl}/api/global/auth/datasource/google/callback`
$: GoogleConfigFields = {
Google: [
{ name: "clientID", label: "Client ID" },
{ name: "clientSecret", label: "Client secret" },
{
name: "callbackURL",
label: "Callback URL",
readonly: googleCallbackReadonly,
tooltip: googleCallbackTooltip,
placeholder: $organisation.googleCallbackUrl,
copyButton: true,
},
{
name: "sheetsURL",
label: "Sheets URL",
readonly: googleCallbackReadonly,
tooltip: googleCallbackTooltip,
placeholder: googleSheetsCallbackUrl,
copyButton: true,
},
],
}
let google
const providers = { google }
// control the state of the save button depending on whether form has changed
let originalGoogleDoc
let googleSaveButtonDisabled
$: {
isEqual(providers.google?.config, originalGoogleDoc?.config)
? (googleSaveButtonDisabled = true)
: (googleSaveButtonDisabled = false)
}
$: googleComplete = !!(
providers.google?.config?.clientID && providers.google?.config?.clientSecret
)
async function saveConfig(config) {
// Delete unsupported fields
delete config.createdAt
delete config.updatedAt
return API.saveConfig(config)
}
async function saveGoogle() {
if (!googleComplete) {
notifications.error(
`Please fill in all required ${ConfigTypes.Google} fields`
)
return
}
const google = providers.google
try {
const res = await saveConfig(google)
providers[res.type]._rev = res._rev
providers[res.type]._id = res._id
notifications.success(`Settings saved`)
} catch (e) {
notifications.error(e.message)
return
}
googleSaveButtonDisabled = true
originalGoogleDoc = cloneDeep(providers.google)
}
const copyToClipboard = async value => {
await Helpers.copyToClipboard(value)
notifications.success("Copied")
}
onMount(async () => {
try {
await organisation.init()
} catch (error) {
notifications.error("Error getting org config")
}
// Fetch Google config
let googleDoc
try {
googleDoc = await API.getConfig(ConfigTypes.Google)
} catch (error) {
notifications.error("Error fetching Google OAuth config")
}
if (!googleDoc?._id) {
providers.google = {
type: ConfigTypes.Google,
config: { activated: false },
}
originalGoogleDoc = cloneDeep(googleDoc)
} else {
// Default activated to true for older configs
if (googleDoc.config.activated === undefined) {
googleDoc.config.activated = true
}
originalGoogleDoc = cloneDeep(googleDoc)
providers.google = googleDoc
}
googleCallbackUrl = providers?.google?.config?.callbackURL
})
</script>
{#if providers.google}
<Divider />
<Layout gap="XS" noPadding>
<Heading size="S">
<div class="provider-title">
<GoogleLogo />
<span>Google</span>
</div>
</Heading>
<Body size="S">
To allow users to authenticate using their Google accounts, fill out the
fields below. Read the <Link
size="M"
href={"https://docs.budibase.com/docs/sso-with-google"}
>documentation</Link
> for more information.
</Body>
</Layout>
<Layout gap="XS" noPadding>
{#each GoogleConfigFields.Google as field}
<div class="form-row">
<Label size="L" tooltip={field.tooltip}>{field.label}</Label>
<div class="inputContainer">
<div class="input">
<Input
bind:value={providers.google.config[field.name]}
readonly={field.readonly}
placeholder={field.placeholder}
/>
</div>
{#if field.copyButton}
<div
class="copy"
on:click={() => copyToClipboard(field.placeholder)}
>
<Icon size="S" name="Copy" />
</div>
{/if}
</div>
</div>
{/each}
<div class="form-row">
<Label size="L">Activated</Label>
<Toggle text="" bind:value={providers.google.config.activated} />
</div>
</Layout>
<div>
<Button
disabled={googleSaveButtonDisabled}
cta
on:click={() => saveGoogle()}
>
Save
</Button>
</div>
{/if}
<style>
.form-row {
display: grid;
grid-template-columns: 120px 1fr;
grid-gap: var(--spacing-l);
align-items: center;
}
.provider-title {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: var(--spacing-m);
}
.provider-title span {
flex: 1 1 auto;
}
.inputContainer {
display: flex;
flex-direction: row;
}
.input {
flex: 1;
}
.copy {
display: flex;
align-items: center;
margin-left: 10px;
}
</style>

View File

@ -1,5 +1,4 @@
<script>
import GoogleLogo from "./_logos/Google.svelte"
import OidcLogo from "./_logos/OIDC.svelte"
import MicrosoftLogo from "assets/microsoft-logo.png"
import Auth0Logo from "assets/auth0-logo.png"
@ -28,9 +27,9 @@
import { API } from "api"
import { organisation, admin, licensing } from "stores/portal"
import Scim from "./scim.svelte"
import Google from "./google.svelte"
const ConfigTypes = {
Google: "google",
OIDC: "oidc",
}
@ -38,43 +37,6 @@
$: enforcedSSO = $organisation.isSSOEnforced
// Some older google configs contain a manually specified value - retain the functionality to edit the field
// When there is no value or we are in the cloud - prohibit editing the field, must use platform url to change
$: googleCallbackUrl = undefined
$: googleCallbackReadonly = $admin.cloud || !googleCallbackUrl
// Indicate to user that callback is based on platform url
// If there is an existing value, indicate that it may be removed to return to default behaviour
$: googleCallbackTooltip = $admin.cloud
? null
: googleCallbackReadonly
? "Visit the organisation page to update the platform URL"
: "Leave blank to use the default callback URL"
$: googleSheetsCallbackUrl = `${$organisation.platformUrl}/api/global/auth/datasource/google/callback`
$: GoogleConfigFields = {
Google: [
{ name: "clientID", label: "Client ID" },
{ name: "clientSecret", label: "Client secret" },
{
name: "callbackURL",
label: "Callback URL",
readonly: googleCallbackReadonly,
tooltip: googleCallbackTooltip,
placeholder: $organisation.googleCallbackUrl,
copyButton: true,
},
{
name: "sheetsURL",
label: "Sheets URL",
readonly: googleCallbackReadonly,
tooltip: googleCallbackTooltip,
placeholder: googleSheetsCallbackUrl,
copyButton: true,
},
],
}
$: OIDCConfigFields = {
Oidc: [
{ name: "configUrl", label: "Config URL" },
@ -133,15 +95,9 @@
const providers = { google, oidc }
// control the state of the save button depending on whether form has changed
let originalGoogleDoc
let originalOidcDoc
let googleSaveButtonDisabled
let oidcSaveButtonDisabled
$: {
isEqual(providers.google?.config, originalGoogleDoc?.config)
? (googleSaveButtonDisabled = true)
: (googleSaveButtonDisabled = false)
// delete the callback url which is never saved to the oidc
// config doc, to ensure an accurate comparison
delete providers.oidc?.config.configs[0].callbackURL
@ -151,10 +107,6 @@
: (oidcSaveButtonDisabled = false)
}
$: googleComplete = !!(
providers.google?.config?.clientID && providers.google?.config?.clientSecret
)
$: oidcComplete = !!(
providers.oidc?.config?.configs[0].configUrl &&
providers.oidc?.config?.configs[0].clientID &&
@ -230,30 +182,6 @@
originalOidcDoc = cloneDeep(providers.oidc)
}
async function saveGoogle() {
if (!googleComplete) {
notifications.error(
`Please fill in all required ${ConfigTypes.Google} fields`
)
return
}
const google = providers.google
try {
const res = await saveConfig(google)
providers[res.type]._rev = res._rev
providers[res.type]._id = res._id
notifications.success(`Settings saved`)
} catch (e) {
notifications.error(e.message)
return
}
googleSaveButtonDisabled = true
originalGoogleDoc = cloneDeep(providers.google)
}
let defaultScopes = ["profile", "email", "offline_access"]
const refreshScopes = idx => {
@ -281,29 +209,6 @@
notifications.error("Error getting org config")
}
// Fetch Google config
let googleDoc
try {
googleDoc = await API.getConfig(ConfigTypes.Google)
} catch (error) {
notifications.error("Error fetching Google OAuth config")
}
if (!googleDoc?._id) {
providers.google = {
type: ConfigTypes.Google,
config: { activated: false },
}
originalGoogleDoc = cloneDeep(googleDoc)
} else {
// Default activated to true for older configs
if (googleDoc.config.activated === undefined) {
googleDoc.config.activated = true
}
originalGoogleDoc = cloneDeep(googleDoc)
providers.google = googleDoc
}
googleCallbackUrl = providers?.google?.config?.callbackURL
// Get the list of user uploaded logos and push it to the dropdown options.
// This needs to be done before the config call so they're available when
// the dropdown renders.
@ -395,62 +300,7 @@
> before enabling this feature.
</Body>
</Layout>
{#if providers.google}
<Divider />
<Layout gap="XS" noPadding>
<Heading size="S">
<div class="provider-title">
<GoogleLogo />
<span>Google</span>
</div>
</Heading>
<Body size="S">
To allow users to authenticate using their Google accounts, fill out the
fields below. Read the <Link
size="M"
href={"https://docs.budibase.com/docs/sso-with-google"}
>documentation</Link
> for more information.
</Body>
</Layout>
<Layout gap="XS" noPadding>
{#each GoogleConfigFields.Google as field}
<div class="form-row">
<Label size="L" tooltip={field.tooltip}>{field.label}</Label>
<div class="inputContainer">
<div class="input">
<Input
bind:value={providers.google.config[field.name]}
readonly={field.readonly}
placeholder={field.placeholder}
/>
</div>
{#if field.copyButton}
<div
class="copy"
on:click={() => copyToClipboard(field.placeholder)}
>
<Icon size="S" name="Copy" />
</div>
{/if}
</div>
</div>
{/each}
<div class="form-row">
<Label size="L">Activated</Label>
<Toggle text="" bind:value={providers.google.config.activated} />
</div>
</Layout>
<div>
<Button
disabled={googleSaveButtonDisabled}
cta
on:click={() => saveGoogle()}
>
Save
</Button>
</div>
{/if}
<Google />
{#if providers.oidc}
<Divider />
<Layout gap="XS" noPadding>