Skip to content

Commit 7a23e8d

Browse files
committed
Merge branch 'main' into bun
2 parents c8df58d + 6f57562 commit 7a23e8d

376 files changed

Lines changed: 7528 additions & 7072 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

e2e/steps/free-project.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,15 @@ export async function createFreeProject(page: Page): Promise<Metadata> {
2424
const regionPicker = dialog.locator('button[role="combobox"]');
2525
if (await regionPicker.isVisible()) {
2626
await regionPicker.click();
27-
await page.getByRole('option', { name: /New York/i }).click();
28-
29-
region = 'nyc';
27+
const firstEnabledOption = page
28+
.locator('[role="option"]:not([data-disabled="true"])')
29+
.first();
30+
31+
if ((await firstEnabledOption.count()) > 0) {
32+
const selectedRegion = await firstEnabledOption.getAttribute('data-value');
33+
await firstEnabledOption.click();
34+
region = selectedRegion?.replace(/"/g, '') || 'fra';
35+
}
3036
}
3137

3238
await dialog.getByRole('button', { name: 'create' }).click();

e2e/steps/pro-project.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ export async function enterCreditCard(page: Page) {
1818
await dialog.waitFor({ state: 'visible' });
1919
await page.getByPlaceholder('cardholder').fill('Test User');
2020
const stripe = page.locator('[title="Secure payment input frame"]').nth(0).contentFrame();
21-
await stripe.locator('id=Field-numberInput').fill('4242424242424242');
22-
await stripe.locator('id=Field-expiryInput').fill('1250');
23-
await stripe.locator('id=Field-cvcInput').fill('123');
24-
await stripe.locator('id=Field-countryInput').selectOption('DE');
21+
await stripe.locator('id=payment-numberInput').fill('4242424242424242');
22+
await stripe.locator('id=payment-expiryInput').fill('1250');
23+
await stripe.locator('id=payment-cvcInput').fill('123');
24+
await stripe.locator('id=payment-countryInput').selectOption('DE');
2525
await dialog.getByRole('button', { name: 'Add', exact: true }).click();
2626
await page.locator('id=state-picker').click(); // open dropdown
2727
await page.getByRole('option', { name: 'Alabama' }).click();
@@ -57,9 +57,15 @@ export async function createProProject(page: Page): Promise<Metadata> {
5757
const regionPicker = dialog.locator('button[role="combobox"]');
5858
if (await regionPicker.isVisible()) {
5959
await regionPicker.click();
60-
await page.getByRole('option', { name: /New York/i }).click();
60+
const firstEnabledOption = page
61+
.locator('[role="option"]:not([data-disabled="true"])')
62+
.first();
6163

62-
region = 'nyc';
64+
if ((await firstEnabledOption.count()) > 0) {
65+
const selectedRegion = await firstEnabledOption.getAttribute('data-value');
66+
await firstEnabledOption.click();
67+
region = selectedRegion?.replace(/"/g, '') || 'fra';
68+
}
6369
}
6470

6571
await dialog.getByRole('button', { name: 'create' }).click();

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@
2020
},
2121
"dependencies": {
2222
"@ai-sdk/svelte": "^1.1.24",
23-
"@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@f21fc7f",
23+
"@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@95675c4",
2424
"@appwrite.io/pink-icons": "0.25.0",
25-
"@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@865e2fc",
25+
"@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@c1feb89",
2626
"@appwrite.io/pink-legacy": "^1.0.3",
27-
"@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@865e2fc",
27+
"@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@c1feb89",
2828
"@faker-js/faker": "^9.9.0",
29+
"@plausible-analytics/tracker": "^0.4.4",
2930
"@popperjs/core": "^2.11.8",
3031
"@sentry/sveltekit": "^8.38.0",
3132
"@stripe/stripe-js": "^3.5.0",
@@ -40,7 +41,6 @@
4041
"ignore": "^6.0.2",
4142
"nanoid": "^5.1.5",
4243
"nanotar": "^0.1.1",
43-
"plausible-tracker": "^0.3.9",
4444
"pretty-bytes": "^6.1.1",
4545
"prismjs": "^1.30.0",
4646
"remarkable": "^2.0.1",
@@ -55,7 +55,7 @@
5555
"@melt-ui/svelte": "^0.86.5",
5656
"@playwright/test": "^1.55.1",
5757
"@sveltejs/adapter-static": "^3.0.8",
58-
"@sveltejs/kit": "^2.42.1",
58+
"@sveltejs/kit": "^2.49.5",
5959
"@sveltejs/vite-plugin-svelte": "^5.0.3",
6060
"@testing-library/dom": "^10.4.0",
6161
"@testing-library/jest-dom": "^6.6.3",

pnpm-lock.yaml

Lines changed: 87 additions & 64 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/actions/analytics.ts

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Analytics, { type AnalyticsPlugin } from 'analytics';
2-
import Plausible from 'plausible-tracker';
2+
import { init, track } from '@plausible-analytics/tracker';
33
import { get } from 'svelte/store';
44
import { page } from '$app/state';
55
import { user } from '$lib/stores/user';
@@ -11,30 +11,30 @@ import { getReferrerAndUtmSource, getTrackedQueryParams } from '$lib/helpers/utm
1111
function plausible(domain: string): AnalyticsPlugin {
1212
if (!browser) return { name: 'analytics-plugin-plausible' };
1313

14-
const instance = Plausible({
15-
domain
14+
init({
15+
domain,
16+
autoCapturePageviews: false
1617
});
1718

1819
return {
1920
name: 'analytics-plugin-plausible',
2021
page: ({ payload }) => {
21-
instance.trackPageview({
22+
track('pageview', {
2223
url: payload.properties.path,
23-
referrer: payload.properties.referrer,
24-
deviceWidth: payload.properties.width
24+
props: {
25+
referrer: payload.properties.referrer,
26+
deviceWidth: String(payload.properties.width)
27+
}
2528
});
2629
},
2730
track: ({ payload }) => {
28-
instance.trackEvent(
29-
payload.event,
30-
{
31-
props: payload.properties
32-
},
33-
{
34-
url: payload.properties.path,
35-
deviceWidth: payload.properties.width
31+
track(payload.event, {
32+
url: payload.properties.path,
33+
props: {
34+
...payload.properties,
35+
deviceWidth: String(payload.properties.width)
3636
}
37-
);
37+
});
3838
},
3939
loaded: () => true
4040
};
@@ -52,7 +52,7 @@ const analytics = Analytics({
5252
});
5353

5454
export function trackEvent(name: string, data: object = null): void {
55-
if (!isTrackingAllowed()) {
55+
if (!name || !isTrackingAllowed()) {
5656
return;
5757
}
5858

@@ -76,7 +76,7 @@ export function trackEvent(name: string, data: object = null): void {
7676
}
7777

7878
export function trackError(exception: Error, event: Submit): void {
79-
if (exception instanceof AppwriteException && exception.type) {
79+
if (exception instanceof AppwriteException && exception.type && event) {
8080
trackEvent(Submit.Error, {
8181
type: exception.type,
8282
form: event
@@ -148,11 +148,14 @@ export enum Click {
148148
ConnectRepositoryClick = 'click_connect_repository',
149149
CreditsRedeemClick = 'click_credits_redeem',
150150
CloudSignupClick = 'click_cloud_signup',
151+
151152
DatabaseColumnDelete = 'click_column_delete',
152153
DatabaseIndexDelete = 'click_index_delete',
153154
DatabaseTableDelete = 'click_table_delete',
155+
DatabaseRowDelete = 'click_row_delete',
154156
DatabaseDatabaseDelete = 'click_database_delete',
155157
DatabaseImportCsv = 'click_database_import_csv',
158+
156159
DomainCreateClick = 'click_domain_create',
157160
DomainDeleteClick = 'click_domain_delete',
158161
DomainRetryDomainVerificationClick = 'click_domain_retry_domain_verification',
@@ -247,6 +250,7 @@ export enum Submit {
247250
ProjectDelete = 'submit_project_delete',
248251
ProjectUpdateName = 'submit_project_update_name',
249252
ProjectUpdateTeam = 'submit_project_update_team',
253+
ProjectUpdateLabels = 'submit_project_update_labels',
250254
ProjectService = 'submit_project_service',
251255
ProjectUpdateSMTP = 'submit_project_update_smtp',
252256
MemberCreate = 'submit_member_create',
@@ -278,6 +282,7 @@ export enum Submit {
278282
DatabaseUpdateName = 'submit_database_update_name',
279283
DatabaseImportCsv = 'submit_database_import_csv',
280284
DatabaseBackupDelete = 'submit_database_backup_delete',
285+
DatabaseBackupPolicyCreate = 'submit_database_backup_policy_create',
281286

282287
ColumnCreate = 'submit_column_create',
283288
ColumnUpdate = 'submit_column_update',
@@ -288,15 +293,18 @@ export enum Submit {
288293
RowDelete = 'submit_row_delete',
289294
RowUpdate = 'submit_row_update',
290295
RowUpdatePermissions = 'submit_row_update_permissions',
296+
291297
IndexCreate = 'submit_index_create',
292298
IndexDelete = 'submit_index_delete',
293-
TableCreate = 'submit_row_create',
294-
TableDelete = 'submit_row_delete',
295-
TableUpdateName = 'submit_row_update_name',
296-
TableUpdatePermissions = 'submit_row_update_permissions',
297-
TableUpdateSecurity = 'submit_row_update_security',
298-
TableUpdateEnabled = 'submit_row_update_enabled',
299-
TableUpdateDisplayNames = 'submit_row_update_display_names',
299+
300+
TableCreate = 'submit_table_create',
301+
TableDelete = 'submit_table_delete',
302+
TableUpdateName = 'submit_table_update_name',
303+
TableUpdatePermissions = 'submit_table_update_permissions',
304+
TableUpdateSecurity = 'submit_table_update_security',
305+
TableUpdateEnabled = 'submit_table_update_enabled',
306+
TableUpdateDisplayNames = 'submit_table_update_display_names',
307+
300308
FunctionCreate = 'submit_function_create',
301309
FunctionDelete = 'submit_function_delete',
302310
FunctionUpdateName = 'submit_function_update_name',

src/lib/commandCenter/searchers/organizations.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
1+
import { resolve } from '$app/paths';
12
import { goto } from '$app/navigation';
2-
import { base } from '$app/paths';
3-
import { sdk } from '$lib/stores/sdk';
43
import type { Searcher } from '../commands';
5-
import { isCloud } from '$lib/system';
6-
import { Platform, Query } from '@appwrite.io/console';
4+
import { getTeamOrOrganizationList } from '$lib/stores/organization';
75

86
export const orgSearcher = (async (query: string) => {
9-
const { teams } = !isCloud
10-
? await sdk.forConsole.teams.list()
11-
: await sdk.forConsole.billing.listOrganization([
12-
Query.equal('platform', Platform.Appwrite)
13-
]);
7+
const { teams } = await getTeamOrOrganizationList();
148

159
return teams
1610
.filter((organization) => organization.name.toLowerCase().includes(query.toLowerCase()))
1711
.map((organization) => {
1812
return {
1913
label: organization.name,
2014
callback: () => {
21-
goto(`${base}/organization-${organization.$id}`);
15+
goto(
16+
resolve('/(console)/organization-[organization]', {
17+
organization: organization.$id
18+
})
19+
);
2220
},
2321
group: 'organizations'
2422
} as const;

src/lib/components/archiveProject.svelte

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,21 @@
3838
import { isSmallViewport } from '$lib/stores/viewport';
3939
import { isCloud } from '$lib/system';
4040
import { regions as regionsStore } from '$lib/stores/organization';
41-
import type { Organization } from '$lib/stores/organization';
42-
import type { Plan } from '$lib/sdk/billing';
4341
4442
// props
4543
interface Props {
44+
currentPlan: Models.BillingPlan;
45+
organization: Models.Organization;
4646
projectsToArchive: Models.Project[];
47-
organization: Organization;
48-
currentPlan: Plan;
4947
archivedTotalOverall: number;
5048
archivedOffset: number;
5149
limit: number;
5250
}
5351
5452
let {
55-
projectsToArchive,
56-
organization,
5753
currentPlan,
54+
organization,
55+
projectsToArchive,
5856
archivedTotalOverall,
5957
archivedOffset,
6058
limit

src/lib/components/backupDatabaseAlert.svelte

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
<script lang="ts">
22
import { page } from '$app/state';
3-
import { BillingPlan } from '$lib/constants';
43
import { Button } from '$lib/elements/forms';
54
import { organization } from '$lib/stores/organization';
65
import { HeaderAlert } from '$lib/layout';
76
import { isCloud } from '$lib/system';
8-
import { upgradeURL } from '$lib/stores/billing';
7+
import { getChangePlanUrl } from '$lib/stores/billing';
98
import { hideNotification } from '$lib/helpers/notifications';
109
import { backupsBannerId, showPolicyAlert } from '$lib/stores/database';
1110
import { IconX } from '@appwrite.io/pink-icons-svelte';
@@ -18,14 +17,16 @@
1817
</script>
1918

2019
{#if $showPolicyAlert && isCloud && $organization?.$id && page.url.pathname.match(/\/databases\/database-[^/]+$/)}
21-
{@const isFreePlan = $organization?.billingPlan === BillingPlan.FREE}
20+
{@const areBackupsAvailable = $organization?.billingPlanDetails.backupsEnabled}
2221

23-
{@const subtitle = isFreePlan
22+
{@const subtitle = !areBackupsAvailable
2423
? 'Upgrade your plan to ensure your data stays safe and backed up'
2524
: 'Protect your data by quickly adding a backup policy'}
2625

27-
{@const ctaText = isFreePlan ? 'Upgrade plan' : 'Create policy'}
28-
{@const ctaURL = isFreePlan ? $upgradeURL : `${page.url.pathname}/backups`}
26+
{@const ctaText = !areBackupsAvailable ? 'Upgrade plan' : 'Create policy'}
27+
{@const ctaURL = !areBackupsAvailable
28+
? getChangePlanUrl($organization.$id)
29+
: `${page.url.pathname}/backups`}
2930

3031
<HeaderAlert type="warning" title="Your database has no backup policy">
3132
<svelte:fragment>{subtitle}</svelte:fragment>
@@ -35,7 +36,7 @@
3536
href={ctaURL}
3637
secondary
3738
fullWidthMobile
38-
event={isFreePlan ? 'backup_banner_upgrade' : 'backup_banner_add'}>
39+
event={!areBackupsAvailable ? 'backup_banner_upgrade' : 'backup_banner_add'}>
3940
<span class="text">{ctaText}</span>
4041
</Button>
4142

src/lib/components/backupRestoreBox.svelte

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44
import { onMount } from 'svelte';
55
import { isCloud, isSelfHosted } from '$lib/system';
66
import { organization } from '$lib/stores/organization';
7-
import { BillingPlan, Dependencies } from '$lib/constants';
8-
import type { BackupArchive, BackupRestoration } from '$lib/sdk/backups';
7+
import { Dependencies } from '$lib/constants';
98
import { goto, invalidate } from '$app/navigation';
109
import { page } from '$app/state';
1110
import { addNotification } from '$lib/stores/notifications';
1211
import { base } from '$app/paths';
1312
import { getProjectId } from '$lib/helpers/project';
1413
import { toLocaleDate } from '$lib/helpers/date';
1514
import { Typography } from '@appwrite.io/pink-svelte';
15+
import { type Models } from '@appwrite.io/console';
1616
1717
const backupRestoreItems: {
18-
archives: Map<string, BackupArchive>;
19-
restorations: Map<string, BackupRestoration>;
18+
archives: Map<string, Models.BackupArchive>;
19+
restorations: Map<string, Models.BackupRestoration>;
2020
} = {
2121
archives: new Map(),
2222
restorations: new Map()
@@ -57,21 +57,22 @@
5757
}
5858
5959
function updateOrAddItem(payload: Payload) {
60-
// todo: @itznotabug - might need a change to $table?
61-
const { $id, status, $collection, policyId } = payload;
62-
if ($collection === 'archives' && policyId !== null) {
60+
// the internal structure still uses `$collection`,
61+
// and is basically an identifier of the op. type here!
62+
const { $id, status, $collection: type, policyId } = payload;
63+
if (type === 'archives' && policyId !== null) {
6364
return;
6465
}
6566
66-
if ($collection in backupRestoreItems) {
67-
const collectionMap = backupRestoreItems[$collection];
67+
if (type in backupRestoreItems) {
68+
const collectionMap = backupRestoreItems[type];
6869
6970
if (collectionMap.has($id)) {
7071
collectionMap.get($id).status = status;
7172
if (status === 'completed') {
7273
invalidate(Dependencies.BACKUPS);
7374
74-
if ($collection === 'restorations') {
75+
if (type === 'restorations') {
7576
const { newId, newName } =
7677
collectionMap.get($id).options?.['databases']?.['database'][0] || {};
7778
@@ -81,7 +82,7 @@
8182
} else if (status === 'pending' || status === 'processing' || status === 'uploading') {
8283
collectionMap.set($id, payload);
8384
}
84-
backupRestoreItems[$collection] = collectionMap;
85+
backupRestoreItems[type] = collectionMap;
8586
}
8687
}
8788
@@ -117,15 +118,15 @@
117118
if (which === 'restorations') lastDatabaseRestorationId = null;
118119
}
119120
120-
function backupName(item: BackupArchive | BackupRestoration, key: string) {
121+
function backupName(item: Models.BackupArchive | Models.BackupRestoration, key: string) {
121122
const column = key === 'archives' ? '$createdAt' : 'startedAt';
122123
123124
return toLocaleDate(item[column]);
124125
}
125126
126127
onMount(() => {
127-
// 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;
128+
// fast path: don't subscribe if org doesn't support backups or is self-hosted.
129+
if (isSelfHosted || (isCloud && !$organization?.billingPlanDetails.backupsEnabled)) return;
129130
130131
return realtime.forProject(page.params.region, 'console', (response) => {
131132
if (!response.channels.includes(`projects.${getProjectId()}`)) return;

0 commit comments

Comments
 (0)