Skip to content

Commit 27de654

Browse files
committed
Merge branch 'main' into e2e
2 parents 0441538 + 60d0bdb commit 27de654

36 files changed

Lines changed: 455 additions & 333 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Copilot Setup Steps
2+
3+
# Automatically run the setup steps when they are changed to allow for easy validation, and
4+
# allow manual testing through the repository's "Actions" tab
5+
on:
6+
workflow_dispatch:
7+
push:
8+
paths:
9+
- .github/workflows/copilot-setup-steps.yml
10+
pull_request:
11+
paths:
12+
- .github/workflows/copilot-setup-steps.yml
13+
14+
jobs:
15+
copilot-setup-steps:
16+
runs-on: ubuntu-latest
17+
permissions:
18+
contents: read
19+
steps:
20+
- uses: actions/checkout@v5
21+
- name: Use Node.js
22+
uses: actions/setup-node@v6
23+
with:
24+
node-version: 20
25+
- name: Install pnpm
26+
uses: pnpm/action-setup@v4
27+
- name: Install dependencies
28+
run: pnpm install --frozen-lockfile
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script lang="ts">
2+
import { Copy } from '.';
3+
import { Icon, Tag } from '@appwrite.io/pink-svelte';
4+
import { IconDuplicate } from '@appwrite.io/pink-icons-svelte';
5+
import { getProjectEndpoint } from '$lib/helpers/project';
6+
</script>
7+
8+
<Copy value={getProjectEndpoint()} copyText="Copy endpoint">
9+
<Tag size="xs" variant="code">
10+
<Icon icon={IconDuplicate} size="s" slot="start" />
11+
<span style:white-space="nowrap" style:overflow="hidden" style:word-break="break-all">
12+
API endpoint
13+
</span>
14+
</Tag>
15+
</Copy>

src/lib/components/backupRestoreBox.svelte

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -125,20 +125,18 @@
125125
126126
onMount(() => {
127127
// fast path: don't subscribe if org is on a free plan or is self-hosted.
128-
if (isSelfHosted || (isCloud && $organization.billingPlan === BillingPlan.FREE)) return;
129-
130-
return realtime
131-
.forProject(page.params.region, page.params.project)
132-
.subscribe('console', (response) => {
133-
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
134-
135-
if (
136-
response.events.includes('archives.*') ||
137-
response.events.includes('restorations.*')
138-
) {
139-
updateOrAddItem(response.payload);
140-
}
141-
});
128+
if (isSelfHosted || (isCloud && $organization?.billingPlan === BillingPlan.FREE)) return;
129+
130+
return realtime.forProject(page.params.region, 'console', (response) => {
131+
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
132+
133+
if (
134+
response.events.includes('archives.*') ||
135+
response.events.includes('restorations.*')
136+
) {
137+
updateOrAddItem(response.payload);
138+
}
139+
});
142140
});
143141
</script>
144142

src/lib/components/copy.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
disabled={tooltipDisabled}
5858
portal={tooltipPortal}
5959
delay={tooltipDelay}
60+
maxWidth="500px"
6061
placement={tooltipPlacement}>
6162
<span
6263
data-private

