Skip to content

Commit bd6a99f

Browse files
committed
add enable and disable all to protocol ui for consistency
1 parent 5885084 commit bd6a99f

File tree

1 file changed

+150
-24
lines changed

1 file changed

+150
-24
lines changed

src/routes/(console)/project-[region]-[project]/settings/updateProtocols.svelte

Lines changed: 150 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,36 @@
88
import { protocols, type Protocol } from '$lib/stores/project-protocols';
99
import { sdk } from '$lib/stores/sdk';
1010
import { project } from '../store';
11-
import { Divider, Layout, Spinner } from '@appwrite.io/pink-svelte';
11+
import Button from '$lib/elements/forms/button.svelte';
12+
import { Dialog, Divider, Layout, Spinner } from '@appwrite.io/pink-svelte';
1213
import { SvelteSet } from 'svelte/reactivity';
1314
import { ProtocolId } from '@appwrite.io/console';
15+
import { get } from 'svelte/store';
1416
17+
let isUpdatingAllProtocols = $state(false);
18+
let showUpdateProtocolDialog = $state(false);
19+
let updateProtocolsEnabledMode = $state<boolean | null>(null);
1520
let apiProtocolUpdates = new SvelteSet<ProtocolId>();
1621
const protocolDescriptions: Record<ProtocolId, string> = {
1722
[ProtocolId.Rest]: 'Standard HTTP API requests from client SDKs.',
1823
[ProtocolId.Graphql]: 'GraphQL API access for queries and mutations.',
1924
[ProtocolId.Websocket]: 'Realtime subscriptions over WebSocket connections.'
2025
};
26+
const isAnyProtocolUpdating = $derived(apiProtocolUpdates.size > 0);
27+
const isAnyUpdateInProgress = $derived(isUpdatingAllProtocols || isAnyProtocolUpdating);
28+
29+
const allProtocolsEnabled = $derived.by(() => {
30+
if (isAnyUpdateInProgress) return false;
31+
return $protocols.list.every((protocol) => protocol.value);
32+
});
33+
34+
const allProtocolsDisabled = $derived.by(() => {
35+
if (isAnyUpdateInProgress) return false;
36+
return $protocols.list.every((protocol) => !protocol.value);
37+
});
38+
39+
const shouldDisableEnableAllButton = $derived(isAnyUpdateInProgress || allProtocolsEnabled);
40+
const shouldDisableDisableAllButton = $derived(isAnyUpdateInProgress || allProtocolsDisabled);
2141
2242
async function protocolUpdate(protocol: Protocol) {
2343
apiProtocolUpdates.add(protocol.method);
@@ -51,6 +71,60 @@
5171
}
5272
}
5373
74+
async function toggleAllProtocols(status: boolean) {
75+
isUpdatingAllProtocols = true;
76+
77+
try {
78+
const projectSdk = sdk.forProject($project.region, $project.$id);
79+
for (const protocol of get(protocols).list) {
80+
if (protocol.value === status) continue;
81+
await projectSdk.project.updateProtocolStatus({
82+
protocolId: protocol.method,
83+
enabled: status
84+
});
85+
}
86+
87+
await invalidate(Dependencies.PROJECT);
88+
89+
addNotification({
90+
type: 'success',
91+
message:
92+
'All protocols for ' +
93+
$project.name +
94+
' have been ' +
95+
(status ? 'enabled.' : 'disabled.')
96+
});
97+
trackEvent(Submit.ProjectService);
98+
} catch (error) {
99+
addNotification({
100+
type: 'error',
101+
message: error.message
102+
});
103+
trackError(error, Submit.ProjectService);
104+
} finally {
105+
isUpdatingAllProtocols = false;
106+
showUpdateProtocolDialog = false;
107+
updateProtocolsEnabledMode = null;
108+
}
109+
}
110+
111+
const dialogDetails = $derived.by(() => {
112+
if (updateProtocolsEnabledMode) {
113+
return {
114+
title: 'Enable all protocols',
115+
message: 'All project protocols will be enabled.',
116+
actionButton: 'Enable all'
117+
};
118+
} else {
119+
return {
120+
title: 'Disable all protocols',
121+
message:
122+
'Are you sure you want to disable all protocols? This will disable client access over those protocols until they are re-enabled.',
123+
actionButton: 'Disable all'
124+
};
125+
}
126+
});
127+
54128
$effect(() => protocols.load($project));
55129
</script>
56130

