Skip to content

Commit 37c38c7

Browse files
authored
Merge branch 'main' into fix-SER-457-resolve-forever-pending-deployments
2 parents 6a4c4ed + 95528de commit 37c38c7

11 files changed

Lines changed: 157 additions & 71 deletions

File tree

AGENTS.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Appwrite Console - Copilot Instructions
2+
3+
## Repository Overview
4+
5+
Appwrite Console is the web-based GUI for the Appwrite backend-as-a-service platform. Single-page application built with **Svelte 5 + SvelteKit 2**, **TypeScript** (not strict mode), **Vite 7**, tested with **Vitest + Playwright**. Package manager: **pnpm 10.15.1**, Node 20+. ~1500 files with extensive component-based architecture.
6+
7+
## Critical Build & Test Commands
8+
9+
### Setup (REQUIRED before any commands)
10+
11+
1. **Install pnpm**: `npm install -g corepack && corepack enable && corepack prepare pnpm@10.15.1 --activate`
12+
2. **Create .env**: `cp .env.example .env` (configure `PUBLIC_APPWRITE_ENDPOINT` and `PUBLIC_CONSOLE_MODE`)
13+
3. **Configure network access** (if using GitHub Actions or restricted environments):
14+
- Ensure firewall/proxy allows access to: `pkg.pr.new`, `pkg.vc`, `registry.npmjs.org`
15+
- These domains are required for dependencies: `@appwrite.io/console`, `@appwrite.io/pink-icons-svelte`, `@appwrite.io/pink-svelte`
16+
- In GitHub Actions: Use `pnpm/action-setup@v4` which handles registry configuration
17+
- If network errors persist, check proxy settings: `npm config get proxy` and `npm config get https-proxy`
18+
4. **Install dependencies**: `pnpm install --frozen-lockfile` (if pkg.pr.new/pkg.vc fail due to network restrictions, installation may still succeed with cached versions)
19+
20+
### Development Commands
21+
22+
**Standard workflow**: `check``lint``test``build` (before committing)
23+
24+
- `pnpm run check` - TypeScript/Svelte validation (~30-60s)
25+
- `pnpm run lint` - ESLint check (~10-20s)
26+
- `pnpm run format` - Auto-fix Prettier formatting
27+
- `pnpm run test` - Vitest unit tests with TZ=EST (~10-30s)
28+
- `pnpm run build` - Production build via build.js (~60-120s)
29+
- `pnpm dev` - Dev server on port 3000
30+
- `pnpm run preview` - Preview build on port 4173
31+
- `pnpm run e2e` - Playwright tests (needs `pnpm exec playwright install --with-deps chromium` first, ~120s+)
32+
33+
**CI Pipeline** (`.github/workflows/tests.yml`): audit → install → check → lint → test → build
34+
35+
## Project Structure
36+
37+
```
38+
src/
39+
├── lib/ # Reusable logic ($lib alias)
40+
│ ├── components/ # Feature components (billing, domains, permissions, etc.)
41+
│ ├── elements/ # Basic UI elements
42+
│ ├── helpers/ # Utility functions (array, date, string, etc.)
43+
│ ├── stores/ # Svelte stores for state
44+
│ ├── sdk/ # Appwrite SDK wrappers
45+
│ └── constants.ts, flags.ts, system.ts
46+
├── routes/
47+
│ ├── (console)/ # Auth-required routes
48+
│ │ ├── organization-[organization]/
49+
│ │ └── project-[region]-[project]/ # databases, functions, messaging, storage
50+
│ └── (public)/ # Public routes (login, register, auth callbacks)
51+
├── themes/ # Theme definitions ($themes alias)
52+
└── app.html, hooks.{client,server}.ts, service-worker.ts
53+
```
54+
55+
**SvelteKit conventions**: `+page.svelte` (component), `+page.ts` (data loader), `+layout.svelte` (wrapper), `+error.svelte` (errors). Groups like `(console)` organize routes without affecting URLs. Dynamic params: `[param]`.
56+
57+
## Key Configuration
58+
59+
**svelte.config.js**: Adapter = static SPA (fallback: index.html), base path `/console`, aliases: `$lib`, `$routes`, `$themes`
60+
**vite.config.ts**: Dev port 3000, Vitest (client=jsdom, server=node), test files: `src/**/*.{test,spec}.{js,ts}`
61+
**tsconfig.json**: Extends `.svelte-kit/tsconfig.json`, **NOT strict mode** (`strict: false`)
62+
**eslint.config.js**: Flat config (ESLint 9+), many rules disabled (see TODOs)
63+
**.prettierrc**: 4 spaces, single quotes, 100 char width, no trailing commas
64+
65+
## Testing
66+
67+
**Unit (Vitest)**: Tests in `src/lib/helpers/*.test.ts`, run with `TZ=EST` (timezone matters). Setup mocks SvelteKit (`$app/*`) in `vitest-setup-client.ts`.
68+
**E2E (Playwright)**: Tests in `e2e/journeys/*.spec.ts`, needs build+preview on port 4173, retries 3x, timeout 120s, Chromium only.
69+
70+
## Common Pitfalls
71+
72+
1. **Blank page in dev**: Disable ad blockers if seeing "Failed to fetch dynamically imported module" (known SvelteKit issue)
73+
2. **Network errors on install**:
74+
- pkg.pr.new/pkg.vc deps may fail due to firewall/proxy restrictions
75+
- Check access: `curl -I https://pkg.pr.new` and `curl -I https://pkg.vc`
76+
- Configure proxy if needed: `npm config set proxy http://proxy:port` and `npm config set https-proxy http://proxy:port`
77+
- GitHub Actions: Ensure runner has internet access; use `pnpm/action-setup@v4` action
78+
- Local dev: Often safe to continue with cached versions if network fails
79+
3. **OOM on build**: Set `NODE_OPTIONS=--max_old_space_size=8192` (like Dockerfile does)
80+
4. **Test failures**: Always use `pnpm run test` (sets TZ=EST), not `vitest` directly
81+
5. **TS errors not showing**: Run `pnpm run check` explicitly (dev server doesn't always surface them)
82+
6. **Format vs lint conflicts**: Run `pnpm run format` before `pnpm run lint`
83+
7. **E2E timeouts**: Wait 120s for preview server startup, tests auto-retry 3x
84+
8. **Stale build**: Clear `.svelte-kit` if changes not reflected: `rm -rf .svelte-kit && pnpm run build`
85+
86+
## Code Conventions
87+
88+
- Imports: Use `$lib`, `$routes`, `$themes` aliases
89+
- Components: PascalCase, in `src/lib/components/[feature]/`
90+
- Helpers: Pure functions in `src/lib/helpers/`
91+
- Types: Inline or `.d.ts`, not `.types.ts` files
92+
- Comments: Minimal, use for TODOs or complex logic
93+
- TypeScript: Not strict mode, `any` tolerated
94+
95+
## Workflow
96+
97+
1. Run Appwrite backend locally (see [docs](https://appwrite.io/docs/advanced/self-hosting))
98+
2. Configure `.env` with backend endpoint
99+
3. `pnpm install --frozen-lockfile`
100+
4. `pnpm dev` (hot reload on port 3000)
101+
5. Before commit: `pnpm run check && pnpm run format && pnpm run lint && pnpm run test && pnpm run build`
102+
6. **Take screenshots**: For any UI changes, capture screenshots and include them in the PR description or comments before finalizing
103+
104+
**Trust these instructions** - only search if incomplete/incorrect. See CONTRIBUTING.md for PR conventions. Use `--frozen-lockfile` always. Docker builds: multi-stage, final image is nginx serving static files from `/console` path.

src/routes/(console)/project-[region]-[project]/functions/function-[function]/(components)/downloadActionMenuItem.svelte

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { page } from '$app/state';
33
import { SubMenu } from '$lib/components/menu';
44
import { type Models } from '@appwrite.io/console';
5-
import { IconDownload } from '@appwrite.io/pink-icons-svelte';
5+
import { IconDownload, IconChevronRight } from '@appwrite.io/pink-icons-svelte';
66
import { ActionMenu } from '@appwrite.io/pink-svelte';
77
import { getOutputDownload, getSourceDownload } from '../store';
88
@@ -13,7 +13,8 @@
1313
{#if deployment?.status === 'ready' || deployment?.status === 'failed' || deployment?.status === 'building'}
1414
<SubMenu>
1515
<ActionMenu.Root noPadding>
16-
<ActionMenu.Item.Button trailingIcon={IconDownload}>Download</ActionMenu.Item.Button>
16+
<ActionMenu.Item.Button leadingIcon={IconDownload} trailingIcon={IconChevronRight}
17+
>Download</ActionMenu.Item.Button>
1718
</ActionMenu.Root>
1819
<svelte:fragment slot="menu">
1920
<ActionMenu.Root>

src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createCli.svelte

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,26 +54,26 @@
5454
function setCodeSnippets() {
5555
return {
5656
Unix: {
57-
code: `appwrite client --projectId="${page.params.project}" && \\
58-
appwrite functions createDeployment \\
59-
--functionId=${functionId} \\
57+
code: `appwrite client --project-id="${page.params.project}" && \\
58+
appwrite functions create-deployment \\
59+
--function-id=${functionId} \\
6060
--code="." \\
6161
--activate=true`,
6262
language: 'bash'
6363
},
6464
6565
CMD: {
66-
code: `appwrite client --projectId="${page.params.project}" && ^
67-
appwrite functions createDeployment ^
68-
--functionId=${functionId} ^
66+
code: `appwrite client --project-id="${page.params.project}" && ^
67+
appwrite functions create-deployment ^
68+
--function-id=${functionId} ^
6969
--code="." ^
7070
--activate`,
7171
language: 'CMD'
7272
},
7373
PowerShell: {
74-
code: `appwrite client --projectId="${page.params.project}" && ,
75-
appwrite functions createDeployment ,
76-
--functionId=${functionId} ,
74+
code: `appwrite client --project-id="${page.params.project}" && ,
75+
appwrite functions create-deployment ,
76+
--function-id=${functionId} ,
7777
--code="." ,
7878
--activate`,
7979
language: 'PowerShell'

src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/deleteModal.svelte

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script lang="ts">
2-
import { invalidate } from '$app/navigation';
2+
import { goto, invalidate } from '$app/navigation';
3+
import { base } from '$app/paths';
34
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
45
import Confirm from '$lib/components/confirm.svelte';
56
import { Dependencies } from '$lib/constants';
@@ -20,6 +21,12 @@
2021
functionId: selectedDeployment.resourceId,
2122
deploymentId: selectedDeployment.$id
2223
});
24+
if (page.route.id?.includes('deployment-[deployment]')) {
25+
goto(
26+
`${base}/project-${page.params.region}-${page.params.project}/functions/function-${page.params.function}/deployments`
27+
);
28+
return;
29+
}
2330
await invalidate(Dependencies.FUNCTION);
2431
showDelete = false;
2532
addNotification({

src/routes/(console)/project-[region]-[project]/functions/function-[function]/+page.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@
113113
placement={'bottom'}>
114114
<div>
115115
<ActionMenu.Item.Button
116-
trailingIcon={IconRefresh}
116+
leadingIcon={IconRefresh}
117117
disabled={activeDeployment.sourceSize === 0}
118118
on:click={() => {
119119
selectedDeployment = activeDeployment;
@@ -134,7 +134,7 @@
134134
deployment={activeDeployment}
135135
{toggle} />
136136
<ActionMenu.Item.Anchor
137-
trailingIcon={IconTerminal}
137+
leadingIcon={IconTerminal}
138138
href={`${base}/project-${page.params.region}-${page.params.project}/functions/function-${page.params.function}/deployment-${activeDeployment.$id}`}>
139139
Build logs
140140
</ActionMenu.Item.Anchor>

src/routes/(console)/project-[region]-[project]/functions/function-[function]/delete.svelte

Lines changed: 0 additions & 39 deletions
This file was deleted.

src/routes/(console)/project-[region]-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store';
2929
import { timer } from '$lib/actions/timer';
3030
import { app } from '$lib/stores/app';
31-
import { IconDotsHorizontal, IconRefresh } from '@appwrite.io/pink-icons-svelte';
31+
import { IconDotsHorizontal, IconRefresh, IconTrash } from '@appwrite.io/pink-icons-svelte';
3232
import { Menu } from '$lib/components/menu';
3333
import { canWriteFunctions } from '$lib/stores/roles';
3434
import { Click, trackEvent } from '$lib/actions/analytics';
@@ -110,7 +110,7 @@
110110
placement={'bottom'}>
111111
<div>
112112
<ActionMenu.Item.Button
113-
trailingIcon={IconRefresh}
113+
leadingIcon={IconRefresh}
114114
disabled={data.deployment.sourceSize === 0}
115115
on:click={() => {
116116
showRedeploy = true;
@@ -127,6 +127,18 @@
127127
{#if !!data.deployment?.sourceSize || !!data.deployment?.sourceSize}
128128
<DownloadActionMenuItem deployment={data.deployment} {toggle} />
129129
{/if}
130+
{#if $canWriteFunctions && ['ready', 'failed'].includes(data.deployment.status)}
131+
<ActionMenu.Item.Button
132+
status="danger"
133+
leadingIcon={IconTrash}
134+
on:click={() => {
135+
showDelete = true;
136+
toggle();
137+
}}
138+
style="width: 100%">
139+
Delete
140+
</ActionMenu.Item.Button>
141+
{/if}
130142
</ActionMenu.Root>
131143
</svelte:fragment>
132144
</Menu>

src/routes/(console)/project-[region]-[project]/functions/function-[function]/table.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@
143143
placement={'bottom'}>
144144
<div>
145145
<ActionMenu.Item.Button
146-
trailingIcon={IconRefresh}
146+
leadingIcon={IconRefresh}
147147
disabled={deployment.sourceSize === 0}
148148
on:click={() => {
149149
selectedDeployment = deployment;
@@ -159,7 +159,7 @@
159159
</Tooltip>
160160
{#if deployment.status === 'ready' && deployment.$id !== $func.deploymentId}
161161
<ActionMenu.Item.Button
162-
trailingIcon={IconLightningBolt}
162+
leadingIcon={IconLightningBolt}
163163
on:click={() => {
164164
selectedDeployment = deployment;
165165
showActivate = true;
@@ -186,7 +186,7 @@
186186
{/if}
187187
{#if effectiveStatus !== 'building' && effectiveStatus !== 'processing' && effectiveStatus !== 'waiting'}
188188
<ActionMenu.Item.Button
189-
trailingIcon={IconTrash}
189+
leadingIcon={IconTrash}
190190
status="danger"
191191
on:click={() => {
192192
selectedDeployment = deployment;

src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@
131131
Cancel
132132
</ActionMenu.Item.Button>
133133
{/if}
134-
{#if effectiveStatus !== 'building' && effectiveStatus !== 'processing' && effectiveStatus !== 'waiting'}
134+
{#if ['ready', 'failed'].includes(deployment.status)}
135135
<ActionMenu.Item.Button
136136
status="danger"
137137
leadingIcon={IconTrash}

src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/createCliModal.svelte

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
3838
return {
3939
Unix: {
40-
code: `appwrite client --projectId="${projectId}" && \\
40+
code: `appwrite client --project-id="${projectId}" && \\
4141
appwrite sites create-deployment \\
4242
--site-id="${siteId}" \\
4343
--code="${codePath}" \\
@@ -49,9 +49,9 @@ appwrite sites create-deployment \\
4949
},
5050
5151
CMD: {
52-
code: `appwrite client --projectId="${projectId}" && ^
53-
appwrite sites createDeployment ^
54-
--siteId=${siteId} ^
52+
code: `appwrite client --project-id="${projectId}" && ^
53+
appwrite sites create-deployment ^
54+
--site-id=${siteId} ^
5555
--code="${codePath}" ^
5656
--activate ^
5757
--build-command="${buildCommand}" ^
@@ -61,9 +61,9 @@ appwrite sites createDeployment ^
6161
},
6262
6363
PowerShell: {
64-
code: `appwrite client --projectId="${projectId}" ;
65-
appwrite sites createDeployment ,
66-
--siteId=${siteId} ,
64+
code: `appwrite client --project-id="${projectId}" ;
65+
appwrite sites create-deployment ,
66+
--site-id=${siteId} ,
6767
--code="${codePath}" ,
6868
--activate ,
6969
--build-command="${buildCommand}" ,

0 commit comments

Comments
 (0)