update datasource config to allow env var selection

This commit is contained in:
Peter Clement 2023-01-19 16:43:06 +00:00
parent 5ed038406a
commit 47663ca395
13 changed files with 331 additions and 11 deletions

View File

@ -0,0 +1,241 @@
<script>
import "@spectrum-css/textfield/dist/index-vars.css"
import { createEventDispatcher, onMount } from "svelte"
import clickOutside from "../../Actions/click_outside"
import Divider from "../../Divider/Divider.svelte"
import Body from "../../Typography/Body.svelte"
export let value = null
export let placeholder = null
export let type = "text"
export let disabled = false
export let id = null
export let readonly = false
export let updateOnChange = true
export let dataCy
export let align
export let autofocus = false
export let variables
export let showModal
$: console.log(showModal)
const dispatch = createEventDispatcher()
let field
let focus = false
let open = false
const updateValue = newValue => {
if (readonly) {
return
}
if (type === "number") {
const float = parseFloat(newValue)
newValue = isNaN(float) ? null : float
}
dispatch("change", newValue)
}
const onFocus = () => {
if (readonly) {
return
}
focus = true
}
const onBlur = event => {
if (readonly) {
return
}
focus = false
updateValue(event.target.value)
}
const onInput = event => {
if (readonly || !updateOnChange) {
return
}
updateValue(event.target.value)
}
const updateValueOnEnter = event => {
if (readonly) {
return
}
if (event.key === "Enter") {
updateValue(event.target.value)
}
}
const handleOutsideClick = event => {
if (open) {
event.stopPropagation()
open = false
dispatch("closed")
}
}
const handleVarSelect = variable => {
console.log(variable)
open = false
updateValue(`{{ ${variable} }}`)
}
onMount(() => {
focus = autofocus
if (focus) field.focus()
})
</script>
<div class="spectrum-InputGroup">
<div
class:is-focused={focus}
class="spectrum-Textfield spectrum-InputGroup-textfield "
>
<svg
class="hoverable icon-position spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
focusable="false"
aria-hidden="true"
on:click={() => (open = true)}
>
<use xlink:href="#spectrum-icon-18-Key" />
</svg>
<input
bind:this={field}
{disabled}
{readonly}
{id}
data-cy={dataCy}
value={value || ""}
placeholder={placeholder || ""}
on:click
on:blur
on:focus
on:input
on:keyup
on:blur={onBlur}
on:focus={onFocus}
on:input={onInput}
on:keyup={updateValueOnEnter}
{type}
class="spectrum-Textfield-input"
style={align ? `text-align: ${align};` : ""}
inputmode={type === "number" ? "decimal" : "text"}
/>
</div>
{#if open}
<div
use:clickOutside={handleOutsideClick}
class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open"
>
<ul class="spectrum-Menu" role="listbox">
{#if variables.length}
{#each variables as variable, idx}
<li
class="spectrum-Menu-item"
role="option"
aria-selected="true"
tabindex="0"
on:click={() => handleVarSelect(variable.name)}
>
<span class="spectrum-Menu-itemLabel">
<div class="primary-text">
{variable.name}
<span />
</div>
<svg
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
focusable="false"
aria-hidden="true"
>
<use xlink:href="#spectrum-css-icon-Checkmark100" />
</svg>
</span>
</li>
{/each}
{:else}
<li class="spectrum-Menu-item" role="option" aria-selected="true">
<span class="spectrum-Menu-itemLabel">
<div class="primary-text">
You don't have any environment variables yet
</div>
</span>
</li>
{/if}
</ul>
<Divider noMargin />
<div class="add-variable">
<svg
class="spectrum-Icon spectrum-Icon--sizeS "
focusable="false"
aria-hidden="true"
>
<use xlink:href="#spectrum-icon-18-Add" />
</svg>
<div on:click={() => showModal()} class="primary-text">
<Body size="S">Add Variable</Body>
</div>
</div>
</div>
{/if}
</div>
<style>
.spectrum-Textfield {
width: 100%;
}
input:disabled {
color: var(--spectrum-global-color-gray-600) !important;
-webkit-text-fill-color: var(--spectrum-global-color-gray-600) !important;
}
.icon-position {
position: absolute;
top: 20%;
right: 2%;
}
.hoverable:hover {
cursor: pointer;
color: var(--spectrum-global-color-blue-400);
}
.primary-text {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.spectrum-InputGroup {
min-width: 0;
width: 100%;
}
.spectrum-InputGroup :global(.spectrum-Search-input) {
border: none;
border-bottom: 1px solid var(--spectrum-global-color-gray-300);
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.spectrum-Popover {
max-height: 240px;
z-index: 999;
top: 100%;
}
.spectrum-Popover.spectrum-Popover--bottom.spectrum-Picker-popover.is-open {
width: 100%;
}
/* Fix focus borders to show only when opened */
.spectrum-Textfield-input {
border-color: var(--spectrum-global-color-gray-400) !important;
border-right-width: 1px;
}
.add-variable {
display: flex;
padding: var(--spacing-m) 0 var(--spacing-m) var(--spacing-m);
align-items: center;
gap: var(--spacing-s);
}
</style>

View File

@ -0,0 +1,48 @@
<script>
import Field from "./Field.svelte"
import EnvDropdown from "./Core/EnvDropdown.svelte"
import { createEventDispatcher } from "svelte"
export let value = null
export let label = null
export let labelPosition = "above"
export let placeholder = null
export let type = "text"
export let disabled = false
export let readonly = false
export let error = null
export let updateOnChange = true
export let quiet = false
export let dataCy
export let autofocus
export let variables
export let showModal
const dispatch = createEventDispatcher()
const onChange = e => {
value = e.detail
dispatch("change", e.detail)
}
</script>
<Field {label} {labelPosition} {error}>
<EnvDropdown
{dataCy}
{updateOnChange}
{error}
{disabled}
{readonly}
{value}
{placeholder}
{type}
{quiet}
{autofocus}
{variables}
{showModal}
on:change={onChange}
on:click
on:input
on:blur
on:focus
on:keyup
/>
</Field>

View File

@ -27,6 +27,7 @@ export { default as RadioGroup } from "./Form/RadioGroup.svelte"
export { default as Checkbox } from "./Form/Checkbox.svelte" export { default as Checkbox } from "./Form/Checkbox.svelte"
export { default as InputDropdown } from "./Form/InputDropdown.svelte" export { default as InputDropdown } from "./Form/InputDropdown.svelte"
export { default as PickerDropdown } from "./Form/PickerDropdown.svelte" export { default as PickerDropdown } from "./Form/PickerDropdown.svelte"
export { default as EnvDropdown } from "./Form/EnvDropdown.svelte"
export { default as DetailSummary } from "./DetailSummary/DetailSummary.svelte" export { default as DetailSummary } from "./DetailSummary/DetailSummary.svelte"
export { default as Popover } from "./Popover/Popover.svelte" export { default as Popover } from "./Popover/Popover.svelte"
export { default as ProgressBar } from "./ProgressBar/ProgressBar.svelte" export { default as ProgressBar } from "./ProgressBar/ProgressBar.svelte"

View File

@ -6,16 +6,22 @@
Toggle, Toggle,
Button, Button,
TextArea, TextArea,
Modal,
EnvDropdown,
} from "@budibase/bbui" } from "@budibase/bbui"
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte" import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
import { capitalise } from "helpers" import { capitalise } from "helpers"
import { IntegrationTypes } from "constants/backend" import { IntegrationTypes } from "constants/backend"
import { createValidationStore } from "helpers/validation/yup" import { createValidationStore } from "helpers/validation/yup"
import { createEventDispatcher } from "svelte" import { createEventDispatcher, onMount } from "svelte"
import { environment } from "stores/portal"
import CreateEditVariableModal from "components/portal/environment/CreateEditVariableModal.svelte"
export let datasource export let datasource
export let schema export let schema
export let creating export let creating
let createVariableModal
const validation = createValidationStore() const validation = createValidationStore()
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -60,6 +66,18 @@
} }
return capitalise(name) return capitalise(name)
} }
function save(data) {
environment.createVariable(data)
createVariableModal.hide()
}
function showModal() {
createVariableModal.show()
}
onMount(async () => {
await environment.loadVariables()
})
</script> </script>
<form> <form>
@ -103,7 +121,9 @@
{:else} {:else}
<div class="form-row"> <div class="form-row">
<Label>{getDisplayName(configKey)}</Label> <Label>{getDisplayName(configKey)}</Label>
<Input <EnvDropdown
{showModal}
variables={$environment.variables}
type={schema[configKey].type} type={schema[configKey].type}
on:change on:change
bind:value={config[configKey]} bind:value={config[configKey]}
@ -115,6 +135,10 @@
</Layout> </Layout>
</form> </form>
<Modal bind:this={createVariableModal}>
<CreateEditVariableModal {save} />
</Modal>
<style> <style>
.form-row { .form-row {
display: grid; display: grid;

View File

@ -122,6 +122,7 @@
// Adds a data binding to the expression // Adds a data binding to the expression
const addBinding = (binding, { forceJS } = {}) => { const addBinding = (binding, { forceJS } = {}) => {
console.log(binding)
if (usingJS || forceJS) { if (usingJS || forceJS) {
let js = decodeJSBinding(jsValue) let js = decodeJSBinding(jsValue)
js = addJSBinding(js, getCaretPosition(), binding.readableBinding) js = addJSBinding(js, getCaretPosition(), binding.readableBinding)

View File

@ -20,7 +20,7 @@
export let allowHelpers = true export let allowHelpers = true
export let updateOnChange = true export let updateOnChange = true
export let drawerLeft export let drawerLeft
$: console.log(bindings)
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
let bindingDrawer let bindingDrawer
let valid = true let valid = true
@ -28,6 +28,7 @@
$: readableValue = runtimeToReadableBinding(bindings, value) $: readableValue = runtimeToReadableBinding(bindings, value)
$: tempValue = readableValue $: tempValue = readableValue
$: console.log(tempValue)
$: isJS = isJSBinding(value) $: isJS = isJSBinding(value)
const saveBinding = () => { const saveBinding = () => {

View File

@ -105,7 +105,7 @@
> >
{#each fields as field, idx} {#each fields as field, idx}
<Input <Input
placeholder={keyPlaceholder} placeholder={"hello"}
readonly={readOnly} readonly={readOnly}
bind:value={field.name} bind:value={field.name}
on:blur={changed} on:blur={changed}

View File

@ -1,5 +1,6 @@
<script> <script>
import { ModalContent, Toggle, Body, InlineAlert } from "@budibase/bbui" import { ModalContent, Toggle, Body, InlineAlert } from "@budibase/bbui"
import { licensing } from "stores/portal"
export let app export let app
export let published export let published
@ -16,9 +17,11 @@
</script> </script>
<ModalContent {title} {confirmText} onConfirm={exportApp}> <ModalContent {title} {confirmText} onConfirm={exportApp}>
{#if licensing.environmentVariablesEnabled}
<InlineAlert <InlineAlert
header="Do not share your budibase application exports publicly as they may contain sensitive information such as database credentials or secret keys." header="Do not share your budibase application exports publicly as they may contain sensitive information such as database credentials or secret keys."
/> />
{/if}
<Body <Body
>Apps can be exported with or without data that is within internal tables - >Apps can be exported with or without data that is within internal tables -
select this below.</Body select this below.</Body

View File

@ -2,7 +2,7 @@
import { ActionButton, Modal } from "@budibase/bbui" import { ActionButton, Modal } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { environment } from "stores/portal" import { environment } from "stores/portal"
import CreateEditVariableModal from "./CreateEditVariableModal.svelte" import CreateEditVariableModal from "components/portal/environment/CreateEditVariableModal.svelte"
export let row export let row

View File

@ -13,7 +13,7 @@
} from "@budibase/bbui" } from "@budibase/bbui"
import { environment, licensing, auth, admin } from "stores/portal" import { environment, licensing, auth, admin } from "stores/portal"
import { onMount } from "svelte" import { onMount } from "svelte"
import CreateEditVariableModal from "./_components/CreateEditVariableModal.svelte" import CreateEditVariableModal from "components/portal/environment/CreateEditVariableModal.svelte"
import EditVariableColumn from "./_components/EditVariableColumn.svelte" import EditVariableColumn from "./_components/EditVariableColumn.svelte"
let modal let modal
@ -64,7 +64,7 @@
>Add and manage environment variables for development and production</Body >Add and manage environment variables for development and production</Body
> >
</Layout> </Layout>
{#if !$licensing.environmentVariablesEnabled} {#if $licensing.environmentVariablesEnabled}
{#if noEncryptionKey} {#if noEncryptionKey}
<InlineAlert <InlineAlert
message="Your Budibase installation does not have a key for encryption, please update your app service's environment variables to contain an 'ENCRYPTION_KEY' value." message="Your Budibase installation does not have a key for encryption, please update your app service's environment variables to contain an 'ENCRYPTION_KEY' value."

View File

@ -9,7 +9,6 @@ export function createEnvironmentStore() {
async function checkStatus() { async function checkStatus() {
const status = await API.checkEnvironmentVariableStatus() const status = await API.checkEnvironmentVariableStatus()
console.log(status)
update(store => { update(store => {
store.status = status store.status = status
return store return store

View File

@ -63,6 +63,8 @@ export const createLicensingStore = () => {
let environmentVariablesEnabled = license.features.includes( let environmentVariablesEnabled = license.features.includes(
Constants.Features.ENVIRONMENT_VARIABLES Constants.Features.ENVIRONMENT_VARIABLES
) )
environmentVariablesEnabled = true
store.update(state => { store.update(state => {
return { return {
...state, ...state,