diff --git a/package-lock.json b/package-lock.json
index 7a4750ed6..0d504f8ae 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,8 +7,8 @@
"name": "@appwrite/console",
"dependencies": {
"@appwrite.io/console": "^0.6.1",
- "@appwrite.io/pink": "0.8.0",
- "@appwrite.io/pink-icons": "0.8.0",
+ "@appwrite.io/pink": "0.11.0",
+ "@appwrite.io/pink-icons": "0.11.0",
"@popperjs/core": "^2.11.8",
"@sentry/svelte": "^7.66.0",
"@sentry/tracing": "^7.66.0",
@@ -166,19 +166,19 @@
}
},
"node_modules/@appwrite.io/pink": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/@appwrite.io/pink/-/pink-0.8.0.tgz",
- "integrity": "sha512-UZKwkUtAo2N0JiTiKDPWC8GHubTF2905DOzuCGl716fYua2gNIlS8D+HA/wd15qyRjZlgQh4MtVUAdHI8GLf8g==",
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@appwrite.io/pink/-/pink-0.11.0.tgz",
+ "integrity": "sha512-0/ztJxeV6Cy1FnXy2ClLELzDnR4eRtGAhQ24napCg0VwOFevSIc0S7jcRrWVyA6WRuwex4eGiEn2JeYMTq70Xg==",
"dependencies": {
- "@appwrite.io/pink-icons": "0.8.0",
+ "@appwrite.io/pink-icons": "0.11.0",
"normalize.css": "^8.0.1",
"the-new-css-reset": "^1.11.2"
}
},
"node_modules/@appwrite.io/pink-icons": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/@appwrite.io/pink-icons/-/pink-icons-0.8.0.tgz",
- "integrity": "sha512-UQd4mXOohGggXHNhIlYt4u2NLB/ubI6pvkdllrBQnHZEb7JL2iklff8Ne5moW8F9DeXLBt/ZQLRe240lvVjm6Q=="
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@appwrite.io/pink-icons/-/pink-icons-0.11.0.tgz",
+ "integrity": "sha512-FOvP87m4S17QRQPrLzsSlwrbIeJNJi5RliGUQYONIhmI0PiwE4Xm5LXFE+NqFYsR56w2X3jYdJIHdIdZlH3XjA=="
},
"node_modules/@babel/code-frame": {
"version": "7.24.2",
diff --git a/package.json b/package.json
index 453405dd8..5783c798a 100644
--- a/package.json
+++ b/package.json
@@ -19,8 +19,8 @@
},
"dependencies": {
"@appwrite.io/console": "^0.6.1",
- "@appwrite.io/pink": "0.8.0",
- "@appwrite.io/pink-icons": "0.8.0",
+ "@appwrite.io/pink": "0.11.0",
+ "@appwrite.io/pink-icons": "0.11.0",
"@popperjs/core": "^2.11.8",
"@sentry/svelte": "^7.66.0",
"@sentry/tracing": "^7.66.0",
diff --git a/src/lib/actions/analytics.ts b/src/lib/actions/analytics.ts
index 4c9cb3be8..b82ad351b 100644
--- a/src/lib/actions/analytics.ts
+++ b/src/lib/actions/analytics.ts
@@ -151,7 +151,12 @@ export enum Submit {
AccountDelete = 'submit_account_delete',
AccountDeleteSession = 'submit_account_delete_session',
AccountDeleteAllSessions = 'submit_account_delete_all_sessions',
+ AccountUpdateMfa = 'submit_account_update_mfa',
+ AccountAuthenticatorCreate = 'submit_account_authenticator_create',
+ AccountAuthenticatorUpdate = 'submit_account_authenticator_update',
AccountAuthenticatorDelete = 'submit_account_authenticator_delete',
+ AccountRecoveryCodesCreate = 'submit_account_recovery_codes_create',
+ AccountRecoveryCodesUpdate = 'submit_account_recovery_codes_update',
UserCreate = 'submit_user_create',
UserDelete = 'submit_user_delete',
UserUpdateEmail = 'submit_user_update_email',
diff --git a/src/lib/components/copyInput.svelte b/src/lib/components/copyInput.svelte
index b19d9b002..3ff70378d 100644
--- a/src/lib/components/copyInput.svelte
+++ b/src/lib/components/copyInput.svelte
@@ -1,46 +1,58 @@
-
{label}
+ {#if label}
+
+ {label}{#if popover}
+
+
+ (show = !show)}
+ class="tooltip"
+ aria-label="input tooltip">
+
+
+
+
+
+
+
+
+ {/if}
+
+ {/if}
diff --git a/src/lib/components/modal.svelte b/src/lib/components/modal.svelte
index 9bcdbdc89..ed85e0cab 100644
--- a/src/lib/components/modal.svelte
+++ b/src/lib/components/modal.svelte
@@ -64,11 +64,13 @@
{/if}
-
-
- {description}
-
-
+ {#if description.length > 0}
+
+
+ {description}
+
+
+ {/if}
diff --git a/src/lib/elements/forms/inputDigits.svelte b/src/lib/elements/forms/inputDigits.svelte
index ae0162864..b3c5edcbe 100644
--- a/src/lib/elements/forms/inputDigits.svelte
+++ b/src/lib/elements/forms/inputDigits.svelte
@@ -10,6 +10,7 @@
export let readonly = false;
export let autofocus = false;
export let fullWidth = false;
+ export let autoSubmit = true;
let element: HTMLOListElement;
@@ -21,9 +22,12 @@
placeholder: '',
defaultValue: value.split(''),
onValueChange: ({ next }) => {
+ if (!autoSubmit) {
+ return next;
+ }
value = next.join('');
- if (value.length === 6 && !autoSubmitted) {
+ if (value.length === length && !autoSubmitted) {
autoSubmitted = true;
const firstInputElement = element.querySelector('input');
firstInputElement?.form.requestSubmit();
@@ -47,15 +51,15 @@
-
+
{#each Array.from({ length }) as _}
+
+
diff --git a/src/lib/elements/forms/inputFile.svelte b/src/lib/elements/forms/inputFile.svelte
index 2de200818..3ecb27959 100644
--- a/src/lib/elements/forms/inputFile.svelte
+++ b/src/lib/elements/forms/inputFile.svelte
@@ -23,17 +23,6 @@
function setFiles(value: FileList) {
if (!value) return;
- const hasInvalidExt = Array.from(value).some((file) => {
- const fileExtension = file.name.split('.').pop();
- return allowedFileExtensions?.length
- ? !allowedFileExtensions.includes(fileExtension)
- : false;
- });
- if (hasInvalidExt) {
- error = 'Invalid file extension';
- return;
- }
-
files = value;
input.files = value;
}
@@ -42,11 +31,22 @@
setFiles(new DataTransfer().files);
}
+ function isFileExtensionAllowed(fileExtension: string) {
+ if (allowedFileExtensions.length && !allowedFileExtensions.includes(fileExtension)) {
+ return false;
+ }
+ return true;
+ }
function dropHandler(ev: DragEvent) {
ev.dataTransfer.dropEffect = 'move';
hovering = false;
if (!ev.dataTransfer.items) return;
for (let i = 0; i < ev.dataTransfer.items.length; i++) {
+ const fileExtension = ev.dataTransfer.items[i].getAsFile().name.split('.')[1];
+ if (!isFileExtensionAllowed(fileExtension)) {
+ error = 'Invalid file extension';
+ return;
+ }
if (ev.dataTransfer.items[i].kind === 'file') {
const dataTransfer = new DataTransfer();
dataTransfer.items.add(ev.dataTransfer.items[i].getAsFile());
@@ -81,6 +81,18 @@
const handleChange = (event: Event) => {
const target = event.currentTarget as HTMLInputElement;
+
+ const isValidFiles = Array.from(target.files).every((file) => {
+ const fileExtension = file.name.split('.').pop();
+ return isFileExtensionAllowed(fileExtension);
+ });
+
+ if (!isValidFiles) {
+ error = 'Invalid file extension';
+ target.value = '';
+ return;
+ }
+
setFiles(target.files);
};
diff --git a/src/lib/layout/unauthenticated.svelte b/src/lib/layout/unauthenticated.svelte
index 7c16c7a8d..1ceb0057c 100644
--- a/src/lib/layout/unauthenticated.svelte
+++ b/src/lib/layout/unauthenticated.svelte
@@ -14,7 +14,7 @@
-
+
-
+
+
-
@@ -127,4 +151,8 @@
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
+
+ .form-container {
+ max-inline-size: 27.5rem;
+ }
diff --git a/src/routes/console/account/deleteMfa.svelte b/src/routes/console/account/deleteMfa.svelte
index 15d0b629f..9d01dcfed 100644
--- a/src/routes/console/account/deleteMfa.svelte
+++ b/src/routes/console/account/deleteMfa.svelte
@@ -15,7 +15,7 @@
let code: string;
let error: string;
- async function deleteProvider() {
+ async function deleteAuthenticator() {
try {
await sdk.forConsole.account.deleteMfaAuthenticator(AuthenticatorType.Totp, code);
await invalidate(Dependencies.ACCOUNT);
@@ -41,18 +41,14 @@
-
- Deleting the authentication method will disable multi-factor authentication for your
- account. To re-enable it, you'll need to add a new authentication method.
-
Enter the 6-digit verification code generated by your authenticator app to continue.
-
+
diff --git a/src/routes/console/account/mfa.svelte b/src/routes/console/account/mfa.svelte
index 53ada1479..5fa0c8d4a 100644
--- a/src/routes/console/account/mfa.svelte
+++ b/src/routes/console/account/mfa.svelte
@@ -1,25 +1,24 @@
+ onSubmit={verifyAuthenticator}
+ {error}>
{#key showSetup}
-
- Install an authenticator app on your mobile device, open it and scan the provided QR
- code or enter it manually.
-
{#if step === 1}
+
+ Install an authenticator app on your mobile device, open it and scan the provided QR
+ code or enter it manually.
+
{#await addAuthenticator()}
@@ -69,26 +63,12 @@
or
-
Manual entry code
-
-
-
-
-
-
-
-
- {#key copyParent}
-
-
-
- {/key}
-
-
+
{/await}
{:else}
@@ -108,68 +88,6 @@
-
- {#if type && codes}
- {@const formattedBackupCodes = codes.recoveryCodes.join('\n')}
-
-
- It is highly recommended to securely store your recovery codes
-
-
- Use security codes for emergency sign-ins in case you've lost access to your mobile
- device. Each recovery code can only be used once, but you can re-generate a new set
- of 6 codes anytime.
-
-
-
-
-
- {#each codes.recoveryCodes as code}
-
-
- {code}
-
-
-
-
-
-
-
- {/each}
-
-
- {/if}
-
- (showRecoveryCodes = false)}>Close
-
-
-
diff --git a/src/routes/console/project-[project]/auth/user-[user]/updateMfa.svelte b/src/routes/console/project-[project]/auth/user-[user]/updateMfa.svelte
index 3a99efa4a..47827068d 100644
--- a/src/routes/console/project-[project]/auth/user-[user]/updateMfa.svelte
+++ b/src/routes/console/project-[project]/auth/user-[user]/updateMfa.svelte
@@ -50,7 +50,7 @@