mirror of https://github.com/Budibase/budibase.git
committed by
GitHub
17 changed files with 526 additions and 28 deletions
@ -0,0 +1,13 @@ |
|||
<script> |
|||
import { AUTH_TYPE_LABELS } from "./authTypes" |
|||
|
|||
export let value |
|||
|
|||
const renderAuthType = value => { |
|||
return AUTH_TYPE_LABELS.filter(type => type.value === value).map( |
|||
type => type.label |
|||
) |
|||
} |
|||
</script> |
|||
|
|||
{renderAuthType(value)} |
|||
@ -0,0 +1,65 @@ |
|||
<script> |
|||
import { Table, Modal, Layout, ActionButton } from "@budibase/bbui" |
|||
import AuthTypeRenderer from "./AuthTypeRenderer.svelte" |
|||
import RestAuthenticationModal from "./RestAuthenticationModal.svelte" |
|||
import { uuid } from "builderStore/uuid" |
|||
|
|||
export let configs = [] |
|||
|
|||
let currentConfig = null |
|||
let modal |
|||
|
|||
const schema = { |
|||
name: "", |
|||
type: "", |
|||
} |
|||
|
|||
const openConfigModal = config => { |
|||
currentConfig = config |
|||
modal.show() |
|||
} |
|||
|
|||
const onConfirm = config => { |
|||
if (currentConfig) { |
|||
configs = configs.map(c => { |
|||
// replace the current config with the new one |
|||
if (c._id === currentConfig._id) { |
|||
return config |
|||
} |
|||
return c |
|||
}) |
|||
} else { |
|||
config._id = uuid() |
|||
configs = [...configs, config] |
|||
} |
|||
} |
|||
|
|||
const onRemove = () => { |
|||
configs = configs.filter(c => { |
|||
return c._id !== currentConfig._id |
|||
}) |
|||
} |
|||
</script> |
|||
|
|||
<Modal bind:this={modal}> |
|||
<RestAuthenticationModal {configs} {currentConfig} {onConfirm} {onRemove} /> |
|||
</Modal> |
|||
|
|||
<Layout gap="S" noPadding> |
|||
{#if configs && configs.length > 0} |
|||
<Table |
|||
on:click={({ detail }) => openConfigModal(detail)} |
|||
{schema} |
|||
data={configs} |
|||
allowEditColumns={false} |
|||
allowEditRows={false} |
|||
allowSelectRows={false} |
|||
customRenderers={[{ column: "type", component: AuthTypeRenderer }]} |
|||
/> |
|||
{/if} |
|||
<div> |
|||
<ActionButton on:click={() => openConfigModal()} con="Add" |
|||
>Add authentication</ActionButton |
|||
> |
|||
</div> |
|||
</Layout> |
|||
@ -0,0 +1,218 @@ |
|||
<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 onRemove |
|||
|
|||
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 (currentConfig) { |
|||
newConfig._id = currentConfig._id |
|||
} |
|||
|
|||
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"} |
|||
size="M" |
|||
showSecondaryButton={!!currentConfig} |
|||
secondaryButtonText={"Remove"} |
|||
secondaryAction={onRemove} |
|||
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> |
|||
@ -0,0 +1,15 @@ |
|||
export const AUTH_TYPES = { |
|||
BASIC: "basic", |
|||
BEARER: "bearer", |
|||
} |
|||
|
|||
export const AUTH_TYPE_LABELS = [ |
|||
{ |
|||
label: "Basic Auth", |
|||
value: AUTH_TYPES.BASIC, |
|||
}, |
|||
{ |
|||
label: "Bearer Token", |
|||
value: AUTH_TYPES.BEARER, |
|||
}, |
|||
] |
|||
@ -1,6 +1,6 @@ |
|||
export interface IntegrationBase { |
|||
create?(query: any): Promise<any[]|any> |
|||
read?(query: any): Promise<any[]|any> |
|||
update?(query: any): Promise<any[]|any> |
|||
delete?(query: any): Promise<any[]|any> |
|||
create?(query: any): Promise<any[] | any> |
|||
read?(query: any): Promise<any[] | any> |
|||
update?(query: any): Promise<any[] | any> |
|||
delete?(query: any): Promise<any[] | any> |
|||
} |
|||
|
|||
Loading…
Reference in new issue