Skip to content

Commit 7331b3a

Browse files
authored
Merge pull request #3097 from appwrite/fix-create-function-env-variable-bugs
fix: env variable overwrite and action menu clipping in create function wizard
2 parents b6f1e6b + 2aa0eb7 commit 7331b3a

3 files changed

Lines changed: 160 additions & 76 deletions

File tree

src/lib/components/variables/environmentVariables.svelte

Lines changed: 25 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,17 @@
22
import { Empty, Paginator } from '$lib/components';
33
import { Button } from '$lib/elements/forms';
44
import {
5-
ActionMenu,
65
Accordion,
76
Badge,
87
InteractiveText,
98
Icon,
109
Layout,
11-
Popover,
1210
Skeleton,
1311
Table,
14-
Tooltip,
15-
Button as PinkButton
12+
Tooltip
1613
} from '@appwrite.io/pink-svelte';
17-
import {
18-
IconDotsHorizontal,
19-
IconCode,
20-
IconUpload,
21-
IconPlus,
22-
IconTrash,
23-
IconEyeOff,
24-
IconPencil
25-
} from '@appwrite.io/pink-icons-svelte';
14+
import { IconCode, IconUpload, IconPlus } from '@appwrite.io/pink-icons-svelte';
15+
import VariableActionMenu from './variableActionMenu.svelte';
2616
import type { Models } from '@appwrite.io/console';
2717
import VariableEditorModal from './variableEditorModal.svelte';
2818
import SecretVariableModal from './secretVariableModal.svelte';
@@ -66,14 +56,14 @@
6656
const tableColumns = $derived(
6757
$isSmallViewport
6858
? [
69-
{ id: 'key', width: { min: 420 } },
70-
{ id: 'value', width: { min: 240 } },
59+
{ id: 'key', width: { min: 120, max: 300 } },
60+
{ id: 'value', width: { min: 100, max: 200 } },
7161
{ id: 'actions', width: 40 }
7262
]
7363
: [
74-
{ id: 'key', width: { min: 300 } },
75-
{ id: 'value', width: { min: 280 } },
76-
{ id: 'actions', width: 40 }
64+
{ id: 'key', width: { min: 280, max: 420 } },
65+
{ id: 'value', width: { min: 200, max: 400 } },
66+
{ id: 'actions', width: 50 }
7767
]
7868
);
7969
</script>
@@ -111,13 +101,15 @@
111101
<Button
112102
secondary
113103
size="s"
104+
icon={$isSmallViewport}
114105
on:click={() => {
115106
showCreate = true;
116107
trackEvent(Click.VariablesCreateClick, {
117108
source: createSource
118109
});
119110
}}>
120-
<Icon slot="start" icon={IconPlus} /> Create variable
111+
<Icon slot="start" icon={IconPlus} />
112+
{#if !$isSmallViewport}Create variable{/if}
121113
</Button>
122114
{/if}
123115
</Layout.Stack>
@@ -179,59 +171,20 @@
179171
</Table.Cell>
180172
<Table.Cell column="actions" {root}>
181173
<div style="margin-inline-start: auto">
182-
<Popover
183-
padding="none"
184-
placement="bottom-end"
185-
let:toggle>
186-
<PinkButton.Button
187-
icon
188-
variant="text"
189-
size="s"
190-
aria-label="More options"
191-
onclick={(e) => {
192-
e.preventDefault();
193-
toggle(e);
194-
}}>
195-
<Icon icon={IconDotsHorizontal} size="s" />
196-
</PinkButton.Button>
197-
198-
<svelte:fragment slot="tooltip" let:toggle>
199-
<ActionMenu.Root>
200-
{#if !variable?.secret}
201-
<ActionMenu.Item.Button
202-
leadingIcon={IconPencil}
203-
onclick={(e) => {
204-
toggle(e);
205-
currentVariable = variable;
206-
showUpdate = true;
207-
}}>
208-
Update
209-
</ActionMenu.Item.Button>
210-
{/if}
211-
{#if !variable?.secret}
212-
<ActionMenu.Item.Button
213-
leadingIcon={IconEyeOff}
214-
onclick={(e) => {
215-
toggle(e);
216-
currentVariable = variable;
217-
showSecretModal = true;
218-
}}>
219-
Secret
220-
</ActionMenu.Item.Button>
221-
{/if}
222-
<ActionMenu.Item.Button
223-
status="danger"
224-
leadingIcon={IconTrash}
225-
onclick={(e) => {
226-
toggle(e);
227-
currentVariable = variable;
228-
showDelete = true;
229-
}}>
230-
Delete
231-
</ActionMenu.Item.Button>
232-
</ActionMenu.Root>
233-
</svelte:fragment>
234-
</Popover>
174+
<VariableActionMenu
175+
{variable}
176+
onUpdate={() => {
177+
currentVariable = variable;
178+
showUpdate = true;
179+
}}
180+
onSecret={() => {
181+
currentVariable = variable;
182+
showSecretModal = true;
183+
}}
184+
onDelete={() => {
185+
currentVariable = variable;
186+
showDelete = true;
187+
}} />
235188
</div>
236189
</Table.Cell>
237190
</Table.Row.Base>

src/lib/components/variables/updateVariableModal.svelte

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
function handleVariable() {
2424
if (selectedVar) {
2525
variables = variables.map((variable) => {
26-
if (variable.$id === selectedVar.$id) {
27-
return pair;
28-
}
29-
return variable;
26+
const match = selectedVar.$id
27+
? variable.$id === selectedVar.$id
28+
: variable.key === selectedVar.key;
29+
return match ? pair : variable;
3030
});
3131
} else {
3232
variables = [...variables, pair];
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<script lang="ts">
2+
import { computePosition, flip, offset, shift, autoUpdate } from '@floating-ui/dom';
3+
import { Icon, ActionMenu } from '@appwrite.io/pink-svelte';
4+
import {
5+
IconDotsHorizontal,
6+
IconPencil,
7+
IconEyeOff,
8+
IconTrash
9+
} from '@appwrite.io/pink-icons-svelte';
10+
import { Button as PinkButton } from '@appwrite.io/pink-svelte';
11+
import type { Models } from '@appwrite.io/console';
12+
13+
let {
14+
variable,
15+
onUpdate,
16+
onSecret,
17+
onDelete
18+
}: {
19+
variable: Partial<Models.Variable>;
20+
onUpdate: () => void;
21+
onSecret: () => void;
22+
onDelete: () => void;
23+
} = $props();
24+
25+
let open = $state(false);
26+
let triggerEl = $state<HTMLElement | null>(null);
27+
let menuEl = $state<HTMLElement | null>(null);
28+
let cleanup: (() => void) | null = null;
29+
30+
function hide() {
31+
open = false;
32+
}
33+
34+
function toggle() {
35+
open = !open;
36+
}
37+
38+
function portalToBody(node: HTMLElement) {
39+
document.body.appendChild(node);
40+
return {
41+
destroy() {
42+
node.parentNode?.removeChild(node);
43+
}
44+
};
45+
}
46+
47+
$effect(() => {
48+
if (open && triggerEl && menuEl) {
49+
cleanup = autoUpdate(triggerEl, menuEl, () => {
50+
computePosition(triggerEl, menuEl, {
51+
placement: 'bottom-end',
52+
middleware: [offset(2), flip(), shift()]
53+
}).then(({ x, y }) => {
54+
if (menuEl) {
55+
Object.assign(menuEl.style, { left: `${x}px`, top: `${y}px` });
56+
}
57+
});
58+
});
59+
} else {
60+
cleanup?.();
61+
cleanup = null;
62+
}
63+
});
64+
65+
function handleWindowClick(e: MouseEvent) {
66+
if (!open) return;
67+
const target = e.target as Node;
68+
if (triggerEl?.contains(target) || menuEl?.contains(target)) return;
69+
hide();
70+
}
71+
72+
function handleKeydown(e: KeyboardEvent) {
73+
if (e.key === 'Escape') hide();
74+
}
75+
</script>
76+
77+
<svelte:window onclick={handleWindowClick} onkeydown={handleKeydown} />
78+
79+
<span bind:this={triggerEl}>
80+
<PinkButton.Button
81+
icon
82+
variant="text"
83+
size="s"
84+
aria-label="More options"
85+
onclick={(e) => {
86+
e.preventDefault();
87+
toggle();
88+
}}>
89+
<Icon icon={IconDotsHorizontal} size="s" />
90+
</PinkButton.Button>
91+
</span>
92+
93+
{#if open}
94+
<div
95+
use:portalToBody
96+
bind:this={menuEl}
97+
style="position: fixed; z-index: 9001; background: var(--bgcolor-neutral-primary); border: var(--border-width-s) solid var(--border-neutral); border-radius: var(--border-radius-m); box-shadow: 0 1px 3px 0 rgba(0,0,0,0.03), 0 4px 4px 0 rgba(0,0,0,0.04); overflow: hidden;"
98+
role="menu">
99+
<ActionMenu.Root>
100+
{#if !variable?.secret}
101+
<ActionMenu.Item.Button
102+
leadingIcon={IconPencil}
103+
on:click={() => {
104+
hide();
105+
onUpdate();
106+
}}>
107+
Update
108+
</ActionMenu.Item.Button>
109+
{/if}
110+
{#if !variable?.secret}
111+
<ActionMenu.Item.Button
112+
leadingIcon={IconEyeOff}
113+
on:click={() => {
114+
hide();
115+
onSecret();
116+
}}>
117+
Secret
118+
</ActionMenu.Item.Button>
119+
{/if}
120+
<ActionMenu.Item.Button
121+
status="danger"
122+
leadingIcon={IconTrash}
123+
on:click={() => {
124+
hide();
125+
onDelete();
126+
}}>
127+
Delete
128+
</ActionMenu.Item.Button>
129+
</ActionMenu.Root>
130+
</div>
131+
{/if}

0 commit comments

Comments
 (0)