src/lib/components/csvImportBox.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
import { onMount } from 'svelte';
33
import { base } from '$app/paths';
44
import { page } from '$app/state';
5-
import { sdk } from '$lib/stores/sdk';
65
import { Dependencies } from '$lib/constants';
6+
import { realtime, sdk } from '$lib/stores/sdk';
77
import { goto, invalidate } from '$app/navigation';
88
import { getProjectId } from '$lib/helpers/project';
99
import { addNotification } from '$lib/stores/notifications';
@@ -187,7 +187,7 @@
187187
migrations.migrations.forEach(updateOrAddItem);
188188
});
189189
190-
return sdk.forConsoleIn(page.params.region).realtime.subscribe('console', (response) => {
190+
return realtime.forConsole(page.params.region, 'console', (response) => {
191191
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
192192
if (response.events.includes('migrations.*')) {
193193
updateOrAddItem(response.payload as Payload);

src/lib/components/id.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,11 @@
9595
export let tooltipPortal = false;
9696
export let tooltipDelay: number = 0;
9797
export let tooltipPlacement: TooltipPlacement = undefined;
98+
export let copyText: string | undefined = undefined;
9899
</script>
99100

100101
{#key value}
101-
<Copy {value} {event} {tooltipPortal} {tooltipDelay} {tooltipPlacement}>
102+
<Copy {value} {event} {tooltipPortal} {tooltipDelay} {tooltipPlacement} {copyText}>
102103
<Tag size="xs" variant="code">
103104
<Icon icon={IconDuplicate} size="s" slot="start" />
104105
<span

src/lib/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export { default as BottomSheet } from './bottom-sheet/index';
8282
export { default as Confirm } from './confirm.svelte';
8383
export { default as UsageCard } from './usageCard.svelte';
8484
export { default as ViewToggle } from './viewToggle.svelte';
85+
export { default as ApiEndpoint } from './apiEndpoint.svelte';
8586
export { default as RegionEndpoint } from './regionEndpoint.svelte';
8687
export { default as ExpirationInput } from './expirationInput.svelte';
8788
export { default as EstimatedCard } from './estimatedCard.svelte';

src/lib/components/migrationBox.svelte

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,14 @@
5050
})();
5151
5252
onMount(() => {
53-
return realtime
54-
.forProject(page.params.region, page.params.project)
55-
.subscribe<Models.Migration>(['console'], async (response) => {
56-
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
57-
if (response.events.includes('migrations.*')) {
58-
if (response.payload.source === 'Backup') return;
59-
migration = response.payload;
60-
}
61-
});
53+
return realtime.forProject(page.params.region, ['console'], async (response) => {
54+
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
55+
if (response.events.includes('migrations.*')) {
56+
const payload = response.payload as Models.Migration;
57+
if (payload.source === 'Backup') return;
58+
migration = payload;
59+
}
60+
});
6261
});
6362
</script>
6463

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<script lang="ts">
22
import { Copy } from '.';
33
import { sdk } from '$lib/stores/sdk';
4-
import { Layout, Tag } from '@appwrite.io/pink-svelte';
4+
import { Icon, Tag } from '@appwrite.io/pink-svelte';
5+
import { IconDuplicate } from '@appwrite.io/pink-icons-svelte';
56
import { Flag, type Models } from '@appwrite.io/console';
6-
import { truncateText } from '$lib/components/id.svelte';
77
import { isValueOfStringEnum } from '$lib/helpers/types';
88
import { getProjectEndpoint } from '$lib/helpers/project';
99
@@ -21,28 +21,28 @@
2121
</script>
2222

2323
{#if region}
24-
<Copy value={getProjectEndpoint()} copyText="Copy endpoint">
25-
<Tag size="xs" variant="default">
26-
<Layout.Stack direction="row" gap="s" alignItems="center" inline>
27-
{#if flagSrc}
28-
<img
29-
width={16}
30-
height={12}
31-
src={flagSrc}
32-
alt={region?.name}
33-
style:border-radius="2.5px" />
34-
{/if}
35-
36-
<span
37-
style:white-space="nowrap"
38-
class="text u-line-height-1-5"
39-
style:overflow="hidden"
40-
style:word-break="break-all"
41-
use:truncateText
42-
style:font-family="unset">
43-
{region?.name}
44-
</span>
45-
</Layout.Stack>
24+
<Copy value={getProjectEndpoint()} copyText={`Copy endpoint (${region.name})`}>
25+
<Tag size="xs" variant="code">
26+
<Icon icon={IconDuplicate} size="s" slot="start" />
27+
<span class="endpoint-label"> API endpoint </span>
28+
{#if flagSrc}
29+
<img class="region-flag" src={flagSrc} alt={region?.name} />
30+
{/if}
4631
</Tag>
4732
</Copy>
4833
{/if}
34+
35+
<style>
36+
.endpoint-label {
37+
white-space: nowrap;
38+
overflow: hidden;
39+
word-break: break-all;
40+
}
41+
42+
.region-flag {
43+
width: 16px;
44+
height: 12px;
45+
border-radius: 2.5px;
46+
margin-inline-start: 6px;
47+
}
48+
</style>

src/lib/stores/sdk.ts

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import {
4242
SUBDOMAIN_TOR
4343
} from '$lib/constants';
4444
import { building } from '$app/environment';
45-
import { getProjectId } from '$lib/helpers/project';
4645

4746
export function getApiEndpoint(region?: string): string {
4847
if (building) return '';
@@ -141,12 +140,32 @@ const sdkForProject = {
141140
};
142141

143142
export const realtime = {
144-
forProject(region: string, _projectId: string) {
143+
forProject(
144+
region: string,
145+
channels: string | string[],
146+
callback: AppwriteRealtimeResponseEvent
147+
) {
145148
const endpoint = getApiEndpoint(region);
146149
if (endpoint !== clientRealtime.config.endpoint) {
147150
clientRealtime.setEndpoint(endpoint);
148151
}
149-
return clientRealtime;
152+
153+
// because uses a different client!
154+
const realtime = new Realtime(clientRealtime);
155+
156+
return createRealtimeSubscription(realtime, channels, callback);
157+
},
158+
159+
forConsole(
160+
region: string,
161+
channels: string | string[],
162+
callback: AppwriteRealtimeResponseEvent
163+
): () => void {
164+
const realtimeInstance = region
165+
? sdk.forConsoleIn(region).realtime
166+
: sdk.forConsole.realtime;
167+
168+
return createRealtimeSubscription(realtimeInstance, channels, callback);
150169
}
151170
};
152171

@@ -176,8 +195,8 @@ export const sdk = {
176195
};
177196

178197
export enum RuleType {
179-
DEPLOYMENT = 'deployment',
180198
API = 'api',
199+
DEPLOYMENT = 'deployment',
181200
REDIRECT = 'redirect'
182201
}
183202

@@ -191,11 +210,24 @@ export enum RuleTrigger {
191210
MANUAL = 'manual'
192211
}
193212

194-
/**
195-
* Some type imports are broken on the SDK, this works correctly for the time being!
196-
*/
197-
export type AppwriteRealtimeSubscription = Awaited<ReturnType<Realtime['subscribe']>>;
198-
199-
export const createAdminClient = () => {
200-
return new Client().setEndpoint(getApiEndpoint()).setMode('admin').setProject(getProjectId());
213+
export type RealtimeResponse = {
214+
events: string[];
215+
channels: string[];
216+
timestamp: string;
217+
payload: unknown;
201218
};
219+
220+
export type AppwriteRealtimeResponseEvent = (response: RealtimeResponse) => void;
221+
222+
function createRealtimeSubscription(
223+
realtimeInstance: Realtime,
224+
channels: string | string[],
225+
callback: AppwriteRealtimeResponseEvent
226+
): () => void {
227+
const channelsArray = Array.isArray(channels) ? channels : [channels];
228+
const subscriptionPromise = realtimeInstance.subscribe(channelsArray, callback);
229+
230+
return () => {
231+
subscriptionPromise.then((sub) => sub.close());
232+
};
233+
}

0 commit comments

Comments
 (0)