Auth config forms
This commit is contained in:
parent
01ab892a00
commit
e8755b6854
|
@ -21,6 +21,7 @@
|
||||||
export let showSecondaryButton = false
|
export let showSecondaryButton = false
|
||||||
export let secondaryButtonText = undefined
|
export let secondaryButtonText = undefined
|
||||||
export let secondaryAction = undefined
|
export let secondaryAction = undefined
|
||||||
|
export let secondaryButtonWarning = false
|
||||||
|
|
||||||
const { hide, cancel } = getContext(Context.Modal)
|
const { hide, cancel } = getContext(Context.Modal)
|
||||||
let loading = false
|
let loading = false
|
||||||
|
@ -88,8 +89,11 @@
|
||||||
|
|
||||||
{#if showSecondaryButton && secondaryButtonText && secondaryAction}
|
{#if showSecondaryButton && secondaryButtonText && secondaryAction}
|
||||||
<div class="secondary-action">
|
<div class="secondary-action">
|
||||||
<Button group secondary on:click={secondary}
|
<Button
|
||||||
>{secondaryButtonText}</Button
|
group
|
||||||
|
secondary
|
||||||
|
warning={secondaryButtonWarning}
|
||||||
|
on:click={secondary}>{secondaryButtonText}</Button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
<Body size="S">
|
<Body size="S">
|
||||||
Create an authentication config that can be shared with queries.
|
Create an authentication config that can be shared with queries.
|
||||||
</Body>
|
</Body>
|
||||||
<RestAuthenticationBuilder bind:authConfigs={datasource.config.authConfigs} />
|
<RestAuthenticationBuilder bind:configs={datasource.config.authConfigs} />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.section-header {
|
.section-header {
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
|
|
||||||
export let value
|
export let value
|
||||||
|
|
||||||
const renderAuthType = () => {
|
const renderAuthType = value => {
|
||||||
return AUTH_TYPE_LABELS.filter(type => type.value === value).map(
|
return AUTH_TYPE_LABELS.filter(type => type.value === value).map(
|
||||||
type => type.label
|
type => type.label
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{renderAuthType()}
|
{renderAuthType(value)}
|
||||||
|
|
|
@ -1,22 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import {
|
import { Table, Modal, Layout, ActionButton } from "@budibase/bbui"
|
||||||
Table,
|
|
||||||
Modal,
|
|
||||||
ModalContent,
|
|
||||||
Layout,
|
|
||||||
ActionButton,
|
|
||||||
Select,
|
|
||||||
Body,
|
|
||||||
Input,
|
|
||||||
} from "@budibase/bbui"
|
|
||||||
import AuthTypeRenderer from "./AuthTypeRenderer.svelte"
|
import AuthTypeRenderer from "./AuthTypeRenderer.svelte"
|
||||||
import { AUTH_TYPE_LABELS, AUTH_TYPES } from "./authTypes"
|
import RestAuthenticationModal from "./RestAuthenticationModal.svelte"
|
||||||
|
|
||||||
export let authConfigs = []
|
export let configs = []
|
||||||
|
|
||||||
|
let currentConfig = null
|
||||||
let modal
|
let modal
|
||||||
let currentConfig
|
|
||||||
let isNew = false
|
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
name: "",
|
name: "",
|
||||||
|
@ -24,73 +14,44 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const openConfigModal = config => {
|
const openConfigModal = config => {
|
||||||
if (!config) {
|
currentConfig = config
|
||||||
currentConfig = {
|
|
||||||
config: {},
|
|
||||||
}
|
|
||||||
isNew = true
|
|
||||||
} else {
|
|
||||||
currentConfig = { ...config }
|
|
||||||
isNew = false
|
|
||||||
}
|
|
||||||
modal.show()
|
modal.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onConfirm = () => {
|
const onConfirm = config => {
|
||||||
if (isNew) {
|
if (currentConfig) {
|
||||||
authConfigs.push(currentConfig)
|
// TODO: Update with _id
|
||||||
} else {
|
configs = configs.map(c => {
|
||||||
authConfigs = authConfigs.map(c => {
|
// replace the current config with the new one
|
||||||
if (c.name === currentConfig.name) {
|
if (c.name === currentConfig.name) {
|
||||||
return currentConfig
|
return config
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
configs.push(config)
|
||||||
|
configs = [...configs]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onCancel = () => {
|
const onDelete = () => {
|
||||||
currentConfig = {}
|
// TODO: Update with _id
|
||||||
|
configs = configs.filter(c => {
|
||||||
|
return c.name !== currentConfig.name
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
<ModalContent
|
<RestAuthenticationModal {configs} {currentConfig} {onConfirm} {onDelete} />
|
||||||
title={isNew ? "Add Authentication" : "Update Authentication"}
|
|
||||||
{onConfirm}
|
|
||||||
{onCancel}
|
|
||||||
confirmText={isNew ? "Add" : "Update"}
|
|
||||||
cancelText="Cancel"
|
|
||||||
size="M"
|
|
||||||
>
|
|
||||||
<Layout gap="S">
|
|
||||||
<Body size="S">
|
|
||||||
The authorization header will be automatically generated when you
|
|
||||||
sendthe request.
|
|
||||||
</Body>
|
|
||||||
<Select
|
|
||||||
label="Type"
|
|
||||||
bind:value={currentConfig.type}
|
|
||||||
options={AUTH_TYPE_LABELS}
|
|
||||||
on:change={({ detail }) => (currentConfig.type = detail)}
|
|
||||||
/>
|
|
||||||
{#if currentConfig.type === AUTH_TYPES.BASIC}
|
|
||||||
<Input label="Username" bind:value={currentConfig.config.username} />
|
|
||||||
<Input label="Password" bind:value={currentConfig.config.password} />
|
|
||||||
{/if}
|
|
||||||
{#if currentConfig.type === AUTH_TYPES.BEARER}
|
|
||||||
<Input label="Token" bind:value={currentConfig.config.token} />
|
|
||||||
{/if}
|
|
||||||
</Layout>
|
|
||||||
</ModalContent>
|
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Layout gap="S" noPadding>
|
<Layout gap="S" noPadding>
|
||||||
{#if authConfigs && authConfigs.length > 0}
|
{#if configs && configs.length > 0}
|
||||||
<Table
|
<Table
|
||||||
on:click={({ detail }) => openConfigModal(detail)}
|
on:click={({ detail }) => openConfigModal(detail)}
|
||||||
{schema}
|
{schema}
|
||||||
data={authConfigs}
|
data={configs}
|
||||||
allowEditColumns={false}
|
allowEditColumns={false}
|
||||||
allowEditRows={false}
|
allowEditRows={false}
|
||||||
allowSelectRows={false}
|
allowSelectRows={false}
|
||||||
|
@ -103,6 +64,3 @@
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -0,0 +1,215 @@
|
||||||
|
<script>
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
import { ModalContent, Layout, Select, Body, Input } from "@budibase/bbui"
|
||||||
|
import { AUTH_TYPE_LABELS, AUTH_TYPES } from "./authTypes"
|
||||||
|
|
||||||
|
export let configs
|
||||||
|
export let currentConfig
|
||||||
|
export let onConfirm
|
||||||
|
export let onDelete
|
||||||
|
|
||||||
|
let form = {
|
||||||
|
basic: {},
|
||||||
|
bearer: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
let errors = {
|
||||||
|
basic: {},
|
||||||
|
bearer: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
let blurred = {
|
||||||
|
basic: {},
|
||||||
|
bearer: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasErrors = false
|
||||||
|
let hasChanged = false
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (currentConfig) {
|
||||||
|
deconstructConfig()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* map the current config's data into the form by type
|
||||||
|
*/
|
||||||
|
const deconstructConfig = () => {
|
||||||
|
form.name = currentConfig.name
|
||||||
|
form.type = currentConfig.type
|
||||||
|
|
||||||
|
if (currentConfig.type === AUTH_TYPES.BASIC) {
|
||||||
|
form.basic = {
|
||||||
|
...currentConfig.config,
|
||||||
|
}
|
||||||
|
} else if (currentConfig.type === AUTH_TYPES.BEARER) {
|
||||||
|
form.bearer = {
|
||||||
|
...currentConfig.config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* map the form into a new config to save by type
|
||||||
|
*/
|
||||||
|
const constructConfig = () => {
|
||||||
|
const newConfig = {
|
||||||
|
name: form.name,
|
||||||
|
type: form.type,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (form.type === AUTH_TYPES.BASIC) {
|
||||||
|
newConfig.config = {
|
||||||
|
...form.basic,
|
||||||
|
}
|
||||||
|
} else if (form.type === AUTH_TYPES.BEARER) {
|
||||||
|
newConfig.config = {
|
||||||
|
...form.bearer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compare the existing config with the new config to see if there are any changes
|
||||||
|
*/
|
||||||
|
const checkChanged = () => {
|
||||||
|
if (currentConfig) {
|
||||||
|
hasChanged =
|
||||||
|
JSON.stringify(currentConfig) !== JSON.stringify(constructConfig())
|
||||||
|
} else {
|
||||||
|
hasChanged = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkErrors = () => {
|
||||||
|
hasErrors = false
|
||||||
|
|
||||||
|
// NAME
|
||||||
|
const nameError = () => {
|
||||||
|
// Unique name
|
||||||
|
if (form.name) {
|
||||||
|
errors.name =
|
||||||
|
// check for duplicate excluding the current config
|
||||||
|
configs.find(
|
||||||
|
c => c.name === form.name && c.name !== currentConfig?.name
|
||||||
|
) !== undefined
|
||||||
|
? "Name must be unique"
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
// Name required
|
||||||
|
else {
|
||||||
|
errors.name = "Name is required"
|
||||||
|
}
|
||||||
|
return !!errors.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// TYPE
|
||||||
|
const typeError = () => {
|
||||||
|
errors.type = form.type ? null : "Type is required"
|
||||||
|
return !!errors.type
|
||||||
|
}
|
||||||
|
|
||||||
|
// BASIC AUTH
|
||||||
|
const basicAuthErrors = () => {
|
||||||
|
errors.basic.username = form.basic.username
|
||||||
|
? null
|
||||||
|
: "Username is required"
|
||||||
|
errors.basic.password = form.basic.password
|
||||||
|
? null
|
||||||
|
: "Password is required"
|
||||||
|
|
||||||
|
return !!(errors.basic.username || errors.basic.password || commonError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BEARER TOKEN
|
||||||
|
const bearerTokenErrors = () => {
|
||||||
|
errors.bearer.token = form.bearer.token ? null : "Token is required"
|
||||||
|
return !!(errors.bearer.token || commonError)
|
||||||
|
}
|
||||||
|
|
||||||
|
const commonError = nameError() || typeError()
|
||||||
|
if (form.type === AUTH_TYPES.BASIC) {
|
||||||
|
hasErrors = basicAuthErrors() || commonError
|
||||||
|
} else if (form.type === AUTH_TYPES.BEARER) {
|
||||||
|
hasErrors = bearerTokenErrors() || commonError
|
||||||
|
} else {
|
||||||
|
hasErrors = !!commonError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFieldChange = () => {
|
||||||
|
checkErrors()
|
||||||
|
checkChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
const onConfirmInternal = () => {
|
||||||
|
onConfirm(constructConfig())
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ModalContent
|
||||||
|
title={currentConfig ? "Update Authentication" : "Add Authentication"}
|
||||||
|
onConfirm={onConfirmInternal}
|
||||||
|
confirmText={currentConfig ? "Update" : "Add"}
|
||||||
|
disabled={hasErrors || !hasChanged}
|
||||||
|
cancelText={"Cancel"}
|
||||||
|
warning={true}
|
||||||
|
size="M"
|
||||||
|
showSecondaryButton={!!currentConfig}
|
||||||
|
secondaryButtonText={"Delete"}
|
||||||
|
secondaryAction={onDelete}
|
||||||
|
secondaryButtonWarning={true}
|
||||||
|
>
|
||||||
|
<Layout gap="S">
|
||||||
|
<Body size="S">
|
||||||
|
The authorization header will be automatically generated when you send the
|
||||||
|
request.
|
||||||
|
</Body>
|
||||||
|
<Input
|
||||||
|
label="Name"
|
||||||
|
bind:value={form.name}
|
||||||
|
on:change={onFieldChange}
|
||||||
|
on:blur={() => (blurred.name = true)}
|
||||||
|
error={blurred.name ? errors.name : null}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label="Type"
|
||||||
|
bind:value={form.type}
|
||||||
|
on:change={onFieldChange}
|
||||||
|
options={AUTH_TYPE_LABELS}
|
||||||
|
on:blur={() => (blurred.type = true)}
|
||||||
|
error={blurred.type ? errors.type : null}
|
||||||
|
/>
|
||||||
|
{#if form.type === AUTH_TYPES.BASIC}
|
||||||
|
<Input
|
||||||
|
label="Username"
|
||||||
|
bind:value={form.basic.username}
|
||||||
|
on:change={onFieldChange}
|
||||||
|
on:blur={() => (blurred.basic.username = true)}
|
||||||
|
error={blurred.basic.username ? errors.basic.username : null}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
label="Password"
|
||||||
|
bind:value={form.basic.password}
|
||||||
|
on:change={onFieldChange}
|
||||||
|
on:blur={() => (blurred.basic.password = true)}
|
||||||
|
error={blurred.basic.password ? errors.basic.password : null}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{#if form.type === AUTH_TYPES.BEARER}
|
||||||
|
<Input
|
||||||
|
label="Token"
|
||||||
|
bind:value={form.bearer.token}
|
||||||
|
on:change={onFieldChange}
|
||||||
|
on:blur={() => (blurred.bearer.token = true)}
|
||||||
|
error={blurred.bearer.token ? errors.bearer.token : null}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</Layout>
|
||||||
|
</ModalContent>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
Loading…
Reference in New Issue