Merge pull request #182 from appwrite/fix-function-review

draft: fix function design review
This commit is contained in:
Torsten Dittmann
2023-01-31 13:04:17 +01:00
committed by GitHub
17 changed files with 553 additions and 297 deletions
+14 -14
View File
@@ -10,8 +10,8 @@
"dependencies": {
"@analytics/google-analytics": "^1.0.5",
"@aw-labs/appwrite-console": "^13.1.0",
"@aw-labs/icons": "0.0.0-77",
"@aw-labs/ui": "0.0.0-77",
"@aw-labs/icons": "0.0.0-82",
"@aw-labs/ui": "0.0.0-82",
"@popperjs/core": "^2.11.6",
"@sentry/svelte": "^7.19.0",
"@sentry/tracing": "^7.19.0",
@@ -154,14 +154,14 @@
}
},
"node_modules/@aw-labs/icons": {
"version": "0.0.0-77",
"resolved": "https://registry.npmjs.org/@aw-labs/icons/-/icons-0.0.0-77.tgz",
"integrity": "sha512-z/gH6B//qShnlJbf1sxv0ltSbRvJha1El0pl4jACAWDD+orgh2hzBrv6YdgPi1AVBTacu2GWWTcyobItghbpgA=="
"version": "0.0.0-82",
"resolved": "https://registry.npmjs.org/@aw-labs/icons/-/icons-0.0.0-82.tgz",
"integrity": "sha512-TQ3abZGBjisd4WpeBVSUihY98drljdlcdw++z8icNpQVYohmUejRHU59mhmIfXCkhpA1s0tW+5xEMp0WmLNp9Q=="
},
"node_modules/@aw-labs/ui": {
"version": "0.0.0-77",
"resolved": "https://registry.npmjs.org/@aw-labs/ui/-/ui-0.0.0-77.tgz",
"integrity": "sha512-y/7cbPFcK+jUnarsn9X1arrIB69RVMPWMjjIiiaX7uSa0rq9ZN1agBZxfA63meyh23kdIK4K5CcJhatShMMsYg==",
"version": "0.0.0-82",
"resolved": "https://registry.npmjs.org/@aw-labs/ui/-/ui-0.0.0-82.tgz",
"integrity": "sha512-zZDTP117uxMrwzAacOcpSXI77FMFcfv6+Da1R5sDWoqxhvZ0Wyx0Z6cn3dakV0M3zJfYZQ49LmSnU/5wqHPc7A==",
"dependencies": {
"@aw-labs/icons": "*",
"normalize.css": "^8.0.1",
@@ -7749,14 +7749,14 @@
}
},
"@aw-labs/icons": {
"version": "0.0.0-77",
"resolved": "https://registry.npmjs.org/@aw-labs/icons/-/icons-0.0.0-77.tgz",
"integrity": "sha512-z/gH6B//qShnlJbf1sxv0ltSbRvJha1El0pl4jACAWDD+orgh2hzBrv6YdgPi1AVBTacu2GWWTcyobItghbpgA=="
"version": "0.0.0-82",
"resolved": "https://registry.npmjs.org/@aw-labs/icons/-/icons-0.0.0-82.tgz",
"integrity": "sha512-TQ3abZGBjisd4WpeBVSUihY98drljdlcdw++z8icNpQVYohmUejRHU59mhmIfXCkhpA1s0tW+5xEMp0WmLNp9Q=="
},
"@aw-labs/ui": {
"version": "0.0.0-77",
"resolved": "https://registry.npmjs.org/@aw-labs/ui/-/ui-0.0.0-77.tgz",
"integrity": "sha512-y/7cbPFcK+jUnarsn9X1arrIB69RVMPWMjjIiiaX7uSa0rq9ZN1agBZxfA63meyh23kdIK4K5CcJhatShMMsYg==",
"version": "0.0.0-82",
"resolved": "https://registry.npmjs.org/@aw-labs/ui/-/ui-0.0.0-82.tgz",
"integrity": "sha512-zZDTP117uxMrwzAacOcpSXI77FMFcfv6+Da1R5sDWoqxhvZ0Wyx0Z6cn3dakV0M3zJfYZQ49LmSnU/5wqHPc7A==",
"requires": {
"@aw-labs/icons": "*",
"normalize.css": "^8.0.1",
+2 -2
View File
@@ -22,8 +22,8 @@
"@analytics/google-analytics": "^1.0.5",
"analytics": "^0.8.1",
"@aw-labs/appwrite-console": "^13.1.0",
"@aw-labs/icons": "0.0.0-77",
"@aw-labs/ui": "0.0.0-77",
"@aw-labs/icons": "0.0.0-82",
"@aw-labs/ui": "0.0.0-82",
"@popperjs/core": "^2.11.6",
"@sentry/svelte": "^7.19.0",
"@sentry/tracing": "^7.19.0",
+2 -1
View File
@@ -1,9 +1,10 @@
<script lang="ts">
export let withIndentation = false;
export let open = false;
</script>
<li class="collapsible-item">
<details class="collapsible-wrapper">
<details class="collapsible-wrapper" {open}>
<summary class="collapsible-button">
<slot name="beforetitle" />
<div>
+1
View File
@@ -20,4 +20,5 @@ export { default as InputChoice } from './inputChoice.svelte';
export { default as InputPhone } from './inputPhone.svelte';
export { default as InputCron } from './inputCron.svelte';
export { default as InputURL } from './inputURL.svelte';
export { default as InputSecret } from './inputSecret.svelte';
export { default as Helper } from './helper.svelte';
+49
View File
@@ -0,0 +1,49 @@
<script lang="ts">
import { FormItem } from '.';
export let id: string;
export let label: string;
export let showLabel = true;
export let value = '';
export let placeholder = '';
let showInPlainText = false;
</script>
<FormItem>
<label class:u-hide={!showLabel} class="label" for={id}>{label}</label>
<div class="input-text-wrapper" style="--amount-of-buttons:1">
{#if showInPlainText}
<div
contenteditable="true"
role="textbox"
{id}
aria-placeholder={placeholder}
name={id}
type="text"
class="input-text is-resizable"
bind:textContent={value} />
{:else}
<input
{id}
{placeholder}
name={id}
type="password"
class="input-text"
autocomplete="off"
bind:value />
{/if}
<div class="options-list">
<button
type="button"
on:click={() => (showInPlainText = !showInPlainText)}
class="options-list-button"
aria-label="show / hide password">
<span
class:icon-eye={!showInPlainText}
class:icon-eye-off={showInPlainText}
aria-hidden="true" />
</button>
</div>
</div>
</FormItem>
+6 -6
View File
@@ -8,17 +8,17 @@ export function calculateTime(time: number) {
const years = Math.floor(months / 12);
if (milliseconds < 1000) {
return milliseconds + 'ms';
return `${milliseconds}ms`;
} else if (seconds < 60) {
return `${seconds} s`;
return `${seconds}s`;
} else if (minutes < 60) {
return `${minutes} m`;
return `${minutes}m`;
} else if (hours < 24) {
return `${hours} h`;
return `${hours}h`;
} else if (days < 30) {
return `${days} d`;
return `${days}d`;
} else if (months < 12) {
return `${months} M`;
return `${months}M`;
} else {
return `${years} y`;
}
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

+8 -6
View File
@@ -116,11 +116,13 @@
</header>
{#if selectedTab === 'logs'}
<code class="code-panel-content">
{$log.data.buildStdout ?? 'No logs recorded'}
{$log.data.buildStdout ? $log.data.buildStdout : 'No logs recorded'}
</code>
{:else}
<code class="code-panel-content">
{$log.data.buildStderr ?? 'No errors recorded'}
{$log.data.buildStderr
? $log.data.buildStderr
: 'No errors recorded'}
</code>
{/if}
</section>
@@ -149,7 +151,7 @@
Created at: {toLocaleDateTime($log.data.$createdAt)}</time>
</div>
<div>
<p>Triggered by: {$log.data.trigger}</p>
<p>Triggered by: <b>{$log.data.trigger}</b></p>
</div>
<div class="status u-margin-inline-start-auto">
<Status status={$log.data.status}>{$log.data.status}</Status>
@@ -191,15 +193,15 @@
</header>
{#if selectedTab === 'logs'}
<code class="code-panel-content">
{$log.data.stdout ?? 'No logs recorded'}
{$log.data.stdout ? $log.data.stdout : 'No logs recorded'}
</code>
{:else if selectedTab === 'errors'}
<code class="code-panel-content">
{$log.data.stderr ?? 'No errors recorded'}
{$log.data.stderr ? $log.data.stderr : 'No errors recorded'}
</code>
{:else}
<code class="code-panel-content">
{$log.data.response ?? 'No response recorded'}
{$log.data.response ? $log.data.response : 'No response recorded'}
</code>
{/if}
</section>
@@ -92,7 +92,7 @@
{:else}
<Empty
single
href="https://appwrite.io/docs/functions"
href="https://appwrite.io/docs/functions#deployFunction"
target="function"
on:click={openWizard} />
{/if}
@@ -1,7 +1,7 @@
<script lang="ts">
import { Button } from '$lib/elements/forms';
import { Button, InputSecret } from '$lib/elements/forms';
import { Modal } from '$lib/components';
import { InputText, InputPassword, FormList } from '$lib/elements/forms';
import { InputText, FormList } from '$lib/elements/forms';
import { createEventDispatcher } from 'svelte';
import type { Models } from '@aw-labs/appwrite-console';
@@ -42,15 +42,9 @@
placeholder="Enter key"
bind:value={pair.key}
required
autofocus />
<InputPassword
id="value"
label="Value"
minlength={0}
showPasswordButton
placeholder="Enter value"
bind:value={pair.value}
required />
autofocus
autocomplete={false} />
<InputSecret id="value" label="Value" placeholder="Enter value" bind:value={pair.value} />
</FormList>
<svelte:fragment slot="footer">
<Button secondary on:click={close}>Cancel</Button>
@@ -155,98 +155,120 @@
<div class="common-section">
<Heading tag="h3" size="7">Inactive</Heading>
</div>
{#if data.deployments.total > 1}
<Table>
<TableHeader>
<TableCellHead width={90}>Deployment ID</TableCellHead>
<TableCellHead width={140}>Created</TableCellHead>
<TableCellHead width={100}>Status</TableCellHead>
<TableCellHead width={100}>Build Time</TableCellHead>
<TableCellHead width={70}>Size</TableCellHead>
<TableCellHead width={25} />
</TableHeader>
<TableBody>
{#each data.deployments.deployments as deployment, index}
{#if deployment.$id !== $func.deployment}
<TableRow>
<TableCell title="Deployment ID">
<Copy value={deployment.$id}>
<Pill button trim>
<span class="icon-duplicate" aria-hidden="true" />
<span class="text u-trim">{deployment.$id}</span>
</Pill>
</Copy>
</TableCell>
<TableCellText title="Created">
{toLocaleDateTime(deployment.$createdAt)}
</TableCellText>
<Table>
<TableHeader>
<TableCellHead width={90}>Deployment ID</TableCellHead>
<TableCellHead width={140}>Created</TableCellHead>
<TableCellHead width={100}>Status</TableCellHead>
<TableCellHead width={100}>Build Time</TableCellHead>
<TableCellHead width={70}>Size</TableCellHead>
<TableCellHead width={25} />
</TableHeader>
<TableBody>
{#each data.deployments.deployments as deployment, index}
{#if deployment.$id !== $func.deployment}
<TableRow>
<TableCell title="Deployment ID">
<Copy value={deployment.$id}>
<Pill button trim>
<span class="icon-duplicate" aria-hidden="true" />
<span class="text u-trim">{deployment.$id}</span>
</Pill>
</Copy>
</TableCell>
<TableCellText title="Created">
{toLocaleDateTime(deployment.$createdAt)}
</TableCellText>
<TableCell title="Status">
<Status status={deployment.status}>
{deployment.status}
</Status>
</TableCell>
<TableCell title="Status">
<Status status={deployment.status}>
{deployment.status}
</Status>
</TableCell>
<TableCellText title="Build Time">
{#if deployment.status === 'ready'}
{calculateTime(deployment.buildTime)}
{/if}
</TableCellText>
<TableCellText title="Build Time">
{#if deployment.status === 'ready'}
{calculateTime(deployment.buildTime)}
{/if}
</TableCellText>
<TableCellText title="Size">
{calculateSize(deployment.size)}
</TableCellText>
<TableCellText title="Size">
{calculateSize(deployment.size)}
</TableCellText>
<TableCell showOverflow>
<DropList
bind:show={showDropdown[index]}
placement="bottom-start"
noArrow>
<button
class="button is-only-icon is-text"
aria-label="More options"
on:click|preventDefault={() => {
showDropdown[index] = !showDropdown[index];
}}>
<span class="icon-dots-horizontal" aria-hidden="true" />
</button>
<svelte:fragment slot="list">
<DropListItem
icon="lightning-bolt"
on:click={() => {
selectedDeployment = deployment;
showActivate = true;
showDropdown = [];
<TableCell showOverflow>
<DropList
bind:show={showDropdown[index]}
placement="bottom-start"
noArrow>
<button
class="button is-only-icon is-text"
aria-label="More options"
on:click|preventDefault={() => {
showDropdown[index] = !showDropdown[index];
}}>
Activate
</DropListItem>
<DropListItem
icon="terminal"
on:click={() => {
$log.show = true;
$log.func = $func;
$log.data = deployment;
showDropdown = [];
}}>
Output
</DropListItem>
<DropListItem
icon="trash"
on:click={() => {
selectedDeployment = deployment;
showDropdown = [];
showDelete = true;
}}>
Delete
</DropListItem>
</svelte:fragment>
</DropList>
</TableCell>
</TableRow>
{/if}
{/each}
</TableBody>
</Table>
<span class="icon-dots-horizontal" aria-hidden="true" />
</button>
<svelte:fragment slot="list">
<DropListItem
icon="lightning-bolt"
on:click={() => {
selectedDeployment = deployment;
showActivate = true;
showDropdown = [];
}}>
Activate
</DropListItem>
<DropListItem
icon="terminal"
on:click={() => {
$log.show = true;
$log.func = $func;
$log.data = deployment;
showDropdown = [];
}}>
Output
</DropListItem>
<DropListItem
icon="trash"
on:click={() => {
selectedDeployment = deployment;
showDropdown = [];
showDelete = true;
}}>
Delete
</DropListItem>
</svelte:fragment>
</DropList>
</TableCell>
</TableRow>
{/if}
{/each}
</TableBody>
</Table>
{:else}
<Empty single target="deployment" on:click={() => (showCreate = true)}>
<div class="u-text-center">
<Heading size="7" tag="h2"
>You have no inactive deployments. Create one to see it here.</Heading>
<p class="body-text-2 u-margin-block-start-4">
Learn more about deployments in our Documentation.
</p>
</div>
<div class="u-flex u-gap-16 u-main-center">
<Button
external
href="https://appwrite.io/docs/functions#createFunction"
text
event="empty_documentation"
ariaLabel={`create {target}`}>Documentation</Button>
<Button secondary on:click={() => (showCreate = true)}>
Create deployment
</Button>
</div>
</Empty>
{/if}
{:else}
<Empty
single
@@ -255,12 +277,12 @@
on:click={() => (showCreate = true)} />
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.deployments.total}</p>
<p class="text">Total results: {data.deployments.total ? data.deployments.total - 1 : 0}</p>
<Pagination
limit={PAGE_LIMIT}
path={`/console/project-${$page.params.project}/functions/function-${$page.params.function}`}
offset={data.offset}
sum={data.deployments.total} />
sum={data.deployments.total ? data.deployments.total - 1 : 0} />
</div>
</Container>
@@ -5,11 +5,13 @@
import { createEventDispatcher, onMount } from 'svelte';
import { addNotification } from '$lib/stores/notifications';
import { page } from '$app/stores';
import Github from '$lib/images/github-illustration.svg';
import GithubLight from '$lib/images/github-illustration-light.svg';
import GithubDark from '$lib/images/github-illustration-dark.svg';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { func } from './store';
import { trackEvent } from '$lib/actions/analytics';
import { app } from '$lib/stores/app';
export let showCreate = false;
@@ -117,7 +119,7 @@
on:click={() => (mode = Mode.Github)}
selected={mode === Mode.Github}
event="deploy_github">
GitHub - Soon!
GitHub - (Soon!)
</Tab>
<Tab
on:click={() => (mode = Mode.Manual)}
@@ -141,8 +143,8 @@
>.
</p>
<Collapsible>
{#each ['Unix', 'CMD', 'PowerShell'] as category}
<CollapsibleItem>
{#each ['Unix', 'CMD', 'PowerShell'] as category, i}
<CollapsibleItem open={i === 0}>
<svelte:fragment slot="title">{category}</svelte:fragment>
<Code
withLineNumbers
@@ -156,7 +158,11 @@
{:else if mode === Mode.Github}
<div class="common-section grid-1-2">
<div class="grid-1-2-col-1 u-flex u-flex-vertical u-gap-16">
<img src={Github} alt="github" />
{#if $app.themeInUse === 'dark'}
<img src={GithubDark} alt="github" />
{:else}
<img src={GithubLight} alt="github" />
{/if}
</div>
<div class="grid-1-2-col-2 u-flex u-flex-vertical u-gap-24">
<h3 class="body-text-1">Coming Soon!</h3>
@@ -55,8 +55,8 @@
<TableCellHead width={140}>Created</TableCellHead>
<TableCellHead width={110}>Status</TableCellHead>
<TableCellHead width={90}>Trigger</TableCellHead>
<TableCellHead width={100}>Duration</TableCellHead>
<TableCellHead width={40} />
<TableCellHead width={80}>Duration</TableCellHead>
<TableCellHead width={50} />
</TableHeader>
<TableBody>
{#each data.executions.executions as execution}
@@ -4,9 +4,10 @@
Box,
DropList,
DropListItem,
Copy,
Empty,
EventModal
EventModal,
Output,
Secret
} from '$lib/components';
import { Container } from '$lib/layout';
import { Button, InputNumber, InputText, InputCron, Form, FormList } from '$lib/elements/forms';
@@ -25,7 +26,15 @@
import { Roles } from '$lib/components/permissions';
import { symmetricDifference } from '$lib/helpers/array';
import TableList from '$lib/elements/table/tableList.svelte';
import { TableCell, TableCellText } from '$lib/elements/table';
import {
Table,
TableBody,
TableCell,
TableCellHead,
TableCellText,
TableHeader,
TableRow
} from '$lib/elements/table';
import Heading from '$lib/components/heading.svelte';
import { writable, type Writable } from 'svelte/store';
import { invalidate } from '$app/navigation';
@@ -40,7 +49,6 @@
let selectedVar: Models.Variable = null;
// let showVariablesUpload = false;
let showVariablesModal = false;
let showVariablesValue = [];
let showVariablesDropdown = [];
let timeout: number = null;
let functionName: string = null;
@@ -300,7 +308,7 @@
<div>
<Heading tag="h6" size="7">{$func.name}</Heading>
<p>{$func.runtime}</p>
<p class="text u-capitalize">{$func.runtime}</p>
</div>
</div>
<svelte:fragment slot="aside">
@@ -346,7 +354,12 @@
<Heading tag="h6" size="7">Execute Access</Heading>
<p>
Choose who can execute this function using the client API. For more information,
check out the Permissions Guide in our documentation.
check out the <a
href="https://appwrite.io/docs/permissions"
target="_blank"
rel="noopener noreferrer"
class="link">
Permissions Guide</a> in our documentation.
</p>
<svelte:fragment slot="aside">
<Roles bind:roles={permissions} />
@@ -364,28 +377,28 @@
<p>Set the events that will trigger your function. Maximum 100 events allowed.</p>
<svelte:fragment slot="aside">
{#if $eventSet.size}
<TableList>
{#each Array.from($eventSet) as event}
<li class="table-row">
<TableCellText title="id">
{event}
</TableCellText>
<TableCell showOverflow title="options" width={40}>
<button
class="button is-text is-only-icon"
aria-label="delete id"
on:click|preventDefault={() => {
$eventSet.delete(event);
eventSet.set($eventSet);
}}>
<span class="icon-x" aria-hidden="true" />
</button>
</TableCell>
</li>
{/each}
</TableList>
<div class="u-flex u-flex-vertical u-gap-16">
<TableList>
{#each Array.from($eventSet) as event}
<li class="table-row">
<TableCellText title="id">
{event}
</TableCellText>
<TableCell showOverflow title="options" width={40}>
<button
class="button is-text is-only-icon"
aria-label="delete id"
on:click|preventDefault={() => {
$eventSet.delete(event);
eventSet.set($eventSet);
}}>
<span class="icon-x" aria-hidden="true" />
</button>
</TableCell>
</li>
{/each}
</TableList>
<div class="u-flex u-margin-block-start-16">
<Button text noMargin on:click={() => (showEvents = true)}>
<span class="icon-plus" aria-hidden="true" />
<span class="u-text">Add event</span>
@@ -407,7 +420,7 @@
<Heading tag="h6" size="7">Update CRON Schedule</Heading>
<p>
Set a CRON schedule to trigger your function. Leave blank for no schedule. <a
href="https://appwrite.io/docs/functions#createFunction"
href="https://en.wikipedia.org/wiki/Cron"
target="_blank"
rel="noopener noreferrer"
class="link">
@@ -428,6 +441,98 @@
</CardGrid>
</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>
<svelte:fragment slot="aside">
<div class="u-flex u-margin-inline-start-auto u-gap-16">
<Button disabled={!data.variables.total} 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 data.variables.total}
<div class="u-flex u-flex-vertical u-gap-16">
<Table noMargin noStyles>
<TableHeader>
<TableCellHead>Key</TableCellHead>
<TableCellHead>Value</TableCellHead>
<TableCellHead width={30} />
</TableHeader>
<TableBody>
{#each data.variables.variables as variable, i}
<TableRow>
<TableCell title="key">
<Output value={variable.key}>
{variable.key}
</Output>
</TableCell>
<TableCell showOverflow title="value">
<Secret value={variable.value} />
</TableCell>
<TableCell showOverflow title="options">
<DropList
bind:show={showVariablesDropdown[i]}
placement="bottom-start"
noArrow>
<Button
text
round
ariaLabel="more options"
on:click={() =>
(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>
</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
<Button
text
noMargin
on:click={() => {
showVariablesModal = true;
}}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create variable</span>
</Button>
</div>
{:else}
<Empty on:click={() => (showVariablesModal = !showVariablesModal)}
>Create a variable to get started</Empty>
{/if}
</svelte:fragment>
</CardGrid>
<Form on:submit={updateTimeout}>
<CardGrid>
<Heading tag="h6" size="7">Update Timeout</Heading>
@@ -452,124 +557,6 @@
</CardGrid>
</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>
<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>
</svelte:fragment>
</CardGrid>
<CardGrid danger>
<Heading tag="h6" size="7">Delete Function</Heading>
<p>
@@ -42,9 +42,8 @@
{#if !showCustomId}
<div>
<Pill button on:click={() => (showCustomId = !showCustomId)}>
<span class="icon-pencil" aria-hidden="true" /><span class="text">
Function ID
</span>
<span class="icon-pencil" aria-hidden="true" />
<span class="text">Function ID </span>
</Pill>
</div>
{:else}
@@ -2,14 +2,13 @@
import { WizardStep } from '$lib/layout';
import { createFunction } from './store';
import Create from '../createVariable.svelte';
import { DropList, DropListItem, Secret, Empty } from '$lib/components';
import { DropList, DropListItem, Secret, Empty, Output } from '$lib/components';
import type { Models } from '@aw-labs/appwrite-console';
import {
Table,
TableBody,
TableCell,
TableCellHead,
TableCellText,
TableHeader,
TableRow
} from '$lib/elements/table';
@@ -59,21 +58,23 @@
<TableBody>
{#each $createFunction.vars as variable, i}
<TableRow>
<TableCellText title="key">
{variable.key}
</TableCellText>
<TableCell title="key">
<Output value={variable.key}>
{variable.key}
</Output>
</TableCell>
<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])}>
<Button
text
round
ariaLabel="more options"
on:click={() => (showDropdown[i] = !showDropdown[i])}>
<span class="icon-dots-horizontal" aria-hidden="true" />
</button>
</Button>
<svelte:fragment slot="list">
<DropListItem
icon="pencil"