Merge branch 'main' into e2e

This commit is contained in:
Darshan
2025-10-31 16:39:00 +05:30
36 changed files with 455 additions and 333 deletions
+28
View File
@@ -0,0 +1,28 @@
name: Copilot Setup Steps
# Automatically run the setup steps when they are changed to allow for easy validation, and
# allow manual testing through the repository's "Actions" tab
on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yml
pull_request:
paths:
- .github/workflows/copilot-setup-steps.yml
jobs:
copilot-setup-steps:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v5
- name: Use Node.js
uses: actions/setup-node@v6
with:
node-version: 20
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install dependencies
run: pnpm install --frozen-lockfile
+15
View File
@@ -0,0 +1,15 @@
<script lang="ts">
import { Copy } from '.';
import { Icon, Tag } from '@appwrite.io/pink-svelte';
import { IconDuplicate } from '@appwrite.io/pink-icons-svelte';
import { getProjectEndpoint } from '$lib/helpers/project';
</script>
<Copy value={getProjectEndpoint()} copyText="Copy endpoint">
<Tag size="xs" variant="code">
<Icon icon={IconDuplicate} size="s" slot="start" />
<span style:white-space="nowrap" style:overflow="hidden" style:word-break="break-all">
API endpoint
</span>
</Tag>
</Copy>
+10 -12
View File
@@ -125,20 +125,18 @@
onMount(() => {
// fast path: don't subscribe if org is on a free plan or is self-hosted.
if (isSelfHosted || (isCloud && $organization.billingPlan === BillingPlan.FREE)) return;
if (isSelfHosted || (isCloud && $organization?.billingPlan === BillingPlan.FREE)) return;
return realtime
.forProject(page.params.region, page.params.project)
.subscribe('console', (response) => {
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
return realtime.forProject(page.params.region, 'console', (response) => {
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
if (
response.events.includes('archives.*') ||
response.events.includes('restorations.*')
) {
updateOrAddItem(response.payload);
}
});
if (
response.events.includes('archives.*') ||
response.events.includes('restorations.*')
) {
updateOrAddItem(response.payload);
}
});
});
</script>
+1
View File
@@ -57,6 +57,7 @@
disabled={tooltipDisabled}
portal={tooltipPortal}
delay={tooltipDelay}
maxWidth="500px"
placement={tooltipPlacement}>
<span
data-private
+2 -2
View File
@@ -2,8 +2,8 @@
import { onMount } from 'svelte';
import { base } from '$app/paths';
import { page } from '$app/state';
import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import { realtime, sdk } from '$lib/stores/sdk';
import { goto, invalidate } from '$app/navigation';
import { getProjectId } from '$lib/helpers/project';
import { addNotification } from '$lib/stores/notifications';
@@ -187,7 +187,7 @@
migrations.migrations.forEach(updateOrAddItem);
});
return sdk.forConsoleIn(page.params.region).realtime.subscribe('console', (response) => {
return realtime.forConsole(page.params.region, 'console', (response) => {
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
if (response.events.includes('migrations.*')) {
updateOrAddItem(response.payload as Payload);
+2 -1
View File
@@ -95,10 +95,11 @@
export let tooltipPortal = false;
export let tooltipDelay: number = 0;
export let tooltipPlacement: TooltipPlacement = undefined;
export let copyText: string | undefined = undefined;
</script>
{#key value}
<Copy {value} {event} {tooltipPortal} {tooltipDelay} {tooltipPlacement}>
<Copy {value} {event} {tooltipPortal} {tooltipDelay} {tooltipPlacement} {copyText}>
<Tag size="xs" variant="code">
<Icon icon={IconDuplicate} size="s" slot="start" />
<span
+1
View File
@@ -82,6 +82,7 @@ export { default as BottomSheet } from './bottom-sheet/index';
export { default as Confirm } from './confirm.svelte';
export { default as UsageCard } from './usageCard.svelte';
export { default as ViewToggle } from './viewToggle.svelte';
export { default as ApiEndpoint } from './apiEndpoint.svelte';
export { default as RegionEndpoint } from './regionEndpoint.svelte';
export { default as ExpirationInput } from './expirationInput.svelte';
export { default as EstimatedCard } from './estimatedCard.svelte';
+8 -9
View File
@@ -50,15 +50,14 @@
})();
onMount(() => {
return realtime
.forProject(page.params.region, page.params.project)
.subscribe<Models.Migration>(['console'], async (response) => {
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
if (response.events.includes('migrations.*')) {
if (response.payload.source === 'Backup') return;
migration = response.payload;
}
});
return realtime.forProject(page.params.region, ['console'], async (response) => {
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
if (response.events.includes('migrations.*')) {
const payload = response.payload as Models.Migration;
if (payload.source === 'Backup') return;
migration = payload;
}
});
});
</script>
+24 -24
View File
@@ -1,9 +1,9 @@
<script lang="ts">
import { Copy } from '.';
import { sdk } from '$lib/stores/sdk';
import { Layout, Tag } from '@appwrite.io/pink-svelte';
import { Icon, Tag } from '@appwrite.io/pink-svelte';
import { IconDuplicate } from '@appwrite.io/pink-icons-svelte';
import { Flag, type Models } from '@appwrite.io/console';
import { truncateText } from '$lib/components/id.svelte';
import { isValueOfStringEnum } from '$lib/helpers/types';
import { getProjectEndpoint } from '$lib/helpers/project';
@@ -21,28 +21,28 @@
</script>
{#if region}
<Copy value={getProjectEndpoint()} copyText="Copy endpoint">
<Tag size="xs" variant="default">
<Layout.Stack direction="row" gap="s" alignItems="center" inline>
{#if flagSrc}
<img
width={16}
height={12}
src={flagSrc}
alt={region?.name}
style:border-radius="2.5px" />
{/if}
<span
style:white-space="nowrap"
class="text u-line-height-1-5"
style:overflow="hidden"
style:word-break="break-all"
use:truncateText
style:font-family="unset">
{region?.name}
</span>
</Layout.Stack>
<Copy value={getProjectEndpoint()} copyText={`Copy endpoint (${region.name})`}>
<Tag size="xs" variant="code">
<Icon icon={IconDuplicate} size="s" slot="start" />
<span class="endpoint-label"> API endpoint </span>
{#if flagSrc}
<img class="region-flag" src={flagSrc} alt={region?.name} />
{/if}
</Tag>
</Copy>
{/if}
<style>
.endpoint-label {
white-space: nowrap;
overflow: hidden;
word-break: break-all;
}
.region-flag {
width: 16px;
height: 12px;
border-radius: 2.5px;
margin-inline-start: 6px;
}
</style>
+43 -11
View File
@@ -42,7 +42,6 @@ import {
SUBDOMAIN_TOR
} from '$lib/constants';
import { building } from '$app/environment';
import { getProjectId } from '$lib/helpers/project';
export function getApiEndpoint(region?: string): string {
if (building) return '';
@@ -141,12 +140,32 @@ const sdkForProject = {
};
export const realtime = {
forProject(region: string, _projectId: string) {
forProject(
region: string,
channels: string | string[],
callback: AppwriteRealtimeResponseEvent
) {
const endpoint = getApiEndpoint(region);
if (endpoint !== clientRealtime.config.endpoint) {
clientRealtime.setEndpoint(endpoint);
}
return clientRealtime;
// because uses a different client!
const realtime = new Realtime(clientRealtime);
return createRealtimeSubscription(realtime, channels, callback);
},
forConsole(
region: string,
channels: string | string[],
callback: AppwriteRealtimeResponseEvent
): () => void {
const realtimeInstance = region
? sdk.forConsoleIn(region).realtime
: sdk.forConsole.realtime;
return createRealtimeSubscription(realtimeInstance, channels, callback);
}
};
@@ -176,8 +195,8 @@ export const sdk = {
};
export enum RuleType {
DEPLOYMENT = 'deployment',
API = 'api',
DEPLOYMENT = 'deployment',
REDIRECT = 'redirect'
}
@@ -191,11 +210,24 @@ export enum RuleTrigger {
MANUAL = 'manual'
}
/**
* Some type imports are broken on the SDK, this works correctly for the time being!
*/
export type AppwriteRealtimeSubscription = Awaited<ReturnType<Realtime['subscribe']>>;
export const createAdminClient = () => {
return new Client().setEndpoint(getApiEndpoint()).setMode('admin').setProject(getProjectId());
export type RealtimeResponse = {
events: string[];
channels: string[];
timestamp: string;
payload: unknown;
};
export type AppwriteRealtimeResponseEvent = (response: RealtimeResponse) => void;
function createRealtimeSubscription(
realtimeInstance: Realtime,
channels: string | string[],
callback: AppwriteRealtimeResponseEvent
): () => void {
const channelsArray = Array.isArray(channels) ? channels : [channels];
const subscriptionPromise = realtimeInstance.subscribe(channelsArray, callback);
return () => {
subscriptionPromise.then((sub) => sub.close());
};
}
@@ -27,15 +27,13 @@
import CsvImportBox from '$lib/components/csvImportBox.svelte';
onMount(() => {
return realtime
.forProject(page.params.region, page.params.project)
.subscribe(['project', 'console'], (response) => {
if (response.events.includes('stats.connections')) {
for (const [projectId, value] of Object.entries(response.payload)) {
stats.add(projectId, [new Date(response.timestamp).toISOString(), value]);
}
return realtime.forProject(page.params.region, ['project', 'console'], (response) => {
if (response.events.includes('stats.connections')) {
for (const [projectId, value] of Object.entries(response.payload)) {
stats.add(projectId, [new Date(response.timestamp).toISOString(), value]);
}
});
}
});
});
$: $registerCommands([
@@ -161,19 +161,14 @@
};
onMount(() => {
return realtime
.forProject(page.params.region, page.params.project)
.subscribe(['project', 'console'], (response) => {
// fast path return.
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
return realtime.forProject(page.params.region, ['project', 'console'], (response) => {
// fast path return.
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
if (
response.events.includes('archives.*') ||
response.events.includes('policies.*')
) {
invalidate(Dependencies.BACKUPS);
}
});
if (response.events.includes('archives.*') || response.events.includes('policies.*')) {
invalidate(Dependencies.BACKUPS);
}
});
});
</script>
@@ -20,7 +20,7 @@
<script lang="ts">
import { goto, invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { realtime, sdk } from '$lib/stores/sdk';
import { type RealtimeResponse, realtime, sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import {
table,
@@ -66,7 +66,6 @@
import IndexesSuggestions from '../(suggestions)/indexes.svelte';
import { showIndexesSuggestions, tableColumnSuggestions } from '../(suggestions)';
import type { RealtimeResponseEvent } from '@appwrite.io/console';
let editRow: EditRow;
let editRelatedRow: EditRelatedRow;
@@ -83,35 +82,33 @@
*/
let isWaterfallFromFaker = false;
let columnCreationHandler: ((response: RealtimeResponseEvent<unknown>) => void) | null = null;
let columnCreationHandler: ((response: RealtimeResponse) => void) | null = null;
onMount(() => {
expandTabs.set(preferences.getKey('tableHeaderExpanded', true));
return realtime
.forProject(page.params.region, page.params.project)
.subscribe(['project', 'console'], (response) => {
if (
response.events.includes('databases.*.tables.*.columns.*') ||
response.events.includes('databases.*.tables.*.indexes.*')
) {
if (isWaterfallFromFaker) {
columnCreationHandler?.(response);
}
// don't invalidate when -
// 1. from faker
// 2. ai columns creation
// 3. ai indexes creation
if (
!isWaterfallFromFaker &&
!$showIndexesSuggestions &&
!$tableColumnSuggestions.table
) {
invalidate(Dependencies.TABLE);
}
return realtime.forProject(page.params.region, ['project', 'console'], (response) => {
if (
response.events.includes('databases.*.tables.*.columns.*') ||
response.events.includes('databases.*.tables.*.indexes.*')
) {
if (isWaterfallFromFaker) {
columnCreationHandler?.(response);
}
});
// don't invalidate when -
// 1. from faker
// 2. ai columns creation
// 3. ai indexes creation
if (
!isWaterfallFromFaker &&
!$showIndexesSuggestions &&
!$tableColumnSuggestions.table
) {
invalidate(Dependencies.TABLE);
}
}
});
});
// TODO: use route ids instead of pathname
@@ -268,7 +265,7 @@
const availableColumns = new Set<string>();
const waitPromise = new Promise<void>((resolve) => (resolvePromise = resolve));
columnCreationHandler = (response) => {
columnCreationHandler = (response: RealtimeResponse) => {
const { events, payload } = response;
if (
@@ -21,30 +21,29 @@
onMount(() => {
let previousStatus = null;
return realtime
.forProject(page.params.region, page.params.project)
.subscribe<Models.Deployment>('console', (message) => {
if (
message.payload.status !== 'ready' &&
previousStatus === message.payload.status
) {
return;
}
previousStatus = message.payload.status;
if (message.events.includes('functions.*.deployments.*.create')) {
invalidate(Dependencies.DEPLOYMENTS);
return;
}
if (message.events.includes('functions.*.deployments.*.update')) {
invalidate(Dependencies.DEPLOYMENTS);
invalidate(Dependencies.FUNCTION);
return;
}
if (message.events.includes('functions.*.deployments.*.delete')) {
invalidate(Dependencies.DEPLOYMENTS);
return;
}
});
return realtime.forProject(page.params.region, 'console', (response) => {
const payload = response.payload as Models.Deployment;
if (payload.status !== 'ready' && previousStatus === payload.status) {
return;
}
previousStatus = payload.status;
if (response.events.includes('functions.*.deployments.*.create')) {
invalidate(Dependencies.DEPLOYMENTS);
return;
}
if (response.events.includes('functions.*.deployments.*.update')) {
invalidate(Dependencies.DEPLOYMENTS);
invalidate(Dependencies.FUNCTION);
return;
}
if (response.events.includes('functions.*.deployments.*.delete')) {
invalidate(Dependencies.DEPLOYMENTS);
return;
}
});
});
$: $registerCommands([
@@ -1,7 +1,7 @@
<script lang="ts">
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { sdk } from '$lib/stores/sdk';
import { realtime } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { type Models } from '@appwrite.io/console';
import { page } from '$app/state';
@@ -44,24 +44,18 @@
let showRedeploy = false;
onMount(() => {
const unsubscribe = sdk.forConsole.client.subscribe<Models.Deployment>(
'console',
(message) => {
if (
message.events.includes(
`functions.${page.params.function}.deployments.${page.params.deployment}.update`
)
) {
if (message.payload.status === 'ready') {
invalidate(Dependencies.DEPLOYMENT);
}
return realtime.forProject(page.params.region, 'console', (response) => {
if (
response.events.includes(
`functions.${page.params.function}.deployments.${page.params.deployment}.update`
)
) {
const payload = response.payload as Models.Deployment;
if (payload.status === 'ready') {
invalidate(Dependencies.DEPLOYMENT);
}
}
);
return () => {
unsubscribe();
};
});
});
export function badgeTypeDeployment(status: string) {
@@ -1,18 +1,16 @@
<script>
import { invalidate } from '$app/navigation';
import { page } from '$app/state';
import { Dependencies } from '$lib/constants';
import { realtime } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { page } from '$app/state';
import { realtime } from '$lib/stores/sdk';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
onMount(() => {
return realtime
.forProject(page.params.region, page.params.project)
.subscribe('functions.*.executions', (response) => {
if (response.events.includes('functions.*.executions.*')) {
invalidate(Dependencies.EXECUTIONS);
}
});
return realtime.forProject(page.params.region, 'functions.*.executions', (response) => {
if (response.events.includes('functions.*.executions.*')) {
invalidate(Dependencies.EXECUTIONS);
}
});
});
</script>
@@ -4,7 +4,7 @@
import { Dependencies } from '$lib/constants';
import { Button } from '$lib/elements/forms';
import { Container, ResponsiveContainerHeader } from '$lib/layout';
import { sdk } from '$lib/stores/sdk';
import { realtime } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { project } from '$routes/(console)/project-[region]-[project]/store';
import { base } from '$app/paths';
@@ -12,11 +12,13 @@
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
import Table from './table.svelte';
import { columns } from './store';
import type { PageProps } from './$types';
import { page } from '$app/state';
export let data;
let { data }: PageProps = $props();
onMount(() => {
return sdk.forConsole.realtime.subscribe('console', (response) => {
return realtime.forConsole(page.params.region, 'console', (response) => {
if (response.events.includes('functions.*.executions.*')) {
invalidate(Dependencies.EXECUTIONS);
}
@@ -15,6 +15,7 @@
import { writable } from 'svelte/store';
import Scopes from '../api-keys/scopes.svelte';
import { page } from '$app/state';
import { copy } from '$lib/helpers/copy';
const projectId = page.params.project;
@@ -28,7 +29,7 @@
async function create() {
try {
const { $id } = await sdk.forConsole.projects.createKey({
const { $id, secret } = await sdk.forConsole.projects.createKey({
projectId,
name,
scopes,
@@ -45,7 +46,21 @@
);
addNotification({
message: `API key has been created`,
type: 'success'
type: 'success',
buttons: [
{
name: 'Copy API key',
method: async () => {
await copy(secret);
}
},
{
name: 'Copy endpoint',
method: async () => {
await copy(sdk.forConsole.client.config.endpoint);
}
}
]
});
} catch (error) {
addNotification({
@@ -3,6 +3,10 @@
import { page } from '$app/state';
import { Cover, CoverTitle } from '$lib/layout';
import { key } from './store';
import { RegionEndpoint, Copy } from '$lib/components';
import { Layout, Tag, Icon } from '@appwrite.io/pink-svelte';
import { IconDuplicate } from '@appwrite.io/pink-icons-svelte';
import { projectRegion } from '../../../store';
const projectId = page.params.project;
</script>
@@ -12,5 +16,26 @@
<CoverTitle href={`${base}/project-${page.params.region}-${projectId}/overview/api-keys`}>
{$key?.name}
</CoverTitle>
<Layout.Stack direction="row" inline>
{#if $key?.secret}
<Copy value={$key.secret} copyText="Copy API secret">
<Tag size="xs" variant="code">
<Icon icon={IconDuplicate} size="s" slot="start" />
<span class="api-secret-label"> API secret </span>
</Tag>
</Copy>
{/if}
{#if $projectRegion}
<RegionEndpoint region={$projectRegion} />
{/if}
</Layout.Stack>
</svelte:fragment>
</Cover>
<style>
.api-secret-label {
white-space: nowrap;
overflow: hidden;
word-break: break-all;
}
</style>
Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

@@ -2,19 +2,24 @@
import { page } from '$app/state';
import { Id, RegionEndpoint } from '$lib/components';
import { Cover } from '$lib/layout';
import { project, projectRegion } from '../store';
import { projectRegion } from '../store';
import { hasOnboardingDismissed, setHasOnboardingDismissed } from '$lib/helpers/onboarding';
import { goto } from '$app/navigation';
import { base } from '$app/paths';
import { resolve } from '$app/paths';
import { Layout, Button, Typography } from '@appwrite.io/pink-svelte';
import { user } from '$lib/stores/user';
import { isSmallViewport } from '$lib/stores/viewport';
import { trackEvent } from '$lib/actions/analytics';
function dismissOnboarding() {
setHasOnboardingDismissed($project.$id, $user);
setHasOnboardingDismissed(page.params.project, $user);
trackEvent('onboarding_hub_platform_dismiss');
goto(`${base}/project-${$project.region}-${$project.$id}/overview/platforms`);
goto(
resolve('/(console)/project-[region]-[project]/overview/platforms', {
region: page.params.region,
project: page.params.project
})
);
}
</script>
@@ -24,12 +29,15 @@
<Layout.Stack alignItems="baseline" direction={$isSmallViewport ? 'column' : 'row'}>
<Typography.Title color="--fgcolor-neutral-primary" size="xl" truncate>
<span class="project-title">
{$project?.name}
{page.data.project?.name}
</span>
</Typography.Title>
<Layout.Stack direction="row" inline>
<Id value={$project.$id}>{$project.$id}</Id>
<RegionEndpoint region={$projectRegion} />
<Id value={page.params.project} copyText="Copy project ID"
>{page.params.project}</Id>
{#if $projectRegion}
<RegionEndpoint region={$projectRegion} />
{/if}
</Layout.Stack>
</Layout.Stack>
</svelte:fragment>
@@ -53,7 +61,7 @@
>Follow a few quick steps to get started with Appwrite</Typography.Text>
</Layout.Stack>
<div class="dashboard-header-button">
{#if !hasOnboardingDismissed($project.$id, $user)}
{#if !hasOnboardingDismissed(page.params.project, $user)}
<Button.Button size="s" variant="secondary" on:click={dismissOnboarding}>
Dismiss this page
</Button.Button>
@@ -14,12 +14,7 @@
import { app } from '$lib/stores/app';
import AuthPreview from './assets/auth-preview.svg';
import AuthPreviewDark from './assets/auth-preview-dark.svg';
import {
IconArrowRight,
IconNodeJs,
IconPhp,
IconPython
} from '@appwrite.io/pink-icons-svelte';
import { IconArrowRight } from '@appwrite.io/pink-icons-svelte';
import DatabaseImgSource from './assets/database.png';
import DatabaseImgSourceDark from './assets/database-dark.png';
import DiscordImgSource from './assets/discord.png';
@@ -31,9 +26,10 @@
import PlatformAndroidImgSourceDark from './assets/platform-android-dark.svg';
import PlatformFlutterImgSource from './assets/platform-flutter.svg';
import PlatformFlutterImgSourceDark from './assets/platform-flutter-dark.svg';
import PlatformSdkImgSource from './assets/platform-sdk.jpg';
import PlatformSdkImgSourceDark from './assets/platform-sdk-dark.png';
import { base } from '$app/paths';
import { isSmallViewport } from '$lib/stores/viewport';
import { AvatarGroup } from '$lib/components';
import type { Models } from '@appwrite.io/console';
import { getPlatformInfo } from '$lib/helpers/platform';
import { Click, trackEvent } from '$lib/actions/analytics';
@@ -103,7 +99,9 @@
</Layout.Stack>
</div>
<Layout.Stack gap="l">
<Layout.Stack gap="l" direction="row">
<Layout.Stack
gap="l"
direction={$isSmallViewport ? 'column' : 'row'}>
<Card.Button
on:click={() => {
openPlatformWizard(0, platformMap.get('Web'));
@@ -341,17 +339,34 @@
</Layout.Stack>
</Card.Button>
</Layout.Stack>
<Layout.Stack direction="row" gap="xxs" alignItems="center">
<Typography.Text>Or connect</Typography.Text>
<Link.Button variant="muted" on:click={createKey}
>server side</Link.Button>
<div style:padding-inline-start="8px">
<AvatarGroup
icons={[IconPython, IconNodeJs, IconPhp]}
total={7}
size="s" />
</div>
</Layout.Stack>
<span class="with-separators eyebrow-heading-3">or</span>
<Card.Button on:click={createKey} padding="none">
<Layout.Stack gap="xl">
<div
class="card-top-image api-key-card-image"
style:background-image={`url('${
$app.themeInUse === 'dark'
? PlatformSdkImgSourceDark
: PlatformSdkImgSource
}')`}>
<Layout.Stack
direction="row"
alignItems="center"
justifyContent="space-between">
<Layout.Stack gap="xxs">
<Typography.Title size="s"
>Create API key</Typography.Title>
<Typography.Text
>Connect your server or backend to Appwrite</Typography.Text>
</Layout.Stack>
<div class="arrow-icon">
<Icon icon={IconArrowRight} size="s" />
</div>
</Layout.Stack>
</div>
</Layout.Stack>
</Card.Button>
</Layout.Stack>
</Layout.Stack></Step.Item>
<Step.Item state="next"
@@ -684,6 +699,24 @@
background-position: bottom;
background-repeat: no-repeat;
}
.api-key-card-image {
background-size: cover;
background-position: right center;
background-repeat: no-repeat;
margin: 0;
width: 100%;
height: 100%;
min-height: 160px;
border-radius: var(--border-radius-m);
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: flex-start;
padding: var(--base-16, 16px);
@media (min-width: 1200px) {
min-height: 187px;
}
}
.full-height-card {
height: 100%;
}
@@ -17,7 +17,7 @@
import { Card } from '$lib/components';
import { page } from '$app/state';
import { onMount } from 'svelte';
import { type AppwriteRealtimeSubscription, sdk } from '$lib/stores/sdk';
import { realtime, sdk } from '$lib/stores/sdk';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { addNotification } from '$lib/stores/notifications';
import { fade } from 'svelte/transition';
@@ -63,8 +63,10 @@ const val APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.region, page.
message: 'Platform created.'
});
invalidate(Dependencies.PROJECT);
invalidate(Dependencies.PLATFORMS);
await Promise.all([
invalidate(Dependencies.PROJECT),
invalidate(Dependencies.PLATFORMS)
]);
} catch (error) {
trackError(error, Submit.PlatformCreate);
addNotification({
@@ -81,20 +83,17 @@ const val APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.region, page.
}
onMount(() => {
let subscription: AppwriteRealtimeSubscription;
sdk.forConsole.realtime
.subscribe('console', (response) => {
if (response.events.includes(`projects.${projectId}.ping`)) {
connectionSuccessful = true;
invalidate(Dependencies.ORGANIZATION);
invalidate(Dependencies.PROJECT);
subscription?.close();
}
})
.then((realtime) => (subscription = realtime));
const unsubscribe = realtime.forConsole(page.params.region, 'console', (response) => {
if (response.events.includes(`projects.${projectId}.ping`)) {
connectionSuccessful = true;
invalidate(Dependencies.ORGANIZATION);
invalidate(Dependencies.PROJECT);
unsubscribe();
}
});
return () => {
subscription?.close();
unsubscribe();
resetPlatformStore();
};
});
@@ -18,7 +18,7 @@
import { Card } from '$lib/components';
import { page } from '$app/state';
import { onMount } from 'svelte';
import { type AppwriteRealtimeSubscription, sdk } from '$lib/stores/sdk';
import { realtime, sdk } from '$lib/stores/sdk';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { addNotification } from '$lib/stores/notifications';
import { fade } from 'svelte/transition';
@@ -72,8 +72,10 @@ APPWRITE_PUBLIC_ENDPOINT: "${sdk.forProject(page.params.region, page.params.proj
message: 'Platform created.'
});
invalidate(Dependencies.PROJECT);
invalidate(Dependencies.PLATFORMS);
await Promise.all([
invalidate(Dependencies.PROJECT),
invalidate(Dependencies.PLATFORMS)
]);
} catch (error) {
trackError(error, Submit.PlatformCreate);
addNotification({
@@ -90,20 +92,17 @@ APPWRITE_PUBLIC_ENDPOINT: "${sdk.forProject(page.params.region, page.params.proj
}
onMount(() => {
let subscription: AppwriteRealtimeSubscription;
sdk.forConsole.realtime
.subscribe('console', (response) => {
if (response.events.includes(`projects.${projectId}.ping`)) {
connectionSuccessful = true;
invalidate(Dependencies.ORGANIZATION);
invalidate(Dependencies.PROJECT);
subscription?.close();
}
})
.then((realtime) => (subscription = realtime));
const unsubscribe = realtime.forConsole(page.params.region, 'console', (response) => {
if (response.events.includes(`projects.${projectId}.ping`)) {
connectionSuccessful = true;
invalidate(Dependencies.ORGANIZATION);
invalidate(Dependencies.PROJECT);
unsubscribe();
}
});
return () => {
subscription?.close();
unsubscribe();
resetPlatformStore();
};
});
@@ -18,7 +18,7 @@
import { Card } from '$lib/components';
import { page } from '$app/state';
import { onMount } from 'svelte';
import { type AppwriteRealtimeSubscription, sdk } from '$lib/stores/sdk';
import { realtime, sdk } from '$lib/stores/sdk';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { addNotification } from '$lib/stores/notifications';
import { fade } from 'svelte/transition';
@@ -138,8 +138,10 @@
message: 'Platform created.'
});
invalidate(Dependencies.PROJECT);
invalidate(Dependencies.PLATFORMS);
await Promise.all([
invalidate(Dependencies.PROJECT),
invalidate(Dependencies.PLATFORMS)
]);
} catch (error) {
trackError(error, Submit.PlatformCreate);
addNotification({
@@ -156,20 +158,17 @@
}
onMount(() => {
let subscription: AppwriteRealtimeSubscription;
sdk.forConsole.realtime
.subscribe('console', (response) => {
if (response.events.includes(`projects.${projectId}.ping`)) {
connectionSuccessful = true;
invalidate(Dependencies.ORGANIZATION);
invalidate(Dependencies.PROJECT);
subscription?.close();
}
})
.then((realtime) => (subscription = realtime));
const unsubscribe = realtime.forConsole(page.params.region, 'console', (response) => {
if (response.events.includes(`projects.${projectId}.ping`)) {
connectionSuccessful = true;
invalidate(Dependencies.ORGANIZATION);
invalidate(Dependencies.PROJECT);
unsubscribe();
}
});
return () => {
subscription?.close();
unsubscribe();
resetPlatformStore();
};
});
@@ -18,7 +18,7 @@
import { Card } from '$lib/components';
import { page } from '$app/state';
import { onMount } from 'svelte';
import { type AppwriteRealtimeSubscription, sdk } from '$lib/stores/sdk';
import { realtime, sdk } from '$lib/stores/sdk';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { addNotification } from '$lib/stores/notifications';
import { fade } from 'svelte/transition';
@@ -99,8 +99,10 @@ EXPO_PUBLIC_APPWRITE_ENDPOINT=${sdk.forProject(page.params.region, page.params.p
message: 'Platform created.'
});
invalidate(Dependencies.PROJECT);
invalidate(Dependencies.PLATFORMS);
await Promise.all([
invalidate(Dependencies.PROJECT),
invalidate(Dependencies.PLATFORMS)
]);
} catch (error) {
trackError(error, Submit.PlatformCreate);
addNotification({
@@ -117,20 +119,17 @@ EXPO_PUBLIC_APPWRITE_ENDPOINT=${sdk.forProject(page.params.region, page.params.p
}
onMount(() => {
let subscription: AppwriteRealtimeSubscription;
sdk.forConsole.realtime
.subscribe('console', (response) => {
if (response.events.includes(`projects.${projectId}.ping`)) {
connectionSuccessful = true;
invalidate(Dependencies.ORGANIZATION);
invalidate(Dependencies.PROJECT);
subscription?.close();
}
})
.then((realtime) => (subscription = realtime));
const unsubscribe = realtime.forConsole(page.params.region, 'console', (response) => {
if (response.events.includes(`projects.${projectId}.ping`)) {
connectionSuccessful = true;
invalidate(Dependencies.ORGANIZATION);
invalidate(Dependencies.PROJECT);
unsubscribe();
}
});
return () => {
subscription?.close();
unsubscribe();
resetPlatformStore();
};
});
@@ -28,7 +28,7 @@
} from '@appwrite.io/pink-icons-svelte';
import { page } from '$app/state';
import { onMount } from 'svelte';
import { type AppwriteRealtimeSubscription, sdk } from '$lib/stores/sdk';
import { realtime, sdk } from '$lib/stores/sdk';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { addNotification } from '$lib/stores/notifications';
import { fade } from 'svelte/transition';
@@ -184,8 +184,10 @@ ${prefix}APPWRITE_ENDPOINT = "${sdk.forProject(page.params.region, page.params.p
message: 'Platform created.'
});
invalidate(Dependencies.PROJECT);
invalidate(Dependencies.PLATFORMS);
await Promise.all([
invalidate(Dependencies.PROJECT),
invalidate(Dependencies.PLATFORMS)
]);
} catch (error) {
trackError(error, Submit.PlatformCreate);
addNotification({
@@ -202,21 +204,18 @@ ${prefix}APPWRITE_ENDPOINT = "${sdk.forProject(page.params.region, page.params.p
}
onMount(() => {
let subscription: AppwriteRealtimeSubscription;
sdk.forConsole.realtime
.subscribe('console', (response) => {
if (response.events.includes(`projects.${projectId}.ping`)) {
connectionSuccessful = true;
invalidate(Dependencies.ORGANIZATION);
invalidate(Dependencies.PROJECT);
subscription?.close();
}
})
.then((realtime) => (subscription = realtime));
const unsubscribe = realtime.forConsole(page.params.region, 'console', (response) => {
if (response.events.includes(`projects.${projectId}.ping`)) {
connectionSuccessful = true;
invalidate(Dependencies.ORGANIZATION);
invalidate(Dependencies.PROJECT);
unsubscribe();
}
});
return () => {
unsubscribe();
resetPlatformStore();
subscription?.close();
};
});
</script>
@@ -38,13 +38,11 @@
let migration: Models.Migration = null;
onMount(() => {
return realtime
.forProject(page.params.region, page.params.project)
.subscribe(['project', 'console'], (response) => {
if (response.events.includes('migrations.*')) {
invalidate(Dependencies.MIGRATIONS);
}
});
return realtime.forProject(page.params.region, ['project', 'console'], (response) => {
if (response.events.includes('migrations.*')) {
invalidate(Dependencies.MIGRATIONS);
}
});
});
$: $registerCommands([
@@ -25,7 +25,8 @@
import { onMount } from 'svelte';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { sdk } from '$lib/stores/sdk';
import { realtime } from '$lib/stores/sdk';
import { page } from '$app/state';
export let data;
@@ -49,7 +50,7 @@
$updateCommandGroupRanks({ sites: 1000 });
onMount(() => {
return sdk.forConsole.realtime.subscribe('console', (response) => {
return realtime.forConsole(page.params.region, 'console', (response) => {
if (response.events.includes('sites.*')) {
invalidate(Dependencies.SITES);
}
@@ -7,42 +7,36 @@
import Aside from '../aside.svelte';
import Logs from '../../(components)/logs.svelte';
import { Copy, SvgIcon } from '$lib/components';
import { type AppwriteRealtimeSubscription, sdk } from '$lib/stores/sdk';
import { realtime } from '$lib/stores/sdk';
import { goto } from '$app/navigation';
import { onMount } from 'svelte';
import { getFrameworkIcon } from '$lib/stores/sites';
import type { Models } from '@appwrite.io/console';
let { data } = $props();
let deployment = $state(data.deployment);
onMount(() => {
let subscription: AppwriteRealtimeSubscription;
sdk.forConsoleIn(page.params.region)
.realtime.subscribe('console', async (response) => {
if (
response.events.includes(
`sites.${data.site.$id}.deployments.${data.deployment.$id}.update`
)
) {
deployment = response.payload;
if (response.payload.status === 'ready') {
const resolvedUrl = resolve(
'/(console)/project-[region]-[project]/sites/create-site/finish',
{
region: page.params.region,
project: page.params.project
}
);
await goto(`${resolvedUrl}?site=${data.site.$id}`);
}
return realtime.forConsole(page.params.region, 'console', async (response) => {
if (
response.events.includes(
`sites.${data.site.$id}.deployments.${data.deployment.$id}.update`
)
) {
deployment = response.payload as Models.Deployment;
if (deployment.status === 'ready') {
const resolvedUrl = resolve(
'/(console)/project-[region]-[project]/sites/create-site/finish',
{
region: page.params.region,
project: page.params.project
}
);
await goto(`${resolvedUrl}?site=${data.site.$id}`);
}
})
.then((realtime) => (subscription = realtime));
return () => {
subscription?.close();
};
}
});
});
</script>
@@ -7,19 +7,21 @@
import { Button } from '$lib/elements/forms';
import InstantRollbackDomain from './instantRollbackModal.svelte';
import { app } from '$lib/stores/app';
import { sdk } from '$lib/stores/sdk';
import { realtime } from '$lib/stores/sdk';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { onMount } from 'svelte';
import { page } from '$app/state';
import { base } from '$app/paths';
import type { PageProps } from './$types';
import { regionalProtocol } from '$routes/(console)/project-[region]-[project]/store';
export let data;
let showRollback = false;
let { data }: PageProps = $props();
let showRollback = $state(false);
onMount(() => {
return sdk.forConsole.realtime.subscribe('console', (response) => {
return realtime.forConsole(page.params.region, 'console', (response) => {
if (response.events.includes(`sites.${page.params.site}.deployments.*`)) {
invalidate(Dependencies.SITE);
}
@@ -1,7 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import { page } from '$app/state';
import { sdk } from '$lib/stores/sdk';
import { realtime } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import { invalidate, goto } from '$app/navigation';
import { registerCommands } from '$lib/commandCenter';
@@ -13,11 +13,14 @@
onMount(() => {
let previousStatus: string = null;
return sdk.forConsole.realtime.subscribe<Models.Deployment>('console', (message) => {
if (message.payload.status !== 'ready' && previousStatus === message.payload.status) {
return realtime.forConsole(page.params.region, 'console', (message) => {
const payload = message.payload as Models.Deployment;
if (payload.status !== 'ready' && previousStatus === payload.status) {
return;
}
previousStatus = message.payload.status;
previousStatus = payload.status;
if (message.events.includes('sites.*.deployments.*.create')) {
invalidate(Dependencies.DEPLOYMENTS);
@@ -13,7 +13,7 @@
import DeploymentMetrics from './deploymentMetrics.svelte';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
import { onMount } from 'svelte';
import { sdk } from '$lib/stores/sdk';
import { realtime, sdk } from '$lib/stores/sdk';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import CreateCliModal from './createCliModal.svelte';
@@ -32,11 +32,7 @@
let showAlert = true;
onMount(() => {
if (page.url.searchParams.has('createDeployment')) {
showConnectRepo = true;
}
return sdk.forConsole.realtime.subscribe('console', (response) => {
return realtime.forConsole(page.params.region, 'console', (response) => {
if (response.events.includes('sites.*.deployments.*')) {
invalidate(Dependencies.DEPLOYMENTS);
}
@@ -1,6 +1,6 @@
<script lang="ts">
import { Container } from '$lib/layout';
import { type AppwriteRealtimeSubscription, sdk } from '$lib/stores/sdk';
import { realtime } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import SiteCard from '../../../(components)/siteCard.svelte';
import Logs, { badgeTypeDeployment } from '../../../(components)/logs.svelte';
@@ -31,22 +31,15 @@
let showCancel = $state(false);
onMount(() => {
let subscription: AppwriteRealtimeSubscription;
sdk.forConsoleIn(page.params.region)
.realtime.subscribe('console', async (response) => {
if (
response.events.includes(
`sites.${page.params.site}.deployments.${page.params.deployment}.update`
)
) {
await invalidate(Dependencies.DEPLOYMENT);
}
})
.then((realtime) => (subscription = realtime));
return () => {
subscription?.close();
};
return realtime.forConsole(page.params.region, 'console', async (response) => {
if (
response.events.includes(
`sites.${page.params.site}.deployments.${page.params.deployment}.update`
)
) {
await invalidate(Dependencies.DEPLOYMENT);
}
});
});
</script>
@@ -4,16 +4,17 @@
import { Dependencies } from '$lib/constants';
import { Button } from '$lib/elements/forms';
import { Container, ResponsiveContainerHeader } from '$lib/layout';
import { sdk } from '$lib/stores/sdk';
import { realtime } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import Table from './table.svelte';
import { Card, Empty } from '@appwrite.io/pink-svelte';
import { columns } from './store';
import { page } from '$app/state';
export let data;
onMount(() => {
return sdk.forConsole.realtime.subscribe('console', (response) => {
return realtime.forConsole(page.params.region, 'console', (response) => {
if (response.events.includes('sites.*.executions.*')) {
invalidate(Dependencies.EXECUTIONS);
}