(flag);
+}
+
+export function devFlagValue(flag: keyof DevFlags) {
+ return baseDevFlagValue(flag);
+}
diff --git a/apps/desktop/src/locales/af/messages.json b/apps/desktop/src/locales/af/messages.json
index 347028a59fa..42fdf47753b 100644
--- a/apps/desktop/src/locales/af/messages.json
+++ b/apps/desktop/src/locales/af/messages.json
@@ -1980,16 +1980,16 @@
"message": "API-sleutel"
},
"premiumSubcriptionRequired": {
- "message": "Premium subscription required"
+ "message": "Premie-intekening word vereis"
},
"organizationIsDisabled": {
"message": "Organisasie is gedeaktiveer."
},
"disabledOrganizationFilterError": {
- "message": "Items in disabled Organizations cannot be accessed. Contact your Organization owner for assistance."
+ "message": "Items in gedeaktiveerde organisasies is ontoeganklik. Kontak u organisasie-eienaar vir bystand."
},
"neverLockWarning": {
- "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected."
+ "message": "Is u seker u wil die “Nooit”-opsie gebruik? Deur u vergrendelopsies op “Nooit” te stel word u kluis se enkripsie op u toestel bewaar. Indien u hierdie opsie gebruik moet u verseker dat u toestel behoorlik beskerm is."
},
"cardBrandMir": {
"message": "Mir"
diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json
index fcc68d0b2dd..1f8eacd1d55 100644
--- a/apps/desktop/src/locales/ar/messages.json
+++ b/apps/desktop/src/locales/ar/messages.json
@@ -1394,19 +1394,19 @@
"message": "قفل مع كلمة المرور الرئيسية عند إعادة تشغيل"
},
"deleteAccount": {
- "message": "Delete account"
+ "message": "حذف الحساب"
},
"deleteAccountDesc": {
- "message": "Proceed below to delete your account and all vault data."
+ "message": "تابع أدناه لحذف حسابك وجميع بيانات خزنتك."
},
"deleteAccountWarning": {
- "message": "Deleting your account is permanent. It cannot be undone."
+ "message": "حذف حسابك دائم. لا يمكن التراجع عنه."
},
"accountDeleted": {
- "message": "Account deleted"
+ "message": "تم حذف الحساب"
},
"accountDeletedDesc": {
- "message": "Your account has been closed and all associated data has been deleted."
+ "message": "لقد تم إغلاق حسابك وتم حذف جميع البيانات المرتبطة به."
},
"preferences": {
"message": "التفضيلات"
@@ -1980,7 +1980,7 @@
"message": "مفتاح API"
},
"premiumSubcriptionRequired": {
- "message": "Premium subscription required"
+ "message": "الاشتراك المميز مطلوب"
},
"organizationIsDisabled": {
"message": "تم تعطيل المؤسسة."
diff --git a/apps/desktop/src/locales/be/messages.json b/apps/desktop/src/locales/be/messages.json
index 28a9676d03e..42f68a95699 100644
--- a/apps/desktop/src/locales/be/messages.json
+++ b/apps/desktop/src/locales/be/messages.json
@@ -361,7 +361,7 @@
"message": "Выдаліць далучэнне"
},
"deleteItemConfirmation": {
- "message": "Вы ўпэўнены, што хочаце выдаліць гэты элемент?"
+ "message": "Вы сапраўды хочаце адправіць элемент у сметніцу?"
},
"deletedItem": {
"message": "Элемент адпраўлены ў сметніцу"
@@ -560,7 +560,7 @@
"message": "Няма элементаў для паказу."
},
"sendVerificationCode": {
- "message": "Адправіць код праверкі на вашу электронную пошту"
+ "message": "Адправіць праверачны код на вашу электронную пошту"
},
"sendCode": {
"message": "Адправіць код"
@@ -608,7 +608,7 @@
"message": "Запомніць мяне"
},
"sendVerificationCodeEmailAgain": {
- "message": "Адправіць код пацвярджэння зноў"
+ "message": "Адправіць праверачны код яшчэ раз"
},
"useAnotherTwoStepMethod": {
"message": "Выкарыстоўваць іншы метад двухэтапнага ўваходу"
@@ -1305,26 +1305,26 @@
"message": "Гатова"
},
"accessibilityCookieSaved": {
- "message": "Accessibility cookie saved!"
+ "message": "Cookie са спецыяльнымі магчымасцямі захаваны!"
},
"noAccessibilityCookieSaved": {
- "message": "No accessibility cookie saved"
+ "message": "Адсутнічаюць захаваныя cookie са спецыяльнымі магчымасцямі"
},
"warning": {
"message": "УВАГА",
"description": "WARNING (should stay in capitalized letters if the language permits)"
},
"confirmVaultExport": {
- "message": "Confirm Vault Export"
+ "message": "Пацвердзіць экспартаванне сховішча"
},
"exportWarningDesc": {
"message": "Экспартуемы файл утрымлівае даныя вашага сховішча ў незашыфраваным фармаце. Яго не варта захоўваць ці адпраўляць па небяспечным каналам (напрыклад, па электроннай пошце). Выдаліце яго адразу пасля выкарыстання."
},
"encExportKeyWarningDesc": {
- "message": "This export encrypts your data using your account's encryption key. If you ever rotate your account's encryption key you should export again since you will not be able to decrypt this export file."
+ "message": "Падчас экспартавання даныя шыфруюцца з дапамогай ключа шыфравання ўліковага запісу. Калі вы калі-небудзь зменіце ключ шыфравання ўліковага запісу, вам неабходна будзе экспартаваць даныя паўторна, паколькі вы не зможаце расшыфраваць гэты файл экспартавання."
},
"encExportAccountWarningDesc": {
- "message": "Account encryption keys are unique to each Bitwarden user account, so you can't import an encrypted export into a different account."
+ "message": "Ключы шыфравання з'яўляюцца ўнікальнымі для кожнага ўліковага запісу Bitwarden, таму нельга імпартаваць зашыфраванае сховішча ў іншы ўліковы запіс."
},
"noOrganizationsList": {
"message": "Вы не з'яўляецеся членам якой-небудзь арганізацыі. Арганізацыі дазваляюць бяспечна абменьвацца элементамі з іншымі карыстальнікамі."
@@ -1385,16 +1385,16 @@
"message": "Праверыць на Bitwarden."
},
"autoPromptWindowsHello": {
- "message": "Ask for Windows Hello on launch"
+ "message": "Запытваць Windows Hello пры запуску"
},
"autoPromptTouchId": {
- "message": "Ask for Touch ID on launch"
+ "message": "Запытваць Touch ID пры запуску"
},
"lockWithMasterPassOnRestart": {
"message": "Блакіраваць асноўным паролем пры перазапуску"
},
"deleteAccount": {
- "message": "Delete account"
+ "message": "Выдаліць уліковы запіс"
},
"deleteAccountDesc": {
"message": "Proceed below to delete your account and all vault data."
@@ -1613,7 +1613,7 @@
"message": "An organization policy is affecting your ownership options."
},
"allSends": {
- "message": "Усе адпраўленні",
+ "message": "Усе Send'ы",
"description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendTypeFile": {
@@ -1623,11 +1623,11 @@
"message": "Тэкст"
},
"searchSends": {
- "message": "Пошук адпраўленняў",
+ "message": "Пошук Send'аў",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"editSend": {
- "message": "Рэдагаваць адпраўленне",
+ "message": "Рэдагаваць Send",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"myVault": {
@@ -1640,7 +1640,7 @@
"message": "Дата выдалення"
},
"deletionDateDesc": {
- "message": "The Send will be permanently deleted on the specified date and time.",
+ "message": "Send будзе незваротна выдалены ў азначаныя дату і час.",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"expirationDate": {
@@ -1651,7 +1651,7 @@
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"maxAccessCount": {
- "message": "Maximum Access Count",
+ "message": "Максімальная колькасць доступаў",
"description": "This text will be displayed after a Send has been accessed the maximum amount of times."
},
"maxAccessCountDesc": {
@@ -1674,27 +1674,27 @@
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendLink": {
- "message": "Даслаць спасылку",
+ "message": "Адправіць спасылку",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendLinkLabel": {
- "message": "Send Link",
+ "message": "Адправіць спасылку",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"textHiddenByDefault": {
- "message": "When accessing the Send, hide the text by default",
+ "message": "Прадвызначана хаваць тэкст, калі адбываецца доступ да Send",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"createdSend": {
- "message": "Created Send",
+ "message": "Створаны Send",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"editedSend": {
- "message": "Edited Send",
+ "message": "Адрэдагаваны Send",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"deletedSend": {
- "message": "Deleted Send",
+ "message": "Выдалены Send",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"newPassword": {
@@ -1705,7 +1705,7 @@
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"createSend": {
- "message": "Стварыць адпраўленне",
+ "message": "Стварыць Send",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendTextDesc": {
@@ -1734,7 +1734,7 @@
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"copySendLinkToClipboard": {
- "message": "Скапіяваць спасылку адпраўлення ў буфер абмену",
+ "message": "Капіяваць спасылку на Send у буфер абмену",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"copySendLinkOnSave": {
diff --git a/apps/desktop/src/locales/da/messages.json b/apps/desktop/src/locales/da/messages.json
index 3b388f1312f..5083a5060ee 100644
--- a/apps/desktop/src/locales/da/messages.json
+++ b/apps/desktop/src/locales/da/messages.json
@@ -1980,7 +1980,7 @@
"message": "API-nøgle"
},
"premiumSubcriptionRequired": {
- "message": "Premium subscription required"
+ "message": "Premium-abonnement kræves"
},
"organizationIsDisabled": {
"message": "Organisationen er deaktiveret."
diff --git a/apps/desktop/src/locales/de/messages.json b/apps/desktop/src/locales/de/messages.json
index d85be199e02..11c3390bb6f 100644
--- a/apps/desktop/src/locales/de/messages.json
+++ b/apps/desktop/src/locales/de/messages.json
@@ -587,7 +587,7 @@
"message": "Gib den 6-stelligen Verifizierungscode aus deiner Authentifizierungs-App ein."
},
"enterVerificationCodeEmail": {
- "message": "Gib den 6-stelligen Bestätigungscode ein, der an $EMAIL$ gesendet wurde.",
+ "message": "Gib den 6-stelligen Verifizierungscode ein, der an $EMAIL$ gesendet wurde.",
"placeholders": {
"email": {
"content": "$1",
@@ -988,7 +988,7 @@
"description": "Copy to clipboard"
},
"checkForUpdates": {
- "message": "Auf Updates prüfen"
+ "message": "Auf Updates prüfen …"
},
"version": {
"message": "Version $VERSION_NUM$",
@@ -1803,7 +1803,7 @@
"message": "Minuten"
},
"vaultTimeoutPolicyInEffect": {
- "message": "Deine Unternehmensrichtlinien beeinflussen dein Tresor-Timeout. Das maximal zulässige Tresor-Timeout ist $HOURS$ Stunde(n) und $MINUTES$ Minute(n)",
+ "message": "Die Unternehmensrichtlinien beeinflussen deinen Tresor-Timeout. Das maximal zulässige Tresor-Timeout ist $HOURS$ Stunde(n) und $MINUTES$ Minute(n)",
"placeholders": {
"hours": {
"content": "$1",
@@ -1864,7 +1864,7 @@
"message": "Alle Tresore sperren"
},
"accountLimitReached": {
- "message": "Es dürfen nicht mehr als 5 Konten gleichzeitig angemeldet sein."
+ "message": "Es dürfen nicht mehr als fünf Konten gleichzeitig angemeldet sein."
},
"accountPreferences": {
"message": "Einstellungen"
@@ -1921,7 +1921,7 @@
"message": "Passworttyp"
},
"regenerateUsername": {
- "message": "Benutzername neu generieren"
+ "message": "Benutzernamen neu generieren"
},
"generateUsername": {
"message": "Benutzernamen generieren"
@@ -1958,7 +1958,7 @@
"message": "Alle Tresore"
},
"searchOrganization": {
- "message": "Organisationen durchsuchen"
+ "message": "Organisation durchsuchen"
},
"searchMyVault": {
"message": "Meinen Tresor durchsuchen"
diff --git a/apps/desktop/src/locales/eo/messages.json b/apps/desktop/src/locales/eo/messages.json
index 4bc416e01b9..472ff720952 100644
--- a/apps/desktop/src/locales/eo/messages.json
+++ b/apps/desktop/src/locales/eo/messages.json
@@ -145,7 +145,7 @@
"message": "Brand"
},
"expiration": {
- "message": "Validoperiodo"
+ "message": "Eksvalidiĝo"
},
"securityCode": {
"message": "Kodo de sekureco"
diff --git a/apps/desktop/src/locales/es/messages.json b/apps/desktop/src/locales/es/messages.json
index bf6f57bd2de..e871c6e1c36 100644
--- a/apps/desktop/src/locales/es/messages.json
+++ b/apps/desktop/src/locales/es/messages.json
@@ -1980,7 +1980,7 @@
"message": "Clave API"
},
"premiumSubcriptionRequired": {
- "message": "Premium subscription required"
+ "message": "Se requiere una Suscripción Premium"
},
"organizationIsDisabled": {
"message": "La organización está desactivada."
diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json
index b6c656a4ace..c3bcfa61b0d 100644
--- a/apps/desktop/src/locales/fi/messages.json
+++ b/apps/desktop/src/locales/fi/messages.json
@@ -560,7 +560,7 @@
"message": "Ei näytettäviä kohteita."
},
"sendVerificationCode": {
- "message": "Lähetä vahvistuskoodi sähköpostiisi"
+ "message": "Lähetä todennuskoodi sähköpostiisi"
},
"sendCode": {
"message": "Lähetä koodi"
@@ -578,7 +578,7 @@
"message": "Todennuskoodi vaaditaan."
},
"invalidVerificationCode": {
- "message": "Virheellinen vahvistuskoodi"
+ "message": "Virheellinen todennuskoodi"
},
"continue": {
"message": "Jatka"
diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json
index e18492558a1..86f16ebeb96 100644
--- a/apps/desktop/src/locales/fr/messages.json
+++ b/apps/desktop/src/locales/fr/messages.json
@@ -533,13 +533,13 @@
"message": "Adresse e-mail invalide."
},
"masterPasswordRequired": {
- "message": "Master password is required."
+ "message": "Le mot de passe maître est requis."
},
"confirmMasterPasswordRequired": {
- "message": "Master password retype is required."
+ "message": "Le mot de passe maître doit être entré de nouveau."
},
"masterPasswordMinlength": {
- "message": "Master password must be at least 8 characters long."
+ "message": "Le mot de passe maître doit au moins contenir 8 caractères."
},
"masterPassDoesntMatch": {
"message": "La confirmation du mot de passe maître ne correspond pas."
@@ -898,10 +898,10 @@
"description": "Clipboard is the operating system thing where you copy/paste data to on your device."
},
"enableFavicon": {
- "message": "Show website icons"
+ "message": "Afficher les icônes du site web"
},
"faviconDesc": {
- "message": "Show a recognizable image next to each login."
+ "message": "Afficher une image reconnaissable à côté de chaque identifiant."
},
"enableMinToTray": {
"message": "Réduire dans la barre d'outils"
@@ -1394,19 +1394,19 @@
"message": "Verrouiller avec le mot de passe maître lors du redémarrage"
},
"deleteAccount": {
- "message": "Delete account"
+ "message": "Supprimer le compte"
},
"deleteAccountDesc": {
- "message": "Proceed below to delete your account and all vault data."
+ "message": "Continuez ci-dessous pour supprimer votre compte et toutes les données associées."
},
"deleteAccountWarning": {
- "message": "Deleting your account is permanent. It cannot be undone."
+ "message": "La suppression de votre compte est définitive. Cette action ne peut pas être annulée."
},
"accountDeleted": {
- "message": "Account deleted"
+ "message": "Compte supprimé"
},
"accountDeletedDesc": {
- "message": "Your account has been closed and all associated data has been deleted."
+ "message": "Votre compte a été fermé et toutes les données associées ont été supprimées."
},
"preferences": {
"message": "Préférences"
@@ -1562,7 +1562,7 @@
"message": "En cochant cette case, vous acceptez les éléments suivants :"
},
"acceptPoliciesRequired": {
- "message": "Terms of Service and Privacy Policy have not been acknowledged."
+ "message": "Les Conditions d'Utilisation et la Politique de Confidentialité n'ont pas été acceptées."
},
"enableBrowserIntegration": {
"message": "Activer l'intégration avec le navigateur"
@@ -1980,16 +1980,16 @@
"message": "Clé d'IPA"
},
"premiumSubcriptionRequired": {
- "message": "Premium subscription required"
+ "message": "Abonnement Premium requis"
},
"organizationIsDisabled": {
- "message": "Organization is disabled."
+ "message": "L'organisation est désactivée."
},
"disabledOrganizationFilterError": {
- "message": "Items in disabled Organizations cannot be accessed. Contact your Organization owner for assistance."
+ "message": "Les éléments des Organisations désactivées ne sont pas accessibles. Contactez le propriétaire de votre Organisation pour obtenir de l'aide."
},
"neverLockWarning": {
- "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected."
+ "message": "Êtes-vous sûr de vouloir utiliser l'option \"Jamais\" ? Définir le verrouillage sur \"Jamais\" stocke la clé de chiffrement de votre coffre sur votre appareil. Si vous utilisez cette option, vous devez vous assurer de correctement protéger votre appareil."
},
"cardBrandMir": {
"message": "Mir"
diff --git a/apps/desktop/src/locales/pl/messages.json b/apps/desktop/src/locales/pl/messages.json
index 6871aeea05d..5d12b9b62e2 100644
--- a/apps/desktop/src/locales/pl/messages.json
+++ b/apps/desktop/src/locales/pl/messages.json
@@ -1403,7 +1403,7 @@
"message": "Usunięcie konta jest nieodwracalne. Ta czynność nie może zostać cofnięta."
},
"accountDeleted": {
- "message": "Konto usunięte"
+ "message": "Konto zostało usunięte"
},
"accountDeletedDesc": {
"message": "Konto zostało zamknięte i wszystkie powiązane z nim dane zostały usunięte."
diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json
index 4b2c1931eaf..5f15af3dc3d 100644
--- a/apps/desktop/src/locales/sr/messages.json
+++ b/apps/desktop/src/locales/sr/messages.json
@@ -1980,7 +1980,7 @@
"message": "АПИ Кључ"
},
"premiumSubcriptionRequired": {
- "message": "Premium subscription required"
+ "message": "Premium претплата је потребна"
},
"organizationIsDisabled": {
"message": "Организација је онемогућена."
diff --git a/apps/desktop/src/locales/th/messages.json b/apps/desktop/src/locales/th/messages.json
index 4c27a385e01..f439ddd8817 100644
--- a/apps/desktop/src/locales/th/messages.json
+++ b/apps/desktop/src/locales/th/messages.json
@@ -12,7 +12,7 @@
"message": "รายการโปรด"
},
"types": {
- "message": "Types"
+ "message": "ประเภท"
},
"typeLogin": {
"message": "เข้าสู่ระบบ"
@@ -42,13 +42,13 @@
"message": "แบ่งปัน"
},
"share": {
- "message": "Share"
+ "message": "แชร์"
},
"moveToOrganization": {
- "message": "Move to Organization"
+ "message": "ย้ายไปที่องค์กร"
},
"movedItemToOrg": {
- "message": "$ITEMNAME$ moved to $ORGNAME$",
+ "message": "$ITEMNAME$ ย้ายไปที่ $ORGNAME$ แล้ว",
"placeholders": {
"itemname": {
"content": "$1",
@@ -61,10 +61,10 @@
}
},
"moveToOrgDesc": {
- "message": "Choose an organization that you wish to move this item to. Moving to an organization transfers ownership of the item to that organization. You will no longer be the direct owner of this item once it has been moved."
+ "message": "เลือกองค์กรที่คุณต้องการย้ายรายการนี้ไป การย้ายไปยังองค์กรจะเป็นการโอนความเป็นเจ้าของรายการไปยังองค์กรนั้น คุณจะไม่ได้เป็นเจ้าของโดยตรงของรายการนี้อีกต่อไปเมื่อมีการย้าย"
},
"attachments": {
- "message": "Attachments"
+ "message": "ไฟล์แนบ"
},
"viewItem": {
"message": "ดูรายการ"
@@ -86,7 +86,7 @@
}
},
"newUri": {
- "message": "New URI"
+ "message": "URL ใหม่"
},
"username": {
"message": "ชื่อผู้ใช้"
@@ -110,13 +110,13 @@
"message": "เว็บไซต์"
},
"notes": {
- "message": "Notes"
+ "message": "โน๊ต"
},
"customFields": {
"message": "Custom Fields"
},
"launch": {
- "message": "Launch"
+ "message": "เริ่ม"
},
"copyValue": {
"message": "คัดลอกค่า",
@@ -269,7 +269,7 @@
"message": "นามสกุล"
},
"fullName": {
- "message": "Full Name"
+ "message": "ชื่อเต็ม"
},
"address1": {
"message": "ที่อยู่ 1"
@@ -401,16 +401,16 @@
"message": "ความยาว"
},
"uppercase": {
- "message": "Uppercase (A-Z)"
+ "message": "ตัวพิมพ์ใหญ่ (A-Z)"
},
"lowercase": {
- "message": "Lowercase (a-z)"
+ "message": "ตัวพิมพ์เล็ก (a-z)"
},
"numbers": {
- "message": "Numbers (0-9)"
+ "message": "หมายเลข (0-9)"
},
"specialCharacters": {
- "message": "Special Characters (!@#$%^&*)"
+ "message": "อักขระพิเศษ (!@#$%^&*)"
},
"numWords": {
"message": "Number of Words"
@@ -419,7 +419,7 @@
"message": "Word Separator"
},
"capitalize": {
- "message": "Capitalize",
+ "message": "ขึ้นต้นด้วยตัวพิมพ์ใหญ่",
"description": "Make the first letter of a work uppercase."
},
"includeNumber": {
@@ -563,19 +563,19 @@
"message": "Send a verification code to your email"
},
"sendCode": {
- "message": "Send Code"
+ "message": "ส่งรหัส"
},
"codeSent": {
- "message": "Code Sent"
+ "message": "ส่งรหัสแล้ว"
},
"verificationCode": {
"message": "รหัสยืนยัน"
},
"confirmIdentity": {
- "message": "Confirm your identity to continue."
+ "message": "ยืนยันตัวตนของคุณเพื่อดำเนินการต่อ"
},
"verificationCodeRequired": {
- "message": "Verification code is required."
+ "message": "จำเป็นต้องมีรหัสการตรวจสอบยืนยัน"
},
"invalidVerificationCode": {
"message": "Invalid verification code"
@@ -758,16 +758,16 @@
"message": "ตัวสร้างรหัสผ่าน"
},
"contactUs": {
- "message": "Contact Us"
+ "message": "ติดต่อเรา"
},
"getHelp": {
- "message": "Get Help"
+ "message": "ขอความช่วยเหลือ"
},
"fileBugReport": {
"message": "File a Bug Report"
},
"blog": {
- "message": "Blog"
+ "message": "บล็อก"
},
"followUs": {
"message": "Follow Us"
@@ -779,7 +779,7 @@
"message": "เปลี่ยนรหัสผ่านหลัก"
},
"changeMasterPasswordConfirmation": {
- "message": "You can change your master password on the bitwarden.com web vault. Do you want to visit the website now?"
+ "message": "คุณสามารถเปลี่ยนรหัสผ่านหลักของคุณได้ที่เว็บ bitwarden.com คุณต้องการไปที่เว็บไซต์ตอนนี้ไหม?"
},
"fingerprintPhrase": {
"message": "Fingerprint Phrase",
@@ -799,19 +799,19 @@
"message": "Get Browser Extension"
},
"syncingComplete": {
- "message": "Syncing complete"
+ "message": "การซิงก์เสร็จสมบูรณ์"
},
"syncingFailed": {
- "message": "Syncing failed"
+ "message": "การซิงก์ล้มเหลว"
},
"yourVaultIsLocked": {
- "message": "Your vault is locked. Verify your identity to continue."
+ "message": "ตู้เซฟของคุณถูกล็อก ยืนยันตัวตนของคุณเพื่อดำเนินการต่อ"
},
"unlock": {
- "message": "Unlock"
+ "message": "ปลดล็อค"
},
"loggedInAsOn": {
- "message": "Logged in as $EMAIL$ on $HOSTNAME$.",
+ "message": "ล็อกอินด้วย $EMAIL$ บน $HOSTNAME$",
"placeholders": {
"email": {
"content": "$1",
@@ -824,10 +824,10 @@
}
},
"invalidMasterPassword": {
- "message": "Invalid master password"
+ "message": "รหัสผ่านหลักไม่ถูกต้อง"
},
"twoStepLoginConfirmation": {
- "message": "Two-step login makes your account more secure by requiring you to verify your login with another device such as a security key, authenticator app, SMS, phone call, or email. Two-step login can be enabled on the bitwarden.com web vault. Do you want to visit the website now?"
+ "message": "การเข้าสู่ระบบแบบสองขั้นตอนทำให้บัญชีของคุณมีความปลอดภัยมากขึ้นด้วยการให้คุณตรวจสอบการเข้าสู่ระบบของคุณกับอุปกรณ์อื่นเช่นคีย์ความปลอดภัย, แอพ authenticator, SMS, โทรศัพท์หรืออีเมล. เข้าสู่ระบบแบบสองขั้นตอนสามารถเปิดใช้งานบน เว็บนิรภัย bitwarden.com คุณต้องการเยี่ยมชมเว็บไซต์เดี๋ยวนี้หรือไม่"
},
"twoStepLogin": {
"message": "เข้าสู่ระบบแบบสองขั้นตอน"
@@ -842,19 +842,19 @@
"message": "ทันที"
},
"tenSeconds": {
- "message": "10 seconds"
+ "message": "10 วินาที"
},
"twentySeconds": {
- "message": "20 seconds"
+ "message": "20 วินาที"
},
"thirtySeconds": {
- "message": "30 seconds"
+ "message": "30 วินาที"
},
"oneMinute": {
"message": "1 นาที"
},
"twoMinutes": {
- "message": "2 minutes"
+ "message": "2 นาที"
},
"fiveMinutes": {
"message": "5 นาที"
@@ -884,13 +884,13 @@
"message": "On Restart"
},
"never": {
- "message": "Never"
+ "message": "ไม่อีกเลย"
},
"security": {
- "message": "Security"
+ "message": "ความปลอดภัย"
},
"clearClipboard": {
- "message": "Clear clipboard",
+ "message": "ล้างคลิปบอร์ด",
"description": "Clipboard is the operating system thing where you copy/paste data to on your device."
},
"clearClipboardDesc": {
@@ -898,7 +898,7 @@
"description": "Clipboard is the operating system thing where you copy/paste data to on your device."
},
"enableFavicon": {
- "message": "Show website icons"
+ "message": "โชว์ไอคอนเว็บไซต์"
},
"faviconDesc": {
"message": "Show a recognizable image next to each login."
@@ -964,23 +964,23 @@
"message": "Disabling this setting will also disable all other tray related settings."
},
"language": {
- "message": "Language"
+ "message": "ภาษา"
},
"languageDesc": {
- "message": "Change the language used by the application. Restart is required."
+ "message": "การเปลี่ยนภาษาของแอพพลิเคชั่น จำเป็นต้องรีสตาร์ท"
},
"theme": {
- "message": "Theme"
+ "message": "ธีม"
},
"themeDesc": {
"message": "Change the application's color theme."
},
"dark": {
- "message": "Dark",
+ "message": "มืด",
"description": "Dark color"
},
"light": {
- "message": "Light",
+ "message": "สว่าง",
"description": "Light color"
},
"copy": {
@@ -1015,7 +1015,7 @@
"message": "Update Available"
},
"updateAvailableDesc": {
- "message": "An update was found. Do you want to download it now?"
+ "message": "ตรวจพบการอัปเดต คุณต้องการดาวโหลดตอนนี้เลยไหม?"
},
"restart": {
"message": "เริ่มต้นใหม่"
@@ -1030,7 +1030,7 @@
"message": "เกิดข้อผิดพลาดในการอัปเดต"
},
"unknown": {
- "message": "Unknown"
+ "message": "ไม่ทราบ"
},
"copyUsername": {
"message": "คัดลอกชื่อผู้ใช้"
@@ -1056,10 +1056,10 @@
"message": "Refresh Membership"
},
"premiumNotCurrentMember": {
- "message": "You are not currently a premium member."
+ "message": "คุณยังไม่ได้เป็นสมาชิกระดับพรีเมียม"
},
"premiumSignUpAndGet": {
- "message": "Sign up for a premium membership and get:"
+ "message": "สมัครสมาชิกพรีเมี่ยมและรับ:"
},
"premiumSignUpStorage": {
"message": "1 GB of encrypted file storage."
@@ -1259,11 +1259,11 @@
"message": "Hide to Tray"
},
"alwaysOnTop": {
- "message": "Always on Top",
+ "message": "อยู่ด้านบนเสมอ",
"description": "Application window should always stay on top of other windows"
},
"dateUpdated": {
- "message": "Updated",
+ "message": "อัปเดตแล้ว",
"description": "ex. Date this item was updated"
},
"datePasswordUpdated": {
@@ -1299,10 +1299,10 @@
"description": "hCaptcha is the name of a website, should not be translated"
},
"invalidUrl": {
- "message": "Invalid Url"
+ "message": "Url ไม่ถูกต้อง"
},
"done": {
- "message": "Done"
+ "message": "เสร็จสิ้น"
},
"accessibilityCookieSaved": {
"message": "Accessibility cookie saved!"
@@ -1311,7 +1311,7 @@
"message": "No accessibility cookie saved"
},
"warning": {
- "message": "WARNING",
+ "message": "คำเตือน",
"description": "WARNING (should stay in capitalized letters if the language permits)"
},
"confirmVaultExport": {
@@ -1333,21 +1333,21 @@
"message": "There are no collections to list."
},
"ownership": {
- "message": "Ownership"
+ "message": "ความเป็นเจ้าของ"
},
"whoOwnsThisItem": {
- "message": "Who owns this item?"
+ "message": "ใครเป็นเจ้าของรายการนี้?"
},
"strong": {
- "message": "Strong",
+ "message": "แข็งแรง",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
- "message": "Good",
+ "message": "ไม่เลว",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
- "message": "Weak",
+ "message": "ง่ายเกินไป",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
@@ -1361,19 +1361,19 @@
"description": "PIN code. Ex. The short code (often numeric) that you use to unlock a device."
},
"unlockWithPin": {
- "message": "Unlock with PIN"
+ "message": "ปลดล็อกด้วย PIN"
},
"setYourPinCode": {
"message": "Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application."
},
"pinRequired": {
- "message": "PIN code is required."
+ "message": "กรุณาใส่รหัส PIN"
},
"invalidPin": {
- "message": "Invalid PIN code."
+ "message": "PIN ไม่ถูกต้อง"
},
"unlockWithWindowsHello": {
- "message": "Unlock with Windows Hello"
+ "message": "ปลดล็อก ด้วย Windows Hello"
},
"windowsHelloConsentMessage": {
"message": "Verify for Bitwarden."
@@ -1394,7 +1394,7 @@
"message": "Lock with master password on restart"
},
"deleteAccount": {
- "message": "Delete account"
+ "message": "ลบบัญชีผู้ใช้"
},
"deleteAccountDesc": {
"message": "Proceed below to delete your account and all vault data."
@@ -1403,13 +1403,13 @@
"message": "Deleting your account is permanent. It cannot be undone."
},
"accountDeleted": {
- "message": "Account deleted"
+ "message": "ลบบัญชีผู้ใช้แล้ว"
},
"accountDeletedDesc": {
"message": "Your account has been closed and all associated data has been deleted."
},
"preferences": {
- "message": "Preferences"
+ "message": "การตั้งค่า"
},
"enableMenuBar": {
"message": "Show menu bar icon"
@@ -1437,7 +1437,7 @@
"description": "Noun. As in 'legal documents', like our terms of service and privacy policy."
},
"termsOfService": {
- "message": "Terms of Service"
+ "message": "เงื่อนไขการใช้บริการ"
},
"privacyPolicy": {
"message": "Privacy Policy"
@@ -1505,7 +1505,7 @@
"message": "Enterprise Single Sign-On"
},
"setMasterPassword": {
- "message": "Set Master Password"
+ "message": "ตั้งรหัสผ่านหลัก"
},
"ssoCompleteRegistration": {
"message": "In order to complete logging in with SSO, please set a master password to access and protect your vault."
@@ -1514,7 +1514,7 @@
"message": "New Master Password"
},
"confirmNewMasterPass": {
- "message": "Confirm New Master Password"
+ "message": "ยืนยันรหัสผ่านใหม่"
},
"masterPasswordPolicyInEffect": {
"message": "One or more organization policies require your master password to meet the following requirements:"
@@ -1589,7 +1589,7 @@
"message": "Add an additional layer of security by requiring fingerprint phrase confirmation when establishing a link between your desktop and browser. This requires user action and verification each time a connection is created."
},
"approve": {
- "message": "Approve"
+ "message": "อนุมัติ"
},
"verifyBrowserTitle": {
"message": "Verify browser connection"
@@ -1613,14 +1613,14 @@
"message": "An organization policy is affecting your ownership options."
},
"allSends": {
- "message": "All Sends",
+ "message": "ส่งทั้งหมด",
"description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendTypeFile": {
- "message": "File"
+ "message": "ไฟล์"
},
"sendTypeText": {
- "message": "Text"
+ "message": "ข้อความ"
},
"searchSends": {
"message": "Search Sends",
@@ -1631,13 +1631,13 @@
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"myVault": {
- "message": "My Vault"
+ "message": "ตู้เซฟของฉัน"
},
"text": {
- "message": "Text"
+ "message": "ข้อความ"
},
"deletionDate": {
- "message": "Deletion Date"
+ "message": "ถูกลบเมื่อวันที่"
},
"deletionDateDesc": {
"message": "The Send will be permanently deleted on the specified date and time.",
@@ -1674,7 +1674,7 @@
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendLink": {
- "message": "Send link",
+ "message": "ส่งลิงก์",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendLinkLabel": {
@@ -1715,7 +1715,7 @@
"message": "The file you want to send."
},
"days": {
- "message": "$DAYS$ days",
+ "message": "$DAYS$ วัน",
"placeholders": {
"days": {
"content": "$1",
diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json
index eef6c908477..a840594b06e 100644
--- a/apps/desktop/src/locales/uk/messages.json
+++ b/apps/desktop/src/locales/uk/messages.json
@@ -61,7 +61,7 @@
}
},
"moveToOrgDesc": {
- "message": "Виберіть організацію, до якої ви бажаєте перемістити цей запис. При переміщенні до організації власність запису передається тій організації. Ви більше не будете єдиним власником цього запису після переміщення."
+ "message": "Виберіть організацію, до якої ви бажаєте перемістити цей запис. Переміщуючи до організації, власність запису передається тій організації. Ви більше не будете єдиним власником цього запису після переміщення."
},
"attachments": {
"message": "Вкладення"
diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts
index 55c7fb688c5..4d1ac739ef6 100644
--- a/apps/desktop/src/main.ts
+++ b/apps/desktop/src/main.ts
@@ -104,7 +104,7 @@ export class Main {
this.updaterMain = new UpdaterMain(
this.i18nService,
this.windowMain,
- "desktop",
+ "clients",
null,
null,
null,
diff --git a/apps/desktop/src/services/i18n.service.ts b/apps/desktop/src/services/i18n.service.ts
index 7f130faee3d..4a05981e338 100644
--- a/apps/desktop/src/services/i18n.service.ts
+++ b/apps/desktop/src/services/i18n.service.ts
@@ -34,6 +34,7 @@ export class I18nService extends BaseI18nService {
"eo",
"es",
"et",
+ "eu",
"fa",
"fi",
"fil",
diff --git a/apps/web/README.md b/apps/web/README.md
index 569f220fdf9..1193b139a4d 100644
--- a/apps/web/README.md
+++ b/apps/web/README.md
@@ -5,8 +5,8 @@
The Bitwarden web project is an Angular application that powers the web vault (https://vault.bitwarden.com/).
-
-
+
+
diff --git a/apps/web/src/app/accounts/accept-organization.component.ts b/apps/web/src/app/accounts/accept-organization.component.ts
index 1e9e8e32aa0..ae24498ddeb 100644
--- a/apps/web/src/app/accounts/accept-organization.component.ts
+++ b/apps/web/src/app/accounts/accept-organization.component.ts
@@ -5,6 +5,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction";
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
@@ -34,7 +35,8 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent {
private cryptoService: CryptoService,
private policyApiService: PolicyApiServiceAbstraction,
private policyService: PolicyService,
- private logService: LogService
+ private logService: LogService,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {
super(router, platformUtilsService, i18nService, route, stateService);
}
@@ -74,7 +76,7 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent {
request.token = qParams.token;
if (await this.performResetPasswordAutoEnroll(qParams)) {
- const response = await this.apiService.getOrganizationKeys(qParams.organizationId);
+ const response = await this.organizationApiService.getKeys(qParams.organizationId);
if (response == null) {
throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
@@ -92,7 +94,7 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent {
return request;
}
- private async performResetPasswordAutoEnroll(qParams: any): Promise {
+ private async performResetPasswordAutoEnroll(qParams: Params): Promise {
let policyList: Policy[] = null;
try {
const policies = await this.policyApiService.getPoliciesByToken(
diff --git a/apps/web/src/app/accounts/login.component.ts b/apps/web/src/app/accounts/login.component.ts
index 30b09246b06..6a13ff32337 100644
--- a/apps/web/src/app/accounts/login.component.ts
+++ b/apps/web/src/app/accounts/login.component.ts
@@ -26,6 +26,7 @@ import { RouterService, StateService } from "../core";
selector: "app-login",
templateUrl: "login.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class LoginComponent extends BaseLoginComponent {
showResetPasswordAutoEnrollWarning = false;
enforcedPasswordPolicyOptions: MasterPasswordPolicyOptions;
@@ -68,6 +69,7 @@ export class LoginComponent extends BaseLoginComponent {
}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
if (qParams.email != null && qParams.email.indexOf("@") > -1) {
this.email = qParams.email;
diff --git a/apps/web/src/app/accounts/register.component.ts b/apps/web/src/app/accounts/register.component.ts
index 3f5ce3bf7d6..4e700ca4d40 100644
--- a/apps/web/src/app/accounts/register.component.ts
+++ b/apps/web/src/app/accounts/register.component.ts
@@ -27,6 +27,7 @@ import { RouterService } from "../core";
selector: "app-register",
templateUrl: "register.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class RegisterComponent extends BaseRegisterComponent {
email = "";
showCreateOrgMessage = false;
@@ -70,6 +71,7 @@ export class RegisterComponent extends BaseRegisterComponent {
}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
this.route.queryParams.pipe(first()).subscribe((qParams) => {
this.referenceData = new ReferenceEventRequest();
if (qParams.email != null && qParams.email.indexOf("@") > -1) {
diff --git a/apps/web/src/app/accounts/set-password.component.ts b/apps/web/src/app/accounts/set-password.component.ts
index 5b7bc2ec61f..771a71affa4 100644
--- a/apps/web/src/app/accounts/set-password.component.ts
+++ b/apps/web/src/app/accounts/set-password.component.ts
@@ -6,6 +6,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction";
@@ -30,7 +31,8 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
router: Router,
syncService: SyncService,
route: ActivatedRoute,
- stateService: StateService
+ stateService: StateService,
+ organizationApiService: OrganizationApiServiceAbstraction
) {
super(
i18nService,
@@ -44,7 +46,8 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
apiService,
syncService,
route,
- stateService
+ stateService,
+ organizationApiService
);
}
}
diff --git a/apps/web/src/app/accounts/sso.component.ts b/apps/web/src/app/accounts/sso.component.ts
index 35a9458cd4a..111d5f2a366 100644
--- a/apps/web/src/app/accounts/sso.component.ts
+++ b/apps/web/src/app/accounts/sso.component.ts
@@ -17,6 +17,7 @@ import { StateService } from "@bitwarden/common/abstractions/state.service";
selector: "app-sso",
templateUrl: "sso.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class SsoComponent extends BaseSsoComponent {
constructor(
authService: AuthService,
@@ -50,6 +51,7 @@ export class SsoComponent extends BaseSsoComponent {
async ngOnInit() {
super.ngOnInit();
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
if (qParams.identifier != null) {
this.identifier = qParams.identifier;
diff --git a/apps/web/src/app/accounts/trial-initiation/billing.component.ts b/apps/web/src/app/accounts/trial-initiation/billing.component.ts
index 6f02000b958..3cff0c82d29 100644
--- a/apps/web/src/app/accounts/trial-initiation/billing.component.ts
+++ b/apps/web/src/app/accounts/trial-initiation/billing.component.ts
@@ -8,6 +8,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
import { SyncService } from "@bitwarden/common/abstractions/sync.service";
@@ -34,7 +35,8 @@ export class BillingComponent extends OrganizationPlansComponent {
organizationService: OrganizationService,
logService: LogService,
messagingService: MessagingService,
- formBuilder: UntypedFormBuilder
+ formBuilder: UntypedFormBuilder,
+ organizationApiService: OrganizationApiServiceAbstraction
) {
super(
apiService,
@@ -47,7 +49,8 @@ export class BillingComponent extends OrganizationPlansComponent {
organizationService,
logService,
messagingService,
- formBuilder
+ formBuilder,
+ organizationApiService
);
}
diff --git a/apps/web/src/app/accounts/trial-initiation/content/cnet-enterprise-content.component.html b/apps/web/src/app/accounts/trial-initiation/content/cnet-enterprise-content.component.html
new file mode 100644
index 00000000000..b5c16911ab0
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/cnet-enterprise-content.component.html
@@ -0,0 +1,17 @@
+Start Your Enterprise Free Trial Now
+
+
+ Millions of individuals, teams, and organizations worldwide trust Bitwarden for secure password
+ storage and sharing.
+
+
+
+ - Collaborate and share securely
+ - Deploy and manage quickly and easily
+ - Access anywhere on any device
+ - Create your account to get started
+
+
diff --git a/apps/web/src/app/accounts/trial-initiation/content/cnet-enterprise-content.component.ts b/apps/web/src/app/accounts/trial-initiation/content/cnet-enterprise-content.component.ts
new file mode 100644
index 00000000000..4a6de8d3003
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/cnet-enterprise-content.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-cnet-enterprise-content",
+ templateUrl: "cnet-enterprise-content.component.html",
+})
+export class CnetEnterpriseContentComponent {}
diff --git a/apps/web/src/app/accounts/trial-initiation/content/cnet-individual-content.component.html b/apps/web/src/app/accounts/trial-initiation/content/cnet-individual-content.component.html
new file mode 100644
index 00000000000..6e6f545c170
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/cnet-individual-content.component.html
@@ -0,0 +1,17 @@
+Start Your Premium Account Now
+
+
+ Millions of individuals, teams, and organizations worldwide trust Bitwarden for secure password
+ storage and sharing.
+
+
+
+ - Store logins, secure notes, and more
+ - Secure your account with advanced two-step login
+ - Access anywhere on any device
+ - Create your account to get started
+
+
diff --git a/apps/web/src/app/accounts/trial-initiation/content/cnet-individual-content.component.ts b/apps/web/src/app/accounts/trial-initiation/content/cnet-individual-content.component.ts
new file mode 100644
index 00000000000..56d8b37af90
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/cnet-individual-content.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-cnet-individual-content",
+ templateUrl: "cnet-individual-content.component.html",
+})
+export class CnetIndividualContentComponent {}
diff --git a/apps/web/src/app/accounts/trial-initiation/content/cnet-teams-content.component.html b/apps/web/src/app/accounts/trial-initiation/content/cnet-teams-content.component.html
new file mode 100644
index 00000000000..c719c5ac7ce
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/cnet-teams-content.component.html
@@ -0,0 +1,17 @@
+Start Your Teams Free Trial Now
+
+
+ Millions of individuals, teams, and organizations worldwide trust Bitwarden for secure password
+ storage and sharing.
+
+
+
+ - Collaborate and share securely
+ - Deploy and manage quickly and easily
+ - Access anywhere on any device
+ - Create your account to get started
+
+
diff --git a/apps/web/src/app/accounts/trial-initiation/content/cnet-teams-content.component.ts b/apps/web/src/app/accounts/trial-initiation/content/cnet-teams-content.component.ts
new file mode 100644
index 00000000000..ff79a0d37cd
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/cnet-teams-content.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-cnet-teams-content",
+ templateUrl: "cnet-teams-content.component.html",
+})
+export class CnetTeamsContentComponent {}
diff --git a/apps/web/src/app/accounts/trial-initiation/content/default-content.component.html b/apps/web/src/app/accounts/trial-initiation/content/default-content.component.html
new file mode 100644
index 00000000000..46e1fae80df
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/default-content.component.html
@@ -0,0 +1,17 @@
+The Bitwarden Password Manager
+
+
+ Trusted by millions of individuals, teams, and organizations worldwide for secure password
+ storage and sharing.
+
+
+
+ - Store logins, secure notes, and more
+ - Collaborate and share securely
+ - Access anywhere on any device
+ - Create your account to get started
+
+
diff --git a/apps/web/src/app/accounts/trial-initiation/content/default-content.component.ts b/apps/web/src/app/accounts/trial-initiation/content/default-content.component.ts
new file mode 100644
index 00000000000..7ad40b089d1
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/default-content.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-default-content",
+ templateUrl: "default-content.component.html",
+})
+export class DefaultContentComponent {}
diff --git a/apps/web/src/app/accounts/trial-initiation/content/enterprise-content.component.html b/apps/web/src/app/accounts/trial-initiation/content/enterprise-content.component.html
new file mode 100644
index 00000000000..46e1fae80df
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/enterprise-content.component.html
@@ -0,0 +1,17 @@
+The Bitwarden Password Manager
+
+
+ Trusted by millions of individuals, teams, and organizations worldwide for secure password
+ storage and sharing.
+
+
+
+ - Store logins, secure notes, and more
+ - Collaborate and share securely
+ - Access anywhere on any device
+ - Create your account to get started
+
+
diff --git a/apps/web/src/app/accounts/trial-initiation/enterprise-content.component.ts b/apps/web/src/app/accounts/trial-initiation/content/enterprise-content.component.ts
similarity index 100%
rename from apps/web/src/app/accounts/trial-initiation/enterprise-content.component.ts
rename to apps/web/src/app/accounts/trial-initiation/content/enterprise-content.component.ts
diff --git a/apps/web/src/app/accounts/trial-initiation/content/enterprise1-content.component.html b/apps/web/src/app/accounts/trial-initiation/content/enterprise1-content.component.html
new file mode 100644
index 00000000000..46e1fae80df
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/enterprise1-content.component.html
@@ -0,0 +1,17 @@
+The Bitwarden Password Manager
+
+
+ Trusted by millions of individuals, teams, and organizations worldwide for secure password
+ storage and sharing.
+
+
+
+ - Store logins, secure notes, and more
+ - Collaborate and share securely
+ - Access anywhere on any device
+ - Create your account to get started
+
+
diff --git a/apps/web/src/app/accounts/trial-initiation/content/enterprise1-content.component.ts b/apps/web/src/app/accounts/trial-initiation/content/enterprise1-content.component.ts
new file mode 100644
index 00000000000..7b1199eb421
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/enterprise1-content.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-enterprise1-content",
+ templateUrl: "enterprise1-content.component.html",
+})
+export class Enterprise1ContentComponent {}
diff --git a/apps/web/src/app/accounts/trial-initiation/content/enterprise2-content.component.html b/apps/web/src/app/accounts/trial-initiation/content/enterprise2-content.component.html
new file mode 100644
index 00000000000..e0739f58a2d
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/enterprise2-content.component.html
@@ -0,0 +1,17 @@
+Start Your Enterprise Free Trial Now
+
+
+ Millions of individuals, teams, and organizations worldwide trust Bitwarden for secure password
+ storage and sharing.
+
+
+
+ - Collaborate and share securely
+ - Deploy and manage quickly and easily
+ - Access anywhere on any device
+ - Create your account to get started
+
+
diff --git a/apps/web/src/app/accounts/trial-initiation/content/enterprise2-content.component.ts b/apps/web/src/app/accounts/trial-initiation/content/enterprise2-content.component.ts
new file mode 100644
index 00000000000..08dec6190c7
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/enterprise2-content.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-enterprise2-content",
+ templateUrl: "enterprise2-content.component.html",
+})
+export class Enterprise2ContentComponent {}
diff --git a/apps/web/src/app/accounts/trial-initiation/content/logo-cnet.component.html b/apps/web/src/app/accounts/trial-initiation/content/logo-cnet.component.html
new file mode 100644
index 00000000000..4e04cec6da4
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/logo-cnet.component.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ "No more excuses; start using Bitwarden today. The identity you save could be your own. The
+ money definitely will be."
+
+
diff --git a/apps/web/src/app/accounts/trial-initiation/content/logo-cnet.component.ts b/apps/web/src/app/accounts/trial-initiation/content/logo-cnet.component.ts
new file mode 100644
index 00000000000..4f755f66a86
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/logo-cnet.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-logo-cnet",
+ templateUrl: "logo-cnet.component.html",
+})
+export class LogoCnetComponent {}
diff --git a/apps/web/src/app/accounts/trial-initiation/content/logo-forbes.component.html b/apps/web/src/app/accounts/trial-initiation/content/logo-forbes.component.html
new file mode 100644
index 00000000000..34426168324
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/logo-forbes.component.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ “Bitwarden boasts the backing of some of the world's best security experts and an attractive,
+ easy-to-use interface”
+
+
diff --git a/apps/web/src/app/accounts/trial-initiation/content/logo-forbes.component.ts b/apps/web/src/app/accounts/trial-initiation/content/logo-forbes.component.ts
new file mode 100644
index 00000000000..818721fd1e9
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/logo-forbes.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-logo-forbes",
+ templateUrl: "logo-forbes.component.html",
+})
+export class LogoForbesComponent {}
diff --git a/apps/web/src/app/accounts/trial-initiation/content/logo-us-news.component.html b/apps/web/src/app/accounts/trial-initiation/content/logo-us-news.component.html
new file mode 100644
index 00000000000..bd44b56f090
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/logo-us-news.component.html
@@ -0,0 +1,5 @@
+
diff --git a/apps/web/src/app/accounts/trial-initiation/content/logo-us-news.component.ts b/apps/web/src/app/accounts/trial-initiation/content/logo-us-news.component.ts
new file mode 100644
index 00000000000..fb0b1e0c71b
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/logo-us-news.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-logo-us-news",
+ templateUrl: "logo-us-news.component.html",
+})
+export class LogoUSNewsComponent {}
diff --git a/apps/web/src/app/accounts/trial-initiation/content/teams-content.component.html b/apps/web/src/app/accounts/trial-initiation/content/teams-content.component.html
new file mode 100644
index 00000000000..46e1fae80df
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/teams-content.component.html
@@ -0,0 +1,17 @@
+The Bitwarden Password Manager
+
+
+ Trusted by millions of individuals, teams, and organizations worldwide for secure password
+ storage and sharing.
+
+
+
+ - Store logins, secure notes, and more
+ - Collaborate and share securely
+ - Access anywhere on any device
+ - Create your account to get started
+
+
diff --git a/apps/web/src/app/accounts/trial-initiation/teams-content.component.ts b/apps/web/src/app/accounts/trial-initiation/content/teams-content.component.ts
similarity index 100%
rename from apps/web/src/app/accounts/trial-initiation/teams-content.component.ts
rename to apps/web/src/app/accounts/trial-initiation/content/teams-content.component.ts
diff --git a/apps/web/src/app/accounts/trial-initiation/content/teams1-content.component.html b/apps/web/src/app/accounts/trial-initiation/content/teams1-content.component.html
new file mode 100644
index 00000000000..7819ead3ce5
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/teams1-content.component.html
@@ -0,0 +1,17 @@
+Start Your Teams Free Trial Now
+
+
+ Millions of individuals, teams, and organizations worldwide trust Bitwarden for secure password
+ storage and sharing.
+
+
+
+ - Collaborate and share securely
+ - Deploy and manage quickly and easily
+ - Access anywhere on any device
+ - Create your account to get started
+
+
diff --git a/apps/web/src/app/accounts/trial-initiation/content/teams1-content.component.ts b/apps/web/src/app/accounts/trial-initiation/content/teams1-content.component.ts
new file mode 100644
index 00000000000..055ec7fda10
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/teams1-content.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-teams1-content",
+ templateUrl: "teams1-content.component.html",
+})
+export class Teams1ContentComponent {}
diff --git a/apps/web/src/app/accounts/trial-initiation/content/teams2-content.component.html b/apps/web/src/app/accounts/trial-initiation/content/teams2-content.component.html
new file mode 100644
index 00000000000..3145e20d4f8
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/teams2-content.component.html
@@ -0,0 +1,17 @@
+Start Your Free Trial Now
+
+
+ Millions of individuals, teams, and organizations worldwide trust Bitwarden for secure password
+ storage and sharing.
+
+
+
+ - Collaborate and share securely
+ - Deploy and manage quickly and easily
+ - Access anywhere on any device
+ - Create your account to get started
+
+
diff --git a/apps/web/src/app/accounts/trial-initiation/content/teams2-content.component.ts b/apps/web/src/app/accounts/trial-initiation/content/teams2-content.component.ts
new file mode 100644
index 00000000000..394ba90b491
--- /dev/null
+++ b/apps/web/src/app/accounts/trial-initiation/content/teams2-content.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-teams2-content",
+ templateUrl: "teams2-content.component.html",
+})
+export class Teams2ContentComponent {}
diff --git a/apps/web/src/app/accounts/trial-initiation/enterprise-content.component.html b/apps/web/src/app/accounts/trial-initiation/enterprise-content.component.html
deleted file mode 100644
index 239c25fdc91..00000000000
--- a/apps/web/src/app/accounts/trial-initiation/enterprise-content.component.html
+++ /dev/null
@@ -1,11 +0,0 @@
-You've chosen Bitwarden for Enterprise
-
-
What you can do with Bitwarden for Enterprise
-
-
-
-
Collaborate and share securely
-
Deploy and manage quickly and easily
-
Access anywhere on any device
-
Create your account to get started
-
diff --git a/apps/web/src/app/accounts/trial-initiation/families-content.component.html b/apps/web/src/app/accounts/trial-initiation/families-content.component.html
deleted file mode 100644
index c0c6af0be00..00000000000
--- a/apps/web/src/app/accounts/trial-initiation/families-content.component.html
+++ /dev/null
@@ -1,13 +0,0 @@
-You've chosen Bitwarden for Families
-
-
- Trusted by millions of individuals, teams, and organizations worldwide for secure password
- storage and sharing.
-
-
-
-
Collaborate and share securely
-
Deploy and manage quickly and easily
-
Access anywhere on any device
-
Create your account to get started
-
diff --git a/apps/web/src/app/accounts/trial-initiation/families-content.component.ts b/apps/web/src/app/accounts/trial-initiation/families-content.component.ts
deleted file mode 100644
index 1a13be80e67..00000000000
--- a/apps/web/src/app/accounts/trial-initiation/families-content.component.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { Component } from "@angular/core";
-
-@Component({
- selector: "app-families-content",
- templateUrl: "families-content.component.html",
-})
-export class FamiliesContentComponent {}
diff --git a/apps/web/src/app/accounts/trial-initiation/teams-content.component.html b/apps/web/src/app/accounts/trial-initiation/teams-content.component.html
deleted file mode 100644
index 20e547fef13..00000000000
--- a/apps/web/src/app/accounts/trial-initiation/teams-content.component.html
+++ /dev/null
@@ -1,10 +0,0 @@
-You've chosen Bitwarden for Teams
-
-
What you can do with Btiwarden for Teams
-
-
-
Collaborate and share securely
-
Deploy and manage quickly and easily
-
Access anywhere on any device
-
Create your account to get started
-
diff --git a/apps/web/src/app/accounts/trial-initiation/trial-initiation.component.html b/apps/web/src/app/accounts/trial-initiation/trial-initiation.component.html
index c51a1b0277b..b78468133d5 100644
--- a/apps/web/src/app/accounts/trial-initiation/trial-initiation.component.html
+++ b/apps/web/src/app/accounts/trial-initiation/trial-initiation.component.html
@@ -1,19 +1,18 @@
-
{{ "createAccount" | i18n }}
+
{{ "createAccount" | i18n }}
-
-
+
+

-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -44,6 +52,7 @@
diff --git a/apps/web/src/app/accounts/trial-initiation/trial-initiation.component.spec.ts b/apps/web/src/app/accounts/trial-initiation/trial-initiation.component.spec.ts
index 9feda5af50e..f20b407e6bf 100644
--- a/apps/web/src/app/accounts/trial-initiation/trial-initiation.component.spec.ts
+++ b/apps/web/src/app/accounts/trial-initiation/trial-initiation.component.spec.ts
@@ -18,6 +18,8 @@ import { StateService as BaseStateService } from "@bitwarden/common/abstractions
import { PlanType } from "@bitwarden/common/enums/planType";
import { MasterPasswordPolicyOptions } from "@bitwarden/common/models/domain/masterPasswordPolicyOptions";
+import { RouterService } from "../../core";
+
import { TrialInitiationComponent } from "./trial-initiation.component";
import { VerticalStepperComponent } from "./vertical-stepper/vertical-stepper.component";
@@ -84,6 +86,10 @@ describe("TrialInitiationComponent", () => {
provide: VerticalStepperComponent,
useClass: VerticalStepperStubComponent,
},
+ {
+ provide: RouterService,
+ useClass: Substitute.for(),
+ },
],
schemas: [NO_ERRORS_SCHEMA], // Allows child components to be ignored (such as register component)
}).compileComponents();
diff --git a/apps/web/src/app/accounts/trial-initiation/trial-initiation.component.ts b/apps/web/src/app/accounts/trial-initiation/trial-initiation.component.ts
index 1c452cdf5ea..00bbc6e236f 100644
--- a/apps/web/src/app/accounts/trial-initiation/trial-initiation.component.ts
+++ b/apps/web/src/app/accounts/trial-initiation/trial-initiation.component.ts
@@ -15,13 +15,16 @@ import { ProductType } from "@bitwarden/common/enums/productType";
import { PolicyData } from "@bitwarden/common/models/data/policyData";
import { MasterPasswordPolicyOptions } from "@bitwarden/common/models/domain/masterPasswordPolicyOptions";
import { Policy } from "@bitwarden/common/models/domain/policy";
+import { ReferenceEventRequest } from "@bitwarden/common/models/request/referenceEventRequest";
+import { RouterService } from "./../../core/router.service";
import { VerticalStepperComponent } from "./vertical-stepper/vertical-stepper.component";
@Component({
selector: "app-trial",
templateUrl: "trial-initiation.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class TrialInitiationComponent implements OnInit {
email = "";
org = "";
@@ -29,12 +32,14 @@ export class TrialInitiationComponent implements OnInit {
orgId = "";
orgLabel = "";
billingSubLabel = "";
+ layout = "default";
plan: PlanType;
product: ProductType;
accountCreateOnly = true;
policies: Policy[];
enforcedPolicyOptions: MasterPasswordPolicyOptions;
validOrgs: string[] = ["teams", "enterprise", "families"];
+ referenceData: ReferenceEventRequest;
@ViewChild("stepper", { static: false }) verticalStepper: VerticalStepperComponent;
orgInfoFormGroup = this.formBuilder.group({
@@ -42,6 +47,22 @@ export class TrialInitiationComponent implements OnInit {
email: [""],
});
+ private set referenceDataId(referenceId: string) {
+ if (referenceId != null) {
+ this.referenceData.id = referenceId;
+ } else {
+ this.referenceData.id = ("; " + document.cookie)
+ .split("; reference=")
+ .pop()
+ .split(";")
+ .shift();
+ }
+
+ if (this.referenceData.id === "") {
+ this.referenceData.id = null;
+ }
+ }
+
constructor(
private route: ActivatedRoute,
protected router: Router,
@@ -51,25 +72,40 @@ export class TrialInitiationComponent implements OnInit {
private logService: LogService,
private policyApiService: PolicyApiServiceAbstraction,
private policyService: PolicyService,
- private i18nService: I18nService
+ private i18nService: I18nService,
+ private routerService: RouterService
) {}
async ngOnInit(): Promise {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
this.route.queryParams.pipe(first()).subscribe((qParams) => {
+ this.referenceData = new ReferenceEventRequest();
if (qParams.email != null && qParams.email.indexOf("@") > -1) {
this.email = qParams.email;
}
+ this.referenceDataId = qParams.reference;
+
if (!qParams.org) {
return;
}
+ if (qParams.layout) {
+ this.layout = qParams.layout;
+ }
+
if (this.validOrgs.includes(qParams.org)) {
this.org = qParams.org;
} else {
this.org = "families";
}
+ this.referenceData.flow = qParams.org;
+
+ // Are they coming from an email for sponsoring a families organization
+ // After logging in redirect them to setup the families sponsorship
+ this.setupFamilySponsorship(qParams.sponsorshipToken);
+
this.orgLabel = this.titleCasePipe.transform(this.org);
this.accountCreateOnly = false;
@@ -148,4 +184,13 @@ export class TrialInitiationComponent implements OnInit {
previousStep() {
this.verticalStepper.previous();
}
+
+ private setupFamilySponsorship(sponsorshipToken: string) {
+ if (sponsorshipToken != null) {
+ const route = this.router.createUrlTree(["setup/families-for-enterprise"], {
+ queryParams: { plan: sponsorshipToken },
+ });
+ this.routerService.setPreviousUrl(route.toString());
+ }
+ }
}
diff --git a/apps/web/src/app/accounts/trial-initiation/trial-initiation.module.ts b/apps/web/src/app/accounts/trial-initiation/trial-initiation.module.ts
index 8d0ebbb1a78..fb02824222f 100644
--- a/apps/web/src/app/accounts/trial-initiation/trial-initiation.module.ts
+++ b/apps/web/src/app/accounts/trial-initiation/trial-initiation.module.ts
@@ -10,9 +10,19 @@ import { RegisterFormModule } from "../register-form/register-form.module";
import { BillingComponent } from "./billing.component";
import { ConfirmationDetailsComponent } from "./confirmation-details.component";
-import { EnterpriseContentComponent } from "./enterprise-content.component";
-import { FamiliesContentComponent } from "./families-content.component";
-import { TeamsContentComponent } from "./teams-content.component";
+import { CnetEnterpriseContentComponent } from "./content/cnet-enterprise-content.component";
+import { CnetIndividualContentComponent } from "./content/cnet-individual-content.component";
+import { CnetTeamsContentComponent } from "./content/cnet-teams-content.component";
+import { DefaultContentComponent } from "./content/default-content.component";
+import { EnterpriseContentComponent } from "./content/enterprise-content.component";
+import { Enterprise1ContentComponent } from "./content/enterprise1-content.component";
+import { Enterprise2ContentComponent } from "./content/enterprise2-content.component";
+import { LogoCnetComponent } from "./content/logo-cnet.component";
+import { LogoForbesComponent } from "./content/logo-forbes.component";
+import { LogoUSNewsComponent } from "./content/logo-us-news.component";
+import { TeamsContentComponent } from "./content/teams-content.component";
+import { Teams1ContentComponent } from "./content/teams1-content.component";
+import { Teams2ContentComponent } from "./content/teams2-content.component";
import { TrialInitiationComponent } from "./trial-initiation.component";
import { VerticalStepperModule } from "./vertical-stepper/vertical-stepper.module";
@@ -29,10 +39,22 @@ import { VerticalStepperModule } from "./vertical-stepper/vertical-stepper.modul
declarations: [
TrialInitiationComponent,
EnterpriseContentComponent,
- FamiliesContentComponent,
TeamsContentComponent,
ConfirmationDetailsComponent,
BillingComponent,
+ DefaultContentComponent,
+ EnterpriseContentComponent,
+ Enterprise1ContentComponent,
+ Enterprise2ContentComponent,
+ TeamsContentComponent,
+ Teams1ContentComponent,
+ Teams2ContentComponent,
+ CnetEnterpriseContentComponent,
+ CnetIndividualContentComponent,
+ CnetTeamsContentComponent,
+ LogoCnetComponent,
+ LogoForbesComponent,
+ LogoUSNewsComponent,
],
exports: [TrialInitiationComponent],
providers: [TitleCasePipe],
diff --git a/apps/web/src/app/accounts/two-factor.component.ts b/apps/web/src/app/accounts/two-factor.component.ts
index 1d9b19af213..5ebf3ea02ed 100644
--- a/apps/web/src/app/accounts/two-factor.component.ts
+++ b/apps/web/src/app/accounts/two-factor.component.ts
@@ -22,6 +22,7 @@ import { TwoFactorOptionsComponent } from "./two-factor-options.component";
selector: "app-two-factor",
templateUrl: "two-factor.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class TwoFactorComponent extends BaseTwoFactorComponent {
@ViewChild("twoFactorOptions", { read: ViewContainerRef, static: true })
twoFactorOptionsModal: ViewContainerRef;
@@ -63,11 +64,13 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
TwoFactorOptionsComponent,
this.twoFactorOptionsModal,
(comp) => {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
comp.onProviderSelected.subscribe(async (provider: TwoFactorProviderType) => {
modal.close();
this.selectedProviderType = provider;
await this.init();
});
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onRecoverSelected.subscribe(() => {
modal.close();
});
diff --git a/apps/web/src/app/accounts/verify-email-token.component.ts b/apps/web/src/app/accounts/verify-email-token.component.ts
index 90983f7cf00..c0ebfa78d7f 100644
--- a/apps/web/src/app/accounts/verify-email-token.component.ts
+++ b/apps/web/src/app/accounts/verify-email-token.component.ts
@@ -13,6 +13,7 @@ import { VerifyEmailRequest } from "@bitwarden/common/models/request/verifyEmail
selector: "app-verify-email-token",
templateUrl: "verify-email-token.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class VerifyEmailTokenComponent implements OnInit {
constructor(
private router: Router,
@@ -25,6 +26,7 @@ export class VerifyEmailTokenComponent implements OnInit {
) {}
ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
if (qParams.userId != null && qParams.token != null) {
try {
diff --git a/apps/web/src/app/accounts/verify-recover-delete.component.ts b/apps/web/src/app/accounts/verify-recover-delete.component.ts
index 3deadbd4d47..7139e4d10e7 100644
--- a/apps/web/src/app/accounts/verify-recover-delete.component.ts
+++ b/apps/web/src/app/accounts/verify-recover-delete.component.ts
@@ -12,6 +12,7 @@ import { VerifyDeleteRecoverRequest } from "@bitwarden/common/models/request/ver
selector: "app-verify-recover-delete",
templateUrl: "verify-recover-delete.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class VerifyRecoverDeleteComponent implements OnInit {
email: string;
formPromise: Promise;
@@ -29,6 +30,7 @@ export class VerifyRecoverDeleteComponent implements OnInit {
) {}
ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
if (qParams.userId != null && qParams.token != null && qParams.email != null) {
this.userId = qParams.userId;
diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts
index ef80dc5e736..ae9107ea0ec 100644
--- a/apps/web/src/app/app.component.ts
+++ b/apps/web/src/app/app.component.ts
@@ -215,7 +215,7 @@ export class AppComponent implements OnDestroy, OnInit {
ngOnDestroy() {
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
this.destroy$.next();
- this.destroy$.unsubscribe();
+ this.destroy$.complete();
}
private async logOut(expired: boolean) {
diff --git a/apps/web/src/app/common/base.accept.component.ts b/apps/web/src/app/common/base.accept.component.ts
index 907d7410f8b..dcca9e061c1 100644
--- a/apps/web/src/app/common/base.accept.component.ts
+++ b/apps/web/src/app/common/base.accept.component.ts
@@ -29,6 +29,7 @@ export abstract class BaseAcceptComponent implements OnInit {
abstract unauthedHandler(qParams: Params): Promise;
ngOnInit() {
+ // eslint-disable-next-line rxjs/no-async-subscribe
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
let error = this.requiredParameters.some((e) => qParams?.[e] == null || qParams[e] === "");
let errorMessage: string = null;
diff --git a/apps/web/src/app/common/base.people.component.ts b/apps/web/src/app/common/base.people.component.ts
index b1aab35b322..6b9370ae814 100644
--- a/apps/web/src/app/common/base.people.component.ts
+++ b/apps/web/src/app/common/base.people.component.ts
@@ -85,7 +85,7 @@ export abstract class BasePeopleComponent<
users: UserType[] = [];
pagedUsers: UserType[] = [];
searchText: string;
- actionPromise: Promise;
+ actionPromise: Promise;
protected allUsers: UserType[] = [];
protected activeUsers: UserType[] = [];
@@ -111,11 +111,11 @@ export abstract class BasePeopleComponent<
abstract edit(user: UserType): void;
abstract getUsers(): Promise>;
- abstract deleteUser(id: string): Promise;
- abstract revokeUser(id: string): Promise;
- abstract restoreUser(id: string): Promise;
- abstract reinviteUser(id: string): Promise;
- abstract confirmUser(user: UserType, publicKey: Uint8Array): Promise;
+ abstract deleteUser(id: string): Promise;
+ abstract revokeUser(id: string): Promise;
+ abstract restoreUser(id: string): Promise;
+ abstract reinviteUser(id: string): Promise;
+ abstract confirmUser(user: UserType, publicKey: Uint8Array): Promise;
async load() {
const response = await this.getUsers();
@@ -343,6 +343,7 @@ export abstract class BasePeopleComponent<
comp.name = this.userNamePipe.transform(user);
comp.userId = user != null ? user.userId : null;
comp.publicKey = publicKey;
+ // eslint-disable-next-line rxjs/no-async-subscribe
comp.onConfirmedUser.subscribe(async () => {
try {
comp.formPromise = confirmUser(publicKey);
diff --git a/apps/web/src/app/components/user-verification-prompt.component.html b/apps/web/src/app/components/user-verification-prompt.component.html
new file mode 100644
index 00000000000..37e2ce87cf5
--- /dev/null
+++ b/apps/web/src/app/components/user-verification-prompt.component.html
@@ -0,0 +1,26 @@
+
diff --git a/apps/web/src/app/components/user-verification-prompt.component.ts b/apps/web/src/app/components/user-verification-prompt.component.ts
new file mode 100644
index 00000000000..e057193affc
--- /dev/null
+++ b/apps/web/src/app/components/user-verification-prompt.component.ts
@@ -0,0 +1,8 @@
+import { Component } from "@angular/core";
+
+import { UserVerificationPromptComponent as BaseUserVerificationPrompt } from "@bitwarden/angular/components/user-verification-prompt.component";
+
+@Component({
+ templateUrl: "user-verification-prompt.component.html",
+})
+export class UserVerificationPromptComponent extends BaseUserVerificationPrompt {}
diff --git a/apps/web/src/app/core/i18n.service.ts b/apps/web/src/app/core/i18n.service.ts
index 5d6d40191b8..b60efef36ba 100644
--- a/apps/web/src/app/core/i18n.service.ts
+++ b/apps/web/src/app/core/i18n.service.ts
@@ -33,6 +33,7 @@ export class I18nService extends BaseI18nService {
"eo",
"es",
"et",
+ "eu",
"fi",
"fil",
"fr",
diff --git a/apps/web/src/app/layouts/navbar.component.ts b/apps/web/src/app/layouts/navbar.component.ts
index c5a6b03cad5..bbd4644bdb3 100644
--- a/apps/web/src/app/layouts/navbar.component.ts
+++ b/apps/web/src/app/layouts/navbar.component.ts
@@ -18,6 +18,7 @@ import { canAccessOrgAdmin } from "../organizations/navigation-permissions";
selector: "app-navbar",
templateUrl: "navbar.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class NavbarComponent implements OnInit {
selfHosted = false;
name: string;
diff --git a/apps/web/src/app/organizations/billing/billing-sync-api-key.component.ts b/apps/web/src/app/organizations/billing/billing-sync-api-key.component.ts
index 5b36a69e172..d93e1654d5c 100644
--- a/apps/web/src/app/organizations/billing/billing-sync-api-key.component.ts
+++ b/apps/web/src/app/organizations/billing/billing-sync-api-key.component.ts
@@ -2,6 +2,7 @@ import { Component } from "@angular/core";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
import { OrganizationApiKeyType } from "@bitwarden/common/enums/organizationApiKeyType";
@@ -28,7 +29,8 @@ export class BillingSyncApiKeyComponent {
private userVerificationService: UserVerificationService,
private apiService: ApiService,
private platformUtilsService: PlatformUtilsService,
- private i18nService: I18nService
+ private i18nService: I18nService,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {}
copy() {
@@ -41,7 +43,7 @@ export class BillingSyncApiKeyComponent {
.buildRequest(this.masterPassword, OrganizationApiKeyRequest)
.then((request) => {
request.type = OrganizationApiKeyType.BillingSync;
- return this.apiService.postOrganizationRotateApiKey(this.organizationId, request);
+ return this.organizationApiService.rotateApiKey(this.organizationId, request);
});
const response = await this.formPromise;
await this.load(response);
@@ -56,7 +58,7 @@ export class BillingSyncApiKeyComponent {
.buildRequest(this.masterPassword, OrganizationApiKeyRequest)
.then((request) => {
request.type = OrganizationApiKeyType.BillingSync;
- return this.apiService.postOrganizationApiKey(this.organizationId, request);
+ return this.organizationApiService.getOrCreateApiKey(this.organizationId, request);
});
const response = await this.formPromise;
await this.load(response);
diff --git a/apps/web/src/app/organizations/billing/organization-subscription.component.ts b/apps/web/src/app/organizations/billing/organization-subscription.component.ts
index dc1dd0a1a4e..cf80ff2af1c 100644
--- a/apps/web/src/app/organizations/billing/organization-subscription.component.ts
+++ b/apps/web/src/app/organizations/billing/organization-subscription.component.ts
@@ -8,6 +8,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { OrganizationApiKeyType } from "@bitwarden/common/enums/organizationApiKeyType";
import { OrganizationConnectionType } from "@bitwarden/common/enums/organizationConnectionType";
@@ -25,6 +26,7 @@ import { BillingSyncApiKeyComponent } from "./billing-sync-api-key.component";
selector: "app-org-subscription",
templateUrl: "organization-subscription.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class OrganizationSubscriptionComponent implements OnInit {
@ViewChild("setupBillingSyncTemplate", { read: ViewContainerRef, static: true })
setupBillingSyncModalRef: ViewContainerRef;
@@ -48,9 +50,9 @@ export class OrganizationSubscriptionComponent implements OnInit {
userOrg: Organization;
existingBillingSyncConnection: OrganizationConnectionResponse;
- removeSponsorshipPromise: Promise;
- cancelPromise: Promise;
- reinstatePromise: Promise;
+ removeSponsorshipPromise: Promise;
+ cancelPromise: Promise;
+ reinstatePromise: Promise;
@ViewChild("rotateBillingSyncKeyTemplate", { read: ViewContainerRef, static: true })
billingSyncKeyViewContainerRef: ViewContainerRef;
@@ -64,12 +66,14 @@ export class OrganizationSubscriptionComponent implements OnInit {
private route: ActivatedRoute,
private organizationService: OrganizationService,
private logService: LogService,
- private modalService: ModalService
+ private modalService: ModalService,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {
this.selfHosted = platformUtilsService.isSelfHost();
}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
await this.load();
@@ -85,9 +89,9 @@ export class OrganizationSubscriptionComponent implements OnInit {
this.loading = true;
this.userOrg = await this.organizationService.get(this.organizationId);
if (this.userOrg.canManageBilling) {
- this.sub = await this.apiService.getOrganizationSubscription(this.organizationId);
+ this.sub = await this.organizationApiService.getSubscription(this.organizationId);
}
- const apiKeyResponse = await this.apiService.getOrganizationApiKeyInformation(
+ const apiKeyResponse = await this.organizationApiService.getApiKeyInformation(
this.organizationId
);
this.hasBillingSyncToken = apiKeyResponse.data.some(
@@ -125,7 +129,7 @@ export class OrganizationSubscriptionComponent implements OnInit {
}
try {
- this.reinstatePromise = this.apiService.postOrganizationReinstate(this.organizationId);
+ this.reinstatePromise = this.organizationApiService.reinstate(this.organizationId);
await this.reinstatePromise;
this.platformUtilsService.showToast("success", null, this.i18nService.t("reinstated"));
this.load();
@@ -151,7 +155,7 @@ export class OrganizationSubscriptionComponent implements OnInit {
}
try {
- this.cancelPromise = this.apiService.postOrganizationCancel(this.organizationId);
+ this.cancelPromise = this.organizationApiService.cancel(this.organizationId);
await this.cancelPromise;
this.platformUtilsService.showToast(
"success",
@@ -185,6 +189,7 @@ export class OrganizationSubscriptionComponent implements OnInit {
comp.hasBillingToken = this.hasBillingSyncToken;
}
);
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
ref.onClosed.subscribe(async () => {
await this.load();
});
diff --git a/apps/web/src/app/organizations/layouts/organization-layout.component.ts b/apps/web/src/app/organizations/layouts/organization-layout.component.ts
index 107fef459a9..48fde0d2b9d 100644
--- a/apps/web/src/app/organizations/layouts/organization-layout.component.ts
+++ b/apps/web/src/app/organizations/layouts/organization-layout.component.ts
@@ -33,6 +33,7 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
ngOnInit() {
document.body.classList.remove("layout_frontend");
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.params.subscribe(async (params: any) => {
this.organizationId = params.organizationId;
await this.load();
diff --git a/apps/web/src/app/organizations/manage/collections.component.ts b/apps/web/src/app/organizations/manage/collections.component.ts
index e935e7b10b0..04867a4eabe 100644
--- a/apps/web/src/app/organizations/manage/collections.component.ts
+++ b/apps/web/src/app/organizations/manage/collections.component.ts
@@ -27,6 +27,7 @@ import { EntityUsersComponent } from "./entity-users.component";
selector: "app-org-manage-collections",
templateUrl: "collections.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class CollectionsComponent implements OnInit {
@ViewChild("addEdit", { read: ViewContainerRef, static: true }) addEditModalRef: ViewContainerRef;
@ViewChild("usersTemplate", { read: ViewContainerRef, static: true })
@@ -59,9 +60,11 @@ export class CollectionsComponent implements OnInit {
) {}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
await this.load();
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe, rxjs/no-nested-subscribe
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
this.searchText = qParams.search;
});
@@ -131,10 +134,12 @@ export class CollectionsComponent implements OnInit {
comp.collectionId = collection != null ? collection.id : null;
comp.canSave = canCreate || canEdit;
comp.canDelete = canDelete;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onSavedCollection.subscribe(() => {
modal.close();
this.load();
});
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onDeletedCollection.subscribe(() => {
modal.close();
this.removeCollection(collection);
@@ -183,6 +188,7 @@ export class CollectionsComponent implements OnInit {
comp.entityId = collection.id;
comp.entityName = collection.name;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onEditedUsers.subscribe(() => {
this.load();
modal.close();
diff --git a/apps/web/src/app/organizations/manage/events.component.ts b/apps/web/src/app/organizations/manage/events.component.ts
index e16d7c4b6dd..6573543d0d0 100644
--- a/apps/web/src/app/organizations/manage/events.component.ts
+++ b/apps/web/src/app/organizations/manage/events.component.ts
@@ -20,6 +20,7 @@ import { EventService } from "../../core";
selector: "app-org-events",
templateUrl: "events.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class EventsComponent extends BaseEventsComponent implements OnInit {
exportFileName = "org-events";
organizationId: string;
@@ -52,6 +53,7 @@ export class EventsComponent extends BaseEventsComponent implements OnInit {
}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
this.organization = await this.organizationService.get(this.organizationId);
diff --git a/apps/web/src/app/organizations/manage/groups.component.ts b/apps/web/src/app/organizations/manage/groups.component.ts
index 0f95da5d811..419e3ab6410 100644
--- a/apps/web/src/app/organizations/manage/groups.component.ts
+++ b/apps/web/src/app/organizations/manage/groups.component.ts
@@ -18,6 +18,7 @@ import { GroupAddEditComponent } from "./group-add-edit.component";
selector: "app-org-groups",
templateUrl: "groups.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class GroupsComponent implements OnInit {
@ViewChild("addEdit", { read: ViewContainerRef, static: true }) addEditModalRef: ViewContainerRef;
@ViewChild("usersTemplate", { read: ViewContainerRef, static: true })
@@ -45,9 +46,11 @@ export class GroupsComponent implements OnInit {
) {}
async ngOnInit() {
- this.route.parent.params.subscribe(async (params) => {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
+ this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
await this.load();
+ /* eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe, rxjs/no-nested-subscribe */
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
this.searchText = qParams.search;
});
@@ -88,10 +91,12 @@ export class GroupsComponent implements OnInit {
(comp) => {
comp.organizationId = this.organizationId;
comp.groupId = group != null ? group.id : null;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onSavedGroup.subscribe(() => {
modal.close();
this.load();
});
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onDeletedGroup.subscribe(() => {
modal.close();
this.removeGroup(group);
@@ -139,6 +144,7 @@ export class GroupsComponent implements OnInit {
comp.entityId = group.id;
comp.entityName = group.name;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onEditedUsers.subscribe(() => {
modal.close();
});
diff --git a/apps/web/src/app/organizations/manage/manage.component.ts b/apps/web/src/app/organizations/manage/manage.component.ts
index f9026f55707..f1e25092596 100644
--- a/apps/web/src/app/organizations/manage/manage.component.ts
+++ b/apps/web/src/app/organizations/manage/manage.component.ts
@@ -8,12 +8,14 @@ import { Organization } from "@bitwarden/common/models/domain/organization";
selector: "app-org-manage",
templateUrl: "manage.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class ManageComponent implements OnInit {
organization: Organization;
constructor(private route: ActivatedRoute, private organizationService: OrganizationService) {}
ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.params.subscribe(async (params) => {
this.organization = await this.organizationService.get(params.organizationId);
});
diff --git a/apps/web/src/app/organizations/manage/people.component.ts b/apps/web/src/app/organizations/manage/people.component.ts
index 48a2790cff2..84877602493 100644
--- a/apps/web/src/app/organizations/manage/people.component.ts
+++ b/apps/web/src/app/organizations/manage/people.component.ts
@@ -11,6 +11,7 @@ import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction";
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
@@ -42,6 +43,7 @@ import { UserGroupsComponent } from "./user-groups.component";
selector: "app-org-people",
templateUrl: "people.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class PeopleComponent
extends BasePeopleComponent
implements OnInit
@@ -92,7 +94,8 @@ export class PeopleComponent
userNamePipe: UserNamePipe,
private syncService: SyncService,
stateService: StateService,
- private organizationService: OrganizationService
+ private organizationService: OrganizationService,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {
super(
apiService,
@@ -110,7 +113,8 @@ export class PeopleComponent
}
async ngOnInit() {
- this.route.parent.params.subscribe(async (params) => {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
+ this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
const organization = await this.organizationService.get(this.organizationId);
this.accessEvents = organization.useEvents;
@@ -125,7 +129,7 @@ export class PeopleComponent
const orgShareKey = await this.cryptoService.getOrgKey(this.organizationId);
const orgKeys = await this.cryptoService.makeKeyPair(orgShareKey);
const request = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
- const response = await this.apiService.postOrganizationKeys(this.organizationId, request);
+ const response = await this.organizationApiService.updateKeys(this.organizationId, request);
if (response != null) {
this.orgHasKeys = response.publicKey != null && response.privateKey != null;
await this.syncService.fullSync(true); // Replace oganizations with new data
@@ -136,6 +140,7 @@ export class PeopleComponent
await this.load();
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe, rxjs/no-nested-subscribe
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
this.searchText = qParams.search;
if (qParams.viewEvents != null) {
@@ -161,26 +166,26 @@ export class PeopleComponent
return this.apiService.getOrganizationUsers(this.organizationId);
}
- deleteUser(id: string): Promise {
+ deleteUser(id: string): Promise {
return this.apiService.deleteOrganizationUser(this.organizationId, id);
}
- revokeUser(id: string): Promise {
+ revokeUser(id: string): Promise {
return this.apiService.revokeOrganizationUser(this.organizationId, id);
}
- restoreUser(id: string): Promise {
+ restoreUser(id: string): Promise {
return this.apiService.restoreOrganizationUser(this.organizationId, id);
}
- reinviteUser(id: string): Promise {
+ reinviteUser(id: string): Promise {
return this.apiService.postOrganizationUserReinvite(this.organizationId, id);
}
async confirmUser(
user: OrganizationUserUserDetailsResponse,
publicKey: Uint8Array
- ): Promise {
+ ): Promise {
const orgKey = await this.cryptoService.getOrgKey(this.organizationId);
const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey.buffer);
const request = new OrganizationUserConfirmRequest();
@@ -235,18 +240,22 @@ export class PeopleComponent
comp.organizationId = this.organizationId;
comp.organizationUserId = user != null ? user.id : null;
comp.usesKeyConnector = user?.usesKeyConnector;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onSavedUser.subscribe(() => {
modal.close();
this.load();
});
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onDeletedUser.subscribe(() => {
modal.close();
this.removeUser(user);
});
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onRevokedUser.subscribe(() => {
modal.close();
this.load();
});
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onRestoredUser.subscribe(() => {
modal.close();
this.load();
@@ -263,6 +272,7 @@ export class PeopleComponent
comp.name = this.userNamePipe.transform(user);
comp.organizationId = this.organizationId;
comp.organizationUserId = user != null ? user.id : null;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onSavedUser.subscribe(() => {
modal.close();
});
@@ -387,6 +397,7 @@ export class PeopleComponent
comp.organizationId = this.organizationId;
comp.id = user != null ? user.id : null;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onPasswordReset.subscribe(() => {
modal.close();
this.load();
@@ -425,6 +436,7 @@ export class PeopleComponent
// Workaround to handle closing the modal shortly after it has been opened
let close = false;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
modal.onShown.subscribe(() => {
if (close) {
modal.close();
diff --git a/apps/web/src/app/organizations/manage/policies.component.ts b/apps/web/src/app/organizations/manage/policies.component.ts
index 17cc3b7bbe6..b9f11322de5 100644
--- a/apps/web/src/app/organizations/manage/policies.component.ts
+++ b/apps/web/src/app/organizations/manage/policies.component.ts
@@ -18,6 +18,7 @@ import { PolicyEditComponent } from "./policy-edit.component";
selector: "app-org-policies",
templateUrl: "policies.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class PoliciesComponent implements OnInit {
@ViewChild("editTemplate", { read: ViewContainerRef, static: true })
editModalRef: ViewContainerRef;
@@ -40,6 +41,7 @@ export class PoliciesComponent implements OnInit {
) {}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
this.organization = await this.organizationService.get(this.organizationId);
@@ -48,6 +50,7 @@ export class PoliciesComponent implements OnInit {
await this.load();
// Handle policies component launch from Event message
+ /* eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe, rxjs/no-nested-subscribe */
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
if (qParams.policyId != null) {
const policyIdFromEvents: string = qParams.policyId;
@@ -85,6 +88,7 @@ export class PoliciesComponent implements OnInit {
comp.policy = policy;
comp.organizationId = this.organizationId;
comp.policiesEnabledMap = this.policiesEnabledMap;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onSavedPolicy.subscribe(() => {
modal.close();
this.load();
diff --git a/apps/web/src/app/organizations/settings/account.component.ts b/apps/web/src/app/organizations/settings/account.component.ts
index dc2d9581643..cf4a5afdf70 100644
--- a/apps/web/src/app/organizations/settings/account.component.ts
+++ b/apps/web/src/app/organizations/settings/account.component.ts
@@ -7,6 +7,7 @@ import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SyncService } from "@bitwarden/common/abstractions/sync.service";
import { OrganizationKeysRequest } from "@bitwarden/common/models/request/organizationKeysRequest";
@@ -22,6 +23,7 @@ import { DeleteOrganizationComponent } from "./delete-organization.component";
selector: "app-org-account",
templateUrl: "account.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class AccountComponent {
@ViewChild("deleteOrganizationTemplate", { read: ViewContainerRef, static: true })
deleteModalRef: ViewContainerRef;
@@ -37,7 +39,8 @@ export class AccountComponent {
loading = true;
canUseApi = false;
org: OrganizationResponse;
- formPromise: Promise;
+ formPromise: Promise;
+ taxFormPromise: Promise;
private organizationId: string;
@@ -51,19 +54,21 @@ export class AccountComponent {
private cryptoService: CryptoService,
private logService: LogService,
private router: Router,
- private organizationService: OrganizationService
+ private organizationService: OrganizationService,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {}
async ngOnInit() {
this.selfHosted = this.platformUtilsService.isSelfHost();
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
this.canManageBilling = (
await this.organizationService.get(this.organizationId)
).canManageBilling;
try {
- this.org = await this.apiService.getOrganization(this.organizationId);
+ this.org = await this.organizationApiService.get(this.organizationId);
this.canUseApi = this.org.useApi;
} catch (e) {
this.logService.error(e);
@@ -87,7 +92,7 @@ export class AccountComponent {
request.keys = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
}
- this.formPromise = this.apiService.putOrganization(this.organizationId, request).then(() => {
+ this.formPromise = this.organizationApiService.save(this.organizationId, request).then(() => {
return this.syncService.fullSync(true);
});
await this.formPromise;
@@ -107,6 +112,7 @@ export class AccountComponent {
this.deleteModalRef,
(comp) => {
comp.organizationId = this.organizationId;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onSuccess.subscribe(() => {
this.router.navigate(["/"]);
});
@@ -124,7 +130,9 @@ export class AccountComponent {
await this.modalService.openViewRef(ApiKeyComponent, this.apiKeyModalRef, (comp) => {
comp.keyType = "organization";
comp.entityId = this.organizationId;
- comp.postKey = this.apiService.postOrganizationApiKey.bind(this.apiService);
+ comp.postKey = this.organizationApiService.getOrCreateApiKey.bind(
+ this.organizationApiService
+ );
comp.scope = "api.organization";
comp.grantType = "client_credentials";
comp.apiKeyTitle = "apiKey";
@@ -138,7 +146,7 @@ export class AccountComponent {
comp.keyType = "organization";
comp.isRotation = true;
comp.entityId = this.organizationId;
- comp.postKey = this.apiService.postOrganizationRotateApiKey.bind(this.apiService);
+ comp.postKey = this.organizationApiService.rotateApiKey.bind(this.organizationApiService);
comp.scope = "api.organization";
comp.grantType = "client_credentials";
comp.apiKeyTitle = "apiKey";
diff --git a/apps/web/src/app/organizations/settings/adjust-subscription.component.ts b/apps/web/src/app/organizations/settings/adjust-subscription.component.ts
index 006c735aef4..6930f86068a 100644
--- a/apps/web/src/app/organizations/settings/adjust-subscription.component.ts
+++ b/apps/web/src/app/organizations/settings/adjust-subscription.component.ts
@@ -1,8 +1,8 @@
import { Component, EventEmitter, Input, Output } from "@angular/core";
-import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { OrganizationSubscriptionUpdateRequest } from "@bitwarden/common/models/request/organizationSubscriptionUpdateRequest";
@@ -18,16 +18,16 @@ export class AdjustSubscription {
@Input() interval = "year";
@Output() onAdjusted = new EventEmitter();
- formPromise: Promise;
+ formPromise: Promise;
limitSubscription: boolean;
newSeatCount: number;
newMaxSeats: number;
constructor(
- private apiService: ApiService,
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService,
- private logService: LogService
+ private logService: LogService,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {}
ngOnInit() {
@@ -40,7 +40,7 @@ export class AdjustSubscription {
try {
const seatAdjustment = this.newSeatCount - this.currentSeatCount;
const request = new OrganizationSubscriptionUpdateRequest(seatAdjustment, this.newMaxSeats);
- this.formPromise = this.apiService.postOrganizationUpdateSubscription(
+ this.formPromise = this.organizationApiService.updateSubscription(
this.organizationId,
request
);
diff --git a/apps/web/src/app/organizations/settings/delete-organization.component.ts b/apps/web/src/app/organizations/settings/delete-organization.component.ts
index 19b82ebcaab..2b2341a44ac 100644
--- a/apps/web/src/app/organizations/settings/delete-organization.component.ts
+++ b/apps/web/src/app/organizations/settings/delete-organization.component.ts
@@ -1,10 +1,10 @@
import { Component, EventEmitter, OnInit, Output } from "@angular/core";
-import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
import { CipherType } from "@bitwarden/common/enums/cipherType";
@@ -53,19 +53,19 @@ export class DeleteOrganizationComponent implements OnInit {
deleteOrganizationRequestType: "InvalidFamiliesForEnterprise" | "RegularDelete" = "RegularDelete";
organizationName: string;
organizationContentSummary: OrganizationContentSummary = new OrganizationContentSummary();
- @Output() onSuccess: EventEmitter = new EventEmitter();
+ @Output() onSuccess: EventEmitter = new EventEmitter();
masterPassword: Verification;
- formPromise: Promise;
+ formPromise: Promise;
constructor(
- private apiService: ApiService,
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService,
private userVerificationService: UserVerificationService,
private logService: LogService,
private cipherService: CipherService,
- private organizationService: OrganizationService
+ private organizationService: OrganizationService,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {}
async ngOnInit(): Promise {
@@ -76,7 +76,7 @@ export class DeleteOrganizationComponent implements OnInit {
try {
this.formPromise = this.userVerificationService
.buildRequest(this.masterPassword)
- .then((request) => this.apiService.deleteOrganization(this.organizationId, request));
+ .then((request) => this.organizationApiService.delete(this.organizationId, request));
await this.formPromise;
this.platformUtilsService.showToast(
"success",
diff --git a/apps/web/src/app/organizations/settings/download-license.component.ts b/apps/web/src/app/organizations/settings/download-license.component.ts
index 05927c1ec3a..5cad1c3b22b 100644
--- a/apps/web/src/app/organizations/settings/download-license.component.ts
+++ b/apps/web/src/app/organizations/settings/download-license.component.ts
@@ -1,8 +1,8 @@
import { Component, EventEmitter, Input, Output } from "@angular/core";
-import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
@Component({
selector: "app-download-license",
@@ -14,12 +14,12 @@ export class DownloadLicenseComponent {
@Output() onCanceled = new EventEmitter();
installationId: string;
- formPromise: Promise;
+ formPromise: Promise;
constructor(
- private apiService: ApiService,
private fileDownloadService: FileDownloadService,
- private logService: LogService
+ private logService: LogService,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {}
async submit() {
@@ -28,7 +28,7 @@ export class DownloadLicenseComponent {
}
try {
- this.formPromise = this.apiService.getOrganizationLicense(
+ this.formPromise = this.organizationApiService.getLicense(
this.organizationId,
this.installationId
);
diff --git a/apps/web/src/app/organizations/settings/settings.component.ts b/apps/web/src/app/organizations/settings/settings.component.ts
index 2a4f798c7f2..318608524b3 100644
--- a/apps/web/src/app/organizations/settings/settings.component.ts
+++ b/apps/web/src/app/organizations/settings/settings.component.ts
@@ -8,6 +8,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti
selector: "app-org-settings",
templateUrl: "settings.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class SettingsComponent {
access2fa = false;
showBilling: boolean;
@@ -19,6 +20,7 @@ export class SettingsComponent {
) {}
ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.params.subscribe(async (params) => {
const organization = await this.organizationService.get(params.organizationId);
this.showBilling = !this.platformUtilsService.isSelfHost() && organization.canManageBilling;
diff --git a/apps/web/src/app/organizations/settings/two-factor-setup.component.ts b/apps/web/src/app/organizations/settings/two-factor-setup.component.ts
index c3684aa420e..be82b0a86b9 100644
--- a/apps/web/src/app/organizations/settings/two-factor-setup.component.ts
+++ b/apps/web/src/app/organizations/settings/two-factor-setup.component.ts
@@ -18,6 +18,7 @@ import { TwoFactorSetupComponent as BaseTwoFactorSetupComponent } from "../../se
selector: "app-two-factor-setup",
templateUrl: "../../settings/two-factor-setup.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent {
constructor(
apiService: ApiService,
@@ -43,6 +44,7 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent {
}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
await super.ngOnInit();
@@ -55,6 +57,7 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent {
const duoComp = await this.openModal(this.duoModalRef, TwoFactorDuoComponent);
duoComp.type = TwoFactorProviderType.OrganizationDuo;
duoComp.organizationId = this.organizationId;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
duoComp.onUpdated.subscribe((enabled: boolean) => {
this.updateStatus(enabled, TwoFactorProviderType.OrganizationDuo);
});
diff --git a/apps/web/src/app/organizations/sponsorships/families-for-enterprise-setup.component.ts b/apps/web/src/app/organizations/sponsorships/families-for-enterprise-setup.component.ts
index ea8c90d7ef0..8420fd91223 100644
--- a/apps/web/src/app/organizations/sponsorships/families-for-enterprise-setup.component.ts
+++ b/apps/web/src/app/organizations/sponsorships/families-for-enterprise-setup.component.ts
@@ -22,6 +22,7 @@ import { DeleteOrganizationComponent } from "../settings/delete-organization.com
selector: "families-for-enterprise-setup",
templateUrl: "families-for-enterprise-setup.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class FamiliesForEnterpriseSetupComponent implements OnInit {
@ViewChild(OrganizationPlansComponent, { static: false })
set organizationPlansComponent(value: OrganizationPlansComponent) {
@@ -32,6 +33,7 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit {
value.plan = PlanType.FamiliesAnnually;
value.product = ProductType.Families;
value.acceptingSponsorship = true;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
value.onSuccess.subscribe(this.onOrganizationCreateSuccess.bind(this));
}
@@ -63,6 +65,7 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit {
async ngOnInit() {
document.body.classList.remove("layout_frontend");
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
const error = qParams.token == null;
if (error) {
@@ -130,6 +133,7 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit {
(comp) => {
comp.organizationId = organizationId;
comp.deleteOrganizationRequestType = "InvalidFamiliesForEnterprise";
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onSuccess.subscribe(() => {
this.router.navigate(["/"]);
});
diff --git a/apps/web/src/app/organizations/tools/exposed-passwords-report.component.ts b/apps/web/src/app/organizations/tools/exposed-passwords-report.component.ts
index d34e757d744..00c2ce2e3f4 100644
--- a/apps/web/src/app/organizations/tools/exposed-passwords-report.component.ts
+++ b/apps/web/src/app/organizations/tools/exposed-passwords-report.component.ts
@@ -18,6 +18,7 @@ import { ExposedPasswordsReportComponent as BaseExposedPasswordsReportComponent
selector: "app-org-exposed-passwords-report",
templateUrl: "../../reports/pages/exposed-passwords-report.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class ExposedPasswordsReportComponent extends BaseExposedPasswordsReportComponent {
manageableCiphers: Cipher[];
@@ -42,6 +43,7 @@ export class ExposedPasswordsReportComponent extends BaseExposedPasswordsReportC
}
ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organization = await this.organizationService.get(params.organizationId);
this.manageableCiphers = await this.cipherService.getAll();
diff --git a/apps/web/src/app/organizations/tools/import-export/org-export.component.ts b/apps/web/src/app/organizations/tools/import-export/org-export.component.ts
index 79f92542317..20b6690acd9 100644
--- a/apps/web/src/app/organizations/tools/import-export/org-export.component.ts
+++ b/apps/web/src/app/organizations/tools/import-export/org-export.component.ts
@@ -2,6 +2,7 @@ import { Component } from "@angular/core";
import { UntypedFormBuilder } from "@angular/forms";
import { ActivatedRoute } from "@angular/router";
+import { ModalService } from "@bitwarden/angular/services/modal.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EventService } from "@bitwarden/common/abstractions/event.service";
import { ExportService } from "@bitwarden/common/abstractions/export.service";
@@ -19,6 +20,7 @@ import { ExportComponent } from "../../../tools/import-export/export.component";
selector: "app-org-export",
templateUrl: "../../../tools/import-export/export.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class OrganizationExportComponent extends ExportComponent {
constructor(
cryptoService: CryptoService,
@@ -31,7 +33,8 @@ export class OrganizationExportComponent extends ExportComponent {
logService: LogService,
userVerificationService: UserVerificationService,
formBuilder: UntypedFormBuilder,
- fileDownloadService: FileDownloadService
+ fileDownloadService: FileDownloadService,
+ modalService: ModalService
) {
super(
cryptoService,
@@ -43,11 +46,13 @@ export class OrganizationExportComponent extends ExportComponent {
logService,
userVerificationService,
formBuilder,
- fileDownloadService
+ fileDownloadService,
+ modalService
);
}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
});
diff --git a/apps/web/src/app/organizations/tools/import-export/org-import-export.module.ts b/apps/web/src/app/organizations/tools/import-export/org-import-export.module.ts
index 527ac69bddd..650363300b3 100644
--- a/apps/web/src/app/organizations/tools/import-export/org-import-export.module.ts
+++ b/apps/web/src/app/organizations/tools/import-export/org-import-export.module.ts
@@ -7,7 +7,6 @@ import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { ImportService as ImportServiceAbstraction } from "@bitwarden/common/abstractions/import.service";
-import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { ImportService } from "@bitwarden/common/services/import.service";
import { LooseComponentsModule, SharedModule } from "../../../shared";
@@ -29,7 +28,6 @@ import { OrganizationImportComponent } from "./org-import.component";
ApiService,
I18nService,
CollectionService,
- PlatformUtilsService,
CryptoService,
],
},
diff --git a/apps/web/src/app/organizations/tools/import-export/org-import.component.ts b/apps/web/src/app/organizations/tools/import-export/org-import.component.ts
index 504163a76fc..27d1c6cd39e 100644
--- a/apps/web/src/app/organizations/tools/import-export/org-import.component.ts
+++ b/apps/web/src/app/organizations/tools/import-export/org-import.component.ts
@@ -1,6 +1,7 @@
import { Component } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
+import { ModalService } from "@bitwarden/angular/services/modal.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { ImportService } from "@bitwarden/common/abstractions/import.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
@@ -14,6 +15,7 @@ import { ImportComponent } from "../../../tools/import-export/import.component";
selector: "app-org-import",
templateUrl: "../../../tools/import-export/import.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class OrganizationImportComponent extends ImportComponent {
organizationName: string;
@@ -25,12 +27,22 @@ export class OrganizationImportComponent extends ImportComponent {
platformUtilsService: PlatformUtilsService,
policyService: PolicyService,
private organizationService: OrganizationService,
- logService: LogService
+ logService: LogService,
+ modalService: ModalService
) {
- super(i18nService, importService, router, platformUtilsService, policyService, logService);
+ super(
+ i18nService,
+ importService,
+ router,
+ platformUtilsService,
+ policyService,
+ logService,
+ modalService
+ );
}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
this.successNavigate = ["organizations", this.organizationId, "vault"];
diff --git a/apps/web/src/app/organizations/tools/inactive-two-factor-report.component.ts b/apps/web/src/app/organizations/tools/inactive-two-factor-report.component.ts
index 56e9625511f..80fe51d32d3 100644
--- a/apps/web/src/app/organizations/tools/inactive-two-factor-report.component.ts
+++ b/apps/web/src/app/organizations/tools/inactive-two-factor-report.component.ts
@@ -17,6 +17,7 @@ import { InactiveTwoFactorReportComponent as BaseInactiveTwoFactorReportComponen
selector: "app-inactive-two-factor-report",
templateUrl: "../../reports/pages/inactive-two-factor-report.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class InactiveTwoFactorReportComponent extends BaseInactiveTwoFactorReportComponent {
constructor(
cipherService: CipherService,
@@ -39,6 +40,7 @@ export class InactiveTwoFactorReportComponent extends BaseInactiveTwoFactorRepor
}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organization = await this.organizationService.get(params.organizationId);
await super.ngOnInit();
diff --git a/apps/web/src/app/organizations/tools/reused-passwords-report.component.ts b/apps/web/src/app/organizations/tools/reused-passwords-report.component.ts
index 1f97546cf36..98a62cd83ab 100644
--- a/apps/web/src/app/organizations/tools/reused-passwords-report.component.ts
+++ b/apps/web/src/app/organizations/tools/reused-passwords-report.component.ts
@@ -17,6 +17,7 @@ import { ReusedPasswordsReportComponent as BaseReusedPasswordsReportComponent }
selector: "app-reused-passwords-report",
templateUrl: "../../reports/pages/reused-passwords-report.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class ReusedPasswordsReportComponent extends BaseReusedPasswordsReportComponent {
manageableCiphers: Cipher[];
@@ -33,6 +34,7 @@ export class ReusedPasswordsReportComponent extends BaseReusedPasswordsReportCom
}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organization = await this.organizationService.get(params.organizationId);
this.manageableCiphers = await this.cipherService.getAll();
diff --git a/apps/web/src/app/organizations/tools/tools.component.ts b/apps/web/src/app/organizations/tools/tools.component.ts
index cfff58a682f..249e5cd2ca8 100644
--- a/apps/web/src/app/organizations/tools/tools.component.ts
+++ b/apps/web/src/app/organizations/tools/tools.component.ts
@@ -9,6 +9,7 @@ import { Organization } from "@bitwarden/common/models/domain/organization";
selector: "app-org-tools",
templateUrl: "tools.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class ToolsComponent {
organization: Organization;
accessReports = false;
@@ -21,6 +22,7 @@ export class ToolsComponent {
) {}
ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.params.subscribe(async (params) => {
this.organization = await this.organizationService.get(params.organizationId);
// TODO: Maybe we want to just make sure they are not on a free plan? Just compare useTotp for now
diff --git a/apps/web/src/app/organizations/tools/unsecured-websites-report.component.ts b/apps/web/src/app/organizations/tools/unsecured-websites-report.component.ts
index f636303bb0e..b1e99c50fc5 100644
--- a/apps/web/src/app/organizations/tools/unsecured-websites-report.component.ts
+++ b/apps/web/src/app/organizations/tools/unsecured-websites-report.component.ts
@@ -16,6 +16,7 @@ import { UnsecuredWebsitesReportComponent as BaseUnsecuredWebsitesReportComponen
selector: "app-unsecured-websites-report",
templateUrl: "../../reports/pages/unsecured-websites-report.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class UnsecuredWebsitesReportComponent extends BaseUnsecuredWebsitesReportComponent {
constructor(
cipherService: CipherService,
@@ -30,6 +31,7 @@ export class UnsecuredWebsitesReportComponent extends BaseUnsecuredWebsitesRepor
}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organization = await this.organizationService.get(params.organizationId);
await super.ngOnInit();
diff --git a/apps/web/src/app/organizations/tools/weak-passwords-report.component.ts b/apps/web/src/app/organizations/tools/weak-passwords-report.component.ts
index 306b861f369..9b5d95b6372 100644
--- a/apps/web/src/app/organizations/tools/weak-passwords-report.component.ts
+++ b/apps/web/src/app/organizations/tools/weak-passwords-report.component.ts
@@ -18,6 +18,7 @@ import { WeakPasswordsReportComponent as BaseWeakPasswordsReportComponent } from
selector: "app-weak-passwords-report",
templateUrl: "../../reports/pages/weak-passwords-report.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class WeakPasswordsReportComponent extends BaseWeakPasswordsReportComponent {
manageableCiphers: Cipher[];
@@ -42,6 +43,7 @@ export class WeakPasswordsReportComponent extends BaseWeakPasswordsReportCompone
}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organization = await this.organizationService.get(params.organizationId);
this.manageableCiphers = await this.cipherService.getAll();
diff --git a/apps/web/src/app/organizations/users/enroll-master-password-reset.component.ts b/apps/web/src/app/organizations/users/enroll-master-password-reset.component.ts
index 2a8e5f21880..c2977180d4b 100644
--- a/apps/web/src/app/organizations/users/enroll-master-password-reset.component.ts
+++ b/apps/web/src/app/organizations/users/enroll-master-password-reset.component.ts
@@ -6,6 +6,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SyncService } from "@bitwarden/common/abstractions/sync.service";
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
@@ -33,7 +34,8 @@ export class EnrollMasterPasswordReset {
private syncService: SyncService,
private logService: LogService,
private modalRef: ModalRef,
- config: ModalConfig
+ config: ModalConfig,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {
this.organization = config.data.organization;
}
@@ -48,7 +50,7 @@ export class EnrollMasterPasswordReset {
let keyString: string = null;
// Retrieve Public Key
- const orgKeys = await this.apiService.getOrganizationKeys(this.organization.id);
+ const orgKeys = await this.organizationApiService.getKeys(this.organization.id);
if (orgKeys == null) {
throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
}
diff --git a/apps/web/src/app/organizations/vault/vault.component.ts b/apps/web/src/app/organizations/vault/vault.component.ts
index 953a05f3d80..c25e565e78c 100644
--- a/apps/web/src/app/organizations/vault/vault.component.ts
+++ b/apps/web/src/app/organizations/vault/vault.component.ts
@@ -86,11 +86,13 @@ export class VaultComponent implements OnInit, OnDestroy {
? "trashCleanupWarningSelfHosted"
: "trashCleanupWarning"
);
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.params.subscribe(async (params: any) => {
this.organization = await this.organizationService.get(params.organizationId);
this.vaultFilterComponent.organization = this.organization;
this.ciphersComponent.organization = this.organization;
+ /* eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe, rxjs/no-nested-subscribe */
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
this.ciphersComponent.searchText = this.vaultFilterComponent.searchText = qParams.search;
if (!this.organization.canViewAllCollections) {
@@ -126,6 +128,7 @@ export class VaultComponent implements OnInit, OnDestroy {
}
}
+ /* eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe, rxjs/no-nested-subscribe */
this.route.queryParams.subscribe(async (params) => {
const cipherId = getCipherIdFromParams(params);
if (cipherId) {
@@ -191,11 +194,14 @@ export class VaultComponent implements OnInit, OnDestroy {
(comp) => {
comp.organization = this.organization;
comp.cipherId = cipher.id;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onUploadedAttachment.subscribe(() => (madeAttachmentChanges = true));
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onDeletedAttachment.subscribe(() => (madeAttachmentChanges = true));
}
);
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
modal.onClosed.subscribe(async () => {
if (madeAttachmentChanges) {
await this.ciphersComponent.refresh();
@@ -217,6 +223,7 @@ export class VaultComponent implements OnInit, OnDestroy {
}
comp.organization = this.organization;
comp.cipherId = cipher.id;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
comp.onSavedCollections.subscribe(async () => {
modal.close();
await this.ciphersComponent.refresh();
@@ -258,14 +265,17 @@ export class VaultComponent implements OnInit, OnDestroy {
(comp) => {
comp.organization = this.organization;
comp.cipherId = cipherId;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
comp.onSavedCipher.subscribe(async () => {
modal.close();
await this.ciphersComponent.refresh();
});
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
comp.onDeletedCipher.subscribe(async () => {
modal.close();
await this.ciphersComponent.refresh();
});
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
comp.onRestoredCipher.subscribe(async () => {
modal.close();
await this.ciphersComponent.refresh();
diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts
index 6fb664facc8..61daf7c82cb 100644
--- a/apps/web/src/app/oss-routing.module.ts
+++ b/apps/web/src/app/oss-routing.module.ts
@@ -5,7 +5,7 @@ import { AuthGuard } from "@bitwarden/angular/guards/auth.guard";
import { LockGuard } from "@bitwarden/angular/guards/lock.guard";
import { UnauthGuard } from "@bitwarden/angular/guards/unauth.guard";
-import { flagEnabled, FlagName } from "../utils/flags";
+import { flagEnabled, Flags } from "../utils/flags";
import { AcceptEmergencyComponent } from "./accounts/accept-emergency.component";
import { AcceptOrganizationComponent } from "./accounts/accept-organization.component";
@@ -261,7 +261,7 @@ const routes: Routes = [
})
export class OssRoutingModule {}
-export function buildFlaggedRoute(flagName: FlagName, route: Route): Route {
+export function buildFlaggedRoute(flagName: keyof Flags, route: Route): Route {
return flagEnabled(flagName)
? route
: {
diff --git a/apps/web/src/app/reports/pages/cipher-report.component.ts b/apps/web/src/app/reports/pages/cipher-report.component.ts
index 9179c04371a..44d7cae619a 100644
--- a/apps/web/src/app/reports/pages/cipher-report.component.ts
+++ b/apps/web/src/app/reports/pages/cipher-report.component.ts
@@ -53,14 +53,17 @@ export class CipherReportComponent {
}
comp.cipherId = cipher == null ? null : cipher.id;
+ // eslint-disable-next-line rxjs/no-async-subscribe
comp.onSavedCipher.subscribe(async () => {
modal.close();
await this.load();
});
+ // eslint-disable-next-line rxjs/no-async-subscribe
comp.onDeletedCipher.subscribe(async () => {
modal.close();
await this.load();
});
+ // eslint-disable-next-line rxjs/no-async-subscribe
comp.onRestoredCipher.subscribe(async () => {
modal.close();
await this.load();
diff --git a/apps/web/src/app/reports/reports-layout.component.ts b/apps/web/src/app/reports/reports-layout.component.ts
index 3d3fee2904b..7bfe912c1ad 100644
--- a/apps/web/src/app/reports/reports-layout.component.ts
+++ b/apps/web/src/app/reports/reports-layout.component.ts
@@ -14,6 +14,7 @@ export class ReportsLayoutComponent implements OnDestroy {
constructor(router: Router) {
this.subscription = router.events
.pipe(filter((event) => event instanceof NavigationEnd))
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
.subscribe((event) => {
this.homepage = (event as NavigationEnd).url == "/reports";
});
diff --git a/apps/web/src/app/send/access.component.ts b/apps/web/src/app/send/access.component.ts
index 707a5bef63d..7f4c6bbab8e 100644
--- a/apps/web/src/app/send/access.component.ts
+++ b/apps/web/src/app/send/access.component.ts
@@ -22,6 +22,7 @@ import { SendAccessView } from "@bitwarden/common/models/view/sendAccessView";
selector: "app-send-access",
templateUrl: "access.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class AccessComponent implements OnInit {
send: SendAccessView;
sendType = SendType;
@@ -72,6 +73,7 @@ export class AccessComponent implements OnInit {
}
ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.params.subscribe(async (params) => {
this.id = params.sendId;
this.key = params.key;
diff --git a/apps/web/src/app/send/send.component.ts b/apps/web/src/app/send/send.component.ts
index 4024f7c18f7..2719d904564 100644
--- a/apps/web/src/app/send/send.component.ts
+++ b/apps/web/src/app/send/send.component.ts
@@ -85,10 +85,12 @@ export class SendComponent extends BaseSendComponent {
this.sendAddEditModalRef,
(comp) => {
comp.sendId = send == null ? null : send.id;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
comp.onSavedSend.subscribe(async () => {
modal.close();
await this.load();
});
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
comp.onDeletedSend.subscribe(async () => {
modal.close();
await this.load();
diff --git a/apps/web/src/app/settings/adjust-payment.component.ts b/apps/web/src/app/settings/adjust-payment.component.ts
index e88329fd7b8..4e9338081fa 100644
--- a/apps/web/src/app/settings/adjust-payment.component.ts
+++ b/apps/web/src/app/settings/adjust-payment.component.ts
@@ -3,6 +3,7 @@ import { Component, EventEmitter, Input, Output, ViewChild } from "@angular/core
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PaymentMethodType } from "@bitwarden/common/enums/paymentMethodType";
import { PaymentRequest } from "@bitwarden/common/models/request/paymentRequest";
@@ -24,13 +25,14 @@ export class AdjustPaymentComponent {
@Output() onCanceled = new EventEmitter();
paymentMethodType = PaymentMethodType;
- formPromise: Promise;
+ formPromise: Promise;
constructor(
private apiService: ApiService,
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService,
- private logService: LogService
+ private logService: LogService,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {}
async submit() {
@@ -50,7 +52,7 @@ export class AdjustPaymentComponent {
request.line2 = this.taxInfoComponent.taxInfo.line2;
request.city = this.taxInfoComponent.taxInfo.city;
request.state = this.taxInfoComponent.taxInfo.state;
- return this.apiService.postOrganizationPayment(this.organizationId, request);
+ return this.organizationApiService.updatePayment(this.organizationId, request);
}
});
await this.formPromise;
diff --git a/apps/web/src/app/settings/adjust-storage.component.ts b/apps/web/src/app/settings/adjust-storage.component.ts
index eea26c2a2df..6931ad9d10b 100644
--- a/apps/web/src/app/settings/adjust-storage.component.ts
+++ b/apps/web/src/app/settings/adjust-storage.component.ts
@@ -4,6 +4,7 @@ import { ActivatedRoute, Router } from "@angular/router";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { StorageRequest } from "@bitwarden/common/models/request/storageRequest";
import { PaymentResponse } from "@bitwarden/common/models/response/paymentResponse";
@@ -25,7 +26,7 @@ export class AdjustStorageComponent {
@ViewChild(PaymentComponent, { static: true }) paymentComponent: PaymentComponent;
storageAdjustment = 0;
- formPromise: Promise;
+ formPromise: Promise;
constructor(
private apiService: ApiService,
@@ -33,7 +34,8 @@ export class AdjustStorageComponent {
private platformUtilsService: PlatformUtilsService,
private router: Router,
private activatedRoute: ActivatedRoute,
- private logService: LogService
+ private logService: LogService,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {}
async submit() {
@@ -50,7 +52,7 @@ export class AdjustStorageComponent {
if (this.organizationId == null) {
response = this.formPromise = this.apiService.postAccountStorage(request);
} else {
- response = this.formPromise = this.apiService.postOrganizationStorage(
+ response = this.formPromise = this.organizationApiService.updateStorage(
this.organizationId,
request
);
diff --git a/apps/web/src/app/settings/change-password.component.ts b/apps/web/src/app/settings/change-password.component.ts
index 86c3987fd93..abd8daaf4a0 100644
--- a/apps/web/src/app/settings/change-password.component.ts
+++ b/apps/web/src/app/settings/change-password.component.ts
@@ -11,6 +11,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
@@ -53,7 +54,8 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
private sendService: SendService,
private organizationService: OrganizationService,
private keyConnectorService: KeyConnectorService,
- private router: Router
+ private router: Router,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {
super(
i18nService,
@@ -267,7 +269,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
}
// Retrieve public key
- const response = await this.apiService.getOrganizationKeys(org.id);
+ const response = await this.organizationApiService.getKeys(org.id);
const publicKey = Utils.fromB64ToArray(response?.publicKey);
// Re-enroll - encrpyt user's encKey.key with organization public key
diff --git a/apps/web/src/app/settings/create-organization.component.ts b/apps/web/src/app/settings/create-organization.component.ts
index fc6caf815a8..6cae85c940e 100644
--- a/apps/web/src/app/settings/create-organization.component.ts
+++ b/apps/web/src/app/settings/create-organization.component.ts
@@ -11,6 +11,7 @@ import { OrganizationPlansComponent } from "./organization-plans.component";
selector: "app-create-organization",
templateUrl: "create-organization.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class CreateOrganizationComponent implements OnInit {
@ViewChild(OrganizationPlansComponent, { static: true })
orgPlansComponent: OrganizationPlansComponent;
@@ -18,6 +19,7 @@ export class CreateOrganizationComponent implements OnInit {
constructor(private route: ActivatedRoute) {}
ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
if (qParams.plan === "families") {
this.orgPlansComponent.plan = PlanType.FamiliesAnnually;
diff --git a/apps/web/src/app/settings/emergency-access-view.component.ts b/apps/web/src/app/settings/emergency-access-view.component.ts
index acdf6e43e27..f40113a5ad6 100644
--- a/apps/web/src/app/settings/emergency-access-view.component.ts
+++ b/apps/web/src/app/settings/emergency-access-view.component.ts
@@ -18,6 +18,7 @@ import { EmergencyAddEditComponent } from "./emergency-add-edit.component";
selector: "emergency-access-view",
templateUrl: "emergency-access-view.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class EmergencyAccessViewComponent implements OnInit {
@ViewChild("cipherAddEdit", { read: ViewContainerRef, static: true })
cipherAddEditModalRef: ViewContainerRef;
@@ -38,6 +39,7 @@ export class EmergencyAccessViewComponent implements OnInit {
) {}
ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
this.route.params.subscribe((qParams) => {
if (qParams.id == null) {
return this.router.navigate(["settings/emergency-access"]);
diff --git a/apps/web/src/app/settings/emergency-access.component.ts b/apps/web/src/app/settings/emergency-access.component.ts
index fec4ea59dfc..a5fe4099b04 100644
--- a/apps/web/src/app/settings/emergency-access.component.ts
+++ b/apps/web/src/app/settings/emergency-access.component.ts
@@ -27,6 +27,7 @@ import { EmergencyAccessTakeoverComponent } from "./emergency-access-takeover.co
selector: "emergency-access",
templateUrl: "emergency-access.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class EmergencyAccessComponent implements OnInit {
@ViewChild("addEdit", { read: ViewContainerRef, static: true }) addEditModalRef: ViewContainerRef;
@ViewChild("takeoverTemplate", { read: ViewContainerRef, static: true })
@@ -84,10 +85,12 @@ export class EmergencyAccessComponent implements OnInit {
comp.name = this.userNamePipe.transform(details);
comp.emergencyAccessId = details?.id;
comp.readOnly = !this.canAccessPremium;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onSaved.subscribe(() => {
modal.close();
this.load();
});
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onDeleted.subscribe(() => {
modal.close();
this.remove(details);
@@ -132,6 +135,7 @@ export class EmergencyAccessComponent implements OnInit {
comp.name = this.userNamePipe.transform(contact);
comp.emergencyAccessId = contact.id;
comp.userId = contact?.granteeId;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
comp.onConfirmed.subscribe(async () => {
modal.close();
@@ -264,6 +268,7 @@ export class EmergencyAccessComponent implements OnInit {
comp.email = details.email;
comp.emergencyAccessId = details != null ? details.id : null;
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
comp.onDone.subscribe(() => {
modal.close();
this.platformUtilsService.showToast(
diff --git a/apps/web/src/app/settings/organization-plans.component.ts b/apps/web/src/app/settings/organization-plans.component.ts
index b7598fc9790..12fcb4ad40d 100644
--- a/apps/web/src/app/settings/organization-plans.component.ts
+++ b/apps/web/src/app/settings/organization-plans.component.ts
@@ -8,6 +8,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
import { SyncService } from "@bitwarden/common/abstractions/sync.service";
@@ -26,6 +27,10 @@ import { PlanResponse } from "@bitwarden/common/models/response/planResponse";
import { PaymentComponent } from "./payment.component";
import { TaxInfoComponent } from "./tax-info.component";
+interface OnSuccessArgs {
+ organizationId: string;
+}
+
@Component({
selector: "app-organization-plans",
templateUrl: "organization-plans.component.html",
@@ -41,14 +46,14 @@ export class OrganizationPlansComponent implements OnInit {
@Input() product: ProductType = ProductType.Free;
@Input() plan: PlanType = PlanType.Free;
@Input() providerId: string;
- @Output() onSuccess = new EventEmitter();
- @Output() onCanceled = new EventEmitter();
+ @Output() onSuccess = new EventEmitter();
+ @Output() onCanceled = new EventEmitter();
@Output() onTrialBillingSuccess = new EventEmitter();
loading = true;
selfHosted = false;
productTypes = ProductType;
- formPromise: Promise;
+ formPromise: Promise;
singleOrgPolicyBlock = false;
isInTrialFlow = false;
discount = 0;
@@ -79,7 +84,8 @@ export class OrganizationPlansComponent implements OnInit {
private organizationService: OrganizationService,
private logService: LogService,
private messagingService: MessagingService,
- private formBuilder: UntypedFormBuilder
+ private formBuilder: UntypedFormBuilder,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {
this.selfHosted = platformUtilsService.isSelfHost();
}
@@ -372,7 +378,7 @@ export class OrganizationPlansComponent implements OnInit {
request.keys = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
}
- const result = await this.apiService.postOrganizationUpgrade(this.organizationId, request);
+ const result = await this.organizationApiService.upgrade(this.organizationId, request);
if (!result.success && result.paymentIntentClientSecret != null) {
await this.paymentComponent.handleStripeCardPayment(result.paymentIntentClientSecret, null);
}
@@ -434,7 +440,7 @@ export class OrganizationPlansComponent implements OnInit {
return orgId;
} else {
- return (await this.apiService.postOrganization(request)).id;
+ return (await this.organizationApiService.create(request)).id;
}
}
@@ -449,14 +455,14 @@ export class OrganizationPlansComponent implements OnInit {
fd.append("license", files[0]);
fd.append("key", key);
fd.append("collectionName", collectionCt);
- const response = await this.apiService.postOrganizationLicense(fd);
+ const response = await this.organizationApiService.createLicense(fd);
const orgId = response.id;
await this.apiService.refreshIdentityToken();
// Org Keys live outside of the OrganizationLicense - add the keys to the org here
const request = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
- await this.apiService.postOrganizationKeys(orgId, request);
+ await this.organizationApiService.updateKeys(orgId, request);
return orgId;
}
diff --git a/apps/web/src/app/settings/payment.component.ts b/apps/web/src/app/settings/payment.component.ts
index a4de1521c38..d0f4407b355 100644
--- a/apps/web/src/app/settings/payment.component.ts
+++ b/apps/web/src/app/settings/payment.component.ts
@@ -27,7 +27,7 @@ export class PaymentComponent implements OnInit, OnDestroy {
@Input() hideCredit = false;
@Input() trialFlow = false;
- private destroy$: Subject = new Subject();
+ private destroy$ = new Subject();
bank: any = {
routing_number: null,
diff --git a/apps/web/src/app/settings/tax-info.component.ts b/apps/web/src/app/settings/tax-info.component.ts
index 91d9ca3ad3f..216a0d030a1 100644
--- a/apps/web/src/app/settings/tax-info.component.ts
+++ b/apps/web/src/app/settings/tax-info.component.ts
@@ -3,21 +3,29 @@ import { ActivatedRoute } from "@angular/router";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { OrganizationTaxInfoUpdateRequest } from "@bitwarden/common/models/request/organizationTaxInfoUpdateRequest";
import { TaxInfoUpdateRequest } from "@bitwarden/common/models/request/taxInfoUpdateRequest";
+import { TaxInfoResponse } from "@bitwarden/common/models/response/taxInfoResponse";
import { TaxRateResponse } from "@bitwarden/common/models/response/taxRateResponse";
+type TaxInfoView = Omit & {
+ includeTaxId: boolean;
+ [key: string]: unknown;
+};
+
@Component({
selector: "app-tax-info",
templateUrl: "tax-info.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class TaxInfoComponent {
@Input() trialFlow = false;
@Output() onCountryChanged = new EventEmitter();
loading = true;
organizationId: string;
- taxInfo: any = {
+ taxInfo: TaxInfoView = {
taxId: null,
line1: null,
line2: null,
@@ -30,7 +38,7 @@ export class TaxInfoComponent {
taxRates: TaxRateResponse[];
- private pristine: any = {
+ private pristine: TaxInfoView = {
taxId: null,
line1: null,
line2: null,
@@ -44,15 +52,17 @@ export class TaxInfoComponent {
constructor(
private apiService: ApiService,
private route: ActivatedRoute,
- private logService: LogService
+ private logService: LogService,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {}
async ngOnInit() {
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
if (this.organizationId) {
try {
- const taxInfo = await this.apiService.getOrganizationTaxInfo(this.organizationId);
+ const taxInfo = await this.organizationApiService.getTaxInfo(this.organizationId);
if (taxInfo) {
this.taxInfo.taxId = taxInfo.taxId;
this.taxInfo.state = taxInfo.state;
@@ -140,7 +150,7 @@ export class TaxInfoComponent {
}
const request = this.getTaxInfoRequest();
return this.organizationId
- ? this.apiService.putOrganizationTaxInfo(
+ ? this.organizationApiService.updateTaxInfo(
this.organizationId,
request as OrganizationTaxInfoUpdateRequest
)
diff --git a/apps/web/src/app/settings/two-factor-setup.component.ts b/apps/web/src/app/settings/two-factor-setup.component.ts
index 35c8a0f16db..13e3cbecea8 100644
--- a/apps/web/src/app/settings/two-factor-setup.component.ts
+++ b/apps/web/src/app/settings/two-factor-setup.component.ts
@@ -25,6 +25,7 @@ import { TwoFactorYubiKeyComponent } from "./two-factor-yubikey.component";
selector: "app-two-factor-setup",
templateUrl: "two-factor-setup.component.html",
})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class TwoFactorSetupComponent implements OnInit {
@ViewChild("recoveryTemplate", { read: ViewContainerRef, static: true })
recoveryModalRef: ViewContainerRef;
@@ -116,6 +117,7 @@ export class TwoFactorSetupComponent implements OnInit {
this.authenticatorModalRef,
TwoFactorAuthenticatorComponent
);
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
authComp.onUpdated.subscribe((enabled: boolean) => {
this.updateStatus(enabled, TwoFactorProviderType.Authenticator);
});
@@ -123,6 +125,7 @@ export class TwoFactorSetupComponent implements OnInit {
}
case TwoFactorProviderType.Yubikey: {
const yubiComp = await this.openModal(this.yubikeyModalRef, TwoFactorYubiKeyComponent);
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
yubiComp.onUpdated.subscribe((enabled: boolean) => {
this.updateStatus(enabled, TwoFactorProviderType.Yubikey);
});
@@ -130,6 +133,7 @@ export class TwoFactorSetupComponent implements OnInit {
}
case TwoFactorProviderType.Duo: {
const duoComp = await this.openModal(this.duoModalRef, TwoFactorDuoComponent);
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
duoComp.onUpdated.subscribe((enabled: boolean) => {
this.updateStatus(enabled, TwoFactorProviderType.Duo);
});
@@ -137,6 +141,7 @@ export class TwoFactorSetupComponent implements OnInit {
}
case TwoFactorProviderType.Email: {
const emailComp = await this.openModal(this.emailModalRef, TwoFactorEmailComponent);
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
emailComp.onUpdated.subscribe((enabled: boolean) => {
this.updateStatus(enabled, TwoFactorProviderType.Email);
});
@@ -147,6 +152,7 @@ export class TwoFactorSetupComponent implements OnInit {
this.webAuthnModalRef,
TwoFactorWebAuthnComponent
);
+ // eslint-disable-next-line rxjs-angular/prefer-takeuntil
webAuthnComp.onUpdated.subscribe((enabled: boolean) => {
this.updateStatus(enabled, TwoFactorProviderType.WebAuthn);
});
diff --git a/apps/web/src/app/settings/update-license.component.ts b/apps/web/src/app/settings/update-license.component.ts
index e843a5d6009..de23be5f777 100644
--- a/apps/web/src/app/settings/update-license.component.ts
+++ b/apps/web/src/app/settings/update-license.component.ts
@@ -3,6 +3,7 @@ import { Component, EventEmitter, Input, Output } from "@angular/core";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
@Component({
@@ -14,13 +15,14 @@ export class UpdateLicenseComponent {
@Output() onUpdated = new EventEmitter();
@Output() onCanceled = new EventEmitter();
- formPromise: Promise;
+ formPromise: Promise;
constructor(
private apiService: ApiService,
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService,
- private logService: LogService
+ private logService: LogService,
+ private organizationApiService: OrganizationApiServiceAbstraction
) {}
async submit() {
@@ -39,11 +41,11 @@ export class UpdateLicenseComponent {
const fd = new FormData();
fd.append("license", files[0]);
- let updatePromise: Promise = null;
+ let updatePromise: Promise = null;
if (this.organizationId == null) {
updatePromise = this.apiService.postAccountLicense(fd);
} else {
- updatePromise = this.apiService.postOrganizationLicenseUpdate(this.organizationId, fd);
+ updatePromise = this.organizationApiService.updateLicense(this.organizationId, fd);
}
this.formPromise = updatePromise.then(() => {
diff --git a/apps/web/src/app/shared/locales.ts b/apps/web/src/app/shared/locales.ts
index 706db45bd5e..ab551e93ac8 100644
--- a/apps/web/src/app/shared/locales.ts
+++ b/apps/web/src/app/shared/locales.ts
@@ -15,6 +15,7 @@ import localeEnIn from "@angular/common/locales/en-IN";
import localeEo from "@angular/common/locales/eo";
import localeEs from "@angular/common/locales/es";
import localeEt from "@angular/common/locales/et";
+import localeEu from "@angular/common/locales/eu";
import localeFi from "@angular/common/locales/fi";
import localeFil from "@angular/common/locales/fil";
import localeFr from "@angular/common/locales/fr";
@@ -66,6 +67,7 @@ registerLocaleData(localeEnIn, "en-IN");
registerLocaleData(localeEo, "eo");
registerLocaleData(localeEs, "es");
registerLocaleData(localeEt, "et");
+registerLocaleData(localeEu, "eu");
registerLocaleData(localeFi, "fi");
registerLocaleData(localeFil, "fil");
registerLocaleData(localeFr, "fr");
diff --git a/apps/web/src/app/shared/loose-components.module.ts b/apps/web/src/app/shared/loose-components.module.ts
index f253df0d0a1..128b0585ee1 100644
--- a/apps/web/src/app/shared/loose-components.module.ts
+++ b/apps/web/src/app/shared/loose-components.module.ts
@@ -24,6 +24,7 @@ import { NestedCheckboxComponent } from "../components/nested-checkbox.component
import { OrganizationSwitcherComponent } from "../components/organization-switcher.component";
import { PasswordRepromptComponent } from "../components/password-reprompt.component";
import { PremiumBadgeComponent } from "../components/premium-badge.component";
+import { UserVerificationPromptComponent } from "../components/user-verification-prompt.component";
import { FooterComponent } from "../layouts/footer.component";
import { FrontendLayoutComponent } from "../layouts/frontend-layout.component";
import { NavbarComponent } from "../layouts/navbar.component";
@@ -248,6 +249,7 @@ import { SharedModule } from ".";
PasswordGeneratorHistoryComponent,
PasswordGeneratorPolicyComponent,
PasswordRepromptComponent,
+ UserVerificationPromptComponent,
PaymentComponent,
PaymentMethodComponent,
PersonalOwnershipPolicyComponent,
diff --git a/apps/web/src/app/tools/generator.component.html b/apps/web/src/app/tools/generator.component.html
index 30f2a304014..542c0c3c5e3 100644
--- a/apps/web/src/app/tools/generator.component.html
+++ b/apps/web/src/app/tools/generator.component.html
@@ -296,6 +296,19 @@
/>
+
+
+
+
+
+
@@ -330,6 +343,18 @@
/>
+
+
+
+
+
+
diff --git a/apps/web/src/app/tools/import-export/export.component.html b/apps/web/src/app/tools/import-export/export.component.html
index da667f3e44a..4e27fc70f75 100644
--- a/apps/web/src/app/tools/import-export/export.component.html
+++ b/apps/web/src/app/tools/import-export/export.component.html
@@ -1,9 +1,9 @@