diff --git a/package.json b/package.json
index 2fb60a34d..62476588f 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
"build": "node build.js",
"preview": "vite preview",
"sync": "svelte-kit sync",
- "check": "svelte-check --tsconfig ./tsconfig.json --fail-on-warnings --threshold warning",
+ "check": "svelte-check --tsconfig ./tsconfig.json --fail-on-warnings --threshold warning --workspace",
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write .",
@@ -19,11 +19,11 @@
"e2e:ui": "playwright test tests/e2e --ui"
},
"dependencies": {
- "@appwrite.io/console": "https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@ac51fcb",
+ "@appwrite.io/console": "https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@74f9464",
"@appwrite.io/pink-icons": "0.25.0",
- "@appwrite.io/pink-icons-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@286 ",
- "@appwrite.io/pink-legacy": "^1.0.2",
- "@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@286",
+ "@appwrite.io/pink-icons-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@bcb8ad2b",
+ "@appwrite.io/pink-legacy": "^1.0.3",
+ "@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@c962928",
"@popperjs/core": "^2.11.8",
"@sentry/sveltekit": "^8.38.0",
"@stripe/stripe-js": "^3.5.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e3abacd84..ffd6caeeb 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,20 +9,20 @@ importers:
.:
dependencies:
'@appwrite.io/console':
- specifier: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@ac51fcb
- version: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@ac51fcb
+ specifier: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@74f9464
+ version: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@74f9464
'@appwrite.io/pink-icons':
specifier: 0.25.0
version: 0.25.0
'@appwrite.io/pink-icons-svelte':
- specifier: 'https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@286 '
- version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@286 (svelte@4.2.19)
+ specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@bcb8ad2b
+ version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@bcb8ad2b(svelte@4.2.19)
'@appwrite.io/pink-legacy':
- specifier: ^1.0.2
- version: 1.0.2
+ specifier: ^1.0.3
+ version: 1.0.3
'@appwrite.io/pink-svelte':
- specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@286
- version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@286(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)
+ specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@c962928
+ version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@c962928(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)
'@popperjs/core':
specifier: ^2.11.8
version: 2.11.8
@@ -107,7 +107,7 @@ importers:
version: 6.6.3
'@testing-library/svelte':
specifier: ^5.2.4
- version: 5.2.7(svelte@4.2.19)(vite@5.4.14(@types/node@22.13.5)(sass@1.85.1))(vitest@1.6.1(@types/node@22.13.5)(@vitest/ui@1.6.1)(jsdom@22.1.0)(sass@1.85.1))
+ version: 5.2.7(svelte@4.2.19)(vite@5.4.14(@types/node@22.13.5)(sass@1.85.1))(vitest@1.6.1)
'@testing-library/user-event':
specifier: ^14.5.2
version: 14.6.1(@testing-library/dom@10.4.0)
@@ -211,18 +211,18 @@ packages:
'@analytics/type-utils@0.6.2':
resolution: {integrity: sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==}
- '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@ac51fcb':
- resolution: {tarball: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@ac51fcb}
+ '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@74f9464':
+ resolution: {tarball: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@74f9464}
version: 1.2.1
- '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@286 ':
- resolution: {tarball: 'https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@286 '}
+ '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@bcb8ad2b':
+ resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@bcb8ad2b}
version: 1.0.0-next.7
peerDependencies:
svelte: ^4.0.0
- '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@85544105e5bd22ce2068c1c41e67238bad65eb82':
- resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@85544105e5bd22ce2068c1c41e67238bad65eb82}
+ '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c962928eeee5cfc960cc1070d469e613e096b7e1':
+ resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c962928eeee5cfc960cc1070d469e613e096b7e1}
version: 1.0.0-next.7
peerDependencies:
svelte: ^4.0.0
@@ -233,11 +233,11 @@ packages:
'@appwrite.io/pink-icons@1.0.0':
resolution: {integrity: sha512-+zpksP07MvOYwhx9AZDFW0pxXQNC2juKwyOQVRAwAOkN1ACSQKPlyytkI1u2ci6CQPWjJe20CzbvBBuRNXOKjA==}
- '@appwrite.io/pink-legacy@1.0.2':
- resolution: {integrity: sha512-1AYNcfbV+x0Tyj56CoieSq5g7+u+7F5/LDVN/z+Hx1kp9gj7xc1eT39Dy832xxfihImF6ksjp0FXEMVSBR8cew==}
+ '@appwrite.io/pink-legacy@1.0.3':
+ resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==}
- '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@286':
- resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@286}
+ '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@c962928':
+ resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@c962928}
version: 1.0.0-next.85
peerDependencies:
react-dom: ^18.0.0
@@ -4097,13 +4097,13 @@ snapshots:
'@analytics/type-utils@0.6.2': {}
- '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@ac51fcb': {}
+ '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@74f9464': {}
- '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@286 (svelte@4.2.19)':
+ '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@bcb8ad2b(svelte@4.2.19)':
dependencies:
svelte: 4.2.19
- '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@85544105e5bd22ce2068c1c41e67238bad65eb82(svelte@4.2.19)':
+ '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c962928eeee5cfc960cc1070d469e613e096b7e1(svelte@4.2.19)':
dependencies:
svelte: 4.2.19
@@ -4111,14 +4111,14 @@ snapshots:
'@appwrite.io/pink-icons@1.0.0': {}
- '@appwrite.io/pink-legacy@1.0.2':
+ '@appwrite.io/pink-legacy@1.0.3':
dependencies:
'@appwrite.io/pink-icons': 1.0.0
the-new-css-reset: 1.11.3
- '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@286(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)':
+ '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@c962928(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)':
dependencies:
- '@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@85544105e5bd22ce2068c1c41e67238bad65eb82(svelte@4.2.19)
+ '@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c962928eeee5cfc960cc1070d469e613e096b7e1(svelte@4.2.19)
'@floating-ui/dom': 1.6.13
'@melt-ui/pp': 0.3.2(@melt-ui/svelte@0.86.3(svelte@4.2.19))(svelte@4.2.19)
'@melt-ui/svelte': 0.86.3(svelte@4.2.19)
@@ -5375,7 +5375,7 @@ snapshots:
lodash: 4.17.21
redent: 3.0.0
- '@testing-library/svelte@5.2.7(svelte@4.2.19)(vite@5.4.14(@types/node@22.13.5)(sass@1.85.1))(vitest@1.6.1(@types/node@22.13.5)(@vitest/ui@1.6.1)(jsdom@22.1.0)(sass@1.85.1))':
+ '@testing-library/svelte@5.2.7(svelte@4.2.19)(vite@5.4.14(@types/node@22.13.5)(sass@1.85.1))(vitest@1.6.1)':
dependencies:
'@testing-library/dom': 10.4.0
svelte: 4.2.19
diff --git a/src/app.html b/src/app.html
index 4efaaef1f..18a92b1fa 100644
--- a/src/app.html
+++ b/src/app.html
@@ -7,128 +7,6 @@
content="Appwrite is an open-source platform for building applications at any scale, using your preferred programming languages and tools." />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
%sveltekit.head%
diff --git a/src/lib/actions/analytics.ts b/src/lib/actions/analytics.ts
index 19975c6ee..cbdc60077 100644
--- a/src/lib/actions/analytics.ts
+++ b/src/lib/actions/analytics.ts
@@ -138,6 +138,60 @@ export function isTrackingAllowed() {
}
}
+export enum Click {
+ BackupRestoreClick = 'click_backup_restore',
+ BreadcrumbClick = 'click_breadcrumb',
+ ConnectRepositoryClick = 'click_connect_repository',
+ CreditsRedeemClick = 'click_credits_redeem',
+ CloudSignupClick = 'click_cloud_signup',
+ DatabaseAttributeDelete = 'click_attribute_delete',
+ DatabaseIndexDelete = 'click_index_delete',
+ DatabaseCollectionDelete = 'click_collection_delete',
+ DatabaseDatabaseDelete = 'click_database_delete',
+ DomainCreateClick = 'click_domain_create',
+ DomainDeleteClick = 'click_domain_delete',
+ DomainRetryDomainVerificationClick = 'click_domain_retry_domain_verification',
+ FeedbackSubmitClick = 'click_leave_feedback',
+ FilterApplyClick = 'click_apply_filter',
+ FunctionsRedeployClick = 'click_function_redeploy',
+ FunctionsDeploymentDeleteClick = 'click_deployment_delete',
+ FunctionsDeploymentCancelClick = 'click_deployment_cancel',
+ KeyCreateClick = 'click_key_create',
+ MenuDropDownClick = 'click_menu_dropdown',
+ MenuOverviewClick = 'click_menu_overview',
+ ModalCloseClick = 'click_close_modal',
+ MessagingScheduleClick = 'click_messaging_schedule',
+ MessagingTopicCreateClick = 'click_messaging_topic_create',
+ MessagingTargetCreateClick = 'click_messaging_target_create',
+ MembershipDeleteClick = 'click_delete_membership',
+ PlatformCreateClick = 'click_platform_create',
+ OrganizationClickCreate = 'click_create_organization',
+ OrganizationClickUpgrade = 'click_organization_upgrade',
+ OnboardingSetupDatabaseClick = 'click_onboarding_setup_database',
+ OnboardingApiReferencesClick = 'click_onboarding_api_references',
+ OnboardingTutorialsClick = 'click_onboarding_tutorials',
+ OnboardingStorageQuickstartClick = 'click_onboarding_storage_quickstart',
+ OnboardingFunctionsQuickstartClick = 'click_onboarding_functions_quickstart',
+ OnboardingAuthEmailPasswordClick = 'click_onboarding_auth_email_password',
+ OnboardingAuthOauth2Click = 'click_onboarding_auth_oauth2',
+ OnboardingAuthAllMethodsClick = 'click_onboarding_auth_all_methods',
+ OnboardingDiscordClick = 'click_onboarding_discord',
+ StorageBucketDeleteClick = 'click_bucket_delete',
+ SettingsWebhookUpdateSignatureClick = 'click_webhook_update_signature',
+ SettingsWebhookDeleteClick = 'click_webhook_delete',
+ SettingsInstallProviderClick = 'click_install_provider',
+ SettingsStartMigrationClick = 'click_start_migration',
+ SubmitFormClick = 'click_submit_form',
+ ShowCustomIdClick = 'click_show_custom_id',
+ SupportOpenClick = 'click_open_support_menu',
+ PromoClick = 'click_promo',
+ PolicyDeleteClick = 'click_policy_delete',
+ VariablesCreateClick = 'click_variable_create',
+ VariablesUpdateClick = 'click_variable_update',
+ VariablesImportClick = 'click_variable_import',
+ WebsiteOpenClick = 'click_open_website'
+}
+
export enum Submit {
DownloadDPA = 'submit_download_dpa',
Error = 'submit_error',
@@ -158,6 +212,9 @@ export enum Submit {
AccountRecoveryCodesCreate = 'submit_account_recovery_codes_create',
AccountRecoveryCodesUpdate = 'submit_account_recovery_codes_update',
AccountDeleteIdentity = 'submit_account_delete_identity',
+ FeedbackSubmit = 'submit_leave_feedback',
+ FilterClear = 'submit_clear_filter',
+ FilterApply = 'submit_filter_apply',
UserCreate = 'submit_user_create',
UserDelete = 'submit_user_delete',
UserUpdateEmail = 'submit_user_update_email',
@@ -165,6 +222,7 @@ export enum Submit {
UserUpdateName = 'submit_user_update_name',
UserUpdatePassword = 'submit_user_update_password',
UserUpdatePhone = 'submit_user_update_phone',
+ UserUpdateMfa = 'submit_user_update_mfa',
UserUpdatePreferences = 'submit_user_update_preferences',
UserUpdateStatus = 'submit_user_update_status',
UserUpdateVerificationEmail = 'submit_user_update_verification_email',
@@ -186,9 +244,12 @@ export enum Submit {
MemberDelete = 'submit_member_delete',
MembershipUpdate = 'submit_membership_update',
MembershipUpdateStatus = 'submit_membership_update_status',
+ MessagingTargetUpdate = 'submit_messaging_target_update',
+ MessagingUpdateHtmlMode = 'submit_update_html_mode',
ProviderUpdate = 'submit_provider_update',
TeamCreate = 'submit_team_create',
TeamDelete = 'submit_team_delete',
+ TeamUpdatePreferences = 'submit_team_update_preferences',
TeamUpdateName = 'submit_team_update_name',
AuthLimitUpdate = 'submit_auth_limit_update',
AuthStatusUpdate = 'submit_auth_status_update',
@@ -231,6 +292,8 @@ export enum Submit {
FunctionUpdateTimeout = 'submit_function_update_timeout',
FunctionUpdateEvents = 'submit_function_update_events',
FunctionUpdateScopes = 'submit_function_key_update_scopes',
+ FunctionUpdateRuntime = 'submit_function_update_runtime',
+ FunctionUpdateBuildCommand = 'submit_function_update_build_command',
FunctionConnectRepo = 'submit_function_connect_repo',
FunctionDisconnectRepo = 'submit_function_disconnect_repo',
FunctionRedeploy = 'submit_function_redeploy',
@@ -249,9 +312,11 @@ export enum Submit {
KeyUpdateName = 'submit_key_update_name',
KeyUpdateScopes = 'submit_key_update_scopes',
KeyUpdateExpire = 'submit_key_update_expire',
+
PlatformCreate = 'submit_platform_create',
PlatformDelete = 'submit_platform_delete',
PlatformUpdate = 'submit_platform_update',
+
DomainCreate = 'submit_domain_create',
DomainDelete = 'submit_domain_delete',
DomainUpdateVerification = 'submit_domain_update_verification',
@@ -344,5 +409,7 @@ export enum Submit {
SiteActivateDeployment = 'submit_site_activate_deployment',
RecordCreate = 'submit_dns_record_create',
RecordUpdate = 'submit_dns_record_update',
- RecordDelete = 'submit_dns_record_delete'
+ RecordDelete = 'submit_dns_record_delete',
+ SearchClear = 'submit_clear_search',
+ FrameworkDetect = 'submit_framework_detect'
}
diff --git a/src/lib/commandCenter/panels/ai.svelte b/src/lib/commandCenter/panels/ai.svelte
index 59b341f6f..5f8a06ee3 100644
--- a/src/lib/commandCenter/panels/ai.svelte
+++ b/src/lib/commandCenter/panels/ai.svelte
@@ -1,11 +1,11 @@
-
-
-
- Apply
-
-
- {#if couponData?.status === 'error'}
+
+
+ Apply
+
+
+{#if couponData?.status === 'error'}
+
+
+
+ {couponData.code.toUpperCase()} is not a valid promo code
+
+
+{:else if couponData?.status === 'active'}
+
-
-
- {couponData.code.toUpperCase()} is not a valid promo code
-
+
+
+
+ {couponData.code.toUpperCase()} applied (-{formatCurrency(couponData.credits)})
+
+
- {:else if couponData?.status === 'active'}
-
-
-
-
-
- {couponData.code.toUpperCase()} applied (-{formatCurrency(
- couponData.credits
- )})
-
-
-
-
-
- {/if}
-
+
+
+{/if}
diff --git a/src/lib/components/billing/emptyCardCloud.svelte b/src/lib/components/billing/emptyCardCloud.svelte
index 7b7638ce6..b83676f28 100644
--- a/src/lib/components/billing/emptyCardCloud.svelte
+++ b/src/lib/components/billing/emptyCardCloud.svelte
@@ -1,8 +1,9 @@
-
-
-
- {currentPlan.name} plan
- {formatCurrency(currentPlan.price)}
-
-
- Additional seats ({collaborators?.length})
-
- {formatCurrency(extraSeatsCost)}
-
-
- {#if couponData?.status === 'active'}
-
- {/if}
-
-
-
- Upcoming chargeDue on {!currentPlan.trialDays
- ? toLocaleDate(billingPayDate.toString())
- : toLocaleDate(trialEndDate.toString())}
-
-
- {formatCurrency(estimatedTotal)}
-
-
-
-
- You'll pay {formatCurrency(estimatedTotal)} now, with your first
- billing cycle starting on
- {!currentPlan.trialDays
- ? toLocaleDate(billingPayDate.toString())
- : toLocaleDate(trialEndDate.toString())} . {#if couponData?.status === 'active'}Once your credits run out, you'll be charged
- {formatCurrency(currentPlan.price)} plus usage fees every 30
- days.
+
+
+
+
+ {currentPlan.name} plan
+ {formatCurrency(currentPlan.price)}
+
+
+ Additional seats ({collaborators?.length})
+ {formatCurrency(extraSeatsCost)}
+
+ {#if couponData?.status === 'active'}
+
{/if}
-
+
+
+
+ Upcoming charge
+ Due on {!currentPlan.trialDays
+ ? toLocaleDate(billingPayDate.toString())
+ : toLocaleDate(trialEndDate.toString())}
+ {formatCurrency(estimatedTotal)}
+
+
+
+ You'll pay {formatCurrency(estimatedTotal)} now, with your first billing cycle
+ starting on
+ {!currentPlan.trialDays
+ ? toLocaleDate(billingPayDate.toString())
+ : toLocaleDate(trialEndDate.toString())} . {#if couponData?.status === 'active'}Once your credits run out, you'll be charged
+ {formatCurrency(currentPlan.price)} plus usage fees every 30 days.
+ {/if}
+
-
{/if}
-
-
+
+
diff --git a/src/lib/components/billing/paymentBoxes.svelte b/src/lib/components/billing/paymentBoxes.svelte
index 0ff377796..be241fdf7 100644
--- a/src/lib/components/billing/paymentBoxes.svelte
+++ b/src/lib/components/billing/paymentBoxes.svelte
@@ -1,11 +1,12 @@
-
-
-
-
-
-
-
- {element.brand} ending in {element.last4}
-
-
- {#if element.$id === backupMethod}
- Backup
- {:else if element.$id === defaultMethod}
- Default
- {/if}
-
- {#if !!defaultMethod && element.$id !== defaultMethod && group === element.$id && showSetAsDefault && element.$id !== backupMethod}
-
+
+ {#each methods as method}
+ {@const value = method.$id}
+
+
+ {#if method.$id === backupMethod}
+
+ {:else if method.$id === defaultMethod}
+
{/if}
-
-
-
-
- Add new payment method
-
-
-
+
+
+ {method.brand} ending in {method.last4}
+
+
+
+ {/each}
+
+ {#if group === '$new'}
-
-
-
+
{#if showSetAsDefault}
-
+
{/if}
-
-
+ {/if}
+
diff --git a/src/lib/components/billing/planComparisonBox.svelte b/src/lib/components/billing/planComparisonBox.svelte
index 6d11df4fd..9d7443df4 100644
--- a/src/lib/components/billing/planComparisonBox.svelte
+++ b/src/lib/components/billing/planComparisonBox.svelte
@@ -2,38 +2,40 @@
import { BillingPlan } from '$lib/constants';
import { formatNum } from '$lib/helpers/string';
import { plansInfo, tierFree, tierPro, tierScale, type Tier } from '$lib/stores/billing';
- import { Card, SecondaryTabs, SecondaryTabsItem } from '..';
+ import { Card, Layout, Tabs, Typography } from '@appwrite.io/pink-svelte';
+
+ export let downgrade = false;
let selectedTab: Tier = BillingPlan.FREE;
- export let downgrade = false;
$: plan = $plansInfo.get(selectedTab);
-
-
-
-
+
+
+ (selectedTab = BillingPlan.FREE)}>
{tierFree.name}
-
-
+ (selectedTab = BillingPlan.PRO)}>
{tierPro.name}
-
-
+ (selectedTab = BillingPlan.SCALE)}>
{tierScale.name}
-
-
-
+
+
-
+
{plan.name} plan
{#if selectedTab === BillingPlan.FREE}
-
{plan.name} plan
{#if downgrade}
{:else}
-
+
-
- Limited to {plan.databases} Database, {plan.buckets} Buckets, {plan.functions}
- Functions per project
-
+ Limited to {plan.databases} Database, {plan.buckets} Buckets, {plan.functions}
+ Functions per project
+
+ Limited to 1 organization member
+
+ Limited to {plan.bandwidth}GB bandwidth
- Limited to 1 organization member
+ Limited to {plan.storage}GB storage
-
- {plan.bandwidth}GB bandwidth
-
-
-
-
- {plan.storage}GB storage
-
-
-
-
- {formatNum(plan.executions)} executions
-
+ Limited to {formatNum(plan.executions)} executions
{/if}
{:else if selectedTab === BillingPlan.PRO}
- {plan.name} plan
- Everything in the Free plan, plus:
-
+ Everything in the Free plan, plus:
+
Unlimited databases, buckets, functions
{plan.bandwidth}GB bandwidth
{plan.storage}GB storage
@@ -105,9 +96,8 @@
Email support
{:else if selectedTab === BillingPlan.SCALE}
- {plan.name} plan
- Everything in the Pro plan, plus:
-
+ Everything in the Pro plan, plus:
+
Unlimited seats
Organization roles
SOC-2, HIPAA compliance
@@ -115,29 +105,5 @@
Priority support
{/if}
-
-
-
-
+
+
diff --git a/src/lib/components/billing/planExcess.svelte b/src/lib/components/billing/planExcess.svelte
index 10fe17d54..485dbe74b 100644
--- a/src/lib/components/billing/planExcess.svelte
+++ b/src/lib/components/billing/planExcess.svelte
@@ -1,14 +1,4 @@
{#if showExcess}
-
-
- Your {tierToPlan($organization.billingPlan).name} plan subscription will end on {toLocaleDate(
- $organization.billingNextInvoiceDate
- )}
-
+
Following payment of your final invoice, your organization will switch to the {tierToPlan(
BillingPlan.FREE
).name} plan. {#if excess?.members > 0}All team members except the owner will be removed on
@@ -67,80 +58,78 @@
Learn more
-
+
-
-
- Resource
- Free limit
-
+
+
+ Resource
+ Free limit
+
Excess usage
+ >
Metrics are estimates updated every 24 hours
-
-
-
- {#if excess?.members}
-
- Organization members
- {plan.members} members
-
-
-
- {excess?.members} members
-
-
-
- {/if}
- {#if excess?.storage}
-
- Storage
- {plan.storage} GB
-
-
-
- {humanFileSize(excess?.storage).value}
- {humanFileSize(excess?.storage).unit}
-
-
-
- {/if}
- {#if excess?.executions}
-
- Function executions
-
- {abbreviateNumber(plan.executions)} executions
-
-
-
-
-
- {formatNum(excess?.executions)} executions
-
-
-
-
- {/if}
- {#if excess?.users}
-
- Users
-
- {abbreviateNumber(plan.users)} users
-
-
-
-
-
- {formatNum(excess?.users)} users
-
-
-
-
- {/if}
-
-
+
+
+ {#if excess?.members}
+
+ Organization members
+ {plan.members} members
+
+
+
+ {excess?.members} members
+
+
+
+ {/if}
+ {#if excess?.storage}
+
+ Storage
+ {plan.storage} GB
+
+
+
+ {humanFileSize(excess?.storage).value}
+ {humanFileSize(excess?.storage).unit}
+
+
+
+ {/if}
+ {#if excess?.executions}
+
+ Function executions
+
+ {abbreviateNumber(plan.executions)} executions
+
+
+
+
+
+ {formatNum(excess?.executions)} executions
+
+
+
+
+ {/if}
+ {#if excess?.users}
+
+ Users
+
+ {abbreviateNumber(plan.users)} users
+
+
+
+
+
+ {formatNum(excess?.users)} users
+
+
+
+
+ {/if}
+
{/if}
diff --git a/src/lib/components/billing/planSelection.svelte b/src/lib/components/billing/planSelection.svelte
index f016c6871..e26ea88c4 100644
--- a/src/lib/components/billing/planSelection.svelte
+++ b/src/lib/components/billing/planSelection.svelte
@@ -3,6 +3,7 @@
import { formatCurrency } from '$lib/helpers/numbers';
import { plansInfo, type Tier, tierFree, tierPro, tierScale } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
+ import { Badge, Layout, Typography } from '@appwrite.io/pink-svelte';
import { LabelCard } from '..';
export let billingPlan: Tier;
@@ -17,81 +18,60 @@
$: scalePlan = $plansInfo.get(BillingPlan.SCALE);
-{#if billingPlan}
-
-
-
-
-
- {tierFree.name}
- {#if $organization?.billingPlan === BillingPlan.FREE && !isNewOrg}
- Current plan
- {/if}
-
-
- {tierFree.description}
-
-
- {formatCurrency(freePlan?.price ?? 0)}
-
-
-
-
-
-
-
-
-
- {#if $organization?.billingPlan === BillingPlan.PRO && !isNewOrg}
- Current plan
- {/if}
-
-
- {tierPro.description}
-
-
- {formatCurrency(proPlan?.price ?? 0)} per member/month + usage
-
-
-
-
-
-
-
-
-
- {tierScale.name}
- {#if $organization?.billingPlan === BillingPlan.SCALE && !isNewOrg}
- Current plan
- {/if}
-
-
- {tierScale.description}
-
-
- {formatCurrency(scalePlan?.price ?? 0)} per month + usage
-
-
-
-
-
-
-{/if}
+
+
+
+ {#if $organization?.billingPlan === BillingPlan.FREE && !isNewOrg}
+
+ {/if}
+
+
+ {tierFree.description}
+
+
+ {formatCurrency(freePlan?.price ?? 0)}
+
+
+
+
+ {#if $organization?.billingPlan === BillingPlan.PRO && !isNewOrg}
+
+ {/if}
+
+
+ {tierPro.description}
+
+
+ {formatCurrency(proPlan?.price ?? 0)} per month + usage
+
+
+
+
+ {#if $organization?.billingPlan === BillingPlan.SCALE && !isNewOrg}
+
+ {/if}
+
+
+ {tierScale.description}
+
+
+ {formatCurrency(scalePlan?.price ?? 0)} per month + usage
+
+
+
diff --git a/src/lib/components/billing/selectPaymentMethod.svelte b/src/lib/components/billing/selectPaymentMethod.svelte
index cc479938d..dfd586ea7 100644
--- a/src/lib/components/billing/selectPaymentMethod.svelte
+++ b/src/lib/components/billing/selectPaymentMethod.svelte
@@ -1,14 +1,15 @@
-{#if filteredMethods?.length}
- {#if selectedPaymentMethod?.country?.toLowerCase() === 'in'}
-
- Indian credit or debit card-holders
- To comply with RBI regulations in India, Appwrite will ask for verification to charge up
- to $150 USD on your payment method. We will never charge more than the cost of your plan
- and the resources you use, or your budget cap limit. For higher usage limits, please contact
- us.
-
- {/if}
- {
- return {
- value: method.$id,
- label: `${capitalize(method.brand)} ending in ${method.last4}`,
- data: [method.brand]
- };
- })}
- interactiveOutput
- let:option={o}>
-
-
-
-
-
- {o.label}
-
-
-
-
-
-
-
-
-
-
- {o.label}
-
-
-
-
-
- (showPaymentModal = true)}>
-
- Add new payment method
-
-
-
-{:else}
-
-
-
-
-
-
- No saved payment methods
-
+
+
+ {#if filteredMethods?.length}
+ {#if selectedPaymentMethod?.country?.toLowerCase() === 'in'}
+
+ Indian credit or debit card-holders
+ To comply with RBI regulations in India, Appwrite will ask for verification to charge
+ up to $150 USD on your payment method. We will never charge more than the cost of
+ your plan and the resources you use, or your budget cap limit. For higher usage limits,
+ please contact us.
+
+ {/if}
+ {
+ return {
+ value: method.$id,
+ label: `${capitalize(method.brand)} ending in ${method.last4}`,
+ data: [method.brand]
+ };
+ })} />
+
(showPaymentModal = true)}>
+
+ Add new payment method
+
+
+ {:else}
+
+ (showPaymentModal = true)}>
Add
-
-
- {#if error}
-
{error}
+
{/if}
-
-{/if}
+
+
{#if showPaymentModal && isCloud && hasStripePublicKey}
-
- {#if showTaxId}
-
-
-
- {/if}
-
+ bind:checked={showTaxId} />
+ {#if showTaxId}
+
+ {/if}
{/if}
diff --git a/src/lib/components/billing/usageRates.svelte b/src/lib/components/billing/usageRates.svelte
index 48630dfbf..c3e67be8e 100644
--- a/src/lib/components/billing/usageRates.svelte
+++ b/src/lib/components/billing/usageRates.svelte
@@ -1,19 +1,12 @@
-
+
{#if isFree}
- Usage on the {$plansInfo?.get(BillingPlan.FREE).name} plan is limited for the following resources.
- Next billing period: {toLocaleDate(nextDate)}.
+
+ Usage on the {$plansInfo?.get(BillingPlan.FREE).name} plan is limited for the following resources.
+ Next billing period: {toLocaleDate(nextDate)}.
+
{:else if org.billingPlan === BillingPlan.PRO}
-
+
Usage on the Pro plan will be charged at the end of each billing period at the following
rates. Next billing period: {toLocaleDate(nextDate)}.
-
+
{:else if org.billingPlan === BillingPlan.SCALE}
-
+
Usage on the Scale plan will be charged at the end of each billing period at the
following rates. Next billing period: {toLocaleDate(nextDate)}.
-
+
{/if}
-
-
- Resource
- Limit
+
+
+ Resource
+ Limit
{#if !isFree}
- Rate
+ Rate
{/if}
-
-
- {#each planData as usage}
- {#if usage['id'] === 'members'}
-
- {usage.resource}
-
- {plan[usage.id] || 'Unlimited'}
-
- {#if !isFree}
-
- {formatCurrency(plan.addons.member.price)}/{usage?.unit}
-
- {/if}
-
- {:else}
- {@const addon = plan.addons[usage.id]}
-
- {usage.resource}
-
- {abbreviateNumber(plan[usage.id])}{usage?.unit}
-
- {#if !isFree}
-
- {formatCurrency(addon?.price)}/{['MB', 'GB', 'TB'].includes(
- addon?.unit
- )
- ? addon?.value
- : abbreviateNumber(addon?.value, 0)}{usage?.unit}
-
- {/if}
-
- {/if}
- {/each}
-
-
+
+ {#each planData as usage}
+ {#if usage['id'] === 'members'}
+
+ {usage.resource}
+
+ {plan[usage.id] || 'Unlimited'}
+
+ {#if !isFree}
+
+ {formatCurrency(plan.addons?.member?.price)}/{usage?.unit}
+
+ {/if}
+
+ {:else}
+ {@const addon = plan.addons[usage.id]}
+
+ {usage.resource}
+
+ {abbreviateNumber(plan[usage.id])}{usage?.unit}
+
+ {#if !isFree}
+
+ {formatCurrency(addon?.price)}/{['MB', 'GB', 'TB'].includes(addon?.unit)
+ ? addon?.value
+ : abbreviateNumber(addon?.value, 0)}{usage?.unit}
+
+ {/if}
+
+ {/if}
+ {/each}
+
(show = false)}>Close
diff --git a/src/lib/components/billing/validateCreditModal.svelte b/src/lib/components/billing/validateCreditModal.svelte
index 71775a383..9403e32f1 100644
--- a/src/lib/components/billing/validateCreditModal.svelte
+++ b/src/lib/components/billing/validateCreditModal.svelte
@@ -1,20 +1,20 @@
-
- Credits will be applied automatically to your next invoice.
+
+
+ Credits will be applied automatically to your next invoice.
+
-
-
-
+
(show = false)}>Cancel
- Add
+ Add
diff --git a/src/lib/components/bottom-sheet/SheetMenuBlock.svelte b/src/lib/components/bottom-sheet/SheetMenuBlock.svelte
index 8a408eeb7..a8d65c4be 100644
--- a/src/lib/components/bottom-sheet/SheetMenuBlock.svelte
+++ b/src/lib/components/bottom-sheet/SheetMenuBlock.svelte
@@ -1,13 +1,14 @@
-{#if menu.title}
+{#if menu?.title}
{/if}
@@ -31,12 +32,23 @@
on:click={() => {
if (menuItem.subMenu) {
navigateSubMenu(menuItem.subMenu);
+ } else if (menuItem.navigatePrevious) {
+ navigatePreviousMenu();
} else if (menuItem.onClick !== undefined) {
menuItem.onClick();
- isOpen = false;
+ if (menuItem.closeOnClick !== false) {
+ isOpen = false;
+ }
}
}}>
- {menuItem.name}
+ {#if menuItem?.checked !== undefined}
+
+
+ {menuItem.name}
+
+ {:else}
+ {menuItem.name}
+ {/if}
{/if}
{/each}
diff --git a/src/lib/components/bottom-sheet/bottomSheetMenu.svelte b/src/lib/components/bottom-sheet/bottomSheetMenu.svelte
index 8934de273..b83d07b1e 100644
--- a/src/lib/components/bottom-sheet/bottomSheetMenu.svelte
+++ b/src/lib/components/bottom-sheet/bottomSheetMenu.svelte
@@ -8,8 +8,10 @@
let sheetContainerRef: $$Props['sheetContainerRef'];
let activeMenu = menu;
let showDivider = true;
+ let previousMenu = activeMenu;
function navigateSubMenu(subMenu: SheetMenu) {
+ previousMenu = activeMenu;
if (sheetContainerRef) {
const currentHeight = sheetContainerRef.offsetHeight;
sheetContainerRef.style.overflowY = 'hidden';
@@ -27,6 +29,11 @@
showDivider = activeMenu.bottom !== undefined;
}
+ function navigatePreviousMenu() {
+ activeMenu = previousMenu;
+ showDivider = activeMenu.bottom !== undefined;
+ }
+
function restoreMenu(isOpenState: boolean) {
showDivider = activeMenu.bottom !== undefined;
if (!isOpenState) {
@@ -40,11 +47,20 @@
-
+
+
+
- {#if activeMenu.bottom} {/if}
+ {navigatePreviousMenu}
+ bind:isOpen />
+ {/if}
diff --git a/src/lib/components/bottom-sheet/index.ts b/src/lib/components/bottom-sheet/index.ts
index 80cb607e4..be8134d22 100644
--- a/src/lib/components/bottom-sheet/index.ts
+++ b/src/lib/components/bottom-sheet/index.ts
@@ -19,6 +19,9 @@ type MenuItem = {
trailingIcon?: ComponentType;
onClick?: () => void;
href?: string;
+ closeOnClick?: boolean;
+ navigatePrevious?: boolean;
+ checked?: boolean;
subMenu?: { top: SubMenu; bottom: SubMenu };
};
diff --git a/src/lib/components/bottomModalAlert.svelte b/src/lib/components/bottomModalAlert.svelte
index 03ace8873..acc8ade8d 100644
--- a/src/lib/components/bottomModalAlert.svelte
+++ b/src/lib/components/bottomModalAlert.svelte
@@ -15,7 +15,7 @@
import { addBottomModalAlerts } from '$routes/(console)/bottomAlerts';
import { project } from '$routes/(console)/project-[project]/store';
import { page } from '$app/stores';
- import { trackEvent } from '$lib/actions/analytics';
+ import { Click, trackEvent } from '$lib/actions/analytics';
let currentIndex = 0;
let openModalOnMobile = false;
@@ -170,7 +170,7 @@
external={!!currentModalAlert.cta.external}
fullWidthMobile
on:click={() => {
- trackEvent('click_promo', {
+ trackEvent(Click.PromoClick, {
promo: currentModalAlert.id,
type: shouldShowUpgrade ? 'upgrade' : 'try_now'
});
@@ -282,7 +282,7 @@
fullWidthMobile
on:click={() => {
openModalOnMobile = false;
- trackEvent('click_promo', {
+ trackEvent(Click.PromoClick, {
promo: currentModalAlert.id,
type: shouldShowUpgrade ? 'upgrade' : 'try_now'
});
diff --git a/src/lib/components/breadcrumbs.svelte b/src/lib/components/breadcrumbs.svelte
index a0cb4468e..b62544e53 100644
--- a/src/lib/components/breadcrumbs.svelte
+++ b/src/lib/components/breadcrumbs.svelte
@@ -13,6 +13,7 @@
import { goto } from '$app/navigation';
import { base } from '$app/paths';
import { newOrgModal } from '$lib/stores/organization';
+ import { Click, trackEvent } from '$lib/actions/analytics';
type Project = {
name: string;
@@ -68,6 +69,7 @@
let projectsBottomSheetOpen = false;
function createOrg() {
+ trackEvent(Click.OrganizationClickCreate, { source: 'breadcrumbs' });
if (isCloud) {
goto(`${base}/create-organization`);
} else newOrgModal.set(true);
@@ -397,7 +399,7 @@
:global(.item[data-highlighted]) {
border-radius: var(--border-radius-S, 8px);
- background: var(--color-overlay-neutral-hover, rgba(25, 25, 28, 0.03));
+ background: var(--overlay-neutral-hover, rgba(25, 25, 28, 0.03));
}
.trigger {
display: inline-flex;
@@ -412,7 +414,7 @@
color: var(--fgcolor-neutral-primary, #2d2d31);
border-radius: var(--corner-radius-medium, 8px);
- cursor: default;
+ cursor: pointer;
/* Body text/level 2 Regular */
font-family: Inter;
font-size: 14px;
@@ -422,7 +424,7 @@
}
.trigger:hover {
- background: var(--color-overlay-neutral-hover, rgba(25, 25, 28, 0.03));
+ background: var(--overlay-neutral-hover, rgba(25, 25, 28, 0.03));
}
:global(.trigger[data-highlighted]) {
@@ -430,12 +432,12 @@
background: var(--bgcolor-neutral-secondary, #f4f4f7);
}
- :global(.trigger[data-highlighted]:focus) {
+ :global(.trigger[data-highlighted]:focus-visible) {
outline: none;
box-shadow: 0 0 0 2px var(--bgcolor-neutral-secondary, #f4f4f7);
}
- .trigger:focus {
+ .trigger:focus-visible {
z-index: 30;
box-shadow:
var(--shadow-offsetx-0, 0px) var(--shadow-offsety-0, 0px) 0 2px
diff --git a/src/lib/components/cardContainer.svelte b/src/lib/components/cardContainer.svelte
index 83f93628f..19ed61f5f 100644
--- a/src/lib/components/cardContainer.svelte
+++ b/src/lib/components/cardContainer.svelte
@@ -19,10 +19,7 @@
$: limit = preferences.get($page.route)?.limit ?? CARD_LIMIT;
- 3 ? '22rem' : '25rem'};`}
- data-private>
+ 3 ? '22rem' : '25rem'};`} data-private>
{#if total > 3 ? total < limit + offset : total % 2 !== 0}
@@ -35,3 +32,13 @@
{/if}
{/if}
+
+
diff --git a/src/lib/components/cardGrid.svelte b/src/lib/components/cardGrid.svelte
index 54d23375e..802e7bc5a 100644
--- a/src/lib/components/cardGrid.svelte
+++ b/src/lib/components/cardGrid.svelte
@@ -3,23 +3,24 @@
export let hideOverflow = false;
export let hideFooter = false;
+ export let gap: 'none' | 'xxxs' | 'xxs' | 'xs' | 's' | 'm' | 'l' | 'xl' | 'xxl' | 'xxxl' = 'l';
-
-
-
+
+
+
{#if $$slots.default}
{/if}
-
-
+
+
-
-
+
+
{#if $$slots.actions && !hideFooter}
@@ -31,10 +32,3 @@
{/if}
-
-
diff --git a/src/lib/components/cardPlanLimit.svelte b/src/lib/components/cardPlanLimit.svelte
index 51fd5242e..3baae619d 100644
--- a/src/lib/components/cardPlanLimit.svelte
+++ b/src/lib/components/cardPlanLimit.svelte
@@ -1,6 +1,7 @@
@@ -8,6 +9,11 @@
Upgrade your plan to add more {service}
-
Change plan
+
{
+ trackEvent(Click.OrganizationClickUpgrade, { source: 'card_plan_limit' });
+ }}>Change plan
diff --git a/src/lib/components/creditCardInfo.svelte b/src/lib/components/creditCardInfo.svelte
index f18743134..ff19679a8 100644
--- a/src/lib/components/creditCardInfo.svelte
+++ b/src/lib/components/creditCardInfo.svelte
@@ -1,41 +1,38 @@
-
-
-
-
-
- {paymentMethod?.brand} ending in {paymentMethod?.last4}
-
-
-
-
- Expires {paymentMethod?.expiryMonth}/{paymentMethod?.expiryYear}
-
- {#if paymentMethod?.name}
-
- {paymentMethod.name}
-
- {/if}
-
-
-
-
- {#if paymentMethod?.expired}
-
- This payment method has expired
-
+
+
+
+ ending in {paymentMethod?.last4}
+ {#if isBackup}
+
+ {/if}
+
+
+
{paymentMethod?.name}
+
{paymentMethod?.expiryMonth}/{paymentMethod?.expiryYear}
+
+ {#if paymentMethod?.lastError || paymentMethod?.expired}
+
+
+
+ Details
+
+
+ {#if paymentMethod?.expired}
+ This payment method has expired
+ {/if}
+ {#if paymentMethod?.lastError}
+ {paymentMethod.lastError}
+ {/if}
+
+
{/if}
- {#if paymentMethod?.lastError}
-
- {paymentMethod.lastError}
-
- {/if}
-
+
diff --git a/src/lib/components/customId.svelte b/src/lib/components/customId.svelte
index 9301b04a1..0db5336dc 100644
--- a/src/lib/components/customId.svelte
+++ b/src/lib/components/customId.svelte
@@ -1,5 +1,5 @@
diff --git a/src/lib/components/emptySearch.svelte b/src/lib/components/emptySearch.svelte
index 5a0b7e00d..220a79f3c 100644
--- a/src/lib/components/emptySearch.svelte
+++ b/src/lib/components/emptySearch.svelte
@@ -1,26 +1,32 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-{#if !hidePagination}
-
-{/if}
+ {#if !hidePagination}
+
+ Total results: 0
+
+
+ {/if}
+
diff --git a/src/lib/components/fakeModal.svelte b/src/lib/components/fakeModal.svelte
index 23bb89aa7..405bd8233 100644
--- a/src/lib/components/fakeModal.svelte
+++ b/src/lib/components/fakeModal.svelte
@@ -2,7 +2,7 @@
import { Alert } from '$lib/components';
import { onMount } from 'svelte';
import Form from '$lib/elements/forms/form.svelte';
- import { trackEvent } from '$lib/actions/analytics';
+ import { Click, trackEvent } from '$lib/actions/analytics';
import { clickOnEnter } from '$lib/helpers/a11y';
export let show = false;
@@ -23,7 +23,7 @@
function handleBLur(event: MouseEvent) {
if (event.target === backdrop) {
- trackEvent('click_close_modal', {
+ trackEvent(Click.ModalCloseClick, {
from: 'backdrop'
});
closeModal();
@@ -38,7 +38,7 @@
function handleKeydown(event: KeyboardEvent) {
if (event.key === 'Escape') {
event.preventDefault();
- trackEvent('click_close_modal', {
+ trackEvent(Click.ModalCloseClick, {
from: 'escape'
});
closeModal();
@@ -100,7 +100,7 @@
aria-label="Close Modal"
title="Close Modal"
on:click={() =>
- trackEvent('click_close_modal', {
+ trackEvent(Click.ModalCloseClick, {
from: 'button'
})}
on:click={closeModal}>
@@ -152,5 +152,9 @@
:global() {
background-color: hsl(240 5% 8% / 0.6);
}
+
+ & :global(.modal-form) {
+ position: unset;
+ }
}
diff --git a/src/lib/components/filePicker.svelte b/src/lib/components/filePicker.svelte
index 8e1ec6bc6..0a91034c4 100644
--- a/src/lib/components/filePicker.svelte
+++ b/src/lib/components/filePicker.svelte
@@ -1,31 +1,32 @@
@@ -91,27 +92,24 @@
{#if column && operator && !operator?.hideInput}
{#if column?.array}
-
- {#if column.format === 'enum'}
- ({
- label: e?.label ?? e,
- value: e?.value ?? e,
- checked: arrayValues.includes(e?.value ?? e)
- }))}>
-
- {:else}
-
- {/if}
-
+ {#if column.format === 'enum'}
+
({
+ label: e?.label ?? e,
+ value: e?.value ?? e,
+ checked: arrayValues.includes(e?.value ?? e)
+ }))}>
+
+ {:else}
+
+ {/if}
{:else}
{#if column.format === 'enum'}
@@ -122,9 +120,7 @@
options={column?.elements?.map((e) => ({
label: e?.label ?? e,
value: e?.value ?? e
- }))}
- label="Value"
- showLabel={false} />
+ }))} />
{:else if column.type === 'integer' || column.type === 'double'}
{:else if column.type === 'boolean'}
@@ -139,12 +135,7 @@
bind:value />
{:else if column.type === 'datetime'}
{#key value}
-
+
{/key}
{:else}
@@ -162,21 +153,12 @@
{#if !singleCondition}
{/if}
-
-
diff --git a/src/lib/components/filters/customFilters.svelte b/src/lib/components/filters/customFilters.svelte
new file mode 100644
index 000000000..09ff475fb
--- /dev/null
+++ b/src/lib/components/filters/customFilters.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {
+ show = true;
+ }}>Custom filters
+
+
+{#if show}
+
+{/if}
diff --git a/src/lib/components/filters/filters.svelte b/src/lib/components/filters/filters.svelte
index 1a05210a0..6d9e7067f 100644
--- a/src/lib/components/filters/filters.svelte
+++ b/src/lib/components/filters/filters.svelte
@@ -16,6 +16,7 @@
import { createEventDispatcher } from 'svelte';
import { Icon, Layout, Popover } from '@appwrite.io/pink-svelte';
import { IconFilter, IconFilterLine } from '@appwrite.io/pink-icons-svelte';
+ import { Click, Submit, trackEvent } from '$lib/actions/analytics';
export let query = '[]';
export let columns: Writable;
@@ -25,6 +26,7 @@
export let clearOnClick = false; // When enabled the user doesn't have to click apply to clear the filters
export let enableApply = false;
export let quickFilters = false;
+ export let analyticsSource = '';
let displayQuickFilters = quickFilters;
const dispatch = createEventDispatcher();
@@ -53,12 +55,14 @@
selectedColumn = null;
queries.clearAll();
if (clearOnClick) {
+ trackEvent(Submit.FilterClear, { source: analyticsSource });
queries.apply();
}
}
function apply() {
if (quickFilters && displayQuickFilters) {
+ trackEvent(Submit.FilterApply, { source: analyticsSource });
dispatch('apply');
} else if (
selectedColumn &&
@@ -118,7 +122,13 @@
-
+ {
+ toggle(event);
+ trackEvent(Click.FilterApplyClick, { source: analyticsSource });
+ }}
+ {disabled}>
Filters
{#if applied > 0}
@@ -225,24 +235,3 @@
-
-
diff --git a/src/lib/components/filters/filtersModal.svelte b/src/lib/components/filters/filtersModal.svelte
new file mode 100644
index 000000000..a25291de0
--- /dev/null
+++ b/src/lib/components/filters/filtersModal.svelte
@@ -0,0 +1,180 @@
+
+
+
+ Apply filter rules to refine the table view
+
+
+
+ c.filter !== false)
+ .map((c) => ({
+ label: c.title,
+ value: c.id
+ }))}
+ placeholder="Select column"
+ bind:value={selectedColumn} />
+
+
+ {#if column && operatorKey}
+ {#if column?.array}
+ {#if column.format === 'enum'}
+ ({
+ label: e?.label ?? e,
+ value: e?.value ?? e,
+ checked: arrayValues.includes(e?.value ?? e)
+ }))}>
+
+ {:else}
+
+ {/if}
+ {:else if column.format === 'enum'}
+ ({
+ label: e?.label ?? e,
+ value: e?.value ?? e
+ }))} />
+ {:else if column.type === 'integer' || column.type === 'double'}
+
+ {:else if column.type === 'boolean'}
+
+ {:else if column.type === 'datetime'}
+ {#key value}
+
+ {/key}
+ {:else}
+
+ {/if}
+ {/if}
+
+
+
+ Add condition
+
+
+
+ {#if localTags?.length}
+
+ removeCondition(e.detail)} />
+
+ {/if}
+
+
+ {#if localTags?.length}
+ Clear all
+ {:else}
+ (show = false)}>Cancel
+ {/if}
+ Apply
+
+
diff --git a/src/lib/components/filters/index.ts b/src/lib/components/filters/index.ts
index 7d3b7f3d2..eb4bd0f3d 100644
--- a/src/lib/components/filters/index.ts
+++ b/src/lib/components/filters/index.ts
@@ -1,3 +1,6 @@
export { default as Filters } from './filters.svelte';
export { default as TagList } from './tagList.svelte';
+export { default as CustomFilters } from './customFilters.svelte';
+export { default as QuickFilters } from './quickFilters.svelte';
+export { default as ParsedTagList } from './parsedTagList.svelte';
export { hasPageQueries, queryParamToMap, queries } from '$lib/components/filters/store';
diff --git a/src/lib/components/filters/parsedTagList.svelte b/src/lib/components/filters/parsedTagList.svelte
new file mode 100644
index 000000000..4b1faa05d
--- /dev/null
+++ b/src/lib/components/filters/parsedTagList.svelte
@@ -0,0 +1,42 @@
+
+
+{#if $parsedTags?.length}
+
+ {#each $parsedTags as tag}
+
+
+ {
+ const t = $tags.filter((t) => t.tag.includes(tag.tag.split(' ')[0]));
+ t.forEach((t) => (t ? queries.removeFilter(t) : null));
+ queries.apply();
+ parsedTags.update((tags) => tags.filter((t) => t.tag !== tag.tag));
+ }}>
+ {#key tag.tag}
+ {tag.tag}
+ {/key}
+
+
+ {tag?.value?.toString()}
+
+
+ {/each}
+ {
+ queries.clearAll();
+ queries.apply();
+ parsedTags.set([]);
+ }}>Clear all
+
+{/if}
diff --git a/src/lib/components/filters/quickFilters.svelte b/src/lib/components/filters/quickFilters.svelte
new file mode 100644
index 000000000..3db6a3de5
--- /dev/null
+++ b/src/lib/components/filters/quickFilters.svelte
@@ -0,0 +1,208 @@
+
+
+{#if $isSmallViewport}
+ {#if $parsedTags?.length}
+ (openBottomSheet = true)}>
+
+ Filters
+
+ {:else}
+ (openBottomSheet = true)}>
+
+ Filters
+
+ {/if}
+{:else}
+
+ {#if $parsedTags?.length}
+
+
+ Filters
+
+ {:else}
+
+
+ Filters
+
+ {/if}
+
+ {#each filterCols as filter}
+ {#if filter.options}
+ {
+ addFilterAndApply(
+ filter.id,
+ filter.title,
+ filter.operator,
+ e.detail.value,
+ filter?.array
+ ? (filter.options
+ .filter((opt) => opt.checked)
+ .map((opt) => opt.value) ?? [])
+ : [],
+ $columns,
+ analyticsSource
+ );
+ }}
+ on:clear={() => {
+ addFilterAndApply(
+ filter.id,
+ filter.title,
+ filter.operator,
+ null,
+ [],
+ $columns,
+ analyticsSource
+ );
+ }} />
+ {/if}
+ {/each}
+
+
+
+
+
+
+{/if}
+
+{#if $isSmallViewport && openBottomSheet}
+
+{/if}
diff --git a/src/lib/components/filters/quickFilters.ts b/src/lib/components/filters/quickFilters.ts
new file mode 100644
index 000000000..fc09619b0
--- /dev/null
+++ b/src/lib/components/filters/quickFilters.ts
@@ -0,0 +1,77 @@
+import type { Column } from '$lib/helpers/types';
+import { get } from 'svelte/store';
+import { addFilter, queries, tags, ValidOperators } from './store';
+import { Submit, trackEvent } from '$lib/actions/analytics';
+
+export type FilterData = {
+ title: string;
+ id: string;
+ array: boolean;
+ show: boolean;
+ tag: string;
+ operator: ValidOperators;
+ options: { value: string; label: string; checked: boolean }[];
+};
+
+export function buildFilterCol(col: Column, customOperator = null): FilterData {
+ return {
+ title: col.title,
+ id: col.id,
+ show: false,
+ array: col?.array,
+ tag: null,
+ operator: customOperator ?? ValidOperators.Equal,
+ options: col?.elements?.map((element) => {
+ return {
+ value: (element?.value ?? element) as string,
+ label: (element?.label ?? element) as string,
+ checked: false
+ };
+ })
+ };
+}
+
+export function addFilterAndApply(
+ colId: string,
+ colTitle: string,
+ operator: ValidOperators,
+ value: string,
+ arrayValues: string[] = [],
+ columns: Column[],
+ analyticsSource: string
+) {
+ const tagList = get(tags).filter((tag) => tag.tag.includes(colTitle));
+ tagList.forEach((tag) => queries.removeFilter(tag));
+ if (value || arrayValues?.length) {
+ if (colId === 'sourceSize' || colId === 'buildSize') {
+ addSizeFilter(value, colId, columns);
+ } else if (colId === 'statusCode') {
+ addStatusCodeFilter(value, colId, columns);
+ } else if (colId === '$createdAt' || colId === '$updatedAt' || colId === 'buildDuration') {
+ addDateFilter(value, colId, columns);
+ } else {
+ addFilter(columns, colId, operator, value, arrayValues);
+ }
+ }
+ queries.apply();
+ trackEvent(Submit.ApplyQuickFilter, {
+ source: analyticsSource,
+ column: colId,
+ value: value || arrayValues.join(', ')
+ });
+}
+
+export function addStatusCodeFilter(value: string, colId: string, columns: Column[]) {
+ addFilter(columns, colId, ValidOperators.LessThanOrEqual, parseInt(value));
+ addFilter(columns, colId, ValidOperators.GreaterThanOrEqual, parseInt(value) - 99);
+}
+export function addDateFilter(value: string, colId: string, columns: Column[]) {
+ const now = new Date();
+ const isoValue = new Date(now.getTime() - parseInt(value));
+ addFilter(columns, colId, ValidOperators.GreaterThanOrEqual, isoValue.toISOString());
+ addFilter(columns, colId, ValidOperators.LessThanOrEqual, now.toISOString());
+}
+
+export function addSizeFilter(value: string, colId: string, columns: Column[]) {
+ addFilter(columns, colId, ValidOperators.GreaterThanOrEqual, value);
+}
diff --git a/src/lib/components/filters/quickfiltersSubMenu.svelte b/src/lib/components/filters/quickfiltersSubMenu.svelte
new file mode 100644
index 000000000..23159f67e
--- /dev/null
+++ b/src/lib/components/filters/quickfiltersSubMenu.svelte
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
diff --git a/src/lib/components/filters/setFilters.ts b/src/lib/components/filters/setFilters.ts
new file mode 100644
index 000000000..97c9f741f
--- /dev/null
+++ b/src/lib/components/filters/setFilters.ts
@@ -0,0 +1,187 @@
+import type { Column } from '$lib/helpers/types';
+import { get, writable } from 'svelte/store';
+import { type FilterData } from './quickFilters';
+import { tags, type TagValue } from './store';
+
+export const parsedTags = writable([]);
+
+export function setFilters(localTags: TagValue[], filterCols: FilterData[], $columns: Column[]) {
+ if (!localTags?.length) {
+ filterCols.forEach((filter) => {
+ resetOptions(filter);
+ cleanOldTags(filter.title);
+ });
+ } else {
+ filterCols.forEach((filter) => {
+ if (filter.id.toLowerCase().includes('duration')) {
+ setTimeFilter(filter, $columns);
+ } else if (filter.id.toLocaleLowerCase().includes('size')) {
+ setSizeFilter(filter, $columns);
+ } else if (filter.id.toLocaleLowerCase().includes('statuscode')) {
+ setStatusCodeFilter(filter, $columns);
+ } else if (filter.id === '$createdAt' || filter.id === '$updatedAt') {
+ setDateFilter(filter, $columns);
+ } else {
+ setFilterData(filter);
+ }
+ });
+
+ // Reasinging the filters to trigger reactivity
+ filterCols = filterCols;
+ }
+}
+
+export function setFilterData(filter: FilterData) {
+ const tagData = get(tags).find((tag) => tag.tag.includes(`**${filter.title}**`));
+ if (tagData) {
+ if (Array.isArray(tagData.value) && tagData.value?.length) {
+ const values = tagData.value as string[];
+ filter.options.forEach((option) => {
+ option.checked = values.includes(option.value);
+ });
+ }
+ cleanOldTags(filter.title);
+ const newTag = {
+ tag: tagData.tag.replace(',', ' or '),
+ value: tagData.value
+ };
+
+ parsedTags.update((tags) => {
+ tags.push(newTag);
+ return tags;
+ });
+ } else {
+ resetOptions(filter);
+ cleanOldTags(filter.title);
+ }
+}
+
+export function setTimeFilter(filter: FilterData, columns: Column[]) {
+ const col = columns.find((c) => c.id === filter.id);
+ const timeTag = get(tags).find((tag) => tag.tag.includes(`**${filter.title}**`));
+ if (timeTag) {
+ const now = new Date();
+
+ const diff = now.getTime() - new Date(timeTag.value as string).getTime();
+ const ranges = col.elements as { value: string; label: string }[];
+ const dateRange = ranges.reduce((prev, curr) => {
+ if (parseInt(curr.value) < diff && curr.value > prev.value) {
+ return curr;
+ }
+ return prev;
+ });
+ if (dateRange) {
+ const newTag = {
+ tag: `**${filter.title}** is **${dateRange.label}**`,
+ value: timeTag.value
+ };
+
+ cleanOldTags(filter.title);
+
+ parsedTags.update((tags) => {
+ tags.push(newTag);
+ return tags;
+ });
+ }
+ } else {
+ cleanOldTags(filter.title);
+ }
+}
+
+export function setSizeFilter(filter: FilterData, columns: Column[]) {
+ const sizeTag = get(tags).find((tag) => tag.tag.includes(`**${filter.title}**`));
+ const col = columns.find((c) => c.id === filter.id);
+ if (sizeTag) {
+ const size = sizeTag.value as string;
+ const ranges = col.elements as { value: string; label: string }[];
+ // find smallest range that is bigger than size
+ const sizeRange = ranges.reduce((prev, curr) => {
+ if (parseInt(size) >= parseInt(curr.value)) {
+ return curr;
+ }
+ return prev;
+ });
+ if (sizeRange) {
+ cleanOldTags(filter.title);
+
+ const newTag = {
+ tag: `**${filter.title}** is **${sizeRange.label}**`,
+ value: sizeTag.value
+ };
+ parsedTags.update((tags) => {
+ tags.push(newTag);
+ return tags;
+ });
+ }
+ } else {
+ cleanOldTags(filter.title);
+ }
+}
+
+export function setStatusCodeFilter(filter: FilterData, columns: Column[]) {
+ const statusCodeTag = get(tags).find((tag) => tag.tag.includes(`**${filter.title}**`));
+ const col = columns.find((c) => c.id === filter.id);
+
+ if (statusCodeTag) {
+ const ranges = col.elements as { value: number; label: string }[];
+
+ const codeRange = ranges.find((c) => c?.value && c.value === statusCodeTag.value);
+ if (codeRange) {
+ cleanOldTags(filter.title);
+ const newTag = {
+ tag: `**${filter.title}** is **${codeRange.label}**`,
+ value: statusCodeTag.value
+ };
+ console.log(codeRange);
+ parsedTags.update((tags) => {
+ tags.push(newTag);
+ return tags;
+ });
+ }
+ } else {
+ cleanOldTags(filter.title);
+ }
+}
+
+export function setDateFilter(filter: FilterData, columns: Column[]) {
+ const dateTag = get(tags).find((tag) => tag.tag.includes(`**${filter.title}**`));
+ const col = columns.find((c) => c.id === filter.id);
+ if (dateTag) {
+ const now = new Date();
+
+ const diff = now.getTime() - new Date(dateTag.value as string).getTime();
+ const ranges = col.elements as { value: string; label: string }[];
+ const dateRange = ranges.reduce((prev, curr) => {
+ if (parseInt(curr.value) < diff && curr.value > prev.value) {
+ return curr;
+ }
+ return prev;
+ });
+ if (dateRange) {
+ cleanOldTags(filter.title);
+ const newTag = {
+ tag: `**${filter.title}** is **${dateRange.label}**`,
+ value: dateTag.value
+ };
+ parsedTags.update((tags) => {
+ tags.push(newTag);
+ return tags;
+ });
+ }
+ } else {
+ cleanOldTags(filter.title);
+ }
+}
+
+function cleanOldTags(title: string) {
+ parsedTags.update((tags) => {
+ tags = tags.filter((tag) => !tag.tag.includes(`**${title}**`));
+ return tags;
+ });
+}
+
+export function resetOptions(filter: FilterData) {
+ filter.options.forEach((option) => {
+ option.checked = false;
+ });
+}
diff --git a/src/lib/components/filters/store.ts b/src/lib/components/filters/store.ts
index 10cd6f183..6be45f6a0 100644
--- a/src/lib/components/filters/store.ts
+++ b/src/lib/components/filters/store.ts
@@ -1,5 +1,4 @@
import { goto } from '$app/navigation';
-
import { derived, get, writable } from 'svelte/store';
import { page } from '$app/stores';
import deepEqual from 'deep-equal';
@@ -245,30 +244,13 @@ function formatArray(array: string[]) {
}
}
-function generateDefaultOperators() {
+export function generateDefaultOperators() {
const operators: Record = {};
operatorsDefault.forEach((operator, operatorName) => {
operators[operatorName] = {
toQuery: operator.query,
toTag: (attribute, input = null, type = null) => {
- if (input === null) {
- return {
- value: '',
- tag: `**${attribute}** ${operatorName}`
- };
- } else if (Array.isArray(input) && input.length > 2) {
- return {
- value: input,
- tag: `**${attribute}** ${operatorName} **${formatArray(input)}** `
- };
- } else if (type === ValidTypes.Datetime) {
- return {
- value: input,
- tag: `**${attribute}** ${operatorName} **${toLocaleDateTime(input.toString())}**`
- };
- } else {
- return { value: input, tag: `**${attribute}** ${operatorName} **${input}**` };
- }
+ return generateTag(attribute, operatorName, input, type);
},
types: operator.types,
hideInput: operator.hideInput
@@ -277,6 +259,27 @@ function generateDefaultOperators() {
return operators;
}
+export function generateTag(attribute: string, operatorName: string, input = null, type = null) {
+ if (input === null) {
+ return {
+ value: '',
+ tag: `**${attribute}** ${operatorName}`
+ };
+ } else if (Array.isArray(input) && input.length > 2) {
+ return {
+ value: input,
+ tag: `**${attribute}** ${operatorName} **${formatArray(input)}** `
+ };
+ } else if (type === ValidTypes.Datetime) {
+ return {
+ value: input,
+ tag: `**${attribute}** ${operatorName} **${toLocaleDateTime(input.toString())}**`
+ };
+ } else {
+ return { value: input, tag: `**${attribute}** ${operatorName} **${input}**` };
+ }
+}
+
export const operators = generateDefaultOperators();
export function tagFormat(node: HTMLElement) {
diff --git a/src/lib/components/filters/tagList.svelte b/src/lib/components/filters/tagList.svelte
index 6e7f2a5d5..33389514b 100644
--- a/src/lib/components/filters/tagList.svelte
+++ b/src/lib/components/filters/tagList.svelte
@@ -1,22 +1,29 @@
-{#each $tags as tag (tag)}
-
- {
- queries.removeFilter(tag);
- queries.apply();
- }}>
-
- {tag.tag}
-
-
-
- {tag?.value?.toString()}
-
+{#each tags as tag (tag)}
+
+
+ {
+ dispatch('remove', tag);
+ }}>
+ {#key tag.tag}
+ {tag.tag}
+ {/key}
+
+
+ {tag?.value?.toString()}
+
+
{/each}
diff --git a/src/routes/(console)/project-[project]/sites/create-site/templates/template-[template]/connectBehaviour.svelte b/src/lib/components/git/connectBehaviour.svelte
similarity index 84%
rename from src/routes/(console)/project-[project]/sites/create-site/templates/template-[template]/connectBehaviour.svelte
rename to src/lib/components/git/connectBehaviour.svelte
index 714851b88..ae0da51eb 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/templates/template-[template]/connectBehaviour.svelte
+++ b/src/lib/components/git/connectBehaviour.svelte
@@ -3,8 +3,8 @@
import { consoleVariables } from '$routes/(console)/store';
import { Layout } from '@appwrite.io/pink-svelte';
- export let connectBehaviour: 'now' | 'later' = 'now';
const isVcsEnabled = $consoleVariables?._APP_VCS_ENABLED === true;
+ export let connectBehaviour: 'now' | 'later' = isVcsEnabled ? 'now' : 'later';
@@ -15,7 +15,7 @@
title="Connect your repository">
Clone this template into a new Git repository or link it to an existing one.
-
+
Connect later
Deploy now and connect your version control later via CLI or Git integration in your settings.
diff --git a/src/lib/components/git/connectGit.svelte b/src/lib/components/git/connectGit.svelte
index 0d04da858..9dbca0fc7 100644
--- a/src/lib/components/git/connectGit.svelte
+++ b/src/lib/components/git/connectGit.svelte
@@ -1,54 +1,48 @@
-{#if !isVcsEnabled && isSelfHosted}
-
- Installing Git on a self-hosted instance
-
- Before installing Git in a locally hosted Appwrite project, ensure your environment
- variables are configured.
-
-
- Learn more
-
-
-{/if}
-
-
-
-
-
- Connect to GitHub
-
-
-
-
+
+ {#if !isVcsEnabled && isSelfHosted}
+
+
+
+ Before installing Git in a locally hosted Appwrite project, ensure your
+ environment variables are configured.
+
+
+ Learn more
+
+
+
+ {/if}
+
+
+
+
+
+ Connect to GitHub
+
+
+
+
+
diff --git a/src/routes/(console)/project-[project]/sites/(components)/deploymentCreatedBy.svelte b/src/lib/components/git/deploymentCreatedBy.svelte
similarity index 100%
rename from src/routes/(console)/project-[project]/sites/(components)/deploymentCreatedBy.svelte
rename to src/lib/components/git/deploymentCreatedBy.svelte
diff --git a/src/routes/(console)/project-[project]/sites/(components)/deploymentDomains.svelte b/src/lib/components/git/deploymentDomains.svelte
similarity index 98%
rename from src/routes/(console)/project-[project]/sites/(components)/deploymentDomains.svelte
rename to src/lib/components/git/deploymentDomains.svelte
index 164739bce..3bd231384 100644
--- a/src/routes/(console)/project-[project]/sites/(components)/deploymentDomains.svelte
+++ b/src/lib/components/git/deploymentDomains.svelte
@@ -10,7 +10,7 @@
- {#if domains.total}
+ {#if domains?.total}
diff --git a/src/routes/(console)/project-[project]/sites/(components)/deploymentSource.svelte b/src/lib/components/git/deploymentSource.svelte
similarity index 98%
rename from src/routes/(console)/project-[project]/sites/(components)/deploymentSource.svelte
rename to src/lib/components/git/deploymentSource.svelte
index 9dc2a901c..071b7c5e6 100644
--- a/src/routes/(console)/project-[project]/sites/(components)/deploymentSource.svelte
+++ b/src/lib/components/git/deploymentSource.svelte
@@ -16,7 +16,7 @@
{#if deployment.type === 'vcs'}
-
+
{
e.preventDefault();
@@ -26,7 +26,7 @@
GitHub
-
+
import { Button, InputSelect, InputText } from '$lib/elements/forms';
- import { Fieldset, Layout, Selector } from '@appwrite.io/pink-svelte';
- import SelectRootModal from '../../../routes/(console)/project-[project]/sites/(components)/selectRootModal.svelte';
+ import { Fieldset, Layout, Selector, Skeleton } from '@appwrite.io/pink-svelte';
+ import SelectRootModal from './selectRootModal.svelte';
+ import { sdk } from '$lib/stores/sdk';
+ import { sortBranches } from '$lib/stores/vcs';
export let branch: string;
export let rootDir: string;
- export let options: { value: string; label: string }[] = [];
export let silentMode: boolean;
+ export let installationId: string;
+ export let repositoryId: string;
let show = false;
+
+ async function loadBranches() {
+ const { branches } = await sdk.forProject.vcs.listRepositoryBranches(
+ installationId,
+ repositoryId
+ );
+ const sorted = sortBranches(branches);
+ branch = sorted[0]?.name ?? null;
+
+ if (!branch) {
+ branch = 'main';
+ }
+
+ return sorted;
+ }
-
- {
- branch = event.detail.value;
- }}
- {options} />
-
-
- (show = true)}>Select
+ {#await loadBranches()}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {:then branches}
+ {@const options =
+ branches
+ ?.map((branch) => {
+ return {
+ value: branch.name,
+ label: branch.name
+ };
+ })
+ ?.sort((a, b) => {
+ return a.label > b.label ? 1 : -1;
+ }) ?? []}
+
+ {
+ branch = event.detail.value;
+ }}
+ {options} />
+
+
+ (show = true)}>Select
+
-
-
+
+
+ {/await}
{#if show}
diff --git a/src/lib/components/git/repositories.svelte b/src/lib/components/git/repositories.svelte
index 993040b9c..a75ec80cd 100644
--- a/src/lib/components/git/repositories.svelte
+++ b/src/lib/components/git/repositories.svelte
@@ -1,9 +1,7 @@
@@ -145,79 +154,87 @@
{:then response}
{#if response?.length}
-
- {#each response as repo}
-
-
-
- {#if action === 'select'}
- repository.set(repo)}
- value={repo.id} />
- {/if}
- {#if product === 'sites'}
- {#await detectFramework(repo)}
-
- {:then framework}
-
-
-
- {/await}
- {:else}
-
- {/if}
-
-
- {repo.name}
-
- {#if repo.private}
-
+
+
+ {#each paginatedItems as repo}
+
+
+
+ {#if action === 'select'}
+ repository.set(repo)}
+ value={repo.id} />
{/if}
-
-
+
+
+ {:else}
+
+ {/if}
+ {:else}
+ {@const iconName = repo?.runtime
+ ? repo.runtime.split('-')[0]
+ : undefined}
+
+
+
+ {/if}
+
+
- {timeFromNow(repo.pushedAt)}
-
-
-
- {#if action === 'button'}
-
- dispatch('connect', repo)}>
- Connect
-
+ color="--fgcolor-neutral-secondary">
+ {repo.name}
+
+ {#if repo.private}
+
+ {/if}
+
+
+ {timeFromNow(repo.pushedAt)}
+
+
- {/if}
-
-
-
- {/each}
-
+ {#if action === 'button'}
+
+ dispatch('connect', repo)}>
+ Connect
+
+
+ {/if}
+
+
+
+ {/each}
+
+
{:else}
-
+
{#if search}
(search = '')}>
diff --git a/src/routes/(console)/project-[project]/sites/(components)/selectRootModal.svelte b/src/lib/components/git/selectRootModal.svelte
similarity index 82%
rename from src/routes/(console)/project-[project]/sites/(components)/selectRootModal.svelte
rename to src/lib/components/git/selectRootModal.svelte
index cf63bbc25..13b0f7c7f 100644
--- a/src/routes/(console)/project-[project]/sites/(components)/selectRootModal.svelte
+++ b/src/lib/components/git/selectRootModal.svelte
@@ -1,8 +1,10 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
-
-
diff --git a/src/lib/components/labelCard.svelte b/src/lib/components/labelCard.svelte
index 4995a2d12..b7c154791 100644
--- a/src/lib/components/labelCard.svelte
+++ b/src/lib/components/labelCard.svelte
@@ -6,7 +6,7 @@
type Props = ComponentProps;
export let group: string;
- export let value: string | number | boolean;
+ export let value: string;
export let tooltipText: string = null;
export let tooltipShow = false;
@@ -15,6 +15,7 @@
export let imageRadius: Props['imageRadius'] = 'xxs';
export let padding: Props['padding'] = 's';
export let variant: Props['variant'] = 'primary';
+ export let name: Props['name'] = undefined;
//temporarily unefined
export let title: Props['title'] = undefined;
export let disabled = false;
@@ -27,6 +28,7 @@
{#if $$slots.default}
-
-
-
+
{/if}
+
{tooltipText}
diff --git a/src/lib/components/limit.svelte b/src/lib/components/limit.svelte
index aa1d943a2..9c7c1d4ad 100644
--- a/src/lib/components/limit.svelte
+++ b/src/lib/components/limit.svelte
@@ -36,6 +36,6 @@
- {name} per page. Total results: {sum >= 5000 ? `${sum}+` : sum}
+ {name} per page. Total: {sum >= 5000 ? `${sum}+` : sum}
diff --git a/src/lib/components/menu/index.ts b/src/lib/components/menu/index.ts
new file mode 100644
index 000000000..1ba6002f9
--- /dev/null
+++ b/src/lib/components/menu/index.ts
@@ -0,0 +1,2 @@
+export { default as Menu } from './menu.svelte';
+export { default as SubMenu } from './subMenu.svelte';
diff --git a/src/lib/components/menu/menu.svelte b/src/lib/components/menu/menu.svelte
new file mode 100644
index 000000000..b381296bb
--- /dev/null
+++ b/src/lib/components/menu/menu.svelte
@@ -0,0 +1,54 @@
+
+
+
+
+
diff --git a/src/lib/components/menu/subMenu.svelte b/src/lib/components/menu/subMenu.svelte
new file mode 100644
index 000000000..ac52af18c
--- /dev/null
+++ b/src/lib/components/menu/subMenu.svelte
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/lib/components/mfaChallengeFormList.svelte b/src/lib/components/mfaChallengeFormList.svelte
index e04952d95..4b69eef35 100644
--- a/src/lib/components/mfaChallengeFormList.svelte
+++ b/src/lib/components/mfaChallengeFormList.svelte
@@ -10,10 +10,10 @@
}
await sdk.forConsole.account.updateMfaChallenge(challenge.$id, code);
await invalidate(Dependencies.ACCOUNT);
- trackEvent(Submit.AccountCreate);
+ trackEvent(Submit.AccountLogin, { mfa_used: true });
} catch (error) {
inputDigitFields?.clearInputsAndRefocus();
- trackError(error, Submit.AccountCreate);
+ trackError(error, Submit.AccountLogin);
throw error;
}
}
@@ -33,7 +33,6 @@
export let factors: Models.MfaFactors & { recoveryCode: boolean };
/** If true, the form will be submitted automatically when the code is entered. */
- export let autoSubmit: boolean = true;
export let showVerifyButton: boolean = true;
export let disabled: boolean = false;
export let challenge: Models.MfaChallenge;
diff --git a/src/lib/components/modal.svelte b/src/lib/components/modal.svelte
index ad51b11c8..9bd18b068 100644
--- a/src/lib/components/modal.svelte
+++ b/src/lib/components/modal.svelte
@@ -1,14 +1,12 @@
{#if [...$groups.keys()]?.length}
-
-
- Role
-
-
- {#each [...$groups.keys()].sort(sortRoles) as role}
-
-
-
-
-
-
- deleteRole(role)}>
-
-
-
-
-
- {/each}
-
-
-
-
- Add role
-
-
+
+
+
+ Role
+
+
+ {#each [...$groups.keys()].sort(sortRoles) as role}
+
+
+
+
+
+
+ deleteRole(role)}>
+
+
+
+
+
+ {/each}
+
+
+
+
+
+ Add role
+
+
+
+
{:else}
-
-
-
+
+
+
+
+
+
+
+ Add a role
+
+
{/if}
diff --git a/src/lib/components/permissions/row.svelte b/src/lib/components/permissions/row.svelte
index 631136098..9d28c0144 100644
--- a/src/lib/components/permissions/row.svelte
+++ b/src/lib/components/permissions/row.svelte
@@ -1,17 +1,24 @@
-
-
- {#if role === 'users'}
-
Users
- {:else if role === 'guests'}
-
Guests
- {:else if role === 'any'}
-
Any
- {:else}
-
{
- data = n;
- })
- .finally(() => {
- tick().then(() => {
- instance.setContent(content);
- });
- });
- }
- }}>
- {role}
-
-
-
- {#if data}
- {@const isUser = role.startsWith('user')}
- {@const isTeam = role.startsWith('team')}
- {@const isAnonymous = !data.email && !data.phone && isUser}
-
+{#if role === 'users'}
+
Users
+{:else if role === 'guests'}
+
Guests
+{:else if role === 'any'}
+
Any
+{:else}
+
+ {role}
+
+ {#key showing}
+ {#await getData(role)}
+
+
+
+ {:then data}
+ {@const isUser = role.startsWith('user')}
+ {@const isTeam = role.startsWith('team')}
+ {@const isAnonymous = !data.email && !data.phone && !data.name && isUser}
+
+
{#if isAnonymous}
-
-
-
+
+
+
{:else if data.name}
-
+
{:else}
-
-
-
+
+
+
{/if}
-
-
- {data.name ?? data?.email ?? data?.phone ?? '-'}
-
- {role}
-
- {#if (isUser && (data?.email || data?.phone)) || isTeam}
-
+
+ {data.name ?? data?.email ?? data?.phone ?? '-'}
+
+
-
-
- {#if isUser}
-
- {#if data?.email}
-
Email: {data?.email}
- {/if}
- {#if data?.phone}
-
Phone: {data?.phone}
- {/if}
-
- {:else if isTeam}
- Members: {data?.total}
- {/if}
-
+
+ {#if isUser}
+ {#if data?.email}
+ Email: {data?.email}
{/if}
-
- {:else}
- Not found.
- {/if}
-
-
- {/if}
-
-
-
-
-
+ {#if data?.phone}
+
Phone: {data?.phone}
+ {/if}
+
+
+ View user
+
+
+
+ {:else if isTeam}
+
Members: {data?.total}
+
+
+ View team
+
+
+
+ {/if}
+
+ {/await}
+ {/key}
+
+
+{/if}
diff --git a/src/lib/components/permissions/team.svelte b/src/lib/components/permissions/team.svelte
index b2efaf4d0..5a155d350 100644
--- a/src/lib/components/permissions/team.svelte
+++ b/src/lib/components/permissions/team.svelte
@@ -70,7 +70,7 @@
}
-
+
Grant access to any member of a specific team. To grant access to team members with
specific roles, you will need to set a dispatch('custom')}
@@ -93,23 +93,14 @@
- Text
+ {team.name}
- Secondary Text
+ {team.$id}
-
-
-
- {team.name}
-
-
- {team.$id}
-
-
{/each}
diff --git a/src/lib/components/permissions/user.svelte b/src/lib/components/permissions/user.svelte
index 12410e455..c31f58d9f 100644
--- a/src/lib/components/permissions/user.svelte
+++ b/src/lib/components/permissions/user.svelte
@@ -17,13 +17,7 @@
Table,
Typography
} from '@appwrite.io/pink-svelte';
- import {
- IconAnonymous,
- IconChartSquareBar,
- IconCheck,
- IconMinus,
- IconMinusSm
- } from '@appwrite.io/pink-icons-svelte';
+ import { IconAnonymous, IconMinusSm } from '@appwrite.io/pink-icons-svelte';
export let show: boolean;
export let groups: Writable>;
diff --git a/src/lib/components/progressBarBig.svelte b/src/lib/components/progressBarBig.svelte
index 01d47ed26..54ed44d8c 100644
--- a/src/lib/components/progressBarBig.svelte
+++ b/src/lib/components/progressBarBig.svelte
@@ -1,5 +1,6 @@
{#if $uploader?.isOpen}
- uploader.close()} />
+ {
+ return {
+ name: file.name,
+ size: file.size,
+ status: file.status
+ };
+ })}
+ on:close={() => uploader.close()} />
{/if}
diff --git a/src/lib/components/usageCard.svelte b/src/lib/components/usageCard.svelte
index 1fd9a03aa..e37fdf073 100644
--- a/src/lib/components/usageCard.svelte
+++ b/src/lib/components/usageCard.svelte
@@ -16,7 +16,7 @@
{value}
{:else}
-
+
{/if}
diff --git a/src/lib/components/viewSelector.svelte b/src/lib/components/viewSelector.svelte
index 7a4727d56..04afafc9b 100644
--- a/src/lib/components/viewSelector.svelte
+++ b/src/lib/components/viewSelector.svelte
@@ -23,7 +23,6 @@
export let hideView = false;
export let hideColumns = false;
export let allowNoColumns = false;
- export let fullWidthMobile = false;
onMount(async () => {
if (isCustomCollection) {
@@ -76,12 +75,14 @@
});
}
- $: selectedColumnsNumber = $columns.reduce((acc, column) => {
- if (column.show) {
- acc++;
- }
- return acc;
- }, 0);
+ $: selectedColumnsNumber = $columns
+ .filter((c) => !c.hide)
+ .reduce((acc, column) => {
+ if (column.show) {
+ acc++;
+ }
+ return acc;
+ }, 0);
{#if !hideColumns && view === View.Table}
@@ -97,7 +98,7 @@
- {#each $columns as column}
+ {#each $columns.filter((c) => !c.hide) as column}
@@ -43,6 +45,7 @@
- import { onMount } from 'svelte';
- import { Helper, Label } from '.';
- import NullCheckbox from './nullCheckbox.svelte';
+ import { Input } from '@appwrite.io/pink-svelte';
- export let label: string;
- export let showLabel = true;
- export let optionalText: string | undefined = undefined;
+ export let label: string = undefined;
export let id: string;
+ export let name: string = id;
+ export let helper: string = undefined;
export let value = '';
+ export let placeholder = '';
export let required = false;
export let nullable = false;
- export let min: string | number | undefined = undefined;
- export let max: string | number | undefined = undefined;
export let disabled = false;
export let readonly = false;
export let autofocus = false;
export let autocomplete = false;
- export let fullWidth = false;
+ export let step: number | 'any' = 0.001;
+ export let min: string = undefined;
+ export let max: string = undefined;
- let element: HTMLInputElement;
let error: string;
- onMount(() => {
- if (element && autofocus) {
- element.focus();
- }
- });
-
function handleInvalid(event: Event) {
event.preventDefault();
- if (element.validity.valueMissing) {
+ if (event.currentTarget.validity.valueMissing) {
error = 'This field is required';
return;
}
- error = element.validationMessage;
- }
-
- let prevValue = '';
- function handleNullChange(e: CustomEvent) {
- const isNull = e.detail;
- if (isNull) {
- prevValue = value;
- value = null;
- } else {
- value = prevValue;
- }
+ error = event.currentTarget.validationMessage;
}
$: if (value) {
error = null;
}
-
- $: isNullable = nullable && !required;
-
+
-
-
-
- {#if isNullable}
-
- {/if}
-
-{#if error}
- {error}
-{/if}
+ {step}
+ {nullable}
+ {readonly}
+ {min}
+ {max}
+ type="date"
+ autofocus={autofocus || undefined}
+ autocomplete={autocomplete ? 'on' : 'off'}
+ helper={error || helper}
+ state={error ? 'error' : 'default'}
+ on:invalid={handleInvalid}
+ on:input
+ bind:value>
+
+
+
+
diff --git a/src/lib/elements/forms/inputDigits.svelte b/src/lib/elements/forms/inputDigits.svelte
index 6895d82a4..f6e20f6cd 100644
--- a/src/lib/elements/forms/inputDigits.svelte
+++ b/src/lib/elements/forms/inputDigits.svelte
@@ -6,11 +6,6 @@
export let required = false;
export let disabled = false;
export let readonly = false;
- export let autofocus = false;
- export let fullWidth = false;
- export let autoSubmit = true;
-
- $: console.log(value);
-
+
diff --git a/src/lib/elements/forms/inputFilePicker.svelte b/src/lib/elements/forms/inputFilePicker.svelte
index db81cfae5..290728a03 100644
--- a/src/lib/elements/forms/inputFilePicker.svelte
+++ b/src/lib/elements/forms/inputFilePicker.svelte
@@ -4,6 +4,7 @@
import { humanFileSize } from '$lib/helpers/sizeConvertion';
import type { Models } from '@appwrite.io/console';
import { Label } from '.';
+ import { Upload } from '@appwrite.io/pink-svelte';
export let label: string = null;
export let value: Models.File = null;
diff --git a/src/lib/elements/forms/inputSelect.svelte b/src/lib/elements/forms/inputSelect.svelte
index 8c560bedc..a05d95452 100644
--- a/src/lib/elements/forms/inputSelect.svelte
+++ b/src/lib/elements/forms/inputSelect.svelte
@@ -58,4 +58,6 @@
on:invalid={handleInvalid}
on:input
on:change
- bind:value />
+ bind:value>
+
+
diff --git a/src/lib/elements/forms/inputSelectSearch.svelte b/src/lib/elements/forms/inputSelectSearch.svelte
index 260e7ac02..0ca641f95 100644
--- a/src/lib/elements/forms/inputSelectSearch.svelte
+++ b/src/lib/elements/forms/inputSelectSearch.svelte
@@ -144,15 +144,3 @@
{error}
{/if}
-->
-
-
diff --git a/src/lib/elements/forms/inputTime.svelte b/src/lib/elements/forms/inputTime.svelte
index e618918d1..6c6d9a8a5 100644
--- a/src/lib/elements/forms/inputTime.svelte
+++ b/src/lib/elements/forms/inputTime.svelte
@@ -1,39 +1,33 @@
-
+
-
-
-
-
-{#if error}
- {error}
-{/if}
+ {step}
+ {nullable}
+ {readonly}
+ {min}
+ {max}
+ type="time"
+ autofocus={autofocus || undefined}
+ autocomplete={autocomplete ? 'on' : 'off'}
+ helper={error || helper}
+ state={error ? 'error' : 'default'}
+ on:invalid={handleInvalid}
+ on:input
+ bind:value>
+
+
+
+
diff --git a/src/lib/elements/link.svelte b/src/lib/elements/link.svelte
index b5807ae58..6e75e98a5 100644
--- a/src/lib/elements/link.svelte
+++ b/src/lib/elements/link.svelte
@@ -13,6 +13,7 @@
export let variant: Props['variant'] = 'default';
export let size: Props['size'] = 'm';
export let external = false;
+ export let icon = false;
function track() {
if (!event) {
@@ -33,6 +34,7 @@
on:click={track}
{href}
{disabled}
+ {icon}
{variant}
{size}
target={external ? '_blank' : ''}
@@ -40,7 +42,7 @@
{:else}
-
+
{/if}
diff --git a/src/lib/elements/selectSearchCheckbox.svelte b/src/lib/elements/selectSearchCheckbox.svelte
index e54a4fd33..b7d854c88 100644
--- a/src/lib/elements/selectSearchCheckbox.svelte
+++ b/src/lib/elements/selectSearchCheckbox.svelte
@@ -3,7 +3,6 @@
import InputCheckbox from './forms/inputCheckbox.svelte';
export let value = false;
- export let padding: number | null = null;
diff --git a/src/lib/elements/table/body.svelte b/src/lib/elements/table/body.svelte
index eaca43a10..a3ac5fe78 100644
--- a/src/lib/elements/table/body.svelte
+++ b/src/lib/elements/table/body.svelte
@@ -1,6 +1,6 @@
diff --git a/src/lib/layout/containerButton.svelte b/src/lib/layout/containerButton.svelte
index 05047bdde..6d081807d 100644
--- a/src/lib/layout/containerButton.svelte
+++ b/src/lib/layout/containerButton.svelte
@@ -14,9 +14,10 @@
} plan`;
export let disabled: boolean;
export let buttonText: string;
- export let buttonMethod: () => void | Promise;
+ export let buttonMethod: () => void | Promise = () => {};
export let buttonHref: string = null;
export let buttonEvent: string = buttonText?.toLocaleLowerCase();
+ export let buttonEventData: Record = {};
export let icon = 'plus';
export let showIcon = true;
export let buttonType: 'primary' | 'secondary' | 'text' = 'primary';
@@ -29,6 +30,7 @@
secondary={buttonType === 'secondary'}
on:click={buttonMethod}
event={buttonEvent}
+ eventData={buttonEventData}
{disabled}
href={buttonHref}>
{#if showIcon}
diff --git a/src/lib/layout/containerHeader.svelte b/src/lib/layout/containerHeader.svelte
index 7294e8550..7a6a58976 100644
--- a/src/lib/layout/containerHeader.svelte
+++ b/src/lib/layout/containerHeader.svelte
@@ -29,6 +29,7 @@
export let buttonMethod: () => void = null;
export let buttonHref: string = null;
export let buttonEvent: string = buttonText?.toLocaleLowerCase();
+ export let buttonEventData: Record = {};
export let buttonDisabled = false;
let showDropdown = false;
@@ -172,6 +173,7 @@
disabled={isButtonDisabled}
{buttonText}
{buttonEvent}
+ {buttonEventData}
{buttonMethod}
{buttonHref} />
{/if}
diff --git a/src/lib/layout/createProject.svelte b/src/lib/layout/createProject.svelte
new file mode 100644
index 000000000..8e5eeb0cb
--- /dev/null
+++ b/src/lib/layout/createProject.svelte
@@ -0,0 +1,89 @@
+
+
+
+ {#each regions as region}
+
+ {/each}
+
+
diff --git a/src/lib/layout/header.svelte b/src/lib/layout/header.svelte
index deeb75a5d..2c528951b 100644
--- a/src/lib/layout/header.svelte
+++ b/src/lib/layout/header.svelte
@@ -6,7 +6,7 @@
import { user } from '$lib/stores/user';
import { organizationList, organization, newOrgModal } from '$lib/stores/organization';
import { page } from '$app/stores';
- import { trackEvent } from '$lib/actions/analytics';
+ import { Click, trackEvent } from '$lib/actions/analytics';
import { tooltip } from '$lib/actions/tooltip';
import { toggleCommandCenter } from '$lib/commandCenter/commandCenter.svelte';
import Button from '$lib/elements/forms/button.svelte';
@@ -30,6 +30,7 @@
function toggleFeedback() {
feedback.toggleFeedback();
+ trackEvent(Click.FeedbackSubmitClick);
if ($feedback.notification) {
feedback.toggleNotification();
feedback.addVisualization();
@@ -53,7 +54,7 @@
}
$: if (showDropdown) {
- trackEvent('click_menu_dropdown');
+ trackEvent(Click.MenuDropDownClick);
}
const slideFade: typeof slide = (node, options) => {
@@ -97,7 +98,7 @@
disabled={$organization?.markedForDeletion}
href={$upgradeURL}
on:click={() => {
- trackEvent('click_organization_upgrade', {
+ trackEvent(Click.OrganizationClickUpgrade, {
from: 'button',
source: 'top_nav'
});
diff --git a/src/lib/layout/headerAlert.svelte b/src/lib/layout/headerAlert.svelte
index 44d15f046..4e26306c9 100644
--- a/src/lib/layout/headerAlert.svelte
+++ b/src/lib/layout/headerAlert.svelte
@@ -1,9 +1,37 @@
+
.alert {
padding: 1rem 1rem 0.75rem 1.5rem;
- margin-block-start: 18px;
+ position: fixed;
+ top: 0;
+ width: 100%;
+ z-index: 100;
}
.alert-content {
diff --git a/src/lib/layout/logs.svelte b/src/lib/layout/logs.svelte
index 4246c8f98..7927f8aa8 100644
--- a/src/lib/layout/logs.svelte
+++ b/src/lib/layout/logs.svelte
@@ -3,14 +3,6 @@
import { log } from '$lib/stores/logs';
import { Alert, Card, Code, Copy, Id, SvgIcon, Tab, Tabs } from '../components';
import { calculateTime } from '$lib/helpers/timeConversion';
- import {
- TableBody,
- TableCellHead,
- TableCellText,
- TableHeader,
- TableRow,
- TableScroll
- } from '$lib/elements/table';
import { beforeNavigate } from '$app/navigation';
import { Pill } from '$lib/elements';
import { isCloud } from '$lib/system';
@@ -18,7 +10,7 @@
import { organization } from '$lib/stores/organization';
import { Button } from '$lib/elements/forms';
import { BillingPlan } from '$lib/constants';
- import { Tooltip, Typography } from '@appwrite.io/pink-svelte';
+ import { Table, Tooltip, Typography } from '@appwrite.io/pink-svelte';
let selectedRequest = 'parameters';
let selectedResponse = 'logs';
@@ -223,26 +215,22 @@
{#if selectedRequest === 'parameters'}
{#if parameters?.length}
-
-
-
- Name
- Value
-
-
- {#each parameters as param}
-
-
- {param.key}
-
-
- {param.value}
-
-
- {/each}
-
-
-
+
+
+ Name
+ Value
+
+ {#each parameters as param}
+
+
+ {param.key}
+
+
+ {param.value}
+
+
+ {/each}
+
{/if}
@@ -261,26 +249,22 @@
{:else if selectedRequest === 'headers'}
{#if execution.requestHeaders.length}
-
-
-
- Name
- Value
-
-
- {#each execution.requestHeaders as header}
-
-
- {header.name}
-
-
- {header.value}
-
-
- {/each}
-
-
-
+
+
+ Name
+ Value
+
+ {#each execution.requestHeaders as header}
+
+
+ {header.key}
+
+
+ {header.value}
+
+
+ {/each}
+
{/if}
@@ -379,23 +363,22 @@
{/if}
{:else if selectedResponse === 'headers'}
{#if execution.responseHeaders.length}
-
-
- Name
- Value
-
-
- {#each execution.responseHeaders as header}
-
-
- {header.name}
-
- {header.value}
-
- {/each}
-
-
+
+
+ Name
+ Value
+
+ {#each execution.responseHeaders as header}
+
+
+ {header.key}
+
+
+ {header.value}
+
+
+ {/each}
+
{/if}
{execution.responseHeaders?.length
diff --git a/src/lib/layout/shell.svelte b/src/lib/layout/shell.svelte
index 110919e28..0edd5e688 100644
--- a/src/lib/layout/shell.svelte
+++ b/src/lib/layout/shell.svelte
@@ -134,7 +134,11 @@
+{#if $activeHeaderAlert?.show}
+
+{/if}
- {#if $activeHeaderAlert?.show}
-
- {/if}
{#if $page.data?.header}
{/if}
@@ -247,4 +248,14 @@
grid-template-columns: auto 1fr !important;
}
}
+ //
+ //:global(main.has-alert > header) {
+ // top: 70px;
+ //}
+ //:global(main.has-alert > div nav) {
+ // @media (min-width: 1024px) {
+ // top: calc(48px + 70px) !important;
+ // height: calc(100vh - (48px + 70px)) !important;
+ // }
+ //}
diff --git a/src/lib/layout/unauthenticated.svelte b/src/lib/layout/unauthenticated.svelte
index ba694c3d9..5497d4991 100644
--- a/src/lib/layout/unauthenticated.svelte
+++ b/src/lib/layout/unauthenticated.svelte
@@ -270,7 +270,7 @@
}
.tag-line {
- font-family: 'Aeonik Pro';
+ font-family: 'Aeonik Pro', 'Inter', sans-serif;
font-size: 4rem;
font-style: normal;
font-weight: 400;
diff --git a/src/lib/layout/usage.svelte b/src/lib/layout/usage.svelte
index 71d376898..3077d1f74 100644
--- a/src/lib/layout/usage.svelte
+++ b/src/lib/layout/usage.svelte
@@ -78,32 +78,35 @@
export let count: Models.Metric[];
export let countMetadata: MetricMetadata;
export let path: string = null;
+ export let hidePeriodSelect = false;
-
- goto(`${path}/${e.detail}`)}
- id="period"
- options={[
- {
- label: '24 hours',
- value: '24h'
- },
- {
- label: '30 days',
- value: '30d'
- },
- {
- label: '90 days',
- value: '90d'
- }
- ]}
- value={$page.params.period ?? '30d'} />
-
+ {#if !hidePeriodSelect}
+
+ goto(`${path}/${e.detail}`)}
+ id="period"
+ options={[
+ {
+ label: '24 hours',
+ value: '24h'
+ },
+ {
+ label: '30 days',
+ value: '30d'
+ },
+ {
+ label: '90 days',
+ value: '90d'
+ }
+ ]}
+ value={$page.params.period ?? '30d'} />
+
+ {/if}
{#if count}
diff --git a/src/lib/layout/wizard.svelte b/src/lib/layout/wizard.svelte
index 850b882ed..4e5e49078 100644
--- a/src/lib/layout/wizard.svelte
+++ b/src/lib/layout/wizard.svelte
@@ -14,7 +14,7 @@
invertColumns?: boolean;
hideFooter?: boolean;
column?: boolean;
- columnSize?: 's' | 'm';
+ columnSize?: 's' | 'm' | 'l';
onExit?: () => void;
}
| {
@@ -25,7 +25,7 @@
invertColumns?: boolean;
hideFooter?: boolean;
column?: boolean;
- columnSize?: 's' | 'm';
+ columnSize?: 's' | 'm' | 'l';
onExit?: () => void;
};
diff --git a/src/lib/pages/domains/wizard/step1.svelte b/src/lib/pages/domains/wizard/step1.svelte
index 5a7150194..0e8750d15 100644
--- a/src/lib/pages/domains/wizard/step1.svelte
+++ b/src/lib/pages/domains/wizard/step1.svelte
@@ -1,6 +1,5 @@
-
-{#if hasInstallations}
- {#await loadInstallations()}
-
- {:then installations}
-
- {
- return {
- label: entry.organization,
- value: entry.$id
- };
- })}
- on:change={() => {
- search = '';
- installation.set(
- installations.find((entry) => entry.$id === selectedInstallation)
- );
- }}
- bind:value={selectedInstallation} />
-
-
- {/await}
-
- Manage organization configuration in your project settings .
-
- {#if selectedInstallation}
- {#await loadRepositories(selectedInstallation, search)}
-
- {:then response}
- {#if response?.length}
-
- {#each response as repo, i}
-
-
-
- {#if action === 'select'}
-
repository.set(repo)}
- value={repo.id} />
- {/if}
-
- {#if repo.runtime}
-
- {/if}
-
-
- {repo.name}
- {#if repo.private}
-
- {/if}
-
- {timeFromNow(repo.pushedAt)}
-
-
- {#if action === 'button'}
-
- dispatch('connect', repo)}>
- Connect
-
-
- {/if}
-
-
-
- {/each}
-
- {:else if search}
-
-
-
-
Sorry we couldn't find "{search}"
-
There are no repositories that match your search.
-
-
- (search = '')}>Clear search
-
-
-
- {:else}
-
- {/if}
- {/await}
- {/if}
-{:else}
-
-
-
- GitHub
-
-
-
- GitLab (coming soon)
-
-
-
- BitBucket (coming soon)
-
-
-
- Azure (coming soon)
-
-
-{/if}
-
-
diff --git a/src/lib/wizards/functions/components/specificationsTooltip.svelte b/src/lib/wizards/functions/components/specificationsTooltip.svelte
deleted file mode 100644
index 279f5a0f1..000000000
--- a/src/lib/wizards/functions/components/specificationsTooltip.svelte
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
Additional CPU and RAM are available for Pro and Scale teams.
-
-
-
-
diff --git a/src/lib/wizards/functions/connectExisting.svelte b/src/lib/wizards/functions/connectExisting.svelte
deleted file mode 100644
index a619870d2..000000000
--- a/src/lib/wizards/functions/connectExisting.svelte
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
diff --git a/src/lib/wizards/functions/cover.svelte b/src/lib/wizards/functions/cover.svelte
deleted file mode 100644
index d31eaae83..000000000
--- a/src/lib/wizards/functions/cover.svelte
+++ /dev/null
@@ -1,317 +0,0 @@
-
-
-
-
-
- Create function
-
-
-
-
-
Connect Git repository
-
- Create and deploy a function with a connected git repository.
-
-
-
-
- {#if isSelfHosted && !isVcsEnabled}
-
-
-
- Connect your self-hosted instance to Git
-
-
- Configure your self-hosted instance to connect your function to
- a Git repository.
- Learn more .
-
-
-
- {/if}
-
-
-
-
- Quick start
- Use a starter template.
-
- {#await Promise.all([$baseRuntimesList, $starterTemplate])}
- {#each Array(6) as _i}
-
-
-
-
-
- {/each}
- {:then [response, quickStart]}
- {@const runtimes = new Map(
- response.runtimes.map((r) => [r.$id, r])
- )}
- {@const templates = quickStart.runtimes.filter((template) =>
- runtimes.has(template.name)
- )}
- {#each templates.slice(0, 6) as template}
- {@const runtimeDetail = runtimes.get(template.name)}
-
- {
- trackEvent('click_connect_template', {
- from: 'cover',
- template: quickStart.id,
- runtime: template.name
- });
- }}
- on:click={() =>
- connectTemplate(quickStart, template.name)}
- class="box u-width-full-line u-flex u-cross-center u-gap-8"
- style:--box-padding="1rem"
- style:--box-border-radius="var(--border-radius-small)">
-
-
-
-
- {runtimeDetail.name}
- {#if runtimeDetail.name.toLowerCase() === 'deno'}
- New
- {/if}
-
-
-
- {/each}
-
- {#if templates.length < 6}
-
-
-
-
-
-
- More runtimes coming soon
-
- {/if}
- {/await}
-
-
-
-
- All starter templates
-
-
-
- Templates
-
- Find the right template for your use case.
-
-
-
- {#await $featuredTemplatesList}
- {#each Array(3) as _i}
-
-
-
-
-
-
- {/each}
- {:then templatesListWithoutStarter}
- {#each templatesListWithoutStarter.templates as template}
-
- {
- trackEvent('click_connect_template', {
- from: 'cover',
- template: template.id
- });
- }}
- on:click={() => connectTemplate(template)}
- class="clickable-list-button u-width-full-line u-flex u-gap-12">
-
-
-
-
-
- {template.name}
-
-
- {template.tagline}
-
-
-
-
- {/each}
- {/await}
-
-
-
- All templates
-
-
-
-
-
- You can also create a function {
- trackEvent('click_create_function_manual', {
- from: 'cover'
- });
- }}
- on:click={() => wizard.start(CreateManual)}>manually
- or using the CLI.
- Learn more .
-
-
-
-
-
-
diff --git a/src/lib/wizards/functions/createGit.svelte b/src/lib/wizards/functions/createGit.svelte
deleted file mode 100644
index 751487c0e..000000000
--- a/src/lib/wizards/functions/createGit.svelte
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
-
diff --git a/src/lib/wizards/functions/createManual.svelte b/src/lib/wizards/functions/createManual.svelte
deleted file mode 100644
index 586b580c6..000000000
--- a/src/lib/wizards/functions/createManual.svelte
+++ /dev/null
@@ -1,109 +0,0 @@
-
-
-
diff --git a/src/lib/wizards/functions/createTemplate.svelte b/src/lib/wizards/functions/createTemplate.svelte
deleted file mode 100644
index ae703bc45..000000000
--- a/src/lib/wizards/functions/createTemplate.svelte
+++ /dev/null
@@ -1,128 +0,0 @@
-
-
-
diff --git a/src/lib/wizards/functions/steps/createRepository.svelte b/src/lib/wizards/functions/steps/createRepository.svelte
deleted file mode 100644
index aecb74761..000000000
--- a/src/lib/wizards/functions/steps/createRepository.svelte
+++ /dev/null
@@ -1,179 +0,0 @@
-
-
-
- Repository
-
- Select a Git repository that will trigger your function deployments when updated.
-
-
- {#if $templateConfig.repositoryBehaviour === 'existing'}
-
- {:else}
- {#await loadInstallations()}
-
- {:then installations}
- {#if hasInstallations}
-
- {
- return {
- label: entry.organization,
- value: entry.$id
- };
- })}
- on:change={() => {
- $installation = installations.find(
- (entry) => entry.$id === selectedInstallationId
- );
- }}
- bind:value={selectedInstallationId} />
-
- {:else}
-
-
-
- GitHub
-
-
-
- GitLab (coming soon)
-
-
-
- BitBucket (coming soon)
-
-
-
- Azure (coming soon)
-
-
- {/if}
- {#if $installation}
-
-
-
-
-
-
-
- {$installation.organization}/{$templateConfig.repositoryName}
-
-
-
-
-
-
-
-
-
-
- {/if}
- {/await}
- {/if}
-
diff --git a/src/lib/wizards/functions/steps/executeAccess.svelte b/src/lib/wizards/functions/steps/executeAccess.svelte
deleted file mode 100644
index 64f2ec6d9..000000000
--- a/src/lib/wizards/functions/steps/executeAccess.svelte
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
- Permissions
-
- Choose who can execute this function using the client API. For more information, visit our
-
- Permissions guide .
-
-
-
-
diff --git a/src/lib/wizards/functions/steps/functionConfiguration.svelte b/src/lib/wizards/functions/steps/functionConfiguration.svelte
deleted file mode 100644
index cafa196af..000000000
--- a/src/lib/wizards/functions/steps/functionConfiguration.svelte
+++ /dev/null
@@ -1,120 +0,0 @@
-
-
-
- Configuration
-
- Set your deployment configuration and any build commands here.
-
-
-
- {#if !showCustomId}
-
-
(showCustomId = !showCustomId)}>
-
- Function ID
-
-
- {:else}
-
- {/if}
-
- {#if detectingRuntime}
-
- {:else}
-
- {/if}
-
-
-
-
- Build commands
- (optional)
-
-
-
-
-
-
-
diff --git a/src/lib/wizards/functions/steps/gitConfiguration.svelte b/src/lib/wizards/functions/steps/gitConfiguration.svelte
deleted file mode 100644
index 8788b50cc..000000000
--- a/src/lib/wizards/functions/steps/gitConfiguration.svelte
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-
- Branch
-
- Choose the Git branch that will trigger your function deployments when updated.
-
-
-
-
-
-
{$installation.organization}/{$repository.name}
-
- {#await loadBranches()}
-
- {:then branches}
- {@const options =
- branches
- ?.map((branch) => {
- return {
- value: branch.name,
- label: branch.name
- };
- })
- ?.sort((a, b) => {
- return a.label > b.label ? 1 : -1;
- }) ?? []}
-
-
- {
- $choices.branch = event.detail.value;
- }}
- interactiveOutput
- name="branches"
- {options} />
-
-
-
-
- {/await}
-
-
- Visit your repository on GitHub .
-
-
diff --git a/src/lib/wizards/functions/steps/manualConfiguration.svelte b/src/lib/wizards/functions/steps/manualConfiguration.svelte
deleted file mode 100644
index 11e86decb..000000000
--- a/src/lib/wizards/functions/steps/manualConfiguration.svelte
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
- Configuration
-
- Set your deployment configuration and any build commands here.
-
-
-
-
-
-
-
- Build commands
- (optional)
-
-
-
-
-
-
-
diff --git a/src/lib/wizards/functions/steps/manualDetails.svelte b/src/lib/wizards/functions/steps/manualDetails.svelte
deleted file mode 100644
index 9167474d0..000000000
--- a/src/lib/wizards/functions/steps/manualDetails.svelte
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
-
- Details
- Create and deploy your function manually.
-
-
-
-
-
-
-
- {#if !showCustomId}
-
-
(showCustomId = !showCustomId)}>
-
- Function ID
-
-
- {:else}
-
- {/if}
-
-
diff --git a/src/lib/wizards/functions/steps/selectRepository.svelte b/src/lib/wizards/functions/steps/selectRepository.svelte
deleted file mode 100644
index 8ae8a1b14..000000000
--- a/src/lib/wizards/functions/steps/selectRepository.svelte
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
- Repository
-
- Select a Git repository that will trigger your function deployments when updated.
-
-
-
diff --git a/src/lib/wizards/functions/steps/templateConfiguration.svelte b/src/lib/wizards/functions/steps/templateConfiguration.svelte
deleted file mode 100644
index 190e338e0..000000000
--- a/src/lib/wizards/functions/steps/templateConfiguration.svelte
+++ /dev/null
@@ -1,128 +0,0 @@
-
-
-
- {$template.name}
-
- {$template.tagline}
-
-
-
- {#await loadRuntimes()}
-
- {:then options}
-
- {/await}
- {#await loadSpecifications()}
-
- {:then specificationOptions}
-
- {/await}
-
- {#if !showCustomId}
-
-
(showCustomId = !showCustomId)}>
-
- Function ID
-
-
- {:else}
-
- {/if}
-
-
diff --git a/src/lib/wizards/functions/steps/templateDeployment.svelte b/src/lib/wizards/functions/steps/templateDeployment.svelte
deleted file mode 100644
index 524ce1272..000000000
--- a/src/lib/wizards/functions/steps/templateDeployment.svelte
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
- Deployment
-
-
- Connect with Git Recommended
-
- Create a new repository
- Clone the template to a newly created repository in your organization.
-
-
- Add to existing repository
- Clone the template to an existing repository in your organization.
-
-
- Quick start
-
- Connect later
- Deploy now and continue development via CLI, or connect Git from your function settings.
-
-
-
diff --git a/src/lib/wizards/functions/steps/templatePermissions.svelte b/src/lib/wizards/functions/steps/templatePermissions.svelte
deleted file mode 100644
index 42a4474f1..000000000
--- a/src/lib/wizards/functions/steps/templatePermissions.svelte
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
- Permissions
-
- Enable recommended scopes and execute access for when your function is deployed.
-
- Execute permissions
-
-
-
-
-
-
-
-
- Public (anyone can execute) You can further customize execute permissions in your function
- settings.
-
-
- This could include unauthorized users and bots.
-
-
-
-
-
-
-
- {#if templateScopes.length > 0}
- Function scopes
-
- {#each templateScopes as scope, i}
-
-
-
-
-
-
-
{scope.scope}
-
{scope.description}
-
-
-
-
-
- {#if i < templateScopes.length - 1}
-
- {/if}
- {/each}
-
- {/if}
-
diff --git a/src/lib/wizards/functions/steps/templateVariables.svelte b/src/lib/wizards/functions/steps/templateVariables.svelte
deleted file mode 100644
index c7db15bd4..000000000
--- a/src/lib/wizards/functions/steps/templateVariables.svelte
+++ /dev/null
@@ -1,124 +0,0 @@
-
-
-
- Variables
-
- Edit the values of the environment variables that will be passed to your function at
- runtime.
-
- {#if $template?.variables?.length}
- {#if requiredVariables?.length}
-
-
- Required variables
-
- {requiredVariables.length}
-
-
-
- {#each requiredVariables as variable}
-
-
-
- {@html variable.description}
-
-
- {/each}
-
-
-
- {/if}
-
- {#if optionalVariables?.length}
-
-
- Optional variables
-
- {optionalVariables.length}
-
-
-
- {#each optionalVariables as variable}
-
-
-
-
- {@html variable.description}
-
-
- {/each}
-
-
-
- {/if}
- {:else}
-
- There are no environment variables to configure.
-
- {/if}
-
diff --git a/src/lib/wizards/functions/store.ts b/src/lib/wizards/functions/store.ts
deleted file mode 100644
index 6613438a2..000000000
--- a/src/lib/wizards/functions/store.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import { page } from '$app/stores';
-import type { WizardStepsType } from '$lib/layout/wizardWithSteps.svelte';
-import type { Models } from '@appwrite.io/console';
-import { derived, writable, type Writable } from 'svelte/store';
-
-export const template = writable();
-export const templateConfig = writable<{
- $id: string;
- name: string;
- runtime: string;
- variables: { [key: string]: unknown };
- repositoryBehaviour: 'new' | 'existing' | 'manual';
- repositoryName?: string;
- repositoryPrivate?: boolean;
- repositoryId: string;
- execute?: boolean;
- scopes?: string[];
- specification?: string;
-}>();
-export const repository = writable();
-export const installation = writable();
-export const choices = writable<{
- branch: string;
- rootDir: string;
- silentMode: boolean;
-}>({
- branch: null,
- rootDir: null,
- silentMode: null
-});
-
-export const installations = derived(
- page,
- ($page) => $page.data.installations as Models.InstallationList
-);
-
-const initialCreateFunction: Partial = {
- $id: null,
- name: null,
- entrypoint: null,
- execute: [],
- runtime: null,
- commands: null
-};
-
-function createFunctionStore() {
- const store = writable>({
- ...initialCreateFunction
- });
-
- const reset = () => {
- store.set({ ...initialCreateFunction });
- };
-
- return {
- ...store,
- reset
- };
-}
-export const createFunction = createFunctionStore();
-
-export const createFunctionDeployment = writable();
-
-export const templateStepsComponents: Writable = writable(new Map());
diff --git a/src/routes/(console)/+layout.ts b/src/routes/(console)/+layout.ts
index d4d311286..447f41d90 100644
--- a/src/routes/(console)/+layout.ts
+++ b/src/routes/(console)/+layout.ts
@@ -34,7 +34,9 @@ export const load: LayoutLoad = async ({ params, fetch, depends, parent }) => {
}, new Map());
}
- const organizations = await sdk.forConsole.teams.list();
+ const organizations = !isCloud
+ ? await sdk.forConsole.teams.list()
+ : await sdk.forConsole.billing.listOrganization();
let projects = [];
let currentOrgId = params.organization ? params.organization : prefs.organization;
diff --git a/src/routes/(console)/account/organizations/+page.ts b/src/routes/(console)/account/organizations/+page.ts
index 0b89b1d30..c1734a28c 100644
--- a/src/routes/(console)/account/organizations/+page.ts
+++ b/src/routes/(console)/account/organizations/+page.ts
@@ -3,19 +3,22 @@ import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { CARD_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
+import { isCloud } from '$lib/system';
export const load: PageLoad = async ({ url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, CARD_LIMIT);
const offset = pageToOffset(page, limit);
+ const queries = [Query.offset(offset), Query.limit(limit), Query.orderDesc('')];
+
+ const organizations = !isCloud
+ ? await sdk.forConsole.teams.list(queries)
+ : await sdk.forConsole.billing.listOrganization(queries);
+
return {
offset,
limit,
- organizations: await sdk.forConsole.teams.list([
- Query.offset(offset),
- Query.limit(limit),
- Query.orderDesc('')
- ])
+ organizations
};
};
diff --git a/src/routes/(console)/account/payments/+page.svelte b/src/routes/(console)/account/payments/+page.svelte
index 8eb25c9e2..c46855761 100644
--- a/src/routes/(console)/account/payments/+page.svelte
+++ b/src/routes/(console)/account/payments/+page.svelte
@@ -19,9 +19,7 @@
-
- Payment details
-
+ Payment details
diff --git a/src/routes/(console)/account/payments/billingAddress.svelte b/src/routes/(console)/account/payments/billingAddress.svelte
index a5617e7a7..d3129ce7c 100644
--- a/src/routes/(console)/account/payments/billingAddress.svelte
+++ b/src/routes/(console)/account/payments/billingAddress.svelte
@@ -1,14 +1,6 @@
- Billing Address
+ Billing address
View or update your billing address. This address will be included in your invoices from Appwrite.
{#if $addressList.total && countryList?.total}
-
-
- Billing address
-
-
-
-
- {#each $addressList.billingAddresses as address, i}
- {@const country = countryList?.countries?.find(
- (c) => c.code === address.country
- )}
- {@const linkedOrgs = orgList?.filter(
- (org) => address.$id === org.billingAddressId
- )}
+
+ {#each $addressList.billingAddresses as address}
+ {@const country = countryList?.countries?.find(
+ (c) => c.code === address.country
+ )}
+ {@const linkedOrgs = orgList?.filter(
+ (org) => address.$id === org.billingAddressId
+ )}
-
-
-
-
{address.streetAddress}
- {#if address?.addressLine2}
-
{address.addressLine2}
- {/if}
-
{address.city}
-
{address.state}
-
{address.postalCode}
-
{country ? country.name : address.country}
-
-
-
- {#if linkedOrgs?.length > 0}
-
- (showLinked[i] = !showLinked[i])}>
- linked to organization
-
-
-
+
+
+ {address.streetAddress},
+ {#if address?.addressLine2}
+ {address.addressLine2},
+ {/if}
+ {address.city},
+ {#if address?.state}
+ {address.state},
+ {/if}
+ {#if address?.postalCode}
+ {address.postalCode},
+ {/if}
+ {country ? country.name : address.country}
+
+
+ {#if linkedOrgs?.length > 0}
+
+
+
+ linked to organization
+
+
+
+
This billing address is linked to the following
organizations:
-
-
-
-
- {/if}
-
-
-
- {
- showDropdown[i] = !showDropdown[i];
- }}>
-
-
-
- {
- showEdit = true;
- selectedAddress = address;
- showDropdown[i] = false;
- }}>
- Edit
-
- {
- showDelete = true;
- selectedAddress = address;
- selectedLinkedOrgs = linkedOrgs;
- showDropdown[i] = false;
- }}>
- Delete
-
+
+
-
-
-
- {/each}
-
-
+
+ {/if}
+
+
+
+
+
+
+
+ {
+ showEdit = true;
+ selectedAddress = address;
+ }}>
+ Edit
+
+ {
+ showDelete = true;
+ selectedAddress = address;
+ selectedLinkedOrgs = linkedOrgs;
+ }}>
+ Delete
+
+
+
+
+
+ {/each}
+
- (show = true)}>
-
- Add a billing address
-
+
+ (show = true)}>
+
+ Add a billing address
+
+
{:else}
(show = true)}>
Add a billing address
diff --git a/src/routes/(console)/account/payments/deleteAddressModal.svelte b/src/routes/(console)/account/payments/deleteAddressModal.svelte
index a25cf15c7..059beab3c 100644
--- a/src/routes/(console)/account/payments/deleteAddressModal.svelte
+++ b/src/routes/(console)/account/payments/deleteAddressModal.svelte
@@ -8,6 +8,7 @@
import { addNotification } from '$lib/stores/notifications';
import type { Organization } from '$lib/stores/organization';
import { sdk } from '$lib/stores/sdk';
+ import { Layout, Link } from '@appwrite.io/pink-svelte';
export let showDelete = false;
export let selectedAddress: Address;
@@ -48,13 +49,13 @@
This billing address is set as the default for the following organisations. As they have
upcoming invoices it cannot be deleted from your account.
-
+
{#each linkedOrgs as org}
-
- {org.name}
-
+
+ {org.name}
+
{/each}
-
+
{:else}
Are you sure you want to delete this billing address from your account?
{/if}
diff --git a/src/routes/(console)/account/payments/deletePaymentModal.svelte b/src/routes/(console)/account/payments/deletePaymentModal.svelte
index 9e5b43498..63efeca25 100644
--- a/src/routes/(console)/account/payments/deletePaymentModal.svelte
+++ b/src/routes/(console)/account/payments/deletePaymentModal.svelte
@@ -9,6 +9,7 @@
import { addNotification } from '$lib/stores/notifications';
import type { Organization } from '$lib/stores/organization';
import { sdk } from '$lib/stores/sdk';
+ import { Layout, Link, Typography } from '@appwrite.io/pink-svelte';
export let linkedOrgs: Organization[] = [];
export let showDelete = false;
@@ -40,23 +41,23 @@
bind:open={showDelete}
bind:error>
{#if linkedOrgs.length === 1}
-
+
This payment method is set as the default for the {linkedOrgs[0].name} . As it has upcoming invoices it cannot be deleted from your account.
-
+
{:else if linkedOrgs.length > 1}
-
+
This payment method is set as the default for the following organisations. As they have
upcoming invoices it cannot be deleted from your account.
-
-
+
+
{#each linkedOrgs as org}
-
- {org.name}
-
+
+ {org.name}
+
{/each}
-
+
{:else}
Are you sure you want to delete this payment method from your account?
{/if}
diff --git a/src/routes/(console)/account/payments/editAddressModal.svelte b/src/routes/(console)/account/payments/editAddressModal.svelte
index a70f9d8e7..74938b4af 100644
--- a/src/routes/(console)/account/payments/editAddressModal.svelte
+++ b/src/routes/(console)/account/payments/editAddressModal.svelte
@@ -51,10 +51,10 @@
type: 'success',
message: `Address has been added`
});
- trackEvent(Submit.BillingAddressCreate);
+ trackEvent(Submit.BillingAddressUpdate);
} catch (e) {
error = e.message;
- trackError(e, Submit.BillingAddressCreate);
+ trackError(e, Submit.BillingAddressUpdate);
}
}
diff --git a/src/routes/(console)/account/payments/editPaymentModal.svelte b/src/routes/(console)/account/payments/editPaymentModal.svelte
index bcd68d08c..c054ec557 100644
--- a/src/routes/(console)/account/payments/editPaymentModal.svelte
+++ b/src/routes/(console)/account/payments/editPaymentModal.svelte
@@ -1,5 +1,5 @@
Create organization - Appwrite
-
- Create organization
-
-
-
- {#if billingPlan !== BillingPlan.FREE}
-
- {:else}
-
- {/if}
-
-
-
-
+
+
+
+ {#if selectedPlan !== BillingPlan.FREE}
+
+ {:else}
+
+ {/if}
+
+
(showExitModal = true)}>Cancel
Create organization
-
-
+
+
-
+
diff --git a/src/routes/(console)/create-organization/+page.ts b/src/routes/(console)/create-organization/+page.ts
new file mode 100644
index 000000000..6c3cfe2f0
--- /dev/null
+++ b/src/routes/(console)/create-organization/+page.ts
@@ -0,0 +1,50 @@
+import { BillingPlan } from '$lib/constants';
+import { sdk } from '$lib/stores/sdk';
+import type { PageLoad } from './$types';
+import type { Coupon } from '$lib/sdk/billing';
+import type { Organization } from '$lib/stores/organization';
+
+export const load: PageLoad = async ({ url, parent }) => {
+ const { organizations } = await parent();
+ const [coupon, paymentMethods] = await Promise.all([
+ getCoupon(url),
+ sdk.forConsole.billing.listPaymentMethods()
+ ]);
+ let plan = getPlanFromUrl(url);
+ const hasFreeOrganizations = organizations.teams?.some(
+ (org) => (org as Organization)?.billingPlan === BillingPlan.FREE
+ );
+ if (plan === BillingPlan.FREE && hasFreeOrganizations) {
+ plan = BillingPlan.PRO;
+ }
+
+ return {
+ plan,
+ coupon,
+ hasFreeOrganizations,
+ paymentMethods,
+ name: url.searchParams.get('name') ?? ''
+ };
+};
+
+function getPlanFromUrl(url: URL): BillingPlan | null {
+ if (url.searchParams.has('plan')) {
+ const plan = url.searchParams.get('plan');
+ if (plan && plan in BillingPlan) {
+ return plan as BillingPlan;
+ }
+ }
+ return BillingPlan.FREE;
+}
+
+async function getCoupon(url: URL): Promise {
+ if (url.searchParams.has('code')) {
+ const coupon = url.searchParams.get('code');
+ try {
+ return sdk.forConsole.billing.getCoupon(coupon);
+ } catch (e) {
+ return null;
+ }
+ }
+ return null;
+}
diff --git a/src/routes/(console)/createOrganization.svelte b/src/routes/(console)/createOrganization.svelte
index 6547a5c51..9896ef451 100644
--- a/src/routes/(console)/createOrganization.svelte
+++ b/src/routes/(console)/createOrganization.svelte
@@ -8,9 +8,9 @@
import { Dependencies } from '$lib/constants';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { ID } from '@appwrite.io/console';
- import Alert from '$lib/components/alert.svelte';
import { isCloud } from '$lib/system';
import { base } from '$app/paths';
+ import { Alert } from '@appwrite.io/pink-svelte';
export let show = false;
@@ -39,18 +39,17 @@
}
-
+
{#if isCloud}
-
- Get ready for Appwrite Pro
+
We will soon introduce the much-anticipated Pro plan. Your account will continue to have
access to one free organization . If you manage more than one organization, you
will need to either upgrade to the Pro plan, transfer your projects to a Pro
organization, or migrate to self-hosting.
-
+
Learn more
-
+
{/if}
- import { Card, Layout, Typography, Input, Tag, Icon, Button } from '@appwrite.io/pink-svelte';
- import { IconPencil } from '@appwrite.io/pink-icons-svelte';
- import { CustomId } from '$lib/components/index.js';
+ import { Card } from '@appwrite.io/pink-svelte';
import type { RegionList } from '$lib/sdk/billing';
- import { onMount } from 'svelte';
import { isCloud } from '$lib/system';
import { sdk } from '$lib/stores/sdk';
- import { isValueOfStringEnum } from '$lib/helpers/types';
import { Flag, ID, Region } from '@appwrite.io/console';
import Loading from './loading.svelte';
import { BillingPlan, Dependencies } from '$lib/constants';
@@ -15,27 +11,15 @@
import { base } from '$app/paths';
import { addNotification } from '$lib/stores/notifications';
import { tierToPlan } from '$lib/stores/billing';
+ import CreateProject from '$lib/layout/createProject.svelte';
- let showCustomId = false;
let isLoading = false;
let id: string;
let startAnimation = false;
let projectName = '';
+ let region = Region.Default;
export let data: { regions: RegionList | null };
- onMount(() => {
- if (isCloud) {
- if (data.regions) {
- data.regions.regions.forEach((region) => fetch(getFlagUrl(region.flag)));
- }
- }
- });
-
- function getFlagUrl(countryCode: string) {
- if (!isValueOfStringEnum(Flag, countryCode)) return '';
- return sdk.forProject.avatars.getFlag(countryCode, 22, 15, 100)?.toString();
- }
-
async function createProject() {
isLoading = true;
@@ -72,7 +56,7 @@
id ?? ID.unique(),
projectName,
teamId,
- Region.Default
+ region
);
trackEvent(Submit.ProjectCreate, {
customId: !!id,
@@ -99,28 +83,6 @@
}
}
}
-
- function getRegions() {
- if (!data.regions) {
- return;
- }
- return data.regions.regions
- .filter((region) => region.$id !== 'default')
- .sort((regionA, regionB) => {
- if (regionA.disabled && !regionB.disabled) {
- return 1;
- }
- return regionA.name > regionB.name ? 1 : -1;
- })
- .map((region) => {
- return {
- label: region.name,
- value: region.$id,
- leadingHtml: ` `,
- disabled: region.disabled
- };
- });
- }
@@ -144,57 +106,13 @@
height="22"
class="u-only-dark"
alt="Appwrite Logo" />
-
-
- Create your project
-
-
-
-
-
- {#if !showCustomId}
-
- {
- showCustomId = true;
- }}> Project ID
-
- {/if}
-
-
- {#if data.regions}
-
- Region cannot be changed after creation
-
- {/if}
-
-
-
- Create
-
-
-
+
+
{/if}
diff --git a/src/routes/(console)/onboarding/create-project/loading.svelte b/src/routes/(console)/onboarding/create-project/loading.svelte
index 6d817bde4..23c467c2b 100644
--- a/src/routes/(console)/onboarding/create-project/loading.svelte
+++ b/src/routes/(console)/onboarding/create-project/loading.svelte
@@ -197,7 +197,7 @@
-->
diff --git a/src/routes/(console)/organization-[organization]/billing/paymentMethods.svelte b/src/routes/(console)/organization-[organization]/billing/paymentMethods.svelte
index ab4b51c7a..bd8077e29 100644
--- a/src/routes/(console)/organization-[organization]/billing/paymentMethods.svelte
+++ b/src/routes/(console)/organization-[organization]/billing/paymentMethods.svelte
@@ -2,13 +2,7 @@
import { sdk } from '$lib/stores/sdk';
import { invalidate } from '$app/navigation';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
- import {
- CardGrid,
- CreditCardBrandImage,
- CreditCardInfo,
- DropList,
- DropListItem
- } from '$lib/components';
+ import { CardGrid, CreditCardBrandImage, CreditCardInfo } from '$lib/components';
import { BillingPlan, Dependencies } from '$lib/constants';
import { addNotification } from '$lib/stores/notifications';
import { organization } from '$lib/stores/organization';
@@ -21,11 +15,25 @@
import EditPaymentModal from '$routes/(console)/account/payments/editPaymentModal.svelte';
import PaymentModal from '$lib/components/billing/paymentModal.svelte';
import { user } from '$lib/stores/user';
- import { Icon, Tooltip } from '@appwrite.io/pink-svelte';
- import { IconPlus } from '@appwrite.io/pink-icons-svelte';
-
- let showDropdown = false;
- let showDropdownBackup = false;
+ import {
+ ActionMenu,
+ Card,
+ Divider,
+ Icon,
+ Layout,
+ Popover,
+ Table,
+ Tooltip,
+ Typography
+ } from '@appwrite.io/pink-svelte';
+ import {
+ IconDotsHorizontal,
+ IconInfo,
+ IconPencil,
+ IconPlus,
+ IconSwitchHorizontal,
+ IconTrash
+ } from '@appwrite.io/pink-icons-svelte';
let showPayment = false;
let showEdit = false;
@@ -97,204 +105,178 @@
Payment methods
View or update your organization payment methods here.
-
- {#if $organization?.paymentMethodId}
-
-
- {
- showDropdown = !showDropdown;
- }}>
-
-
-
- {#if defaultPaymentMethod.userId === $user.$id}
- {
- isSelectedBackup = false;
- showEdit = true;
- showDropdown = false;
- }}>
- Edit
-
- {/if}
- {
- isSelectedBackup = false;
- showReplace = true;
- showDropdown = false;
- }}>
- Replace
-
- {
- isSelectedBackup = false;
- showDelete = true;
- showDropdown = false;
- }}>
- Remove
-
-
-
-
- {:else}
- {@const filteredPaymentMethods = $paymentMethods.paymentMethods.filter(
- (o) => !!o.last4 && o.$id !== $organization?.backupPaymentMethodId
- )}
-
-
-
-
- {
- if (filteredPaymentMethods.length) {
- showDropdown = !showDropdown;
- } else {
- showPayment = true;
- }
- }}>
-
-
-
- {#if $paymentMethods.total}
- {#each filteredPaymentMethods as paymentMethod}
- {
- showDropdown = false;
- addPaymentMethod(paymentMethod?.$id);
- }}>
-
-
- Card ending in {paymentMethod.last4}
-
-
-
-
- {/each}
- {/if}
- (showPayment = true)}>
- Add new payment method
-
-
-
-
-
- Add a payment method
-
-
-
- {/if}
-
- {#if $organization?.billingPlan !== BillingPlan.FREE && $organization?.billingPlan !== BillingPlan.GITHUB_EDUCATION}
-
- {#if $organization?.backupPaymentMethodId}
-
Backup
-
-
- {
- showDropdownBackup = !showDropdownBackup;
- }}>
-
+ {#if $organization?.paymentMethodId}
+
+
+ Credit card
+ Name
+ Expiration date
+
+
+
+
+
+
+
+
+
+
-
- {#if backupPaymentMethod.userId === $user.$id}
-
+ {#if defaultPaymentMethod?.userId === $user?.$id}
+ {
+ isSelectedBackup = false;
showEdit = true;
- isSelectedBackup = true;
- showDropdownBackup = false;
}}>
Edit
-
+
{/if}
- {
+ isSelectedBackup = false;
showReplace = true;
- isSelectedBackup = true;
- showDropdownBackup = false;
}}>
Replace
-
-
+ {
+ isSelectedBackup = false;
showDelete = true;
- isSelectedBackup = true;
- showDropdownBackup = false;
}}>
- Delete
-
-
-
-
- {:else}
- {@const filteredPaymentMethods = $paymentMethods.paymentMethods.filter(
- (o) => !!o.last4 && o.$id !== $organization?.paymentMethodId
- )}
-
-
-
-
{
- if (filteredPaymentMethods.length) {
- showDropdownBackup = !showDropdownBackup;
- } else {
- isSelectedBackup = true;
- showPayment = true;
- }
- }}>
-
- Add a backup payment method
+ Remove
+
+
+
+
+
+ {#if $organization?.backupPaymentMethodId}
+
+
+
+
+
+
-
-
-
-
- {#if $paymentMethods.total}
- {#each filteredPaymentMethods as paymentMethod}
-
+ {#if backupPaymentMethod?.userId === $user?.$id}
+ {
- showDropdownBackup = true;
- addBackupPaymentMethod(paymentMethod?.$id);
+ isSelectedBackup = true;
+ showEdit = true;
}}>
-
-
- Card ending in {paymentMethod.last4}
-
-
-
-
- {/each}
- {/if}
- (showPayment = true)}>
- Add new payment method
-
-
-
-
+ Edit
+
+ {/if}
+
{
+ isSelectedBackup = true;
+ showReplace = true;
+ }}>
+ Replace
+
+
{
+ isSelectedBackup = true;
+ showDelete = true;
+ }}>
+ Remove
+
+
+
+
+
{/if}
-
+
+ {#if !$organization?.backupPaymentMethodId}
+ {@const filteredPaymentMethods = $paymentMethods.paymentMethods.filter(
+ (o) => !!o.last4 && o.$id !== $organization?.paymentMethodId
+ )}
+
+
+
+ {
+ if (filteredPaymentMethods.length) {
+ toggle(e);
+ } else {
+ isSelectedBackup = true;
+ showPayment = true;
+ }
+ }}>
+
+ Add a backup payment method
+
+
+
+
+ If your default payment fails, your backup method will be
+ charged automatically.
+
+
+
+
+ {#if $paymentMethods.total}
+ {#each filteredPaymentMethods as paymentMethod}
+ addBackupPaymentMethod(paymentMethod?.$id)}>
+
+
+ Card ending in {paymentMethod.last4}
+
+
+ {/each}
+ {/if}
+
+ (showPayment = true)}>
+ Add new payment method
+
+
+
+
+ {/if}
+ {:else}
+ {@const filteredPaymentMethods = $paymentMethods.paymentMethods.filter(
+ (o) => !!o.last4 && o.$id !== $organization?.backupPaymentMethodId
+ )}
+
+
+
+
+
+
+
+ {#if $paymentMethods.total}
+ {#each filteredPaymentMethods as paymentMethod}
+ addPaymentMethod(paymentMethod?.$id)}>
+
+
+ Card ending in {paymentMethod.last4}
+
+
+ {/each}
+ {/if}
+
+ (showPayment = true)}>
+ Add new payment method
+
+
+
+ Add a payment method
+
+
{/if}
diff --git a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte
index 2353a55d5..b03133998 100644
--- a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte
+++ b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte
@@ -1,6 +1,6 @@
{#if $organization}
@@ -40,166 +64,165 @@
$organization?.billingNextInvoiceDate
)}
-
-
-
-
-
- {tierToPlan($organization?.billingPlan)?.name} plan
-
- {isTrial ||
- $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION
- ? formatCurrency(0)
- : currentPlan
- ? formatCurrency(currentPlan?.price)
- : ''}
-
-
+
+
+
+
+ {tierToPlan($organization?.billingPlan)?.name} plan
+
+
+ {isTrial || $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION
+ ? formatCurrency(0)
+ : currentPlan
+ ? formatCurrency(currentPlan?.price)
+ : ''}
+
+
- {#if $organization?.billingPlan !== BillingPlan.FREE && $organization?.billingPlan !== BillingPlan.GITHUB_EDUCATION && extraUsage > 0}
-
-
- Add-ons {extraMembers ? extraAddons + 1 : extraAddons}
-
-
-
-
-
-
-
- {formatCurrency(extraUsage >= 0 ? extraUsage : 0)}
-
-
-
+ {#if $organization?.billingPlan !== BillingPlan.FREE && $organization?.billingPlan !== BillingPlan.GITHUB_EDUCATION && extraUsage > 0}
+
+
+ {formatCurrency(extraUsage >= 0 ? extraUsage : 0)}
+
+
+ {#if extraMembers}
+
+
+ Additional members
+ {formatCurrency(
+ extraMembers *
+ (currentPlan?.addons?.member?.price ?? 0)
+ )}
+
+
+ {extraMembers}
+
+
+ {/if}
+ {#if currentInvoice?.usage}
+ {#each currentInvoice.usage as excess, i}
+ {#if i > 0 || extraMembers}
+
+ {/if}
+ {#if ['storage', 'bandwidth'].includes(excess.name)}
+ {@const excessValue = humanFileSize(excess.value)}
+
+
+ {usageNameToLabel(
+ excess.name
+ )}
+ {formatCurrency(
+ excess.amount
+ )}
+
+
+
+
+
+ {formatNumberWithCommas(
+ excess.value ?? 0
+ )} bytes
+
+ {excessValue.value ??
+ 0}{excessValue.unit}
+
+
+
+
+ {/if}
+ {#if ['users', 'executions'].includes(excess.name)}
+
+
+ {usageNameToLabel(
+ excess.name
+ )}
+ {formatCurrency(
+ excess.amount
+ )}
+
+
+
+
+ {formatNumberWithCommas(excess.value)}
+
+ {abbreviateNumber(excess.value)}
+
+
+
+ {/if}
+ {/each}
+ {/if}
+
+
+ {/if}
-
- {#if extraMembers}
-
-
-
- Additional members
-
-
- {formatCurrency(
- extraMembers *
- (currentPlan?.addons?.member?.price ??
- 0)
- )}
-
-
-
-
- {extraMembers}
-
-
-
- {/if}
- {#if currentInvoice?.usage}
- {#each currentInvoice.usage as excess, i}
-
- {/each}
- {/if}
-
-
- {/if}
+ {#if $organization?.billingPlan !== BillingPlan.FREE && availableCredit > 0}
+
+
+
+ Credits to be applied
+
+
+ {formatCurrency(
+ Math.min(availableCredit, currentInvoice?.amount ?? 0)
+ )}
+
+
+ {/if}
- {#if $organization?.billingPlan !== BillingPlan.FREE && availableCredit > 0}
-
-
-
-
- Credits to be applied
-
-
- -{formatCurrency(
- Math.min(availableCredit, currentInvoice?.amount ?? 0)
- )}
-
-
- {/if}
-
- {#if $organization?.billingPlan !== BillingPlan.FREE && $organization?.billingPlan !== BillingPlan.GITHUB_EDUCATION}
-
- Current total (USD)
-
-
-
-
- {formatCurrency(
- Math.max(
- (currentInvoice?.amount ?? 0) -
- Math.min(
- availableCredit,
- currentInvoice?.amount ?? 0
- ),
- 0
- )
- )}
-
-
- {/if}
-
-
-
+ {#if $organization?.billingPlan !== BillingPlan.FREE && $organization?.billingPlan !== BillingPlan.GITHUB_EDUCATION}
+
+
+
+
+ Current total (USD)
+
+
+
+ Estimates are updated daily and may differ from your
+ final invoice.
+
+
+
+
+
+ {formatCurrency(
+ Math.max(
+ (currentInvoice?.amount ?? 0) -
+ Math.min(availableCredit, currentInvoice?.amount ?? 0),
+ 0
+ )
+ )}
+
+
+ {/if}
+
+
{#if $organization?.billingPlan === BillingPlan.FREE || $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION}
@@ -212,7 +235,7 @@
disabled={$organization?.markedForDeletion}
href={$upgradeURL}
on:click={() =>
- trackEvent('click_organization_upgrade', {
+ trackEvent(Click.OrganizationClickUpgrade, {
from: 'button',
source: 'billing_tab'
})}>
diff --git a/src/routes/(console)/organization-[organization]/billing/replaceAddress.svelte b/src/routes/(console)/organization-[organization]/billing/replaceAddress.svelte
index 2018801ab..2f5c85539 100644
--- a/src/routes/(console)/organization-[organization]/billing/replaceAddress.svelte
+++ b/src/routes/(console)/organization-[organization]/billing/replaceAddress.svelte
@@ -1,7 +1,7 @@
diff --git a/src/routes/(console)/organization-[organization]/billing/retryPaymentModal.svelte b/src/routes/(console)/organization-[organization]/billing/retryPaymentModal.svelte
index ee76f3afa..fb82105a8 100644
--- a/src/routes/(console)/organization-[organization]/billing/retryPaymentModal.svelte
+++ b/src/routes/(console)/organization-[organization]/billing/retryPaymentModal.svelte
@@ -7,12 +7,7 @@
import { addNotification } from '$lib/stores/notifications';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { page } from '$app/stores';
- import {
- confirmPayment,
- initializeStripe,
- isStripeInitialized,
- submitStripeCard
- } from '$lib/stores/stripe';
+ import { confirmPayment, isStripeInitialized, submitStripeCard } from '$lib/stores/stripe';
import { organization } from '$lib/stores/organization';
import { toLocaleDate } from '$lib/helpers/date';
import { PaymentBoxes } from '$lib/components/billing';
@@ -98,15 +93,10 @@
}
}
- $: if (paymentMethodId === null && !$isStripeInitialized) {
- initializeStripe();
- }
-
+ $: filteredMethods = $paymentMethods?.paymentMethods.filter((method) => !!method?.last4);
$: if (paymentMethodId) {
isStripeInitialized.set(false);
}
- $: filteredMethods = $paymentMethods?.paymentMethods.filter((method) => !!method?.last4);
-
$: if (!show) {
invoice = null;
}
diff --git a/src/routes/(console)/organization-[organization]/billing/wizard/paymentDetails.svelte b/src/routes/(console)/organization-[organization]/billing/wizard/paymentDetails.svelte
index 8a142ac57..456f446ca 100644
--- a/src/routes/(console)/organization-[organization]/billing/wizard/paymentDetails.svelte
+++ b/src/routes/(console)/organization-[organization]/billing/wizard/paymentDetails.svelte
@@ -5,7 +5,7 @@
import type { PaymentList } from '$lib/sdk/billing';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
- import { initializeStripe, isStripeInitialized, submitStripeCard } from '$lib/stores/stripe';
+ import { isStripeInitialized, submitStripeCard } from '$lib/stores/stripe';
import { sdk } from '$lib/stores/sdk';
import { PaymentBoxes } from '$lib/components/billing';
import { addCreditWizardStore } from '../store';
@@ -30,10 +30,6 @@
}
}
- $: if ($addCreditWizardStore.paymentMethodId === null && !$isStripeInitialized) {
- initializeStripe();
- }
-
$: if ($addCreditWizardStore.paymentMethodId) {
isStripeInitialized.set(false);
}
@@ -49,10 +45,8 @@
Payment method
-
-
-
+
diff --git a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte
index f17e1b9cc..8fc9c44f4 100644
--- a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte
+++ b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte
@@ -3,7 +3,6 @@
import { base } from '$app/paths';
import { page } from '$app/stores';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
- import { Alert } from '$lib/components';
import {
EstimatedTotalBox,
PlanComparisonBox,
@@ -12,114 +11,48 @@
import PlanExcess from '$lib/components/billing/planExcess.svelte';
import PlanSelection from '$lib/components/billing/planSelection.svelte';
import ValidateCreditModal from '$lib/components/billing/validateCreditModal.svelte';
- import Default from '$lib/components/roles/default.svelte';
import { BillingPlan, Dependencies, feedbackDowngradeOptions } from '$lib/constants';
- import {
- Button,
- Form,
- FormList,
- InputSelect,
- InputTags,
- InputTextarea,
- Label
- } from '$lib/elements/forms';
+ import { Button, Form, InputSelect, InputTags, InputTextarea } from '$lib/elements/forms';
import { formatCurrency } from '$lib/helpers/numbers.js';
- import {
- WizardSecondaryContainer,
- WizardSecondaryContent,
- WizardSecondaryFooter
- } from '$lib/layout';
+ import { Wizard } from '$lib/layout';
import { type Coupon, type PaymentList } from '$lib/sdk/billing';
- import { plansInfo, tierToPlan, type Tier } from '$lib/stores/billing';
+ import { plansInfo, tierToPlan } from '$lib/stores/billing';
import { addNotification } from '$lib/stores/notifications';
- import {
- currentPlan,
- organization,
- organizationList,
- type Organization
- } from '$lib/stores/organization';
+ import { organization } from '$lib/stores/organization';
import { sdk } from '$lib/stores/sdk';
import { user } from '$lib/stores/user';
import { VARS } from '$lib/system';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
- import { Icon } from '@appwrite.io/pink-svelte';
- import { onMount } from 'svelte';
+ import { Alert, Fieldset, Icon, Layout, Link, Typography } from '@appwrite.io/pink-svelte';
import { writable } from 'svelte/store';
export let data;
- $: anyOrgFree = $organizationList.teams?.find(
- (org) => (org as Organization)?.billingPlan === BillingPlan.FREE
- );
- const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$/i;
+ let selectedPlan: BillingPlan = data.plan as BillingPlan;
+ let selectedCoupon: Partial | null = data.coupon;
let previousPage: string = base;
let showExitModal = false;
- afterNavigate(({ from }) => {
- previousPage = from?.url?.pathname || previousPage;
- });
-
let formComponent: Form;
let isSubmitting = writable(false);
- let methods: PaymentList;
- let billingPlan: Tier = $organization.billingPlan;
- let paymentMethodId: string;
+ let paymentMethodId: string =
+ data.organization.paymentMethodId ??
+ data.paymentMethods.paymentMethods.find((method) => !!method?.last4)?.$id;
let collaborators: string[] =
data?.members?.memberships
?.map((m) => {
if (m.userEmail !== $user.email) return m.userEmail;
})
?.filter(Boolean) ?? [];
- let couponData: Partial = {
- code: null,
- status: null,
- credits: null
- };
let taxId: string;
let billingBudget: number;
let showCreditModal = false;
-
let feedbackDowngradeReason: string;
let feedbackMessage: string;
- let selfService: boolean;
- onMount(async () => {
- if ($page.url.searchParams.has('code')) {
- const coupon = $page.url.searchParams.get('code');
- try {
- const response = await sdk.forConsole.billing.getCoupon(coupon);
- couponData = response;
- } catch (e) {
- couponData = {
- code: null,
- status: null,
- credits: null
- };
- }
- }
- if ($page.url.searchParams.has('plan')) {
- const plan = $page.url.searchParams.get('plan');
- if (plan && plan in BillingPlan) {
- billingPlan = plan as BillingPlan;
- }
- }
- if ($organization?.billingPlan === BillingPlan.SCALE) {
- billingPlan = BillingPlan.SCALE;
- } else {
- billingPlan = BillingPlan.PRO;
- }
-
- selfService = $currentPlan?.selfService ?? true;
+ afterNavigate(({ from }) => {
+ previousPage = from?.url?.pathname || previousPage;
});
- async function loadPaymentMethods() {
- methods = await sdk.forConsole.billing.listPaymentMethods();
-
- paymentMethodId =
- $organization?.paymentMethodId ??
- methods.paymentMethods.find((method) => !!method?.last4)?.$id ??
- null;
- }
-
async function handleSubmit() {
if (isDowngrade) {
await downgrade();
@@ -131,8 +64,8 @@
async function downgrade() {
try {
await sdk.forConsole.billing.updatePlan(
- $organization.$id,
- billingPlan,
+ data.organization.$id,
+ selectedPlan,
paymentMethodId,
null
);
@@ -143,14 +76,14 @@
'Content-Type': 'application/json'
},
body: JSON.stringify({
- from: tierToPlan($organization.billingPlan).name,
- to: tierToPlan(billingPlan).name,
- email: $user.email,
+ from: tierToPlan(data.organization.billingPlan).name,
+ to: tierToPlan(selectedPlan).name,
+ email: data.account.email,
reason: feedbackDowngradeOptions.find(
(option) => option.value === feedbackDowngradeReason
)?.label,
- orgId: $organization.$id,
- userId: $user.$id,
+ orgId: data.organization.$id,
+ userId: data.account.$id,
message: feedbackMessage ?? ''
})
});
@@ -161,12 +94,12 @@
isHtml: true,
message: `
${$organization.name} will change to ${
- tierToPlan(billingPlan).name
+ tierToPlan(selectedPlan).name
} plan at the end of the current billing cycle.`
});
trackEvent(Submit.OrganizationDowngrade, {
- plan: tierToPlan(billingPlan)?.name
+ plan: tierToPlan(selectedPlan)?.name
});
} catch (e) {
addNotification({
@@ -180,15 +113,15 @@
async function upgrade() {
try {
const org = await sdk.forConsole.billing.updatePlan(
- $organization.$id,
- billingPlan,
+ data.organization.$id,
+ selectedPlan,
paymentMethodId,
null
);
//Add coupon
- if (couponData?.code) {
- await sdk.forConsole.billing.addCredit(org.$id, couponData.code);
+ if (selectedCoupon?.code) {
+ await sdk.forConsole.billing.addCredit(org.$id, selectedCoupon.code);
trackEvent(Submit.CreditRedeem);
}
@@ -230,7 +163,7 @@
});
trackEvent(Submit.OrganizationUpgrade, {
- plan: tierToPlan(billingPlan)?.name
+ plan: tierToPlan(selectedPlan)?.name
});
} catch (e) {
addNotification({
@@ -241,124 +174,132 @@
}
}
- $: isUpgrade = billingPlan > $organization.billingPlan;
- $: isDowngrade = billingPlan < $organization.billingPlan;
- $: if (billingPlan !== BillingPlan.FREE) {
- loadPaymentMethods();
- }
- $: isButtonDisabled = $organization.billingPlan === billingPlan;
+ $: isUpgrade = data.plan > data.organization.billingPlan;
+ $: isDowngrade = data.plan < data.organization.billingPlan;
+ $: isButtonDisabled = $organization.billingPlan === selectedPlan;
+
+ $: console.log(data.paymentMethods);
Change plan - Appwrite
-
- Change plan
-
-
- Select plan
-
- For more details on our plans, visit our
- pricing page .
-
- {#if !selfService}
- Your contract is not eligible for manual changes. Please reach out to schedule
- a call or setup a dialog.
- {/if}
-
-
- {#if isDowngrade}
- {#if billingPlan === BillingPlan.FREE}
-
- {:else if billingPlan === BillingPlan.PRO && $organization.billingPlan === BillingPlan.SCALE && collaborators?.length > 0}
- {@const extraMembers = collaborators?.length ?? 0}
-
-
- Your monthly payments will be adjusted for the Pro plan
-
- After switching plans,
- you will be charged {formatCurrency(
- extraMembers *
- ($plansInfo?.get(billingPlan)?.addons?.member?.price ?? 0)
- )} monthly for {extraMembers} team members. This will be reflected in
- your next invoice.
-
+
+
+
+
+
+ For more details on our plans, visit our
+ pricing page .
+
+ {#if !data.selfService}
+
+ Your contract is not eligible for manual changes. Please reach out to
+ schedule a call or setup a dialog.
+
{/if}
- {/if}
+
+
+ {#if isDowngrade}
+ {#if selectedPlan === BillingPlan.FREE}
+
+ {:else if selectedPlan === BillingPlan.PRO && data.organization.billingPlan === BillingPlan.SCALE && collaborators?.length > 0}
+ {@const extraMembers = collaborators?.length ?? 0}
+ {@const price = formatCurrency(
+ extraMembers *
+ ($plansInfo?.get(selectedPlan)?.addons?.member?.price ?? 0)
+ )}
+
+
+ Your monthly payments will be adjusted for the Pro plan
+
+ After switching plans,
+ you will be charged {price} monthly for {extraMembers} team members.
+ This will be reflected in your next invoice.
+
+ {/if}
+ {/if}
+
+
- {#if billingPlan !== BillingPlan.FREE && $organization.billingPlan === BillingPlan.FREE}
-
+ {#if selectedPlan !== BillingPlan.FREE && data.organization.billingPlan === BillingPlan.FREE}
+
+
-
- {#if !couponData?.code}
- (showCreditModal = true)}>
-
- Add credits
-
- {/if}
-
+
+ {#if !selectedCoupon?.code}
+ (showCreditModal = true)}>
+
+ Add credits
+
+ {/if}
{/if}
- {#if isDowngrade && billingPlan === BillingPlan.FREE}
-
-
-
-
+ {#if isDowngrade && selectedPlan === BillingPlan.FREE}
+
+
+
+
+
+
{/if}
-
-
- {#if billingPlan !== BillingPlan.FREE && $organization.billingPlan !== billingPlan && $organization.billingPlan !== BillingPlan.CUSTOM}
-
- {:else if $organization.billingPlan !== BillingPlan.CUSTOM}
-
- {/if}
-
-
-
-
+
+
+
+ {#if selectedPlan !== BillingPlan.FREE && data.organization.billingPlan !== selectedPlan && data.organization.billingPlan !== BillingPlan.CUSTOM}
+
+ {:else if data.organization.billingPlan !== BillingPlan.CUSTOM}
+
+ {/if}
+
+
(showExitModal = true)}>Cancel
formComponent.triggerSubmit()}
- disabled={$isSubmitting || isButtonDisabled || !selfService}>
+ disabled={$isSubmitting || isButtonDisabled || !data.selfService}>
Change plan
-
-
+
+
-
+
diff --git a/src/routes/(console)/organization-[organization]/change-plan/+page.ts b/src/routes/(console)/organization-[organization]/change-plan/+page.ts
index e14b3d468..e3d79c69e 100644
--- a/src/routes/(console)/organization-[organization]/change-plan/+page.ts
+++ b/src/routes/(console)/organization-[organization]/change-plan/+page.ts
@@ -1,11 +1,58 @@
-import { Dependencies } from '$lib/constants';
+import { BillingPlan, Dependencies } from '$lib/constants';
+import { sdk } from '$lib/stores/sdk';
import type { PageLoad } from './$types';
+import type { Coupon } from '$lib/sdk/billing';
+import type { Organization } from '$lib/stores/organization';
-export const load: PageLoad = async ({ depends, parent }) => {
- const { members } = await parent();
+export const load: PageLoad = async ({ depends, parent, url }) => {
+ const { members, organization, currentPlan, organizations } = await parent();
+ depends(Dependencies.UPGRADE_PLAN);
+
+ const [coupon, paymentMethods] = await Promise.all([
+ getCoupon(url),
+ sdk.forConsole.billing.listPaymentMethods()
+ ]);
+
+ let plan = getPlanFromUrl(url);
+
+ if (organization?.billingPlan === BillingPlan.SCALE) {
+ plan = BillingPlan.SCALE;
+ } else {
+ plan = BillingPlan.PRO;
+ }
+
+ const selfService = currentPlan?.selfService ?? true;
+ const hasFreeOrgs = organizations.teams?.some(
+ (org) => (org as Organization)?.billingPlan === BillingPlan.FREE
+ );
- depends(Dependencies.ORGANIZATION);
return {
- members
+ members,
+ plan,
+ coupon,
+ selfService,
+ hasFreeOrgs,
+ paymentMethods
};
};
+
+function getPlanFromUrl(url: URL): BillingPlan | null {
+ if (url.searchParams.has('plan')) {
+ const plan = url.searchParams.get('plan');
+ if (plan && plan in BillingPlan) {
+ return plan as BillingPlan;
+ }
+ }
+}
+
+async function getCoupon(url: URL): Promise {
+ if (url.searchParams.has('code')) {
+ const coupon = url.searchParams.get('code');
+ try {
+ return sdk.forConsole.billing.getCoupon(coupon);
+ } catch (e) {
+ return null;
+ }
+ }
+ return null;
+}
diff --git a/src/routes/(console)/organization-[organization]/createProjectCloud.svelte b/src/routes/(console)/organization-[organization]/createProjectCloud.svelte
index c42d662c6..9eeeeb96d 100644
--- a/src/routes/(console)/organization-[organization]/createProjectCloud.svelte
+++ b/src/routes/(console)/organization-[organization]/createProjectCloud.svelte
@@ -1,21 +1,22 @@
-
+
diff --git a/src/routes/(console)/organization-[organization]/domains/+page.svelte b/src/routes/(console)/organization-[organization]/domains/+page.svelte
index 2eeff4d7d..4abfa7f3c 100644
--- a/src/routes/(console)/organization-[organization]/domains/+page.svelte
+++ b/src/routes/(console)/organization-[organization]/domains/+page.svelte
@@ -29,6 +29,7 @@
import SearchQuery from '$lib/components/searchQuery.svelte';
import { app } from '$lib/stores/app';
import type { Domain } from '$lib/sdk/domains';
+ import { Click, trackEvent } from '$lib/actions/analytics';
export let data;
@@ -42,7 +43,13 @@
-
+ {
+ trackEvent(Click.DomainCreateClick, {
+ source: 'organization_domain_overview'
+ });
+ }}
+ href={`${base}/organization-${$page.params.organization}/domains/add-domain`}>
Add domain
@@ -63,18 +70,9 @@
-
-
-
- {domain.domain}
-
-
-
-
+
+ {domain.domain}
+
{domain?.registrar || '-'}
{domain?.nameservers || '-'}
@@ -86,7 +84,7 @@
{domain.autoRenewal ? 'On' : 'Off'}
-
+
Retry
@@ -119,6 +120,9 @@
selectedDomain = domain;
showDelete = true;
toggle(e);
+ trackEvent(Click.DomainDeleteClick, {
+ source: 'organization_domain_overview'
+ });
}}>
Delete
@@ -166,6 +170,11 @@
{
+ trackEvent(Click.DomainCreateClick, {
+ source: 'organization_domain_overview'
+ });
+ }}
href={`${base}/organization-${$page.params.organization}/domains/add-domain`}
size="s">
Add domain
@@ -177,7 +186,7 @@
{#if showDelete}
-
+
{/if}
+
diff --git a/src/routes/(console)/project-[project]/auth/templates/email2FATemplate.svelte b/src/routes/(console)/project-[project]/auth/templates/email2FATemplate.svelte
index 66b12f815..811cb15a1 100644
--- a/src/routes/(console)/project-[project]/auth/templates/email2FATemplate.svelte
+++ b/src/routes/(console)/project-[project]/auth/templates/email2FATemplate.svelte
@@ -7,6 +7,7 @@
import { addNotification } from '$lib/stores/notifications';
import { Id } from '$lib/components';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
+ import { Layout } from '@appwrite.io/pink-svelte';
const projectId = $page.params.project;
let locale = 'en';
@@ -34,11 +35,11 @@
}
-
+
{'{{user}}'}
{'{{project}}'}
{'{{otp}}'}
-
+
diff --git a/src/routes/(console)/project-[project]/auth/templates/emailInviteTemplate.svelte b/src/routes/(console)/project-[project]/auth/templates/emailInviteTemplate.svelte
index fb7a93500..2e4425eb0 100644
--- a/src/routes/(console)/project-[project]/auth/templates/emailInviteTemplate.svelte
+++ b/src/routes/(console)/project-[project]/auth/templates/emailInviteTemplate.svelte
@@ -7,6 +7,7 @@
import { addNotification } from '$lib/stores/notifications';
import { Id } from '$lib/components';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
+ import { Layout } from '@appwrite.io/pink-svelte';
const projectId = $page.params.project;
let locale = 'en';
@@ -34,7 +35,7 @@
}
-
+
{'{{team}}'}
@@ -42,4 +43,4 @@
{'{{project}}'}
{'{{redirect}}'}
-
+
diff --git a/src/routes/(console)/project-[project]/auth/templates/emailMagicUrlTemplate.svelte b/src/routes/(console)/project-[project]/auth/templates/emailMagicUrlTemplate.svelte
index e15372245..19e6c5eb9 100644
--- a/src/routes/(console)/project-[project]/auth/templates/emailMagicUrlTemplate.svelte
+++ b/src/routes/(console)/project-[project]/auth/templates/emailMagicUrlTemplate.svelte
@@ -7,6 +7,7 @@
import { addNotification } from '$lib/stores/notifications';
import { Id } from '$lib/components';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
+ import { Layout } from '@appwrite.io/pink-svelte';
const projectId = $page.params.project;
@@ -36,11 +37,11 @@
}
-
+
{'{{user}}'}
{'{{project}}'}
{'{{redirect}}'}
-
+
diff --git a/src/routes/(console)/project-[project]/auth/templates/emailRecoveryTemplate.svelte b/src/routes/(console)/project-[project]/auth/templates/emailRecoveryTemplate.svelte
index 56d028108..e6a9443f6 100644
--- a/src/routes/(console)/project-[project]/auth/templates/emailRecoveryTemplate.svelte
+++ b/src/routes/(console)/project-[project]/auth/templates/emailRecoveryTemplate.svelte
@@ -7,6 +7,7 @@
import { addNotification } from '$lib/stores/notifications';
import { Id } from '$lib/components';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
+ import { Layout } from '@appwrite.io/pink-svelte';
const projectId = $page.params.project;
@@ -35,11 +36,11 @@
}
-
+
{'{{user}}'}
{'{{project}}'}
{'{{redirect}}'}
-
+
diff --git a/src/routes/(console)/project-[project]/auth/templates/emailSessionAlertTemplate.svelte b/src/routes/(console)/project-[project]/auth/templates/emailSessionAlertTemplate.svelte
index 8dd83904b..438e8d2dd 100644
--- a/src/routes/(console)/project-[project]/auth/templates/emailSessionAlertTemplate.svelte
+++ b/src/routes/(console)/project-[project]/auth/templates/emailSessionAlertTemplate.svelte
@@ -7,6 +7,7 @@
import { addNotification } from '$lib/stores/notifications';
import { Id } from '$lib/components';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
+ import { Layout } from '@appwrite.io/pink-svelte';
const projectId = $page.params.project;
let locale = 'en';
@@ -34,7 +35,7 @@
}
-
+
{'{{user}}'}
@@ -43,4 +44,4 @@
{'{{ipAddress}}'}
{'{{country}}'}
-
+
diff --git a/src/routes/(console)/project-[project]/auth/templates/emailSignature.svelte b/src/routes/(console)/project-[project]/auth/templates/emailSignature.svelte
index 59b9fa5ea..e99af4250 100644
--- a/src/routes/(console)/project-[project]/auth/templates/emailSignature.svelte
+++ b/src/routes/(console)/project-[project]/auth/templates/emailSignature.svelte
@@ -1,5 +1,5 @@
diff --git a/src/routes/(console)/project-[project]/createVariableModal.svelte b/src/routes/(console)/project-[project]/createVariableModal.svelte
new file mode 100644
index 000000000..899b070a3
--- /dev/null
+++ b/src/routes/(console)/project-[project]/createVariableModal.svelte
@@ -0,0 +1,115 @@
+
+
+
+
+
+ Set the environment variables or secret keys that will be passed to {!isGlobal
+ ? `your ${product}`
+ : `all functions and sites within your project`}.
+
+
+
+ {#if !isGlobal}
+
+ When there is a naming conflict with a global variable in your
+ project settings
+ and a {product} environment variable, the global variable will be ignored.
+
+ {/if}
+
+ {#each newVariables as pair, i}
+
+
+
+ removeVariable(i)}>
+
+
+
+ {/each}
+
+ !pair.key)}
+ on:click={() => (newVariables = [...newVariables, { key: '', value: '' }])}>
+ Add variable
+
+
+
+
+
+ Cancel
+ Create
+
+
diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/backups/policy.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/backups/policy.svelte
index ad7224c2c..9feb4a792 100644
--- a/src/routes/(console)/project-[project]/databases/database-[database]/backups/policy.svelte
+++ b/src/routes/(console)/project-[project]/databases/database-[database]/backups/policy.svelte
@@ -15,7 +15,7 @@
import EmptyLight from '$lib/images/backups/backups-light.png';
import type { BackupPolicy, BackupPolicyList } from '$lib/sdk/backups';
import { backupFrequencies } from '$lib/helpers/backups';
- import { trackEvent } from '$lib/actions/analytics';
+ import { Click, trackEvent } from '$lib/actions/analytics';
import { Icon, Tooltip } from '@appwrite.io/pink-svelte';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
@@ -168,7 +168,7 @@
showDelete = true;
selectedPolicy = policy;
showDropdown[index] = false;
- trackEvent('click_policy_delete');
+ trackEvent(Click.PolicyDeleteClick);
}}>
Delete
diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/backups/restoreModal.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/backups/restoreModal.svelte
index 706415d3d..10d7252fc 100644
--- a/src/routes/(console)/project-[project]/databases/database-[database]/backups/restoreModal.svelte
+++ b/src/routes/(console)/project-[project]/databases/database-[database]/backups/restoreModal.svelte
@@ -1,6 +1,6 @@
@@ -22,7 +23,12 @@
- (showDelete = true)}>Delete
+ {
+ trackEvent(Click.DatabaseCollectionDelete);
+ showDelete = true;
+ }}>Delete
diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/subNavigation.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/subNavigation.svelte
index 66b5fc058..abdf465a2 100644
--- a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/subNavigation.svelte
+++ b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/subNavigation.svelte
@@ -4,8 +4,13 @@
import { showCreate } from '../store';
import type { PageData } from './$types';
import { showSubNavigation } from '$lib/stores/layout';
- import { Icon, Sidebar, Navbar, Layout, Link } from '@appwrite.io/pink-svelte';
- import { IconChevronDown, IconDatabase, IconTable } from '@appwrite.io/pink-icons-svelte';
+ import { Icon, Sidebar, Navbar, Layout, Link, ActionMenu } from '@appwrite.io/pink-svelte';
+ import {
+ IconChevronDown,
+ IconDatabase,
+ IconPlus,
+ IconTable
+ } from '@appwrite.io/pink-icons-svelte';
import { isTabletViewport } from '$lib/stores/viewport';
import { BottomSheet } from '$lib/components';
@@ -15,7 +20,7 @@
$: collectionId = $page.params.collection;
$: sortedCollections = data?.allCollections?.collections?.sort((a, b) =>
- a.$updatedAt > b.$updatedAt ? -1 : 1
+ a.name.localeCompare(b.name)
);
$: selectedCollection = sortedCollections?.find(
@@ -49,7 +54,7 @@
{@const isSelected = collectionId === collection.$id}
{/if}
- {
- $showCreate = true;
- $showSubNavigation = false;
- }}>
-
- Create collection
-
+
+ {
+ $showCreate = true;
+ $showSubNavigation = false;
+ }}
+ leadingIcon={IconPlus}>
+ Create collection
+
+
{:else}
@@ -193,10 +199,6 @@
}
}
- .new-button {
- flex-shrink: 0;
- }
-
:global(.sub-navigation header) {
top: 48px !important;
}
diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/table.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/table.svelte
index d61704705..a8b20597f 100644
--- a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/table.svelte
+++ b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/table.svelte
@@ -278,35 +278,33 @@
{#if relAttributes?.length}
-
-
- Relation
- Setting
-
-
-
- {#each relAttributes as attr}
-
-
-
- {#if attr.twoWay}
-
- {:else}
-
- {/if}
- {attr.key}
-
-
-
- {attr.onDelete}
-
-
- {Deletion[attr.onDelete]}
-
-
- {/each}
-
-
+
+
+ Relation
+ Setting
+
+
+ {#each relAttributes as attr}
+
+
+
+ {#if attr.twoWay}
+
+ {:else}
+
+ {/if}
+ {attr.key}
+
+
+
+ {attr.onDelete}
+
+
+ {Deletion[attr.onDelete]}
+
+
+ {/each}
+
To change the selection edit the relationship settings.
diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/settings/+page.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/settings/+page.svelte
index 6cecdb91a..bab02f56a 100644
--- a/src/routes/(console)/project-[project]/databases/database-[database]/settings/+page.svelte
+++ b/src/routes/(console)/project-[project]/databases/database-[database]/settings/+page.svelte
@@ -1,7 +1,7 @@
-
+
+
+
+ Create function
+
+
{#if data.functions.total}
+ service="functions"
+ on:click={() => goto(`${base}/project-${project}/functions/create-function`)}>
{#each data.functions.functions as func}
-
+
+
+
+
+ {func.name}
+
{#if func.schedule}
-
-
-
- {`Next execution:
+
+
+ {`Next execution:
${getNextScheduledExecution(func)}`}
-
-
+
{/if}
{func.$id}
@@ -141,6 +128,6 @@
allowCreate={$canWriteFunctions}
href="https://appwrite.io/docs/products/functions"
target="function"
- on:click={openWizard} />
+ on:click={() => goto(`${base}/project-${project}/functions/create-function`)} />
{/if}
diff --git a/src/routes/(console)/project-[project]/functions/+page.ts b/src/routes/(console)/project-[project]/functions/+page.ts
index e12234637..96f2b6489 100644
--- a/src/routes/(console)/project-[project]/functions/+page.ts
+++ b/src/routes/(console)/project-[project]/functions/+page.ts
@@ -2,10 +2,10 @@ import { Query } from '@appwrite.io/console';
import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { CARD_LIMIT, Dependencies } from '$lib/constants';
-import type { PageLoad } from './$types';
-export const load: PageLoad = async ({ url, depends, route }) => {
+export const load = async ({ url, depends, route, parent }) => {
depends(Dependencies.FUNCTIONS);
+ const { templatesList } = await parent();
const page = getPage(url);
const limit = getLimit(url, route, CARD_LIMIT);
@@ -18,6 +18,7 @@ export const load: PageLoad = async ({ url, depends, route }) => {
Query.limit(limit),
Query.offset(offset),
Query.orderDesc('')
- ])
+ ]),
+ templatesList
};
};
diff --git a/src/routes/(console)/project-[project]/functions/create-function/(components)/aside.svelte b/src/routes/(console)/project-[project]/functions/create-function/(components)/aside.svelte
index 0e818e1db..ae7ea0a6e 100644
--- a/src/routes/(console)/project-[project]/functions/create-function/(components)/aside.svelte
+++ b/src/routes/(console)/project-[project]/functions/create-function/(components)/aside.svelte
@@ -2,29 +2,33 @@
import { Card, SvgIcon } from '$lib/components';
import { Icon, Layout, Typography } from '@appwrite.io/pink-svelte';
import { IconGithub, IconGitBranch } from '@appwrite.io/pink-icons-svelte';
- import type { Models } from '@appwrite.io/console';
+ import type { Models, Runtime } from '@appwrite.io/console';
- export let runtime: Partial
;
- export let repositoryName: string;
- export let branch: string;
- export let rootDir: string;
- export let domain: string = '';
+ export let runtime: Runtime;
+ export let repositoryName: string = undefined;
+ export let branch: string = undefined;
+ export let rootDir: string = undefined;
export let showGitData = true;
+ export let runtimes: Models.RuntimeList;
+
+ $: selectedRuntime = runtimes?.runtimes.find((r) => r.$id === runtime);
+
+ $: console.log(runtimes);
- {#if runtime?.name}
+ {#if selectedRuntime?.name}
Runtime
- {#if runtime?.key}
-
+ {#if selectedRuntime?.key}
+
{/if}
- {runtime.name}
+ {selectedRuntime.name} - {selectedRuntime.version}
diff --git a/src/routes/(console)/project-[project]/functions/create-function/(components)/details.svelte b/src/routes/(console)/project-[project]/functions/create-function/(components)/details.svelte
index 2a71eb135..5d0b031c7 100644
--- a/src/routes/(console)/project-[project]/functions/create-function/(components)/details.svelte
+++ b/src/routes/(console)/project-[project]/functions/create-function/(components)/details.svelte
@@ -1,21 +1,30 @@
@@ -41,13 +50,34 @@
{/if}
-
+ {#key runtime}
+
+ {/key}
+
+ {#if isCloud}
+
+
+ {#if $organization?.billingPlan === BillingPlan.FREE}
+
+ Upgrade to Pro or Scale to adjust
+ your CPU and RAM beyond the default.
+
+ {/if}
+
+ {/if}
{#if showEntrypoint}
- import CreateTemplate from './wizard/createTemplate.svelte';
-
- export function connectTemplate(
- template: Models.TemplateFunction,
- runtime: string | null = null
- ) {
- const variables: Record = {};
- template.variables.forEach((variable) => {
- variables[variable.name] = variable.value ?? '';
- });
-
- templateStore.set(template);
- templateConfig.set({
- $id: null,
- runtime,
- name: template.name,
- variables,
- repositoryBehaviour: 'new',
- repositoryName: template.id,
- repositoryPrivate: true,
- repositoryId: null
- });
- wizard.start(CreateTemplate);
- }
-
-
-
-
-
-
-
Connect Git repository
-
- Create and deploy a function with a connected git repository.
-
-
-
-
- {#if isSelfHosted && !isVcsEnabled}
-
-
-
- Connect your self-hosted instance to Git
-
-
- Configure your self-hosted instance to connect your function to a
- Git repository.
- Learn more .
-
-
-
- {/if}
-
+ let hasInstallations: boolean;
+ let selectedRepository: string;
-
-
- Quick start
- Use a starter template.
-
- {#await Promise.all([$baseRuntimesList, $starterTemplate])}
- {#each Array(6) as _i}
-
-
-
-
-
- {/each}
- {:then [response, quickStart]}
- {@const runtimes = new Map(response.runtimes.map((r) => [r.$id, r]))}
- {@const templates = quickStart.runtimes.filter((template) =>
- runtimes.has(template.name)
- )}
- {#each templates.slice(0, 6) as template}
- {@const runtimeDetail = runtimes.get(template.name)}
-
- {
- trackEvent('click_connect_template', {
- from: 'cover',
- template: quickStart.id,
- runtime: template.name
- });
- }}
- on:click={() => connectTemplate(quickStart, template.name)}
- class="box u-width-full-line u-flex u-cross-center u-gap-8"
- style:--box-padding="1rem"
- style:--box-border-radius="var(--border-radius-small)">
-
-
-
-
- {runtimeDetail.name}
- {#if runtimeDetail.name.toLowerCase() === 'deno'}
- New
- {/if}
-
-
-
- {/each}
+ const featuredTemplatesList = data.templatesList.templates
+ .filter((template) => template.id !== 'starter')
+ .slice(0, 4);
- {#if templates.length < 6}
-
-
-
-
-
-
- More runtimes coming soon
-
- {/if}
- {/await}
-
-
+ const starterTemplate = data.templatesList.templates.find(
+ (template) => template.id === 'starter'
+ );
-
- All starter templates
-
-
-
- Templates
-
- Find the right template for your use case.
-
+ const baseRuntimesList = [
+ ...new Map(
+ data.runtimesList.runtimes.map((runtime) => {
+ const base = runtime.name.split('-')[0];
+ return [base, runtime];
+ })
+ ).values()
+ ];
-
- {#await $featuredTemplatesList}
- {#each Array(3) as _i}
-
-
-
-
-
-
- {/each}
- {:then templatesListWithoutStarter}
- {#each templatesListWithoutStarter.templates as template}
-
- {
- trackEvent('click_connect_template', {
- from: 'cover',
- template: template.id
- });
- }}
- on:click={() => connectTemplate(template)}
- class="clickable-list-button u-width-full-line u-flex u-gap-12">
-
-
-
-
-
- {template.name}
-
-
- {template.tagline}
-
-
-
-
- {/each}
- {/await}
-
-
-
- All templates
-
-
-
-
-
- You can also create a function {
- trackEvent('click_create_function_manual', {
- from: 'cover'
- });
- }}
- on:click={() => wizard.start(CreateManual)}>manually
- or using the CLI.
- Learn more .
-
-
-
+ const starterTemplateRuntimes = starterTemplate.runtimes.filter((r) =>
+ baseRuntimesList.some((base) => base.$id === r.name)
+ );
-
+
+
+
+
+ {#if isSelfHosted && !isVcsEnabled}
+
+ Connect Git repository
+
+
+
+
+ Configure your self-hosted instance to connect your function to
+ a Git repository.
+
+
+ Learn more
+
+
+
+
+ {:else}
+
+
+ Connect Git repository
+
+
+
+ {#if hasInstallations}
+
+
+
+
+ Missing a repository? check your permissions
+
+
+
+ {/if}
+
+ {/if}
+
+
+
+
+ Quick start
+
+ {#each starterTemplateRuntimes.slice(0, 6) as template}
+ {@const iconName = template.name.split('-')[0]}
+ {@const runtimeDetail = baseRuntimesList.find(
+ (runtime) => runtime.$id === template.name
+ )}
+ {
+ trackEvent('click_connect_template', {
+ from: 'cover',
+ template: starterTemplate.id,
+ runtime: template.name
+ });
+ }}
+ href={`${wizardBase}/create-function/template-${starterTemplate.id}?runtime=${runtimeDetail.$id}`}>
+
+
+
+
+
+
+ {runtimeDetail?.name}
+ {#if runtimeDetail?.name?.toLowerCase() === 'deno'}
+
+ {/if}
+
+
+
+
+ {/each}
+
+
+
+
+
+ {#each featuredTemplatesList as template}
+ {
+ trackEvent('click_connect_template', {
+ from: 'cover',
+ template: template.name
+ });
+ }}>
+
+
+
+ {template.name}
+
+
+
+
+ {template.tagline}
+
+
+
+ {/each}
+
+
+
+
+ Browse all templates
+
+
+
+
+
+
+
+ You can also create a function {
+ trackEvent('click_create_function_manual', { from: 'cover' });
+ }}
+ href={`${wizardBase}/create-function/manual`}>manually
+ or using the CLI.
+ Learn more.
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/create-function/+page.ts b/src/routes/(console)/project-[project]/functions/create-function/+page.ts
index e69de29bb..935756a39 100644
--- a/src/routes/(console)/project-[project]/functions/create-function/+page.ts
+++ b/src/routes/(console)/project-[project]/functions/create-function/+page.ts
@@ -0,0 +1,12 @@
+export const load = async ({ parent, url }) => {
+ const { templatesList, installations, runtimesList } = await parent();
+
+ return {
+ installations,
+ installation: installations.installations.find(
+ (installation) => installation.$id === url.searchParams.get('installation')
+ ),
+ runtimesList,
+ templatesList
+ };
+};
diff --git a/src/routes/(console)/project-[project]/functions/create-function/manual/+page.svelte b/src/routes/(console)/project-[project]/functions/create-function/manual/+page.svelte
new file mode 100644
index 000000000..ea7b0f8da
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/create-function/manual/+page.svelte
@@ -0,0 +1,202 @@
+
+
+
+ Create function - Appwrite
+
+
+
+
+
+
+
+ Upload a zip file (tar.gz) containing your function source code
+
+
+
+
+
+
+ Drag and drop file here or click to upload
+
+
+
+
+
+ Only .tar.gz files allowed
+
+
+ Max file size 10MB
+
+
+
+ {#if files?.length}
+ (files = removeFile(e.detail, files))} />
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+ (showExitModal = true)}>Cancel
+ formComponent.triggerSubmit()}
+ disabled={$isSubmitting}>
+ Create
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/create-function/manual/+page.ts b/src/routes/(console)/project-[project]/functions/create-function/manual/+page.ts
new file mode 100644
index 000000000..aa4c29297
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/create-function/manual/+page.ts
@@ -0,0 +1,9 @@
+export const load = async ({ parent }) => {
+ let { installations, runtimesList, specificationsList } = await parent();
+
+ return {
+ installations,
+ runtimesList,
+ specificationsList
+ };
+};
diff --git a/src/routes/(console)/project-[project]/functions/create-function/manual/configuration.svelte b/src/routes/(console)/project-[project]/functions/create-function/manual/configuration.svelte
new file mode 100644
index 000000000..9dff286a2
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/create-function/manual/configuration.svelte
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ Set up how your project is built.
+
+
+
+
+
+
+ Choose who can execute this function using the client API. Learn more
+
+
+
+
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/+page.svelte b/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/+page.svelte
index 42f9c4d45..0f1b156bb 100644
--- a/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/+page.svelte
+++ b/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/+page.svelte
@@ -1,18 +1,16 @@
-
+
@@ -20,10 +20,14 @@
placeholder="npm install" />
-
+
- Choose who can execute this function using the client API. Learn more
+
+ Choose who can execute this function using the client API. Learn more
+
diff --git a/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/repoCard.svelte b/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/repoCard.svelte
new file mode 100644
index 000000000..462ca00d5
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/repoCard.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+ {repository?.organization}/{repository?.name}
+
+
+
+ Change
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/create-function/store.ts b/src/routes/(console)/project-[project]/functions/create-function/store.ts
deleted file mode 100644
index b248d6630..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/store.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import type { WizardStepsType } from '$lib/layout/wizardWithSteps.svelte';
-import type { Models } from '@appwrite.io/console';
-import { writable, type Writable } from 'svelte/store';
-
-export const template = writable();
-export const templateConfig = writable<{
- $id: string;
- name: string;
- runtime: string;
- variables: { [key: string]: unknown };
- repositoryBehaviour: 'new' | 'existing' | 'manual';
- repositoryName?: string;
- repositoryPrivate?: boolean;
- repositoryId: string;
- execute?: boolean;
- scopes?: string[];
- specification?: string;
-}>();
-
-export const choices = writable<{
- branch: string;
- rootDir: string;
- silentMode: boolean;
-}>({
- branch: null,
- rootDir: null,
- silentMode: null
-});
-
-const initialCreateFunction: Partial = {
- $id: null,
- name: null,
- entrypoint: null,
- execute: [],
- runtime: null,
- commands: null
-};
-
-function createFunctionStore() {
- const store = writable>({
- ...initialCreateFunction
- });
-
- const reset = () => {
- store.set({ ...initialCreateFunction });
- };
-
- return {
- ...store,
- reset
- };
-}
-export const createFunction = createFunctionStore();
-
-export const createFunctionDeployment = writable();
-
-export const templateStepsComponents: Writable = writable(new Map());
diff --git a/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.svelte b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.svelte
new file mode 100644
index 000000000..95058fa9d
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.svelte
@@ -0,0 +1,361 @@
+
+
+
+ Create function - Appwrite
+
+
+
+
+
+ {#if selectedRepository && showConfig}
+
+
+
+
+
+ {#if data.template.variables?.length}
+
+ {/if}
+
+ {:else}
+ {@const options = availableRuntimes.map((runtime) => {
+ return {
+ value: runtime.$id,
+ label: `${runtime.name} - ${runtime.version}`,
+ leadingHtml: ` `
+ };
+ })}
+
+
+
+
+
+
+
+
+ {#if connectBehaviour === 'now'}
+ {#if hasInstallations}
+
+
+
+ {#if repositoryBehaviour === 'new'}
+
+
+
+
+
+ Create
+
+
+ {:else}
+ {
+ trackEvent(Click.ConnectRepositoryClick, {
+ from: 'template-wizard'
+ });
+ repository.set(e.detail);
+ repositoryName = e.detail.name;
+ selectedRepository = e.detail.id;
+ showConfig = true;
+ }} />
+ {/if}
+
+
+ {:else}
+
+
+
+
+
+ Connect to GitHub
+
+
+
+
+ {/if}
+ {:else if data.template.variables?.length}
+
+ {/if}
+ {/if}
+
+
+
+
+
+
+ {data.template.name}
+
+
+ {data.template.tagline}
+
+
+
+
+
+
+ (showExitModal = true)}>
+ Cancel
+
+ formComponent.triggerSubmit()}
+ disabled={$isSubmitting || (connectBehaviour === 'now' && !selectedRepository)}>
+ Deploy
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.ts b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.ts
new file mode 100644
index 000000000..0756c7b62
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.ts
@@ -0,0 +1,13 @@
+import { sdk } from '$lib/stores/sdk';
+
+export const load = async ({ parent, params }) => {
+ let { installations, runtimesList, specificationsList } = await parent();
+ const template = await sdk.forProject.functions.getTemplate(params.template);
+
+ return {
+ installations,
+ template,
+ runtimesList,
+ specificationsList
+ };
+};
diff --git a/src/routes/(console)/project-[project]/functions/create-function/template-[template]/configuration.svelte b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/configuration.svelte
new file mode 100644
index 000000000..05f247c76
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/configuration.svelte
@@ -0,0 +1,157 @@
+
+
+
+
+
+ {#if requiredVariables?.length}
+
+
+ {#each requiredVariables as variable, i}
+
+
+
+
+
+
+
+ {
+ e.preventDefault();
+ toggle(e);
+ }}>
+
+ {@html variable.description}
+
+
+
+ {/each}
+
+
+ {/if}
+ {#if optionalVariables?.length}
+
+
+ {#each optionalVariables as variable, i}
+
+
+
+
+
+
+
+ {
+ e.preventDefault();
+ toggle(e);
+ }}>
+
+
+ {@html variable.description}
+
+
+
+ {/each}
+
+
+ {/if}
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/create-function/template-[template]/permissions.svelte b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/permissions.svelte
new file mode 100644
index 000000000..f17aae982
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/permissions.svelte
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+ {#if scopeList.length > 0}
+ {#each scopeList as scope}
+ {
+ selectedScopes = scopeList
+ .filter((s) => s.checked)
+ .map((s) => s.value.scope);
+ }}>
+
+ {/each}
+ {/if}
+
+
diff --git a/src/routes/(console)/project-[project]/functions/create-function/template-[template]/repoCard.svelte b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/repoCard.svelte
new file mode 100644
index 000000000..1d989f087
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/repoCard.svelte
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+ {$repository.organization}/{$repository.name}
+
+
+ {
+ showConfig = false;
+ }}>
+ Update
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/connectExisting.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/connectExisting.svelte
deleted file mode 100644
index 757f7a41a..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/connectExisting.svelte
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/createGit.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/createGit.svelte
deleted file mode 100644
index 4ee360e9a..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/createGit.svelte
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/createManual.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/createManual.svelte
deleted file mode 100644
index ad7225ee4..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/createManual.svelte
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/createTemplate.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/createTemplate.svelte
deleted file mode 100644
index 11107b9ef..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/createTemplate.svelte
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/createRepository.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/createRepository.svelte
deleted file mode 100644
index ef3b6d452..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/createRepository.svelte
+++ /dev/null
@@ -1,173 +0,0 @@
-
-
-
- Repository
-
- Select a Git repository that will trigger your function deployments when updated.
-
-
- {#if $templateConfig.repositoryBehaviour === 'existing'}
-
- {:else}
- {#await loadInstallations()}
-
- {:then installations}
- {#if hasInstallations}
-
- {
- return {
- label: entry.organization,
- value: entry.$id
- };
- })}
- on:change={() => {
- $installation = installations.find(
- (entry) => entry.$id === selectedInstallationId
- );
- }}
- bind:value={selectedInstallationId} />
-
- {:else}
-
-
-
- GitHub
-
-
-
- GitLab (coming soon)
-
-
-
- BitBucket (coming soon)
-
-
-
- Azure (coming soon)
-
-
- {/if}
- {#if $installation}
-
-
-
-
-
-
-
- {$installation.organization}/{$templateConfig.repositoryName}
-
-
-
-
-
-
-
-
-
-
- {/if}
- {/await}
- {/if}
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/executeAccess.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/executeAccess.svelte
deleted file mode 100644
index 5d6442f79..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/executeAccess.svelte
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
- Permissions
-
- Choose who can execute this function using the client API. For more information, visit our
-
- Permissions guide .
-
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/functionConfiguration.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/functionConfiguration.svelte
deleted file mode 100644
index 3ee7ee35d..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/functionConfiguration.svelte
+++ /dev/null
@@ -1,120 +0,0 @@
-
-
-
- Configuration
-
- Set your deployment configuration and any build commands here.
-
-
-
- {#if !showCustomId}
-
-
(showCustomId = !showCustomId)}>
-
- Function ID
-
-
- {:else}
-
- {/if}
-
- {#if detectingRuntime}
-
- {:else}
-
- {/if}
-
-
-
-
- Build commands
- (optional)
-
-
-
-
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/gitConfiguration.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/gitConfiguration.svelte
deleted file mode 100644
index f0b9c9e47..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/gitConfiguration.svelte
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-
- Branch
-
- Choose the Git branch that will trigger your function deployments when updated.
-
-
-
-
-
-
{$installation.organization}/{$repository.name}
-
- {#await loadBranches()}
-
- {:then branches}
- {@const options =
- branches
- ?.map((branch) => {
- return {
- value: branch.name,
- label: branch.name
- };
- })
- ?.sort((a, b) => {
- return a.label > b.label ? 1 : -1;
- }) ?? []}
-
-
- {
- $choices.branch = event.detail.value;
- }}
- interactiveOutput
- name="branch"
- {options} />
-
-
-
-
- {/await}
-
-
- Visit your repository on GitHub .
-
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/manualConfiguration.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/manualConfiguration.svelte
deleted file mode 100644
index 2334025af..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/manualConfiguration.svelte
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
- Configuration
-
- Set your deployment configuration and any build commands here.
-
-
-
-
-
-
-
- Build commands
- (optional)
-
-
-
-
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/manualDetails.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/manualDetails.svelte
deleted file mode 100644
index 30c5fdea2..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/manualDetails.svelte
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
- Details
- Create and deploy your function manually.
-
-
-
-
-
- {#if !showCustomId}
-
-
(showCustomId = !showCustomId)}>
-
- Function ID
-
-
- {:else}
-
- {/if}
-
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/selectRepository.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/selectRepository.svelte
deleted file mode 100644
index e766c24ce..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/selectRepository.svelte
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
- Repository
-
- Select a Git repository that will trigger your function deployments when updated.
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/templateConfiguration.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/templateConfiguration.svelte
deleted file mode 100644
index 63cbdbeb4..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/templateConfiguration.svelte
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
- {$template.name}
-
- {$template.tagline}
-
-
-
- {#await loadRuntimes()}
-
- {:then options}
-
- {/await}
-
-
-
- {#if !showCustomId}
-
-
(showCustomId = !showCustomId)}>
-
- Function ID
-
-
- {:else}
-
- {/if}
-
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/templateDeployment.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/templateDeployment.svelte
deleted file mode 100644
index 718262933..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/templateDeployment.svelte
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
- Deployment
-
- Connect with Git Recommended
-
-
- Create a new repository
- Clone the template to a newly created repository in your organization.
-
-
- Add to existing repository
- Clone the template to an existing repository in your organization.
-
-
- Quick start
-
- Connect later
- Deploy now and continue development via CLI, or connect Git from your function settings.
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/templatePermissions.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/templatePermissions.svelte
deleted file mode 100644
index e283d36d2..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/templatePermissions.svelte
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
- Permissions
-
- Enable recommended scopes and execute access for when your function is deployed.
-
- Execute permissions
-
-
-
-
-
-
-
-
- Public (anyone can execute)
- You can further customize execute permissions in your function
- settings.
-
-
-
- This could include unauthorized users and bots.
-
-
-
-
-
-
-
- {#if templateScopes.length > 0}
- Function scopes
-
- {#each templateScopes as scope, i}
-
-
-
-
-
-
-
{scope.scope}
-
{scope.description}
-
-
-
-
-
- {#if i < templateScopes.length - 1}
-
- {/if}
- {/each}
-
- {/if}
-
diff --git a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/templateVariables.svelte b/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/templateVariables.svelte
deleted file mode 100644
index eea61b616..000000000
--- a/src/routes/(console)/project-[project]/functions/create-function/wizard/steps/templateVariables.svelte
+++ /dev/null
@@ -1,124 +0,0 @@
-
-
-
- Variables
-
- Edit the values of the environment variables that will be passed to your function at
- runtime.
-
- {#if $template?.variables?.length}
- {#if requiredVariables?.length}
-
-
- Required variables
-
- {requiredVariables.length}
-
-
-
- {#each requiredVariables as variable}
-
-
-
- {@html variable.description}
-
-
- {/each}
-
-
-
- {/if}
-
- {#if optionalVariables?.length}
-
-
- Optional variables
-
- {optionalVariables.length}
-
-
-
- {#each optionalVariables as variable}
-
-
-
-
- {@html variable.description}
-
-
- {/each}
-
-
-
- {/if}
- {:else}
-
- There are no environment variables to configure.
-
- {/if}
-
diff --git a/src/routes/(console)/project-[project]/functions/createFunction.svelte b/src/routes/(console)/project-[project]/functions/createFunction.svelte
index 5b77b60d7..33fdf8c25 100644
--- a/src/routes/(console)/project-[project]/functions/createFunction.svelte
+++ b/src/routes/(console)/project-[project]/functions/createFunction.svelte
@@ -54,6 +54,7 @@
type: 'success'
});
trackEvent(Submit.FunctionCreate, {
+ runtime: $createFunction.runtime,
customId: !!$createFunction.id
});
wizard.hide();
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/(components)/createActionMenu.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(components)/createActionMenu.svelte
new file mode 100644
index 000000000..fbf3cdd81
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/(components)/createActionMenu.svelte
@@ -0,0 +1,49 @@
+
+
+
+ {#if $canWriteFunctions}
+
+ {/if}
+
+
+ {
+ showCreateGit = true;
+ toggle(e);
+ }}>
+ Git
+
+ {
+ showCreateCli = true;
+ toggle(e);
+ }}>
+ CLI
+
+ {
+ showCreateManual = true;
+ toggle(e);
+ }}>
+ Manual
+
+
+
+
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/(components)/deploymentCard.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(components)/deploymentCard.svelte
new file mode 100644
index 000000000..64149f024
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/(components)/deploymentCard.svelte
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+ {#if activeDeployment}
+
+ Active deployment
+
+
+
+ {deployment.$id}
+
+
+ {:else}
+
+ Deployment overview
+
+ {/if}
+
+
+
+
+
+
+ Domains
+
+
+
+
+
+
+
+ {#if deployment.status === 'failed'}
+
+
+ Status
+
+
+
+
+
+ {:else}
+
+
+ Deployed
+
+
+
+
+
+ {/if}
+
+
+
+
+ {#if deployment?.buildDuration}
+
+
+ Build duration
+
+
+ {formatTimeDetailed(deployment.buildDuration)}
+
+
+ {/if}
+
+
+ Total size
+
+
+ {totalSize.value}{totalSize.unit}
+
+
+
+
+ Runtime
+
+
+
+
+ {capitalize($func.runtime)}
+
+
+
+
+
+
+
+ Source
+
+
+
+
+
+
+
+
+
+
+ {#if $$slots.footer}
+
+
+
+
+
+
+ {/if}
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/(components)/downloadActionMenuItem.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(components)/downloadActionMenuItem.svelte
new file mode 100644
index 000000000..0a2b6850a
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/(components)/downloadActionMenuItem.svelte
@@ -0,0 +1,55 @@
+
+
+{#if deployment?.status === 'ready' || deployment?.status === 'failed'}
+
+
+ Download
+
+
+
+
+ Download source
+
+
+
+ Download output
+
+
+
+
+{/if}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/activate.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/activateModal.svelte
similarity index 66%
rename from src/routes/(console)/project-[project]/functions/function-[function]/activate.svelte
rename to src/routes/(console)/project-[project]/functions/function-[function]/(modals)/activateModal.svelte
index 69aefb446..5ea77ed0a 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/activate.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/activateModal.svelte
@@ -1,6 +1,6 @@
-
- Are you sure you want to activate this deployment?
+
+ This deployment is ready but not yet live. Activate it to make it publicly accessible.
(showActivate = false)}>Cancel
- Activate
+ Activate
-
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/cancel.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/cancel.svelte
similarity index 95%
rename from src/routes/(console)/project-[project]/functions/function-[function]/cancel.svelte
rename to src/routes/(console)/project-[project]/functions/function-[function]/(modals)/cancel.svelte
index f8755a75d..341710b2a 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/cancel.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/cancel.svelte
@@ -13,7 +13,7 @@
async function handleSubmit() {
try {
- await sdk.forProject.functions.updateDeploymentBuild(
+ await sdk.forProject.functions.updateDeploymentStatus(
selectedDeployment.resourceId,
selectedDeployment.$id
);
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/connectRepoModal.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/connectRepoModal.svelte
new file mode 100644
index 000000000..9709f8bf1
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/connectRepoModal.svelte
@@ -0,0 +1,150 @@
+
+
+
+
+ Connect your function to an existing repository or create a new one.
+
+ {#if hasInstallations}
+
+
+ {#if repositoryBehaviour === 'new'}
+
+ {:else}
+ {
+ trackEvent(Click.ConnectRepositoryClick, {
+ from: 'functions'
+ });
+ repository.set(e.detail);
+ repositoryName = e.detail.name;
+ selectedRepository = e.detail.id;
+ connectRepo();
+ }} />
+ {/if}
+
+ {:else}
+
+ {/if}
+
+ {#if repositoryBehaviour === 'existing'}
+
+
+
+ Missing a repository? check your permissions
+
+
+
+ {:else if repositoryBehaviour === 'new'}
+ (show = false)}>Cancel
+
+ Create
+
+ {/if}
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/createCli.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createCli.svelte
similarity index 95%
rename from src/routes/(console)/project-[project]/functions/function-[function]/createCli.svelte
rename to src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createCli.svelte
index d745ccc0e..cd9ad7839 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/createCli.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createCli.svelte
@@ -1,11 +1,12 @@
-
+
Are you sure you want to redeploy {$func.name} ? Redeploying may affect your
production code.
@@ -47,4 +47,4 @@
(show = false)}>Cancel
Redeploy
-
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/+layout.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/+layout.svelte
index 922bb922c..8dca78429 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/+layout.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/+layout.svelte
@@ -10,6 +10,14 @@
import type { Models } from '@appwrite.io/console';
import { base } from '$app/paths';
import { canWriteFunctions } from '$lib/stores/roles';
+ import {
+ IconCalendar,
+ IconClock,
+ IconList,
+ IconPlus,
+ IconSearch,
+ IconXCircle
+ } from '@appwrite.io/pink-icons-svelte';
onMount(() => {
let previousStatus = null;
@@ -48,7 +56,7 @@
},
keys: $page.url.pathname.endsWith($func.$id) ? ['c'] : ['c', 'd'],
group: 'functions',
- icon: 'plus',
+ icon: IconPlus,
disabled: !$canWriteFunctions
},
{
@@ -59,7 +67,7 @@
);
scrollBy({ top: -100 });
},
- icon: 'search',
+ icon: IconSearch,
group: 'functions',
disabled: !$canWriteFunctions
},
@@ -71,7 +79,7 @@
);
scrollBy({ top: -100 });
},
- icon: 'calendar',
+ icon: IconCalendar,
group: 'functions',
disabled: !$canWriteFunctions
},
@@ -82,7 +90,7 @@
`${base}/project-${$project.$id}/functions/function-${$func.$id}/settings#variables`
);
},
- icon: 'list',
+ icon: IconList,
group: 'functions',
disabled: !$canWriteFunctions
},
@@ -93,7 +101,7 @@
`${base}/project-${$project.$id}/functions/function-${$func.$id}/settings#timeout`
);
},
- icon: 'x-circle',
+ icon: IconXCircle,
group: 'functions',
disabled: !$canWriteFunctions
},
@@ -105,7 +113,7 @@
);
scrollBy({ top: -100 });
},
- icon: 'clock',
+ icon: IconClock,
group: 'functions',
disabled: !$canWriteFunctions
},
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/+layout.ts b/src/routes/(console)/project-[project]/functions/function-[function]/+layout.ts
index 576a7b9e1..e57eeef3b 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/+layout.ts
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/+layout.ts
@@ -1,4 +1,4 @@
-import { sdk } from '$lib/stores/sdk';
+import { DeploymentResourceType, sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import type { LayoutLoad } from './$types';
import Breadcrumbs from './breadcrumbs.svelte';
@@ -12,13 +12,15 @@ export const load: LayoutLoad = async ({ params, depends }) => {
depends(Dependencies.DEPLOYMENTS);
try {
- const [func, proxyRuleList] = await Promise.all([
- sdk.forProject.functions.get(params.function),
- sdk.forProject.proxy.listRules([
- Query.equal('type', RuleType.DEPLOYMENT),
- Query.equal('automation', `function=${params.function}`),
- Query.limit(1)
- ])
+ const func = await sdk.forProject.functions.get(params.function);
+
+ //TODO remove rule limit of 1 and display extra rules
+ const proxyRuleList = await sdk.forProject.proxy.listRules([
+ Query.equal('type', RuleType.DEPLOYMENT),
+ Query.equal('deploymentResourceType', DeploymentResourceType.FUNCTION),
+ Query.equal('deploymentResourceId', params.function),
+ Query.equal('deploymentId', func.deploymentId),
+ Query.limit(1)
]);
return {
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte
index 4721a139f..5f8b2862c 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte
@@ -1,27 +1,31 @@
-
-
-
{#if !data?.deploymentList?.total && !data?.query}
-
-
-
Create your first deployment to get started.
-
- Learn more about deployments in our Documentation.
-
-
-
- Documentation
-
-
-
- {:else}
- {@const activeDeployment = data.activeDeployment}
-
-
- Active
-
- {#if data?.activeDeployment && !$func.live && showAlert}
- (showAlert = false)}>
- Some configuration options are not live yet. Redeploy your function to apply latest
- changes.
-
- {/if}
- {#if activeDeployment}
-
-
-
-
- Build logs
-
- {#if $canWriteFunctions}
- {
- selectedDeployment = activeDeployment;
- showRedeploy = true;
- }}>
- Redeploy
-
- {/if}
-
- Execute
-
-
-
-
- {:else if !$deploymentList.total && !data?.query}
-
-
-
Create your first deployment to get started.
-
- Learn more about deployments in our Documentation.
-
-
-
+
+
+ Need a hand? Learn more in our documentation
+
Documentation
-
-
-
- {:else}
-
-
-
-
-
-
- Add a new deployment, or activate an existing one to see your function in
- action. Learn more about deployments in our
- documentation .
-
-
+
+
+ Create deployment
+
+
+
+
+ {:else}
+ {@const activeDeployment = data.activeDeployment}
+
+ {#if data?.activeDeployment && !$func.live && showAlert}
+ (showAlert = false)}>
+ Some configuration options are not live yet. Redeploy your function to apply latest
+ changes.
+
{/if}
-
-
All deployments
-
-
-
-
-
+
+ {#if activeDeployment}
+
+
+
+
+
+
+
+
+
+ {#if $canWriteFunctions}
+ {
+ selectedDeployment = activeDeployment;
+ showRedeploy = true;
+ trackEvent(Click.FunctionsRedeployClick);
+ toggle();
+ }}>
+ Redeploy
+
+ {/if}
+
+
+ Build logs
+
+
+
+
-
- More filters
+ secondary
+ href={`${base}/project-${$page.params.project}/functions/function-${$func.$id}/executions/execute-function`}
+ disabled={isCloud && $readOnly && !GRACE_PERIOD_OVERRIDE}>
+ Execute
- {#if $tags?.length}
-
-
- Clear all
+
+
+
+ {:else if data.activeDeployment?.status === 'building'}
+
+
+
+ Your build is running. When it completes, this page will automatically
+ update with the latest deployment.
+
+
+ Documentation
+
+ View logs
+
+
+
+ {:else}
+
+
+
+ Deploy your function to get started. Once deployed, you'll see your
+ latest build details here.
+
+
+ Documentation
+
+
+ Create deployment
+
+
+
+
+
+ {/if}
+
+
+
+
+
+ {#if data.deploymentList.total}
+
{/if}
-
-
-
-
-
-
-
-
-
-
(showMobileFilters = !showMobileFilters)}
- ariaLabel="toggle filters"
- noMargin>
-
- Filters
-
+
+
+ {#if data.deploymentList.total}
+
+ {/if}
+
+
+
+ Create deployment
+
+
+
+
+
+
-
-
-
-
+ {#if data.deploymentList.total}
+
+ {:else if data?.query}
+
+ {/if}
-
-
-
-
- More filters
-
-
-
-
-
-
-
- {#if $deploymentList.total}
-
- {:else if data?.query}
-
-
-
-
Sorry we couldn't find any deployments
-
There are no deployments that match your filters.
-
-
- Clear filters
-
-
-
- {/if}
+ {#if $deploymentList.total}
+
+ {/if}
+
+
{/if}
-
-
{#if selectedDeployment}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/+page.ts
index 02b02627d..7dd08f194 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/+page.ts
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/+page.ts
@@ -19,10 +19,10 @@ export const load: PageLoad = async ({ params, depends, url, route, parent }) =>
offset,
limit,
query,
- activeDeployment: data.function.deployment
+ activeDeployment: data.function.deploymentId
? await sdk.forProject.functions.getDeployment(
params.function,
- data.function.deployment
+ data.function.deploymentId
)
: null,
deploymentList: await sdk.forProject.functions.listDeployments(params.function, [
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/create.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/create.svelte
deleted file mode 100644
index 1f736b149..000000000
--- a/src/routes/(console)/project-[project]/functions/function-[function]/create.svelte
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
- {#if $canWriteFunctions}
- (show = !show)} event="create_deployment">
-
- {#if !secondary}
-
- {/if}
- Create deployment
-
-
- {/if}
-
- {
- showCreateGit = true;
- show = false;
- }}>Git
- {
- showCreateCli = true;
- show = false;
- }}>CLI
- {
- showCreateManual = true;
- show = false;
- }}>Manual
-
-
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte
index 4815cd33e..e6d26d0a9 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte
@@ -1,21 +1,21 @@
-
-
-
- {#if $deployment.status === 'processing' || $deployment.status === 'building' || $deployment.status === 'waiting'}
+
+
+
+ {#if data.deployment.status === 'processing' || data.deployment.status === 'building' || data.deployment.status === 'waiting'}
{
@@ -88,81 +92,57 @@
}}>Cancel
{/if}
- {#if $deployment.size > 0}
- Download code
+ {#if data.deployment.sourceSize > 0}
+ Download
{/if}
- {#if $func.deployment !== $deployment.$id && $deployment.status === 'ready'}
+ {#if data.func.deploymentId !== data.deployment.$id && data.deployment.status === 'ready'}
{
showActivate = true;
}}>Activate
{/if}
-
+
-
-
-
-
-
Build {$func.name}
- {#if $deployment.status === 'building'}
-
Building...
+
+
+
+ {#key data.deployment.buildLogs}
+
+ {/key}
+
+
+
+
+ {#if ['processing', 'building'].includes(data.deployment.status)}
+
+
+
+
+
+
{:else}
- {$deployment.status}
+
+ {formatTimeDetailed(data.deployment.buildDuration)}
+
{/if}
-
-
-
-
-
- codePanelContent?.scrollTo({ top: 0, behavior: 'smooth' })}>
- Scroll to top
-
-
-
-
-
-
- {#if !data.activeDeployment}
-
- Delete deployment
- The deployment will be permanently deleted, including all data associated with it. This action
- is irreversible.
-
-
- Last updated: {toLocaleDateTime($func.$updatedAt)}
-
+
-
- (showDelete = true)}>Delete
-
-
- {/if}
+
+
-
-
-
-
-
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.ts
index bb5cd33b0..374b96fd6 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.ts
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.ts
@@ -12,7 +12,8 @@ export const load: PageLoad = async ({ params, depends, parent }) => {
);
return {
+ func,
deployment,
- activeDeployment: func.deployment === params.deployment
+ activeDeployment: func.deploymentId === params.deployment
};
};
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/deploymentCard.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/deploymentCard.svelte
deleted file mode 100644
index a87c83a90..000000000
--- a/src/routes/(console)/project-[project]/functions/function-[function]/deploymentCard.svelte
+++ /dev/null
@@ -1,118 +0,0 @@
-
-
-
-
-
-
-
-
-
Deployment ID
-
-
- {deployment.$id}
-
-
-
-
- {@const status = deployment.status}
- {@const deploymentSize = humanFileSize(deployment.size)}
- {@const buildSize = humanFileSize(deployment.buildSize)}
- {@const totalSize = humanFileSize(deployment.buildSize + deployment.size)}
-
-
- Status
-
-
-
-
- {status === 'ready' ? 'active' : status}
-
-
-
-
-
- Build time
-
- {calculateTime(deployment.buildTime)}
-
-
-
- Total size
-
- {totalSize.value + totalSize.unit}
-
-
-
-
-
-
- Deployment size:
- {deploymentSize.value + deploymentSize.unit}
-
-
Build size: {buildSize.value + buildSize.unit}
-
-
-
-
-
- Updated
-
-
-
-
-
-
-
-
- {#if $proxyRuleList?.rules?.length}
-
- {/if}
-
-
-
-
-
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/deploymentCreatedBy.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/deploymentCreatedBy.svelte
deleted file mode 100644
index 35999e161..000000000
--- a/src/routes/(console)/project-[project]/functions/function-[function]/deploymentCreatedBy.svelte
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
- {#if deployment.providerCommitAuthor}
-
-
- {capitalize(timeFromNow(deployment.$updatedAt))}
-
- {toLocaleDateTime(deployment.$updatedAt)}
-
- by {deployment.providerCommitAuthor}
- {:else}
-
- {/if}
-
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/deploymentDomains.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/deploymentDomains.svelte
deleted file mode 100644
index bd441f17c..000000000
--- a/src/routes/(console)/project-[project]/functions/function-[function]/deploymentDomains.svelte
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
- {domain.rules[0].domain}
-
-
-
-
- {#if domain.rules.length > 1}
-
- (showDropdown = !showDropdown)}>
- +{domain.rules.length - 1}
-
-
- {#each domain.rules as rule, i}
- {#if i !== 0}
-
- {rule.domain}
-
- {/if}
- {/each}
-
-
- {/if}
-
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/deploymentSource.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/deploymentSource.svelte
deleted file mode 100644
index c81332f21..000000000
--- a/src/routes/(console)/project-[project]/functions/function-[function]/deploymentSource.svelte
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-{#if deployment.type === 'vcs'}
-
- (showDropdown = !showDropdown)}
- type="button"
- class="u-flex u-gap-4 u-cross-center">
- GitHub
-
-
-
-
-
- {deployment.providerRepositoryOwner}/{deployment.providerRepositoryName}
-
-
-
-
- {deployment.providerBranch}
-
- {#if deployment?.providerCommitMessage && deployment?.providerCommitHash && deployment?.providerCommitUrl}
-
-
-
- {deployment?.providerCommitHash?.substring(0, 7)}
- {deployment.providerCommitMessage}
-
-
-
- {/if}
-
-
-{:else if deployment.type === 'manual'}
- Manual
-{:else if deployment.type === 'cli'}
- CLI
-{/if}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.svelte
index 603219642..49dc87dab 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.svelte
@@ -1,14 +1,198 @@
-
- Domains
-
+
+
+
+ {
+ toggle(event);
+ trackEvent(Click.DomainCreateClick, {
+ source: 'functions_domain_overview'
+ });
+ }}>
+
+ Add domain
+
+
+
+
+ Custom domain
+
+ (showPreviewDomainModal = true)}>
+ Preview domain
+
+
+
+
+
+
+ {#if data.domains.total}
+
+
+ Domain
+ Redirect to
+ Production branch
+
+
+ {#each data.domains.rules as domain}
+
+
+
+
+ {domain.domain}
+
+
+
+
+
+ {domain?.redirectUrl || 'No redirect'}
+ {domain?.redirectStatusCode ? `(${domain.redirectStatusCode})` : ''}
+
+
+ {domain.deploymentVcsProviderBranch || '-'}
+
+
+
+
+ {
+ e.preventDefault();
+ toggle(e);
+ }}>
+
+
+
+
+
+ {#if domain.status !== 'verified'}
+ {
+ e.preventDefault();
+ selectedDomain = domain;
+ showRetry = true;
+ toggle(e);
+ }}>
+ Retry
+
+ {/if}
+ {
+ e.preventDefault();
+ selectedDomain = domain;
+ showDelete = true;
+ toggle(e);
+ trackEvent(Click.DomainDeleteClick, {
+ source: 'functions_domain_overview'
+ });
+ }}>
+ Delete
+
+
+
+
+
+
+
+ {/each}
+
+
+
+ {:else if data?.search}
+
+
+ {
+ data.search = '';
+ }}>Clear search
+
+
+ {:else}
+
+
+
+ Documentation
+
+
+ Add domain
+
+
+
+
+ {/if}
+
+{#if showDelete}
+
+{/if}
+
+{#if showRetry}
+
+{/if}
+
+{#if showPreviewDomainModal}
+
+{/if}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.ts
index d6fb50833..8f39e94d8 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.ts
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.ts
@@ -1,15 +1,43 @@
import { Dependencies } from '$lib/constants';
-import { RuleType, sdk } from '$lib/stores/sdk';
+import { RuleType, DeploymentResourceType, RuleTrigger, sdk } from '$lib/stores/sdk';
import { Query } from '@appwrite.io/console';
import type { PageLoad } from './$types';
+import { getPage } from '$lib/helpers/load';
+import { getLimit } from '$lib/helpers/load';
+import { pageToOffset } from '$lib/helpers/load';
+import { getQuery } from '$lib/helpers/load';
+import { getSearch } from '$lib/helpers/load';
+import { queries, queryParamToMap } from '$lib/components/filters';
+import { PAGE_LIMIT } from '$lib/constants';
-export const load: PageLoad = async ({ depends, params }) => {
+export const load: PageLoad = async ({ depends, params, url, route }) => {
depends(Dependencies.FUNCTION_DOMAINS);
+ const page = getPage(url);
+ const limit = getLimit(url, route, PAGE_LIMIT);
+ const offset = pageToOffset(page, limit);
+ const query = getQuery(url);
+ const search = getSearch(url);
+
+ const parsedQueries = queryParamToMap(query || '[]');
+ queries.set(parsedQueries);
return {
- rules: await sdk.forProject.proxy.listRules([
- Query.equal('type', RuleType.DEPLOYMENT),
- Query.equal('automantion', `function=${params.function}`)
- ])
+ offset,
+ limit,
+ query,
+ search,
+ domains: await sdk.forProject.proxy.listRules(
+ [
+ Query.equal('type', [RuleType.DEPLOYMENT, RuleType.REDIRECT]),
+ Query.equal('deploymentResourceType', DeploymentResourceType.FUNCTION),
+ Query.equal('deploymentResourceId', params.function),
+ Query.equal('trigger', RuleTrigger.MANUAL),
+ Query.limit(limit),
+ Query.offset(offset),
+ Query.orderDesc(''),
+ ...parsedQueries.values()
+ ],
+ search || undefined
+ )
};
};
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.svelte
new file mode 100644
index 000000000..fba7380f8
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.svelte
@@ -0,0 +1,296 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Connect this domain to your active deployment and configure the linked Git
+ branch as needed.
+
+
+ Automatically forward traffic from this domain to another URL of your choice.
+
+
+
+ {#if behaviour === 'CREATE'}
+
+
+ {#if data.branches?.total}
+ {@const sortedBranches = sortBranches(data.branches.branches)}
+ {@const options = sortedBranches.map((branch) => ({
+ label: branch.name,
+ value: branch.name
+ }))}
+
+ {:else}
+
+
+
+
+
+ The domain will be connected to your active deployment.
+ Connect your Git repository to link a production branch.
+
+
+ (showConnectRepo = true)}>
+ Connect repository
+
+
+
+
+ {/if}
+
+
+
+
+ {:else if behaviour === 'REDIRECT'}
+
+
+
+
+
+
+ Redirect this domain. Domains added to your project will be
+ listed here.
+
+
+
+
+
+
+ {/if}
+
+
+
+ Cancel
+ formComponent.triggerSubmit()} bind:disabled={$isSubmitting}>
+ Add
+
+
+
+
+{#if showConnectRepo}
+
+{/if}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.ts
new file mode 100644
index 000000000..1105f8445
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.ts
@@ -0,0 +1,28 @@
+import { Query } from '@appwrite.io/console';
+import { sdk } from '$lib/stores/sdk';
+import { RuleTrigger, RuleType } from '$lib/stores/sdk';
+
+export const load = async ({ parent }) => {
+ const { site } = await parent();
+
+ const [domains, installations] = await Promise.all([
+ sdk.forProject.proxy.listRules([
+ Query.equal('type', RuleType.DEPLOYMENT),
+ Query.equal('trigger', RuleTrigger.MANUAL)
+ ]),
+ sdk.forProject.vcs.listInstallations()
+ ]);
+
+ return {
+ site,
+ domains,
+ installations,
+ branches:
+ site?.installationId && site?.providerRepositoryId
+ ? await sdk.forProject.vcs.listRepositoryBranches(
+ site.installationId,
+ site.providerRepositoryId
+ )
+ : undefined
+ };
+};
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.svelte
new file mode 100644
index 000000000..88289f579
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.svelte
@@ -0,0 +1,182 @@
+
+
+
+ {#if isVerified}
+
+
+ {data.domain.domain}
+
+
+
+ {:else}
+
+
+
+
+ (selectedTab = 'cname')}
+ active={selectedTab === 'cname'}>
+ CNAME
+
+ (selectedTab = 'nameserver')}
+ active={selectedTab === 'nameserver'}>
+ Nameservers
+
+
+
+
+ {#if selectedTab === 'cname'}
+
+
+ {data.domain?.domain}
+ {#if isVerified}
+
+ {:else}
+
+ {/if}
+
+
+ Add the following record on your DNS provider. Note that DNS changes may
+ take time to propagate fully.
+
+
+
+
+
+ Type
+ Name
+ Value
+
+
+ CNAME
+ {data.domain?.domain}
+
+
+ {globalThis?.location?.origin}
+
+
+
+
+
+
+ A list of all domain providers and their DNS setting is available here.
+
+
+
+
+
+ Verify
+
+ {:else}
+
+
+ {data.domain?.domain}
+
+
+
+ Add the following nameservers on your DNS provider. Note that DNS
+ changes may take time to propagate fully.
+
+
+
+
+
+ Type
+ Value
+
+ {#each nameservers as nameserver}
+
+ NS
+
+
+ {nameserver}
+
+
+ {/each}
+
+
+
+
+
+ Verify
+
+ {/if}
+
+
+ {/if}
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.ts
new file mode 100644
index 000000000..eab359a42
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.ts
@@ -0,0 +1,16 @@
+import { sdk } from '$lib/stores/sdk';
+import { isCloud } from '$lib/system';
+
+export const load = async ({ params }) => {
+ if (isCloud) {
+ // if (params?.id) {
+ // return {
+ // domain: await sdk.forConsole.domains.get(params.id)
+ // };
+ // }
+ } else {
+ return {
+ domain: undefined
+ };
+ }
+};
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/createPreviewDomainModal.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/createPreviewDomainModal.svelte
new file mode 100644
index 000000000..16f87952e
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/createPreviewDomainModal.svelte
@@ -0,0 +1,104 @@
+
+
+
+
+ Get an auto-generated domain to quickly access your project. You can customize its prefix.
+
+
+
+
+
+
+
+ .{$consoleVariables._APP_DOMAIN_TARGET}
+
+
+
+
+
+
+
+
+ (show = false)}>Cancel
+ Add
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/deleteDomainModal.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/deleteDomainModal.svelte
new file mode 100644
index 000000000..cbfc54944
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/deleteDomainModal.svelte
@@ -0,0 +1,54 @@
+
+
+
+ {#if selectedDomain}
+
+ Are you sure you want to delete this domain? You will no longer be able to execute your
+ function by visiting:
+
+
+ {selectedDomain.domain}
+
+ {/if}
+
+
+ (show = false)}>Cancel
+ Delete
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/recordsCard.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/recordsCard.svelte
new file mode 100644
index 000000000..23beba2cd
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/recordsCard.svelte
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+ {domain?.domain}
+
+
+
+ Add the following nameservers on your DNS provider. Note that DNS changes may
+ take time to propagate fully.
+
+
+
+
+
+ Type
+ Name
+ Value
+
+
+ CNAME
+ {domain?.domain}
+
+ {globalThis?.location?.origin}
+
+
+
+
+
+
+ A list of all domain providers and their DNS setting is available here.
+
+
+
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/retryDomainModal.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/retryDomainModal.svelte
new file mode 100644
index 000000000..0afc74175
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/retryDomainModal.svelte
@@ -0,0 +1,46 @@
+
+
+
+ {#if selectedDomain}
+
+ {/if}
+
+
+ (show = false)}>Cancel
+ Retry
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/(components)/LogsRequest.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/(components)/LogsRequest.svelte
new file mode 100644
index 000000000..71fee3b9a
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/(components)/LogsRequest.svelte
@@ -0,0 +1,114 @@
+
+
+
+
+
+ (requestTab = 'parameters')}>
+ Parameters
+
+
+ (requestTab = 'headers')}>
+ Headers
+
+
+
+
+ {#if requestTab === 'parameters'}
+ {#if parameters?.length}
+
+
+ Key
+ Value
+
+ {#each parameters as parameter}
+
+ {parameter.name}
+ {parameter.value}
+
+ {/each}
+
+ {:else}
+
+ No parameters found.
+
+ {/if}
+ {:else if requestTab === 'headers'}
+ {#if selectedLog.requestHeaders?.length}
+
+
+ Key
+ Value
+
+ {#each selectedLog.requestHeaders as request}
+
+ {request.name}
+ {request.value}
+
+ {/each}
+
+
+
+
+ Missing headers? Check the docs to
+ see the supported data and how to log it.
+
+
+ {:else}
+
+ No headers found.
+
+ {/if}
+ {/if}
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/(components)/LogsResponse.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/(components)/LogsResponse.svelte
new file mode 100644
index 000000000..82e204396
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/(components)/LogsResponse.svelte
@@ -0,0 +1,127 @@
+
+
+
+
+
+ (responseTab = 'logs')}>
+ Logs
+
+ (responseTab = 'errors')}>
+ Errors
+
+ (responseTab = 'headers')}>
+ Headers
+
+
+ (responseTab = 'body')}>
+ Body
+
+
+
+
+
+ {#if responseTab === 'logs'}
+ {#if selectedLog.logs}
+
+ {:else}
+
+ No logs found.
+
+ {/if}
+ {:else if responseTab === 'errors'}
+ {#if selectedLog.errors}
+
+ {:else}
+
+ No errors found.
+
+ {/if}
+ {:else if responseTab === 'headers'}
+ {#if selectedLog.responseHeaders?.length}
+
+
+ Key
+ Value
+
+ {#each selectedLog.responseHeaders as request}
+
+ {request.name}
+ {request.value}
+
+ {/each}
+
+
+
+
+ Missing headers? Check the docs to
+ see the supported data and how to log it.
+
+
+ {:else}
+
+ No headers found.
+
+ {/if}
+ {:else if responseTab === 'body'}
+ {#if selectedLog.responseBody}
+
+ {:else}
+
+ Body data is not captured by Appwrite for your user's security and privacy. To
+ display body data in the Logs tab, use .
+ Learn more.
+
+
+ {/if}
+ {/if}
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/+page.svelte
index 453702517..fd38e91fb 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/executions/+page.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/+page.svelte
@@ -1,285 +1,72 @@
-
-
- The {tier} plan has limits
-
-
- {abbreviateNumber(limit)} function executions
-
-
- {hoursToDays(logs)} of logs
-
-
- {#if $organization?.billingPlan === BillingPlan.FREE}
-
- Upgrade
- to increase your resource limits.
-
- {:else}
-
- After this amount, ($showUsageRatesModal = true)}
- >usage fees will apply .
-
- {/if}
-
-
-
-
-
-
-
-
-
- More filters
-
- {#if $tags?.length}
-
-
-
Clear All
- {/if}
-
-
-
-
-
-
- Execute
-
-
-
-
-
-
(showMobileFilters = !showMobileFilters)}
- ariaLabel="toggle filters">
-
- Filters
-
+
+
+
-
-
-
- Execute
-
-
-
-
-
+
+ {#if data?.executions?.total}
+
+ {/if}
+
+
+
+
+ Create execution
+
+
+
+ Execution cannot be created because there is no active deployment.
+
+
+
+
+
+
-
-
-
-
- More filters
-
-
-
-
-
-
-
- {#if !$func.logging}
+ {#if !data.func.logging}
-
- Your execution logs are disabled
+
To view execution logs and errors, enable them in your
-
- Function settings
+ Function settings.
-
+
{/if}
{#if data?.executions?.total}
-
+
{:else if data?.query}
-
-
-
-
Sorry we couldn't find any executions
-
There are no executions that match your filters.
-
-
- {
- queries.clearAll();
- queries.apply();
- }}>Clear filters
-
-
-
+
{:else}
-
-
-
- You have no execution logs. Create and activate a deployment to see it here.
-
-
Need a hand? Learn more in our documentation.
-
-
-
- Documentation
-
-
-
-
+
+
+ Documentation
+
+
+
+ Create execution
+
+
+
+ Execution cannot be created because there is no active deployment.
+
+
+
+
{/if}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/executions/+page.ts
index 2d4d66858..6f2190057 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/executions/+page.ts
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/+page.ts
@@ -5,7 +5,9 @@ import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
import { queries, queryParamToMap } from '$lib/components/filters';
-export const load: PageLoad = async ({ params, depends, url, route }) => {
+export const load: PageLoad = async ({ params, depends, url, route, parent }) => {
+ const { function: func } = await parent();
+
depends(Dependencies.EXECUTIONS);
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
@@ -19,6 +21,7 @@ export const load: PageLoad = async ({ params, depends, url, route }) => {
offset,
limit,
query,
+ func,
executions: await sdk.forProject.functions.listExecutions(params.function, [
Query.limit(limit),
Query.offset(offset),
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/execute-function/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/execute-function/+page.svelte
index 311812487..f63e4302d 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/executions/execute-function/+page.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/execute-function/+page.svelte
@@ -3,38 +3,21 @@
import { base } from '$app/paths';
import { page } from '$app/stores';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
- import { timer } from '$lib/actions/timer';
- import { Alert, Card, Id } from '$lib/components';
-
import { Dependencies } from '$lib/constants';
- import { Pill } from '$lib/elements';
import {
Button,
Form,
- FormList,
Helper,
InputDate,
InputSelect,
- InputSelectSearch,
InputText,
InputTextarea,
InputTime
} from '$lib/elements/forms';
- import { humanFileSize } from '$lib/helpers/sizeConvertion';
- import { calculateTime } from '$lib/helpers/timeConversion';
- import {
- WizardSecondaryContainer,
- WizardSecondaryContent,
- WizardSecondaryFooter
- } from '$lib/layout';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { ExecutionMethod, type Models } from '@appwrite.io/console';
import { writable } from 'svelte/store';
- import DeploymentSource from '../../deploymentSource.svelte';
- import DeploymentDomains from '../../deploymentDomains.svelte';
- import { proxyRuleList } from '../../store';
- import DeploymentCreatedBy from '../../deploymentCreatedBy.svelte';
import {
isSameDay,
toLocaleDateISO,
@@ -42,9 +25,19 @@
toLocaleTimeISO
} from '$lib/helpers/date';
import { last } from '$lib/helpers/array';
- import { Icon, Tooltip } from '@appwrite.io/pink-svelte';
- import { IconPlus } from '@appwrite.io/pink-icons-svelte';
+ import {
+ Accordion,
+ Alert,
+ Fieldset,
+ Icon,
+ Input,
+ Layout,
+ Tooltip,
+ Typography
+ } from '@appwrite.io/pink-svelte';
+ import { IconInfo, IconPlus, IconX } from '@appwrite.io/pink-icons-svelte';
import Wizard from '$lib/layout/wizard.svelte';
+ import Aside from './aside.svelte';
let previousPage: string = `${base}/project-${$page.params.project}/functions/function-${$page.params.function}/executions`;
@@ -146,258 +139,221 @@
- Execute function - Appwrite
+ Create execution - Appwrite
-
- Execute function
-
-
-
- {#if func?.version === 'v2'}
-
-
- Customizable execution data now available for functions v3.0
-
- Update your function version to make use of new features including customizable
- HTTP data in your executions.
-
-
- Learn more
-
-
-
-
- {:else}
-
-
-
-
- Headers
- (optional)
-
-
- Headers should contain alphanumeric characters (a-z, A-Z, and
- 0-9) and hyphens only (- and _).
-
-
-
+
+ Create execution
+
+
+ {#if func?.version === 'v2'}
+
+
-
- {#if headers}
- {#each headers as [name, value], index}
-
-
-
- {
- if (index === 0) {
- headers = [['', '']];
- } else {
- headers.splice(index, 1);
- headers = headers;
- }
- }}>
-
-
- {/each}
- {/if}
-
+ Update your function version to make use of new features including customizable
+ HTTP data in your executions.
+
{
- if (headers[headers.length - 1][0]) {
- headers.push(['', '']);
- headers = headers;
- }
- }}>
-
- Add Header
+ href="https://appwrite.io/docs/products/functions/development"
+ external
+ compact>
+ Learn more
-
+
+
+
+
+
+
+ Provide the request body to include the main data you want to send
+ to the server.
+
+
+
+
+
+ {:else}
+
+
+
+
+
+
-
+
+
+
+
+ Provide essential metadata to define the content type,
+ authentication details, and the expected response format.
+
-
-
- {#if isScheduled}
-
-
- {/if}
-
- {isScheduled
- ? `Your function will be executed on ${toLocaleDateTime(dateTime?.toString())}`
- : 'Your function will be executed immediately'}
-
-
- {/if}
-
-
-
-
-
-
Deployment ID
+
+ {#if headers}
+ {#each headers as [name, value], index}
+
+
+
+
+
+
+
+
+
+
+ Values should contain
+ alphanumeric characters (a-z,
+ A-Z, and 0-9) and hyphens only
+ (- and _).
+
+
+
+
+ {
+ if (index === 0) {
+ headers = [['', '']];
+ } else {
+ headers.splice(index, 1);
+ headers = headers;
+ }
+ }}>
+
+
+
+ {/each}
+ {/if}
+
+ {
+ if (headers[headers.length - 1][0]) {
+ headers.push(['', '']);
+ headers = headers;
+ }
+ }}>
+
+ Add header
+
+
+
+
+
-
- {func.deployment}
-
-
-
+
+
+
+
+
+ {#if !isScheduled}
+
+ Your function will be executed immediately
+
{/if}
-
-
-
- Total size
-
- {humanFileSize(deployment.size + deployment.buildSize).value +
- humanFileSize(deployment.size + deployment.buildSize).unit}
-
-
-
-
-
-
- Deployment size:
- {humanFileSize(deployment.size).value +
- humanFileSize(deployment.size).unit}
-
-
- Build size:
- {humanFileSize(deployment.buildSize).value +
- humanFileSize(deployment.buildSize).unit}
-
-
-
-
-
-
-
- {#if $proxyRuleList?.rules?.length}
-
- {/if}
-
-
-
-
+
+ {#if isScheduled}
+
+
+
+
+
+
+ Your function will be executed on {toLocaleDateTime(
+ dateTime?.toString()
+ )}
+
+
+ {/if}
+
+
+ {/if}
+
+
+
+
+
-
+
Cancel
formComponent.triggerSubmit()}
disabled={$isSubmitting}>
- Execute
+ Create
-
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/execute-function/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/executions/execute-function/+page.ts
index 1d11c6734..7ee66a5a4 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/executions/execute-function/+page.ts
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/execute-function/+page.ts
@@ -8,11 +8,12 @@ export const load: PageLoad = async ({ params, depends, parent }) => {
return {
func: data.function,
- activeDeployment: data.function.deployment
+ activeDeployment: data.function.deploymentId
? await sdk.forProject.functions.getDeployment(
params.function,
- data.function.deployment
+ data.function.deploymentId
)
- : null
+ : null,
+ proxyRuleList: data.proxyRuleList
};
};
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/execute-function/aside.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/execute-function/aside.svelte
new file mode 100644
index 000000000..4c38b622a
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/execute-function/aside.svelte
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+ Deployment ID
+
+
+ {deployment.$id}
+
+
+
+
+ Build duration
+
+ {#if ['processing', 'building'].includes(deployment.status)}
+
+ {:else}
+ {formatTimeDetailed(deployment.buildDuration)}
+ {/if}
+
+
+
+ Size
+
+
+ {humanFileSize(deployment.sourceSize + deployment.buildSize).value +
+ humanFileSize(deployment.sourceSize + deployment.buildSize).unit}
+
+
+
+
+ Deployment size:
+ {humanFileSize(deployment.sourceSize).value +
+ humanFileSize(deployment.sourceSize).unit}
+
+
+ Build size:
+ {humanFileSize(deployment.buildSize).value +
+ humanFileSize(deployment.buildSize).unit}
+
+
+
+
+
+
+
+ Source
+
+
+
+
+ {#if proxyRuleList?.total}
+
+ Domains
+
+
+
+
+ {/if}
+
+
+ Updated
+
+
+
+
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/quickFilters.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/quickFilters.svelte
deleted file mode 100644
index 71b432739..000000000
--- a/src/routes/(console)/project-[project]/functions/function-[function]/executions/quickFilters.svelte
+++ /dev/null
@@ -1,283 +0,0 @@
-
-
-{#each [statusFilter, triggerFilter, methodFilter] as filter}
-
- (filter.show = !filter.show)}
- event="apply_quick_filter"
- eventData={{ source: 'function_execution', column: filter.title }}>
- {#key filter.tag}
-
- {filter?.tag ?? filter.title}
-
- {/key}
-
-
-
-
- {#each filter.options as option (option.value + option.checked)}
- {
- option.checked = !option.checked;
- addFilterAndApply(
- filter.id,
- filter.title,
- filter.operator,
- filter?.array ? null : option.checked ? option.value : null,
- filter?.array
- ? (filter.options
- .filter((opt) => opt.checked)
- .map((opt) => opt.value) ?? [])
- : []
- );
- }}>
- {option.label}
-
- {/each}
- {#if filter.options.some((option) => option.checked)}
- {
- filter.show = false;
- filter.tag = null;
- addFilterAndApply(filter.id, filter.title, filter.operator, null, []);
- }}>
- Clear selection
-
- {/if}
-
-
-{/each}
-{#each [statusCodeFilter, createdAtFilter] as filter}
-
- (filter.show = !filter.show)}
- event="apply_quick_filter"
- eventData={{ source: 'function_execution', column: filter.title }}>
- {#key filter.tag}
-
- {filter?.tag ?? filter.title}
-
- {/key}
-
-
-
-
- {#each filter.options as option (option.value + option.checked)}
- {
- filter.show = false;
-
- addFilterAndApply(
- filter.id,
- filter.title,
- filter.operator,
- filter?.array ? null : option.value,
- []
- );
- }}>
- {option.label}
-
- {/each}
- {#if filter?.tag}
- {
- filter.show = false;
- filter.tag = null;
- addFilterAndApply(filter.id, filter.title, filter.operator, null, []);
- }}>
- Clear selection
-
- {/if}
-
-
-{/each}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/sheet.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/sheet.svelte
new file mode 100644
index 000000000..6657a6fc0
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/sheet.svelte
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+ Execution ID
+
+ {selectedLog?.$id}
+
+
+
+
+
+
+
+
+
+
+
+
+ {#if selectedLog}
+
+
+
+
+
+
+ Method
+
+
+ {selectedLog.requestMethod}
+
+
+
+
+ Status code
+
+
+ = 400
+ ? 'error'
+ : selectedLog.responseStatusCode === 0
+ ? undefined
+ : 'success'} />
+
+
+
+
+ Status
+
+
+
+
+
+ {capitalize(selectedLog.status)}
+
+
+
+ {`Scheduled to execute on ${toLocaleDateTime(selectedLog.scheduledAt)}`}
+
+
+
+
+
+
+ Triggered by
+
+
+ {capitalize(selectedLog.trigger)}
+
+
+
+
+
+ Duration
+
+
+ {calculateTime(selectedLog.duration)}
+
+
+
+
+
+ Created
+
+
+ {capitalize(timeFromNow(selectedLog.$createdAt))}
+
+
+
+
+
+ Path
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/if}
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/store.ts b/src/routes/(console)/project-[project]/functions/function-[function]/executions/store.ts
new file mode 100644
index 000000000..a882b2d83
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/store.ts
@@ -0,0 +1,146 @@
+import type { Column } from '$lib/helpers/types';
+import { writable } from 'svelte/store';
+
+export const columns = writable([
+ { id: '$id', title: 'Execution ID', type: 'string', show: true, width: 150 },
+ {
+ id: 'requestPath',
+ title: 'Path',
+ type: 'string',
+ show: true,
+ width: 90,
+ format: 'string'
+ },
+
+ {
+ id: 'trigger',
+ title: 'Trigger',
+ type: 'string',
+ show: false,
+ width: 90,
+ array: true,
+ format: 'enum',
+ elements: [
+ { value: 'http', label: 'HTTP' },
+ { value: 'schedule', label: 'Schedule' },
+ { value: 'event', label: 'Event' }
+ ],
+ hide: true
+ },
+ {
+ id: 'requestMethod',
+ title: 'Method',
+ type: 'string',
+ show: false,
+ width: 70,
+ array: true,
+ format: 'enum',
+ elements: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
+ hide: true
+ },
+ {
+ id: 'responseStatusCode',
+ title: 'Status code',
+ type: 'integer',
+ show: false,
+ width: 100,
+ format: 'integer',
+ elements: [
+ {
+ value: 299,
+ label: 'Success (200-299)'
+ },
+ {
+ value: 399,
+ label: 'Redirect (300-399)'
+ },
+ {
+ value: 499,
+ label: 'Client error (400-499)'
+ },
+ {
+ value: 599,
+ label: 'Server error (500-599)'
+ }
+ ],
+ hide: true
+ },
+
+ {
+ id: 'status',
+ title: 'Status',
+ type: 'enum',
+ show: true,
+ width: 130,
+ array: true,
+ format: 'enum',
+ elements: ['completed', 'failed', 'waiting', 'scheduled', 'processing', 'cancelled']
+ },
+ {
+ id: 'duration',
+ title: 'Duration',
+ type: 'integer',
+ show: true,
+ width: 80,
+ format: 'integer',
+ elements: [
+ {
+ value: 1,
+ label: 'more than 1 second'
+ },
+ {
+ value: 5,
+ label: 'more than 5 seconds'
+ },
+ {
+ value: 30,
+ label: 'more than 30 seconds'
+ }
+ ]
+ },
+ {
+ id: '$createdAt',
+ title: 'Created',
+ type: 'datetime',
+ show: true,
+ width: 120,
+ format: 'datetime',
+ elements: [
+ {
+ value: 5 * 60 * 1000,
+ label: 'last 5 minutes'
+ },
+ {
+ value: 60 * 60 * 1000,
+ label: 'last 1 hour'
+ },
+ {
+ value: 24 * 60 * 60 * 1000,
+ label: 'last 24 hours'
+ }
+ ]
+ }
+]);
+
+export function logStatusConverter(status: string) {
+ // ['completed', 'failed', 'waiting', 'scheduled', 'processing', 'cancelled']
+
+ switch (status) {
+ case 'completed':
+ return 'complete';
+ case 'scheduled':
+ return 'processing';
+ case 'processing':
+ return 'processing';
+ case 'waiting':
+ return 'waiting';
+ case 'queued':
+ return 'waiting';
+ case 'peding':
+ return 'pending';
+ case 'cancelled':
+ return 'waiting';
+ case 'failed':
+ return 'failed';
+ }
+}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/table.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/table.svelte
index dba3ececb..702b322cc 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/executions/table.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/table.svelte
@@ -1,155 +1,98 @@
{#each columns as column}
- {#if column.show}
- {column.title}
+ {#if column.show && !column.hide}
+ {column.title}
{/if}
{/each}
-
- {#each data.executions.executions as execution, index (execution.$id)}
-
+ {#each logs.executions as log}
+ {
+ openSheet = true;
+ selectedLogId = log.$id;
+ }}>
{#each columns as column}
- {#if column.show}
+ {#if column.show && !column.hide}
{#if column.id === '$id'}
{#key column.id}
- {execution.$id}
+ {log.$id}
{/key}
- {:else if column.id === 'status'}
-
- {@const status = execution.status}
-
-
-
- {#if status === 'scheduled'}
-
- {timeFromNow(execution.scheduledAt)}
- {:else}
- {status}
- {/if}
-
-
- {`Scheduled to execute on ${toLocaleDateTime(execution.scheduledAt)}`}
-
-
{:else if column.id === '$createdAt'}
-
-
- {:else if column.id === 'trigger'}
-
-
- {execution.trigger}
-
-
- {:else if column.id === 'requestMethod'}
-
- {execution.requestMethod}
-
- {:else if column.id === 'responseStatusCode'}
-
- {execution.responseStatusCode}
+
{:else if column.id === 'requestPath'}
- {execution.requestPath}
+
+ = 400
+ ? 'error'
+ : log.responseStatusCode === 0
+ ? undefined
+ : 'success'}
+ content={log.responseStatusCode.toString()} />
+
+ {log.requestMethod}
+
+
+ {log.requestPath}
+
+
+
+ {:else if column.id === 'responseStatusCode'}
+
+ {log.responseStatusCode}
+
+ {:else if column.id === 'status'}
+
+ {@const status = log.status}
+
+
+
+ {status}
+
+
+
+ {`Scheduled to execute on ${toLocaleDateTime(log.scheduledAt)}`}
+
+
{:else if column.id === 'duration'}
- {calculateTime(execution.duration)}
+ {formatTimeDetailed(log.duration)}
{/if}
{/if}
{/each}
-
-
- {
- showDropdown[index] = !showDropdown[index];
- }}>
-
-
-
- {
- showDropdown = [];
- showLogs(execution);
- }}>
- Logs
-
- {
- selectedExecution = execution;
- showDropdown = [];
- showDelete = true;
- }}>
- Delete
-
-
-
-
-
+
{/each}
-{#if selectedExecution}
-
-{/if}
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/quickFilters.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/quickFilters.svelte
deleted file mode 100644
index efbbe4f06..000000000
--- a/src/routes/(console)/project-[project]/functions/function-[function]/quickFilters.svelte
+++ /dev/null
@@ -1,281 +0,0 @@
-
-
-{#each [typeFilter] as filter}
-
- (filter.show = !filter.show)}
- event="apply_quick_filter"
- eventData={{ source: 'function_deployments', column: filter.title }}>
- {#key filter.tag}
-
- {filter?.tag ?? filter.title}
-
- {/key}
-
-
-
-
- {#each filter.options as option (option.value + option.checked)}
- {
- option.checked = !option.checked;
- addFilterAndApply(
- filter.id,
- filter.title,
- filter.operator,
- filter?.array ? null : option.checked ? option.value : null,
- filter?.array
- ? (filter.options
- .filter((opt) => opt.checked)
- .map((opt) => opt.value) ?? [])
- : []
- );
- }}>
- {option.label}
-
- {/each}
- {#if filter.options.some((option) => option.checked)}
- {
- filter.show = false;
- filter.tag = null;
- addFilterAndApply(filter.id, filter.title, filter.operator, null, []);
- }}>
- Clear selection
-
- {/if}
-
-
-{/each}
-{#each [sizeFilter] as filter}
-
- (filter.show = !filter.show)}
- event="apply_quick_filter"
- eventData={{ source: 'function_deployments', column: filter.title }}>
- {#key filter.tag}
-
- {filter?.tag ?? filter.title}
-
- {/key}
-
-
-
-
- {#each filter.options as option (option.value + option.checked)}
- {
- filter.show = false;
-
- addFilterAndApply(
- filter.id,
- filter.title,
- filter.operator,
- filter?.array ? null : option.value,
- []
- );
- }}>
- {option.label}
-
- {/each}
- {#if filter?.tag}
- {
- filter.show = false;
- filter.tag = null;
- addFilterAndApply(filter.id, filter.title, filter.operator, null, []);
- }}>
- Clear selection
-
- {/if}
-
-
-{/each}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/+page.svelte
index 862862ee5..0db9d6895 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/+page.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/+page.svelte
@@ -1,9 +1,7 @@
- Settings
- {#if $func.version === 'v2' && showAlert}
+ {#if data.function.version === 'v2' && showAlert}
- trackEvent('click_open_website', {
+ trackEvent(Click.WebsiteOpenClick, {
from: 'button',
source: 'function_keys_card',
destination: 'docs'
@@ -77,20 +86,29 @@
{/if}
-
-
-
-
-
-
+
+ {#key data.function.providerRepositoryId}
+
+ {/key}
+
+ variableList={data.variables}
+ analyticsSource="function_settings" />
+
+
+
+ {#if isCloud}
+
+ {/if}
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/settings/+page.ts
index 818c56a6e..e4ec0997b 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/+page.ts
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/+page.ts
@@ -1,10 +1,11 @@
import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
-import type { PageLoad } from './$types';
-export const load: PageLoad = async ({ params, depends }) => {
+export const load = async ({ params, depends, parent }) => {
depends(Dependencies.VARIABLES);
- depends(Dependencies.FUNCTIONS);
+ depends(Dependencies.FUNCTION);
+
+ const { runtimesList, specificationsList } = await parent();
const [globalVariables, variables] = await Promise.all([
sdk.forProject.projectApi.listVariables(),
@@ -31,6 +32,8 @@ export const load: PageLoad = async ({ params, depends }) => {
return {
variables,
- globalVariables
+ globalVariables,
+ runtimesList,
+ specificationsList
};
};
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/dangerZone.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/dangerZone.svelte
index 20af9413e..1152f0337 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/dangerZone.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/dangerZone.svelte
@@ -11,8 +11,7 @@
Delete function
- The function will be permanently deleted, including all deployments associated with it. This action
- is irreversible.
+ The function will be permanently deleted, including all deployments associated with it.
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/disconnectRepo.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/disconnectRepo.svelte
index 33b849b9e..792506c3b 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/disconnectRepo.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/disconnectRepo.svelte
@@ -2,7 +2,7 @@
import { invalidate } from '$app/navigation';
import { page } from '$app/stores';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
- import { Modal } from '$lib/components';
+ import { Confirm } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Button } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
@@ -61,7 +61,7 @@
}
-
+
Are you sure you want to disconnect {$func.name} ? This will affect future deployments
to this function.
@@ -70,4 +70,4 @@
(show = false)}>Cancel
Disconnect
-
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/executeFunction.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/executeFunction.svelte
index b98a86cde..3feb55e48 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/executeFunction.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/executeFunction.svelte
@@ -2,30 +2,45 @@
import { base } from '$app/paths';
import { CardGrid, SvgIcon } from '$lib/components';
import { Button } from '$lib/elements/forms';
- import { toLocaleDateTime } from '$lib/helpers/date';
+ import { timeFromNow, toLocaleDateTime } from '$lib/helpers/date';
import { project } from '$routes/(console)/project-[project]/store';
- import { Typography } from '@appwrite.io/pink-svelte';
+ import { Layout, Tooltip, Typography } from '@appwrite.io/pink-svelte';
import { func } from '../store';
+ import { capitalize } from '$lib/helpers/string';
-
-
-
-
-
-
{$func.name}
+
{$func.name}
-
{$func.runtime}
-
-
-
-
-
Created at: {toLocaleDateTime($func.$createdAt)}
-
Last updated at: {toLocaleDateTime($func.$updatedAt)}
-
-
+
+
+ Runtime
+
+
+
+ {capitalize($func.runtime)}
+
+
+
+
+ Updated
+
+
+ {capitalize(timeFromNow($func.$updatedAt))}
+
+ {toLocaleDateTime($func.$updatedAt)}
+
+
+
+
+
+ Created
+
+ {toLocaleDateTime($func.$createdAt)}
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/gitConfigurationModal.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/gitConfigurationModal.svelte
deleted file mode 100644
index c73914191..000000000
--- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/gitConfigurationModal.svelte
+++ /dev/null
@@ -1,288 +0,0 @@
-
-
-
-
- Configure a Git repository that will trigger your function deployments when updated.
-
- {#if step === 1}
- {#await getRepos()}
- Fetching repositories..
- {:then}
-
-
-
- Manage organization configuration in your project settings .
-
- {#if repositoriesList.length}
-
- {#each repositoriesList as repo}
-
-
-
-
-
-
-
-
- {repo.name}
- {#if repo.private}
-
- {/if}
-
- {timeFromNow(repo.pushedAt)}
-
-
-
-
-
- {/each}
-
-
-
Total results: {repositoriesList.length}
-
-
- {:else if search}
-
-
-
-
Sorry we couldn't find "{search}"
-
There are no repositories that match your search.
-
-
- Documentation
- (search = '')}>Clear search
-
-
-
- {:else}
-
-
-
-
You have no repositories.
-
- Need a hand? Learn more in our
- documentation .
-
-
-
-
- {/if}
- {/await}
- {:else}
- {#await getBranches()}
- Fetching branches..
- {:then}
-
-
-
-
-
-
-
- {selectedRepo.name}
-
- Last updated: {toLocaleDateTime(selectedRepo.pushedAt)}
-
-
- {
- selectedBranch = event.detail.value;
- }}
- name="branch"
- options={branchesList?.branches?.map((branch) => {
- return {
- value: branch.name,
- label: branch.name
- };
- }) ?? []} />
-
-
- {/await}
- {/if}
-
-
- {#if step === 1}
- (show = false)}>Cancel
- step++}>Next
- {:else}
- step--}>Back
- Deploy now
- {/if}
-
-
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateBuildCommand.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateBuildCommand.svelte
new file mode 100644
index 000000000..616259065
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateBuildCommand.svelte
@@ -0,0 +1,71 @@
+
+
+
+
+ Build command
+ Define the command used to build your function before deployment.
+
+
+
+
+
+ Update
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateConfiguration.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateConfiguration.svelte
deleted file mode 100644
index b8b0233d3..000000000
--- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateConfiguration.svelte
+++ /dev/null
@@ -1,345 +0,0 @@
-
-
-
-
- Configuration
- Connect a Git repository for automatic deployments, or set install and build commands for your
- function.
-
-
-
-
-
- {#if repository === false}
-
-
- Git settings
-
-
-
-
- Loading repository...
-
-
-
- {:else}
-
-
- Git settings
- {#if !repository}
-
-
- NOT CONNECTED
-
-
- {/if}
-
- {#if repository}
-
-
-
-
-
- {repository.name}
- {#if repository.private}
-
- {/if}
-
-
- Last updated: {toLocaleDateTime(repository.pushedAt)}
-
-
-
-
-
- {
- selectedBranch = event.detail.value;
- }}
- name="branch"
- options={branchesList?.branches?.map((branch) => {
- return {
- value: branch.name,
- label: branch.name
- };
- }) ?? []} />
-
-
-
-
-
- (showDisconnect = true)}>
- Disconnect repository
-
-
- View on {ProviderNames[repository.provider] ??
- 'unknown provider'}
-
-
-
-
- {:else}
- {#if isSelfHosted && !isVcsEnabled}
-
-
- Installing Git to a self-hosted instance
-
- When installing Git in a locally hosted Appwrite project, you must
- first configure your environment variables.
-
-
- Learn more
-
-
-
- {/if}
-
-
-
-
wizard.start(ConnectExisting)}>
- Connect Git
-
-
-
- {/if}
-
- {/if}
-
- Build settings
-
-
-
-
-
-
-
-
- Update
-
-
-
-
-{#if !$installations?.total && showGit}
-
-{:else}
-
-{/if}
-
-
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateEvents.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateEvents.svelte
index e191289b1..e6a711559 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateEvents.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateEvents.svelte
@@ -1,14 +1,11 @@
+
+
+
+ Git repository
+ Automatically deploy changes for every commit pushed to your Git repository.
+
+ {#if repository === false}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {:else if repository}
+
+
+
+
+
+
+
+ {repository.name}
+
+
+ Last updated: {toLocaleDateTime(repository.pushedAt)}
+
+
+
+ (showDisconnect = true)}>
+ Disconnect
+
+
+
+
+
+
+ {
+ selectedBranch = event.detail.value;
+ }}
+ name="branch"
+ options={branchesList?.branches?.map((branch) => {
+ return {
+ value: branch.name,
+ label: branch.name
+ };
+ }) ?? []} />
+
+
+ Select
+
+
+
+
+
+
+ {:else if func.installationId || installations?.total}
+
+
+
+ (showConnectRepo = true)}>
+
+ Connect Git repository
+
+
+
+
+ {:else}
+
+ {/if}
+
+
+
+ Update
+
+
+
+
+{#if showConnectRepo}
+
+{/if}
+
+{#if showDisconnect}
+
+{/if}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateResourceLimits.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateResourceLimits.svelte
new file mode 100644
index 000000000..d72598f8c
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateResourceLimits.svelte
@@ -0,0 +1,98 @@
+
+
+
+
+ Resource limits
+ Define your function's compute specifications, including CPU and memory, to optimize performance
+ for your workloads.
+ Learn more
+ .
+
+
+ {#if isCloud && $organization.billingPlan === BillingPlan.FREE}
+
+ Upgrade to Pro or Scale to adjust your CPU and RAM beyond the default.
+
+ Upgrade
+
+
+ {/if}
+
+
+
+ Update
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateRuntime.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateRuntime.svelte
index cf93e975b..02c9d94d1 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateRuntime.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateRuntime.svelte
@@ -3,35 +3,30 @@
import { page } from '$app/stores';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { CardGrid } from '$lib/components';
- import { BillingPlan, Dependencies } from '$lib/constants';
- import { Button, Form, FormList } from '$lib/elements/forms';
+ import { Dependencies } from '$lib/constants';
+ import { Button, Form, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { func } from '../store';
import InputSelect from '$lib/elements/forms/inputSelect.svelte';
import { specificationsList } from '$lib/stores/specifications';
- import { runtimesList } from '$lib/stores/runtimes';
import { isValueOfStringEnum } from '$lib/helpers/types';
- import { Runtime } from '@appwrite.io/console';
- import { isCloud } from '$lib/system';
- import { organization } from '$lib/stores/organization';
- import SpecificationsTooltip from '$lib/wizards/functions/components/specificationsTooltip.svelte';
+ import { Runtime, type Models } from '@appwrite.io/console';
+ import { Layout, Typography } from '@appwrite.io/pink-svelte';
+ import Link from '$lib/elements/link.svelte';
+ export let runtimesList: Models.RuntimeList;
const functionId = $page.params.function;
- let runtime: string = null;
- let specification: string = null;
+ let runtime: string = $func.runtime;
+ let entrypoint = $func.entrypoint;
let options = [];
let specificationOptions = [];
onMount(async () => {
- runtime ??= $func.runtime;
- specification ??= $func.specification;
-
- let runtimes = await $runtimesList;
let allowedSpecifications = (await $specificationsList).specifications;
- options = runtimes.runtimes.map((runtime) => ({
+ options = runtimesList.runtimes.map((runtime) => ({
label: `${runtime.name} - ${runtime.version}`,
value: runtime.$id
}));
@@ -60,7 +55,7 @@
$func.timeout || undefined,
$func.enabled || undefined,
$func.logging || undefined,
- $func.entrypoint || undefined,
+ entrypoint || undefined,
$func.commands || undefined,
$func.scopes || undefined,
$func.installationId || undefined,
@@ -68,51 +63,51 @@
$func.providerBranch || undefined,
$func.providerSilentMode || undefined,
$func.providerRootDirectory || undefined,
- specification
+ $func.specification || undefined
);
await invalidate(Dependencies.FUNCTION);
addNotification({
message: 'Runtime settings have been updated',
type: 'success'
});
- trackEvent(Submit.FunctionUpdateName);
+ trackEvent(Submit.FunctionUpdateRuntime, { runtime });
} catch (error) {
addNotification({
message: error.message,
type: 'error'
});
- trackError(error, Submit.FunctionUpdateName);
+ trackError(error, Submit.FunctionUpdateRuntime);
}
}
- $: isUpdateButtonEnabled = runtime !== $func?.runtime || specification !== $func?.specification;
+ $: isUpdateButtonEnabled = runtime !== $func?.runtime || entrypoint !== $func?.entrypoint;
Runtime
+
+ Select the runtime for executing your function and define its entrypoint. Version
+ changes apply on redeploy and can be updated here. Learn more.
+
-
+
+
-
-
+ placeholder="Enter entrypoint"
+ bind:value={$func.entrypoint} />
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateSchedule.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateSchedule.svelte
index 6eb076eff..160c0c2fe 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateSchedule.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateSchedule.svelte
@@ -11,6 +11,7 @@
import { func } from '../store';
import { isValueOfStringEnum } from '$lib/helpers/types';
import { Runtime } from '@appwrite.io/console';
+ import { Link } from '$lib/elements';
const functionId = $page.params.function;
let functionSchedule: string = null;
@@ -63,18 +64,14 @@
Schedule
Set a Cron schedule to trigger your function. Leave blank for no schedule.
-
- More details on Cron syntax here
+ Learn more.
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateScopes.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateScopes.svelte
index a418a5b12..f5191feee 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateScopes.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateScopes.svelte
@@ -13,6 +13,7 @@
import { Runtime } from '@appwrite.io/console';
import Scopes from '$routes/(console)/project-[project]/overview/keys/scopes.svelte';
import { symmetricDifference } from '$lib/helpers/array';
+ import { Link } from '$lib/elements';
const functionId = $page.params.function;
let functionScopes: string[] = null;
@@ -68,11 +69,8 @@
Scopes
Select scopes to grant the dynamic key generated temporarily for your function. It is best practice
to allow only necessary permissions.
- Learn more Learn more.
{#if functionScopes !== null}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateTimeout.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateTimeout.svelte
index 7b1abea85..5ab47da82 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateTimeout.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateTimeout.svelte
@@ -62,7 +62,7 @@
Timeout
- Limit the execution time of your function. Maximum value is 900 seconds (15 minutes).
+ Limit the execution time of your function. The maximum value is 900 seconds (15 minutes).
$page.data.function as Models.Function);
export const deploymentList = derived(
@@ -23,3 +24,91 @@ export const repositories: Writable<{
});
export const showCreateDeployment: Writable = writable(false);
+
+export const columns = writable([
+ { id: '$id', title: 'Deployment ID', type: 'string', show: true, width: 150 },
+ {
+ id: 'status',
+ title: 'Status',
+ type: 'enum',
+ show: true,
+ width: 110,
+ array: true,
+ format: 'enum',
+ elements: ['ready', 'processing', 'building', 'waiting', 'cancelled', 'failed'],
+ filter: false
+ },
+ {
+ id: 'buildDuration',
+ title: 'Build duration',
+ type: 'integer',
+ show: true,
+ width: 90,
+ elements: [
+ {
+ value: 15,
+ label: 'more than 15 seconds'
+ },
+ {
+ value: 60,
+ label: 'more than 1 minute'
+ },
+ {
+ value: 5 * 60,
+ label: 'more than 5 minutes'
+ }
+ ],
+ filter: false
+ },
+ {
+ id: 'sourceSize',
+ title: 'Source size',
+ type: 'integer',
+ show: true,
+ width: 140,
+ elements: [
+ {
+ value: 2 * 1000 * 1000,
+ label: 'more than 2MB'
+ },
+ {
+ value: 10 * 1000 * 1000,
+ label: 'more than 10MB'
+ },
+ {
+ value: 50 * 1000 * 1000,
+ label: 'more than 50MB'
+ }
+ ]
+ },
+ {
+ id: 'buildSize',
+ title: 'Build size',
+ type: 'integer',
+ show: false,
+ filter: false,
+ width: 80
+ },
+ {
+ id: 'type',
+ title: 'Source',
+ type: 'string',
+ show: true,
+ width: 90,
+ array: true,
+ format: 'enum',
+ elements: [
+ { value: 'manual', label: 'Manual' },
+ { value: 'cli', label: 'CLI' },
+ { value: 'vcs', label: 'Git' }
+ ]
+ },
+ {
+ id: '$updatedAt',
+ title: 'Updated',
+ type: 'datetime',
+ show: true,
+ width: 150,
+ format: 'datetime'
+ }
+]);
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/table.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/table.svelte
index a03da9f08..f7f80ac6a 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/table.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/table.svelte
@@ -1,30 +1,39 @@
@@ -55,8 +57,9 @@
{/each}
- {#each data.deploymentList.deployments as deployment, index (deployment.$id)}
-
+ {#each data.deploymentList.deployments as deployment (deployment.$id)}
+
{#each columns as column}
{#if column.show}
{#if column.id === '$id'}
@@ -68,18 +71,13 @@
{:else if column.id === 'status'}
{@const status = deployment.status}
+
{#if data?.activeDeployment?.$id === deployment?.$id}
-
-
- active
-
+
{:else}
-
- {status}
-
+
{/if}
{:else if column.id === 'type'}
@@ -90,17 +88,19 @@
- {:else if column.id === 'buildTime'}
+ {:else if column.id === 'buildDuration'}
- {#if ['processing', 'building'].includes(deployment.status)}
+ {#if ['waiting'].includes(deployment.status)}
+ -
+ {:else if ['processing', 'building'].includes(deployment.status)}
{:else}
- {calculateTime(deployment.buildTime)}
+ {formatTimeDetailed(deployment.buildDuration)}
{/if}
- {:else if column.id === 'size'}
+ {:else if column.id === 'sourceSize'}
- {calculateSize(deployment.size)}
+ {calculateSize(deployment.sourceSize)}
{:else if column.id === 'buildSize'}
@@ -110,74 +110,76 @@
{/if}
{/each}
-
- {
- showDropdown[index] = !showDropdown[index];
- }}>
-
-
-
- {
- selectedDeployment = deployment;
- showRedeploy = true;
- showDropdown = [];
- }}>
- Redeploy
-
- {#if deployment.status === 'ready' && deployment.$id !== $func.deployment}
- {
- selectedDeployment = deployment;
- showActivate = true;
- showDropdown = [];
- }}>
- Activate
-
- {/if}
-
- Logs
-
- (showDropdown[index] = false)}>
- Download
-
- {#if deployment.status === 'processing' || deployment.status === 'building' || deployment.status === 'waiting'}
- {
- selectedDeployment = deployment;
- showDropdown = [];
- showCancel = true;
- }}>
- Cancel
-
- {/if}
- {#if deployment.status !== 'building' && deployment.status !== 'processing' && deployment.status !== 'waiting'}
- {
- selectedDeployment = deployment;
- showDropdown = [];
- showDelete = true;
- }}>
- Delete
-
- {/if}
-
-
+
+
+
+
+
+
+
+
+ {
+ selectedDeployment = deployment;
+ showRedeploy = true;
+ toggle();
+ trackEvent(Click.FunctionsRedeployClick);
+ }}>
+ Redeploy
+
+ {#if deployment.status === 'ready' && deployment.$id !== $func.deploymentId}
+ {
+ selectedDeployment = deployment;
+ showActivate = true;
+ toggle();
+ }}>
+ Activate
+
+ {/if}
+
+
+
+ {#if deployment.status === 'processing' || deployment.status === 'building' || deployment.status === 'waiting'}
+ {
+ selectedDeployment = deployment;
+ toggle();
+
+ showCancel = true;
+ trackEvent(Click.FunctionsDeploymentCancelClick);
+ }}>
+ Cancel
+
+ {/if}
+ {#if deployment.status !== 'building' && deployment.status !== 'processing' && deployment.status !== 'waiting'}
+ {
+ selectedDeployment = deployment;
+ toggle();
+
+ showDelete = true;
+ trackEvent(Click.FunctionsDeploymentDeleteClick);
+ }}>
+ Delete
+
+ {/if}
+
+
+
+
-
+
{/each}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/usage/[[period]]/+page.svelte
index c01ce72d7..8fd494f88 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/usage/[[period]]/+page.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/usage/[[period]]/+page.svelte
@@ -1,12 +1,9 @@
-
-
- Functions
-
-
- 24h
-
-
- 30d
-
-
- 90d
-
-
-
+
{#if count}
-
- {formatNumberWithCommas(total)}
- Executions
-
- [e.date, e.value])]
- }
- ]} />
-
+
{/if}
{#if mbSecondsCount}
-
- {formatNumberWithCommas(gbHoursTotal)}
- GB Hours
-
- [
- e.date,
- Math.ceil((e.value / 1000 / 3600) * 1000) / 1000
- ])
- ]
- }
- ]} />
-
+
{/if}
-
+
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/usage/[[period]]/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/usage/[[period]]/+page.ts
index 1766c60a0..8fcf3d7c7 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/usage/[[period]]/+page.ts
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/usage/[[period]]/+page.ts
@@ -9,7 +9,7 @@ export const load: PageLoad = async ({ params }) => {
const period = isValueOfStringEnum(FunctionUsageRange, params.period)
? params.period
: FunctionUsageRange.ThirtyDays;
- return sdk.forProject.functions.getFunctionUsage(params.function, period);
+ return sdk.forProject.functions.getUsage(params.function, period);
} catch (e) {
error(e.code, e.message);
}
diff --git a/src/routes/(console)/project-[project]/functions/header.svelte b/src/routes/(console)/project-[project]/functions/header.svelte
index 6f49fd464..e5be12f6f 100644
--- a/src/routes/(console)/project-[project]/functions/header.svelte
+++ b/src/routes/(console)/project-[project]/functions/header.svelte
@@ -19,6 +19,11 @@
href: `${path}/templates`,
title: 'Templates',
event: 'templates'
+ },
+ {
+ href: `${path}/usage`,
+ title: 'Usage',
+ event: 'usage'
}
];
diff --git a/src/routes/(console)/project-[project]/functions/templates/+page.svelte b/src/routes/(console)/project-[project]/functions/templates/+page.svelte
index 83ab46475..864b70f58 100644
--- a/src/routes/(console)/project-[project]/functions/templates/+page.svelte
+++ b/src/routes/(console)/project-[project]/functions/templates/+page.svelte
@@ -2,33 +2,43 @@
import { goto } from '$app/navigation';
import { base } from '$app/paths';
import { page } from '$app/stores';
- import {
- Collapsible,
- CollapsibleItem,
- EmptySearch,
- Pagination,
- SvgIcon
- } from '$lib/components';
+ import { EmptySearch, SvgIcon } from '$lib/components';
import { Button, InputSearch } from '$lib/elements/forms';
import { Container, ContainerButton } from '$lib/layout';
- import { app } from '$lib/stores/app';
import { isServiceLimited } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import { canWriteFunctions } from '$lib/stores/roles';
- import { connectTemplate } from '$lib/wizards/functions/cover.svelte';
import type { Models } from '@appwrite.io/console';
import { functionsList } from '../store';
import { debounce } from '$lib/helpers/debounce';
- import { Tooltip, Typography } from '@appwrite.io/pink-svelte';
+ import {
+ Accordion,
+ AvatarGroup,
+ Layout,
+ Selector,
+ Tooltip,
+ Typography,
+ Card as PinkCard
+ } from '@appwrite.io/pink-svelte';
import { capitalize } from '$lib/helpers/string';
+ import Card from '$lib/components/card.svelte';
+ import Link from '$lib/elements/link.svelte';
+ import Avatar from '$lib/components/avatar.svelte';
+ import PaginationWithLimit from '$lib/components/paginationWithLimit.svelte';
+ import { getIconFromRuntime } from '$lib/stores/runtimes';
export let data;
- function applyFilter(filter: string, value: string, event: Event) {
- const add = (event.target as EventTarget & HTMLInputElement).checked;
+ function applyFilter(filter: string, value: string, event: CustomEvent) {
const target = new URL($page.url);
- if (add) {
- target.searchParams.append(filter, value);
+ if (event?.detail) {
+ if (
+ !target.searchParams
+ .getAll(filter)
+ .some((n) => n.toLowerCase() === value.toLowerCase())
+ ) {
+ target.searchParams.append(filter, value);
+ }
} else {
const previous = target.searchParams
.getAll(filter)
@@ -58,29 +68,6 @@
return [...baseRuntimes.values()];
}
- function getIconFromRuntime(runtime: string) {
- switch (true) {
- case runtime.includes('node'):
- return 'node';
- case runtime.includes('php'):
- return 'php';
- case runtime.includes('ruby'):
- return 'ruby';
- case runtime.includes('python'):
- return 'python';
- case runtime.includes('dart'):
- return 'dart';
- case runtime.includes('bun'):
- return 'bun';
- case runtime.includes('go'):
- return 'go';
- case runtime.includes('deno'):
- return 'deno';
- default:
- return undefined;
- }
- }
-
function applySearch(event: CustomEvent) {
debounce(() => {
const value = event.detail;
@@ -122,154 +109,143 @@
-
-
Templates
-
- Experimental
-
-
-
-
+
+
-
-
-
- Use case
-
-
-
- Runtime
-
-
-
-
+
+
+
+ {#each [...data.useCases] as useCase}
+
+ {
+ console.log(useCase, e);
+ applyFilter('useCase', useCase, e);
+ }} />
+
+ {/each}
+
+
+
+
+ {#each [...data.runtimes] as runtime}
+
+
+ applyFilter('runtime', runtime, e)} />
+
+ {/each}
+
+
+
-
-
-
+
+
+
+ Contribute
+
+
+ Got a function template idea? View the contribution guidelines.
+
+
+
+
+
+
{#if data.templates.length > 0}
-
+
{#each data.templates as template}
{@const baseRuntimes = getBaseRuntimes(template.runtimes)}
{@const displayed = baseRuntimes.slice(0, 2)}
{@const hidden = baseRuntimes.slice(1, -1)}
-
-
-
-
+
+
+
+
{template.name}
-
-
+
+
+
+ {template.tagline}
+
+
+
+
+
{#each displayed as runtime}
{@const icon = getIconFromRuntime(runtime.name)}
{#if icon}
-
-
-
-
-
+
+
+
{/if}
{/each}
{#if hidden.length}
-
-
-
- {hidden
- .map((n) => n.name)
- .join(', ')}
-
-
+
+
+ {hidden.map((n) => n.name).join(', ')}
+
{/if}
-
-
-
-
- {template.tagline}
-
-
-
-
- View details
-
- {#if $canWriteFunctions}
- connectTemplate(template)}
- showIcon={false}
- buttonText="Create function"
- buttonEvent="create_function" />
- {/if}
-
-
-
+
+
+
+ Details
+
+ {#if $canWriteFunctions}
+
+ {/if}
+
+
+
+
{/each}
-
+
{:else}
@@ -283,25 +259,11 @@
{/if}
-
-
Total templates: {data.sum}
-
-
-
-
+
+
+
-
-
diff --git a/src/routes/(console)/project-[project]/functions/templates/+page.ts b/src/routes/(console)/project-[project]/functions/templates/+page.ts
index 1f8f6301a..2b9d51e02 100644
--- a/src/routes/(console)/project-[project]/functions/templates/+page.ts
+++ b/src/routes/(console)/project-[project]/functions/templates/+page.ts
@@ -1,12 +1,12 @@
-import { CARD_LIMIT, Dependencies } from '$lib/constants';
-import { getPage, getSearch, getView, pageToOffset, View } from '$lib/helpers/load';
+import { Dependencies, PAGE_LIMIT } from '$lib/constants';
+import { getLimit, getPage, getSearch, getView, pageToOffset, View } from '$lib/helpers/load';
import { sdk } from '$lib/stores/sdk';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ url, route, depends, parent }) => {
depends(Dependencies.FUNCTIONS);
- const limit = CARD_LIMIT;
+ const limit = getLimit(url, route, PAGE_LIMIT);
const page = getPage(url);
const search = getSearch(url);
const view = getView(url, route, View.Grid);
diff --git a/src/routes/(console)/project-[project]/functions/templates/template-[template]/+page.svelte b/src/routes/(console)/project-[project]/functions/templates/template-[template]/+page.svelte
index 41b75e0eb..4ab0696d9 100644
--- a/src/routes/(console)/project-[project]/functions/templates/template-[template]/+page.svelte
+++ b/src/routes/(console)/project-[project]/functions/templates/template-[template]/+page.svelte
@@ -1,107 +1,104 @@
-
-
-
-
-
- Use cases
- {$template.useCases.length}
-
-
- {#each $template.useCases as useCase}
-
{useCase}
- {/each}
-
-
-
-
- Runtimes
- {$template.runtimes.length}
-
-
- {#each $template.runtimes as runtime}
-
{runtime.name}
- {/each}
-
-
-
-
- Published by
-
-
-
-
-
-
-
-
-
-
-
-
- {$template.name}
-
-
- {$template.tagline}
+
+
+
+
+ Published by
+
+
+
+
+
+
+
+
+
+ About
+
+
+ {$template.tagline}
+
+
+
+
+ Use cases
+
+
+ {#each $template.useCases as useCase}
+
+ {/each}
+
+
+
+
+ Runtimes
+
+
+ {#each $template.runtimes as runtime}
+
+ {/each}
+
+
+
-
+
+
+
View source
-
+
{#if $canWriteFunctions}
connectTemplate($template)}
+ buttonHref={`${base}/project-${$page.params.project}/functions/create-function/template-${$template.id}`}
showIcon={false}
buttonText="Create function"
buttonEvent="create_function" />
{/if}
-
-
-
-
+
+
+
+
-
-
diff --git a/src/routes/(console)/project-[project]/functions/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[project]/functions/usage/[[period]]/+page.svelte
new file mode 100644
index 000000000..b58fa9d8c
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/usage/[[period]]/+page.svelte
@@ -0,0 +1,19 @@
+
+
+
diff --git a/src/routes/(console)/project-[project]/functions/usage/[[period]]/+page.ts b/src/routes/(console)/project-[project]/functions/usage/[[period]]/+page.ts
new file mode 100644
index 000000000..56ec087a5
--- /dev/null
+++ b/src/routes/(console)/project-[project]/functions/usage/[[period]]/+page.ts
@@ -0,0 +1,16 @@
+import { isValueOfStringEnum } from '$lib/helpers/types';
+import { sdk } from '$lib/stores/sdk';
+import { FunctionUsageRange } from '@appwrite.io/console';
+import type { PageLoad } from './$types';
+import { error } from '@sveltejs/kit';
+
+export const load: PageLoad = async ({ params }) => {
+ const period = isValueOfStringEnum(FunctionUsageRange, params.period)
+ ? params.period
+ : FunctionUsageRange.ThirtyDays;
+ try {
+ return sdk.forProject.functions.listUsage(period);
+ } catch (e) {
+ error(e.code, e.message);
+ }
+};
diff --git a/src/routes/(console)/project-[project]/functions/wizard/step1.svelte b/src/routes/(console)/project-[project]/functions/wizard/step1.svelte
deleted file mode 100644
index d8c08dd1e..000000000
--- a/src/routes/(console)/project-[project]/functions/wizard/step1.svelte
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
- Configuration
- Create your new Appwrite Function.
-
-
-
-
- {#if !showCustomId}
-
-
(showCustomId = !showCustomId)}>
-
- Function ID
-
-
- {:else}
-
- {/if}
-
-
diff --git a/src/routes/(console)/project-[project]/functions/wizard/step2.svelte b/src/routes/(console)/project-[project]/functions/wizard/step2.svelte
deleted file mode 100644
index bac95bfbe..000000000
--- a/src/routes/(console)/project-[project]/functions/wizard/step2.svelte
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
- Permissions
-
- Choose which users have permission to execute this function using Client SDKs. For more
- information, visit our
- permissions documentation
- .
-
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/wizard/step3.svelte b/src/routes/(console)/project-[project]/functions/wizard/step3.svelte
deleted file mode 100644
index 9c44e66c4..000000000
--- a/src/routes/(console)/project-[project]/functions/wizard/step3.svelte
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
- Events
-
- Set the events that will trigger your function. Maximum 100 events allowed.
- Learn more about events.
- .
-
-
- {#if $createFunction?.events?.length}
-
- {#each $createFunction.events as event}
-
-
- {event}
-
-
- {
- eventSet.delete(event);
- $createFunction.events = Array.from(eventSet);
- }}>
-
-
-
-
- {/each}
-
-
- (showCreate = !showCreate)}>
-
- Add event
-
-
- {:else}
- (showCreate = !showCreate)}>Add an event
- {/if}
-
-
-{#if showCreate}
-
-
- Select events in your Appwrite project that will trigger your functionLearn more about Appwrite Events .
-
-
-{/if}
diff --git a/src/routes/(console)/project-[project]/functions/wizard/step4.svelte b/src/routes/(console)/project-[project]/functions/wizard/step4.svelte
deleted file mode 100644
index 4d889bdaa..000000000
--- a/src/routes/(console)/project-[project]/functions/wizard/step4.svelte
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
- Schedule
-
- Set a Cron schedule to trigger your function. Leave blank for no schedule. More details on Cron syntax here .
-
-
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/wizard/step5.svelte b/src/routes/(console)/project-[project]/functions/wizard/step5.svelte
deleted file mode 100644
index 54ec9fbba..000000000
--- a/src/routes/(console)/project-[project]/functions/wizard/step5.svelte
+++ /dev/null
@@ -1,130 +0,0 @@
-
-
-
- Variables
-
- Create the environment variables or secret keys that will be passed to your function.
- permissions documentation
- .
-
- {#if $createFunction.vars.length}
-
-
- Key
- Value
-
-
-
-
- {#each $createFunction.vars as variable, i}
-
-
-
- {variable.key}
-
-
-
-
-
-
-
- (showDropdown[i] = !showDropdown[i])}>
-
-
-
- {
- selectedVar = $createFunction.vars[i];
- showDropdown[i] = false;
- showCreate = true;
- }}>
- Edit
-
- {
- $createFunction.vars.splice(i, 1);
- $createFunction = $createFunction;
- showDropdown[i] = false;
- }}>
- Delete
-
-
-
-
-
- {/each}
-
-
-
- (showCreate = !showCreate)}>
-
- Create variable
-
-
- {:else}
- (showCreate = !showCreate)}>Create a variable
- {/if}
-
-
-{#if showCreate}
-
-{/if}
diff --git a/src/routes/(console)/project-[project]/functions/wizard/store.ts b/src/routes/(console)/project-[project]/functions/wizard/store.ts
deleted file mode 100644
index 3edb18648..000000000
--- a/src/routes/(console)/project-[project]/functions/wizard/store.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import type { Models } from '@appwrite.io/console';
-import { writable } from 'svelte/store';
-
-export const createFunction = writable<{
- id?: string;
- name: string;
- entrypoint: string;
- execute: string[];
- runtime: string;
- vars?: Partial[];
- events?: string[];
- schedule?: string;
- timeout?: number;
-}>({
- id: null,
- name: null,
- entrypoint: null,
- execute: [],
- runtime: null,
- vars: [],
- events: [],
- schedule: null,
- timeout: null
-});
diff --git a/src/routes/(console)/project-[project]/messaging/+page.svelte b/src/routes/(console)/project-[project]/messaging/+page.svelte
index d9770f274..31ecb820f 100644
--- a/src/routes/(console)/project-[project]/messaging/+page.svelte
+++ b/src/routes/(console)/project-[project]/messaging/+page.svelte
@@ -14,19 +14,8 @@
} from '$lib/components';
import { Filters, hasPageQueries } from '$lib/components/filters';
import { Button } from '$lib/elements/forms';
- import {
- TableBody,
- TableCell,
- TableCellCheck,
- TableCellHead,
- TableCellHeadCheck,
- TableCellText,
- TableHeader,
- TableRowLink,
- TableScroll
- } from '$lib/elements/table';
import { toLocaleDateTime } from '$lib/helpers/date';
- import { Container, ContainerHeader } from '$lib/layout';
+ import { Container } from '$lib/layout';
import { MessagingProviderType } from '@appwrite.io/console';
import type { PageData } from './$types';
import CreateMessageDropdown from './createMessageDropdown.svelte';
@@ -42,15 +31,14 @@
import type { Column } from '$lib/helpers/types';
import { writable } from 'svelte/store';
import { canWriteMessages } from '$lib/stores/roles';
- import { Layout, Typography } from '@appwrite.io/pink-svelte';
+ import { Layout, Selector, Table } from '@appwrite.io/pink-svelte';
- export let data: PageData;
+ export let data;
let selected: string[] = [];
let showDelete = false;
let deleting = false;
let showFailed = false;
let errors: string[] = [];
- let showCreateDropdownDesktop = false;
let showCreateDropdownMobile = false;
let showCreateDropdownEmpty = false;
const columns = writable([
@@ -97,98 +85,92 @@
+ placeholder="Search by ID, description, type, or status" />
-
-
+
+
{#if $canWriteMessages}
-
+
{/if}
{#if data.messages.total}
-
-
+
+
{#if $canWriteMessages}
- d.$id)} />
+
{/if}
{#each $columns as column}
{#if column.show}
- {column.title}
+ {column.title}
{/if}
{/each}
-
-
- {#each data.messages.messages as message (message.$id)}
-
- {#if $canWriteMessages}
-
+ {#each data.messages.messages as message (message.$id)}
+
+ {#if $canWriteMessages}
+
+
- {/if}
- {#each $columns as column (column.id)}
- {#if column.show}
- {#if column.id === '$id'}
- {#key $columns}
-
- {message.$id}
-
- {/key}
- {:else if column.id === 'message'}
-
- {#if message.providerType === MessagingProviderType.Push}
- {message.data.title}
- {:else if message.providerType === MessagingProviderType.Sms}
- {message.data.content}
- {:else if message.providerType === MessagingProviderType.Email}
- {message.data.subject}
- {:else}
- Invalid provider
- {/if}
-
- {:else if column.id === 'providerType'}
-
-
-
- {:else if column.id === 'status'}
-
-
-
- {#if message.status === 'failed'}
- {
- e.preventDefault();
- errors = message.deliveryErrors;
- showFailed = true;
- }}>Details
- {/if}
-
-
- {:else if column.type === 'datetime'}
-
- {#if !message[column.id]}
- -
- {:else}
- {toLocaleDateTime(message[column.id])}
- {/if}
-
- {:else}
-
- {message[column.id]}
-
- {/if}
+
+ {/if}
+ {#each $columns as column (column.id)}
+ {#if column.show}
+ {#if column.id === '$id'}
+ {#key $columns}
+
+ {message.$id}
+
+ {/key}
+ {:else if column.id === 'message'}
+
+ {#if message.providerType === MessagingProviderType.Push}
+ {message.data.title}
+ {:else if message.providerType === MessagingProviderType.Sms}
+ {message.data.content}
+ {:else if message.providerType === MessagingProviderType.Email}
+ {message.data.subject}
+ {:else}
+ Invalid provider
+ {/if}
+
+ {:else if column.id === 'providerType'}
+
+
+
+ {:else if column.id === 'status'}
+
+
+ {#if message.status === 'failed'}
+ {
+ e.preventDefault();
+ errors = message.deliveryErrors;
+ showFailed = true;
+ }}>Details
+ {/if}
+
+ {:else if column.type === 'datetime'}
+
+ {#if !message[column.id]}
+ -
+ {:else}
+ {toLocaleDateTime(message[column.id])}
+ {/if}
+
+ {:else}
+
+ {message[column.id]}
+
{/if}
- {/each}
-
- {/each}
-
-
+ {/if}
+ {/each}
+
+ {/each}
+
0}>
@@ -235,15 +217,7 @@
{:else}
($showCreate = true)}>
-
-
- Create your first message to get started.
-
-
- Need a hand? Learn more in our documentation.
-
-
-
+
{#if $canWriteMessages}
-
- (showCreateDropdownEmpty = !showCreateDropdownEmpty)}
- event="create_message">
+
+
Create message
{/if}
-
+
{/if}
diff --git a/src/routes/(console)/project-[project]/messaging/actions.svelte b/src/routes/(console)/project-[project]/messaging/actions.svelte
index 0ca3f9c17..5ec9db9b4 100644
--- a/src/routes/(console)/project-[project]/messaging/actions.svelte
+++ b/src/routes/(console)/project-[project]/messaging/actions.svelte
@@ -14,7 +14,7 @@
const dispatch = createEventDispatcher();
-
+
@@ -26,23 +26,27 @@
- {
- showTopics = false;
- dispatch('addTopics', e.detail);
- }} />
- {
- showUserTargets = false;
- dispatch('addTargets', e.detail);
- }}>
- Select existing targets to which you want to send this message.
-
+{#if showTopics}
+ {
+ showTopics = false;
+ dispatch('addTopics', e.detail);
+ }} />
+{/if}
+{#if showUserTargets}
+ {
+ showUserTargets = false;
+ dispatch('addTargets', e.detail);
+ }}>
+ Select existing targets to which you want to send this message.
+
+{/if}
diff --git a/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/(components)/schedule.svelte b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/(components)/schedule.svelte
new file mode 100644
index 000000000..3c7690ae7
--- /dev/null
+++ b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/(components)/schedule.svelte
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+ {#if when === 'now'}
+ The message will be sent immediately
+ {:else if !dateTime || isNaN(dateTime.getTime())}
+ The message will be sent later
+ {:else}
+ The message will be sent at {dateTime.toLocaleString('en', formatOptions)}
+ {/if}
+
+
+{#if showConfirmation}
+
+
+ You are about to send a message to an estimated {totalTargets} recipients. Would you like to proceed?
+
+ This action is irreversible.
+
+ (showConfirmation = false)}>Cancel
+ Send
+
+
+{/if}
diff --git a/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/(components)/targets.svelte b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/(components)/targets.svelte
new file mode 100644
index 000000000..5437fc5c7
--- /dev/null
+++ b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/(components)/targets.svelte
@@ -0,0 +1,137 @@
+
+
+{#if !hasTargets && !hasTopics}
+
+
+
+
+
+
+
+
+ Select targets to get started
+
+
+
+{:else}
+
+
+
+ Target
+
+
+ {#each Object.entries($topicsById) as [topicId, topic] (topicId)}
+
+
+ {topic.name}
+ ({getTotal(topic)} targets)
+
+
+
+ removeTopic(topicId)}>
+
+
+
+
+
+ {/each}
+ {#each Object.entries($targetsById) as [targetId, target] (targetId)}
+
+
+ {target.name ? target.name : target.identifier}
+
+
+
+
+ removeTarget(targetId)}>
+
+
+
+
+
+ {/each}
+
+
+
+{/if}
diff --git a/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/email.svelte b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/email.svelte
new file mode 100644
index 000000000..c2d402a82
--- /dev/null
+++ b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/email.svelte
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+ {#if !showCustomId}
+
+ (showCustomId = !showCustomId)}
+ > Message ID
+
+ {:else}
+
+ {/if}
+
+
+
+
+ Enable the HTML mode if your message contains HTML tags.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (showExitModal = true)}>Cancel
+ Save as draft
+ formComponent.triggerSubmit()}
+ disabled={$isSubmitting}>
+ Create
+
+
+
diff --git a/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/push.svelte b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/push.svelte
new file mode 100644
index 000000000..b489b18e6
--- /dev/null
+++ b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/push.svelte
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+ {#if !showCustomId}
+
+ (showCustomId = !showCustomId)}
+ > Message ID
+
+ {:else}
+
+ {/if}
+
+
+
+
+
+
+
+
+ A key/value payload of additional metadata that's hidden from users. Use
+ this to include information to support logic such as redirection and
+ routing.
+
+ {#each $data as [key, value], index}
+
+
+
+
+ {
+ if (index === 0 && $data?.length === 1) {
+ $data = [['', '']];
+ } else {
+ $data.splice(index, 1);
+ $data = $data;
+ }
+ }}>
+
+
+
+
+ {/each}
+
+ 0 && $data[$data.length - 1][0] === ''}
+ on:click={() => ($data = [...$data, ['', '']])}>
+
+ Add data
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (showExitModal = true)}>Cancel
+ Save as draft
+ formComponent.triggerSubmit()}
+ disabled={$isSubmitting}>
+ Create
+
+
+
diff --git a/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/sms.svelte b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/sms.svelte
new file mode 100644
index 000000000..644d87d10
--- /dev/null
+++ b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/sms.svelte
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+
+ {#if !showCustomId}
+
+ (showCustomId = !showCustomId)}
+ > Message ID
+
+ {:else}
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (showExitModal = true)}>Cancel
+ Save as draft
+ formComponent.triggerSubmit()}
+ disabled={$isSubmitting}>
+ Create
+
+
+
diff --git a/src/routes/(console)/project-[project]/messaging/create-[type]/+page.svelte b/src/routes/(console)/project-[project]/messaging/create-[type]/+page.svelte
new file mode 100644
index 000000000..cb6fe1e58
--- /dev/null
+++ b/src/routes/(console)/project-[project]/messaging/create-[type]/+page.svelte
@@ -0,0 +1,5 @@
+
+
+
diff --git a/src/routes/(console)/project-[project]/messaging/create-[type]/+page.ts b/src/routes/(console)/project-[project]/messaging/create-[type]/+page.ts
new file mode 100644
index 000000000..d21793d27
--- /dev/null
+++ b/src/routes/(console)/project-[project]/messaging/create-[type]/+page.ts
@@ -0,0 +1,30 @@
+import { isValueOfStringEnum } from '$lib/helpers/types';
+import { MessagingProviderType } from '@appwrite.io/console';
+import type { PageLoad } from './$types';
+import { error } from '@sveltejs/kit';
+import Push from './(type)/push.svelte';
+import Email from './(type)/email.svelte';
+import Sms from './(type)/sms.svelte';
+
+function getComponent(type: string) {
+ switch (type) {
+ case MessagingProviderType.Push:
+ return Push;
+ case MessagingProviderType.Email:
+ return Email;
+ case MessagingProviderType.Sms:
+ return Sms;
+ default:
+ return null;
+ }
+}
+
+export const load: PageLoad = async ({ params }) => {
+ if (!isValueOfStringEnum(MessagingProviderType, params.type)) {
+ error(401, 'Invalid provider type');
+ }
+
+ return {
+ component: getComponent(params.type)
+ };
+};
diff --git a/src/routes/(console)/project-[project]/messaging/createMessageDropdown.svelte b/src/routes/(console)/project-[project]/messaging/createMessageDropdown.svelte
index e87598a16..46963ee5d 100644
--- a/src/routes/(console)/project-[project]/messaging/createMessageDropdown.svelte
+++ b/src/routes/(console)/project-[project]/messaging/createMessageDropdown.svelte
@@ -1,72 +1,26 @@
-
-
- (showCreateDropdown = !showCreateDropdown)} event="create_message">
+
+
+
Create message
-
+
{#each Object.entries(providers) as [type, option]}
- {
- if (
- type !== MessagingProviderType.Email &&
- type !== MessagingProviderType.Sms &&
- type !== MessagingProviderType.Push
- )
- return;
- $providerType = type;
- $topicsById = {};
- $targetsById = {};
- const common = {
- topics: [],
- users: [],
- targets: []
- };
- switch (type) {
- case MessagingProviderType.Email:
- $messageParams[$providerType] = {
- ...common,
- subject: '',
- content: ''
- };
- break;
- case MessagingProviderType.Sms:
- $messageParams[$providerType] = {
- ...common,
- content: ''
- };
- break;
- case MessagingProviderType.Push:
- $messageParams[$providerType] = {
- ...common,
- title: '',
- body: '',
- data: [['', '']]
- };
- break;
- }
- showCreateDropdown = false;
- wizard.start(Create);
- }}>
+
{option.name}
-
+
{/each}
-
-
+
+
diff --git a/src/routes/(console)/project-[project]/messaging/helper.ts b/src/routes/(console)/project-[project]/messaging/helper.ts
new file mode 100644
index 000000000..175b9658f
--- /dev/null
+++ b/src/routes/(console)/project-[project]/messaging/helper.ts
@@ -0,0 +1,14 @@
+import { MessagingProviderType, type Models } from '@appwrite.io/console';
+
+export function getProviderText(type: MessagingProviderType | Models.Provider['type']): string {
+ switch (type) {
+ case MessagingProviderType.Email:
+ return 'Email';
+ case MessagingProviderType.Sms:
+ return 'SMS';
+ case MessagingProviderType.Push:
+ return 'Push';
+ default:
+ return '';
+ }
+}
diff --git a/src/routes/(console)/project-[project]/messaging/message-[message]/emailMessage.svelte b/src/routes/(console)/project-[project]/messaging/message-[message]/emailMessage.svelte
index 47560f433..c4d1b65f2 100644
--- a/src/routes/(console)/project-[project]/messaging/message-[message]/emailMessage.svelte
+++ b/src/routes/(console)/project-[project]/messaging/message-[message]/emailMessage.svelte
@@ -69,11 +69,23 @@
Message
-
-
-
+
+
+ trackEvent(Submit.MessagingUpdateHtmlMode)}>
Enable the HTML mode if your message contains HTML tags.
diff --git a/src/routes/(console)/project-[project]/messaging/message-[message]/overview.svelte b/src/routes/(console)/project-[project]/messaging/message-[message]/overview.svelte
index 9ce223947..ddfe90ff3 100644
--- a/src/routes/(console)/project-[project]/messaging/message-[message]/overview.svelte
+++ b/src/routes/(console)/project-[project]/messaging/message-[message]/overview.svelte
@@ -10,6 +10,7 @@
import ScheduleModal from './scheduleModal.svelte';
import CancelModal from './cancelModal.svelte';
import { Typography } from '@appwrite.io/pink-svelte';
+ import { Click, trackEvent } from '$lib/actions/analytics';
export let message: Models.Message & { data: Record };
export let topics: Models.Topic[];
@@ -22,13 +23,9 @@
-
+
+ {text}
+
@@ -49,7 +46,12 @@
{#if message.status === 'draft'}
- (showSchedule = true)}>Schedule
+ {
+ showSchedule = true;
+ trackEvent(Click.MessagingScheduleClick);
+ }}>Schedule
(showSend = true)}>Send message
{:else if message.status === 'scheduled'}
diff --git a/src/routes/(console)/project-[project]/messaging/message-[message]/pushMessage.svelte b/src/routes/(console)/project-[project]/messaging/message-[message]/pushMessage.svelte
index a3f6a41c7..1cf8794f8 100644
--- a/src/routes/(console)/project-[project]/messaging/message-[message]/pushMessage.svelte
+++ b/src/routes/(console)/project-[project]/messaging/message-[message]/pushMessage.svelte
@@ -1,15 +1,6 @@
-
-
- {status}
-
-
+
diff --git a/src/routes/(console)/project-[project]/messaging/provider.svelte b/src/routes/(console)/project-[project]/messaging/provider.svelte
index a78eb75c0..8d11186bd 100644
--- a/src/routes/(console)/project-[project]/messaging/provider.svelte
+++ b/src/routes/(console)/project-[project]/messaging/provider.svelte
@@ -60,46 +60,29 @@
{#if icon === ''}
Invalid provider
{:else}
-
+
{#if !noIcon}
-
- {#if provider === Providers.SMTP}
-
- {:else}
-
- {/if}
-
+ {#if provider === Providers.SMTP}
+
+ {:else}
+
+ {/if}
{/if}
{name || displayName}
-
+
{/if}
diff --git a/src/routes/(console)/project-[project]/messaging/providerType.svelte b/src/routes/(console)/project-[project]/messaging/providerType.svelte
index 91f16310e..46f62ec92 100644
--- a/src/routes/(console)/project-[project]/messaging/providerType.svelte
+++ b/src/routes/(console)/project-[project]/messaging/providerType.svelte
@@ -1,36 +1,27 @@
@@ -38,17 +29,14 @@
{#if text === ''}
Invalid provider type
{:else}
-
+
{#if !noIcon}
-
-
-
+
+
+
{/if}
-
+
{text}
-
+
{/if}
diff --git a/src/routes/(console)/project-[project]/messaging/providers/+page.svelte b/src/routes/(console)/project-[project]/messaging/providers/+page.svelte
index dd4e8b955..28790a313 100644
--- a/src/routes/(console)/project-[project]/messaging/providers/+page.svelte
+++ b/src/routes/(console)/project-[project]/messaging/providers/+page.svelte
@@ -33,7 +33,7 @@
-
+
{#if $canWriteProviders}
diff --git a/src/routes/(console)/project-[project]/messaging/providers/createProviderDropdown.svelte b/src/routes/(console)/project-[project]/messaging/providers/createProviderDropdown.svelte
index 57934fa72..dce53c8b4 100644
--- a/src/routes/(console)/project-[project]/messaging/providers/createProviderDropdown.svelte
+++ b/src/routes/(console)/project-[project]/messaging/providers/createProviderDropdown.svelte
@@ -1,5 +1,4 @@
-
-
- (showCreateDropdown = !showCreateDropdown)} event="create_provider">
-
- Create provider
-
-
-
+
+
+
+ Create provider
+
+
{#each Object.entries(providers) as [type, option]}
- {
if (
type !== MessagingProviderType.Email &&
@@ -37,11 +32,10 @@
if (p && isValueOfStringEnum(Providers, p)) {
$provider = p;
}
- showCreateDropdown = false;
wizard.start(Create);
}}>
{option.name}
-
+
{/each}
-
-
+
+
diff --git a/src/routes/(console)/project-[project]/messaging/providers/provider-[provider]/updateStatus.svelte b/src/routes/(console)/project-[project]/messaging/providers/provider-[provider]/updateStatus.svelte
index 1eecb6deb..cac232ac5 100644
--- a/src/routes/(console)/project-[project]/messaging/providers/provider-[provider]/updateStatus.svelte
+++ b/src/routes/(console)/project-[project]/messaging/providers/provider-[provider]/updateStatus.svelte
@@ -12,6 +12,7 @@
import ProviderType from '../../providerType.svelte';
import { provider as providerData } from './store';
import { Typography } from '@appwrite.io/pink-svelte';
+ import { getProviderText } from '../../helper';
let enabled: boolean = null;
@@ -146,7 +147,7 @@
Provider:
- Type:
+ Type: {getProviderText($providerData.type)}
Created: {toLocaleDateTime($providerData.$createdAt)}
diff --git a/src/routes/(console)/project-[project]/messaging/providers/store.ts b/src/routes/(console)/project-[project]/messaging/providers/store.ts
index ae968d4ba..59741d2ff 100644
--- a/src/routes/(console)/project-[project]/messaging/providers/store.ts
+++ b/src/routes/(console)/project-[project]/messaging/providers/store.ts
@@ -3,6 +3,8 @@ import { MessagingProviderType, SmtpEncryption } from '@appwrite.io/console';
import { writable } from 'svelte/store';
import { Providers } from '../provider.svelte';
import { base } from '$app/paths';
+import type { ComponentType } from 'svelte';
+import { IconAnnotation, IconDeviceMobile, IconMail } from '@appwrite.io/pink-icons-svelte';
export const columns = writable([
{ id: '$id', title: 'Provider ID', type: 'string', show: true },
@@ -35,29 +37,31 @@ export type ProviderInput = {
options?: { label: string; value: string | number | boolean }[];
};
-type ProvidersMap = {
- [key in MessagingProviderType]: {
- name: string;
- text: string;
- icon: string;
- providers: {
- [key in Providers]?: {
- imageIcon?: string;
- classIcon?: string;
- title: string;
- description: string;
- needAHand?: string[];
- configure: (ProviderInput | ProviderInput[])[];
- };
+export type ProviderMapValue = {
+ name: string;
+ text: string;
+ icon: ComponentType;
+ providers: {
+ [key in Providers]?: {
+ imageIcon?: string;
+ classIcon?: string;
+ title: string;
+ description: string;
+ needAHand?: string[];
+ configure: (ProviderInput | ProviderInput[])[];
};
};
};
+export type ProvidersMap = {
+ [key in MessagingProviderType]: ProviderMapValue;
+};
+
export const providers: ProvidersMap = {
[MessagingProviderType.Push]: {
name: 'Push notification',
text: 'notifications',
- icon: 'device-mobile',
+ icon: IconDeviceMobile,
providers: {
[Providers.FCM]: {
imageIcon: 'firebase',
@@ -185,7 +189,7 @@ export const providers: ProvidersMap = {
[MessagingProviderType.Email]: {
name: 'Email',
text: 'emails',
- icon: 'mail',
+ icon: IconMail,
providers: {
[Providers.Mailgun]: {
imageIcon: 'mailgun',
@@ -400,7 +404,7 @@ export const providers: ProvidersMap = {
[MessagingProviderType.Sms]: {
name: 'SMS',
text: 'SMS',
- icon: 'annotation',
+ icon: IconAnnotation,
providers: {
[Providers.Twilio]: {
imageIcon: 'twilio',
diff --git a/src/routes/(console)/project-[project]/messaging/providers/table.svelte b/src/routes/(console)/project-[project]/messaging/providers/table.svelte
index 912e9c257..ebd0fb80c 100644
--- a/src/routes/(console)/project-[project]/messaging/providers/table.svelte
+++ b/src/routes/(console)/project-[project]/messaging/providers/table.svelte
@@ -3,17 +3,6 @@
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { FloatingActionBar, Id, Modal } from '$lib/components';
import { Button } from '$lib/elements/forms';
- import {
- TableBody,
- TableCell,
- TableCellCheck,
- TableCellHead,
- TableCellHeadCheck,
- TableCellText,
- TableHeader,
- TableRowLink,
- TableScroll
- } from '$lib/elements/table';
import { addNotification } from '$lib/stores/notifications';
import type { PageData } from './$types';
import { columns } from './store';
@@ -25,6 +14,8 @@
import { Dependencies } from '$lib/constants';
import { sdk } from '$lib/stores/sdk';
import { canWriteProviders } from '$lib/stores/roles';
+ import { Badge, Icon, Selector, Table } from '@appwrite.io/pink-svelte';
+ import { IconCheckCircle } from '@appwrite.io/pink-icons-svelte';
export let data: PageData;
@@ -62,66 +53,66 @@
}
-
-
+
+
{#if $canWriteProviders}
- d.$id)} />
+
{/if}
{#each $columns as column}
{#if column.show}
- {column.title}
+ {column.title}
{/if}
{/each}
-
-
- {#each data.providers.providers as provider (provider.$id)}
-
- {#if $canWriteProviders}
-
- {/if}
- {#each $columns as column}
- {#if column.show}
- {#if column.id === '$id'}
- {#key $columns}
-
- {provider.$id}
-
- {/key}
- {:else if column.id === 'provider'}
-
-
-
- {:else if column.id === 'type'}
-
-
-
- {:else if column.id === 'enabled'}
-
-
+
+ {#each data.providers.providers as provider (provider.$id)}
+
+ {#if $canWriteProviders}
+
+
+
+ {/if}
+ {#each $columns as column}
+ {#if column.show}
+ {#if column.id === '$id'}
+ {#key $columns}
+
+ {provider.$id}
+
+ {/key}
+ {:else if column.id === 'provider'}
+
+
+
+ {:else if column.id === 'type'}
+
+
+
+ {:else if column.id === 'enabled'}
+
+
+
{#if provider.enabled}
-
+
{/if}
-
- {provider.enabled ? 'enabled' : 'disabled'}
-
-
-
- {:else}
-
- {provider[column.id]}
-
- {/if}
+
+
+
+ {:else}
+
+ {provider[column.id]}
+
{/if}
- {/each}
-
- {/each}
-
-
+ {/if}
+ {/each}
+
+ {/each}
+
0}>
@@ -146,7 +137,6 @@
= {};
const inputs = providers[$providerType].providers[$provider].configure;
@@ -84,10 +85,10 @@
aria-hidden="true" />
How to enable
- {#if $providerType == MessagingProviderType.Push}notifications{:else} {/if} service?
+ >How to enable {getProviderText($provider)}
+ {#if $providerType == MessagingProviderType.Push}notifications{:else}{getProviderText(
+ $provider
+ )}{/if} service?
diff --git a/src/routes/(console)/project-[project]/messaging/topics/+page.svelte b/src/routes/(console)/project-[project]/messaging/topics/+page.svelte
index f4d8c8777..ab1efe59d 100644
--- a/src/routes/(console)/project-[project]/messaging/topics/+page.svelte
+++ b/src/routes/(console)/project-[project]/messaging/topics/+page.svelte
@@ -24,6 +24,7 @@
import { Icon, Layout } from '@appwrite.io/pink-svelte';
import { View } from '$lib/helpers/load';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
+ import { Click, trackEvent } from '$lib/actions/analytics';
export let data: PageData;
@@ -56,10 +57,15 @@
-
+
{#if $canWriteTopics}
- ($showCreate = true)} event="create_topic">
+ {
+ $showCreate = true;
+ trackEvent(Click.MessagingTopicCreateClick);
+ }}
+ event="create_topic">
Create topic
diff --git a/src/routes/(console)/project-[project]/messaging/topics/create.svelte b/src/routes/(console)/project-[project]/messaging/topics/create.svelte
index 944d51447..6be4a28bd 100644
--- a/src/routes/(console)/project-[project]/messaging/topics/create.svelte
+++ b/src/routes/(console)/project-[project]/messaging/topics/create.svelte
@@ -6,6 +6,8 @@
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { ID } from '@appwrite.io/console';
+ import { IconPencil } from '@appwrite.io/pink-icons-svelte';
+ import { Icon, Tag } from '@appwrite.io/pink-svelte';
import { createEventDispatcher } from 'svelte';
export let showCreate = false;
@@ -41,26 +43,24 @@
}
-
-
-
- {#if !showCustomId}
-
-
(showCustomId = !showCustomId)}
- >
- Topic ID
-
-
- {:else}
-
- {/if}
-
+
+
+ {#if !showCustomId}
+
+ (showCustomId = !showCustomId)}>
+
+ Topic ID
+
+
+ {:else}
+
+ {/if}
(showCreate = false)}>Cancel
Create
diff --git a/src/routes/(console)/project-[project]/messaging/topics/table.svelte b/src/routes/(console)/project-[project]/messaging/topics/table.svelte
index 2b7db0130..c4c0535e2 100644
--- a/src/routes/(console)/project-[project]/messaging/topics/table.svelte
+++ b/src/routes/(console)/project-[project]/messaging/topics/table.svelte
@@ -3,17 +3,6 @@
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { FloatingActionBar, Id, Modal } from '$lib/components';
import { Button } from '$lib/elements/forms';
- import {
- TableBody,
- TableCell,
- TableCellCheck,
- TableCellHead,
- TableCellHeadCheck,
- TableCellText,
- TableHeader,
- TableRowLink,
- TableScroll
- } from '$lib/elements/table';
import { addNotification } from '$lib/stores/notifications';
import type { PageData } from './$types';
import { invalidate } from '$app/navigation';
@@ -23,6 +12,7 @@
import type { Column } from '$lib/helpers/types';
import { page } from '$app/stores';
import { canWriteTopics } from '$lib/stores/roles';
+ import { Selector, Table } from '@appwrite.io/pink-svelte';
export let columns: Column[];
export let data: PageData;
@@ -59,57 +49,55 @@
}
-
-
+
+
{#if $canWriteTopics}
- d.$id)} />
+
{/if}
{#each columns as column}
{#if column.show}
- {column.title}
+ {column.title}
{/if}
{/each}
-
-
- {#each data.topics.topics as topic (topic.$id)}
-
- {#if $canWriteTopics}
-
- {/if}
- {#each columns as column (column.id)}
- {#if column.show}
- {#if column.id === '$id'}
- {#key column.id}
-
- {topic.$id}
-
- {/key}
- {:else if column.type === 'datetime'}
-
- {#if !topic[column.id]}
- -
- {:else}
- {toLocaleDateTime(topic[column.id])}
- {/if}
-
- {:else if column.id === 'total'}
-
- {topic.emailTotal + topic.smsTotal + topic.pushTotal}
-
- {:else}
-
- {topic[column.id]}
-
- {/if}
+
+ {#each data.topics.topics as topic (topic.$id)}
+
+ {#if $canWriteTopics}
+
+
+
+ {/if}
+ {#each columns as column (column.id)}
+ {#if column.show}
+ {#if column.id === '$id'}
+ {#key column.id}
+
+ {topic.$id}
+
+ {/key}
+ {:else if column.type === 'datetime'}
+
+ {#if !topic[column.id]}
+ -
+ {:else}
+ {toLocaleDateTime(topic[column.id])}
+ {/if}
+
+ {:else if column.id === 'total'}
+
+ {topic.emailTotal + topic.smsTotal + topic.pushTotal}
+
+ {:else}
+
+ {topic[column.id]}
+
{/if}
- {/each}
-
- {/each}
-
-
+ {/if}
+ {/each}
+
+ {/each}
+
0}>
diff --git a/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/+page.svelte b/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/+page.svelte
index 52597f85a..4ea8bbac4 100644
--- a/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/+page.svelte
+++ b/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/+page.svelte
@@ -14,7 +14,7 @@
import type { PageData } from './$types';
import { sdk } from '$lib/stores/sdk';
import { addNotification } from '$lib/stores/notifications';
- import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
+ import { Click, Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import Table from './table.svelte';
@@ -91,7 +91,12 @@
Subscribers
-
(showAdd = true)} event="create_subscriber">
+ {
+ showAdd = true;
+ trackEvent(Click.MessagingTargetCreateClick);
+ }}
+ event="create_subscriber">
Add subscriber
@@ -102,7 +107,7 @@
search={data.search}
placeholder="Search by subscriber ID, target ID, user ID, or type">
diff --git a/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/table.svelte b/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/table.svelte
index 92117b7c7..8ca76b1bb 100644
--- a/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/table.svelte
+++ b/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/table.svelte
@@ -26,6 +26,7 @@
import { targetsById } from '../../store';
import { MessagingProviderType, type Models } from '@appwrite.io/console';
import type { Column } from '$lib/helpers/types';
+ import { Selector, Table } from '@appwrite.io/pink-svelte';
export let columns: Column[];
export let data: PageData;
@@ -80,67 +81,54 @@
});
-
-
- d.$id)} />
+
+
+
{#each columns as column}
{#if column.show}
- {column.title}
+ {column.title}
{/if}
{/each}
-
-
- {#each data.subscribers.subscribers as subscriber (subscriber.$id)}
- {@const target = subscriber.target}
-
-
+
+ {#each data.subscribers.subscribers as subscriber (subscriber.$id)}
+ {@const target = subscriber.target}
+
+
+
+
- {#each columns as column}
- {#if column.show}
+ {#each columns as column}
+ {#if column.show}
+
{#if column.id === '$id'}
{#key column.id}
-
-
- {subscriber.$id}
-
-
+
+ {subscriber.$id}
+
{/key}
{:else if column.id === 'targetId'}
-
-
- {subscriber[column.id]}
-
-
- {:else if column.id === 'target'}
-
- {#if target.providerType === MessagingProviderType.Push}
- {target.name}
- {:else}
- {target.identifier}
- {/if}
-
- {:else if column.id === 'type'}
-
-
-
- {:else if column.id === '$createdAt'}
-
- {toLocaleDateTime(subscriber[column.id])}
-
- {:else}
-
+
{subscriber[column.id]}
-
+
+ {:else if column.id === 'target'}
+ {#if target.providerType === MessagingProviderType.Push}
+ {target.name}
+ {:else}
+ {target.identifier}
+ {/if}
+ {:else if column.id === 'type'}
+
+ {:else if column.id === '$createdAt'}
+ {toLocaleDateTime(subscriber[column.id])}
+ {:else}
+ {subscriber[column.id]}
{/if}
- {/if}
- {/each}
-
- {/each}
-
-
+
+ {/if}
+ {/each}
+
+ {/each}
+
0}>
diff --git a/src/routes/(console)/project-[project]/messaging/topicsModal.svelte b/src/routes/(console)/project-[project]/messaging/topicsModal.svelte
index 3cb51e63d..2159c4400 100644
--- a/src/routes/(console)/project-[project]/messaging/topicsModal.svelte
+++ b/src/routes/(console)/project-[project]/messaging/topicsModal.svelte
@@ -1,12 +1,20 @@
-
-
-
- Select existing topics you want to send this message to its targets. The message will be
- sent only to
-
- targets.
-
-
-
-
- {#if Object.keys(topicResultsById).length > 0 && !emptyTopicsExists}
-
-
-
-
- {#each Object.entries(topicResultsById) as [topicId, topic]}
-
-
-
- onTopicSelection(event, topic)}>
-
-
-
-
- {topic.name}
-
-
- ({getTotal(topic)} targets)
-
-
-
-
-
-
- {/each}
-
-
-
-
-
Total results: {totalResults}
-
-
-
- {:else if search}
-
-
-
-
Sorry we couldn't find "{search}"
-
There are no topics that match your search.
-
-
- Documentation
-
- (search = '')}
- >Clear search
-
-
-
-
- {:else}
-
-
-
-
- You have no topics{emptyTopicsExists
- ? ` with ${providerType.toUpperCase()} targets`
- : ''}. Create a topic to see them here.
-
-
- Need a hand? Learn more in our
- documentation
-
- .
-
-
-
-
- {/if}
+
+
+ Select existing topics you want to send this message to its targets. The message will be
+ sent only to {getProviderText(providerType)} targets.
+
+
+
+ {#if Object.keys(topicResultsById).length > 0 && !emptyTopicsExists}
+
+ {#each Object.entries(topicResultsById) as [topicId, topic]}
+
+
+
+ onTopicSelection(event, topic)}>
+
+
+ ({getTotal(topic)} targets)
+
+
+
+
+ {/each}
+
+
+
Total results: {totalResults}
+
-
-
+ {:else if search}
+
+ (search = '')}>
+ Clear search
+
+
+ {:else}
+
+
+ Documentation
+
+
+ {/if}
+
-
-
- {selectedSize}
- Topics selected
-
+
+
+
+ Topics selected
+
Add
-
+
diff --git a/src/routes/(console)/project-[project]/messaging/userTargetsModal.svelte b/src/routes/(console)/project-[project]/messaging/userTargetsModal.svelte
index a6409ec8f..31bd6062e 100644
--- a/src/routes/(console)/project-[project]/messaging/userTargetsModal.svelte
+++ b/src/routes/(console)/project-[project]/messaging/userTargetsModal.svelte
@@ -1,16 +1,12 @@
-
-
-
-
-
-
-
- {#if Object.keys(userResultsById).length > 0}
-
-
-
- {#each Object.entries(userResultsById) as [userId, user] (userId)}
- {@const selectedCount = user.targets.filter(
- (target) => selected[target.$id]
- ).length}
-
-
- 0 &&
- user.targets.every(
- (target) => targetsById[target.$id]
- ))}
- checked={selectedCount > 0 &&
- selectedCount === user.targets.length}
- on:change={(event) =>
- onUserSelection(event, userId)} />
-
-
-
-
- {#if user.name}
- {user.name}
- {:else if user.email}
- {user.email}
- {:else if user.phone}
- {user.phone}
- {:else}
- {userId}
- {/if}
-
-
-
-
- {#if user.targets.length === 0}
- (0 targets)
- {:else}
- ({selectedCount}/{user.targets.length} targets)
- {/if}
-
-
- {#each user.targets as target}
-
-
- onTargetSelection(event, target)}>
-
-
-
- {#if target.providerType !== MessagingProviderType.Push}
- {target.identifier}
- {:else}
- {target.name}
- {/if}
-
-
-
-
- {/each}
-
-
- {/each}
-
-
-
-
Total results: {totalResults}
-
-
-
- {:else if search}
-
-
-
-
Sorry we couldn't find "{search}"
-
There are no Users that match your search.
+
+
+
+
+ {#if Object.keys(userResultsById).length > 0}
+ {#each Object.entries(userResultsById) as [userId, user] (userId)}
+ {@const selectedCount = user.targets.filter(
+ (target) => selected[target.$id]
+ ).length}
+ 0 && selectedCount === user.targets.length}
+ on:change={(event) => onUserSelection(event, userId)}>
+ {#each user.targets as target}
+
+ onTargetSelection(event, target)}>
+
+
+
+ {#if target.providerType !== MessagingProviderType.Push}
+ {target.identifier}
+ {:else}
+ {target.name}
+ {/if}
-
- Documentation
- (search = '')}
- >Clear search
-
-
-
- {:else}
-
-
-
-
- You have no users. Create a user to see them here.
-
-
- Need a hand? Learn more in our documentation .
-
-
-
-
- {/if}
+
+ {/each}
+
+ {/each}
+
+
Total results: {totalResults}
+
-
-
+ {:else if search}
+
+ (search = '')}>
+ Clear search
+
+
+ {:else}
+
+
+ Documentation
+
+
+ {/if}
+
-
-
- {selectedUsers}
- Users selected
-
+
+
+
+ Users selected
+
Add
-
+
-
-
diff --git a/src/routes/(console)/project-[project]/messaging/wizard/emailFormList.svelte b/src/routes/(console)/project-[project]/messaging/wizard/emailFormList.svelte
index b4568b02d..fcb66f702 100644
--- a/src/routes/(console)/project-[project]/messaging/wizard/emailFormList.svelte
+++ b/src/routes/(console)/project-[project]/messaging/wizard/emailFormList.svelte
@@ -15,6 +15,7 @@
import { clickOnEnter } from '$lib/helpers/a11y';
import { ID, MessagingProviderType } from '@appwrite.io/console';
import { sdk } from '$lib/stores/sdk';
+ import { Submit, trackEvent } from '$lib/actions/analytics';
let showCustomId = false;
let showTest = false;
@@ -101,7 +102,13 @@
-
+ {
+ trackEvent(Submit.MessagingUpdateHtmlMode);
+ }}>
Enable the HTML mode if your message contains HTML tags.
diff --git a/src/routes/(console)/project-[project]/messaging/wizard/step1.svelte b/src/routes/(console)/project-[project]/messaging/wizard/step1.svelte
index d29471b39..be4221231 100644
--- a/src/routes/(console)/project-[project]/messaging/wizard/step1.svelte
+++ b/src/routes/(console)/project-[project]/messaging/wizard/step1.svelte
@@ -10,8 +10,6 @@
let docsUrl = `https://appwrite.io/docs/products/messaging`;
- async function beforeSubmit() {}
-
const createMessage = (providerText: string) => {
const vowels = ['a', 'e', 'i', 'o', 'u'];
const firstLetter = providerText.toLowerCase().charAt(0);
diff --git a/src/routes/(console)/project-[project]/messaging/wizard/step2.svelte b/src/routes/(console)/project-[project]/messaging/wizard/step2.svelte
index 10def028a..96a368434 100644
--- a/src/routes/(console)/project-[project]/messaging/wizard/step2.svelte
+++ b/src/routes/(console)/project-[project]/messaging/wizard/step2.svelte
@@ -1,21 +1,13 @@
@@ -92,7 +92,7 @@
- {#each [Category.Auth, Category.Database, Category.Functions, Category.Storage, Category.Messaging, Category.Other] as category}
+ {#each [Category.Auth, Category.Database, Category.Functions, Category.Storage, Category.Messaging, Category.Sites, Category.Other] as category}
{@const checked = categoryState(category, scopes)}
{@const scopesLength = allScopes.filter(
(n) => n.category === category && scopes.includes(n.scope)
diff --git a/src/routes/(console)/project-[project]/overview/onboard.svelte b/src/routes/(console)/project-[project]/overview/onboard.svelte
index 106aad1a6..129978a3f 100644
--- a/src/routes/(console)/project-[project]/overview/onboard.svelte
+++ b/src/routes/(console)/project-[project]/overview/onboard.svelte
@@ -35,13 +35,12 @@
import { AvatarGroup } from '$lib/components';
import type { Models } from '@appwrite.io/console';
import { getPlatformInfo } from '$lib/helpers/platform';
- import { trackEvent } from '$lib/actions/analytics';
+ import { Click, trackEvent } from '$lib/actions/analytics';
import { goto } from '$app/navigation';
function createKey() {
- trackEvent('onboarding_hub_platform', {
- platform: 'server',
- state: 'add'
+ trackEvent(Click.KeyCreateClick, {
+ source: 'onboarding'
});
goto(`${base}/project-${projectId}/overview/keys/create`, {
replaceState: true
@@ -56,6 +55,7 @@
if (platform) {
continuePlatform(type, platform.name, platform.key, platform.type);
} else {
+ trackEvent(Click.PlatformCreateClick, { source: 'onboarding' });
addPlatform(type);
}
}
@@ -392,7 +392,7 @@
direction={$isSmallViewport ? 'column' : 'row'}>
{
- trackEvent('onboarding_hub_setup_databases');
+ trackEvent(Click.OnboardingSetupDatabaseClick);
goto(`${base}/project-${projectId}/databases`);
}}
padding="s"
@@ -430,7 +430,7 @@
href="https://appwrite.io/docs/references"
on:click={() => {
trackEvent(
- 'onboarding_hub_api_references'
+ Click.OnboardingApiReferencesClick
);
}}
target="_blank">API references
@@ -438,7 +438,9 @@
variant="quiet-muted"
href="https://appwrite.io/docs/tutorials"
on:click={() => {
- trackEvent('onboarding_hub_tutorials');
+ trackEvent(
+ Click.OnboardingTutorialsClick
+ );
}}
target="_blank">Tutorials
{
trackEvent(
- 'onboarding_hub_storage_quick_start'
+ Click.OnboardingStorageQuickstartClick
);
}}
target="_blank"
@@ -457,7 +459,7 @@
href="https://appwrite.io/docs/products/functions/quick-start"
on:click={() => {
trackEvent(
- 'onboarding_hub_functions_quick_start'
+ Click.OnboardingFunctionsQuickstartClick
);
}}
target="_blank"
@@ -487,7 +489,7 @@
href={`${base}/project-${projectId}/auth/settings`}
on:click={() => {
trackEvent(
- 'onboarding_hub_auth_email_password'
+ Click.OnboardingAuthEmailPasswordClick
);
}}
>E-mail and password
@@ -497,7 +499,7 @@
href={`${base}/project-${projectId}/auth/settings`}
on:click={() => {
trackEvent(
- 'onboarding_hub_auth_oauth2'
+ Click.OnboardingAuthOauth2Click
);
}}>OAuth 2
{
trackEvent(
- 'onboarding_hub_auth_all_methods'
+ Click.OnboardingAuthAllMethodsClick
);
}}>View all methods
@@ -525,7 +527,7 @@
href="https://appwrite.io/discord"
padding="s"
on:click={() => {
- trackEvent('onboarding_hub_discord');
+ trackEvent(Click.OnboardingDiscordClick);
}}>
diff --git a/src/routes/(console)/project-[project]/overview/platforms/+page.svelte b/src/routes/(console)/project-[project]/overview/platforms/+page.svelte
index a34605598..76aff7e25 100644
--- a/src/routes/(console)/project-[project]/overview/platforms/+page.svelte
+++ b/src/routes/(console)/project-[project]/overview/platforms/+page.svelte
@@ -6,7 +6,7 @@
import CreateReactNative from './createReactNative.svelte';
import CreateWeb from './createWeb.svelte';
import { createPlatform, versions } from './wizard/store';
- import { trackEvent } from '$lib/actions/analytics';
+ import { Click, trackEvent } from '$lib/actions/analytics';
export enum Platform {
Web,
@@ -19,9 +19,9 @@
export async function addPlatform(type: Platform) {
await versions.load();
createPlatform.reset();
- trackEvent('onboarding_hub_platform', {
+ trackEvent(Click.PlatformCreateClick, {
platform: platforms[type],
- state: 'add'
+ source: 'platforms_page'
});
wizard.start(platforms[type]);
}
@@ -38,7 +38,7 @@
key: key,
type: type
});
- trackEvent('onboarding_hub_platform', {
+ trackEvent(Click.PlatformCreateClick, {
platform: platforms[platform],
state: 'continue'
});
diff --git a/src/routes/(console)/project-[project]/overview/platforms/createWeb.svelte b/src/routes/(console)/project-[project]/overview/platforms/createWeb.svelte
index bba4cecc2..a00301f73 100644
--- a/src/routes/(console)/project-[project]/overview/platforms/createWeb.svelte
+++ b/src/routes/(console)/project-[project]/overview/platforms/createWeb.svelte
@@ -77,7 +77,7 @@ APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject.client.config.endpoint}"
label: 'React',
icon: ReactFrameworkIcon,
smallIcon: IconReact,
- portNumber: 3000
+ portNumber: 5173
},
{
key: 'nuxt',
@@ -231,7 +231,7 @@ APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject.client.config.endpoint}"
+ code={`\ngit clone https://github.com/appwrite/starter-for-${selectedFramework.key}\ncd starter-for-${selectedFramework.key}`} />
{#if selectedFramework.key === 'angular'}
diff --git a/src/routes/(console)/project-[project]/overview/realtime.svelte b/src/routes/(console)/project-[project]/overview/realtime.svelte
index 14b5f50f3..9e21c4b9c 100644
--- a/src/routes/(console)/project-[project]/overview/realtime.svelte
+++ b/src/routes/(console)/project-[project]/overview/realtime.svelte
@@ -3,8 +3,9 @@
import { BarChart } from '$lib/charts';
import { Card } from '$lib/components';
import { formatNum } from '$lib/helpers/string';
- import { Link, Typography } from '@appwrite.io/pink-svelte';
+ import { Icon, Layout, Link, Typography } from '@appwrite.io/pink-svelte';
import { stats } from '../store';
+ import { IconChartSquareBar } from '@appwrite.io/pink-icons-svelte';
$: projectId = $page.params.project;
$: projectStats = $stats?.get(projectId);
@@ -28,18 +29,13 @@
{:else}
-
-
+
+
No data to show
Get started with Realtime
-
+
{/if}
diff --git a/src/routes/(console)/project-[project]/overview/requests.svelte b/src/routes/(console)/project-[project]/overview/requests.svelte
index 9a484763a..e9e193ed4 100644
--- a/src/routes/(console)/project-[project]/overview/requests.svelte
+++ b/src/routes/(console)/project-[project]/overview/requests.svelte
@@ -14,7 +14,11 @@
Popover,
Typography
} from '@appwrite.io/pink-svelte';
- import { IconChevronDown, IconChevronUp } from '@appwrite.io/pink-icons-svelte';
+ import {
+ IconChartSquareBar,
+ IconChevronDown,
+ IconChevronUp
+ } from '@appwrite.io/pink-icons-svelte';
export let period: UsagePeriods;
@@ -68,12 +72,9 @@
{:else}
-
+
+
+ No data to show
+
{/if}
diff --git a/src/routes/(console)/project-[project]/promoteVariableModal.svelte b/src/routes/(console)/project-[project]/promoteVariableModal.svelte
index 6d9a98b3d..d250984ef 100644
--- a/src/routes/(console)/project-[project]/promoteVariableModal.svelte
+++ b/src/routes/(console)/project-[project]/promoteVariableModal.svelte
@@ -1,7 +1,8 @@
- {
dispatch('promoted');
}}>
-
- {isConflicting ? 'Overwrite global variable' : 'Promote variable'}
-
+
{#if isConflicting}
Promoting this variable will overwrite your global variable with the same name. Are you
- sure you want to promote {selectedVar.key} ?
+ sure you want to promote {selectedVar.key} ?
{:else}
- Are you sure you want to promote {selectedVar.key} ?
- This will convert it to a global variable that can be accessed by other functions in
+ Are you sure you want to promote {selectedVar.key} ? This will convert it to a global variable that can be accessed by other resources in
your project.
{/if}
@@ -35,4 +38,4 @@
(showPromote = false)}>Cancel
{isConflicting ? 'Promote anyway' : 'Promote'}
-
+
diff --git a/src/routes/(console)/project-[project]/secretVariableModal.svelte b/src/routes/(console)/project-[project]/secretVariableModal.svelte
new file mode 100644
index 000000000..a13333238
--- /dev/null
+++ b/src/routes/(console)/project-[project]/secretVariableModal.svelte
@@ -0,0 +1,43 @@
+
+
+
+
+
+ Secret variables are hidden from both the UI and API. Once a variable is marked as
+ secret, this action cannot be reversed.
+
+ Are you sure you want to make this variable secret?
+
+
+
+ (show = false)}>Cancel
+ Mark as secret
+
+
+
diff --git a/src/routes/(console)/project-[project]/settings/+page.svelte b/src/routes/(console)/project-[project]/settings/+page.svelte
index ba532ad46..cc89b813d 100644
--- a/src/routes/(console)/project-[project]/settings/+page.svelte
+++ b/src/routes/(console)/project-[project]/settings/+page.svelte
@@ -2,7 +2,6 @@
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { addNotification } from '$lib/stores/notifications';
- import { organizationList } from '$lib/stores/organization';
import { project } from '../store';
import { Container } from '$lib/layout';
import { invalidate } from '$app/navigation';
@@ -10,18 +9,15 @@
import UpdateName from './updateName.svelte';
import UpdateServices from './updateServices.svelte';
import UpdateInstallations from './updateInstallations.svelte';
- import UpdateVariables from '../updateVariables.svelte';
import DeleteProject from './deleteProject.svelte';
- import { CardGrid } from '$lib/components';
- import { Button, InputSelect } from '$lib/elements/forms';
import { Submit, trackEvent } from '$lib/actions/analytics';
- import Transfer from './transferProject.svelte';
import { canWriteProjects } from '$lib/stores/roles';
+ import ChangeOrganization from './changeOrganization.svelte';
+ import UpdateVariables from '../updateVariables.svelte';
export let data;
let teamId: string = null;
- let showTransfer = false;
onMount(() => {
teamId ??= $project.teamId;
@@ -63,8 +59,13 @@
await invalidate(Dependencies.PROJECT_VARIABLES);
}
- async function sdkUpdateVariable(variableId: string, key: string, value: string) {
- await sdk.forProject.projectApi.updateVariable(variableId, key, value);
+ async function sdkUpdateVariable(
+ variableId: string,
+ key: string,
+ value: string,
+ secret: boolean
+ ) {
+ await sdk.forProject.projectApi.updateVariable(variableId, key, value, secret);
await invalidate(Dependencies.PROJECT_VARIABLES);
}
@@ -85,40 +86,10 @@
{sdkUpdateVariable}
{sdkDeleteVariable}
isGlobal={true}
- variableList={data.variables} />
-
- Transfer project
- Transfer your project to another organization that you own.
-
- team.$id !== $project.teamId)
- .map((team) => ({
- value: team.$id,
- label: team.name
- }))} />
-
-
-
- (showTransfer = true)}>Transfer
-
-
+ variableList={data.variables}
+ analyticsSource="project_settings" />
+
{/if}
{/if}
-
-{#if teamId}
- t.$id == teamId).name}
- bind:show={showTransfer} />
-{/if}
diff --git a/src/routes/(console)/project-[project]/settings/GitDisconnectModal.svelte b/src/routes/(console)/project-[project]/settings/GitDisconnectModal.svelte
index 1cf3592fc..869238418 100644
--- a/src/routes/(console)/project-[project]/settings/GitDisconnectModal.svelte
+++ b/src/routes/(console)/project-[project]/settings/GitDisconnectModal.svelte
@@ -1,14 +1,15 @@
-
- {#await loadFunctions()}
+
+ {#await Promise.all([loadFunctions(), loadSites()])}
- {:then functions}
- {#if functions.total}
+ {:then [functions, sites]}
+ {#if functions?.total || sites?.total}
Are you sure you want to disconnect this git installation? This will affect future
- deployments to the following functions:
+ deployments to the following sites and functions:
-
- {#each functions.functions as func}
-
-
-
-
-
-
{func.name}
-
- Last deployed: {toLocaleDateTime(func.$updatedAt)}
-
-
-
+
+ {#each sites.sites as site}
+
+
+
+
+
+
+ {site.name}
+
+
+
+ Last deployed: {toLocaleDateTime(site.$updatedAt)}
+
+
{/each}
-
+ {#each functions.functions as func}
+
+
+ {#if func?.runtime}
+
+
+
+
+ {func.name}
+
+ {/if}
+
+
+ Last deployed: {toLocaleDateTime(func.$updatedAt)}
+
+
+ {/each}
+
{:else}
Are you sure you want to disconnect this git installation?
{/if}
@@ -83,4 +113,4 @@
(showGitDisconnect = false)}>Cancel
Disconnect
-
+
diff --git a/src/routes/(console)/project-[project]/settings/GitInstallationModal.svelte b/src/routes/(console)/project-[project]/settings/GitInstallationModal.svelte
deleted file mode 100644
index 0308652d7..000000000
--- a/src/routes/(console)/project-[project]/settings/GitInstallationModal.svelte
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
- Select a provider to import an existing git repository.
-
-
-
-
- GitHub
-
-
-
- GitLab (coming soon)
-
-
-
- BitBucket (coming soon)
-
-
-
- Azure (coming soon)
-
-
-
-
- (showGitInstall = false)}>Cancel
-
-
diff --git a/src/routes/(console)/project-[project]/settings/changeOrganization.svelte b/src/routes/(console)/project-[project]/settings/changeOrganization.svelte
new file mode 100644
index 000000000..848b718db
--- /dev/null
+++ b/src/routes/(console)/project-[project]/settings/changeOrganization.svelte
@@ -0,0 +1,43 @@
+
+
+
+ Change organization
+ Select an organization you own to move this project.
+
+ team.$id !== $project.teamId)
+ .map((team) => ({
+ value: team.$id,
+ label: team.name
+ }))} />
+
+
+
+ (showTransfer = true)}>Move
+
+
+
+{#if teamId}
+ t.$id == teamId).name}
+ bind:show={showTransfer} />
+{/if}
diff --git a/src/routes/(console)/project-[project]/settings/migrations/+page.svelte b/src/routes/(console)/project-[project]/settings/migrations/+page.svelte
index c34ccf665..9a7d41eee 100644
--- a/src/routes/(console)/project-[project]/settings/migrations/+page.svelte
+++ b/src/routes/(console)/project-[project]/settings/migrations/+page.svelte
@@ -29,6 +29,7 @@
import { Icon, Layout, Link, Status, Table } from '@appwrite.io/pink-svelte';
import { capitalize } from '$lib/helpers/string';
import DualTimeView from '$lib/components/dualTimeView.svelte';
+ import { Click, trackEvent } from '$lib/actions/analytics';
export let data;
let migration: Models.Migration = null;
@@ -252,7 +253,12 @@
- (showExport = true)}>Export data
+ {
+ showExport = true;
+ trackEvent(Click.SettingsStartMigrationClick);
+ }}>Export data
diff --git a/src/routes/(console)/project-[project]/settings/migrations/exportModal.svelte b/src/routes/(console)/project-[project]/settings/migrations/exportModal.svelte
index ff6539a7c..0531752b2 100644
--- a/src/routes/(console)/project-[project]/settings/migrations/exportModal.svelte
+++ b/src/routes/(console)/project-[project]/settings/migrations/exportModal.svelte
@@ -106,47 +106,43 @@
-
-
- API key creation
- By initiating the transfer, an API key will be automatically generated in the background,
- which you can delete after completion
-
+
+ API key creation
+ By initiating the transfer, an API key will be automatically generated in the background, which
+ you can delete after completion
+
- {
- if (!submitted) return;
- const input = e.target;
- const value = input.value;
+ {
+ if (!submitted) return;
+ const input = e.target;
+ const value = input.value;
- if (!isValidEndpoint(value)) {
- input.setCustomValidity('Please enter a valid endpoint');
- } else {
- input.setCustomValidity('');
- }
- input.reportValidity();
- }} />
+ if (!isValidEndpoint(value)) {
+ input.setCustomValidity('Please enter a valid endpoint');
+ } else {
+ input.setCustomValidity('');
+ }
+ input.reportValidity();
+ }} />
-
-
- Share your feedback: why our self-hosted solution works better for you
-
-
- We appreciate your continued support and we understand that our self-hosted solution
- might better fit your needs. To help us improve our Cloud solution, please share why
- it works better for you. Your feedback is important to us and we'll use it to make
- our services better.
-
-
-
-
-
-
+
+ Share your feedback: why our self-hosted solution works better for you
+
+ We appreciate your continued support and we understand that our self-hosted solution
+ might better fit your needs. To help us improve our Cloud solution, please share why it
+ works better for you. Your feedback is important to us and we'll use it to make our
+ services better.
+
+
+
+
+
You will be redirected to your self-hosted instance
diff --git a/src/routes/(console)/project-[project]/settings/smtp/+page.svelte b/src/routes/(console)/project-[project]/settings/smtp/+page.svelte
index 1c970442c..a18459f50 100644
--- a/src/routes/(console)/project-[project]/settings/smtp/+page.svelte
+++ b/src/routes/(console)/project-[project]/settings/smtp/+page.svelte
@@ -8,7 +8,7 @@
import { invalidate } from '$app/navigation';
import { BillingPlan, Dependencies } from '$lib/constants';
import { addNotification } from '$lib/stores/notifications';
- import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
+ import { Click, Submit, trackError, trackEvent } from '$lib/actions/analytics';
import InputNumber from '$lib/elements/forms/inputNumber.svelte';
import { base } from '$app/paths';
import deepEqual from 'deep-equal';
@@ -127,7 +127,14 @@
status="info"
title="Custom SMTP is a Pro plan feature. Upgrade to enable custom SMTP sever.">
- Upgrade plan
+ {
+ trackEvent(Click.OrganizationClickUpgrade, {
+ source: 'project_settings'
+ });
+ }}>Upgrade plan
{:else}
diff --git a/src/routes/(console)/project-[project]/settings/transferProject.svelte b/src/routes/(console)/project-[project]/settings/transferProjectModal.svelte
similarity index 82%
rename from src/routes/(console)/project-[project]/settings/transferProject.svelte
rename to src/routes/(console)/project-[project]/settings/transferProjectModal.svelte
index 877294fc5..3ad4c9e72 100644
--- a/src/routes/(console)/project-[project]/settings/transferProject.svelte
+++ b/src/routes/(console)/project-[project]/settings/transferProjectModal.svelte
@@ -2,7 +2,7 @@
import { goto } from '$app/navigation';
import { base } from '$app/paths';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
- import { Modal } from '$lib/components';
+ import { Confirm } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
@@ -10,8 +10,8 @@
import { project } from '../store';
export let show = false;
- export let teamName;
- export let teamId;
+ export let teamName: string;
+ export let teamId: string;
const handleTransfer = async () => {
try {
@@ -33,9 +33,9 @@
};
-
+
Are you sure you want to transfer {$project.name} to
+ >Are you sure you want to move {$project.name} to
{teamName} ?
Members who are not part of the destination organization must be invited to gain access to
@@ -44,6 +44,6 @@
(show = false)}>Cancel
- Transfer
+ Move
-
+
diff --git a/src/routes/(console)/project-[project]/settings/updateInstallations.svelte b/src/routes/(console)/project-[project]/settings/updateInstallations.svelte
index 7615a9565..31ef98879 100644
--- a/src/routes/(console)/project-[project]/settings/updateInstallations.svelte
+++ b/src/routes/(console)/project-[project]/settings/updateInstallations.svelte
@@ -1,17 +1,17 @@
@@ -77,39 +54,25 @@
{#if $organization.billingPlan === BillingPlan.SCALE}
On the Scale plan, you'll be charged only for any usage that exceeds the thresholds
- per resource listed below. ($showUsageRatesModal = true)}
- >Learn more about plan usage limits.
+ per resource listed below. ($showUsageRatesModal = true)}
+ >Learn more about plan usage limits.
{:else if $organization.billingPlan === BillingPlan.PRO}
On the Pro plan, you'll be charged only for any usage that exceeds the thresholds
- per resource listed below. ($showUsageRatesModal = true)}
- >Learn more about plan usage limits.
+ per resource listed below. ($showUsageRatesModal = true)}
+ >Learn more about plan usage limits.
{:else if $organization.billingPlan === BillingPlan.FREE}
If you exceed the limits of the {plan} plan, services for your projects may be disrupted.
- Upgrade for greater capacity .
+ Upgrade for greater capacity .
{/if}
-
-
Bandwidth
@@ -117,10 +80,12 @@
{#if network}
{@const humanized = humanFileSize(total(network))}
-
- {humanized.value}
- {humanized.unit}
-
+
+
+ {humanized.value}
+
+ {humanized.unit}
+
{:else}
-
+
+
+ No data to show
+
{/if}
@@ -163,14 +125,12 @@
{#if users}
{@const current = formatNum(usersTotal)}
-
-
-
- {current}
- Users
-
-
-
+
+
+ {current}
+
+ Users
+
{:else}
-
+
+
+ No data to show
+
{/if}
@@ -227,13 +184,10 @@
{:else}
-
+
+
+ No data to show
+
{/if}
@@ -244,14 +198,12 @@
{#if executions}
{@const current = formatNum(executionsTotal)}
-
-
-
- {current}
- Executions
-
-
-
+
+
+ {current}
+
+ Executions
+
{#if data.usage.executionsBreakdown.length > 0}
-
-
- Function
- Usage
-
-
-
- {#each data.usage.executionsBreakdown as func}
-
-
- {func.name ?? func.resourceId}
-
-
- {formatNum(func.value)} executions
-
-
-
-
-
- {/each}
-
-
+
+
+ Function
+ Usage
+
+ {#each data.usage.executionsBreakdown as func}
+
+
+ {func.name ?? func.resourceId}
+
+
+ {formatNum(func.value)} executions
+
+
+ {/each}
+
{/if}
{:else}
-
+
+
+ No data to show
+
{/if}
@@ -336,27 +278,22 @@
}
}
]}
-
-
-
- {humanized.value}
- {humanized.unit}
-
-
-
+
+
+ {humanized.value}
+
+ {humanized.unit}
+
{:else}
-
+
+
+ No data to show
+
{/if}
@@ -388,30 +325,22 @@
}
}
]}
-
-
-
- {(Math.ceil(totalGbHours * 100) / 100).toLocaleString(
- 'en-US'
- )}
- {`GB hours`}
-
-
-
+
+
+ {(Math.ceil(totalGbHours * 100) / 100).toLocaleString('en-US')}
+
+ GB hours
+
{:else}
-
+
+
+ No data to show
+
{/if}
@@ -423,11 +352,12 @@
{#if data.usage.authPhoneTotal}
-
- {formatNumberWithCommas(data.usage.authPhoneTotal)}
- OTPs
-
+
+
+ {formatNumberWithCommas(data.usage.authPhoneTotal)}
+
+ OTPs
+
Estimated cost
@@ -436,43 +366,35 @@
{#if data.usage.authPhoneCountryBreakdown.length > 0}
-
-
- Region breakdown
-
-
- Region
- Amount
- Estimated cost
-
-
- {#each data.usage.authPhoneCountryBreakdown as phone}
-
-
- {getCountryName(phone.name)}
-
-
- {formatNumberWithCommas(phone.value)}
-
-
- {formatCurrency(phone.estimate)}
-
-
- {/each}
-
-
-
-
+
+
+
+ Region
+ Amount
+ Estimated cost
+
+ {#each data.usage.authPhoneCountryBreakdown as phone}
+
+
+ {getCountryName(phone.name)}
+
+
+ {formatNumberWithCommas(phone.value)}
+
+
+ {formatCurrency(phone.estimate)}
+
+
+ {/each}
+
+
{/if}
{:else}
-
+
+
+ No data to show
+
{/if}
diff --git a/src/routes/(console)/project-[project]/settings/webhooks/[webhook]/dangerZone.svelte b/src/routes/(console)/project-[project]/settings/webhooks/[webhook]/dangerZone.svelte
index f21fc23be..424dd7259 100644
--- a/src/routes/(console)/project-[project]/settings/webhooks/[webhook]/dangerZone.svelte
+++ b/src/routes/(console)/project-[project]/settings/webhooks/[webhook]/dangerZone.svelte
@@ -5,6 +5,7 @@
import Delete from './delete.svelte';
import { toLocaleDateTime } from '$lib/helpers/date';
import { Card, Typography } from '@appwrite.io/pink-svelte';
+ import { Click, trackEvent } from '$lib/actions/analytics';
let showDelete = false;
@@ -20,7 +21,12 @@
- (showDelete = true)}>Delete
+ {
+ showDelete = true;
+ trackEvent(Click.SettingsWebhookDeleteClick);
+ }}>Delete
diff --git a/src/routes/(console)/project-[project]/settings/webhooks/[webhook]/updateEvents.svelte b/src/routes/(console)/project-[project]/settings/webhooks/[webhook]/updateEvents.svelte
index 0de4e2ac2..b82d94596 100644
--- a/src/routes/(console)/project-[project]/settings/webhooks/[webhook]/updateEvents.svelte
+++ b/src/routes/(console)/project-[project]/settings/webhooks/[webhook]/updateEvents.svelte
@@ -5,7 +5,6 @@
import { CardGrid, Empty, EventModal } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Button, Form } from '$lib/elements/forms';
- import { TableCell, TableCellText, TableList } from '$lib/elements/table';
import { symmetricDifference } from '$lib/helpers/array';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
diff --git a/src/routes/(console)/project-[project]/settings/webhooks/[webhook]/updateSignature.svelte b/src/routes/(console)/project-[project]/settings/webhooks/[webhook]/updateSignature.svelte
index ddbd8da2a..1632e7dbc 100644
--- a/src/routes/(console)/project-[project]/settings/webhooks/[webhook]/updateSignature.svelte
+++ b/src/routes/(console)/project-[project]/settings/webhooks/[webhook]/updateSignature.svelte
@@ -4,6 +4,7 @@
import { Link } from '@appwrite.io/pink-svelte';
import Regenerate from './regenerate.svelte';
import { webhook } from './store';
+ import { Click, trackEvent } from '$lib/actions/analytics';
let showRegenerate = false;
@@ -22,7 +23,13 @@
- (showRegenerate = true)} secondary submit>Regenerate key
+ {
+ showRegenerate = true;
+ trackEvent(Click.SettingsWebhookUpdateSignatureClick);
+ }}
+ secondary
+ submit>Regenerate key
diff --git a/src/routes/(console)/project-[project]/sites/(components)/addCollaboratorModal.svelte b/src/routes/(console)/project-[project]/sites/(components)/addCollaboratorModal.svelte
index 37b23cea7..e4e7d1c5f 100644
--- a/src/routes/(console)/project-[project]/sites/(components)/addCollaboratorModal.svelte
+++ b/src/routes/(console)/project-[project]/sites/(components)/addCollaboratorModal.svelte
@@ -12,8 +12,8 @@
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { roles } from '$lib/stores/billing';
import InputSelect from '$lib/elements/forms/inputSelect.svelte';
- import Roles from '$lib/components/roles/roles.svelte';
import { Layout } from '@appwrite.io/pink-svelte';
+ import { isCloud, isSelfHosted } from '$lib/system';
export let show = false;
@@ -24,7 +24,7 @@
let email: string,
name: string,
error: string,
- role: string = 'viewer';
+ role: string = isSelfHosted ? 'owner' : 'viewer';
async function create() {
try {
@@ -59,8 +59,6 @@
email = null;
name = null;
}
-
- //TODO: fix popover
@@ -75,14 +73,15 @@
placeholder="Enter email"
autofocus={true}
bind:value={email} />
-
+ {#if isCloud}
+
+ {/if}
(show = false)}>Cancel
diff --git a/src/routes/(console)/project-[project]/sites/(components)/connectRepoModal.svelte b/src/routes/(console)/project-[project]/sites/(components)/connectRepoModal.svelte
index fb88fcc60..9ba9a924e 100644
--- a/src/routes/(console)/project-[project]/sites/(components)/connectRepoModal.svelte
+++ b/src/routes/(console)/project-[project]/sites/(components)/connectRepoModal.svelte
@@ -9,9 +9,9 @@
import { Link } from '$lib/elements';
import { NewRepository, Repositories } from '$lib/components/git';
import ConnectGit from '$lib/components/git/connectGit.svelte';
- import { BuildRuntime, Framework, type Models } from '@appwrite.io/console';
+ import { Adapter, BuildRuntime, Framework, type Models } from '@appwrite.io/console';
import { addNotification } from '$lib/stores/notifications';
- import { trackEvent } from '$lib/actions/analytics';
+ import { Click, trackEvent } from '$lib/actions/analytics';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import RepositoryBehaviour from '$lib/components/git/repositoryBehaviour.svelte';
@@ -21,8 +21,9 @@
export let show = false;
export let site: Models.Site;
export let callbackState: Record = null;
+ export let onlyExisting = false;
- let repositoryBehaviour: 'new' | 'existing' | undefined = undefined;
+ let repositoryBehaviour: 'new' | 'existing' | undefined = onlyExisting ? 'existing' : undefined;
let repositoryName = '';
let repositoryPrivate = true;
let selectedInstallationId = '';
@@ -66,12 +67,15 @@
site.buildCommand,
site.outputDirectory,
site.buildRuntime as BuildRuntime,
- site.adapter,
+ site.adapter as Adapter,
site.fallbackFile,
selectedInstallationId,
- selectedRepository
+ selectedRepository,
+ 'main',
+ undefined,
+ undefined,
+ undefined
);
- console.log('test');
invalidate(Dependencies.SITE);
show = false;
dispatch('connect', s);
@@ -83,8 +87,6 @@
error = e.message;
}
}
-
- $: console.log(selectedInstallationId);
{#if hasInstallations}
-
+ {#if !onlyExisting}
+
+ {/if}
{#if repositoryBehaviour === 'new'}
{
- trackEvent('click_connect_repository', {
+ trackEvent(Click.ConnectRepositoryClick, {
from: 'sites'
});
repository.set(e.detail);
diff --git a/src/routes/(console)/project-[project]/sites/(components)/deploymentActionMenu.svelte b/src/routes/(console)/project-[project]/sites/(components)/deploymentActionMenu.svelte
index 8b78191d9..229759855 100644
--- a/src/routes/(console)/project-[project]/sites/(components)/deploymentActionMenu.svelte
+++ b/src/routes/(console)/project-[project]/sites/(components)/deploymentActionMenu.svelte
@@ -1,8 +1,10 @@
-
- {
- e.preventDefault();
- toggle(e);
- }}>
+
+
-
+
{#if !inCard}
Redeploy
@@ -63,21 +69,37 @@
e.preventDefault();
selectedDeployment = deployment;
showActivate = true;
- toggle(e);
+ toggle();
}}>
Activate
{/if}
{#if deployment?.status === 'ready' || deployment?.status === 'failed'}
- {
- toggle(e);
- }}>
- Download
-
+
+
+
+ Download
+
+
+
+
+
+ Download source
+
+
+
+ Download output
+
+
+
+
{/if}
{#if deployment?.status === 'processing' || deployment?.status === 'building' || deployment.status === 'waiting'}
@@ -88,7 +110,6 @@
e.preventDefault();
selectedDeployment = deployment;
showCancel = true;
- toggle(e);
}}>
Cancel
@@ -101,11 +122,10 @@
e.preventDefault();
selectedDeployment = deployment;
showDelete = true;
- toggle(e);
}}>
Delete
{/if}
-
+
diff --git a/src/routes/(console)/project-[project]/sites/(components)/logs.svelte b/src/routes/(console)/project-[project]/sites/(components)/logs.svelte
index 5129ed64b..497e43467 100644
--- a/src/routes/(console)/project-[project]/sites/(components)/logs.svelte
+++ b/src/routes/(console)/project-[project]/sites/(components)/logs.svelte
@@ -16,14 +16,11 @@
@@ -94,11 +74,10 @@
{/if}
{#key buildLogs}
-
+
{/key}
- {#if ['processing', 'building'].includes(status)}
-
- Cancel deployment
-
- {/if}
diff --git a/src/routes/(console)/project-[project]/sites/(components)/logsTimer.svelte b/src/routes/(console)/project-[project]/sites/(components)/logsTimer.svelte
index 927dd70da..522036f86 100644
--- a/src/routes/(console)/project-[project]/sites/(components)/logsTimer.svelte
+++ b/src/routes/(console)/project-[project]/sites/(components)/logsTimer.svelte
@@ -19,7 +19,7 @@
{:else}
- {formatTimeDetailed(deployment.buildTime)}
+ {formatTimeDetailed(deployment.buildDuration)}
{/if}
diff --git a/src/routes/(console)/project-[project]/sites/(components)/siteCard.svelte b/src/routes/(console)/project-[project]/sites/(components)/siteCard.svelte
index 892644773..6040533f8 100644
--- a/src/routes/(console)/project-[project]/sites/(components)/siteCard.svelte
+++ b/src/routes/(console)/project-[project]/sites/(components)/siteCard.svelte
@@ -13,16 +13,17 @@
Tooltip,
Typography
} from '@appwrite.io/pink-svelte';
- import DeploymentSource from './deploymentSource.svelte';
+ import { DeploymentSource, DeploymentCreatedBy } from '$lib/components/git';
+
import { Button } from '$lib/elements/forms';
import { IconInfo, IconQrcode } from '@appwrite.io/pink-icons-svelte';
import OpenOnMobileModal from './openOnMobileModal.svelte';
- import DeploymentDomains from './deploymentDomains.svelte';
+ import DeploymentDomains from '$lib/components/git/deploymentDomains.svelte';
import { app } from '$lib/stores/app';
import { base } from '$app/paths';
import { isCloud } from '$lib/system';
import { getApiEndpoint } from '$lib/stores/sdk';
- import DualTimeView from '$lib/components/dualTimeView.svelte';
+ import { capitalize } from '$lib/helpers/string';
export let deployment: Models.Deployment;
export let proxyRuleList: Models.ProxyRuleList;
@@ -32,7 +33,7 @@
let show = false;
const siteUrl = proxyRuleList.total > 0 ? proxyRuleList.rules[0].domain : undefined;
- $: totalSize = humanFileSize((deployment?.buildSize ?? 0) + (deployment?.size ?? 0));
+ $: totalSize = humanFileSize((deployment?.buildSize ?? 0) + (deployment?.sourceSize ?? 0));
function getScreenshot(theme: string, deployment: Models.Deployment) {
if (theme === 'dark') {
@@ -49,10 +50,7 @@
function getFilePreview(fileId: string) {
// TODO: @Meldiron use sdk.forConsole.storage.getFilePreview
const endpoint = getApiEndpoint();
- return (
- endpoint +
- `/storage/buckets/screenshots/files/${fileId}/view?project=console&mode=admin`
- );
+ return endpoint + `/storage/buckets/screenshots/files/${fileId}/view?project=console`;
}
@@ -89,7 +87,9 @@
Status
-
+
{:else}
@@ -97,10 +97,8 @@
Deployed
-
-
+
+
{/if}
@@ -108,13 +106,13 @@
- {#if deployment?.buildTime}
+ {#if deployment?.buildDuration}
- Build time
+ Build duration
- {formatTimeDetailed(deployment.buildTime)}
+ {formatTimeDetailed(deployment.buildDuration)}
{/if}
@@ -170,7 +168,7 @@
-
+
Source
diff --git a/src/routes/(console)/project-[project]/sites/(images)/empty-dark.png b/src/routes/(console)/project-[project]/sites/(images)/empty-dark.png
deleted file mode 100644
index b86e54dc3..000000000
Binary files a/src/routes/(console)/project-[project]/sites/(images)/empty-dark.png and /dev/null differ
diff --git a/src/routes/(console)/project-[project]/sites/(images)/empty-light.png b/src/routes/(console)/project-[project]/sites/(images)/empty-light.png
deleted file mode 100644
index 415cc7435..000000000
Binary files a/src/routes/(console)/project-[project]/sites/(images)/empty-light.png and /dev/null differ
diff --git a/src/routes/(console)/project-[project]/sites/(images)/empty-sites-dark.svg b/src/routes/(console)/project-[project]/sites/(images)/empty-sites-dark.svg
new file mode 100644
index 000000000..a770c672e
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/(images)/empty-sites-dark.svg
@@ -0,0 +1,264 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/routes/(console)/project-[project]/sites/(images)/empty-sites-light.svg b/src/routes/(console)/project-[project]/sites/(images)/empty-sites-light.svg
new file mode 100644
index 000000000..af809483f
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/(images)/empty-sites-light.svg
@@ -0,0 +1,349 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/routes/(console)/project-[project]/sites/+page.svelte b/src/routes/(console)/project-[project]/sites/+page.svelte
index 9d611ced6..58864b1c0 100644
--- a/src/routes/(console)/project-[project]/sites/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/+page.svelte
@@ -13,10 +13,10 @@
import { canWriteSites } from '$lib/stores/roles.js';
import { Icon, Layout } from '@appwrite.io/pink-svelte';
import { Button } from '$lib/elements/forms';
- import CreateSiteModal from './createSiteModal.svelte';
- import EmptyLight from './(images)/empty-light.png';
import { app } from '$lib/stores/app';
- import EmptyDark from './(images)/empty-dark.png';
+ import CreateSiteModal from './createSiteModal.svelte';
+ import EmptyLight from './(images)/empty-sites-light.svg';
+ import EmptyDark from './(images)/empty-sites-dark.svg';
import Grid from './grid.svelte';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
import { columns } from './store';
@@ -41,11 +41,6 @@
]);
$updateCommandGroupRanks({ sites: 1000 });
-
- // TODO: remove
- const TMPSITEROLES = true;
-
- $: console.log(data.siteList);
@@ -79,7 +74,7 @@
{:else}
import { Button } from '$lib/elements/forms';
- import { Modal } from '$lib/components';
+ import { Confirm } from '$lib/components';
import { sdk } from '$lib/stores/sdk';
import { addNotification } from '$lib/stores/notifications';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
@@ -14,7 +14,7 @@
async function activate() {
try {
- await sdk.forProject.sites.updateDeployment(siteId, selectedDeploymentId);
+ await sdk.forProject.sites.updateSiteDeployment(siteId, selectedDeploymentId);
addNotification({
type: 'success',
message: `Deployment has been activated`
@@ -31,13 +31,13 @@
}
-
+
- Are you sure you want to activate this deployment? This might affect your production code.
+ This deployment is ready but not yet live. Activate it to make it publicly accessible.
(show = false)}>Cancel
Activate
-
+
diff --git a/src/routes/(console)/project-[project]/sites/create-site/aside.svelte b/src/routes/(console)/project-[project]/sites/create-site/aside.svelte
index 4a5316147..0a40190f9 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/aside.svelte
+++ b/src/routes/(console)/project-[project]/sites/create-site/aside.svelte
@@ -73,7 +73,7 @@
{$consoleVariables._APP_OPTIONS_FORCE_HTTPS
? 'https://'
- : 'http://'}{domain}.{$consoleVariables._APP_DOMAIN_TARGET}
+ : 'http://'}{domain}
{/key}
diff --git a/src/routes/(console)/project-[project]/sites/create-site/configuration.svelte b/src/routes/(console)/project-[project]/sites/create-site/configuration.svelte
index 984786eea..80ba859fd 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/configuration.svelte
+++ b/src/routes/(console)/project-[project]/sites/create-site/configuration.svelte
@@ -32,9 +32,11 @@
import CreateVariableModal from './createVariableModal.svelte';
import DeleteVariableModal from './deleteVariableModal.svelte';
import UpdateVariableModal from './updateVariableModal.svelte';
+ import { Click, trackEvent } from '$lib/actions/analytics';
export let frameworks: Models.Framework[];
export let selectedFramework: Models.Framework;
+ $: frameworkData = frameworks.find((framework) => framework.key === selectedFramework?.key);
export let variables: Partial[] = [];
export let installCommand = '';
@@ -51,7 +53,11 @@
let currentVariable: Partial;
let frameworkId = selectedFramework.key;
- $: frameworkData = frameworks.find((framework) => framework.key === selectedFramework.key);
+ $: if (!installCommand || !buildCommand || !outputDirectory) {
+ installCommand ||= frameworkData?.adapters?.ssr?.installCommand;
+ buildCommand ||= frameworkData?.adapters?.ssr?.buildCommand;
+ outputDirectory ||= frameworkData?.adapters?.ssr?.outputDirectory;
+ }
@@ -80,12 +86,15 @@
id="installCommand"
label="Install command"
bind:value={installCommand}
- placeholder={frameworkData?.defaultInstallCommand} />
+ placeholder={frameworkData?.adapters?.ssr?.installCommand} />
(installCommand = '')}>
+ disabled={frameworkData?.adapters?.ssr?.installCommand ===
+ installCommand}
+ on:click={() =>
+ (installCommand =
+ frameworkData?.adapters?.ssr?.installCommand)}>
Reset
@@ -94,12 +103,14 @@
id="buildCommand"
label="Build command"
bind:value={buildCommand}
- placeholder={frameworkData?.defaultBuildCommand} />
+ placeholder={frameworkData?.adapters?.ssr?.buildCommand} />
(buildCommand = '')}>
+ disabled={frameworkData?.adapters?.ssr?.buildCommand ===
+ buildCommand}
+ on:click={() =>
+ (buildCommand = frameworkData?.adapters?.ssr?.buildCommand)}>
Reset
@@ -108,12 +119,15 @@
id="outputDirectory"
label="Output directory"
bind:value={outputDirectory}
- placeholder={frameworkData?.defaultOutputDirectory} />
+ placeholder={frameworkData?.adapters?.ssr?.outputDirectory} />
(outputDirectory = '')}>
+ disabled={frameworkData?.adapters?.ssr?.outputDirectory ===
+ outputDirectory}
+ on:click={() =>
+ (outputDirectory =
+ frameworkData?.adapters?.ssr?.outputDirectory)}>
Reset
@@ -134,18 +148,36 @@
(showEditorModal = true)}>
+ on:mousedown={() => {
+ showEditorModal = true;
+ trackEvent(Click.VariablesUpdateClick, {
+ source: 'site_configuration'
+ });
+ }}>
Editor
(showImportModal = true)}>
+ on:mousedown={() => {
+ showImportModal = true;
+ trackEvent(Click.VariablesImportClick, {
+ source: 'site_configuration'
+ });
+ }}>
Import .env
{#if variables?.length}
- (showCreate = true)}>
+ {
+ showCreate = true;
+ trackEvent(Click.VariablesCreateClick, {
+ source: 'site_settings'
+ });
+ }}>
Create variable
{/if}
diff --git a/src/routes/(console)/project-[project]/sites/create-site/deploying/+page.svelte b/src/routes/(console)/project-[project]/sites/create-site/deploying/+page.svelte
index 4a21cd5b0..988d4f2e4 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/deploying/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/create-site/deploying/+page.svelte
@@ -7,7 +7,7 @@
import Aside from '../aside.svelte';
import Logs from '../../(components)/logs.svelte';
import { getFrameworkIcon } from '../../store';
- import { SvgIcon } from '$lib/components';
+ import { Copy, SvgIcon } from '$lib/components';
export let data;
@@ -28,12 +28,14 @@
{data.site.name}
- {data.site.$id}
+
+ {data.site.$id}
+
-
+
diff --git a/src/routes/(console)/project-[project]/sites/create-site/deploying/+page.ts b/src/routes/(console)/project-[project]/sites/create-site/deploying/+page.ts
index c5569ebf0..6dc87d795 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/deploying/+page.ts
+++ b/src/routes/(console)/project-[project]/sites/create-site/deploying/+page.ts
@@ -1,4 +1,4 @@
-import { RuleType, sdk } from '$lib/stores/sdk';
+import { DeploymentResourceType, RuleTrigger, RuleType, sdk } from '$lib/stores/sdk';
import { error } from '@sveltejs/kit';
import type { PageLoad } from './$types';
import { Query } from '@appwrite.io/console';
@@ -12,8 +12,11 @@ export const load: PageLoad = async ({ url }) => {
sdk.forProject.sites.get(siteId),
sdk.forProject.sites.getDeployment(siteId, deploymentId),
sdk.forProject.proxy.listRules([
- Query.equal('type', [RuleType.DEPLOYMENT]),
- Query.equal('automation', `site=${siteId}`)
+ Query.equal('type', RuleType.DEPLOYMENT),
+ Query.equal('deploymentResourceType', DeploymentResourceType.SITE),
+ Query.equal('deploymentResourceId', siteId),
+ Query.equal('deploymentId', deploymentId),
+ Query.equal('trigger', RuleTrigger.MANUAL)
])
]);
diff --git a/src/routes/(console)/project-[project]/sites/create-site/finish/+page.svelte b/src/routes/(console)/project-[project]/sites/create-site/finish/+page.svelte
index 1b76cda09..9f0e41c5d 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/finish/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/create-site/finish/+page.svelte
@@ -12,6 +12,7 @@
import { onMount } from 'svelte';
import AddCollaboratorModal from '../../(components)/addCollaboratorModal.svelte';
import { protocol } from '$routes/(console)/store';
+ import { Click, trackEvent } from '$lib/actions/analytics';
export let data;
@@ -91,6 +92,11 @@
{
+ trackEvent(Click.DomainCreateClick, {
+ source: 'sites_create_finish'
+ });
+ }}
href={`${base}/project-${$page.params.project}/sites/site-${data.site.$id}/domains`}>
{
depends(Dependencies.SITE);
if (!url.searchParams.has('site')) error(404, 'Deployment is not optional');
const siteId = url.searchParams.get('site');
- const [site, proxyRuleList] = await Promise.all([
- sdk.forProject.sites.get(siteId),
- sdk.forProject.proxy.listRules([
- Query.equal('type', RuleType.DEPLOYMENT),
- Query.equal('automation', `site=${siteId}`)
- ])
+ const site = await sdk.forProject.sites.get(siteId);
+ const proxyRuleList = await sdk.forProject.proxy.listRules([
+ Query.equal('type', RuleType.DEPLOYMENT),
+ Query.equal('deploymentResourceType', DeploymentResourceType.SITE),
+ Query.equal('deploymentResourceId', siteId),
+ Query.equal('deploymentId', site.deploymentId)
]);
return {
site,
diff --git a/src/routes/(console)/project-[project]/sites/create-site/manual/+page.svelte b/src/routes/(console)/project-[project]/sites/create-site/manual/+page.svelte
index ac058c64c..2a3f17486 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/manual/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/create-site/manual/+page.svelte
@@ -7,17 +7,19 @@
import { Wizard } from '$lib/layout';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
- import { Layout } from '@appwrite.io/pink-svelte';
+ import { Icon, Layout, Tooltip, Typography, Upload } from '@appwrite.io/pink-svelte';
import { writable } from 'svelte/store';
import Details from '../details.svelte';
import Aside from './aside.svelte';
import { BuildRuntime, Framework, ID } from '@appwrite.io/console';
import type { Models } from '@appwrite.io/console';
import Configuration from '../configuration.svelte';
- import InputFile from '$lib/elements/forms/inputFile.svelte';
import { buildVerboseDomain } from '../store';
import { project } from '$routes/(console)/project-[project]/store';
import { organization } from '$lib/stores/organization';
+ import { consoleVariables } from '$routes/(console)/store';
+ import { IconInfo } from '@appwrite.io/pink-icons-svelte';
+ import { removeFile } from '$lib/helpers/files';
export let data;
let showExitModal = false;
@@ -56,7 +58,7 @@
installCommand || undefined,
buildCommand || undefined,
outputDirectory || undefined,
- framework.adapters[Object.keys(framework.adapters)[0]].key, //TODO: fix this
+ undefined,
undefined,
undefined,
undefined,
@@ -65,6 +67,12 @@
undefined
);
+ // Add domain
+ await sdk.forProject.proxy.createSiteRule(
+ `${domain}.${$consoleVariables._APP_DOMAIN_SITES}`,
+ site.$id
+ );
+
//Add variables
const promises = variables.map((variable) =>
sdk.forProject.sites.createVariable(
@@ -101,25 +109,68 @@
trackError(e, Submit.SiteCreate);
}
}
+
+ $: filesList = files?.length
+ ? Array.from(files).map((file) => {
+ let f = file as Partial & { removable: boolean };
+ f.removable = true;
+ return f;
+ })
+ : [];
+
+ $: console.log(files);
Create site - Appwrite
+
-
-
+
+
+ Upload a zip file (tar.gz) containing your function source code
+
+
+
+
+
+
+ Drag and drop file here or click to upload
+
+
+
+
+
+ Only .tar.gz files allowed
+
+
+ Max file size 10MB
+
+
+
+ {#if files?.length}
+ (files = removeFile(e.detail, files))} />
+ {/if}
@@ -130,8 +181,6 @@
bind:selectedFramework={framework}
bind:variables
frameworks={data.frameworks.frameworks} />
-
-
diff --git a/src/routes/(console)/project-[project]/sites/create-site/manual/aside.svelte b/src/routes/(console)/project-[project]/sites/create-site/manual/aside.svelte
index 00b68cacf..8695ffa1c 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/manual/aside.svelte
+++ b/src/routes/(console)/project-[project]/sites/create-site/manual/aside.svelte
@@ -1,14 +1,10 @@
@@ -20,23 +16,11 @@
-
-
diff --git a/src/routes/(console)/project-[project]/sites/create-site/repositories/+page.svelte b/src/routes/(console)/project-[project]/sites/create-site/repositories/+page.svelte
index 0f0c93336..408834c73 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/repositories/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/create-site/repositories/+page.svelte
@@ -2,7 +2,7 @@
import { goto } from '$app/navigation';
import { base } from '$app/paths';
import { page } from '$app/stores';
- import { trackEvent } from '$lib/actions/analytics.js';
+ import { Click, trackEvent } from '$lib/actions/analytics.js';
import Card from '$lib/components/card.svelte';
import { Repositories } from '$lib/components/git/index.js';
import Button from '$lib/elements/forms/button.svelte';
@@ -16,7 +16,7 @@
let selectedRepository: string = null;
function onConnect(e: CustomEvent) {
- trackEvent('click_connect_repository', {
+ trackEvent(Click.ConnectRepositoryClick, {
from: 'cover'
});
repository.set(e.detail);
diff --git a/src/routes/(console)/project-[project]/sites/create-site/repositories/repository-[repository]/+page.svelte b/src/routes/(console)/project-[project]/sites/create-site/repositories/repository-[repository]/+page.svelte
index 3ba558312..1dfb787db 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/repositories/repository-[repository]/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/create-site/repositories/repository-[repository]/+page.svelte
@@ -8,18 +8,23 @@
import { Wizard } from '$lib/layout';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
- import { installation, repository, sortBranches } from '$lib/stores/vcs';
+ import { installation, repository } from '$lib/stores/vcs';
import { Layout, Icon, Typography } from '@appwrite.io/pink-svelte';
import { IconGithub } from '@appwrite.io/pink-icons-svelte';
import { writable } from 'svelte/store';
import Details from '../../details.svelte';
- import ProductionBranch from '../../../../../../../lib/components/git/productionBranchFieldset.svelte';
+ import ProductionBranch from '$lib/components/git/productionBranchFieldset.svelte';
import Aside from '../../aside.svelte';
- import { BuildRuntime, Framework, ID, Type } from '@appwrite.io/console';
+ import {
+ BuildRuntime,
+ Framework,
+ ID,
+ VCSDeploymentType,
+ VCSDetectionType
+ } from '@appwrite.io/console';
import type { Models } from '@appwrite.io/console';
import { onMount } from 'svelte';
import Configuration from '../../configuration.svelte';
- // import Domain from '../../domain.svelte';
import { consoleVariables } from '$routes/(console)/store';
import { buildVerboseDomain } from '../../store';
import { project } from '$routes/(console)/project-[project]/store';
@@ -32,7 +37,7 @@
let name = '';
let id = ID.unique();
- let framework: Models.Framework = data.frameworks.frameworks[0];
+ let framework: Models.Framework = data.frameworks.frameworks.find((f) => f.key === 'other');
let adapter = framework?.adapters[0];
let branch: string;
let rootDir = './';
@@ -42,38 +47,40 @@
let variables: Partial[] = [];
let silentMode = false;
let domain = id;
- // let domainIsValid = true;
onMount(async () => {
installation.set(data.installation);
repository.set(data.repository);
name = data.repository.name;
+
+ await detectFramwork();
});
- async function loadBranches() {
- const { branches } = await sdk.forProject.vcs.listRepositoryBranches(
- data.installation.$id,
- data.repository.id
- );
- const sorted = sortBranches(branches);
- branch = sorted[0]?.name ?? null;
-
- if (!branch) {
- branch = 'main';
+ async function detectFramwork() {
+ try {
+ const response = await sdk.forProject.vcs.createRepositoryDetection(
+ $installation.$id,
+ data.repository.id,
+ VCSDetectionType.Framework,
+ rootDir
+ );
+ framework = data.frameworks.frameworks.find((f) => f.key === response.framework);
+ adapter = framework?.adapters[0];
+ installCommand = adapter?.installCommand;
+ buildCommand = adapter?.buildCommand;
+ outputDirectory = adapter?.outputDirectory;
+ trackEvent(Submit.FrameworkDetect, {
+ source: 'repository',
+ framework: framework.key
+ });
+ } catch (error) {
+ framework = data.frameworks.frameworks.find((f) => f.key === 'other');
+ trackError(error, Submit.FrameworkDetect);
+ console.log(error);
}
-
- return sorted;
}
async function create() {
- // if (!domainIsValid) {
- // addNotification({
- // type: 'error',
- // message: 'Please enter a valid domain'
- // });
- // return;
- // } else {}
-
try {
domain = await buildVerboseDomain(
data.repository.name,
@@ -95,9 +102,9 @@
installCommand,
buildCommand,
outputDirectory,
- framework.adapters[Object.keys(framework.adapters)[0]].key, //TODO: fix this
+ undefined,
data.installation.$id,
- null,
+ undefined,
data.repository.id,
branch,
silentMode,
@@ -123,7 +130,7 @@
const deployment = await sdk.forProject.sites.createVcsDeployment(
site.$id,
- Type.Branch,
+ VCSDeploymentType.Branch,
branch,
true
);
@@ -144,6 +151,8 @@
trackError(e, Submit.SiteCreate);
}
}
+
+ $: console.log(framework);
@@ -178,34 +187,22 @@
- {#await loadBranches()}
-
-
-
- {:then branches}
- {@const options =
- branches
- ?.map((branch) => {
- return {
- value: branch.name,
- label: branch.name
- };
- })
- ?.sort((a, b) => {
- return a.label > b.label ? 1 : -1;
- }) ?? []}
-
- {/await}
+
-
-
-
+ {#key framework.key}
+
+ {/key}
diff --git a/src/routes/(console)/project-[project]/sites/create-site/templates/+page.svelte b/src/routes/(console)/project-[project]/sites/create-site/templates/+page.svelte
index 0dcd35df5..b436a14bc 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/templates/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/create-site/templates/+page.svelte
@@ -67,7 +67,7 @@
@@ -127,10 +127,11 @@
@@ -149,6 +150,6 @@
name="Templates"
limit={data.limit}
offset={data.offset}
- total={data.templates?.length} />
+ total={data.sum} />
diff --git a/src/routes/(console)/project-[project]/sites/create-site/templates/+page.ts b/src/routes/(console)/project-[project]/sites/create-site/templates/+page.ts
index d59edc2a9..96fd3b96a 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/templates/+page.ts
+++ b/src/routes/(console)/project-[project]/sites/create-site/templates/+page.ts
@@ -1,8 +1,9 @@
import { sdk } from '$lib/stores/sdk';
import { getPage, getSearch, getView, pageToOffset, View } from '$lib/helpers/load';
+import { getLimit } from '$lib/helpers/load';
export const load = async ({ url, route }) => {
- const limit = 12;
+ const limit = getLimit(url, route, 12);
const page = getPage(url);
const search = getSearch(url);
const view = getView(url, route, View.Grid);
diff --git a/src/routes/(console)/project-[project]/sites/create-site/templates/template-[template]/+page.svelte b/src/routes/(console)/project-[project]/sites/create-site/templates/template-[template]/+page.svelte
index 0e1bcf140..67d95d064 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/templates/template-[template]/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/create-site/templates/template-[template]/+page.svelte
@@ -2,7 +2,7 @@
import { goto } from '$app/navigation';
import { base } from '$app/paths';
import { page } from '$app/stores';
- import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
+ import { Click, Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { Card } from '$lib/components';
import { Button, Form } from '$lib/elements/forms';
import { Wizard } from '$lib/layout';
@@ -22,19 +22,23 @@
import { onMount } from 'svelte';
import { writable } from 'svelte/store';
import Details from '../../details.svelte';
- import ConnectBehaviour from './connectBehaviour.svelte';
- import ProductionBranch from '../../../../../../../lib/components/git/productionBranchFieldset.svelte';
import Configuration from './configuration.svelte';
import Aside from '../../aside.svelte';
import { Adapter, BuildRuntime, Framework, ID } from '@appwrite.io/console';
- // import Domain from '../../domain.svelte';
- import { NewRepository, Repositories, RepositoryBehaviour } from '$lib/components/git';
+ import {
+ ConnectBehaviour,
+ NewRepository,
+ ProductionBranchFieldset,
+ Repositories,
+ RepositoryBehaviour
+ } from '$lib/components/git';
import { getFrameworkIcon } from '../../../store';
import { app, iconPath } from '$lib/stores/app';
import { consoleVariables } from '$routes/(console)/store';
import { project } from '$routes/(console)/project-[project]/store';
import { buildVerboseDomain } from '../../store';
import { organization } from '$lib/stores/organization';
+ import { connectGitHub } from '$lib/stores/git';
export let data;
@@ -48,13 +52,12 @@
let name = data.template.name;
let id = ID.unique();
let domain = id;
- // let domainIsValid = true;
let framework = data?.template?.frameworks[0];
let branch = 'main';
let rootDir = './';
let connectBehaviour: 'now' | 'later' = 'now';
let repositoryBehaviour: 'new' | 'existing' = 'new';
- let repositoryName = '';
+ let repositoryName = undefined;
let repositoryPrivate = true;
let selectedInstallationId = '';
let selectedRepository = '';
@@ -69,23 +72,6 @@
selectedInstallationId = $installation?.$id;
});
- let callbackState: Record = null;
-
- function connectGitHub() {
- const redirect = new URL($page.url);
- if (callbackState) {
- Object.keys(callbackState).forEach((key) => {
- redirect.searchParams.append(key, callbackState[key]);
- });
- }
- const target = new URL(`${sdk.forProject.client.config.endpoint}/vcs/github/authorize`);
- target.searchParams.set('project', $page.params.project);
- target.searchParams.set('success', redirect.toString());
- target.searchParams.set('failure', redirect.toString());
- target.searchParams.set('mode', 'admin');
- return target;
- }
-
async function createRepository() {
try {
isCreatingRepository = true;
@@ -114,15 +100,7 @@
message: 'Please select a repository'
});
return;
- }
- // else if (!domainIsValid) {
- // addNotification({
- // type: 'error',
- // message: 'Please enter a valid domain'
- // });
- // return;
- // }
- else {
+ } else {
try {
domain = await buildVerboseDomain(
data.template.name,
@@ -147,7 +125,7 @@
framework.outputDirectory,
framework.adapter as unknown as Adapter,
connectBehaviour === 'later' ? undefined : selectedInstallationId || undefined,
- framework.fallbackFile,
+ framework?.fallbackFile || undefined,
selectedRepository || undefined,
branch || undefined,
selectedRepository ? silentMode : undefined,
@@ -202,13 +180,15 @@
$: if (repositoryBehaviour === 'new') {
selectedInstallationId = $installation?.$id;
- repositoryName = name.split(' ').join('-').toLowerCase();
+ repositoryName ??= name.split(' ').join('-').toLowerCase();
}
$: if (connectBehaviour === 'later') {
selectedRepository = null;
}
+ $: console.log(repositoryName);
+
$: console.log(data.template);
$: console.log(variables);
@@ -235,7 +215,7 @@
- {$repository.name}
+ {$repository.organization}/{$repository.name}
-
+
{#if data.template.variables?.length}
{/if}
-
{:else}
{@const options = data.template.frameworks.map((framework) => {
@@ -304,7 +288,7 @@
product="sites"
action="button"
on:connect={(e) => {
- trackEvent('click_connect_repository', {
+ trackEvent(Click.ConnectRepositoryClick, {
from: 'template-wizard'
});
repository.set(e.detail);
@@ -330,11 +314,8 @@
{/if}
- {:else}
- {#if data.template.variables?.length}
-
- {/if}
-
+ {:else if data.template.variables?.length}
+
{/if}
{/if}
@@ -357,10 +338,11 @@
diff --git a/src/routes/(console)/project-[project]/sites/create-site/variableEditorModal.svelte b/src/routes/(console)/project-[project]/sites/create-site/variableEditorModal.svelte
index b10849801..299f9ec94 100644
--- a/src/routes/(console)/project-[project]/sites/create-site/variableEditorModal.svelte
+++ b/src/routes/(console)/project-[project]/sites/create-site/variableEditorModal.svelte
@@ -5,11 +5,10 @@
import Button from '$lib/elements/forms/button.svelte';
import { addNotification } from '$lib/stores/notifications';
import { parse } from 'envfile';
- import { Icon, Layout, Tabs } from '@appwrite.io/pink-svelte';
+ import { Alert, Icon, Layout, Tabs } from '@appwrite.io/pink-svelte';
import { IconDownload, IconDuplicate } from '@appwrite.io/pink-icons-svelte';
import { InputTextarea } from '$lib/elements/forms';
import type { Models } from '@appwrite.io/console';
- import Alert from '$lib/components/alert.svelte';
import { Link } from '$lib/elements';
export let showEditor = false;
@@ -137,10 +136,10 @@
{#if secretVariables?.length > 0}
-
+
{secretVariables.length} secret variables are hidden from the editor. Their values will
remain unchanged. Learn more.
-
+
{/if}
diff --git a/src/routes/(console)/project-[project]/sites/grid.svelte b/src/routes/(console)/project-[project]/sites/grid.svelte
index 3c9966635..e531611f1 100644
--- a/src/routes/(console)/project-[project]/sites/grid.svelte
+++ b/src/routes/(console)/project-[project]/sites/grid.svelte
@@ -35,10 +35,7 @@
function getFilePreview(fileId: string) {
// TODO: @Meldiron use sdk.forConsole.storage.getFilePreview
const endpoint = getApiEndpoint();
- return (
- endpoint +
- `/storage/buckets/screenshots/files/${fileId}/view?project=console&mode=admin`
- );
+ return endpoint + `/storage/buckets/screenshots/files/${fileId}/view?project=console`;
}
diff --git a/src/routes/(console)/project-[project]/sites/redeployModal.svelte b/src/routes/(console)/project-[project]/sites/redeployModal.svelte
index 26a8c749d..ba3360a22 100644
--- a/src/routes/(console)/project-[project]/sites/redeployModal.svelte
+++ b/src/routes/(console)/project-[project]/sites/redeployModal.svelte
@@ -15,7 +15,7 @@
async function redeploy() {
try {
- sdk.forProject.sites.createDeploymentBuild(site.$id, selectedDeploymentId);
+ sdk.forProject.sites.createDuplicateDeployment(site.$id, selectedDeploymentId);
addNotification({
type: 'success',
message: `Redeploying ${site.name}`
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/+page.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/+page.svelte
index eb6cbd5cc..80ec4e7ce 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/+page.svelte
@@ -1,6 +1,6 @@
@@ -48,17 +47,29 @@
Visit
{/if}
-
- (showRollback = true)}>
- Instant rollback
-
+
+
+ (showRollback = true)}
+ disabled={!data.hasProdReadyDeployments}>
+ Instant rollback
+
+
+
+ Rollback is possible only if there is a deployment that is ready and was
+ active.
+
+
{:else if data.deployment?.status === 'building'}
+ src={$app.themeInUse === 'dark'
+ ? `${base}/images/empty-deployment-dark.svg`
+ : `${base}/images/empty-deployment-light.svg`}>
Your build is running. When it completes, this page will automatically
update with the latest deployment.
@@ -69,7 +80,9 @@
+ src={$app.themeInUse === 'dark'
+ ? `${base}/images/empty-deployment-dark.svg`
+ : `${base}/images/empty-deployment-light.svg`}>
Deploy your site to get started. Once deployed, you'll see your latest build
details here.
@@ -95,5 +108,6 @@
+ proxyRuleList={data.proxyRuleList}
+ prodReadyDeployments={data.prodReadyDeployments} />
{/if}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/+page.ts b/src/routes/(console)/project-[project]/sites/site-[site]/+page.ts
index 417ee2caf..c40d649c9 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/+page.ts
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/+page.ts
@@ -2,6 +2,7 @@ import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import { Query } from '@appwrite.io/console';
import { RuleType } from '$lib/stores/sdk';
+import { DeploymentResourceType } from '$lib/stores/sdk';
export const load = async ({ params, depends, parent }) => {
depends(Dependencies.SITE);
@@ -10,25 +11,30 @@ export const load = async ({ params, depends, parent }) => {
const [deploymentList, prodReadyDeployments, proxyRuleList] = await Promise.all([
sdk.forProject.sites.listDeployments(params.site, [Query.limit(4), Query.orderDesc('')]),
-
sdk.forProject.sites.listDeployments(params.site, [
- Query.limit(1)
- // Query.equal('status', 'ready')
- // Query.equal('live', true)
+ Query.equal('status', 'ready'),
+ Query.equal('activate', true),
+ Query.orderDesc('')
]),
sdk.forProject.proxy.listRules([
Query.equal('type', RuleType.DEPLOYMENT),
- Query.equal('automation', `site=${params.site}`),
- Query.orderDesc('')
+ Query.equal('deploymentResourceType', DeploymentResourceType.SITE),
+ Query.equal('deploymentResourceId', site.$id),
+ Query.equal('deploymentId', site.deploymentId),
+ Query.equal('trigger', 'manual')
])
]);
+
+ const deployment = deploymentList?.total
+ ? await sdk.forProject.sites.getDeployment(params.site, site.deploymentId)
+ : null;
return {
site,
deploymentList,
- deployment: deploymentList?.total
- ? await sdk.forProject.sites.getDeployment(params.site, site.deploymentId)
- : null,
+ deployment,
proxyRuleList,
- hasProdReadyDeployments: prodReadyDeployments?.deployments?.length > 0
+ prodReadyDeployments,
+ hasProdReadyDeployments:
+ prodReadyDeployments?.deployments?.filter((d) => d?.$id !== deployment?.$id).length > 0
};
};
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.svelte
index 35a10ebb7..2464ba1af 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.svelte
@@ -3,24 +3,23 @@
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { type Models } from '@appwrite.io/console';
- import { Filters } from '$lib/components/filters';
- import { queries, tags } from '$lib/components/filters/store';
import { View } from '$lib/helpers/load';
- import { ActionMenu, Icon, Layout, Popover, Tag } from '@appwrite.io/pink-svelte';
+ import { ActionMenu, Icon, Layout, Popover } from '@appwrite.io/pink-svelte';
import Table from './table.svelte';
- import QuickFilters from './quickFilters.svelte';
import RedeployModal from '../../redeployModal.svelte';
import CreateGitDeploymentModal from './createGitDeploymentModal.svelte';
import ConnectRepoModal from '../../(components)/connectRepoModal.svelte';
import { columns } from './store';
import CreateManualDeploymentModal from './createManualDeploymentModal.svelte';
- import DeploymentMetrics from './deploymentMetrics.svelte';
- import { IconFilterLine, IconPlus } from '@appwrite.io/pink-icons-svelte';
+ // import DeploymentMetrics from './deploymentMetrics.svelte';
+ import { IconPlus } from '@appwrite.io/pink-icons-svelte';
import { onMount } from 'svelte';
import { sdk } from '$lib/stores/sdk';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import CreateCliModal from './createCliModal.svelte';
+ import { ParsedTagList, QuickFilters } from '$lib/components/filters';
+ import { page } from '$app/stores';
export let data;
@@ -31,15 +30,12 @@
let hasInstallation = !!data.installations?.total;
let showConnectCLI = false;
let showConnectManual = false;
- let showMobileFilters = false;
-
- function clearAll() {
- queries.clearAll();
- queries.apply();
- }
onMount(() => {
- data?.query ? (showMobileFilters = true) : (showMobileFilters = false);
+ if ($page.url.searchParams.has('createDeployment')) {
+ showConnectRepo = true;
+ }
+
return sdk.forConsole.client.subscribe('console', (response) => {
if (response.events.includes('sites.*.deployments.*')) {
invalidate(Dependencies.DEPLOYMENTS);
@@ -50,70 +46,20 @@
-
+
+
-
-
+
+
- {#if data.deploymentList.total}
-
-
-
-
-
- More filters
-
- {#if $tags?.length}
-
-
-
- Clear all
- {/if}
-
-
+ {#if data.deploymentList.total || data?.query}
+
{/if}
-
-
-
(showMobileFilters = !showMobileFilters)}
- ariaLabel="toggle filters">
-
- Filters
-
-
-
-
-
-
- More filters
-
-
-
-
-
-
-
{#if data.deploymentList.total}
-
+
{/if}
@@ -152,7 +98,8 @@
-
+
+
{#if data.deploymentList.total}
@@ -195,7 +142,10 @@
{/if}
{#if showCreateDeployment}
-
+
{/if}
{#if showConnectManual}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/cancelDeploymentModal.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/cancelDeploymentModal.svelte
index d57eb6f77..0de8f95f4 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/cancelDeploymentModal.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/cancelDeploymentModal.svelte
@@ -1,7 +1,7 @@
-
+
Are you sure you want to cancel this deployment?
(showCancel = false)}>Cancel
Continue
-
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/createGitDeploymentModal.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/createGitDeploymentModal.svelte
index d65935c77..23d7c2069 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/createGitDeploymentModal.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/createGitDeploymentModal.svelte
@@ -4,39 +4,41 @@
import { Repositories } from '$lib/components/git';
import { Dependencies } from '$lib/constants';
import { Link } from '$lib/elements';
- import { Button, InputCheckbox, InputSelect } from '$lib/elements/forms';
+ import { Button, InputCheckbox, InputSelect, InputText } from '$lib/elements/forms';
import { timeFromNow } from '$lib/helpers/date';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { installation, repository, sortBranches } from '$lib/stores/vcs';
- import { Type, type Models } from '@appwrite.io/console';
+ import {
+ Adapter,
+ BuildRuntime,
+ Framework,
+ VCSDeploymentType,
+ type Models
+ } from '@appwrite.io/console';
import { IconGithub } from '@appwrite.io/pink-icons-svelte';
import { Icon, Layout, Skeleton, Typography } from '@appwrite.io/pink-svelte';
export let show = false;
export let site: Models.Site;
- let installations = { installations: [], total: 0 };
+ export let installations: Models.InstallationList;
let hasRepository = !!site?.providerRepositoryId;
let selectedRepository: string = site.providerRepositoryId;
let branch: string = null;
+ let commit: string = null;
let activate = true;
let error = '';
async function loadInstallations() {
- try {
- installations = await sdk.forProject.vcs.listInstallations();
- if (!site?.installationId && installations.total > 0) {
- installation.set(installations.installations[0]);
- }
- $installation = installations.installations.find(
- (installation) => installation.$id === site.installationId
- );
- if (!$installation?.$id) {
- $installation = installations.installations[0];
- }
- } catch (error) {
- console.log(error);
+ if (!site?.installationId && installations?.total > 0) {
+ installation.set(installations.installations[0]);
+ }
+ $installation = installations.installations.find(
+ (installation) => installation.$id === site.installationId
+ );
+ if (!$installation?.$id) {
+ $installation = installations.installations[0];
}
}
@@ -49,13 +51,12 @@
site.providerRepositoryId
);
}
+ selectedRepository = $repository?.id;
const branchList = await sdk.forProject.vcs.listRepositoryBranches(
$installation.$id,
selectedRepository
);
- console.log(branchList);
-
const sorted = sortBranches(branchList.branches);
branch = sorted[0]?.name ?? null;
@@ -72,7 +73,41 @@
async function createDeployment() {
try {
- await sdk.forProject.sites.createVcsDeployment(site.$id, Type.Branch, branch, activate);
+ if (!site?.providerRepositoryId) {
+ await sdk.forProject.sites.update(
+ site.$id,
+ site.name,
+ site.framework as Framework,
+ site.enabled || undefined,
+ site.timeout || undefined,
+ site.installCommand || undefined,
+ site.buildCommand || undefined,
+ site.outputDirectory || undefined,
+ (site?.buildRuntime as BuildRuntime) || undefined,
+ (site.adapter as Adapter) || undefined,
+ site.fallbackFile || undefined,
+ $installation.$id || undefined,
+ selectedRepository || undefined,
+ branch || undefined,
+ site.providerSilentMode || undefined,
+ site.providerRootDirectory || undefined
+ );
+ }
+ if (commit) {
+ await sdk.forProject.sites.createVcsDeployment(
+ site.$id,
+ VCSDeploymentType.Commit,
+ commit,
+ activate
+ );
+ } else if (branch) {
+ await sdk.forProject.sites.createVcsDeployment(
+ site.$id,
+ VCSDeploymentType.Branch,
+ branch,
+ activate
+ );
+ }
show = false;
invalidate(Dependencies.DEPLOYMENTS);
addNotification({
@@ -85,6 +120,8 @@
error = e.message;
}
}
+
+ $: console.log($repository);
@@ -153,6 +190,11 @@
branch = event.detail.value;
}}
{options} />
+
{#if branch}
{
+ let f = file as Partial & { removable: boolean };
+ f.removable = true;
+ return f;
+ })
+ : [];
Manually deploy a site by uploading any file(s) or folder.
-
-
+
+
+ Upload a zip file (tar.gz) containing your function source code
+
+
+
+
+
+
+ Drag and drop file here or click to upload
+
+
+
+
+
+ Only .tar.gz files allowed
+
+
+ Max file size 10MB
+
+
+
+ {#if files?.length}
+ (files = removeFile(e.detail, files))} />
+ {/if}
+
(show = false)}>Cancel
Create
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deleteDeploymentModal.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deleteDeploymentModal.svelte
index d1651ae95..cfe01d526 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deleteDeploymentModal.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deleteDeploymentModal.svelte
@@ -8,10 +8,14 @@
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import type { Models } from '@appwrite.io/console';
+ import { Typography } from '@appwrite.io/pink-svelte';
export let showDelete = false;
export let selectedDeployment: Models.Deployment = null;
+ export let activeDeployment: string;
+
let error: string;
+
async function handleSubmit() {
try {
await sdk.forProject.sites.deleteDeployment(
@@ -19,9 +23,11 @@
selectedDeployment.$id
);
await invalidate(Dependencies.SITE);
- await goto(
- `${base}/project-${$page.params.project}/sites/site-${$page.params.site}/deployments`
- );
+ if ($page.url.href.includes(`deployment-${selectedDeployment.$id}`)) {
+ await goto(
+ `${base}/project-${$page.params.project}/sites/site-${$page.params.site}/deployments`
+ );
+ }
showDelete = false;
addNotification({
type: 'success',
@@ -35,6 +41,16 @@
}
-
- Are you sure you want to delete this deployment?
+
+ Are you sure you want to delete this deployment?
+ {#if activeDeployment === selectedDeployment.$id}
+
+ Your site will no longer be available until you redeploy. This action is irreversible.
+
+ {/if}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte
index 7e5577107..5a7fbb1aa 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte
@@ -53,8 +53,8 @@
- {#if data.deployment?.status === 'ready'}
-
+ {#if data.deployment?.status === 'ready' && data.proxyRuleList?.total}
+
Visit
{/if}
@@ -75,17 +75,28 @@
-
+
-
+
+{#if showDelete}
+
+{/if}
{
depends(Dependencies.DEPLOYMENT);
@@ -13,7 +14,9 @@ export const load: PageLoad = async ({ params, depends, parent }) => {
sdk.forProject.sites.getDeployment(params.site, params.deployment),
sdk.forProject.proxy.listRules([
Query.equal('type', RuleType.DEPLOYMENT),
- Query.equal('value', params.deployment)
+ Query.equal('deploymentId', params.deployment),
+ Query.equal('deploymentResourceType', DeploymentResourceType.SITE),
+ Query.equal('deploymentResourceId', params.site)
])
]);
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/quickFilters.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/quickFilters.svelte
deleted file mode 100644
index ac6b64abd..000000000
--- a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/quickFilters.svelte
+++ /dev/null
@@ -1,276 +0,0 @@
-
-
-{#each [typeFilter] as filter}
-
-
-
- {#key filter.tag}
-
- {filter?.tag ?? filter.title}
-
- {/key}
-
-
-
-
- {#each filter.options as option (option.value + option.checked)}
- {
- option.checked = !option.checked;
- addFilterAndApply(
- filter.id,
- filter.title,
- filter.operator,
- filter?.array ? null : option.checked ? option.value : null,
- filter?.array
- ? (filter.options
- .filter((opt) => opt.checked)
- .map((opt) => opt.value) ?? [])
- : []
- );
- }}>
- {option.label}
-
- {/each}
- {#if filter.options.some((option) => option.checked)}
- {
- filter.tag = null;
- addFilterAndApply(filter.id, filter.title, filter.operator, null, []);
- toggle(e);
- }}>
- Clear selection
-
- {/if}
-
-
-
-{/each}
-{#each [sizeFilter] as filter}
-
-
-
-
- {#key filter.tag}
-
- {filter?.tag ?? filter.title}
-
- {/key}
-
-
-
-
-
- {#each filter.options as option (option.value + option.checked)}
- {
- addFilterAndApply(
- filter.id,
- filter.title,
- filter.operator,
- filter?.array ? null : option.value,
- []
- );
- toggle(e);
- }}>
- {option.label}
-
- {/each}
- {#if filter?.tag}
- {
- filter.show = false;
- filter.tag = null;
- addFilterAndApply(filter.id, filter.title, filter.operator, null, []);
- }}>
- Clear selection
-
- {/if}
-
-
-
-{/each}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/store.ts b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/store.ts
index f383a7772..166b666dd 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/store.ts
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/store.ts
@@ -13,13 +13,12 @@ export const columns = writable([
width: 110,
array: true,
format: 'enum',
- elements: ['ready', 'processing', 'building', 'waiting', 'cancelled', 'failed'],
- filter: false
+ elements: ['ready', 'processing', 'building', 'waiting', 'cancelled', 'failed']
},
{
- id: 'buildTime',
- title: 'Build time',
+ id: 'buildDuration',
+ title: 'Build duration',
type: 'integer',
show: true,
width: 90,
@@ -40,10 +39,10 @@ export const columns = writable([
filter: false
},
{
- id: 'size',
+ id: 'sourceSize',
title: 'Source size',
type: 'integer',
- show: true,
+ show: false,
width: 140,
elements: [
{
@@ -64,7 +63,7 @@ export const columns = writable([
id: 'buildSize',
title: 'Build size',
type: 'integer',
- show: false,
+ show: true,
filter: false,
width: 80
},
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/table.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/table.svelte
index 066062e47..43ee52e75 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/table.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/table.svelte
@@ -3,8 +3,7 @@
import type { PageData } from './$types';
import { type Models } from '@appwrite.io/console';
import { formatTimeDetailed } from '$lib/helpers/timeConversion';
- import DeploymentSource from '../../(components)/deploymentSource.svelte';
- import DeploymentCreatedBy from '../../(components)/deploymentCreatedBy.svelte';
+ import { DeploymentSource, DeploymentCreatedBy } from '$lib/components/git';
import { timer } from '$lib/actions/timer';
import { calculateSize } from '$lib/helpers/sizeConvertion';
import { page } from '$app/stores';
@@ -15,9 +14,9 @@
import { Layout, Status, Table } from '@appwrite.io/pink-svelte';
import { columns } from './store';
import ActivateDeploymentModal from '../../activateDeploymentModal.svelte';
- import { deploymentStatusConverter } from '../store';
import { capitalize } from '$lib/helpers/string';
import DeploymentActionMenu from '../../(components)/deploymentActionMenu.svelte';
+ import { deploymentStatusConverter } from '$lib/stores/git';
export let data: PageData;
@@ -70,17 +69,19 @@
- {:else if column.id === 'buildTime'}
+ {:else if column.id === 'buildDuration'}
- {#if ['processing', 'building'].includes(deployment.status)}
+ {#if ['waiting'].includes(deployment.status)}
+ -
+ {:else if ['processing', 'building'].includes(deployment.status)}
{:else}
- {formatTimeDetailed(deployment.buildTime)}
+ {formatTimeDetailed(deployment.buildDuration)}
{/if}
- {:else if column.id === 'size'}
+ {:else if column.id === 'sourceSize'}
- {calculateSize(deployment.size)}
+ {calculateSize(deployment.sourceSize)}
{:else if column.id === 'buildSize'}
@@ -106,7 +107,7 @@
{#if selectedDeployment}
-
+
{/if}
{#if selectedDeployment && showDelete}
-
+
{/if}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/domains/+page.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/domains/+page.svelte
index 82620709c..ca266002f 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/domains/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/domains/+page.svelte
@@ -25,34 +25,53 @@
} from '@appwrite.io/pink-svelte';
import DeleteDomainModal from './deleteDomainModal.svelte';
import RetryDomainModal from './retryDomainModal.svelte';
- import { queries } from '$lib/components/filters';
import SearchQuery from '$lib/components/searchQuery.svelte';
import { app } from '$lib/stores/app';
- import { RuleType } from '$lib/stores/sdk';
+ import { Click, trackEvent } from '$lib/actions/analytics';
+ import CreatePreviewDomainModal from './createPreviewDomainModal.svelte';
export let data;
let showDelete = false;
let showRetry = false;
let selectedDomain: Models.ProxyRule = null;
+ let showPreviewDomainModal = false;
$: console.log(data.domains);
-
-
-
- Add domain
-
+
+
+ {
+ toggle(event);
+ trackEvent(Click.DomainCreateClick, {
+ source: 'sites_domain_overview'
+ });
+ }}>
+
+ Add domain
+
+
+
+
+ Custom domain
+
+ (showPreviewDomainModal = true)}>
+ Preview domain
+
+
+
+
{#if data.domains.total}
- Domain
+ Domain
Redirect to
Production branch
@@ -60,24 +79,20 @@
{#each data.domains.rules as domain}
-
+
{domain.domain}
+
- {domain.type === RuleType.REDIRECT ? (domain?.value ?? '-') : 'No redirect'}
+ {domain?.redirectUrl || 'No redirect'}
+ {domain?.redirectStatusCode ? `(${domain.redirectStatusCode})` : ''}
- {domain.automation.includes('branch')
- ? domain.automation.split('branch=')[1]
- : '-'}
+ {domain.deploymentVcsProviderBranch || '-'}
@@ -114,6 +129,9 @@
selectedDomain = domain;
showDelete = true;
toggle(e);
+ trackEvent(Click.DomainDeleteClick, {
+ source: 'sites_domain_overview'
+ });
}}>
Delete
@@ -131,15 +149,14 @@
limit={data.limit}
offset={data.offset}
total={data.domains.total} />
- {:else if data?.query}
-
+ {:else if data?.search}
+
{
- queries.clearAll();
- queries.apply();
- }}>Clear filters
+ data.search = '';
+ }}>Clear search
{:else}
@@ -148,8 +165,8 @@
src={$app.themeInUse === 'dark'
? `${base}/images/domains/empty-domain-dark.svg`
: `${base}/images/domains/empty-domain-light.svg`}
- title="Add your first domain"
- description="Connect a domain you own to get your project up and running.">
+ title="Use a custom domain for your site"
+ description="Give your site a unique identity and make it easier to find by by assigning it a custom domain.">
{#if showDelete}
-
+
{/if}
{#if showRetry}
-
+
+{/if}
+
+{#if showPreviewDomainModal}
+
{/if}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/domains/+page.ts b/src/routes/(console)/project-[project]/sites/site-[site]/domains/+page.ts
index dc6f0cff0..98f88e4d5 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/domains/+page.ts
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/domains/+page.ts
@@ -1,9 +1,10 @@
import { Query } from '@appwrite.io/console';
-import { sdk } from '$lib/stores/sdk';
+import { RuleTrigger, sdk } from '$lib/stores/sdk';
import { getLimit, getPage, getQuery, getSearch, pageToOffset } from '$lib/helpers/load';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import { queries, queryParamToMap } from '$lib/components/filters';
import { RuleType } from '$lib/stores/sdk';
+import { DeploymentResourceType } from '$lib/stores/sdk';
export const load = async ({ params, depends, url, route }) => {
depends(Dependencies.SITES_DOMAINS);
@@ -24,7 +25,9 @@ export const load = async ({ params, depends, url, route }) => {
domains: await sdk.forProject.proxy.listRules(
[
Query.equal('type', [RuleType.DEPLOYMENT, RuleType.REDIRECT]),
- Query.equal('automation', `site=${params.site}`),
+ Query.equal('deploymentResourceType', DeploymentResourceType.SITE),
+ Query.equal('deploymentResourceId', params.site),
+ Query.equal('trigger', RuleTrigger.MANUAL),
Query.limit(limit),
Query.offset(offset),
Query.orderDesc(''),
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/+page.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/+page.svelte
index 61213a7b4..b7e65b1de 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/+page.svelte
@@ -1,44 +1,45 @@
-
- {#if domainData}
- {#if domainData.status === 'created'}
-
-
-
- Back
- Verify
-
-
- {:else if domainData.status === 'verifying'}
-
-
- {domainData.domain}
-
-
-
-
-
-
-
-
- {:else if domainData.status === 'verified'}
-
-
- {domainData.domain}
-
-
-
-
- {/if}
- {:else}
-
-
-
-
-
-
- {#if redirect}
+
+
+
+
+
+
+
+
+
+
+ Connect this domain to your active deployment and configure the linked Git
+ branch as needed.
+
+
+ Automatically forward traffic from this domain to another URL of your choice.
+
+
+
+ {#if behaviour === 'CREATE'}
+
+
+ {#if data.site?.providerRepositoryId}
+ {@const sortedBranches = sortBranches(data.branches.branches)}
+ {@const options = sortedBranches.map((branch) => ({
+ label: branch.name,
+ value: branch.name
+ }))}
+
+
+ {#if !data.branches?.total}
+
+ No branches found in the selected repository. Create a
+ branch to see it here.
+
+ {/if}
+
+ {:else}
+
+
+
+
+ The domain will be connected to your active deployment.
+ Connect your Git repository to link a production branch.
+
+
+ (showConnectRepo = true)}>
+ Connect repository
+
+
+
+
+ {/if}
+
+
+
+
+ {:else if behaviour === 'REDIRECT'}
+
+
+
+
+
+
+ Redirect this domain. Domains added to your project will be
+ listed here.
+
+
+
- {/if}
-
- {#if data.branches?.total}
- {@const sortedBranches = sortBranches(data.branches.branches)}
- {@const options = sortedBranches.map((branch) => ({
- label: branch.name,
- value: branch.name
- }))}
-
- {/if}
-
-
-
- Add
-
-
-
- {/if}
-
+
+ {/if}
+
+
Cancel
- {#if domainData}
- Go to dashboard
- {/if}
+ formComponent.triggerSubmit()} bind:disabled={$isSubmitting}>
+ Add
+
+
+{#if showConnectRepo}
+
+{/if}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/+page.ts b/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/+page.ts
index f1a438415..1105f8445 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/+page.ts
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/+page.ts
@@ -1,12 +1,22 @@
import { Query } from '@appwrite.io/console';
import { sdk } from '$lib/stores/sdk';
-import { RuleType } from '$lib/stores/sdk';
+import { RuleTrigger, RuleType } from '$lib/stores/sdk';
export const load = async ({ parent }) => {
const { site } = await parent();
+ const [domains, installations] = await Promise.all([
+ sdk.forProject.proxy.listRules([
+ Query.equal('type', RuleType.DEPLOYMENT),
+ Query.equal('trigger', RuleTrigger.MANUAL)
+ ]),
+ sdk.forProject.vcs.listInstallations()
+ ]);
+
return {
- domains: await sdk.forProject.proxy.listRules([Query.equal('type', RuleType.DEPLOYMENT)]),
+ site,
+ domains,
+ installations,
branches:
site?.installationId && site?.providerRepositoryId
? await sdk.forProject.vcs.listRepositoryBranches(
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/verify/+page.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/verify/+page.svelte
new file mode 100644
index 000000000..88289f579
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/verify/+page.svelte
@@ -0,0 +1,182 @@
+
+
+
+ {#if isVerified}
+
+
+ {data.domain.domain}
+
+
+
+ {:else}
+
+
+
+
+ (selectedTab = 'cname')}
+ active={selectedTab === 'cname'}>
+ CNAME
+
+ (selectedTab = 'nameserver')}
+ active={selectedTab === 'nameserver'}>
+ Nameservers
+
+
+
+
+ {#if selectedTab === 'cname'}
+
+
+ {data.domain?.domain}
+ {#if isVerified}
+
+ {:else}
+
+ {/if}
+
+
+ Add the following record on your DNS provider. Note that DNS changes may
+ take time to propagate fully.
+
+
+
+
+
+ Type
+ Name
+ Value
+
+
+ CNAME
+ {data.domain?.domain}
+
+
+ {globalThis?.location?.origin}
+
+
+
+
+
+
+ A list of all domain providers and their DNS setting is available here.
+
+
+
+
+
+ Verify
+
+ {:else}
+
+
+ {data.domain?.domain}
+
+
+
+ Add the following nameservers on your DNS provider. Note that DNS
+ changes may take time to propagate fully.
+
+
+
+
+
+ Type
+ Value
+
+ {#each nameservers as nameserver}
+
+ NS
+
+
+ {nameserver}
+
+
+ {/each}
+
+
+
+
+
+ Verify
+
+ {/if}
+
+
+ {/if}
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/verify/+page.ts b/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/verify/+page.ts
new file mode 100644
index 000000000..eab359a42
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/domains/add-domain/verify/+page.ts
@@ -0,0 +1,16 @@
+import { sdk } from '$lib/stores/sdk';
+import { isCloud } from '$lib/system';
+
+export const load = async ({ params }) => {
+ if (isCloud) {
+ // if (params?.id) {
+ // return {
+ // domain: await sdk.forConsole.domains.get(params.id)
+ // };
+ // }
+ } else {
+ return {
+ domain: undefined
+ };
+ }
+};
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/domains/createPreviewDomainModal.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/domains/createPreviewDomainModal.svelte
new file mode 100644
index 000000000..ec9d82559
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/domains/createPreviewDomainModal.svelte
@@ -0,0 +1,104 @@
+
+
+
+
+ Get an auto-generated domain to quickly access your project. You can customize its prefix.
+
+
+
+
+
+
+
+ .{$consoleVariables._APP_DOMAIN_SITES}
+
+
+
+
+
+
+
+
+ (show = false)}>Cancel
+ Add
+
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/domains/deleteDomainModal.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/domains/deleteDomainModal.svelte
index f3bcf72d9..514078ec0 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/domains/deleteDomainModal.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/domains/deleteDomainModal.svelte
@@ -7,6 +7,7 @@
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { Dependencies } from '$lib/constants';
import { Confirm } from '$lib/components';
+ import { Typography } from '@appwrite.io/pink-svelte';
export let show = false;
export let selectedDomain: Models.ProxyRule;
@@ -20,7 +21,7 @@
show = false;
addNotification({
type: 'success',
- message: `${selectedDomain.domain} has been deleted`
+ message: `Domain has been deleted`
});
trackEvent(Submit.DomainDelete);
} catch (e) {
@@ -32,10 +33,13 @@
{#if selectedDomain}
-
- Are you sure you want to delete {selectedDomain.domain} ? You will no longer be
- able to view your site by visiting this domain.
-
+
+ Are you sure you want to delete this domain? You will no longer be able to view your
+ site by visiting:
+
+
+ {selectedDomain.domain}
+
{/if}
import { Copy } from '$lib/components';
import { Link } from '$lib/elements';
- import type { Models } from '@appwrite.io/console';
+ import type { Domain } from '$lib/sdk/domains';
import { IconInfo } from '@appwrite.io/pink-icons-svelte';
import { Badge, Layout, Typography, Table, Fieldset, Icon } from '@appwrite.io/pink-svelte';
- export let domain: Models.ProxyRule;
+ export let domain: Domain;
@@ -13,7 +13,7 @@
- {domain.domain}
+ {domain?.domain}
@@ -30,7 +30,7 @@
CNAME
- {domain.domain}
+ {domain?.domain}
{globalThis?.location?.origin}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/domainsOverview.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/domainsOverview.svelte
index a71794617..3ec3358b1 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/domainsOverview.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/domainsOverview.svelte
@@ -4,12 +4,13 @@
import { Badge, Divider, Icon, Layout, Typography } from '@appwrite.io/pink-svelte';
import OpenOnMobileModal from '../(components)/openOnMobileModal.svelte';
import { timeFromNow } from '$lib/helpers/date';
- import { IconExternalLink, IconQrcode } from '@appwrite.io/pink-icons-svelte';
+ import { IconQrcode } from '@appwrite.io/pink-icons-svelte';
import { protocol } from '$routes/(console)/store';
import { type Models } from '@appwrite.io/console';
import { Link } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import { Card, Trim } from '$lib/components';
+ import { Click, trackEvent } from '$lib/actions/analytics';
export let proxyRuleList: Models.ProxyRuleList;
@@ -54,6 +55,11 @@
{
+ trackEvent(Click.DomainCreateClick, {
+ source: 'sites_domain_overview'
+ });
+ }}
href={`${base}/project-${$page.params.project}/sites/site-${$page.params.site}/domains/add-domain`}>
Add domain
@@ -70,12 +76,16 @@
direction="row"
gap="xl">
-
+
{rule.domain}
-
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/empty-deployment-dark.svg b/src/routes/(console)/project-[project]/sites/site-[site]/empty-deployment-dark.svg
deleted file mode 100644
index 414175d0a..000000000
--- a/src/routes/(console)/project-[project]/sites/site-[site]/empty-deployment-dark.svg
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/empty-deployment-light.svg b/src/routes/(console)/project-[project]/sites/site-[site]/empty-deployment-light.svg
deleted file mode 100644
index 60330bcaf..000000000
--- a/src/routes/(console)/project-[project]/sites/site-[site]/empty-deployment-light.svg
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/header.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/header.svelte
index 664ad1314..e3e1291ab 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/header.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/header.svelte
@@ -19,11 +19,6 @@
title: 'Deployments',
event: 'deployments'
},
- // {
- // href: `${path}/analytics`,
- // title: 'Analytics',
- // event: 'analytics'
- // },
{
href: `${path}/logs`,
title: 'Logs',
@@ -34,6 +29,11 @@
title: 'Domains',
event: 'domains'
},
+ {
+ href: `${path}/usage`,
+ title: 'Usage',
+ event: 'usage'
+ },
{
href: `${path}/settings`,
title: 'Settings',
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/instantRollbackModal.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/instantRollbackModal.svelte
index 4389c04d0..874fea7ad 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/instantRollbackModal.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/instantRollbackModal.svelte
@@ -1,16 +1,14 @@
-
- (requestTab = 'parameters')}>
- Parameters
-
-
- (requestTab = 'headers')}>
- Headers
-
- (requestTab = 'body')}>
- Body
-
-
+
+
+ (requestTab = 'parameters')}>
+ Parameters
+
+
+ (requestTab = 'headers')}>
+ Headers
+
+
+
+
{#if requestTab === 'parameters'}
{#if parameters?.length}
@@ -66,7 +80,9 @@
{/each}
{:else}
- No parameters found.
+
+ No parameters found.
+
{/if}
{:else if requestTab === 'headers'}
{#if selectedLog.requestHeaders?.length}
@@ -82,16 +98,17 @@
{/each}
-
-
- Missing headers?
- Check our docs to see the supported data and how to log it.
-
-
+
+
+
+ Missing headers? Check the docs to
+ see the supported data and how to log it.
+
+
{:else}
- No headers found.
+
+ No headers found.
+
{/if}
- {:else if requestTab === 'body'}
- No body found.
{/if}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/logs/(components)/LogsResponse.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/logs/(components)/LogsResponse.svelte
index a1f199a81..91071754a 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/logs/(components)/LogsResponse.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/logs/(components)/LogsResponse.svelte
@@ -1,54 +1,75 @@
-
- (responseTab = 'logs')}>
- Logs
-
- (responseTab = 'errors')}>
- Errors
-
- (responseTab = 'headers')}>
- Headers
-
- (responseTab = 'body')}>
- Body
-
-
+
+
+ (responseTab = 'logs')}>
+ Logs
+
+
+ (responseTab = 'headers')}>
+ Headers
+
+
+
+
+
{#if responseTab === 'logs'}
{#if selectedLog.logs}
{:else}
- No logs found.
+
+ No logs found.
+
{/if}
{:else if responseTab === 'errors'}
{#if selectedLog.errors}
{:else}
- No errors found.
+
+ No errors found.
+
{/if}
{:else if responseTab === 'headers'}
{#if selectedLog.responseHeaders?.length}
@@ -64,20 +85,25 @@
{/each}
-
-
- Missing headers?
- Check our docs to see the supported data and how to log it.
-
-
+
+
+
+ Missing headers? Check the docs to
+ see the supported data and how to log it.
+
+
{:else}
- No headers found.
+
+ No headers found.
+
{/if}
{:else if responseTab === 'body'}
{#if selectedLog.responseBody}
{:else}
- No parameters found.
+
+ No parameters found.
+
{/if}
{/if}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/logs/+page.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/logs/+page.svelte
index f75336558..ec1935eaf 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/logs/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/logs/+page.svelte
@@ -1,59 +1,21 @@
-
-
- {#if data.logs.total}
-
- {/if}
-
+
+
+
+ {#if data.logs.total}
+
+ {/if}
+
+
+
{#if data?.logs?.total}
@@ -80,19 +45,11 @@
offset={data.offset}
total={data.logs.total} />
{:else if data?.query}
-
-
- {
- queries.clearAll();
- queries.apply();
- }}>Clear filters
-
-
+
{:else}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/logs/+page.ts b/src/routes/(console)/project-[project]/sites/site-[site]/logs/+page.ts
index 1a324969c..ece296b39 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/logs/+page.ts
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/logs/+page.ts
@@ -11,7 +11,6 @@ export const load = async ({ params, depends, url, route, parent }) => {
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
const query = getQuery(url);
- const search = getSearch(url);
const parsedQueries = queryParamToMap(query || '[]');
queries.set(parsedQueries);
@@ -20,17 +19,12 @@ export const load = async ({ params, depends, url, route, parent }) => {
offset,
limit,
query,
- search,
site,
- logs: await sdk.forProject.sites.listLogs(
- params.site,
- [
- Query.limit(limit),
- Query.offset(offset),
- Query.orderDesc(''),
- ...parsedQueries.values()
- ],
- search
- )
+ logs: await sdk.forProject.sites.listLogs(params.site, [
+ Query.limit(limit),
+ Query.offset(offset),
+ Query.orderDesc(''),
+ ...parsedQueries.values()
+ ])
};
};
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/logs/sheet.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/logs/sheet.svelte
index 6bc7648dd..d50a824b3 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/logs/sheet.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/logs/sheet.svelte
@@ -17,6 +17,7 @@
import LogsRequest from './(components)/LogsRequest.svelte';
import LogsResponse from './(components)/LogsResponse.svelte';
import { capitalize } from '$lib/helpers/string';
+ import { Copy } from '$lib/components';
export let open = false;
export let selectedLogId: string;
@@ -49,7 +50,9 @@
Log ID
- {selectedLog?.$id}
+
+ {selectedLog?.$id}
+
@@ -65,45 +68,48 @@
-
-
-
- Method
-
-
- {selectedLog.requestMethod}
-
-
-
-
- Status code
-
-
- = 400
- ? 'error'
- : 'success'} />
-
-
-
-
- Duration
-
-
- {calculateTime(selectedLog.duration)}
-
-
-
-
- Created
-
-
- {capitalize(timeFromNow(selectedLog.$createdAt))}
-
-
+
+
+
+
+ Method
+
+
+ {selectedLog.requestMethod}
+
+
+
+
+ Status code
+
+
+ = 400
+ ? 'error'
+ : 'success'} />
+
+
+
+
+ Duration
+
+
+ {calculateTime(selectedLog.duration)}
+
+
+
+
+ Created
+
+
+ {capitalize(timeFromNow(selectedLog.$createdAt))}
+
+
+
+
Path
@@ -111,7 +117,7 @@
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/logs/store.ts b/src/routes/(console)/project-[project]/sites/site-[site]/logs/store.ts
new file mode 100644
index 000000000..617963999
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/logs/store.ts
@@ -0,0 +1,117 @@
+import type { Column } from '$lib/helpers/types';
+import { writable } from 'svelte/store';
+
+export const columns = writable([
+ { id: '$id', title: 'Log ID', type: 'string', show: true, width: 150 },
+ {
+ id: 'requestPath',
+ title: 'Path',
+ type: 'string',
+ show: true,
+ width: 90,
+ format: 'string'
+ },
+
+ {
+ id: 'trigger',
+ title: 'Trigger',
+ type: 'string',
+ show: false,
+ width: 90,
+ array: true,
+ format: 'enum',
+ elements: [
+ { value: 'http', label: 'HTTP' },
+ { value: 'schedule', label: 'Schedule' },
+ { value: 'event', label: 'Event' }
+ ],
+ filter: false,
+ hide: true
+ },
+ {
+ id: 'requestMethod',
+ title: 'Method',
+ type: 'string',
+ show: false,
+ width: 70,
+ array: true,
+ format: 'enum',
+ elements: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
+ hide: true
+ },
+ {
+ id: 'responseStatusCode',
+ title: 'Status code',
+ type: 'integer',
+ show: false,
+ width: 100,
+ format: 'integer',
+ elements: [
+ {
+ value: 299,
+ label: 'Success (200-299)'
+ },
+ {
+ value: 399,
+ label: 'Redirect (300-399)'
+ },
+ {
+ value: 499,
+ label: 'Client error (400-499)'
+ },
+ {
+ value: 599,
+ label: 'Server error (500-599)'
+ }
+ ],
+ hide: true,
+ filter: false //TODO: re-enable
+ },
+
+ {
+ id: 'duration',
+ title: 'Duration',
+ type: 'integer',
+ show: true,
+ width: 80,
+ format: 'integer',
+ elements: [
+ {
+ value: 1,
+ label: 'more than 1 second'
+ },
+ {
+ value: 5,
+ label: 'more than 5 seconds'
+ },
+ {
+ value: 30,
+ label: 'more than 30 seconds'
+ }
+ ],
+ filter: false,
+ hide: true
+ },
+ {
+ id: '$createdAt',
+ title: 'Created',
+ type: 'datetime',
+ show: true,
+ width: 120,
+ format: 'datetime',
+ elements: [
+ {
+ value: 5 * 60 * 1000,
+ label: 'last 5 minutes'
+ },
+ {
+ value: 60 * 60 * 1000,
+ label: 'last 1 hour'
+ },
+ {
+ value: 24 * 60 * 60 * 1000,
+ label: 'last 24 hours'
+ }
+ ]
+ }
+]);
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/logs/table.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/logs/table.svelte
index 3d791aafa..5e3e95e80 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/logs/table.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/logs/table.svelte
@@ -19,7 +19,7 @@
{#each columns as column}
{#if column.show}
- {column.title}
+ {column.title}
{/if}
{/each}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/+page.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/settings/+page.svelte
index 6522c13db..d83bb7a02 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/settings/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/settings/+page.svelte
@@ -2,7 +2,6 @@
import { Container } from '$lib/layout';
import DangerZone from './dangerZone.svelte';
import UpdateName from './updateName.svelte';
- import UpdateVariables from '../../../updateVariables.svelte';
import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import { invalidate } from '$app/navigation';
@@ -13,7 +12,9 @@
import UpdateRepository from './updateRepository.svelte';
import { onMount } from 'svelte';
import { showConnectRepo } from './store';
- import UpdateSpa from './updateSPA.svelte';
+ import { isCloud } from '$lib/system';
+ import UpdateResourceLimits from './updateResourceLimits.svelte';
+ import UpdateVariables from '$routes/(console)/project-[project]/updateVariables.svelte';
export let data;
@@ -57,8 +58,11 @@
-
+ {#key data.site.providerRepositoryId}
+
+ {/key}
+
+ product="site"
+ analyticsSource="site_settings" />
+ {#if isCloud}
+
+ {/if}
-
-
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/+page.ts b/src/routes/(console)/project-[project]/sites/site-[site]/settings/+page.ts
index 10a99557a..3a46b9873 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/settings/+page.ts
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/settings/+page.ts
@@ -6,12 +6,14 @@ export const load = async ({ params, depends, parent }) => {
depends(Dependencies.SITE);
const { site } = await parent();
- const [globalVariables, variables, frameworks, installations] = await Promise.all([
- sdk.forProject.projectApi.listVariables(),
- sdk.forProject.sites.listVariables(params.site),
- sdk.forProject.sites.listFrameworks(),
- sdk.forProject.vcs.listInstallations()
- ]);
+ const [globalVariables, variables, frameworks, installations, specificationsList] =
+ await Promise.all([
+ sdk.forProject.projectApi.listVariables(),
+ sdk.forProject.sites.listVariables(params.site),
+ sdk.forProject.sites.listFrameworks(),
+ sdk.forProject.vcs.listInstallations(),
+ sdk.forProject.sites.listSpecifications()
+ ]);
// Conflicting variables first
variables.variables = variables.variables.sort((var1, var2) => {
@@ -36,6 +38,7 @@ export const load = async ({ params, depends, parent }) => {
frameworks,
variables,
globalVariables,
- installations
+ installations,
+ specificationsList
};
};
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/dangerZone.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/settings/dangerZone.svelte
index bfe14638e..0470ebdd7 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/settings/dangerZone.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/settings/dangerZone.svelte
@@ -11,8 +11,7 @@
Delete site
- The site will be permanently deleted, including all deployments associated with it. This action is
- irreversible.
+ The site will be permanently deleted, including all deployments associated with it.
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/deleteModal.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/settings/deleteModal.svelte
index c7e5a41a8..bf7b70560 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/settings/deleteModal.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/settings/deleteModal.svelte
@@ -30,5 +30,6 @@
- Are you sure you want to delete this site and all associated deployments from your project?
+ Are you sure you want to delete this site and all associated deployments from your project? This
+ action is irreversible.
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/disconnectRepo.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/settings/disconnectRepo.svelte
index 2028bb718..5029895a5 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/settings/disconnectRepo.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/settings/disconnectRepo.svelte
@@ -1,12 +1,12 @@
-
+
Are you sure you want to disconnect {site.name} ? This will affect future deployments
to this site.
@@ -63,4 +63,4 @@
(show = false)}>Cancel
Disconnect
-
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/store.ts b/src/routes/(console)/project-[project]/sites/site-[site]/settings/store.ts
index 7b0c5c905..e66ee97b3 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/settings/store.ts
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/settings/store.ts
@@ -1,3 +1,93 @@
import { writable } from 'svelte/store';
export const showConnectRepo = writable(false);
+
+export const adapterDataList = [
+ {
+ framework: 'sveltekit',
+ ssr: {
+ desc: 'Use $ adapter in $ file.',
+ code: ['@sveltejs/adapter-node', 'svelte.config.js'],
+ url: 'https://kit.svelte.dev/docs#adapter-node'
+ },
+ static: {
+ desc: 'Use $ adapter in $ file.',
+ code: ['@sveltejs/adapter-static', 'svelte.config.js'],
+ url: 'https://kit.svelte.dev/docs#adapter-static'
+ }
+ },
+ {
+ framework: 'astro',
+ ssr: {
+ desc: 'Use $ adapter in $ file.',
+ code: ['@astro/node', 'astro.config.mjs'],
+ url: 'https://docs.astro.build/en/guides/server-side-rendering/'
+ },
+ static: {
+ desc: "Ensure you don't set $ adapter in $ file.",
+ code: ['adapter', 'astro.config.mjs'],
+ url: 'https://docs.astro.build/en/guides/deploy/'
+ }
+ },
+ {
+ framework: 'remix',
+ ssr: {
+ desc: 'Ensure $ file uses $ package.',
+ code: ['entry.server.tsx', '@remix-run/node']
+ },
+ static: {
+ desc: 'Set $ in $ plugin in $ file.',
+ code: ['ssr: false', 'remix', 'vite.config.ts']
+ }
+ },
+ {
+ framework: 'nuxt',
+ ssr: {
+ desc: 'Set build command to $ in site settings.',
+ code: ['npm run build'],
+ url: 'https://nuxt.com/docs/getting-started/deployment'
+ },
+ static: {
+ desc: 'Set build command to $ in site settings.',
+ code: ['npm run generate'],
+ url: 'https://nuxt.com/docs/getting-started/deployment#static-hosting'
+ }
+ },
+ {
+ framework: 'nextjs',
+ ssr: {
+ desc: "Ensure you don't set $ in $ file.",
+ code: ['output', 'next.config.js'],
+ url: 'https://nextjs.org/docs/pages/building-your-application/deploying'
+ },
+ static: {
+ desc: 'Set $ in $ file',
+ code: ["output: 'export'", 'next.config.js'],
+ url: 'https://nextjs.org/docs/pages/building-your-application/deploying/static-exports'
+ }
+ },
+ {
+ framework: 'analog',
+ ssr: {
+ desc: 'Set $ in $ plugin in $',
+ code: ['ssr: true', 'analog', 'vite.config.ts'],
+ url: 'https://analogjs.org/docs/features/server/server-side-rendering'
+ },
+ static: {
+ desc: 'Set $ in $ plugin in $',
+ code: ['static: true', 'analog', 'vite.config.ts'],
+ url: 'https://analogjs.org/docs/features/server/static-site-generation'
+ }
+ },
+ {
+ framework: 'angular',
+ ssr: {
+ desc: 'Ensure $ file uses $ package.',
+ code: ['src/server.ts', '@angular/ssr/node'],
+ url: 'https://angular.dev/guide/ssr'
+ },
+ static: {
+ desc: "Angular's default build is static. No further action needed."
+ }
+ }
+];
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateBuildSettings.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateBuildSettings.svelte
index 653953ede..07f4f783a 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateBuildSettings.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateBuildSettings.svelte
@@ -7,21 +7,29 @@
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
- import { BuildRuntime, Framework, type Models } from '@appwrite.io/console';
- import { Layout } from '@appwrite.io/pink-svelte';
+ import { Adapter, BuildRuntime, Framework, type Models } from '@appwrite.io/console';
+ import { Card, Fieldset, Icon, InlineCode, Layout, Tooltip } from '@appwrite.io/pink-svelte';
+ import { iconPath } from '$lib/stores/app';
+ import { getFrameworkIcon } from '../../store';
+ import { Link } from '$lib/elements';
+ import { IconInfo } from '@appwrite.io/pink-icons-svelte';
+ import { adapterDataList } from './store';
export let site: Models.Site;
export let frameworks: Models.Framework[];
- let selectedFramework: Models.Framework = null;
+ let selectedFramework: Models.Framework = frameworks.find(
+ (framework) => framework.key === site.framework
+ );
+ let frameworkKey = site.framework;
+ let adapter: Adapter = site.adapter as Adapter;
let installCommand = undefined;
let buildCommand = undefined;
let outputDirectory = undefined;
- let frameworkKey = site.framework;
+ let fallback = site.fallbackFile;
let isButtonDisabled = true;
+ let showFallback = site.adapter === Adapter.Static;
onMount(async () => {
- selectedFramework ??= frameworks.find((framework) => framework.key === site.framework);
-
installCommand =
site?.installCommand ?? selectedFramework.adapters[site.adapter].defaultInstallCommand;
buildCommand =
@@ -43,8 +51,8 @@
buildCommand || undefined,
outputDirectory || undefined,
(site?.buildRuntime as BuildRuntime) || undefined,
- site.adapter,
- site.fallbackFile || undefined,
+ adapter || undefined,
+ fallback || undefined,
site.installationId || undefined,
site.providerRepositoryId || undefined,
site.providerBranch || undefined,
@@ -66,17 +74,43 @@
}
}
- $: frameworkData = frameworks.find((framework) => framework.key === framework.key);
$: if (
installCommand === site?.installCommand &&
buildCommand === site?.buildCommand &&
outputDirectory === site?.outputDirectory &&
- selectedFramework?.key === site?.framework
+ selectedFramework?.key === site?.framework &&
+ fallback === site?.fallbackFile &&
+ adapter === site?.adapter
) {
isButtonDisabled = true;
} else {
isButtonDisabled = false;
}
+
+ $: if (adapter === Adapter.Static) {
+ showFallback = true;
+ fallback ||= selectedFramework.adapters.static.fallbackFile;
+ console.log(fallback, selectedFramework.adapters.static);
+ } else {
+ showFallback = false;
+ fallback = undefined;
+ }
+
+ $: if (fallback === '') {
+ fallback = null;
+ }
+
+ $: frameworkDataAdapter = selectedFramework.adapters?.length
+ ? selectedFramework.adapters[site.adapter]
+ : frameworks[0].adapters[site.adapter];
+
+ //TODO: fix after backend type is fixed
+ $: if (selectedFramework?.adapters?.length <= 1 || !selectedFramework?.adapters?.ssr?.key) {
+ adapter = Adapter.Static;
+ }
+ $: if (selectedFramework?.adapters?.length <= 1 || !selectedFramework?.adapters?.static?.key) {
+ adapter = Adapter.Ssr;
+ }
@@ -85,44 +119,153 @@
Default build settings are configured based on your framework, ensuring optimal performance.
Adjust the settings here if needed.
- ({
- value: framework.key,
- label: framework.name
- }))}
- on:change={() => {
- selectedFramework = frameworks.find(
- (framework) => framework.key === frameworkKey
- );
- }} />
+ {@const adapterData = adapterDataList.find(
+ (adapterData) => adapterData.framework === frameworkKey.toLowerCase()
+ )}
+
+ ({
+ value: framework.key,
+ label: framework.name,
+ leadingHtml: ` `
+ }))}
+ on:change={() => {
+ selectedFramework = frameworks.find(
+ (framework) => framework.key === frameworkKey
+ );
+ }} />
+ {#if selectedFramework.adapters?.length || (selectedFramework.adapters?.ssr?.key && selectedFramework.adapters?.static?.key)}
+
+
+ {#if adapterData?.ssr?.desc?.includes('$')}
+ {@const parts = adapterData.ssr.desc.split('$')}
+ {#each parts as part, i}
+ {#if i === 0}
+ {part}
+ {:else}
+
+ {part}
+ {/if}
+ {/each}
+ {:else}
+ {adapterData.ssr.desc}
+ {/if}
+ {#if adapterData.ssr.url}
+ Learn more
+ {/if}
+
+
+ {#if adapterData.static.desc.includes('$')}
+ {@const parts = adapterData.static.desc.split('$')}
+ {#each parts as part, i}
+ {#if i === 0}
+ {part}
+ {:else}
+
+ {part}
+ {/if}
+ {/each}
+ {:else}
+ {adapterData.static.desc}
+ {/if}
+ {#if adapterData.static.url}
+ Learn more
+ {/if}
+
+
+ {/if}
+
+
+
+
-
-
- (installCommand = '')}>Reset
-
-
-
- (buildCommand = '')}>Reset
-
-
-
- (outputDirectory = '')}>Reset
+
+ (installCommand =
+ site?.installCommand ??
+ selectedFramework.adapters[site.adapter]
+ ?.defaultInstallCommand)}>
+ Reset
+
+
+
+
+
+ (buildCommand =
+ site?.buildCommand ??
+ selectedFramework.adapters[site.adapter]
+ ?.defaultBuildCommand)}>
+ Reset
+
+
+
+
+
+ (outputDirectory =
+ site?.outputDirectory ??
+ selectedFramework.adapters[site.adapter]
+ ?.defaultOutputDirectory)}>
+ Reset
+
+
+ {#if showFallback}
+
+
+
+
+ Provide a fallback file for advanced routing and proper page
+ handling in SPA mode.
+
+
+
+ {/if}
+
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateName.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateName.svelte
index 3b8290775..ab832d922 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateName.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateName.svelte
@@ -7,7 +7,7 @@
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
- import { BuildRuntime, Framework, type Models } from '@appwrite.io/console';
+ import { Adapter, BuildRuntime, Framework, type Models } from '@appwrite.io/console';
export let site: Models.Site;
let siteName: string = null;
@@ -28,7 +28,7 @@
site.buildCommand || undefined,
site.outputDirectory || undefined,
(site?.buildRuntime as BuildRuntime) || undefined,
- site.adapter,
+ site.adapter as Adapter,
site.fallbackFile || undefined,
site.installationId || undefined,
site.providerRepositoryId || undefined,
@@ -60,7 +60,7 @@
id="name"
label="Name"
placeholder="Enter name"
- autocomplete={false}
+ required
bind:value={siteName} />
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateRepository.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateRepository.svelte
index c34c73434..be324205e 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateRepository.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateRepository.svelte
@@ -6,7 +6,7 @@
import { Button, Form, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
- import { BuildRuntime, Framework, type Models } from '@appwrite.io/console';
+ import { Adapter, BuildRuntime, Framework, type Models } from '@appwrite.io/console';
import { toLocaleDateTime } from '$lib/helpers/date';
import { onMount } from 'svelte';
import DisconnectRepo from './disconnectRepo.svelte';
@@ -75,7 +75,7 @@
site.buildCommand || undefined,
site.outputDirectory || undefined,
(site?.buildRuntime as BuildRuntime) || undefined,
- site.adapter,
+ site.adapter as Adapter,
site.fallbackFile || undefined,
site.installationId || undefined,
site.providerRepositoryId || undefined,
@@ -116,7 +116,7 @@
-
+
Git repository
Automatically deploy changes for every commit pushed to your Git repository.
@@ -142,16 +142,16 @@
-
+
-
+
-
-
+
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateResourceLimits.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateResourceLimits.svelte
new file mode 100644
index 000000000..8f9cc8285
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateResourceLimits.svelte
@@ -0,0 +1,94 @@
+
+
+
+
+ Resource limits
+ Define your sites's compute specifications, including CPU and memory, to optimize performance
+ for your workloads.
+ Learn more
+ .
+
+
+ {#if isCloud && $organization.billingPlan === BillingPlan.FREE}
+
+ Upgrade to Pro or Scale to adjust your CPU and RAM beyond the default.
+
+ Upgrade
+
+
+ {/if}
+
+
+
+ Update
+
+
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateRuntimeSettings.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateRuntimeSettings.svelte
index 3beaaeae3..88fde4c1c 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateRuntimeSettings.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateRuntimeSettings.svelte
@@ -4,10 +4,12 @@
import { CardGrid } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Button, Form, InputSelect } from '$lib/elements/forms';
+ import { capitalize } from '$lib/helpers/string';
+ import { iconPath } from '$lib/stores/app';
import { addNotification } from '$lib/stores/notifications';
+ import { getIconFromRuntime } from '$lib/stores/runtimes';
import { sdk } from '$lib/stores/sdk';
- import { onMount } from 'svelte';
- import { BuildRuntime, Framework, type Models } from '@appwrite.io/console';
+ import { Adapter, BuildRuntime, Framework, type Models } from '@appwrite.io/console';
export let site: Models.Site;
export let frameworks: Models.Framework[];
@@ -15,13 +17,11 @@
let buildRuntime = site?.buildRuntime;
let buildRuntimeOptions = framework.runtimes.map((runtime) => ({
- label: runtime,
- value: runtime
+ label: capitalize(runtime),
+ value: runtime,
+ leadingHtml: ` `
}));
- onMount(async () => {
- buildRuntime ??= framework.buildRuntime;
- });
async function updateRuntime() {
try {
await sdk.forProject.sites.update(
@@ -34,7 +34,7 @@
site.buildCommand || undefined,
site.outputDirectory || undefined,
(buildRuntime as BuildRuntime) || undefined,
- site.adapter,
+ site.adapter as Adapter,
site.fallbackFile || undefined,
site.installationId || undefined,
site.providerRepositoryId || undefined,
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateSPA.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateSPA.svelte
deleted file mode 100644
index 08e004207..000000000
--- a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateSPA.svelte
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
- Single page application
- Provide a fallback file for advanced routing and proper page handling in SPA mode.
-
- {
- if (value.detail) {
- fallback = '';
- } else {
- fallback = null;
- }
- }} />
-
- {#if fallback !== null}
-
- {/if}
-
-
-
- Update
-
-
-
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/store.ts b/src/routes/(console)/project-[project]/sites/site-[site]/store.ts
index 25680aede..c761e1733 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/store.ts
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/store.ts
@@ -3,17 +3,3 @@ import type { Models } from '@appwrite.io/console';
import { derived } from 'svelte/store';
export const site = derived(page, ($page) => $page.data.site as Models.Site);
-
-export function deploymentStatusConverter(status: string) {
- // Status component possible values - status: 'waiting' | 'ready' | 'processing' | 'pending' | 'failed' | 'complete';
- switch (status) {
- case 'ready':
- return 'ready';
- case 'processing':
- return 'processing';
- case 'building':
- return 'pending';
- case 'failed':
- return 'failed';
- }
-}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/usage/[[period]]/+page.svelte
new file mode 100644
index 000000000..ace13c9dc
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/usage/[[period]]/+page.svelte
@@ -0,0 +1,34 @@
+
+
+
+
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/usage/[[period]]/+page.ts b/src/routes/(console)/project-[project]/sites/site-[site]/usage/[[period]]/+page.ts
new file mode 100644
index 000000000..c8b57fc02
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/usage/[[period]]/+page.ts
@@ -0,0 +1,16 @@
+import { isValueOfStringEnum } from '$lib/helpers/types';
+import { sdk } from '$lib/stores/sdk';
+import { SiteUsageRange } from '@appwrite.io/console';
+import type { PageLoad } from './$types';
+import { error } from '@sveltejs/kit';
+
+export const load: PageLoad = async ({ params }) => {
+ const period = isValueOfStringEnum(SiteUsageRange, params.period)
+ ? params.period
+ : SiteUsageRange.ThirtyDays;
+ try {
+ return sdk.forProject.sites.getUsage(params.site, period);
+ } catch (e) {
+ error(e.code, e.message);
+ }
+};
diff --git a/src/routes/(console)/project-[project]/sites/store.ts b/src/routes/(console)/project-[project]/sites/store.ts
index 3e71bbde6..0ac684677 100644
--- a/src/routes/(console)/project-[project]/sites/store.ts
+++ b/src/routes/(console)/project-[project]/sites/store.ts
@@ -36,6 +36,10 @@ export function getFrameworkIcon(framework: string) {
return 'remix';
case framework.toLocaleLowerCase().includes('flutter'):
return 'flutter';
+ case framework.toLocaleLowerCase().includes('analog'):
+ return 'analog';
+ case framework.toLocaleLowerCase().includes('vite'):
+ return 'vite';
case framework.toLocaleLowerCase().includes('other'):
return 'empty';
diff --git a/src/routes/(console)/project-[project]/sites/table.svelte b/src/routes/(console)/project-[project]/sites/table.svelte
index 3dc3da7c3..b40536e92 100644
--- a/src/routes/(console)/project-[project]/sites/table.svelte
+++ b/src/routes/(console)/project-[project]/sites/table.svelte
@@ -3,10 +3,11 @@
import { page } from '$app/stores';
import { toLocaleDateTime } from '$lib/helpers/date';
import { Avatar, Layout, Table } from '@appwrite.io/pink-svelte';
- import { columns } from './store';
+ import { columns, getFrameworkIcon } from './store';
import type { Models } from '@appwrite.io/console';
import SitesActionMenu from './sitesActionMenu.svelte';
import AddCollaboratorModal from './(components)/addCollaboratorModal.svelte';
+ import { SvgIcon } from '$lib/components';
export let siteList: Models.SiteList;
@@ -31,9 +32,12 @@
{#if column.show}
{#if column.id === 'name'}
-
-
+
+
+
{site.name}
diff --git a/src/routes/(console)/project-[project]/sites/usage/+page.svelte b/src/routes/(console)/project-[project]/sites/usage/+page.svelte
deleted file mode 100644
index fbbc96e0d..000000000
--- a/src/routes/(console)/project-[project]/sites/usage/+page.svelte
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-Coming soon
diff --git a/src/routes/(console)/project-[project]/sites/usage/+page.ts b/src/routes/(console)/project-[project]/sites/usage/+page.ts
deleted file mode 100644
index 349bf84de..000000000
--- a/src/routes/(console)/project-[project]/sites/usage/+page.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { sdk } from '$lib/stores/sdk';
-import { Dependencies } from '$lib/constants';
-
-export const load = async ({ depends }) => {
- depends(Dependencies.SITES);
-
- const usage = await sdk.forProject.sites.listUsage();
-
- return {
- usage
- };
-};
diff --git a/src/routes/(console)/project-[project]/sites/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[project]/sites/usage/[[period]]/+page.svelte
new file mode 100644
index 000000000..203a915da
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/usage/[[period]]/+page.svelte
@@ -0,0 +1,21 @@
+
+
+
diff --git a/src/routes/(console)/project-[project]/sites/usage/[[period]]/+page.ts b/src/routes/(console)/project-[project]/sites/usage/[[period]]/+page.ts
new file mode 100644
index 000000000..01f745f99
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/usage/[[period]]/+page.ts
@@ -0,0 +1,16 @@
+import { isValueOfStringEnum } from '$lib/helpers/types';
+import { sdk } from '$lib/stores/sdk';
+import { SiteUsageRange } from '@appwrite.io/console';
+import type { PageLoad } from './$types';
+import { error } from '@sveltejs/kit';
+
+export const load: PageLoad = async ({ params }) => {
+ const period = isValueOfStringEnum(SiteUsageRange, params.period)
+ ? params.period
+ : SiteUsageRange.ThirtyDays;
+ try {
+ return sdk.forProject.sites.listUsage(period);
+ } catch (e) {
+ error(e.code, e.message);
+ }
+};
diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/+layout.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/+layout.svelte
index 2dba92726..f6bb5c944 100644
--- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/+layout.svelte
+++ b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/+layout.svelte
@@ -19,9 +19,8 @@
label: 'Create file',
async callback() {
if (!$page.url.pathname.endsWith($bucket.$id)) {
- goto(`${base}/project-${$project.$id}/storage/bucket-${$bucket.$id}`);
+ goto(`${base}/project-${$project.$id}/storage/bucket-${$bucket.$id}/create`);
}
- showCreateFile();
},
keys: $page.url.pathname.endsWith($bucket.$id) ? ['c'] : ['c', 'f'],
group: 'files',
diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/+page.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/+page.svelte
index 4e73d81de..bd96b0a7c 100644
--- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/+page.svelte
+++ b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/+page.svelte
@@ -9,40 +9,27 @@
import { base } from '$app/paths';
import { page } from '$app/stores';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
- import {
- Avatar,
- DropList,
- DropListItem,
- DropListLink,
- Empty,
- EmptySearch,
- PaginationWithLimit,
- SearchQuery
- } from '$lib/components';
+ import { Avatar, Empty, EmptySearch, PaginationWithLimit, SearchQuery } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Pill } from '$lib/elements';
import { Button } from '$lib/elements/forms';
- import { toLocaleDate } from '$lib/helpers/date';
- import {
- bytesToSize,
- calculateSize,
- humanFileSize,
- sizeToBytes
- } from '$lib/helpers/sizeConvertion';
+ import { calculateSize } from '$lib/helpers/sizeConvertion';
import { Container } from '$lib/layout';
import type { Models } from '@appwrite.io/console';
import { addNotification } from '$lib/stores/notifications';
import { uploader } from '$lib/stores/uploader';
import { wizard } from '$lib/stores/wizard';
- import { getServiceLimit } from '$lib/stores/billing';
import { sdk } from '$lib/stores/sdk.js';
- import Create from './create-file/create.svelte';
import DeleteFile from './deleteFile.svelte';
- import { isCloud } from '$lib/system';
- import { Layout, Table, Icon } from '@appwrite.io/pink-svelte';
+ import { Layout, Table, Icon, Popover, ActionMenu } from '@appwrite.io/pink-svelte';
import { onMount } from 'svelte';
- import { IconPlus } from '@appwrite.io/pink-icons-svelte';
import DualTimeView from '$lib/components/dualTimeView.svelte';
+ import {
+ IconDotsHorizontal,
+ IconPencil,
+ IconPlus,
+ IconTrash
+ } from '@appwrite.io/pink-icons-svelte';
export let data;
@@ -52,12 +39,13 @@
const projectId = $page.params.project;
const bucketId = $page.params.bucket;
- const usedStorage =
- isCloud && data?.organizationUsage?.storageTotal
- ? bytesToSize(data.organizationUsage.storageTotal, 'GB')
- : null;
- const getPreview = (fileId: string) =>
- sdk.forProject.storage.getFilePreview(bucketId, fileId, 64, 64).toString() + '&mode=admin';
+
+ function getPreview(fileId: string) {
+ return (
+ sdk.forProject.storage.getFilePreview(bucketId, fileId, 128, 128).toString() +
+ '&mode=admin'
+ );
+ }
async function fileDeleted(event: CustomEvent) {
showDelete = false;
@@ -80,10 +68,6 @@
}
}
- $: maxFileSize = isCloud
- ? humanFileSize(sizeToBytes(getServiceLimit('fileSize'), 'MB', 1000))
- : null;
-
let isUploading = false;
const beforeunload = (event: BeforeUnloadEvent) => {
@@ -114,7 +98,10 @@
- wizard.start(Create)} event="create_file" size="s">
+
Create file
@@ -163,11 +150,11 @@
{:else}
-
+ {@const href = `${base}/project-${projectId}/storage/bucket-${bucketId}/file-${file.$id}`}
+
@@ -179,34 +166,24 @@
-
- {
- showDropdown[index] = !showDropdown[index];
- }}>
-
-
-
-
+
+
+
+
+
+ Update
+
+ {
- showDropdown[index] = false;
- }}
- href={`${base}/project-${projectId}/storage/bucket-${bucketId}/file-${file.$id}`}
- icon="pencil">Update
- {
- showDropdown[index] = false;
selectedFile = file;
showDelete = true;
- }}>Delete
-
-
+ }}>
+ Delete
+
+
+
{/if}
@@ -243,7 +220,7 @@
single
href="https://appwrite.io/docs/products/storage/upload-download"
target="file"
- on:click={() => wizard.start(Create)} />
+ on:click={() => void 0} />
{/if}
diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create-file/create.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create-file/create.svelte
deleted file mode 100644
index 2def560a1..000000000
--- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create-file/create.svelte
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create-file/step1.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create-file/step1.svelte
deleted file mode 100644
index 137a69381..000000000
--- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create-file/step1.svelte
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
- File
- Upload a file to add it to your bucket.
-
- {#if isCloud && fileError === 'File size exceeds the limit'}
- {@const size = humanFileSize($bucket.maximumFileSize ?? sizeToBytes(service, 'MB', 1000))}
-
-
- The maximum file upload size for this bucket is {parseInt(size.value)}{size.unit}.
- You can adjust it in your
- bucket settings .
-
-
- {/if}
-
-
-
-
-
-
- {#if !showCustomId}
-
-
(showCustomId = !showCustomId)}>
-
- File ID
-
-
-
- {:else}
-
-
-
- {/if}
-
-
-
-
diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create-file/step2.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create-file/step2.svelte
deleted file mode 100644
index 58363e57d..000000000
--- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create-file/step2.svelte
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
- Permissions
-
- Choose who can access your buckets and files. For more information, check out the
-
- Permissions Guide
- .
-
- {#if $bucket.fileSecurity}
-
-
- File security enabled
- Users will be able to access this file if they have been granted
- either File or Bucket permissions .
-
-
-
- {:else}
-
- File security disabled
- If you want to assign file permissions, navigate to Bucket settings and enable file security.
- Otherwise, only Bucket permissions will be used.
-
- {/if}
-
diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create-file/store.ts b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create-file/store.ts
deleted file mode 100644
index 6a6eb9248..000000000
--- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create-file/store.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { writable } from 'svelte/store';
-
-type CreateFile = {
- files: FileList | null;
- id: string | null;
- permissions: string[];
-};
-
-const initialState: CreateFile = {
- files: null,
- id: null,
- permissions: []
-};
-
-export const createFile = (function initialize() {
- const store = writable({ ...initialState });
-
- return {
- ...store,
- reset() {
- store.set({ ...initialState });
- }
- };
-})();
diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create/+page.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create/+page.svelte
new file mode 100644
index 000000000..e02d3f6ac
--- /dev/null
+++ b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/create/+page.svelte
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+ {#if isCloud && fileError === 'File size exceeds the limit'}
+ {@const size = humanFileSize(
+ data.bucket.maximumFileSize ?? sizeToBytes(service, 'MB', 1000)
+ )}
+
+ The maximum file upload size for this bucket is {parseInt(
+ size.value
+ )}{size.unit}. You can adjust it in your
+ bucket settings .
+
+ {/if}
+
+ Drag and drop files here or click to upload
+
+ {#if files}
+ {
+ return {
+ name: b.name,
+ size: b.size,
+ extension: b.type,
+ removable: true
+ };
+ })}
+ on:remove={(e) => (files = removeFile(e.detail, files))} />
+ {/if}
+
+ {#if !showCustomId}
+
+ (showCustomId = !showCustomId)}>
+
+ File ID
+
+
+ {:else}
+
+ {/if}
+
+
+
+
+
+
+ Choose who can access your buckets and files. For more information, check
+ out the
+
+ Permissions Guide
+ .
+
+
+ {#if data.bucket.fileSecurity}
+
+ Users will be able to access this file if they have been granted
+ either File or Bucket permissions .
+
+
+ {:else}
+
+ If you want to assign file permissions, navigate to Bucket settings and
+ enable file security. Otherwise, only Bucket permissions will be used.
+
+ {/if}
+
+
+
+
+
+
+ (showExitModal = true)}>Cancel
+ formComponent.triggerSubmit()}
+ disabled={$isSubmitting}>
+ Create
+
+
+
diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/deleteBucket.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/deleteBucket.svelte
index dca9009da..84d831f15 100644
--- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/deleteBucket.svelte
+++ b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/deleteBucket.svelte
@@ -6,6 +6,7 @@
import Confirm from '$lib/components/confirm.svelte';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
+ import { Typography } from '@appwrite.io/pink-svelte';
import { bucket } from './store';
export let showDelete = false;
@@ -28,5 +29,7 @@
- Are you sure you want to delete {$bucket.name} ?
+
+ Are you sure you want to delete {$bucket.name} ?
+
diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/+page.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/+page.svelte
index a758661b4..be981de52 100644
--- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/+page.svelte
+++ b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/+page.svelte
@@ -1,5 +1,5 @@
- Are you sure you want to delete {$file.name} ?
+
+ Are you sure you want to delete {$file.name} ?
+
diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/settings/+page.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/settings/+page.svelte
index 6c6733d8d..1c716237f 100644
--- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/settings/+page.svelte
+++ b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/settings/+page.svelte
@@ -10,9 +10,12 @@
let arePermsDisabled = writable(true);
- export async function updateBucket(updates: Partial, misc: TUpdateBucketMisc) {
- const bucketData = get(bucket);
- const values = { ...bucketData, ...updates };
+ export async function updateBucket(
+ bucket: Models.Bucket,
+ updates: Partial,
+ misc: TUpdateBucketMisc
+ ) {
+ const values = { ...bucket, ...updates };
if (!isValueOfStringEnum(Compression, values.compression)) {
throw new Error(`Invalid compression: ${values.compression}`);
@@ -39,7 +42,7 @@
}
addNotification({
- message: misc.successMessage ?? `${bucketData.name} has been updated`,
+ message: misc.successMessage ?? `${bucket.name} has been updated`,
type: 'success'
});
@@ -65,8 +68,6 @@
import {
Button,
Form,
- FormList,
- InputChoice,
InputSelect,
InputSwitch,
InputTags,
@@ -78,27 +79,30 @@
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { Compression, type Models } from '@appwrite.io/console';
- import { onMount } from 'svelte';
- import { get, writable } from 'svelte/store';
+ import { writable } from 'svelte/store';
import Delete from '../deleteBucket.svelte';
- import { bucket } from '../store';
import UpdateMaxFileSize from './updateMaxFileSize.svelte';
import { readOnly } from '$lib/stores/billing';
import { GRACE_PERIOD_OVERRIDE } from '$lib/system';
import { isValueOfStringEnum } from '$lib/helpers/types';
import type { PageData } from './$types';
+ import { Icon, Layout, Link, Selector, Tag, Typography } from '@appwrite.io/pink-svelte';
+ import { IconPlus } from '@appwrite.io/pink-icons-svelte';
+ import { Click } from '$lib/actions/analytics';
export let data: PageData;
let showDelete = false;
- let enabled: boolean = null;
- let bucketName: string = null;
- let bucketFileSecurity: boolean = null;
- let bucketPermissions: string[] = null;
- let encryption: boolean = null;
- let antivirus: boolean = null;
- let compression: string = null;
+ let {
+ enabled,
+ name,
+ fileSecurity,
+ $permissions: permissions,
+ encryption,
+ antivirus,
+ compression
+ } = data.bucket;
const compressionOptions = [
{ label: 'None', value: 'none' },
@@ -106,35 +110,24 @@
{ label: 'Zstd', value: 'zstd' }
];
let suggestedExtensions = ['jpg', 'png', 'svg', 'gif', 'html', 'pdf', 'mp4'];
- let extensions = $bucket.allowedFileExtensions;
+ let extensions = data.bucket.allowedFileExtensions;
let isExtensionsDisabled = true;
- onMount(async () => {
- enabled ??= $bucket.enabled;
- bucketName ??= $bucket.name;
- bucketName ??= $bucket.name;
- bucketFileSecurity ??= $bucket.fileSecurity;
- bucketPermissions ??= $bucket.$permissions;
- encryption ??= $bucket.encryption;
- antivirus ??= $bucket.antivirus;
-
- compression ??= $bucket.compression;
- });
-
- $: if (bucketPermissions) {
- if (symmetricDifference(bucketPermissions, $bucket.$permissions).length) {
+ $: if (permissions) {
+ if (symmetricDifference(permissions, data.bucket.$permissions).length) {
$arePermsDisabled = false;
} else $arePermsDisabled = true;
}
$: if (extensions) {
- if (JSON.stringify(extensions) !== JSON.stringify($bucket.allowedFileExtensions)) {
+ if (JSON.stringify(extensions) !== JSON.stringify(data.bucket.allowedFileExtensions)) {
isExtensionsDisabled = false;
} else isExtensionsDisabled = true;
}
function toggleBucket() {
updateBucket(
+ data.bucket,
{
enabled
},
@@ -149,8 +142,9 @@
function updateName() {
updateBucket(
+ data.bucket,
{
- name: bucketName
+ name
},
{
successMessage: 'Name has been updated',
@@ -161,8 +155,9 @@
function updatePermissions() {
updateBucket(
+ data.bucket,
{
- $permissions: bucketPermissions
+ $permissions: permissions
},
{
successMessage: 'Permissions have been updated',
@@ -174,8 +169,9 @@
function updateFileSecurity() {
updateBucket(
+ data.bucket,
{
- fileSecurity: bucketFileSecurity
+ fileSecurity
},
{
successMessage: 'Security has been updated',
@@ -187,6 +183,7 @@
function updateSecurity() {
updateBucket(
+ data.bucket,
{
encryption,
antivirus
@@ -199,6 +196,7 @@
function updateCompression() {
updateBucket(
+ data.bucket,
{
compression
},
@@ -210,6 +208,7 @@
function updateAllowedExtensions() {
updateBucket(
+ data.bucket,
{
allowedFileExtensions: extensions
},
@@ -221,231 +220,217 @@
- {#if $bucket}
-
-
- {$bucket.name}
-
-
-
-
-
-
Created: {toLocaleDateTime($bucket.$createdAt)}
-
Last updated: {toLocaleDateTime($bucket.$updatedAt)}
-
-
-
-
-
- Update
-
-
-
-
-
-
-
- Name
-
-
-
-
-
-
-
-
- Update
-
-
-
-
-
-
-
- Permissions
- Choose who can access your buckets and files. For more information, visit our
-
- Permissions guide
- .
-
- {#if bucketPermissions}
-
- {/if}
-
-
- Update
-
-
-
-
-
-
- File security
-
-
-
-
-
- When file security is enabled, users will be able to access files for which
- they have been granted either File or Bucket permissions .
-
-
- If file security is disabled, users can access files only if they have Bucket permissions . File permissions will be ignored..
-
-
-
-
- Update
-
-
-
-
-
-
-
- Security settings
- Enable or disable security services for the bucket including Ecryption
- and Antivirus scanning.
-
-
-
- This parameter allows you to configure whether or not the files inside
- the bucket will be encrypted. We don't encrypt files bigger than 20MB.
-
-
- This parameter allows you to configure whether or not the files inside
- the bucket should be scanned by the Appwrite Antivirus scanner.
-
-
-
-
-
-
- Update
-
-
-
-
-
-
-
- Compression
- Choose an algorithm for compression. For files larger than 20MB, compression will be
- skipped even if it's enabled.
-
-
-
-
-
-
-
- Update
-
-
-
-
-
-
-
-
- Allowed file extension
- Allowed file extensions. A maximum of 100 file extensions can be added. Leave blank to
- allow all file types.
-
-
-
-
- {#each suggestedExtensions as ext}
- {
- if (!extensions.includes(ext)) {
- extensions = [...extensions, ext];
- } else {
- extensions = extensions.filter((e) => e !== ext);
- }
- }}>
-
- {ext}
-
- {/each}
-
-
-
-
-
- Update
-
-
-
-
+
- Delete bucket
- The bucket will be permanently deleted, including all the files within it. This action is
- irreversible.
+ {data.bucket.name}
-
-
- {$bucket.name}
-
- Last updated: {toLocaleDateTime($bucket.$updatedAt)}
-
+
+
+
Created: {toLocaleDateTime(data.bucket.$createdAt)}
+
Last updated: {toLocaleDateTime(data.bucket.$updatedAt)}
+
- (showDelete = true)}>Delete
+
+ Update
+
- {/if}
+
+
+
+
+ Name
+
+
+
+
+
+
+ Update
+
+
+
+
+
+
+
+ Permissions
+ Choose who can access your buckets and files. For more information, visit our
+
+ Permissions guide
+ .
+
+ {#if permissions}
+
+ {/if}
+
+
+ Update
+
+
+
+
+
+
+ File security
+
+
+
+ When file security is enabled, users will be able to access files for which they
+ have been granted either File or Bucket permissions .
+
+
+ If file security is disabled, users can access files only if they have Bucket permissions . File permissions will be ignored..
+
+
+
+
+ Update
+
+
+
+
+
+
+
+ Security settings
+ Enable or disable security services for the bucket including Ecryption
+ and Antivirus scanning.
+
+
+
+
+
+
+
+ Update
+
+
+
+
+
+
+
+ Compression
+ Choose an algorithm for compression. For files larger than 20MB, compression will be skipped
+ even if it's enabled.
+
+
+
+
+
+ Update
+
+
+
+
+
+
+
+
+ Allowed file extension
+ Allowed file extensions. A maximum of 100 file extensions can be added. Leave blank to allow
+ all file types.
+
+
+
+
+ {#each suggestedExtensions as ext}
+ {
+ if (!extensions.includes(ext)) {
+ extensions = [...extensions, ext];
+ } else {
+ extensions = extensions.filter((e) => e !== ext);
+ }
+ }}>
+
+ {ext}
+
+ {/each}
+
+
+
+
+
+ Update
+
+
+
+
+
+ Delete bucket
+ The bucket will be permanently deleted, including all the files within it. This action is irreversible.
+
+
+
+ {data.bucket.name}
+
+ Last updated: {toLocaleDateTime(data.bucket.$updatedAt)}
+
+
+
+
+ {
+ showDelete = true;
+ trackEvent(Click.StorageBucketDeleteClick);
+ }}>Delete
+
+
diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte
index c5b32d225..3cc163434 100644
--- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte
+++ b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte
@@ -1,5 +1,5 @@
-
-
+
- {#if !showCustomId}
-
-
(showCustomId = !showCustomId)}>
-
- Bucket ID
-
-
- {:else}
-
- {/if}
-
+ {#if !showCustomId}
+
+ {
+ showCustomId = true;
+ }}> Bucket ID
+
+ {:else}
+
+ {/if}
(showCreate = false)}>Cancel
Create
diff --git a/src/routes/(console)/project-[project]/storage/grid.svelte b/src/routes/(console)/project-[project]/storage/grid.svelte
index 1714c61c9..4ff674aeb 100644
--- a/src/routes/(console)/project-[project]/storage/grid.svelte
+++ b/src/routes/(console)/project-[project]/storage/grid.svelte
@@ -4,7 +4,7 @@
import { CardContainer, GridItem1, Id } from '$lib/components';
import Pill from '$lib/elements/pill.svelte';
import { canWriteBuckets } from '$lib/stores/roles';
- import { Tooltip } from '@appwrite.io/pink-svelte';
+ import { Badge, Tooltip } from '@appwrite.io/pink-svelte';
import type { PageData } from './$types';
export let data: PageData;
@@ -25,35 +25,24 @@
{bucket.name}
{#if !bucket.enabled}
- Disabled
+
+
+
{/if}
{bucket.$id}
-
-
-
- {bucket.encryption
- ? 'Encryption enabled'
- : 'Encryption disabled'}
-
-
-
-
-
- {bucket.antivirus ? 'Antivirus enabled' : 'Antivirus disabled'}
-
-
+
+
+
+ {bucket.encryption ? 'Encryption enabled' : 'Encryption disabled'}
+
+
{/each}
diff --git a/src/routes/(console)/project-[project]/updateVariables.svelte b/src/routes/(console)/project-[project]/updateVariables.svelte
index 0b517612b..dc760d7f1 100644
--- a/src/routes/(console)/project-[project]/updateVariables.svelte
+++ b/src/routes/(console)/project-[project]/updateVariables.svelte
@@ -4,14 +4,13 @@
import { Button } from '$lib/elements/forms';
import { CardGrid, Empty, Output, PaginationInline } from '$lib/components';
import UploadVariables from './uploadVariablesModal.svelte';
- import { invalidate } from '$app/navigation';
- import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
+ import { goto, invalidate } from '$app/navigation';
+ import { Click, Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { Dependencies } from '$lib/constants';
import { addNotification } from '$lib/stores/notifications';
import { project } from '$routes/(console)/project-[project]/store';
- import Alert from '$lib/components/alert.svelte';
import PromoteVariableModal from './promoteVariableModal.svelte';
- import CreateVariable from './createVariable.svelte';
+ import CreateVariable from './createVariableModal.svelte';
import RawVariableEditor from './rawVariableEditor.svelte';
import { base } from '$app/paths';
import {
@@ -21,11 +20,13 @@
Icon,
Layout,
Popover,
- Table
+ Table,
+ Alert
} from '@appwrite.io/pink-svelte';
import {
IconCode,
IconDotsHorizontal,
+ IconEyeOff,
IconGlobeAlt,
IconPencil,
IconPlus,
@@ -34,10 +35,13 @@
} from '@appwrite.io/pink-icons-svelte';
import Link from '$lib/elements/link.svelte';
import Copy from '$lib/components/copy.svelte';
+ import { page } from '$app/stores';
+ import UpdateVariablesModal from './updateVariablesModal.svelte';
+ import SecretVariableModal from './secretVariableModal.svelte';
export let variableList: Models.VariableList;
export let globalVariableList: Models.VariableList | undefined = undefined;
-
+ export let analyticsSource = '';
export let isGlobal: boolean;
export let sdkCreateVariable: (
key: string,
@@ -53,20 +57,24 @@
export let sdkDeleteVariable: (variableId: string) => Promise;
export let product: 'function' | 'site' = 'function';
- let showVariablesDropdown = [];
let selectedVar: Models.Variable = null;
let showVariablesUpload = false;
let showVariablesModal = false;
let showPromoteModal = false;
let showEditorModal = false;
+ let showUpdate = false;
+ let showSecretModal = false;
let offset = 0;
const limit = 10;
- async function handleVariableCreated(event: CustomEvent) {
- const variable = event.detail;
+ async function handleVariableCreated(event: CustomEvent) {
+ const variables = event.detail;
+ console.log(variables);
try {
- await sdkCreateVariable(variable.key, variable.value, variable.secret);
- selectedVar = null;
+ const promises = variables.map((variable) =>
+ sdkCreateVariable(variable.key, variable.value, variable?.secret || false)
+ );
+ await Promise.all(promises);
showVariablesModal = false;
addNotification({
type: 'success',
@@ -105,6 +113,28 @@
trackError(error, Submit.VariableUpdate);
}
}
+ async function handleVariableSecret(event: CustomEvent) {
+ const variable = event.detail;
+ console.log(variable);
+ try {
+ await sdkUpdateVariable(variable.$id, variable.key, variable.value, variable.secret);
+ selectedVar = null;
+ showVariablesModal = false;
+ addNotification({
+ type: 'success',
+ message: `${$project.name} ${
+ isGlobal ? 'global variable' : 'variable'
+ } has been marked as secret.`
+ });
+ trackEvent(Submit.VariableUpdate);
+ } catch (error) {
+ addNotification({
+ type: 'error',
+ message: error.message
+ });
+ trackError(error, Submit.VariableUpdate);
+ }
+ }
async function handleVariableDeleted(variable: Models.Variable) {
try {
@@ -177,7 +207,13 @@
addNotification({
type: 'success',
- message: `Variable has been ${isConflicting ? 'overwritten' : 'promoted'}.`
+ message: `Variable has been ${isConflicting ? 'overwritten' : 'promoted'}. You can find it in the project settings.`,
+ buttons: [
+ {
+ method: () => goto(`${base}/project-${$page.params.project}/settings`),
+ name: 'Go to settings'
+ }
+ ]
});
trackEvent(Submit.VariableDelete);
} catch (error) {
@@ -222,15 +258,30 @@
- (showEditorModal = true)}>
+ {
+ showEditorModal = true;
+ trackEvent(Click.VariablesUpdateClick, { source: analyticsSource });
+ }}>
Editor
- (showVariablesUpload = true)}>
+ {
+ showEditorModal = true;
+ trackEvent(Click.VariablesUpdateClick, { source: analyticsSource });
+ }}>
Import .env
{#if variableList.total}
- (showVariablesModal = true)}>
+ {
+ showVariablesModal = true;
+ trackEvent(Click.VariablesCreateClick, { source: 'project_settings' });
+ }}>
Create variable
{/if}
@@ -240,7 +291,7 @@
{#if sum}
{#if conflictVariables.length > 0}
-
+
{#if conflictVariables.length === 1}
{conflictVariables[0].key} has
@@ -255,15 +306,15 @@
project settings.
-
+
{/if}
- Key
+ Key
Value
- {#each variableList.variables.slice(offset, offset + limit) as variable, i}
+ {#each variableList.variables.slice(offset, offset + limit) as variable}
{@const isConflicting = globalVariableList
@@ -310,22 +361,31 @@
- {
- selectedVar = variable;
- showVariablesDropdown[i] = false;
- showVariablesModal = true;
- toggle(e);
- }}>
- Update
-
+ {#if !variable.secret}
+ {
+ selectedVar = variable;
+ showUpdate = true;
+ toggle(e);
+ }}>
+ Update
+
+ {
+ selectedVar = variable;
+ showSecretModal = true;
+ toggle(e);
+ }}>
+ Secret
+
+ {/if}
{#if !isGlobal}
{
selectedVar = variable;
- showVariablesDropdown[i] = false;
showPromoteModal = true;
toggle(e);
}}>
@@ -337,7 +397,6 @@
trailingIcon={IconTrash}
on:click={async (e) => {
handleVariableDeleted(variable);
- showVariablesDropdown[i] = false;
toggle(e);
}}>
Delete
@@ -368,12 +427,24 @@
+ on:created={handleVariableCreated} />
{/if}
+{#if showUpdate}
+
+{/if}
+{#if showSecretModal}
+
+{/if}
{#if showEditorModal}
= null;
+ export let show = false;
+ export let selectedVar: Partial;
let pair = {
$id: selectedVar?.$id,
@@ -24,29 +24,25 @@
const dispatch = createEventDispatcher();
function close() {
- showCreate = false;
+ show = false;
selectedVar = null;
}
function handleVariable() {
- if (selectedVar) {
- dispatch('updated', pair);
- } else {
- dispatch('created', pair);
- }
+ dispatch('updated', pair);
+
close();
}
- $: if (!showCreate) {
- console.log('test');
+ $: if (!show) {
selectedVar = null;
}
+ title={`Update ${isGlobal ? 'global' : 'environment'} variable`}>
Set the environment variables or secret keys that will be passed to {!isGlobal
@@ -56,16 +52,12 @@
{#if !isGlobal}
-
-
- When there is a naming conflict with a global variable in your
- project settings
- and a {product} environment variable, the global variable will be ignored.
-
-
+
+ When there is a naming conflict with a global variable in your
+ project settings
+ and a {product} environment variable, the global variable will be ignored.
+
{/if}
Cancel
- {selectedVar ? 'Update' : 'Create'}
+ Update
diff --git a/src/routes/(console)/project-[project]/uploadVariablesModal.svelte b/src/routes/(console)/project-[project]/uploadVariablesModal.svelte
index 127193428..d5501522a 100644
--- a/src/routes/(console)/project-[project]/uploadVariablesModal.svelte
+++ b/src/routes/(console)/project-[project]/uploadVariablesModal.svelte
@@ -1,11 +1,11 @@
-
+
+
+
+
+ Please describe your request in detail. If applicable, include steps for
+ reproduction of any in-app issues.
+
+
+ Choose a topic
+
+ {#each ['general', 'billing', 'technical'] as category}
+ {
+ $supportData.category = category;
+ }}
+ selected={$supportData.category === category}>{category}
+ {/each}
+
+
+
+
+
+
+ {
+ wizard.hide();
+ }}>Cancel
+ Submit
+
+
+
+
- Contact the Appwrite Team
-
- If you found a bug or have questions, please reach out to the Appwrite team. We try to
- respond to all messages within our office hours.
-
-
- Available: {supportWeekDays}, {supportTimings}
-
-
- Currently:
- {#if isSupportOnline()}
-
- Online
- {:else}
-
- Offline
- {/if}
-
+
+
+ Contact the Appwrite Team
+ If you found a bug or have questions, please reach out to the Appwrite team. We
+ try to respond to all messages within our office hours.
+
+ Available:
+ {supportWeekDays}, {supportTimings}
+
+
+ Currently:
+ {#if isSupportOnline()}
+
+
+ Online
+ {:else}
+
+
+ Offline
+
+ {/if}
+
+
+
-
+
diff --git a/src/routes/(console)/wizard/support/step1.svelte b/src/routes/(console)/wizard/support/step1.svelte
deleted file mode 100644
index 68d2a3739..000000000
--- a/src/routes/(console)/wizard/support/step1.svelte
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
- How can we help you?
-
- Please describe your request in detail. If applicable, include steps for reproduction of any
- in-app issues.
-
-
-
Choose a topic
-
- {#each ['general', 'billing', 'technical'] as topic}
-
{
- $supportData.category = topic;
- }}>{topic}
- {/each}
-
-
-
-
- {#if options?.length}
-
- {/if}
-
-
-
-
-
-
diff --git a/src/routes/(public)/(guest)/login/+page.svelte b/src/routes/(public)/(guest)/login/+page.svelte
index 7986a7023..403e6038a 100644
--- a/src/routes/(public)/(guest)/login/+page.svelte
+++ b/src/routes/(public)/(guest)/login/+page.svelte
@@ -22,8 +22,8 @@
disabled = true;
await sdk.forConsole.account.createEmailPasswordSession(mail, pass);
await invalidate(Dependencies.ACCOUNT);
- trackEvent(Submit.AccountLogin);
if ($user) {
+ trackEvent(Submit.AccountLogin, { mfa_used: 'none' });
addNotification({
type: 'success',
message: 'Successfully logged in.'
diff --git a/src/routes/(public)/(guest)/register/+page.svelte b/src/routes/(public)/(guest)/register/+page.svelte
index 531170cb3..8763ba8a2 100644
--- a/src/routes/(public)/(guest)/register/+page.svelte
+++ b/src/routes/(public)/(guest)/register/+page.svelte
@@ -61,7 +61,6 @@
} else {
await goto(base);
}
- trackEvent(Submit.AccountCreate);
} catch (error) {
disabled = false;
addNotification({
diff --git a/src/routes/(public)/auth/+layout.svelte b/src/routes/(public)/auth/+layout.svelte
index 7fa83f589..a2ac0dc4f 100644
--- a/src/routes/(public)/auth/+layout.svelte
+++ b/src/routes/(public)/auth/+layout.svelte
@@ -1,5 +1,4 @@
-
-
+
-
- POWERED BY
+ POWERED BY
{#if $app.themeInUse === 'dark'}
diff --git a/src/routes/(public)/auth/preview/+page.svelte b/src/routes/(public)/auth/preview/+page.svelte
index 153200e76..0bb62f30d 100644
--- a/src/routes/(public)/auth/preview/+page.svelte
+++ b/src/routes/(public)/auth/preview/+page.svelte
@@ -28,10 +28,12 @@
Preview - Appwrite
-
-
-
+
+
+
Authenticating...
- Please wait while we authenticate you
+
+ Please wait while we verify your access
+
diff --git a/src/routes/(public)/auth/preview/access/+page.svelte b/src/routes/(public)/auth/preview/access/+page.svelte
index 4445f5571..bc7191ee5 100644
--- a/src/routes/(public)/auth/preview/access/+page.svelte
+++ b/src/routes/(public)/auth/preview/access/+page.svelte
@@ -19,7 +19,7 @@
import { sdk } from '$lib/stores/sdk';
import { isCloud } from '$lib/system';
import { ID, OAuthProvider } from '@appwrite.io/console';
- import { Layout } from '@appwrite.io/pink-svelte';
+ import { Layout, Typography } from '@appwrite.io/pink-svelte';
import { onMount } from 'svelte';
import BGDark from './bg_dark.jpg';
import BGLight from './bg_light.jpg';
@@ -126,90 +126,111 @@
show
hideFooter={state !== 'authenticated'}
{error}>
+
+ {#if state === 'authenticated'}
+ Request access to view this preview. You'll gain access once your request is approved.
+ {/if}
+
-
+
{#if state === 'login'}
-
-
- Sign in
- {#if isCloud}
+
+
+
+
+
+
+ Sign in
or
-
-
- Sign in with GitHub
+ {#if isCloud}
+
+
+ Sign in with GitHub
+
+ {/if}
+ (state = 'register')}>
+ Sign up instead
- {/if}
- (state = 'register')}>
- Sign up instead
-
+
{:else if state === 'register'}
-
-
-
-
- By registering, you agree that you have read, understand, and acknowledge our
- Privacy Policy
- and accept our
- General Terms of Use .
- Sign up
- {#if isCloud}
+
+
+
+
+
+
+ By registering, you agree that you have read, understand, and acknowledge
+ our
+ Privacy Policy
+ and accept our
+ General Terms of Use .
+
+
+
+ Sign up
or
-
-
- Continue with GitHub
+ {#if isCloud}
+
+
+ Continue with GitHub
+
+ {/if}
+ (state = 'login')}>
+ Sign in instead
- {/if}
- (state = 'login')}>
- Sign in instead
-
+
{:else if state === 'authenticated'}
-
+
-
- You're signed in as {data.account.email}
-
+
+ You're signed in as
+
+
+ {data.account.email}
+
+
{
- logout();
+ logout(false);
state = 'login';
- }}>Swith account
+ }}>Switch account
{/if}
diff --git a/src/routes/(public)/invite/+page.svelte b/src/routes/(public)/invite/+page.svelte
index 70032758c..83c833616 100644
--- a/src/routes/(public)/invite/+page.svelte
+++ b/src/routes/(public)/invite/+page.svelte
@@ -8,8 +8,7 @@
import { page } from '$app/stores';
import { onMount } from 'svelte';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
- import { Alert } from '$lib/components';
- import { Layout, Link, Typography } from '@appwrite.io/pink-svelte';
+ import { Layout, Link, Typography, Alert } from '@appwrite.io/pink-svelte';
let teamId: string, membershipId: string, userId: string, secret: string;
let terms = false;
@@ -54,13 +53,10 @@
{#if !userId || !secret || !membershipId || !teamId}
-
- The invite link is not valid
+
Please ask the project owner to send you a new invite.
-
-
- Sign up to Appwrite
-
+
+ Sign up to Appwrite
{:else}
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index 9bc2eb60b..d4e5a02c3 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -21,9 +21,9 @@
function resolveTheme(theme: AppStore['themeInUse']) {
switch (theme) {
case 'dark':
- return true ? ThemeDarkCloud : ThemeDark; //TODO: remove after cloud instance is live
+ return isCloud ? ThemeDarkCloud : ThemeDark;
case 'light':
- return true ? ThemeLightCloud : ThemeLight;
+ return isCloud ? ThemeLightCloud : ThemeLight;
}
}
@@ -67,6 +67,7 @@
}
}
}
+
if (user && $page.url.searchParams.has('campaign')) {
const campaignId = $page.url.searchParams.get('campaign');
const campaign = await sdk.forConsole.billing
@@ -123,15 +124,41 @@
});
}
}
+
+ const preloadFonts = [
+ base + '/fonts/inter/inter-v8-latin-600.woff2',
+ base + '/fonts/inter/inter-v8-latin-regular.woff2',
+ base + '/fonts/poppins/poppins-v19-latin-500.woff2',
+ base + '/fonts/poppins/poppins-v19-latin-600.woff2',
+ base + '/fonts/poppins/poppins-v19-latin-700.woff2',
+ base + '/fonts/source-code-pro/source-code-pro-v20-latin-regular.woff2'
+ ];
+ const preloadFontsCloud = [
+ 'https://fonts.appwrite.io/aeonik-pro/AeonikPro-Regular.woff2',
+ 'https://fonts.appwrite.io/aeonik-pro/AeonikPro-Medium.woff2',
+ 'https://fonts.appwrite.io/aeonik-pro/AeonikPro-Bold.woff2',
+ 'https://fonts.appwrite.io/aeonik-fono/AeonikFono-Regular.woff2',
+ 'https://fonts.appwrite.io/aeonik-fono/AeonikFono-Medium.woff2',
+ 'https://fonts.appwrite.io/aeonik-fono/AeonikFono-Bold.woff2'
+ ];
-
-
-
+ {#each preloadFonts as font}
+
+ {/each}
+
+
+ {#if isCloud}
+ {#each preloadFontsCloud as font}
+
+ {/each}
+
+
+ {/if}
@@ -232,7 +259,7 @@
}
.is-cloud {
- --heading-font: 'Aeonik Pro', arial, sans-serif;
+ --heading-font: 'Aeonik Pro', 'Inter', sans-serif;
.heading-level {
@media #{devices.$break3open} {
&-1,
diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts
index 20db1d4af..6e42a690e 100644
--- a/src/routes/+layout.ts
+++ b/src/routes/+layout.ts
@@ -28,9 +28,13 @@ export const load: LayoutLoad = async ({ depends, url, route }) => {
}
if (account) {
+ const organizations = !isCloud
+ ? await sdk.forConsole.teams.list()
+ : await sdk.forConsole.billing.listOrganization();
+
return {
- account: account,
- organizations: await sdk.forConsole.teams.list()
+ account,
+ organizations
};
}
diff --git a/src/themes/light.json b/src/themes/light.json
index a2ab55069..2b3bd76ae 100644
--- a/src/themes/light.json
+++ b/src/themes/light.json
@@ -118,9 +118,9 @@
"overlay-skeleton": "rgba(25, 25, 28, 4%)",
"gradient-border-button-secondary-bottom": "var(--border-neutral)",
"gradient-border-button-secondary-top": "var(--border-neutral-strong)",
- "font-family-brand": "Aeonik Pro",
+ "font-family-brand": "Inter",
"font-family-sansserif": "Inter",
- "font-family-monospace": "Aeonik Fono",
+ "font-family-monospace": "Fira Code",
"font-family-code": "Fira Code",
"font-weight-regular": "Regular",
"font-weight-medium": "Medium",
diff --git a/static/fonts/cloud.css b/static/fonts/cloud.css
index c7650c179..26277ee0e 100644
--- a/static/fonts/cloud.css
+++ b/static/fonts/cloud.css
@@ -1,51 +1,3 @@
-@font-face {
- font-family: 'Aeonik Pro';
- font-style: normal;
- font-weight: 100;
- font-display: swap;
- src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-Air.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Aeonik Pro';
- font-style: italic;
- font-weight: 100;
- font-display: swap;
- src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-AirItalic.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Aeonik Pro';
- font-style: normal;
- font-weight: 200;
- font-display: swap;
- src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-Thin.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Aeonik Pro';
- font-style: italic;
- font-weight: 200;
- font-display: swap;
- src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-ThinItalic.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Aeonik Pro';
- font-style: normal;
- font-weight: 300;
- font-display: swap;
- src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-Light.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Aeonik Pro';
- font-style: italic;
- font-weight: 300;
- font-display: swap;
- src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-LightItalic.woff2') format('woff2');
-}
-
@font-face {
font-family: 'Aeonik Pro';
font-style: normal;
@@ -54,14 +6,6 @@
src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-Regular.woff2') format('woff2');
}
-@font-face {
- font-family: 'Aeonik Pro';
- font-style: italic;
- font-weight: 400;
- font-display: swap;
- src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-RegularItalic.woff2') format('woff2');
-}
-
@font-face {
font-family: 'Aeonik Pro';
font-style: normal;
@@ -70,14 +14,6 @@
src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-Medium.woff2') format('woff2');
}
-@font-face {
- font-family: 'Aeonik Pro';
- font-style: italic;
- font-weight: 500;
- font-display: swap;
- src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-MediumItalic.woff2') format('woff2');
-}
-
@font-face {
font-family: 'Aeonik Pro';
font-style: normal;
@@ -87,25 +23,25 @@
}
@font-face {
- font-family: 'Aeonik Pro';
- font-style: italic;
+ font-family: 'Aenoik Fono';
+ font-style: normal;
+ font-weight: 400;
+ font-display: swap;
+ src: url('https://fonts.appwrite.io/aeonik-fono/AeonikFono-Regular.woff2') format('woff2');
+}
+
+@font-face {
+ font-family: 'Aenoik Fono';
+ font-style: normal;
+ font-weight: 500;
+ font-display: swap;
+ src: url('https://fonts.appwrite.io/aeonik-fono/AeonikFono-Medium.woff2') format('woff2');
+}
+
+@font-face {
+ font-family: 'Aenoik Fono';
+ font-style: normal;
font-weight: 600;
font-display: swap;
- src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-BoldItalic.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Aeonik Pro';
- font-style: normal;
- font-weight: 700;
- font-display: swap;
- src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-Black.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Aeonik Pro';
- font-style: italic;
- font-weight: 700;
- font-display: swap;
- src: url('https://fonts.appwrite.io/aeonik-pro/AeonikPro-BlackItalic.woff2') format('woff2');
+ src: url('https://fonts.appwrite.io/aeonik-fono/AeonikFono-Bold.woff2') format('woff2');
}
diff --git a/static/icons/dark/color/analog.svg b/static/icons/dark/color/analog.svg
new file mode 100644
index 000000000..274a0e312
--- /dev/null
+++ b/static/icons/dark/color/analog.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/dark/color/mongo-db.svg b/static/icons/dark/color/mongo-db.svg
new file mode 100644
index 000000000..6339b5dec
--- /dev/null
+++ b/static/icons/dark/color/mongo-db.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/dark/color/neo4j.svg b/static/icons/dark/color/neo4j.svg
new file mode 100644
index 000000000..5557bd020
--- /dev/null
+++ b/static/icons/dark/color/neo4j.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/static/icons/dark/color/neon.svg b/static/icons/dark/color/neon.svg
new file mode 100644
index 000000000..09135c1d1
--- /dev/null
+++ b/static/icons/dark/color/neon.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/dark/color/redis.svg b/static/icons/dark/color/redis.svg
new file mode 100644
index 000000000..6a5a203f4
--- /dev/null
+++ b/static/icons/dark/color/redis.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/static/icons/dark/color/upstash.svg b/static/icons/dark/color/upstash.svg
new file mode 100644
index 000000000..a0fb67474
--- /dev/null
+++ b/static/icons/dark/color/upstash.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/dark/color/vite.svg b/static/icons/dark/color/vite.svg
new file mode 100644
index 000000000..3d6e1f472
--- /dev/null
+++ b/static/icons/dark/color/vite.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/dark/grayscale/mongo-db.svg b/static/icons/dark/grayscale/mongo-db.svg
new file mode 100644
index 000000000..b238a992d
--- /dev/null
+++ b/static/icons/dark/grayscale/mongo-db.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/dark/grayscale/neo4j.svg b/static/icons/dark/grayscale/neo4j.svg
new file mode 100644
index 000000000..942f32a7f
--- /dev/null
+++ b/static/icons/dark/grayscale/neo4j.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/static/icons/dark/grayscale/neon.svg b/static/icons/dark/grayscale/neon.svg
new file mode 100644
index 000000000..a0a158f18
--- /dev/null
+++ b/static/icons/dark/grayscale/neon.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/static/icons/dark/grayscale/redis.svg b/static/icons/dark/grayscale/redis.svg
new file mode 100644
index 000000000..8362bc644
--- /dev/null
+++ b/static/icons/dark/grayscale/redis.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/static/icons/dark/grayscale/upstash.svg b/static/icons/dark/grayscale/upstash.svg
new file mode 100644
index 000000000..33d004763
--- /dev/null
+++ b/static/icons/dark/grayscale/upstash.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/light/color/analog.svg b/static/icons/light/color/analog.svg
new file mode 100644
index 000000000..d38917f6d
--- /dev/null
+++ b/static/icons/light/color/analog.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/light/color/mongo-db.svg b/static/icons/light/color/mongo-db.svg
new file mode 100644
index 000000000..4209b312e
--- /dev/null
+++ b/static/icons/light/color/mongo-db.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/light/color/neo4j.svg b/static/icons/light/color/neo4j.svg
new file mode 100644
index 000000000..7c376119b
--- /dev/null
+++ b/static/icons/light/color/neo4j.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/static/icons/light/color/neon.svg b/static/icons/light/color/neon.svg
new file mode 100644
index 000000000..2760a8b47
--- /dev/null
+++ b/static/icons/light/color/neon.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/light/color/redis.svg b/static/icons/light/color/redis.svg
new file mode 100644
index 000000000..6a5a203f4
--- /dev/null
+++ b/static/icons/light/color/redis.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/static/icons/light/color/upstash.svg b/static/icons/light/color/upstash.svg
new file mode 100644
index 000000000..8da3831e4
--- /dev/null
+++ b/static/icons/light/color/upstash.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/light/color/vite.svg b/static/icons/light/color/vite.svg
new file mode 100644
index 000000000..37c9e66b9
--- /dev/null
+++ b/static/icons/light/color/vite.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/light/grayscale/mongo-db.svg b/static/icons/light/grayscale/mongo-db.svg
new file mode 100644
index 000000000..b238a992d
--- /dev/null
+++ b/static/icons/light/grayscale/mongo-db.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/static/icons/light/grayscale/neo4j.svg b/static/icons/light/grayscale/neo4j.svg
new file mode 100644
index 000000000..942f32a7f
--- /dev/null
+++ b/static/icons/light/grayscale/neo4j.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/static/icons/light/grayscale/neon.svg b/static/icons/light/grayscale/neon.svg
new file mode 100644
index 000000000..a0a158f18
--- /dev/null
+++ b/static/icons/light/grayscale/neon.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/static/icons/light/grayscale/redis.svg b/static/icons/light/grayscale/redis.svg
new file mode 100644
index 000000000..8362bc644
--- /dev/null
+++ b/static/icons/light/grayscale/redis.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/static/icons/light/grayscale/upstash.svg b/static/icons/light/grayscale/upstash.svg
new file mode 100644
index 000000000..33d004763
--- /dev/null
+++ b/static/icons/light/grayscale/upstash.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/images/domains/empty-domain-dark.svg b/static/images/domains/empty-domain-dark.svg
index 71d19454d..35d9d9355 100644
--- a/static/images/domains/empty-domain-dark.svg
+++ b/static/images/domains/empty-domain-dark.svg
@@ -1,173 +1,153 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
+
+
-
-
-
-
+
+
-
-
-
-
+
+
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/static/images/domains/empty-domain-light.svg b/static/images/domains/empty-domain-light.svg
index 71d19454d..86b5e87c0 100644
--- a/static/images/domains/empty-domain-light.svg
+++ b/static/images/domains/empty-domain-light.svg
@@ -1,173 +1,178 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
diff --git a/static/images/domains/empty-records-dark.svg b/static/images/domains/empty-records-dark.svg
index 0e4b3dd71..84778421a 100644
--- a/static/images/domains/empty-records-dark.svg
+++ b/static/images/domains/empty-records-dark.svg
@@ -1,173 +1,153 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
+
+
-
-
-
-
+
+
-
-
-
-
+
+
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/static/images/domains/empty-records-light.svg b/static/images/domains/empty-records-light.svg
index 0e4b3dd71..c18eca86e 100644
--- a/static/images/domains/empty-records-light.svg
+++ b/static/images/domains/empty-records-light.svg
@@ -1,173 +1,178 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
diff --git a/static/images/empty-deployment-dark.svg b/static/images/empty-deployment-dark.svg
new file mode 100644
index 000000000..e26615ac5
--- /dev/null
+++ b/static/images/empty-deployment-dark.svg
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/images/empty-deployment-light.svg b/static/images/empty-deployment-light.svg
new file mode 100644
index 000000000..f23e04aad
--- /dev/null
+++ b/static/images/empty-deployment-light.svg
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+