Allow user uploaded icons in oidc config
This commit is contained in:
parent
0e6fb73b9e
commit
37b1200051
|
@ -20,5 +20,6 @@ exports.Configs = {
|
|||
ACCOUNT: "account",
|
||||
SMTP: "smtp",
|
||||
GOOGLE: "google",
|
||||
OIDC: "oidc"
|
||||
OIDC: "oidc",
|
||||
OIDC_LOGOS:"oidc_logos"
|
||||
}
|
||||
|
|
|
@ -10,18 +10,20 @@
|
|||
export let disabled = false
|
||||
export let error = null
|
||||
export let fieldText = ""
|
||||
export let fieldIcon = ""
|
||||
export let isPlaceholder = false
|
||||
export let placeholderOption = null
|
||||
export let options = []
|
||||
export let callbackOptionValue = null
|
||||
export let isOptionSelected = () => false
|
||||
export let onSelectOption = () => {}
|
||||
export let getOptionLabel = option => option
|
||||
export let getOptionValue = option => option
|
||||
export let getOptionIcon = option => option
|
||||
export let open = false
|
||||
export let readonly = false
|
||||
export let quiet = false
|
||||
export let autoWidth = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const onClick = () => {
|
||||
dispatch("click")
|
||||
|
@ -30,6 +32,7 @@
|
|||
}
|
||||
open = true
|
||||
}
|
||||
console.log(fieldIcon)
|
||||
</script>
|
||||
|
||||
<button
|
||||
|
@ -42,6 +45,12 @@
|
|||
aria-haspopup="listbox"
|
||||
on:mousedown={onClick}
|
||||
>
|
||||
{#if fieldIcon}
|
||||
<span class="icon-Placeholder-Padding">
|
||||
<img src={fieldIcon} alt="test" width="20" height="15" />
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
<span
|
||||
class="spectrum-Picker-label"
|
||||
class:is-placeholder={isPlaceholder}
|
||||
|
@ -104,6 +113,16 @@
|
|||
tabindex="0"
|
||||
on:click={() => onSelectOption(getOptionValue(option, idx))}
|
||||
>
|
||||
{#if getOptionIcon(option, idx)}
|
||||
<span class="icon-Padding">
|
||||
<img
|
||||
src={getOptionIcon(option, idx)}
|
||||
alt="test"
|
||||
width="20"
|
||||
height="15"
|
||||
/>
|
||||
</span>
|
||||
{/if}
|
||||
<span class="spectrum-Menu-itemLabel"
|
||||
>{getOptionLabel(option, idx)}</span
|
||||
>
|
||||
|
@ -148,4 +167,12 @@
|
|||
.spectrum-Picker-label.auto-width.is-placeholder {
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.icon-Padding {
|
||||
padding-right: 10px;
|
||||
}
|
||||
.icon-Placeholder-Padding {
|
||||
padding-top: 5px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
export let disabled = false
|
||||
export let error = null
|
||||
export let options = []
|
||||
export let callbackOptionValue = null
|
||||
export let getOptionLabel = option => option
|
||||
export let getOptionValue = option => option
|
||||
export let getOptionIcon = option => option
|
||||
export let readonly = false
|
||||
export let quiet = false
|
||||
export let autoWidth = false
|
||||
|
@ -17,6 +19,7 @@
|
|||
const dispatch = createEventDispatcher()
|
||||
let open = false
|
||||
$: fieldText = getFieldText(value, options, placeholder)
|
||||
$: fieldIcon = getFieldIcon(value, options, placeholder)
|
||||
|
||||
const getFieldText = (value, options, placeholder) => {
|
||||
// Always use placeholder if no value
|
||||
|
@ -36,6 +39,17 @@
|
|||
return index !== -1 ? getOptionLabel(options[index], index) : value
|
||||
}
|
||||
|
||||
const getFieldIcon = (value, options) => {
|
||||
// Wait for options to load if there is a value but no options
|
||||
if (!options?.length) {
|
||||
return ""
|
||||
}
|
||||
const index = options.findIndex(
|
||||
(option, idx) => getOptionValue(option, idx) === value
|
||||
)
|
||||
return index !== -1 ? getOptionIcon(options[index], index) : value
|
||||
}
|
||||
|
||||
const selectOption = value => {
|
||||
dispatch("change", value)
|
||||
open = false
|
||||
|
@ -55,6 +69,9 @@
|
|||
{autoWidth}
|
||||
{getOptionLabel}
|
||||
{getOptionValue}
|
||||
{getOptionIcon}
|
||||
{fieldIcon}
|
||||
{callbackOptionValue}
|
||||
isPlaceholder={value == null || value === ""}
|
||||
placeholderOption={placeholder}
|
||||
isOptionSelected={option => option === value}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
export let options = []
|
||||
export let getOptionLabel = option => extractProperty(option, "label")
|
||||
export let getOptionValue = option => extractProperty(option, "value")
|
||||
export let getOptionIcon = option => extractObjectProperty(option, "icon")
|
||||
export let quiet = false
|
||||
export let autoWidth = false
|
||||
|
||||
|
@ -21,6 +22,13 @@
|
|||
value = e.detail
|
||||
dispatch("change", e.detail)
|
||||
}
|
||||
|
||||
const extractObjectProperty = (value, property) => {
|
||||
if (value && typeof value === "object") {
|
||||
return value[property]
|
||||
}
|
||||
}
|
||||
|
||||
const extractProperty = (value, property) => {
|
||||
if (value && typeof value === "object") {
|
||||
return value[property]
|
||||
|
@ -41,6 +49,7 @@
|
|||
{autoWidth}
|
||||
{getOptionLabel}
|
||||
{getOptionValue}
|
||||
{getOptionIcon}
|
||||
on:change={onChange}
|
||||
on:click
|
||||
/>
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -1,7 +1,7 @@
|
|||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 268 268"
|
||||
width="25"
|
||||
height="25 "
|
||||
viewBox="0 0 100 100"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
|
@ -12,9 +12,4 @@
|
|||
/>
|
||||
<path d="M43,90v-75l14,-9v75z" fill="#f60" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="268" height="268" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 432 B After Width: | Height: | Size: 319 B |
|
@ -1,6 +1,11 @@
|
|||
<script>
|
||||
import GoogleLogo from "./_logos/Google.svelte"
|
||||
import OIDCLogo from "./_logos/OIDC.svelte"
|
||||
import OidcLogo from "./_logos/OIDC.svelte"
|
||||
import MicrosoftLogo from "assets/microsoft-logo.png"
|
||||
import OracleLogo from "assets/oracle-logo.png"
|
||||
import Auth0Logo from "assets/auth0-logo.png"
|
||||
import OidcLogoPng from "assets/oidc-logo.png"
|
||||
|
||||
import {
|
||||
Button,
|
||||
Heading,
|
||||
|
@ -10,10 +15,13 @@
|
|||
Layout,
|
||||
Input,
|
||||
Body,
|
||||
Select
|
||||
Select,
|
||||
Dropzone,
|
||||
} from "@budibase/bbui"
|
||||
import { onMount } from "svelte"
|
||||
import api from "builderStore/api"
|
||||
import { writable } from "svelte/store"
|
||||
import { organisation } from "stores/portal"
|
||||
|
||||
const ConfigTypes = {
|
||||
Google: "google",
|
||||
|
@ -34,51 +42,70 @@
|
|||
}
|
||||
|
||||
const OIDCConfigFields = {
|
||||
Oidc: [
|
||||
"issuer",
|
||||
"authUrl",
|
||||
"tokenUrl",
|
||||
"userInfoUrl",
|
||||
"clientId",
|
||||
"clientSecret",
|
||||
"callbackUrl",
|
||||
"name"
|
||||
],
|
||||
Oidc: ["configUrl", "clientId", "clientSecret"],
|
||||
}
|
||||
const OIDCConfigLabels = {
|
||||
Oidc: {
|
||||
issuer: "Issuer",
|
||||
authUrl: "Authorization URL",
|
||||
tokenUrl: "Token URL",
|
||||
userInfoUrl: "User Info URL",
|
||||
configUrl: "Config URL",
|
||||
clientId: "Client ID",
|
||||
clientSecret: "Client Secret",
|
||||
callbackUrl: "Callback URL",
|
||||
name: "Name"
|
||||
},
|
||||
}
|
||||
|
||||
let iconDropdownOptions = [
|
||||
{
|
||||
label: "Azure AD",
|
||||
value: "Active Directory",
|
||||
icon: MicrosoftLogo,
|
||||
},
|
||||
{ label: "Oracle", value: "Oracle", icon: OracleLogo },
|
||||
{ label: "Auth0", value: "Auth0", icon: Auth0Logo },
|
||||
{ label: "OIDC", value: "Auth0", icon: OidcLogoPng },
|
||||
|
||||
{ label: "Upload your own", value: "Upload" },
|
||||
]
|
||||
|
||||
let fileinput
|
||||
let image
|
||||
let google
|
||||
let oidc
|
||||
|
||||
async function uploadLogo(file) {
|
||||
let data = new FormData()
|
||||
data.append("file", file)
|
||||
const res = await api.post(
|
||||
`/api/admin/configs/upload/oidc_logos/${file.name}`,
|
||||
data,
|
||||
{}
|
||||
)
|
||||
return await res.json()
|
||||
}
|
||||
|
||||
const onFileSelected = e => {
|
||||
image = e.target.files[0]
|
||||
}
|
||||
|
||||
const providers = { google, oidc }
|
||||
|
||||
async function save(docs) {
|
||||
uploadLogo(image)
|
||||
let calls = []
|
||||
docs.forEach(element => {
|
||||
calls.push(api.post(`/api/admin/configs`, element))
|
||||
})
|
||||
Promise.all(calls)
|
||||
.then(responses => {
|
||||
return Promise.all(responses.map(response => {
|
||||
return Promise.all(
|
||||
responses.map(response => {
|
||||
return response.json()
|
||||
}))
|
||||
}).then(data => {
|
||||
})
|
||||
)
|
||||
})
|
||||
.then(data => {
|
||||
data.forEach(res => {
|
||||
providers[res.type]._rev = res._rev
|
||||
providers[res.type]._id = res._id
|
||||
})
|
||||
//res.json()._rev = res.json()._rev
|
||||
//res.json().id = res.json().id
|
||||
notifications.success(`Settings saved.`)
|
||||
})
|
||||
.catch(err => {
|
||||
|
@ -114,8 +141,15 @@
|
|||
} else {
|
||||
providers.oidc = oidcDoc
|
||||
}
|
||||
const res = await api.get(`/api/admin/configs/oidc_logos`)
|
||||
const configSettings = await res.json()
|
||||
console.log(configSettings)
|
||||
const logoKeys = Object.keys(configSettings.config)
|
||||
logoKeys.map(logoKey => {
|
||||
const logoUrl = configSettings.config[logoKey]
|
||||
iconDropdownOptions.unshift({label: logoKey, value: logoUrl, icon: logoUrl})
|
||||
})
|
||||
})
|
||||
let fileInput
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -156,7 +190,7 @@
|
|||
<Layout gap="XS" noPadding>
|
||||
<Heading size="S">
|
||||
<span>
|
||||
<GoogleLogo />
|
||||
<OidcLogo />
|
||||
OpenID Connect
|
||||
</span>
|
||||
</Heading>
|
||||
|
@ -171,21 +205,37 @@
|
|||
<Input bind:value={providers.oidc.config[field]} />
|
||||
</div>
|
||||
{/each}
|
||||
<br />
|
||||
<Body size="S">
|
||||
To customize your login button, fill out the fields below.
|
||||
</Body>
|
||||
<div class="form-row">
|
||||
<Label size="L">{OIDCConfigLabels.Oidc['name']}</Label>
|
||||
<Select
|
||||
options={["Upload File"]}
|
||||
placeholder={null}
|
||||
/>
|
||||
|
||||
<Label size="L">Name</Label>
|
||||
<Input bind:value={providers.oidc.config["name"]} />
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<Label size="L">Icon</Label>
|
||||
|
||||
<Select
|
||||
label=""
|
||||
bind:value={providers.oidc.config["iconName"]}
|
||||
options={iconDropdownOptions}
|
||||
on:change={e => (e.detail === "Upload" && fileinput.click())}
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
style="display:none"
|
||||
type="file"
|
||||
accept=".jpg, .jpeg, .png"
|
||||
on:change={e => onFileSelected(e)}
|
||||
bind:this={fileinput}
|
||||
/>
|
||||
</Layout>
|
||||
{/if}
|
||||
<div>
|
||||
<Button cta on:click={() => save([providers.google, providers.oidc])}>Save</Button>
|
||||
<Button cta on:click={() => save([providers.google, providers.oidc])}
|
||||
>Save</Button
|
||||
>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
|
@ -201,4 +251,8 @@
|
|||
align-items: center;
|
||||
gap: var(--spacing-s);
|
||||
}
|
||||
|
||||
input {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -146,7 +146,7 @@ exports.upload = async function (ctx) {
|
|||
}
|
||||
}
|
||||
const url = `/${bucket}/${key}`
|
||||
cfgStructure.config[`${name}Url`] = url
|
||||
cfgStructure.config[`${name}`] = url
|
||||
// write back to db with url updated
|
||||
await db.put(cfgStructure)
|
||||
|
||||
|
@ -192,8 +192,6 @@ exports.configChecklist = async function (ctx) {
|
|||
const oidcConfig = await getScopedFullConfig(db, {
|
||||
type: Configs.OIDC,
|
||||
})
|
||||
|
||||
|
||||
// They have set up an admin user
|
||||
const users = await db.allDocs(
|
||||
getGlobalUserParams(null, {
|
||||
|
|
|
@ -79,7 +79,7 @@ function buildUploadValidation() {
|
|||
// prettier-ignore
|
||||
return joiValidator.params(Joi.object({
|
||||
type: Joi.string().valid(...Object.values(Configs)).required(),
|
||||
name: Joi.string().valid(...Object.values(ConfigUploads)).required(),
|
||||
name: Joi.string().required(),
|
||||
}).required())
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ exports.Configs = Configs
|
|||
|
||||
exports.ConfigUploads = {
|
||||
LOGO: "logo",
|
||||
OIDC_LOGO: "oidc_logo"
|
||||
OIDC_LOGO: "oidc_logo",
|
||||
}
|
||||
|
||||
const TemplateTypes = {
|
||||
|
|
Loading…
Reference in New Issue