Shared variables support

This commit is contained in:
Matej Bačo
2023-03-11 17:07:23 +01:00
parent 5cebe875f1
commit 7d7061950c
13 changed files with 510 additions and 341 deletions
+7 -7
View File
@@ -9,7 +9,7 @@
"version": "0.0.1",
"dependencies": {
"@analytics/google-analytics": "^1.0.5",
"@aw-labs/appwrite-console": "npm:matej-appwrite-console@7.1.8",
"@aw-labs/appwrite-console": "npm:matej-appwrite-console@7.1.9",
"@aw-labs/icons": "0.0.0-77",
"@aw-labs/ui": "0.0.0-77",
"@popperjs/core": "^2.11.6",
@@ -146,9 +146,9 @@
},
"node_modules/@aw-labs/appwrite-console": {
"name": "matej-appwrite-console",
"version": "7.1.8",
"resolved": "https://registry.npmjs.org/matej-appwrite-console/-/matej-appwrite-console-7.1.8.tgz",
"integrity": "sha512-OhhxzcX0mZAjVSlS5A9U8AOw4LEQ8cPTFLsY86LQTqBqBTjEm+qT5MBTkeaeiEPXdL1+MzoqQgZOL+XXQ+RPJQ==",
"version": "7.1.9",
"resolved": "https://registry.npmjs.org/matej-appwrite-console/-/matej-appwrite-console-7.1.9.tgz",
"integrity": "sha512-3sYGFRfUZK0f6caBHCVTw4F6thKlq1/HgqLg5bOfB+gIz5u8ADRPhjPL5CukdN35vLyJkWvn92rOcCr65tY1tA==",
"dependencies": {
"cross-fetch": "3.1.5",
"isomorphic-form-data": "2.0.0"
@@ -7741,9 +7741,9 @@
"integrity": "sha512-1Yw7u/COtxx06BfwlI+kVhsa/upKYzmCNrT4c8QDeCY2KMYlnijkUjtHiPU08HxyTIVB5j6d75O0YWVIHwQS8g=="
},
"@aw-labs/appwrite-console": {
"version": "npm:matej-appwrite-console@7.1.8",
"resolved": "https://registry.npmjs.org/matej-appwrite-console/-/matej-appwrite-console-7.1.8.tgz",
"integrity": "sha512-OhhxzcX0mZAjVSlS5A9U8AOw4LEQ8cPTFLsY86LQTqBqBTjEm+qT5MBTkeaeiEPXdL1+MzoqQgZOL+XXQ+RPJQ==",
"version": "npm:matej-appwrite-console@7.1.9",
"resolved": "https://registry.npmjs.org/matej-appwrite-console/-/matej-appwrite-console-7.1.9.tgz",
"integrity": "sha512-3sYGFRfUZK0f6caBHCVTw4F6thKlq1/HgqLg5bOfB+gIz5u8ADRPhjPL5CukdN35vLyJkWvn92rOcCr65tY1tA==",
"requires": {
"cross-fetch": "3.1.5",
"isomorphic-form-data": "2.0.0"
+1 -1
View File
@@ -21,7 +21,7 @@
"dependencies": {
"@analytics/google-analytics": "^1.0.5",
"analytics": "^0.8.1",
"@aw-labs/appwrite-console": "npm:matej-appwrite-console@7.1.8",
"@aw-labs/appwrite-console": "npm:matej-appwrite-console@7.1.9",
"@aw-labs/icons": "0.0.0-77",
"@aw-labs/ui": "0.0.0-77",
"@popperjs/core": "^2.11.6",
@@ -33,7 +33,7 @@
<Modal bind:show={showCreate} on:submit={handleVariable} size="big">
<svelte:fragment slot="header">
{selectedVar ? 'Update' : 'Create'} Variable
{selectedVar ? 'Update' : 'Create'} Environment Variable
</svelte:fragment>
<FormList>
<InputText
@@ -0,0 +1,56 @@
<script lang="ts">
import { Modal } from '$lib/components';
import Code from '$lib/components/code.svelte';
import Tab from '$lib/components/tab.svelte';
import Tabs from '$lib/components/tabs.svelte';
import { Button } from '$lib/elements/forms';
export let showSnippet = false;
export let variableKey: string;
// TODO: @Meldiron Finish or delete this component
enum Language {
NodeJS,
Python,
Dart,
Ruby,
Java
}
let language: Language = Language.NodeJS;
</script>
<Modal bind:show={showSnippet} size="big">
<svelte:fragment slot="header">Code Snippet</svelte:fragment>
<p>Snippet of a code showing how to read environment variables in Appwrite Functions.</p>
<Tabs>
<Tab on:click={() => (language = Language.NodeJS)} selected={language === Language.NodeJS}>
Node.JS
</Tab>
<Tab on:click={() => (language = Language.Python)} selected={language === Language.Python}>
Python
</Tab>
<Tab on:click={() => (language = Language.Dart)} selected={language === Language.Dart}>
Dart
</Tab>
<Tab on:click={() => (language = Language.Ruby)} selected={language === Language.Ruby}>
Ruby
</Tab>
<Tab on:click={() => (language = Language.Java)} selected={language === Language.Java}>
Java
</Tab>
</Tabs>
{#if language === Language.NodeJS}
<Code
withLineNumbers
withCopy
language="js"
label="JavaScript"
code={`process.env['${variableKey}']`} />
{/if}
<svelte:fragment slot="footer">
<Button text on:click={() => (showSnippet = false)}>Close</Button>
</svelte:fragment>
</Modal>
@@ -1,4 +1,6 @@
<script lang="ts">
// TODO: This is outdated. Update before using
import { invalidate } from '$app/navigation';
import { page } from '$app/stores';
import { Modal } from '$lib/components';
@@ -28,7 +30,7 @@
invalidate(Dependencies.VARIABLES);
addNotification({
type: 'success',
message: 'Variable uploaded'
message: 'Environment Variables uploaded'
});
} catch (error) {
addNotification({
@@ -60,9 +62,10 @@
</script>
<Modal bind:show on:submit={handleSubmit}>
<svelte:fragment slot="header">Upload Variables</svelte:fragment>
<svelte:fragment slot="header">Upload Environment Variables</svelte:fragment>
<p>
Upload multiple variables via a .env file that will be passed to your function at runtime.
Upload multiple environment variables via a .env file that will be passed to your function
at runtime and during build.
</p>
<InputFile bind:files label="Attach a file" />
@@ -0,0 +1,320 @@
<script lang="ts">
import Button from '$lib/elements/forms/button.svelte';
import type { Models } from '@aw-labs/appwrite-console';
import Copy from '../copy.svelte';
import Modal from '../modal.svelte';
import { tooltip } from '$lib/actions/tooltip';
import DropList from '../dropList.svelte';
import DropListItem from '../dropListItem.svelte';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { addNotification } from '$lib/stores/notifications';
import { trackEvent } from '$lib/actions/analytics';
import Snippet from './snippet.svelte';
import Create from './create.svelte';
import { sdkForProject } from '$lib/stores/sdk';
import Alert from '../alert.svelte';
import { page } from '$app/stores';
import Empty from '../empty.svelte';
export let variables: { total: number; variables: Partial<Models.Variable>[] };
export let isShared = false;
export let isWizard = false;
export let deleteVariable: (variableId: string) => Promise<void>;
export let createVariable: (key: string, value: string) => Promise<void>;
export let updateVariable: (variableId: string, key: string, value: string) => Promise<void>;
const sharedVariablesUrl = `/console/project-${$page.params.project}/settings/variables`;
let showPromote = false;
let promoteVariable: Partial<Models.Variable>;
let showSnippet = false;
let snippetKey = '';
let showVariablesValue = [];
let showVariablesDropdown = [];
let showVariablesModal = false;
let selectedVar: Partial<Models.Variable> = null;
function downloadVariables() {
if (variables.total) {
let content = variables.variables
.map((variable) => `${variable.key}=${variable.value}`)
.join('\n');
const file = new File([content], '.env', {
type: 'application/x-envoy'
});
const link = document.createElement('a');
const url = URL.createObjectURL(file);
link.href = url;
link.download = file.name;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
}
}
async function handleVariableDeleted(variable: Partial<Models.Variable>) {
try {
await deleteVariable(variable.$id);
if (!isWizard) {
invalidate(Dependencies.VARIABLES);
addNotification({
type: 'success',
message: `Environment variable has been deleted`
});
trackEvent('submit_variable_delete');
}
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
}
async function handlePromote(variable: Partial<Models.Variable>) {
try {
await sdkForProject.project.createVariable(variable.key, variable.value);
await deleteVariable(variable.$id);
if (!isWizard) {
invalidate(Dependencies.VARIABLES);
addNotification({
type: 'success',
message: `Environment variable has been promoted`
});
trackEvent('submit_variable_promote');
}
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
} finally {
showPromote = false;
}
}
async function handleVariableCreated(event: CustomEvent<Models.Variable>) {
const variable = event.detail;
try {
await createVariable(variable.key, variable.value);
showVariablesModal = false;
if (!isWizard) {
invalidate(Dependencies.VARIABLES);
addNotification({
type: 'success',
message: `Environment variable have been created`
});
trackEvent('submit_variable_create');
}
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
}
async function handleVariableUpdated(event: CustomEvent<Models.Variable>) {
const variable = event.detail;
try {
await updateVariable(variable.$id, variable.key, variable.value);
selectedVar = null;
showVariablesModal = false;
if (!isWizard) {
invalidate(Dependencies.VARIABLES);
addNotification({
type: 'success',
message: `Environment variable have been updated`
});
trackEvent('submit_variable_update');
}
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
}
</script>
{#if variables.variables.length}
{#if !isWizard}
<div class="u-flex u-margin-inline-start-auto u-gap-16">
<Button secondary on:click={downloadVariables}>
<span class="icon-download" />
<span class="text">Download .env file</span>
</Button>
<!-- <Button secondary on:click={() => (showVariablesUpload = true)}>
<span class="icon-upload" />
<span class="text">Import .env file</span>
</Button> -->
</div>
{/if}
<table class="table is-remove-outer-styles">
<thead class="table-thead">
<tr class="table-row">
<th class="table-thead-col">
<span class="eyebrow-heading-3">Key</span>
</th>
<th class="table-thead-col">
<span class="eyebrow-heading-3">Value</span>
</th>
<th class="table-thead-col" style="--p-col-width:40" />
</tr>
</thead>
<tbody class="table-tbody">
{#if variables.total}
{#each variables.variables as variable, i}
<tr class="table-row">
<td class="table-col" data-title="Key">
<span class="text">{variable.key}</span>
</td>
<td class="table-col u-overflow-visible" data-title="value">
<div class="interactive-text-output">
{#if showVariablesValue[i]}
<span class="text">{variable.value}</span>
{:else}
<span class="text">••••••••</span>
{/if}
<div class="u-flex u-cross-child-start u-gap-8">
<button
on:click|preventDefault={() =>
(showVariablesValue[i] = !showVariablesValue[i])}
class="interactive-text-output-button"
aria-label="show hidden text">
{#if showVariablesValue[i]}
<span class="icon-eye-off" aria-hidden="true" />
{:else}
<span class="icon-eye" aria-hidden="true" />
{/if}
</button>
<Copy bind:value={variable.value}>
<button
class="interactive-text-output-button"
aria-label="copy text">
<span class="icon-duplicate" aria-hidden="true" />
</button>
</Copy>
<button
type="button"
on:click={() => {
snippetKey = variable.key;
showSnippet = true;
}}
use:tooltip={{
content: 'Code snippets',
hideOnClick: false
}}
class="interactive-text-output-button"
aria-label="copy code">
<span class="icon-code" aria-hidden="true" />
</button>
</div>
</div>
</td>
<td class="table-col u-overflow-visible" data-title="options">
<DropList
bind:show={showVariablesDropdown[i]}
placement="bottom-start"
noArrow>
<button
class="button is-text is-only-icon"
aria-label="more options"
on:click|preventDefault={() =>
(showVariablesDropdown[i] = !showVariablesDropdown[i])}>
<span class="icon-dots-horizontal" aria-hidden="true" />
</button>
<svelte:fragment slot="list">
<DropListItem
icon="pencil"
on:click={() => {
selectedVar = variable;
showVariablesDropdown[i] = false;
showVariablesModal = true;
}}>
Edit
</DropListItem>
<DropListItem
icon="trash"
on:click={async () => {
handleVariableDeleted(variable);
showVariablesDropdown[i] = false;
}}>
Delete
</DropListItem>
{#if !isShared && !isWizard}
<DropListItem
icon="globe"
on:click={() => {
showPromote = true;
promoteVariable = variable;
}}>Promote</DropListItem>
{/if}
</svelte:fragment>
</DropList>
</td>
</tr>
{/each}
{/if}
</tbody>
</table>
<div class="u-flex u-margin-block-start-16">
<button
class="button is-text u-padding-inline-0"
type="button"
on:click={() => {
showVariablesModal = true;
}}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create environment variables</span>
</button>
</div>
{:else}
<Empty on:click={() => (showVariablesModal = !showVariablesModal)}
>Create an environment variable to get started</Empty>
{/if}
{#if !isShared && !isWizard}
<Alert type="info">
Shared variables from <a href={sharedVariablesUrl} class="link">project settings</a> are also
available. When there is name conflict, function variable is used.
</Alert>
{/if}
<Snippet bind:showSnippet variableKey={snippetKey} />
{#if showVariablesModal}
<Create
bind:selectedVar
bind:showCreate={showVariablesModal}
on:created={handleVariableCreated}
on:updated={handleVariableUpdated} />
{/if}
{#if !isShared}
<Modal bind:show={showPromote} on:submit={() => handlePromote(promoteVariable)} warning>
<svelte:fragment slot="header">Promote To Shared Variable</svelte:fragment>
<p>
Are you sure you want to promote <code>{promoteVariable.key}</code>? This will move
variable into project settings and make it visible to all services.
</p>
<svelte:fragment slot="footer">
<Button text on:click={() => (showPromote = false)}>Cancel</Button>
<Button secondary submit>Promote</Button>
</svelte:fragment>
</Modal>
{/if}
+1 -2
View File
@@ -7,14 +7,13 @@ import {
Health,
Locale,
Projects,
Project,
Proxy,
Storage,
Teams,
Users
} from '@aw-labs/appwrite-console';
import { Project } from './project';
const endpoint =
import.meta.env.VITE_APPWRITE_ENDPOINT?.toString() ?? `${window?.location?.origin}/v1`;
const clientConsole = new Client();
@@ -87,7 +87,7 @@
optional: true
});
stepsComponents.set(5, {
label: 'Variables',
label: 'Environment Variables',
component: Step5,
optional: true
});
@@ -1,13 +1,5 @@
<script lang="ts">
import {
CardGrid,
Box,
DropList,
DropListItem,
Copy,
Empty,
EventModal
} from '$lib/components';
import { CardGrid, Box, Empty, EventModal } from '$lib/components';
import { Container } from '$lib/layout';
import { Button, InputNumber, InputText, InputCron, Form, FormList } from '$lib/elements/forms';
import { base } from '$app/paths';
@@ -18,9 +10,6 @@
import { sdkForProject } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { page } from '$app/stores';
import type { Models } from '@aw-labs/appwrite-console';
import Variable from '../../createVariable.svelte';
// import Upload from './uploadVariables.svelte';
import { toLocaleDateTime } from '$lib/helpers/date';
import { Roles } from '$lib/components/permissions';
import { symmetricDifference } from '$lib/helpers/array';
@@ -33,16 +22,13 @@
import type { PageData } from './$types';
import { trackEvent } from '$lib/actions/analytics';
import InputSwitch from '$lib/elements/forms/inputSwitch.svelte';
import Variables from '$lib/components/environmentVariables/variables.svelte';
export let data: PageData;
const functionId = $page.params.function;
let showDelete = false;
let selectedVar: Models.Variable = null;
// let showVariablesUpload = false;
let showVariablesModal = false;
let showVariablesValue = [];
let showVariablesDropdown = [];
let timeout: number = null;
let functionName: string = null;
let functionSchedule: string = null;
@@ -50,6 +36,8 @@
let arePermsDisabled = true;
let logging: boolean = null;
// TODO: @Meldiron implement "Promote"
const eventSet: Writable<Set<string>> = writable(new Set());
let showEvents = false;
let areEventsDisabled = true;
@@ -221,89 +209,6 @@
}
}
async function handleVariableCreated(event: CustomEvent<Models.Variable>) {
const variable = event.detail;
try {
await sdkForProject.functions.createVariable(functionId, variable.key, variable.value);
showVariablesModal = false;
invalidate(Dependencies.VARIABLES);
addNotification({
type: 'success',
message: `${$func.name} variables have been updated`
});
trackEvent('submit_variable_create');
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
}
async function handleVariableUpdated(event: CustomEvent<Models.Variable>) {
const variable = event.detail;
try {
await sdkForProject.functions.updateVariable(
functionId,
variable.$id,
variable.key,
variable.value
);
selectedVar = null;
showVariablesModal = false;
invalidate(Dependencies.VARIABLES);
addNotification({
type: 'success',
message: `${$func.name} variables have been updated`
});
trackEvent('submit_variable_update');
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
}
async function handleVariableDeleted(variable: Models.Variable) {
try {
await sdkForProject.functions.deleteVariable(variable.functionId, variable.$id);
invalidate(Dependencies.VARIABLES);
addNotification({
type: 'success',
message: `Variable has been deleted`
});
trackEvent('submit_variable_delete');
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
}
function downloadVariables() {
if (data.variables.total) {
let content = data.variables.variables
.map((variable) => `${variable.key}=${variable.value}`)
.join('\n');
const file = new File([content], '.env', {
type: 'application/x-envoy'
});
const link = document.createElement('a');
const url = URL.createObjectURL(file);
link.href = url;
link.download = file.name;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
}
}
function handleEvent(event: CustomEvent) {
eventSet.set($eventSet.add(event.detail));
}
@@ -319,6 +224,18 @@
areEventsDisabled = false;
} else areEventsDisabled = true;
}
async function deleteVariable(variableId: string) {
await sdkForProject.functions.deleteVariable($func.$id, variableId);
}
async function createVariable(key: string, value: string) {
await sdkForProject.functions.createVariable($func.$id, key, value);
}
async function updateVariable(variableId: string, key: string, value: string) {
await sdkForProject.functions.updateVariable($func.$id, variableId, key, value);
}
</script>
<Container>
@@ -510,120 +427,19 @@
</Form>
<CardGrid>
<Heading tag="h6" size="7">Update Function Variables</Heading>
<p>Set the variables (or secret keys) that will be passed to your function at runtime.</p>
<Heading tag="h6" size="7">Update Function Environment Variables</Heading>
<p>
Set the environment variables (or secret keys) that will be passed to your function at
runtime and during build.
</p>
<svelte:fragment slot="aside">
<div class="u-flex u-margin-inline-start-auto u-gap-16">
<Button secondary on:click={downloadVariables}>
<span class="icon-download" />
<span class="text">Download .env file</span>
</Button>
<!-- <Button secondary on:click={() => (showVariablesUpload = true)}>
<span class="icon-upload" />
<span class="text">Import .env file</span>
</Button> -->
</div>
<table class="table is-remove-outer-styles">
<thead class="table-thead">
<tr class="table-row">
<th class="table-thead-col">
<span class="eyebrow-heading-3">Key</span>
</th>
<th class="table-thead-col">
<span class="eyebrow-heading-3">Value</span>
</th>
<th class="table-thead-col" style="--p-col-width:40" />
</tr>
</thead>
<tbody class="table-tbody">
{#if data.variables.total}
{#each data.variables.variables as variable, i}
<tr class="table-row">
<td class="table-col" data-title="Key">
<span class="text">{variable.key}</span>
</td>
<td class="table-col u-overflow-visible" data-title="value">
<div class="interactive-text-output">
{#if showVariablesValue[i]}
<span class="text">{variable.value}</span>
{:else}
<span class="text">••••••••</span>
{/if}
<div class="u-flex u-cross-child-start u-gap-8">
<button
on:click|preventDefault={() =>
(showVariablesValue[i] =
!showVariablesValue[i])}
class="interactive-text-output-button"
aria-label="show hidden text">
{#if showVariablesValue[i]}
<span class="icon-eye-off" aria-hidden="true" />
{:else}
<span class="icon-eye" aria-hidden="true" />
{/if}
</button>
<Copy bind:value={variable.value}>
<button
class="interactive-text-output-button"
aria-label="copy text">
<span
class="icon-duplicate"
aria-hidden="true" />
</button>
</Copy>
</div>
</div>
</td>
<td class="table-col u-overflow-visible" data-title="options">
<DropList
bind:show={showVariablesDropdown[i]}
placement="bottom-start"
noArrow>
<button
class="button is-text is-only-icon"
aria-label="more options"
on:click|preventDefault={() =>
(showVariablesDropdown[i] =
!showVariablesDropdown[i])}>
<span class="icon-dots-horizontal" aria-hidden="true" />
</button>
<svelte:fragment slot="list">
<DropListItem
icon="pencil"
on:click={() => {
selectedVar = variable;
showVariablesDropdown[i] = false;
showVariablesModal = true;
}}>
Edit
</DropListItem>
<DropListItem
icon="trash"
on:click={async () => {
handleVariableDeleted(variable);
showVariablesDropdown[i] = false;
}}>
Delete
</DropListItem>
</svelte:fragment>
</DropList>
</td>
</tr>
{/each}
{/if}
</tbody>
</table>
<div class="u-flex u-margin-block-start-16">
<button
class="button is-text u-padding-inline-0"
type="button"
on:click={() => {
showVariablesModal = true;
}}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create variable</span>
</button>
</div>
<Variables
isShared={false}
variables={data.variables}
{deleteVariable}
{createVariable}
{updateVariable} />
</svelte:fragment>
</CardGrid>
@@ -649,12 +465,6 @@
</Container>
<Delete bind:showDelete />
{#if showVariablesModal}
<Variable
bind:selectedVar
bind:showCreate={showVariablesModal}
on:created={handleVariableCreated}
on:updated={handleVariableUpdated} />
{/if}
<!-- <Upload bind:show={showVariablesUpload} on:uploaded={handleVariableCreated} /> -->
<EventModal bind:show={showEvents} on:created={handleEvent} />
@@ -1,120 +1,46 @@
<script lang="ts">
import { WizardStep } from '$lib/layout';
import { createFunction } from './store';
import Create from '../createVariable.svelte';
import { DropList, DropListItem, Secret, Empty } from '$lib/components';
import type { Models } from '@aw-labs/appwrite-console';
import {
Table,
TableBody,
TableCell,
TableCellHead,
TableCellText,
TableHeader,
TableRow
} from '$lib/elements/table';
import { Button } from '$lib/elements/forms';
import Variables from '$lib/components/environmentVariables/variables.svelte';
let showCreate = false;
let selectedVar: Partial<Models.Variable> = null;
let showDropdown = [];
function handleCreated(dispatchEvent: CustomEvent) {
createFunction.update((n) => {
if (n.vars.length) {
n.vars.map((v) => {
if (v.key !== dispatchEvent.detail.key) {
n.vars.push(dispatchEvent.detail);
}
});
} else {
n.vars.push(dispatchEvent.detail);
}
return n;
});
async function deleteVariable(variableId: string) {
const index = $createFunction.vars.findIndex((variable) => variable.$id === variableId);
$createFunction.vars.splice(index, 1);
$createFunction = $createFunction;
}
function handleUpdated(dispatchEvent: CustomEvent) {
createFunction.update((n) => {
n.vars = n.vars.map((v) => (v.key === selectedVar.key ? dispatchEvent.detail : v));
return n;
});
async function createVariable(key: string, value: string) {
const index = $createFunction.vars.findIndex((variable) => variable.key === key);
if (index !== -1) {
$createFunction.vars[index].key = key;
$createFunction.vars[index].value = value;
} else {
$createFunction.vars.push({ key, value, $id: Date.now().toString() });
}
$createFunction = $createFunction;
}
async function updateVariable(variableId: string, key: string, value: string) {
const index = $createFunction.vars.findIndex((variable) => variable.$id === variableId);
$createFunction.vars[index].key = key;
$createFunction.vars[index].value = value;
$createFunction = $createFunction;
}
</script>
<WizardStep>
<svelte:fragment slot="title">Variables</svelte:fragment>
<svelte:fragment slot="title">Environment Variables</svelte:fragment>
<svelte:fragment slot="subtitle">
Create a variable (or secret key) that will be passed to your function at runtime.
Create an environment variable (or secret key) that will be passed to your function at
runtime and during build.
</svelte:fragment>
{#if $createFunction.vars.length}
<Table noStyles>
<TableHeader>
<TableCellHead>Key</TableCellHead>
<TableCellHead>Value</TableCellHead>
<TableCellHead width={30} />
</TableHeader>
<TableBody>
{#each $createFunction.vars as variable, i}
<TableRow>
<TableCellText title="key">
{variable.key}
</TableCellText>
<TableCell showOverflow title="value">
<Secret value={variable.value} />
</TableCell>
<TableCell showOverflow title="options">
<DropList bind:show={showDropdown[i]} placement="bottom-start" noArrow>
<button
class="button is-text is-only-icon"
aria-label="more options"
on:click|preventDefault={() =>
(showDropdown[i] = !showDropdown[i])}>
<span class="icon-dots-horizontal" aria-hidden="true" />
</button>
<svelte:fragment slot="list">
<DropListItem
icon="pencil"
on:click={() => {
selectedVar = $createFunction.vars[i];
showDropdown[i] = false;
showCreate = true;
}}>
Edit
</DropListItem>
<DropListItem
icon="trash"
on:click={() => {
$createFunction.vars.splice(i, 1);
$createFunction = $createFunction;
showDropdown[i] = false;
}}>
Delete
</DropListItem>
</svelte:fragment>
</DropList>
</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
<div class="u-flex u-margin-block-start-16">
<Button text noMargin on:click={() => (showCreate = !showCreate)}>
<span class="icon-plus" aria-hidden="true" />
<span class="u-text">Create variable</span>
</Button>
</div>
{:else}
<Empty on:click={() => (showCreate = !showCreate)}>Create a variable to get started</Empty>
{/if}
<Variables
isWizard={true}
{deleteVariable}
{createVariable}
{updateVariable}
variables={{ total: $createFunction.vars.length, variables: $createFunction.vars }} />
</WizardStep>
{#if showCreate}
<Create
bind:selectedVar
bind:showCreate
on:created={handleCreated}
on:updated={handleUpdated} />
{/if}
@@ -21,6 +21,11 @@
href: `${path}/webhooks`,
title: 'Webhooks',
event: 'webhooks'
},
{
href: `${path}/variables`,
title: 'Shared Variables',
event: 'sharedVariables'
}
];
</script>
@@ -0,0 +1,38 @@
<script lang="ts">
import CardGrid from '$lib/components/cardGrid.svelte';
import Variables from '$lib/components/environmentVariables/variables.svelte';
import Heading from '$lib/components/heading.svelte';
import Container from '$lib/layout/container.svelte';
import { sdkForProject } from '$lib/stores/sdk';
import type { PageData } from './$types';
export let data: PageData;
async function deleteVariable(variableId: string) {
await sdkForProject.project.deleteVariable(variableId);
}
async function createVariable(key: string, value: string) {
await sdkForProject.project.createVariable(key, value);
}
async function updateVariable(variableId: string, key: string, value: string) {
await sdkForProject.project.updateVariable(variableId, key, value);
}
</script>
<Container>
<CardGrid>
<Heading tag="h6" size="7">Update Shared Environment Variables</Heading>
<p>Set the environment variables (or secret keys) that will be passed to all resources.</p>
<svelte:fragment slot="aside">
<Variables
isShared={true}
variables={data.variables}
{deleteVariable}
{createVariable}
{updateVariable} />
</svelte:fragment>
</CardGrid>
</Container>
@@ -0,0 +1,12 @@
import { Dependencies } from '$lib/constants';
import { sdkForProject } from '$lib/stores/sdk';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ parent, depends }) => {
await parent();
depends(Dependencies.VARIABLES);
return {
variables: await sdkForProject.project.listVariables()
};
};