mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
fix: variables
This commit is contained in:
@@ -2,10 +2,8 @@
|
||||
import { base } from '$app/paths';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Container } from '$lib/layout';
|
||||
import Create from './createProjectCloud.svelte';
|
||||
import CreateProject from './createProject.svelte';
|
||||
import CreateOrganization from '../createOrganization.svelte';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
import { GRACE_PERIOD_OVERRIDE, isCloud } from '$lib/system';
|
||||
import { page } from '$app/stores';
|
||||
import { registerCommands } from '$lib/commandCenter';
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<script lang="ts">
|
||||
import { Button, InputPassword } from '$lib/elements/forms';
|
||||
import { Modal } from '$lib/components';
|
||||
import { InputText } from '$lib/elements/forms';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { project } from './store';
|
||||
import { base } from '$app/paths';
|
||||
import { Alert, Layout, Selector, Button as PinkButton, Icon } from '@appwrite.io/pink-svelte';
|
||||
import { Link } from '$lib/elements';
|
||||
import { IconPlus, IconX } from '@appwrite.io/pink-icons-svelte';
|
||||
|
||||
export let isGlobal: boolean;
|
||||
export let product: 'function' | 'site' = 'function';
|
||||
export let showCreate = false;
|
||||
let newVariables: Partial<Models.Variable>[] = [{ key: '', value: '' }];
|
||||
let secret = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
function close() {
|
||||
showCreate = false;
|
||||
}
|
||||
|
||||
function handleVariable() {
|
||||
if (secret) {
|
||||
newVariables = newVariables.map((variable) => ({ ...variable, secret: true }));
|
||||
}
|
||||
newVariables.forEach((variable) => {
|
||||
if (('' + variable.value).length > 8192) {
|
||||
throw new Error(`Variable ${variable.key} is longer than 8192 allowed characters`);
|
||||
}
|
||||
});
|
||||
dispatch('created', newVariables);
|
||||
close();
|
||||
}
|
||||
|
||||
function removeVariable(index: number) {
|
||||
if (newVariables.length === 1) {
|
||||
newVariables[0].key = '';
|
||||
newVariables[0].value = '';
|
||||
} else {
|
||||
newVariables.splice(index, 1);
|
||||
newVariables = [...newVariables];
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
bind:show={showCreate}
|
||||
onSubmit={handleVariable}
|
||||
title={`Create' ${isGlobal ? 'global' : 'environment'} variable`}>
|
||||
<svelte:fragment slot="description">
|
||||
<span>
|
||||
Set the environment variables or secret keys that will be passed to {!isGlobal
|
||||
? `your ${product}`
|
||||
: `all functions and sites within your project`}.
|
||||
</span>
|
||||
</svelte:fragment>
|
||||
<Layout.Stack>
|
||||
{#if !isGlobal}
|
||||
<Alert.Inline>
|
||||
When there is a naming conflict with a global variable in your <Link
|
||||
href={`${base}/project-${$project.$id}/settings/variables`}>
|
||||
project settings</Link>
|
||||
and a {product} environment variable, the global variable will be ignored.
|
||||
</Alert.Inline>
|
||||
{/if}
|
||||
<Layout.Stack gap="xs">
|
||||
{#each newVariables as pair, i}
|
||||
<Layout.Stack direction="row" gap="s" alignItems="flex-end" inline>
|
||||
<InputText
|
||||
id="key"
|
||||
label={`${i === 0 ? 'Key' : ''}`}
|
||||
placeholder="ENTER_KEY"
|
||||
bind:value={pair.key}
|
||||
autocomplete={false}
|
||||
autofocus />
|
||||
<InputPassword
|
||||
id="value"
|
||||
label={`${i === 0 ? 'Value' : ''}`}
|
||||
placeholder="Enter value"
|
||||
bind:value={pair.value}
|
||||
minlength={0} />
|
||||
<PinkButton.Button
|
||||
icon
|
||||
variant="secondary"
|
||||
type="button"
|
||||
size="s"
|
||||
disabled={newVariables.length === 1 && !pair.key && !pair.value}
|
||||
on:click={() => removeVariable(i)}>
|
||||
<Icon icon={IconX} />
|
||||
</PinkButton.Button>
|
||||
</Layout.Stack>
|
||||
{/each}
|
||||
<div>
|
||||
<Button
|
||||
text
|
||||
compact
|
||||
disabled={newVariables.some((pair) => !pair.key)}
|
||||
on:click={() => (newVariables = [...newVariables, { key: '', value: '' }])}>
|
||||
<Icon slot="start" icon={IconPlus} />Add variable</Button>
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
<Selector.Checkbox
|
||||
id="secret"
|
||||
label="Secret"
|
||||
bind:checked={secret}
|
||||
description="If selected, you and your team won't be able to read the values after creation." />
|
||||
</Layout.Stack>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={close}>Cancel</Button>
|
||||
<Button submit>Create</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
+15
-4
@@ -10,7 +10,6 @@
|
||||
import UpdateSchedule from './updateSchedule.svelte';
|
||||
import UpdateScopes from './updateScopes.svelte';
|
||||
import UpdateTimeout from './updateTimeout.svelte';
|
||||
import UpdateVariables from '../../../updateVariables.svelte';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import { invalidate } from '$app/navigation';
|
||||
@@ -21,17 +20,29 @@
|
||||
import UpdateBuildCommand from './updateBuildCommand.svelte';
|
||||
import UpdateResourceLimits from './updateResourceLimits.svelte';
|
||||
import { isCloud } from '$lib/system';
|
||||
import UpdateVariables from '$routes/(console)/project-[project]/updateVariables.svelte';
|
||||
|
||||
export let data;
|
||||
let showAlert = true;
|
||||
|
||||
const sdkCreateVariable = async (key: string, value: string, secret: boolean) => {
|
||||
const sdkCreateVariable = async (key: string, value: string, secret?: boolean) => {
|
||||
await sdk.forProject.functions.createVariable(data.function.$id, key, value, secret);
|
||||
await Promise.all([invalidate(Dependencies.VARIABLES), invalidate(Dependencies.FUNCTION)]);
|
||||
};
|
||||
|
||||
const sdkUpdateVariable = async (variableId: string, key: string, value: string) => {
|
||||
await sdk.forProject.functions.updateVariable(data.function.$id, variableId, key, value);
|
||||
const sdkUpdateVariable = async (
|
||||
variableId: string,
|
||||
key: string,
|
||||
value: string,
|
||||
secret?: boolean
|
||||
) => {
|
||||
await sdk.forProject.functions.updateVariable(
|
||||
data.function.$id,
|
||||
variableId,
|
||||
key,
|
||||
value,
|
||||
secret
|
||||
);
|
||||
await Promise.all([invalidate(Dependencies.VARIABLES), invalidate(Dependencies.FUNCTION)]);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { Dialog, Layout } from '@appwrite.io/pink-svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
export let show = false;
|
||||
|
||||
export let selectedVar: Partial<Models.Variable>;
|
||||
let pair = {
|
||||
$id: selectedVar?.$id,
|
||||
key: selectedVar?.key,
|
||||
value: selectedVar?.value,
|
||||
secret: true
|
||||
};
|
||||
const dispatch = createEventDispatcher();
|
||||
function markAsSecret() {
|
||||
dispatch('updated', pair);
|
||||
|
||||
selectedVar = null;
|
||||
show = false;
|
||||
}
|
||||
|
||||
$: if (!show) {
|
||||
selectedVar = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog title="Secret variable" bind:open={show}>
|
||||
<Layout.Stack gap="l">
|
||||
<p>
|
||||
Secret variables are hidden from both the UI and API. Once a variable is marked as
|
||||
secret, this action cannot be reversed.
|
||||
</p>
|
||||
<p>Are you sure you want to make this variable secret?</p>
|
||||
</Layout.Stack>
|
||||
<svelte:fragment slot="footer">
|
||||
<Layout.Stack direction="row" gap="s" justifyContent="flex-end">
|
||||
<Button text on:click={() => (show = false)}>Cancel</Button>
|
||||
<Button on:click={markAsSecret}>Mark as secret</Button>
|
||||
</Layout.Stack>
|
||||
</svelte:fragment>
|
||||
</Dialog>
|
||||
@@ -9,11 +9,11 @@
|
||||
import UpdateName from './updateName.svelte';
|
||||
import UpdateServices from './updateServices.svelte';
|
||||
import UpdateInstallations from './updateInstallations.svelte';
|
||||
import UpdateVariables from '../updateVariables.svelte';
|
||||
import DeleteProject from './deleteProject.svelte';
|
||||
import { Submit, trackEvent } from '$lib/actions/analytics';
|
||||
import { canWriteProjects } from '$lib/stores/roles';
|
||||
import ChangeOrganization from './changeOrganization.svelte';
|
||||
import UpdateVariables from '../updateVariables.svelte';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -59,8 +59,13 @@
|
||||
await invalidate(Dependencies.PROJECT_VARIABLES);
|
||||
}
|
||||
|
||||
async function sdkUpdateVariable(variableId: string, key: string, value: string) {
|
||||
await sdk.forProject.projectApi.updateVariable(variableId, key, value);
|
||||
async function sdkUpdateVariable(
|
||||
variableId: string,
|
||||
key: string,
|
||||
value: string,
|
||||
secret: boolean
|
||||
) {
|
||||
await sdk.forProject.projectApi.updateVariable(variableId, key, value, secret);
|
||||
await invalidate(Dependencies.PROJECT_VARIABLES);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
import { base } from '$app/paths';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { getApiEndpoint } from '$lib/stores/sdk';
|
||||
import { capitalize } from '$lib/helpers/string';
|
||||
|
||||
export let deployment: Models.Deployment;
|
||||
export let proxyRuleList: Models.ProxyRuleList;
|
||||
@@ -86,7 +87,9 @@
|
||||
Status
|
||||
</Typography.Text>
|
||||
<Typography.Text variant="m-400" color="--fgcolor-neutral-primary">
|
||||
<Status status={deployment.status} label={deployment.status} />
|
||||
<Status
|
||||
status={deployment.status}
|
||||
label={capitalize(deployment.status)} />
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
{:else}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { Container } from '$lib/layout';
|
||||
import DangerZone from './dangerZone.svelte';
|
||||
import UpdateName from './updateName.svelte';
|
||||
import UpdateVariables from '../../../updateVariables.svelte';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import { invalidate } from '$app/navigation';
|
||||
@@ -15,6 +14,7 @@
|
||||
import { showConnectRepo } from './store';
|
||||
import { isCloud } from '$lib/system';
|
||||
import UpdateResourceLimits from './updateResourceLimits.svelte';
|
||||
import UpdateVariables from '$routes/(console)/project-[project]/updateVariables.svelte';
|
||||
|
||||
export let data;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { project } from '$routes/(console)/project-[project]/store';
|
||||
import PromoteVariableModal from './promoteVariableModal.svelte';
|
||||
import CreateVariable from './createVariable.svelte';
|
||||
import CreateVariable from './createVariableModal.svelte';
|
||||
import RawVariableEditor from './rawVariableEditor.svelte';
|
||||
import { base } from '$app/paths';
|
||||
import {
|
||||
@@ -26,6 +26,8 @@
|
||||
import {
|
||||
IconCode,
|
||||
IconDotsHorizontal,
|
||||
IconEye,
|
||||
IconEyeOff,
|
||||
IconGlobeAlt,
|
||||
IconPencil,
|
||||
IconPlus,
|
||||
@@ -35,6 +37,8 @@
|
||||
import Link from '$lib/elements/link.svelte';
|
||||
import Copy from '$lib/components/copy.svelte';
|
||||
import { page } from '$app/stores';
|
||||
import UpdateVariablesModal from './updateVariablesModal.svelte';
|
||||
import SecretVariableModal from './secretVariableModal.svelte';
|
||||
|
||||
export let variableList: Models.VariableList;
|
||||
export let globalVariableList: Models.VariableList | undefined = undefined;
|
||||
@@ -54,20 +58,24 @@
|
||||
export let sdkDeleteVariable: (variableId: string) => Promise<unknown>;
|
||||
export let product: 'function' | 'site' = 'function';
|
||||
|
||||
let showVariablesDropdown = [];
|
||||
let selectedVar: Models.Variable = null;
|
||||
let showVariablesUpload = false;
|
||||
let showVariablesModal = false;
|
||||
let showPromoteModal = false;
|
||||
let showEditorModal = false;
|
||||
let showUpdate = false;
|
||||
let showSecretModal = false;
|
||||
let offset = 0;
|
||||
const limit = 10;
|
||||
|
||||
async function handleVariableCreated(event: CustomEvent<Models.Variable>) {
|
||||
const variable = event.detail;
|
||||
async function handleVariableCreated(event: CustomEvent<Models.Variable[]>) {
|
||||
const variables = event.detail;
|
||||
console.log(variables);
|
||||
try {
|
||||
await sdkCreateVariable(variable.key, variable.value, variable.secret);
|
||||
selectedVar = null;
|
||||
const promises = variables.map((variable) =>
|
||||
sdkCreateVariable(variable.key, variable.value, variable?.secret || false)
|
||||
);
|
||||
await Promise.all(promises);
|
||||
showVariablesModal = false;
|
||||
addNotification({
|
||||
type: 'success',
|
||||
@@ -106,6 +114,28 @@
|
||||
trackError(error, Submit.VariableUpdate);
|
||||
}
|
||||
}
|
||||
async function handleVariableSecret(event: CustomEvent<Models.Variable>) {
|
||||
const variable = event.detail;
|
||||
console.log(variable);
|
||||
try {
|
||||
await sdkUpdateVariable(variable.$id, variable.key, variable.value, variable.secret);
|
||||
selectedVar = null;
|
||||
showVariablesModal = false;
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: `${$project.name} ${
|
||||
isGlobal ? 'global variable' : 'variable'
|
||||
} has been marked as secret.`
|
||||
});
|
||||
trackEvent(Submit.VariableUpdate);
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
type: 'error',
|
||||
message: error.message
|
||||
});
|
||||
trackError(error, Submit.VariableUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleVariableDeleted(variable: Models.Variable) {
|
||||
try {
|
||||
@@ -285,7 +315,7 @@
|
||||
<Table.Header.Cell>Value</Table.Header.Cell>
|
||||
<Table.Header.Cell width="30px" />
|
||||
</svelte:fragment>
|
||||
{#each variableList.variables.slice(offset, offset + limit) as variable, i}
|
||||
{#each variableList.variables.slice(offset, offset + limit) as variable}
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
{@const isConflicting = globalVariableList
|
||||
@@ -332,22 +362,31 @@
|
||||
</Button>
|
||||
<svelte:fragment slot="tooltip" let:toggle>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Button
|
||||
trailingIcon={IconPencil}
|
||||
on:click={(e) => {
|
||||
selectedVar = variable;
|
||||
showVariablesDropdown[i] = false;
|
||||
showVariablesModal = true;
|
||||
toggle(e);
|
||||
}}>
|
||||
Update
|
||||
</ActionMenu.Item.Button>
|
||||
{#if !variable.secret}
|
||||
<ActionMenu.Item.Button
|
||||
trailingIcon={IconPencil}
|
||||
on:click={(e) => {
|
||||
selectedVar = variable;
|
||||
showUpdate = true;
|
||||
toggle(e);
|
||||
}}>
|
||||
Update
|
||||
</ActionMenu.Item.Button>
|
||||
<ActionMenu.Item.Button
|
||||
trailingIcon={IconEyeOff}
|
||||
on:click={(e) => {
|
||||
selectedVar = variable;
|
||||
showSecretModal = true;
|
||||
toggle(e);
|
||||
}}>
|
||||
Secret
|
||||
</ActionMenu.Item.Button>
|
||||
{/if}
|
||||
{#if !isGlobal}
|
||||
<ActionMenu.Item.Button
|
||||
trailingIcon={IconGlobeAlt}
|
||||
on:click={async (e) => {
|
||||
selectedVar = variable;
|
||||
showVariablesDropdown[i] = false;
|
||||
showPromoteModal = true;
|
||||
toggle(e);
|
||||
}}>
|
||||
@@ -359,7 +398,6 @@
|
||||
trailingIcon={IconTrash}
|
||||
on:click={async (e) => {
|
||||
handleVariableDeleted(variable);
|
||||
showVariablesDropdown[i] = false;
|
||||
toggle(e);
|
||||
}}>
|
||||
Delete
|
||||
@@ -390,12 +428,24 @@
|
||||
<CreateVariable
|
||||
{isGlobal}
|
||||
{product}
|
||||
bind:selectedVar
|
||||
bind:showCreate={showVariablesModal}
|
||||
on:created={handleVariableCreated}
|
||||
on:updated={handleVariableUpdated} />
|
||||
on:created={handleVariableCreated} />
|
||||
{/if}
|
||||
|
||||
{#if showUpdate}
|
||||
<UpdateVariablesModal
|
||||
{isGlobal}
|
||||
{product}
|
||||
bind:selectedVar
|
||||
bind:show={showUpdate}
|
||||
on:updated={handleVariableUpdated} />
|
||||
{/if}
|
||||
{#if showSecretModal}
|
||||
<SecretVariableModal
|
||||
bind:show={showSecretModal}
|
||||
{selectedVar}
|
||||
on:updated={handleVariableSecret} />
|
||||
{/if}
|
||||
{#if showEditorModal}
|
||||
<RawVariableEditor
|
||||
{isGlobal}
|
||||
|
||||
+9
-13
@@ -11,8 +11,8 @@
|
||||
|
||||
export let isGlobal: boolean;
|
||||
export let product: 'function' | 'site' = 'function';
|
||||
export let showCreate = false;
|
||||
export let selectedVar: Partial<Models.Variable> = null;
|
||||
export let show = false;
|
||||
export let selectedVar: Partial<Models.Variable>;
|
||||
|
||||
let pair = {
|
||||
$id: selectedVar?.$id,
|
||||
@@ -24,29 +24,25 @@
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
function close() {
|
||||
showCreate = false;
|
||||
show = false;
|
||||
selectedVar = null;
|
||||
}
|
||||
|
||||
function handleVariable() {
|
||||
if (selectedVar) {
|
||||
dispatch('updated', pair);
|
||||
} else {
|
||||
dispatch('created', pair);
|
||||
}
|
||||
dispatch('updated', pair);
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
$: if (!showCreate) {
|
||||
console.log('test');
|
||||
$: if (!show) {
|
||||
selectedVar = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
bind:show={showCreate}
|
||||
bind:show
|
||||
onSubmit={handleVariable}
|
||||
title={`${selectedVar ? 'Update' : 'Create'} ${isGlobal ? 'global' : 'environment'} variable`}>
|
||||
title={`Update ${isGlobal ? 'global' : 'environment'} variable`}>
|
||||
<svelte:fragment slot="description">
|
||||
<span>
|
||||
Set the environment variables or secret keys that will be passed to {!isGlobal
|
||||
@@ -85,6 +81,6 @@
|
||||
</Layout.Stack>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={close}>Cancel</Button>
|
||||
<Button submit>{selectedVar ? 'Update' : 'Create'}</Button>
|
||||
<Button submit>Update</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
Reference in New Issue
Block a user