@@ -60,44 +134,96 @@
60134
until re-enabled.
61135
<svelte:fragment slot="aside">
62136
<div class="protocols-list">
63-
<Layout.Stack gap="xs">
64-
{#each $protocols.list as protocol, index}
65-
<div class="protocol-row">
66-
<div class="protocol-control">
67-
<InputSwitch
68-
id={protocol.method}
69-
label={protocol.label}
70-
description={protocolDescriptions[protocol.method]}
71-
bind:value={protocol.value}
72-
on:change={() => protocolUpdate(protocol)}
73-
disabled={apiProtocolUpdates.has(protocol.method)} />
74-
75-
{#if apiProtocolUpdates.has(protocol.method)}
76-
<span class="protocol-spinner">
77-
<Spinner size="s" />
78-
</span>
79-
{/if}
137+
<div class="protocol-toolbar">
138+
<Layout.Stack direction="row" alignItems="center" gap="s">
139+
<Button
140+
extraCompact
141+
on:click={() => {
142+
showUpdateProtocolDialog = true;
143+
updateProtocolsEnabledMode = true;
144+
}}
145+
disabled={shouldDisableEnableAllButton}>Enable all</Button>
146+
<span style:height="20px">
147+
<Divider vertical />
148+
</span>
149+
<Button
150+
extraCompact
151+
on:click={() => {
152+
showUpdateProtocolDialog = true;
153+
updateProtocolsEnabledMode = false;
154+
}}
155+
disabled={shouldDisableDisableAllButton}>Disable all</Button>
156+
</Layout.Stack>
157+
</div>
158+
<Divider />
159+
<div class="protocol-list-content">
160+
<Layout.Stack gap="xs">
161+
{#each $protocols.list as protocol, index}
162+
<div class="protocol-row">
163+
<div class="protocol-control">
164+
<InputSwitch
165+
id={protocol.method}
166+
label={protocol.label}
167+
description={protocolDescriptions[protocol.method]}
168+
bind:value={protocol.value}
169+
on:change={() => protocolUpdate(protocol)}
170+
disabled={apiProtocolUpdates.has(protocol.method)} />
171+
172+
{#if apiProtocolUpdates.has(protocol.method)}
173+
<span class="protocol-spinner">
174+
<Spinner size="s" />
175+
</span>
176+
{/if}
177+
</div>
80178
</div>
81-
</div>
82179

83-
{#if index < $protocols.list.length - 1}
84-
<Divider />
85-
{/if}
86-
{/each}
87-
</Layout.Stack>
180+
{#if index < $protocols.list.length - 1}
181+
<Divider />
182+
{/if}
183+
{/each}
184+
</Layout.Stack>
185+
</div>
88186
</div>
89187
</svelte:fragment>
90188
</CardGrid>
91189

190+
<Dialog title={dialogDetails.title} bind:open={showUpdateProtocolDialog}>
191+
<p class="text" data-private>{dialogDetails.message}</p>
192+
<svelte:fragment slot="footer">
193+
<Layout.Stack direction="row" gap="s" justifyContent="flex-end">
194+
<Button text on:click={() => (showUpdateProtocolDialog = false)}>Cancel</Button>
195+
196+
<Button
197+
secondary
198+
submissionLoader
199+
disabled={isUpdatingAllProtocols}
200+
forceShowLoader={isUpdatingAllProtocols}
201+
on:click={() => toggleAllProtocols(updateProtocolsEnabledMode)}>
202+
{dialogDetails.actionButton}
203+
</Button>
204+
</Layout.Stack>
205+
</svelte:fragment>
206+
</Dialog>
207+
92208
<style>
93209
.protocols-list {
94210
max-width: 36rem;
95211
}
96212
213+
.protocol-toolbar {
214+
display: flex;
215+
justify-content: flex-end;
216+
padding-bottom: var(--space-6);
217+
}
218+
97219
.protocol-row {
98220
width: 100%;
99221
}
100222
223+
.protocol-list-content {
224+
padding-top: var(--space-6);
225+
}
226+
101227
.protocol-control {
102228
display: flex;
103229
align-items: center;

0 commit comments

Comments
 (0)