From 53f9d665697adf51f4cc8584a43f66a303c6b921 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:59:33 +0100 Subject: [PATCH 01/17] Autosync the updated translations (#12922) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/desktop/src/locales/af/messages.json | 9 +++++++++ apps/desktop/src/locales/ar/messages.json | 9 +++++++++ apps/desktop/src/locales/az/messages.json | 9 +++++++++ apps/desktop/src/locales/be/messages.json | 9 +++++++++ apps/desktop/src/locales/bg/messages.json | 9 +++++++++ apps/desktop/src/locales/bn/messages.json | 9 +++++++++ apps/desktop/src/locales/bs/messages.json | 9 +++++++++ apps/desktop/src/locales/ca/messages.json | 9 +++++++++ apps/desktop/src/locales/cs/messages.json | 9 +++++++++ apps/desktop/src/locales/cy/messages.json | 9 +++++++++ apps/desktop/src/locales/da/messages.json | 9 +++++++++ apps/desktop/src/locales/de/messages.json | 11 ++++++++++- apps/desktop/src/locales/el/messages.json | 9 +++++++++ apps/desktop/src/locales/en_GB/messages.json | 9 +++++++++ apps/desktop/src/locales/en_IN/messages.json | 9 +++++++++ apps/desktop/src/locales/eo/messages.json | 9 +++++++++ apps/desktop/src/locales/es/messages.json | 9 +++++++++ apps/desktop/src/locales/et/messages.json | 9 +++++++++ apps/desktop/src/locales/eu/messages.json | 9 +++++++++ apps/desktop/src/locales/fa/messages.json | 9 +++++++++ apps/desktop/src/locales/fi/messages.json | 9 +++++++++ apps/desktop/src/locales/fil/messages.json | 9 +++++++++ apps/desktop/src/locales/fr/messages.json | 9 +++++++++ apps/desktop/src/locales/gl/messages.json | 9 +++++++++ apps/desktop/src/locales/he/messages.json | 9 +++++++++ apps/desktop/src/locales/hi/messages.json | 9 +++++++++ apps/desktop/src/locales/hr/messages.json | 9 +++++++++ apps/desktop/src/locales/hu/messages.json | 9 +++++++++ apps/desktop/src/locales/id/messages.json | 9 +++++++++ apps/desktop/src/locales/it/messages.json | 9 +++++++++ apps/desktop/src/locales/ja/messages.json | 9 +++++++++ apps/desktop/src/locales/ka/messages.json | 9 +++++++++ apps/desktop/src/locales/km/messages.json | 9 +++++++++ apps/desktop/src/locales/kn/messages.json | 9 +++++++++ apps/desktop/src/locales/ko/messages.json | 9 +++++++++ apps/desktop/src/locales/lt/messages.json | 9 +++++++++ apps/desktop/src/locales/lv/messages.json | 13 +++++++++++-- apps/desktop/src/locales/me/messages.json | 9 +++++++++ apps/desktop/src/locales/ml/messages.json | 9 +++++++++ apps/desktop/src/locales/mr/messages.json | 9 +++++++++ apps/desktop/src/locales/my/messages.json | 9 +++++++++ apps/desktop/src/locales/nb/messages.json | 9 +++++++++ apps/desktop/src/locales/ne/messages.json | 9 +++++++++ apps/desktop/src/locales/nl/messages.json | 9 +++++++++ apps/desktop/src/locales/nn/messages.json | 9 +++++++++ apps/desktop/src/locales/or/messages.json | 9 +++++++++ apps/desktop/src/locales/pl/messages.json | 9 +++++++++ apps/desktop/src/locales/pt_BR/messages.json | 9 +++++++++ apps/desktop/src/locales/pt_PT/messages.json | 13 +++++++++++-- apps/desktop/src/locales/ro/messages.json | 9 +++++++++ apps/desktop/src/locales/ru/messages.json | 9 +++++++++ apps/desktop/src/locales/si/messages.json | 9 +++++++++ apps/desktop/src/locales/sk/messages.json | 9 +++++++++ apps/desktop/src/locales/sl/messages.json | 9 +++++++++ apps/desktop/src/locales/sr/messages.json | 9 +++++++++ apps/desktop/src/locales/sv/messages.json | 9 +++++++++ apps/desktop/src/locales/te/messages.json | 9 +++++++++ apps/desktop/src/locales/th/messages.json | 9 +++++++++ apps/desktop/src/locales/tr/messages.json | 9 +++++++++ apps/desktop/src/locales/uk/messages.json | 9 +++++++++ apps/desktop/src/locales/vi/messages.json | 9 +++++++++ apps/desktop/src/locales/zh_CN/messages.json | 9 +++++++++ apps/desktop/src/locales/zh_TW/messages.json | 9 +++++++++ 63 files changed, 572 insertions(+), 5 deletions(-) diff --git a/apps/desktop/src/locales/af/messages.json b/apps/desktop/src/locales/af/messages.json index 5ee3ba7e029..1710005ab66 100644 --- a/apps/desktop/src/locales/af/messages.json +++ b/apps/desktop/src/locales/af/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json index 132021f7760..c2ccab5b908 100644 --- a/apps/desktop/src/locales/ar/messages.json +++ b/apps/desktop/src/locales/ar/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "تغيير البريد الإلكتروني الخاص بالحساب" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/az/messages.json b/apps/desktop/src/locales/az/messages.json index 9af089d1ef9..68753f204ea 100644 --- a/apps/desktop/src/locales/az/messages.json +++ b/apps/desktop/src/locales/az/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Hesabın e-poçtunu dəyişdir" + }, + "organizationUpgradeRequired": { + "message": "Təşkilat yüksəltmə tələb olunur" + }, + "upgradeOrganization": { + "message": "Təşkilatı yüksəlt" + }, + "upgradeOrganizationDesc": { + "message": "Bu özəllik, ödənişsiz təşkilatlar üçün əlçatan deyil. Daha çox özəlliyin kilidini açmaq üçün ödənişli plana keçin." } } diff --git a/apps/desktop/src/locales/be/messages.json b/apps/desktop/src/locales/be/messages.json index e778c59525f..70b30128f9b 100644 --- a/apps/desktop/src/locales/be/messages.json +++ b/apps/desktop/src/locales/be/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/bg/messages.json b/apps/desktop/src/locales/bg/messages.json index 9b000177bbe..b3052fbc6cf 100644 --- a/apps/desktop/src/locales/bg/messages.json +++ b/apps/desktop/src/locales/bg/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Промяна на е-пощата" + }, + "organizationUpgradeRequired": { + "message": "Необходимо е надграждане на организацията" + }, + "upgradeOrganization": { + "message": "Надграждане на организацията" + }, + "upgradeOrganizationDesc": { + "message": "Безплатните планове нямат достъп до тази функционалност. Преминете към платен план, за да се възползвате от тази и много други възможности." } } diff --git a/apps/desktop/src/locales/bn/messages.json b/apps/desktop/src/locales/bn/messages.json index 069c58d751d..7e1994cdeab 100644 --- a/apps/desktop/src/locales/bn/messages.json +++ b/apps/desktop/src/locales/bn/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/bs/messages.json b/apps/desktop/src/locales/bs/messages.json index f5052559de9..487d98a327f 100644 --- a/apps/desktop/src/locales/bs/messages.json +++ b/apps/desktop/src/locales/bs/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/ca/messages.json b/apps/desktop/src/locales/ca/messages.json index 9d82ad59fad..46f876e560a 100644 --- a/apps/desktop/src/locales/ca/messages.json +++ b/apps/desktop/src/locales/ca/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/cs/messages.json b/apps/desktop/src/locales/cs/messages.json index 83f2840b724..28c20ee5184 100644 --- a/apps/desktop/src/locales/cs/messages.json +++ b/apps/desktop/src/locales/cs/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Změnit e-mail účtu" + }, + "organizationUpgradeRequired": { + "message": "Je vyžadována aktualizace organizace" + }, + "upgradeOrganization": { + "message": "Aktualizovat organizaci" + }, + "upgradeOrganizationDesc": { + "message": "Tato funkce není dostupná pro bezplatné organizace. Přepněte na placenou verzi a odemkněte další funkce." } } diff --git a/apps/desktop/src/locales/cy/messages.json b/apps/desktop/src/locales/cy/messages.json index f4e0853a933..897b5bb5508 100644 --- a/apps/desktop/src/locales/cy/messages.json +++ b/apps/desktop/src/locales/cy/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/da/messages.json b/apps/desktop/src/locales/da/messages.json index ebe74818f47..0d1c94527b2 100644 --- a/apps/desktop/src/locales/da/messages.json +++ b/apps/desktop/src/locales/da/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Skift kontoe-mailadresse" + }, + "organizationUpgradeRequired": { + "message": "Organisationsopgradering krævet" + }, + "upgradeOrganization": { + "message": "Opgradér organisation" + }, + "upgradeOrganizationDesc": { + "message": "Denne funktion er utilgængelig for gratis organisationer. Skift til en betalingsabonnementstype for at oplåse flere funktioner." } } diff --git a/apps/desktop/src/locales/de/messages.json b/apps/desktop/src/locales/de/messages.json index 133d98c3faa..5ce63034cb9 100644 --- a/apps/desktop/src/locales/de/messages.json +++ b/apps/desktop/src/locales/de/messages.json @@ -260,7 +260,7 @@ "description": "This is part of a larger sentence. The full sentence will read 'Contact customer success to avoid additional data loss.'" }, "contactCSToAvoidDataLossPart2": { - "message": "um zusätzlichen Datenverlust zu vermeiden.", + "message": ", um zusätzlichen Datenverlust zu vermeiden.", "description": "This is part of a larger sentence. The full sentence will read 'Contact customer success to avoid additional data loss.'" }, "january": { @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "E-Mail-Adresse des Kontos ändern" + }, + "organizationUpgradeRequired": { + "message": "Organisations-Upgrade erforderlich" + }, + "upgradeOrganization": { + "message": "Organisation upgraden" + }, + "upgradeOrganizationDesc": { + "message": "Diese Funktion ist für kostenlose Organisationen nicht verfügbar. Wechsle zu einem kostenpflichtigen Abonnement, um weitere Funktionen freizuschalten." } } diff --git a/apps/desktop/src/locales/el/messages.json b/apps/desktop/src/locales/el/messages.json index 145f386c6b9..3fed18252fe 100644 --- a/apps/desktop/src/locales/el/messages.json +++ b/apps/desktop/src/locales/el/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/en_GB/messages.json b/apps/desktop/src/locales/en_GB/messages.json index acca06b8b4f..b33f2644403 100644 --- a/apps/desktop/src/locales/en_GB/messages.json +++ b/apps/desktop/src/locales/en_GB/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organisation upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organisation" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organisations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/en_IN/messages.json b/apps/desktop/src/locales/en_IN/messages.json index 122217dae9d..e3780c16984 100644 --- a/apps/desktop/src/locales/en_IN/messages.json +++ b/apps/desktop/src/locales/en_IN/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organisation upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organisation" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organisations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/eo/messages.json b/apps/desktop/src/locales/eo/messages.json index a4621439f50..4ba31aa743b 100644 --- a/apps/desktop/src/locales/eo/messages.json +++ b/apps/desktop/src/locales/eo/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/es/messages.json b/apps/desktop/src/locales/es/messages.json index 1915002b6bd..00e17cadc40 100644 --- a/apps/desktop/src/locales/es/messages.json +++ b/apps/desktop/src/locales/es/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/et/messages.json b/apps/desktop/src/locales/et/messages.json index 8396316416b..a34820dc5a8 100644 --- a/apps/desktop/src/locales/et/messages.json +++ b/apps/desktop/src/locales/et/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/eu/messages.json b/apps/desktop/src/locales/eu/messages.json index 2daed855e52..ff7faec50b1 100644 --- a/apps/desktop/src/locales/eu/messages.json +++ b/apps/desktop/src/locales/eu/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/fa/messages.json b/apps/desktop/src/locales/fa/messages.json index b79dc2d90ee..710e7ec3460 100644 --- a/apps/desktop/src/locales/fa/messages.json +++ b/apps/desktop/src/locales/fa/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json index 2d0a8cae996..fd3d9a8a3df 100644 --- a/apps/desktop/src/locales/fi/messages.json +++ b/apps/desktop/src/locales/fi/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Muuta tilin sähköpostiosoitetta" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/fil/messages.json b/apps/desktop/src/locales/fil/messages.json index 1f77b85e3c5..179cc7a2a55 100644 --- a/apps/desktop/src/locales/fil/messages.json +++ b/apps/desktop/src/locales/fil/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json index f0ab36ba636..5e6c9ed71a0 100644 --- a/apps/desktop/src/locales/fr/messages.json +++ b/apps/desktop/src/locales/fr/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Changer le courriel du compte" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/gl/messages.json b/apps/desktop/src/locales/gl/messages.json index 1a02e5db4e7..bca12f16a7d 100644 --- a/apps/desktop/src/locales/gl/messages.json +++ b/apps/desktop/src/locales/gl/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/he/messages.json b/apps/desktop/src/locales/he/messages.json index df61cefe73d..853e950dc0e 100644 --- a/apps/desktop/src/locales/he/messages.json +++ b/apps/desktop/src/locales/he/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/hi/messages.json b/apps/desktop/src/locales/hi/messages.json index 723ea0f6992..59c0f3df59f 100644 --- a/apps/desktop/src/locales/hi/messages.json +++ b/apps/desktop/src/locales/hi/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/hr/messages.json b/apps/desktop/src/locales/hr/messages.json index 109a1abff21..5fd7fae86a8 100644 --- a/apps/desktop/src/locales/hr/messages.json +++ b/apps/desktop/src/locales/hr/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Promjeni e-poštu računa" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/hu/messages.json b/apps/desktop/src/locales/hu/messages.json index 3716e1e67a9..19fd8a7fe49 100644 --- a/apps/desktop/src/locales/hu/messages.json +++ b/apps/desktop/src/locales/hu/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Fiók email cím megváltoztatása" + }, + "organizationUpgradeRequired": { + "message": "A szervezet felminősítése szükséges." + }, + "upgradeOrganization": { + "message": "Szervezeti áttérés" + }, + "upgradeOrganizationDesc": { + "message": "Ez a szolgáltatás nem elérhető ingyenes szervezeteknek. Váltás fizetős díjcsomagra a további funkciók feloldásához." } } diff --git a/apps/desktop/src/locales/id/messages.json b/apps/desktop/src/locales/id/messages.json index d4bcded0ee8..328200858e9 100644 --- a/apps/desktop/src/locales/id/messages.json +++ b/apps/desktop/src/locales/id/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/it/messages.json b/apps/desktop/src/locales/it/messages.json index c85127fce20..e58d2fd665d 100644 --- a/apps/desktop/src/locales/it/messages.json +++ b/apps/desktop/src/locales/it/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Cambia l'e-mail dell'account" + }, + "organizationUpgradeRequired": { + "message": "Aggiornamento dell'organizzazione richiesto" + }, + "upgradeOrganization": { + "message": "Aggiorna organizzazione" + }, + "upgradeOrganizationDesc": { + "message": "Questa funzione non è disponibile per le organizzazioni gratuite. Passa a un piano a pagamento per sbloccare più funzioni." } } diff --git a/apps/desktop/src/locales/ja/messages.json b/apps/desktop/src/locales/ja/messages.json index 9ce8f6a3ea7..671ab6c830e 100644 --- a/apps/desktop/src/locales/ja/messages.json +++ b/apps/desktop/src/locales/ja/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "アカウントのメールアドレスを変更する" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/ka/messages.json b/apps/desktop/src/locales/ka/messages.json index bf434a6c29f..a1951c542ad 100644 --- a/apps/desktop/src/locales/ka/messages.json +++ b/apps/desktop/src/locales/ka/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/km/messages.json b/apps/desktop/src/locales/km/messages.json index 1a02e5db4e7..bca12f16a7d 100644 --- a/apps/desktop/src/locales/km/messages.json +++ b/apps/desktop/src/locales/km/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/kn/messages.json b/apps/desktop/src/locales/kn/messages.json index f3401477f4a..840b73558c6 100644 --- a/apps/desktop/src/locales/kn/messages.json +++ b/apps/desktop/src/locales/kn/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/ko/messages.json b/apps/desktop/src/locales/ko/messages.json index 1aafdc4bc6d..38b1a2b9a55 100644 --- a/apps/desktop/src/locales/ko/messages.json +++ b/apps/desktop/src/locales/ko/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/lt/messages.json b/apps/desktop/src/locales/lt/messages.json index 11c70dd4197..1f010d33300 100644 --- a/apps/desktop/src/locales/lt/messages.json +++ b/apps/desktop/src/locales/lt/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/lv/messages.json b/apps/desktop/src/locales/lv/messages.json index 68495a25137..292cff77fba 100644 --- a/apps/desktop/src/locales/lv/messages.json +++ b/apps/desktop/src/locales/lv/messages.json @@ -2880,10 +2880,10 @@ "message": "Noteikta vāja parole, un tā ir atrasta datu noplūdē. Jāizmanto spēcīga un neatkārtojama parole, lai aizsargātu savu kontu. Vai tiešām izmantot šo paroli?" }, "useThisPassword": { - "message": "Use this password" + "message": "Izmantot šo paroli" }, "useThisUsername": { - "message": "Use this username" + "message": "Izmantot šo lietotājvārdu" }, "checkForBreaches": { "message": "Meklēt šo paroli zināmās datu noplūdēs" @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Mainīt konta e-pasta adresi" + }, + "organizationUpgradeRequired": { + "message": "Nepieciešams apvienības uzlabojums" + }, + "upgradeOrganization": { + "message": "Uzlabot apvienību" + }, + "upgradeOrganizationDesc": { + "message": "Šī iespēja nav pieejama bezmaksas apvienībām. Maksas plāna izvēle sniedz plašākas iespējas." } } diff --git a/apps/desktop/src/locales/me/messages.json b/apps/desktop/src/locales/me/messages.json index ac9994c3134..a03a80d01cd 100644 --- a/apps/desktop/src/locales/me/messages.json +++ b/apps/desktop/src/locales/me/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/ml/messages.json b/apps/desktop/src/locales/ml/messages.json index 15d4de334eb..41e4225c2df 100644 --- a/apps/desktop/src/locales/ml/messages.json +++ b/apps/desktop/src/locales/ml/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/mr/messages.json b/apps/desktop/src/locales/mr/messages.json index 1a02e5db4e7..bca12f16a7d 100644 --- a/apps/desktop/src/locales/mr/messages.json +++ b/apps/desktop/src/locales/mr/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/my/messages.json b/apps/desktop/src/locales/my/messages.json index ca399731495..2c16b832f33 100644 --- a/apps/desktop/src/locales/my/messages.json +++ b/apps/desktop/src/locales/my/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/nb/messages.json b/apps/desktop/src/locales/nb/messages.json index 0ebecf3be8f..f6fe08a8979 100644 --- a/apps/desktop/src/locales/nb/messages.json +++ b/apps/desktop/src/locales/nb/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/ne/messages.json b/apps/desktop/src/locales/ne/messages.json index 624547d2121..7be28d2ced5 100644 --- a/apps/desktop/src/locales/ne/messages.json +++ b/apps/desktop/src/locales/ne/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/nl/messages.json b/apps/desktop/src/locales/nl/messages.json index 6f3670afa3d..877acb0d0dc 100644 --- a/apps/desktop/src/locales/nl/messages.json +++ b/apps/desktop/src/locales/nl/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "E-mailadres van het account veranderen" + }, + "organizationUpgradeRequired": { + "message": "Organisatie-upgrade vereist" + }, + "upgradeOrganization": { + "message": "Organisatie upgraden" + }, + "upgradeOrganizationDesc": { + "message": "Deze mogelijkheid is niet beschikbaar voor gratis organisaties. Schakel over naar een betaald abonnement om meer mogelijkheden te ontgrendelen." } } diff --git a/apps/desktop/src/locales/nn/messages.json b/apps/desktop/src/locales/nn/messages.json index df2f70ae839..ef5a0603761 100644 --- a/apps/desktop/src/locales/nn/messages.json +++ b/apps/desktop/src/locales/nn/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/or/messages.json b/apps/desktop/src/locales/or/messages.json index ea55a1c6029..374cbf1bc95 100644 --- a/apps/desktop/src/locales/or/messages.json +++ b/apps/desktop/src/locales/or/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/pl/messages.json b/apps/desktop/src/locales/pl/messages.json index d7b950100f5..9cc63555545 100644 --- a/apps/desktop/src/locales/pl/messages.json +++ b/apps/desktop/src/locales/pl/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/pt_BR/messages.json b/apps/desktop/src/locales/pt_BR/messages.json index 312fe4e8e89..33bceb61667 100644 --- a/apps/desktop/src/locales/pt_BR/messages.json +++ b/apps/desktop/src/locales/pt_BR/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Alterar e-mail" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/pt_PT/messages.json b/apps/desktop/src/locales/pt_PT/messages.json index d88862a7980..61aa40e3307 100644 --- a/apps/desktop/src/locales/pt_PT/messages.json +++ b/apps/desktop/src/locales/pt_PT/messages.json @@ -2801,7 +2801,7 @@ "message": "Recusar início de sessão" }, "logInConfirmedForEmailOnDevice": { - "message": "Início de sessão confirmado para $EMAIL$ em $DEVICE$", + "message": "Início de sessão confirmado para $EMAIL$ no $DEVICE$", "placeholders": { "email": { "content": "$1", @@ -2814,7 +2814,7 @@ } }, "youDeniedALogInAttemptFromAnotherDevice": { - "message": "Negou uma tentativa de início de sessão de outro dispositivo. Se foi realmente o caso, tente iniciar sessão com o dispositivo novamente." + "message": "Recusou uma tentativa de início de sessão de outro dispositivo. Se foi realmente o caso, tente iniciar sessão com o dispositivo novamente." }, "justNow": { "message": "Agora mesmo" @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Alterar o e-mail da conta" + }, + "organizationUpgradeRequired": { + "message": "Atualização da organização necessária" + }, + "upgradeOrganization": { + "message": "Atualizar organização" + }, + "upgradeOrganizationDesc": { + "message": "Esta funcionalidade não está disponível para organizações gratuitas. Mude para um plano pago para desbloquear mais funcionalidades." } } diff --git a/apps/desktop/src/locales/ro/messages.json b/apps/desktop/src/locales/ro/messages.json index d4ca5e21a5e..17b9d050f03 100644 --- a/apps/desktop/src/locales/ro/messages.json +++ b/apps/desktop/src/locales/ro/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/ru/messages.json b/apps/desktop/src/locales/ru/messages.json index 46e04b77704..408bc373178 100644 --- a/apps/desktop/src/locales/ru/messages.json +++ b/apps/desktop/src/locales/ru/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Изменить email аккаунта" + }, + "organizationUpgradeRequired": { + "message": "Требуется обновление организации" + }, + "upgradeOrganization": { + "message": "Обновить организацию" + }, + "upgradeOrganizationDesc": { + "message": "Эта функция недоступна для бесплатных организаций. Переключитесь на платный план, чтобы разблокировать дополнительные возможности." } } diff --git a/apps/desktop/src/locales/si/messages.json b/apps/desktop/src/locales/si/messages.json index 5372bf59637..caec95368e5 100644 --- a/apps/desktop/src/locales/si/messages.json +++ b/apps/desktop/src/locales/si/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/sk/messages.json b/apps/desktop/src/locales/sk/messages.json index 07851ddc47e..1c253151ab1 100644 --- a/apps/desktop/src/locales/sk/messages.json +++ b/apps/desktop/src/locales/sk/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Zmeniť e-mail účtu" + }, + "organizationUpgradeRequired": { + "message": "Vyžaduje sa upgrade organizácie" + }, + "upgradeOrganization": { + "message": "Upgrade organizácie" + }, + "upgradeOrganizationDesc": { + "message": "Táto funkcia nie je k dispozícii pre bezplatné organizácie. Ak chcete odomknúť ďalšie funkcie, prejdite na platený plán." } } diff --git a/apps/desktop/src/locales/sl/messages.json b/apps/desktop/src/locales/sl/messages.json index c4fae11c815..cd36695335b 100644 --- a/apps/desktop/src/locales/sl/messages.json +++ b/apps/desktop/src/locales/sl/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index 03cc5b8c265..d4109a70bf5 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/sv/messages.json b/apps/desktop/src/locales/sv/messages.json index 920981908fa..e26e44c6923 100644 --- a/apps/desktop/src/locales/sv/messages.json +++ b/apps/desktop/src/locales/sv/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/te/messages.json b/apps/desktop/src/locales/te/messages.json index 1a02e5db4e7..bca12f16a7d 100644 --- a/apps/desktop/src/locales/te/messages.json +++ b/apps/desktop/src/locales/te/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/th/messages.json b/apps/desktop/src/locales/th/messages.json index 7f7e373132c..3298ed16682 100644 --- a/apps/desktop/src/locales/th/messages.json +++ b/apps/desktop/src/locales/th/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/tr/messages.json b/apps/desktop/src/locales/tr/messages.json index 2fbd751ddb8..76ba6cb9d2d 100644 --- a/apps/desktop/src/locales/tr/messages.json +++ b/apps/desktop/src/locales/tr/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Hesap e-postasını değiştir" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json index db0259adc05..4d9e8512421 100644 --- a/apps/desktop/src/locales/uk/messages.json +++ b/apps/desktop/src/locales/uk/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Змінити адресу е-пошти" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/vi/messages.json b/apps/desktop/src/locales/vi/messages.json index 07dcdfd373c..c0e79109ad8 100644 --- a/apps/desktop/src/locales/vi/messages.json +++ b/apps/desktop/src/locales/vi/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "Change account email" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index c9046b34a55..54b51259a8b 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "更改账户电子邮箱" + }, + "organizationUpgradeRequired": { + "message": "需要升级组织" + }, + "upgradeOrganization": { + "message": "升级组织" + }, + "upgradeOrganizationDesc": { + "message": "此功能不适用于免费组织。请切换到付费计划以解锁更多功能。" } } diff --git a/apps/desktop/src/locales/zh_TW/messages.json b/apps/desktop/src/locales/zh_TW/messages.json index a9206a50df6..c59d3f8ddfb 100644 --- a/apps/desktop/src/locales/zh_TW/messages.json +++ b/apps/desktop/src/locales/zh_TW/messages.json @@ -3474,5 +3474,14 @@ }, "changeAcctEmail": { "message": "更改帳號電子郵件位址" + }, + "organizationUpgradeRequired": { + "message": "Organization upgrade required" + }, + "upgradeOrganization": { + "message": "Upgrade organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } } From 9eb7daa77d3b90c47f97ac2d5a7e3d938c124cc1 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:13:00 +0100 Subject: [PATCH 02/17] Autosync the updated translations (#12923) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/browser/src/_locales/ar/messages.json | 17 +++--- apps/browser/src/_locales/az/messages.json | 17 +++--- apps/browser/src/_locales/be/messages.json | 17 +++--- apps/browser/src/_locales/bg/messages.json | 19 +++---- apps/browser/src/_locales/bn/messages.json | 17 +++--- apps/browser/src/_locales/bs/messages.json | 17 +++--- apps/browser/src/_locales/ca/messages.json | 17 +++--- apps/browser/src/_locales/cs/messages.json | 17 +++--- apps/browser/src/_locales/cy/messages.json | 17 +++--- apps/browser/src/_locales/da/messages.json | 17 +++--- apps/browser/src/_locales/de/messages.json | 25 ++++----- apps/browser/src/_locales/el/messages.json | 19 +++---- apps/browser/src/_locales/en_GB/messages.json | 19 +++---- apps/browser/src/_locales/en_IN/messages.json | 19 +++---- apps/browser/src/_locales/es/messages.json | 19 +++---- apps/browser/src/_locales/et/messages.json | 17 +++--- apps/browser/src/_locales/eu/messages.json | 17 +++--- apps/browser/src/_locales/fa/messages.json | 17 +++--- apps/browser/src/_locales/fi/messages.json | 19 +++---- apps/browser/src/_locales/fil/messages.json | 17 +++--- apps/browser/src/_locales/fr/messages.json | 19 +++---- apps/browser/src/_locales/gl/messages.json | 47 ++++++++-------- apps/browser/src/_locales/he/messages.json | 19 +++---- apps/browser/src/_locales/hi/messages.json | 17 +++--- apps/browser/src/_locales/hr/messages.json | 19 +++---- apps/browser/src/_locales/hu/messages.json | 17 +++--- apps/browser/src/_locales/id/messages.json | 19 +++---- apps/browser/src/_locales/it/messages.json | 19 +++---- apps/browser/src/_locales/ja/messages.json | 19 +++---- apps/browser/src/_locales/ka/messages.json | 17 +++--- apps/browser/src/_locales/km/messages.json | 17 +++--- apps/browser/src/_locales/kn/messages.json | 17 +++--- apps/browser/src/_locales/ko/messages.json | 19 +++---- apps/browser/src/_locales/lt/messages.json | 17 +++--- apps/browser/src/_locales/lv/messages.json | 19 +++---- apps/browser/src/_locales/ml/messages.json | 17 +++--- apps/browser/src/_locales/mr/messages.json | 17 +++--- apps/browser/src/_locales/my/messages.json | 17 +++--- apps/browser/src/_locales/nb/messages.json | 19 +++---- apps/browser/src/_locales/ne/messages.json | 17 +++--- apps/browser/src/_locales/nl/messages.json | 17 +++--- apps/browser/src/_locales/nn/messages.json | 17 +++--- apps/browser/src/_locales/or/messages.json | 17 +++--- apps/browser/src/_locales/pl/messages.json | 19 +++---- apps/browser/src/_locales/pt_BR/messages.json | 19 +++---- apps/browser/src/_locales/pt_PT/messages.json | 17 +++--- apps/browser/src/_locales/ro/messages.json | 17 +++--- apps/browser/src/_locales/ru/messages.json | 17 +++--- apps/browser/src/_locales/si/messages.json | 17 +++--- apps/browser/src/_locales/sk/messages.json | 17 +++--- apps/browser/src/_locales/sl/messages.json | 17 +++--- apps/browser/src/_locales/sr/messages.json | 19 +++---- apps/browser/src/_locales/sv/messages.json | 17 +++--- apps/browser/src/_locales/te/messages.json | 17 +++--- apps/browser/src/_locales/th/messages.json | 17 +++--- apps/browser/src/_locales/tr/messages.json | 43 +++++++-------- apps/browser/src/_locales/uk/messages.json | 39 +++++++------- apps/browser/src/_locales/vi/messages.json | 19 +++---- apps/browser/src/_locales/zh_CN/messages.json | 17 +++--- apps/browser/src/_locales/zh_TW/messages.json | 19 +++---- apps/browser/store/locales/ru/copy.resx | 53 +++++++++---------- 61 files changed, 509 insertions(+), 690 deletions(-) diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index 8b4bbe23e04..30f20dfff1d 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "الموقع $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index 86f1d07fb3f..9184b84d735 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Bu veb saytlar üçün avto-doldurma və digər əlaqəli özəlliklər təklif olunmayacaq. Dəyişikliklərin qüvvəyə minməsi üçün səhifəni təzələməlisiniz." }, - "autofillBlockedNotice": { - "message": "Bu veb sayt üçün avto-doldurma əngəllənib. Bunu ayarlarda incələyin və ya dəyişdirin." + "autofillBlockedNoticeV2": { + "message": "Bu veb sayt üçün avto-doldurma əngəllənib." }, - "autofillBlockedTooltip": { - "message": "Bu veb saytda avto-doldurma əngəllənib. Ayarlarda incələyin." + "autofillBlockedNoticeGuidance": { + "message": "Bunu ayarlarda dəyişdir" }, "websiteItemLabel": { "message": "Veb sayt $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Avto-doldurma təklifləri" }, + "itemSuggestions": { + "message": "Təklif olunan elementlər" + }, "autofillSuggestionsTip": { "message": "Bu saytın avto-doldurması üçün giriş elementini saxlayın" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Mətn \"Send\"ləri" }, - "bitwardenNewLook": { - "message": "Bitwarden-in yeni bir görünüşü var!" - }, - "bitwardenNewLookDesc": { - "message": "Seyf vərəqindən avto-doldurma və axtarış etmə artıq daha asan və intuitivdir. Nəzər salın!" - }, "accountActions": { "message": "Hesab fəaliyyətləri" }, diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index 036b1dfcb24..66545d5666b 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Вэб-сайт $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 098e2b91051..d4f81883672 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Автоматичното попълване и други свързани функции няма да бъдат предлагани за тези уеб сайтове. Трябва да презаредите страницата, за да влязат в сила промените." }, - "autofillBlockedNotice": { - "message": "Автоматичното попълване е блокирано за този уеб сайт. Можете да прегледате и промените това в настройките." + "autofillBlockedNoticeV2": { + "message": "Автоматичното попълване е блокирано за този уеб сайт." }, - "autofillBlockedTooltip": { - "message": "Автоматичното попълване е блокирано за този уеб сайт. Можете да прегледате това в настройките." + "autofillBlockedNoticeGuidance": { + "message": "Променете това в настройките" }, "websiteItemLabel": { "message": "Уеб сайт $number$ (адрес)", @@ -4008,7 +4008,10 @@ "message": "Секретният ключ е премахнат" }, "autofillSuggestions": { - "message": "Автоматично попълване на предложения" + "message": "Предложения за авт. попълване" + }, + "itemSuggestions": { + "message": "Препоръчани елементи" }, "autofillSuggestionsTip": { "message": "Запазване на елемент за вписване за този уеб сайт, за авт. попълване" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Текстови изпращания" }, - "bitwardenNewLook": { - "message": "Биуорден има нов облик!" - }, - "bitwardenNewLookDesc": { - "message": "Сега е по-лесно и интуитивно от всякога да използвате автоматичното попълване и да търсите в раздела на трезора. Разгледайте!" - }, "accountActions": { "message": "Действия по регистрацията" }, diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index f60fc2c9683..8180813a2cf 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index aaf04da98b7..0bd4144f6cd 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index e7113d5aab1..ec7682f5013 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index eb2f9149daf..c40ddfc6ed9 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Automatické vyplňování a další související funkce nebudou pro tyto webové stránky nabízeny. Aby se změny projevily, musíte stránku aktualizovat." }, - "autofillBlockedNotice": { - "message": "Automatické vyplňování je pro tento web zablokováno. Zkontrolujte to nebo to změňte v nastavení." + "autofillBlockedNoticeV2": { + "message": "Automatické vyplňování je pro tuto stránku zablokováno." }, - "autofillBlockedTooltip": { - "message": "Automatické vyplňování je pro tento web zablokováno. Zkontrolujte to v nastavení." + "autofillBlockedNoticeGuidance": { + "message": "Změňte to v nastavení" }, "websiteItemLabel": { "message": "Webová stránka $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Návrhy automatického vyplňování" }, + "itemSuggestions": { + "message": "Navrhované položky" + }, "autofillSuggestionsTip": { "message": "Uložit přihlašovací údaje pro tuto stránku do automatického vyplňování" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Sends s texty" }, - "bitwardenNewLook": { - "message": "Bitwarden má nový vzhled!" - }, - "bitwardenNewLookDesc": { - "message": "Je snazší a intuitivnější než kdy jindy automaticky vyplňovat a vyhledávat z karty trezor. Mrkněte se!" - }, "accountActions": { "message": "Činnosti účtu" }, diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json index 8ad494f0bfb..cfa74caaa32 100644 --- a/apps/browser/src/_locales/cy/messages.json +++ b/apps/browser/src/_locales/cy/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index 9008049e1a4..c5e69fc375b 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofyldning og andre relaterede funktioner tilbydes ikke på disse websteder. Siden skal opdateres for at effektuere ændringerne." }, - "autofillBlockedNotice": { - "message": "Autoudfyldning er blokeret på dette websted. Gennemgå eller ændr dette i Indstillinger." + "autofillBlockedNoticeV2": { + "message": "Autoudfyldning blokeret for dette websted." }, - "autofillBlockedTooltip": { - "message": "Autoudfyldning er blokeret på dette websted. Gennemgå i Indstillinger." + "autofillBlockedNoticeGuidance": { + "message": "Ændr dette i Indstillinger" }, "websiteItemLabel": { "message": "Websted $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autoudfyldningsforslag" }, + "itemSuggestions": { + "message": "Foreslåede emner" + }, "autofillSuggestionsTip": { "message": "Gem et loginemne for dette websted til autoudfyldning" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Tekst-Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden har fået et nyt look!" - }, - "bitwardenNewLookDesc": { - "message": "Det er lettere og mere intuitivt end nogensinde at autoudfylde og søge via fanen Boks. Tag et kig omkring!" - }, "accountActions": { "message": "Kontohandlinger" }, diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index fce84d1b431..872307dd945 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -2337,13 +2337,13 @@ "message": "Bitwarden wird für alle angemeldeten Konten nicht danach fragen Zugangsdaten für diese Domains speichern. Du musst die Seite neu laden, damit die Änderungen wirksam werden." }, "blockedDomainsDesc": { - "message": "Automatisches Ausfüllen und andere zugehörige Funktionen werden für diese Webseiten nicht angeboten. Sie müssen die Seite aktualisieren, damit die Änderungen wirksam werden." + "message": "Automatisches Ausfüllen und andere zugehörige Funktionen werden für diese Webseiten nicht angeboten. Du musst die Seite neu laden, damit die Änderungen wirksam werden." }, - "autofillBlockedNotice": { - "message": "Das automatische Ausfüllen ist für diese Website gesperrt. Dieses Verhalten kann in den Einstellungen überprüft oder geändert werden." + "autofillBlockedNoticeV2": { + "message": "Automatisches Ausfüllen ist für diese Website gesperrt." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Dies in den Einstellungen ändern" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -2808,14 +2808,14 @@ "message": "Entschlüsselungsfehler" }, "couldNotDecryptVaultItemsBelow": { - "message": "Bitwarden konnte den unten aufgelisteten Tresoreintrag bzw. die Tresoreinträge nicht entschlüsseln." + "message": "Bitwarden konnte folgende(n) Tresor-Eintrag/Einträge nicht entschlüsseln." }, "contactCSToAvoidDataLossPart1": { - "message": "Contact customer success", + "message": "Kontaktiere den Kundensupport", "description": "This is part of a larger sentence. The full sentence will read 'Contact customer success to avoid additional data loss.'" }, "contactCSToAvoidDataLossPart2": { - "message": "um zusätzlichen Datenverlust zu vermeiden.", + "message": ", um zusätzlichen Datenverlust zu vermeiden.", "description": "This is part of a larger sentence. The full sentence will read 'Contact customer success to avoid additional data loss.'" }, "generateUsername": { @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Vorschläge zum Auto-Ausfüllen" }, + "itemSuggestions": { + "message": "Vorgeschlagene Einträge" + }, "autofillSuggestionsTip": { "message": "Speichere einen Login-Eintrag für diese Seite zum automatischen Ausfüllen" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text-Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden hat einen neuen Look!" - }, - "bitwardenNewLookDesc": { - "message": "Auto-Ausfüllen und Suchen vom Tresor-Tab ist einfacher und intuitiver als je zuvor. Schau dich um!" - }, "accountActions": { "message": "Konto-Aktionen" }, diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index bdb0eb2c17d..37ddbc081f7 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Η αυτόματη συμπλήρωση και άλλες σχετικές λειτουργίες δεν θα προσφερθούν για αυτούς τους ιστότοπους. Πρέπει να ανανεώσετε τη σελίδα για να τεθούν σε ισχύ οι αλλαγές." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Ιστοσελίδα $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Το κλειδί πρόσβασης αφαιρέθηκε" }, "autofillSuggestions": { - "message": "Προτάσεις αυτόματης συμπλήρωσης" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Αποθηκεύστε ένα αντικείμενο σύνδεσης για την αυτόματη συμπλήρωση αυτού του ιστοτόπου" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Send κειμένων" }, - "bitwardenNewLook": { - "message": "Το Bitwarden έχει μια νέα εμφάνιση!" - }, - "bitwardenNewLookDesc": { - "message": "Είναι πιο ευκολότερο και πιο διαισθητικό από ποτέ στην αυτόματη συμπλήρωση και αναζήτηση από την καρτέλα Θησαυ/κιο. Ρίξτε μια ματιά τριγύρω!" - }, "accountActions": { "message": "Ενέργειες λογαριασμού" }, diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index 7e938bb6b2c..5a3ca3893b7 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Passkey removed" }, "autofillSuggestions": { - "message": "Auto-fill suggestions" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Save a login item for this site to auto-fill" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 70e725c3a88..0783f0e9172 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Passkey removed" }, "autofillSuggestions": { - "message": "Auto-fill suggestions" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Save a login item for this site to auto-fill" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index d9cd2517816..37a823b77f4 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Clave de acceso eliminada" }, "autofillSuggestions": { - "message": "Autocompletar sugerencias" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Guarda un elemento de inicio de sesión para este sitio para autocompletar" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden tiene un aspecto nuevo." - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Acciones de cuenta" }, diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index 5245de4fb7e..b4401bd8850 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index fc875be6da0..67d45a17458 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index d2362a2655f..1eff69e292f 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index 0dd96ef9a02..143cc603144 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Verkkotunnus $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Pääsyavain poistettiin" }, "autofillSuggestions": { - "message": "Automaattitäytön ehdotukset" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Tallenna tälle sivustolle automaattisesti täytettävä kirjautumistieto." @@ -4586,12 +4589,6 @@ "textSends": { "message": "Teksti-Sendit" }, - "bitwardenNewLook": { - "message": "Bitwardenilla on uusi ulkoasu!" - }, - "bitwardenNewLookDesc": { - "message": "Automaattinen täyttö ja sisällön haku Holvi-välilehdeltä on nyt entistä helpompaa ja luontevampaa. Kokeile nyt!" - }, "accountActions": { "message": "Tilitoiminnot" }, diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index d0fdf1018fb..0c24db214a2 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index 913391d218c..890d00b644f 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Site web $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Clé d'identification (passkey) retirée" }, "autofillSuggestions": { - "message": "Suggestions de saisie automatique" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Enregistrez un élément de connexion à remplir automatiquement pour ce site" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden a un nouveau look !" - }, - "bitwardenNewLookDesc": { - "message": "Il est plus facile et plus intuitif que jamais de remplir automatiquement les champs et d'effectuer des recherches à partir de l'onglet \"Coffre\". Jetez un coup d'œil !" - }, "accountActions": { "message": "Actions du compte" }, diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index e655159f246..9f5e7771a14 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -2325,7 +2325,7 @@ "description": "A category title describing the concept of web domains" }, "blockedDomains": { - "message": "Blocked domains" + "message": "Dominios bloqueados" }, "excludedDomains": { "message": "Dominios excluídos" @@ -2337,13 +2337,13 @@ "message": "Bitwarden non ofrecerá gardar contas para estes dominios en ningunha das sesións iniciadas. Recarga a páxina para que os cambios fornezan efecto." }, "blockedDomainsDesc": { - "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." + "message": "O autoenchido e outras funcións relacionadas non estarán dispoñibles para estas webs. Debes recargar a páxina para que os cambios teñan efecto." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "O autoenchido está bloqueado para esta web." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Cambia isto en axustes" }, "websiteItemLabel": { "message": "Web $number$ (URI)", @@ -2364,7 +2364,7 @@ } }, "blockedDomainsSavedSuccess": { - "message": "Blocked domain changes saved" + "message": "Dominios bloqueados gardados" }, "excludedDomainsSavedSuccess": { "message": "Dominios excluídos gardados" @@ -2805,17 +2805,17 @@ "message": "Erro" }, "decryptionError": { - "message": "Decryption error" + "message": "Erro de descifrado" }, "couldNotDecryptVaultItemsBelow": { - "message": "Bitwarden could not decrypt the vault item(s) listed below." + "message": "Bitwarden non puido descifrar os seguintes elementos." }, "contactCSToAvoidDataLossPart1": { - "message": "Contact customer success", + "message": "Contacto co cliente exitoso", "description": "This is part of a larger sentence. The full sentence will read 'Contact customer success to avoid additional data loss.'" }, "contactCSToAvoidDataLossPart2": { - "message": "to avoid additional data loss.", + "message": "para evitar a perda de datos.", "description": "This is part of a larger sentence. The full sentence will read 'Contact customer success to avoid additional data loss.'" }, "generateUsername": { @@ -4008,7 +4008,10 @@ "message": "Clave de acceso eliminada" }, "autofillSuggestions": { - "message": "Suxestións de autoenchido" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Entradas suxeridas" }, "autofillSuggestionsTip": { "message": "Gardar unha credencial como suxestión para este sitio" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Textos Send" }, - "bitwardenNewLook": { - "message": "Bitwarden ten un novo look!" - }, - "bitwardenNewLookDesc": { - "message": "É máis fácil e intuitivo que nunca autoencher e buscar dende a caixa forte. Bota un ollo!" - }, "accountActions": { "message": "Accións da conta" }, @@ -4671,22 +4668,22 @@ "message": "Non tes permiso para modificar esta entrada" }, "biometricsStatusHelptextUnlockNeeded": { - "message": "Biometric unlock is unavailable because PIN or password unlock is required first." + "message": "O desbloqueo biométrico non está dispoñible porque se require o PIN ou contrasinal primeiro." }, "biometricsStatusHelptextHardwareUnavailable": { - "message": "Biometric unlock is currently unavailable." + "message": "O desbloqueo biométrico non está dispoñible." }, "biometricsStatusHelptextAutoSetupNeeded": { - "message": "Biometric unlock is unavailable due to misconfigured system files." + "message": "O desbloqueo biométrico non está dispoñible por arquivos do sistema desconfigurados." }, "biometricsStatusHelptextManualSetupNeeded": { - "message": "Biometric unlock is unavailable due to misconfigured system files." + "message": "O desbloqueo biométrico non está dispoñible por arquivos do sistema desconfigurados." }, "biometricsStatusHelptextDesktopDisconnected": { - "message": "Biometric unlock is unavailable because the Bitwarden desktop app is closed." + "message": "O desbloqueo biométrico non está dispoñible porque a aplicación de escritorio está pechada." }, "biometricsStatusHelptextNotEnabledInDesktop": { - "message": "Biometric unlock is unavailable because it is not enabled for $EMAIL$ in the Bitwarden desktop app.", + "message": "O desbloqueo biométrico non está dispoñible porque non está activada para $EMAIL$ na aplicación de escritorio.", "placeholders": { "email": { "content": "$1", @@ -4695,7 +4692,7 @@ } }, "biometricsStatusHelptextUnavailableReasonUnknown": { - "message": "Biometric unlock is currently unavailable for an unknown reason." + "message": "O desbloqueo biométrico non está dispoñible por algunha razón non prevista." }, "authenticating": { "message": "Autenticando" diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index 1a3057ac291..19c0d292d14 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Passkey removed" }, "autofillSuggestions": { - "message": "Autofill suggestions" + "message": "הצעות למילוי אוטומטי" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index fd4a6612af4..3db3ef3e293 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "बिटवार्डन का नया रूप!" - }, - "bitwardenNewLookDesc": { - "message": "वॉल्ट टैब से ऑटोफिल और सर्च करना पहले से कहीं ज़्यादा आसान और सहज है। सबकुछ ध्यान से देखें!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index 331bc109309..8d830fd6dc5 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Web stranica $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Pristupni ključ uklonjen" }, "autofillSuggestions": { - "message": "Prijedlozi auto-ispune" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Spremi u auto-ispunu stavku prijave za ovu stranicu" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Send tekstovi" }, - "bitwardenNewLook": { - "message": "Bitwarden ima novi izgled!" - }, - "bitwardenNewLookDesc": { - "message": "Auto-ispuna i pretraga iz kartice Trezor je lakša i intuitivnija nego ikad prije. Razgledaj!" - }, "accountActions": { "message": "Radnje na računu" }, diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index 0aea2c7eced..07bc92c342a 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Az automatikus kitöltés és az egyéb kapcsolódó funkciók ezeken a webhelyeken nincsenek a kínálatban. A változtatások életbe lépéséhez frissíteni kell az oldalt." }, - "autofillBlockedNotice": { - "message": "Az automatikus kitöltés le van tiltva ezen a webhelyen. Tekintsük át vagy módosítsuk ezt a beállításokban." + "autofillBlockedNoticeV2": { + "message": "Az automatikus kitöltés blokkolásra került ezen a webhelyen." }, - "autofillBlockedTooltip": { - "message": "Az automatikus kitöltés le van tiltva ezen a webhelyen. Tekintsük át ezt a beállításokban." + "autofillBlockedNoticeGuidance": { + "message": "Megváltoztatás a beállításokban" }, "websiteItemLabel": { "message": "Webhely $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Automatikus kitöltés javaslatok" }, + "itemSuggestions": { + "message": "Javasolt elemek" + }, "autofillSuggestionsTip": { "message": "A bejelentkezési elem mentése ehhez a webhelyhez az automatikus kitöltéshez" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Szöveg küldés" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Fiókműveletek" }, diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index 82776a8e82b..9755e7322a2 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Situs web $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Kunci sandi dihapus" }, "autofillSuggestions": { - "message": "Saran isi otomatis" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Simpan benda login untuk situs ini ke isi otomatis" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index 04e2c4ee64f..e0a868717a5 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Per questi siti, l'auto-completamento e funzionalità simili non saranno disponibili. Ricarica la pagina per applicare le modifiche." }, - "autofillBlockedNotice": { - "message": "L'auto-completamento è bloccato per questo sito. Modifica questa scelta nelle impostazioni." + "autofillBlockedNoticeV2": { + "message": "La compilazione automatica è bloccata per questo sito." }, - "autofillBlockedTooltip": { - "message": "L'auto-completamento è bloccato per questo sito. Verifica nelle impostazioni." + "autofillBlockedNoticeGuidance": { + "message": "Modifica questo nelle impostazioni" }, "websiteItemLabel": { "message": "Sito $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Passkey rimossa" }, "autofillSuggestions": { - "message": "Suggerimenti per il riempimento automatico" + "message": "Suggerimenti riempimento automatico" + }, + "itemSuggestions": { + "message": "Elementi suggeriti" }, "autofillSuggestionsTip": { "message": "Salva un elemento di accesso per questo sito da riempire automaticamente" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Send Testo" }, - "bitwardenNewLook": { - "message": "Bitwarden ha un nuovo look!" - }, - "bitwardenNewLookDesc": { - "message": "È più facile e intuitivo che mai utilizzare il riempimento automatico e cercare dalla scheda Cassaforte. Dai un'occhiata!" - }, "accountActions": { "message": "Azioni dell'account" }, diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index cc1f34e4985..81b81cf16c8 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "ウェブサイト $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "パスキーを削除しました" }, "autofillSuggestions": { - "message": "候補を自動入力する" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "自動入力するためにこのサイトのログインアイテムを保存します" @@ -4586,12 +4589,6 @@ "textSends": { "message": "テキスト Send" }, - "bitwardenNewLook": { - "message": "Bitwarden が新しい外観になりました。" - }, - "bitwardenNewLookDesc": { - "message": "保管庫タブからの自動入力と検索がこれまで以上に簡単で直感的になりました。" - }, "accountActions": { "message": "アカウントの操作" }, diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index 50fdc6613c5..9bd12ce6017 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index e34751eea7d..ad7d2582146 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index 3f9e99e5637..d613ba26953 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 4ac6d281b09..8aad2f586c7 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "웹사이트 $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "패스키 제거됨" }, "autofillSuggestions": { - "message": "자동 완성 제안" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "이 사이트에서 자동으로 작성할 로그인 항목 저장" @@ -4586,12 +4589,6 @@ "textSends": { "message": "텍스트 Send" }, - "bitwardenNewLook": { - "message": "Bitwarden이 새로운 모습으로 돌아왔습니다!" - }, - "bitwardenNewLookDesc": { - "message": "보관함 탭에서 자동 완성하고 검색하는 것이 그 어느 때보다 쉽고 직관적입니다. 둘러보세요!" - }, "accountActions": { "message": "계정 작업" }, diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index 3c81df00f10..a29c60d5e8c 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index fc682ced389..c1cdd0182a9 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Automātiskā aizpilde un citas saistītās iespējas šajās tīmekļvietnēs netiks piedāvātas. Ir jāatsvaidzina lapa, lai izmaiņas iedarbotos." }, - "autofillBlockedNotice": { - "message": "Automātiskā aizpilde šajā tīmekļvietnē ir liegta. Šo pārskatīt vai mainīt var iestatījumos." + "autofillBlockedNoticeV2": { + "message": "Automātiskā aizpilde šajā tīmekļvietnē ir liegta." }, - "autofillBlockedTooltip": { - "message": "Automātiskā aizpilde šajā tīmekļvietnē ir liegta. Šo var pārskatīt iestatījumos." + "autofillBlockedNoticeGuidance": { + "message": "To var mainīt iestatījumos" }, "websiteItemLabel": { "message": "Tīmekļvietne $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Piekļuves atslēga noņemta" }, "autofillSuggestions": { - "message": "Ieteikumi automātiskajai aizpildei" + "message": "Automātiskās aizpildes ieteikumi" + }, + "itemSuggestions": { + "message": "Ieteiktie vienumi" }, "autofillSuggestionsTip": { "message": "Saglabāt pieteikšanās vienumi, ko automātiski aizpildīt šajā vietnē" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Teksta Send" }, - "bitwardenNewLook": { - "message": "Bitwarden ir jauns izskats." - }, - "bitwardenNewLookDesc": { - "message": "Veikt automātisko aizpildi un meklēšanu glabātavas cilnē ir vienkāršāk un izprotamāk kā jebkad. Apskati izmaiņas!" - }, "accountActions": { "message": "Konta darbības" }, diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index 4cbbfc46d6a..f985f6377ac 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json index cbb0b1bdf1a..26c0af364ad 100644 --- a/apps/browser/src/_locales/mr/messages.json +++ b/apps/browser/src/_locales/mr/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json index e34751eea7d..ad7d2582146 100644 --- a/apps/browser/src/_locales/my/messages.json +++ b/apps/browser/src/_locales/my/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index 3a12c9ae4f4..17cd112b2e8 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Passkey removed" }, "autofillSuggestions": { - "message": "Autoutfyllingsforslag" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden har fått et nytt utseende!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index e34751eea7d..ad7d2582146 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index 0112ded1983..c8e0b46f7e4 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill en andere gerelateerde functies worden niet aangeboden voor deze websites. Vernieuw de pagina om de wijzigingen toe te passen." }, - "autofillBlockedNotice": { - "message": "Automatisch invullen is geblokkeerd voor deze website. Bekijk of verander dit in de instellingen." + "autofillBlockedNoticeV2": { + "message": "Autofill is geblokkeerd voor deze website." }, - "autofillBlockedTooltip": { - "message": "Automatisch invullen is geblokkeerd voor deze website. Bekijk in de instellingen." + "autofillBlockedNoticeGuidance": { + "message": "Dit aanpassen in instellingen" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Suggesties automatisch invullen" }, + "itemSuggestions": { + "message": "Voorgestelde items" + }, "autofillSuggestionsTip": { "message": "Inlogitem opslaan voor automatisch invullen op deze site" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Tekst-Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden heeft een nieuw uiterlijk!" - }, - "bitwardenNewLookDesc": { - "message": "Automatisch invullen en zoeken is makkelijker en intuïtiever dan ooit vanaf het tabblad Kluis. Kijk rond!" - }, "accountActions": { "message": "Accountacties" }, diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index e34751eea7d..ad7d2582146 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json index e34751eea7d..ad7d2582146 100644 --- a/apps/browser/src/_locales/or/messages.json +++ b/apps/browser/src/_locales/or/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index 4b7d3a19fc4..b14cd9961a0 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Strona internetowa $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Passkey został usunięty" }, "autofillSuggestions": { - "message": "Sugestie autouzupełnienia" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Zapisz element logowania dla tej witryny, aby automatycznie wypełnić" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden ma nowy wygląd!" - }, - "bitwardenNewLookDesc": { - "message": "Auto wypełnianie i szukanie na zakładce sejfu jest teraz prostsze i bardziej intuicyjne. Rozejrzyj się tam!" - }, "accountActions": { "message": "Akcje konta" }, diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index e3409b1da52..3ac6412a3cd 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Site $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Chave de acesso removida" }, "autofillSuggestions": { - "message": "Sugestões de autopreenchimento" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Salvar um item de login para este site autopreenchimento" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Texto enviado" }, - "bitwardenNewLook": { - "message": "Bitwarden tem uma nova aparência!" - }, - "bitwardenNewLookDesc": { - "message": "É mais fácil e mais intuitivo do que nunca autopreenchimento e pesquise na guia Cofre. Dê uma olhada ao redor!" - }, "accountActions": { "message": "Ações da conta" }, diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index 6b3c190f0b5..f2f7cd23247 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "O preenchimento automático e outras funcionalidades relacionadas não serão disponibilizados para estes sites. É necessário atualizar a página para que as alterações tenham efeito." }, - "autofillBlockedNotice": { - "message": "O preenchimento automático está bloqueado para este site. Reveja ou altere esta opção nas definições." + "autofillBlockedNoticeV2": { + "message": "O preenchimento automático está bloqueado para este site." }, - "autofillBlockedTooltip": { - "message": "O preenchimento automático está bloqueado neste site. Reveja nas definições." + "autofillBlockedNoticeGuidance": { + "message": "Alterar esta opção nas definições" }, "websiteItemLabel": { "message": "Site $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Sugestões de preenchimento automático" }, + "itemSuggestions": { + "message": "Itens sugeridos" + }, "autofillSuggestionsTip": { "message": "Guarde uma credencial deste site para preenchimento automático" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Sends de texto" }, - "bitwardenNewLook": { - "message": "O Bitwarden tem um novo visual!" - }, - "bitwardenNewLookDesc": { - "message": "É mais fácil e mais intuitivo do que nunca preencher automaticamente e pesquisar a partir do separador Cofre. Dê uma vista de olhos!" - }, "accountActions": { "message": "Ações da conta" }, diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index 114c01aff44..04b3e02fc98 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index 53f31813ac5..605f1bb9a49 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Автозаполнение и другие связанные с ним функции не будут предлагаться для этих сайтов. Чтобы изменения вступили в силу, необходимо обновить страницу." }, - "autofillBlockedNotice": { - "message": "Автозаполнение для этого сайта заблокировано. Просмотрите или измените это в настройках." + "autofillBlockedNoticeV2": { + "message": "Автозаполнение для этого сайта заблокировано." }, - "autofillBlockedTooltip": { - "message": "Автозаполнение на этом сайте заблокировано. Просмотрите в настройках." + "autofillBlockedNoticeGuidance": { + "message": "Измените это в настройках" }, "websiteItemLabel": { "message": "Сайт $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Предложения по автозаполнению" }, + "itemSuggestions": { + "message": "Предлагаемые элементы" + }, "autofillSuggestionsTip": { "message": "Сохранить логин для этого сайта для автозаполнения" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Текстовая Send" }, - "bitwardenNewLook": { - "message": "У Bitwarden новый облик!" - }, - "bitwardenNewLookDesc": { - "message": "Теперь автозаполнение и поиск на вкладке Хранилище стали проще и интуитивно понятнее, чем когда-либо. Осмотритесь!" - }, "accountActions": { "message": "Действия аккаунта" }, diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index 56cf378344f..6a7bb304315 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index 08bfcc79f6a..e1020228e87 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Automatické vypĺňanie a ďalšie súvisiace funkcie sa na týchto webových stránkach nebudú ponúkať. Aby sa zmeny prejavili, musíte stránku obnoviť." }, - "autofillBlockedNotice": { - "message": "Automatické vypĺňanie je pre túto webovú stránku zablokované. Skontrolujte alebo zmeňte to v nastaveniach." + "autofillBlockedNoticeV2": { + "message": "Automatické vypĺňanie je pre túto webovú stránku zablokované." }, - "autofillBlockedTooltip": { - "message": "Automatické vypĺňanie je na tejto webovej stránke zablokované. Pozrite v nastaveniach." + "autofillBlockedNoticeGuidance": { + "message": "Zmeňte to v nastaveniach" }, "websiteItemLabel": { "message": "Webstránka $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Návrhy automatického vypĺňania" }, + "itemSuggestions": { + "message": "Navrhované položky" + }, "autofillSuggestionsTip": { "message": "Uložte položku prihlásenia pre tento web na automatické vyplnenie" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Textové Sendy" }, - "bitwardenNewLook": { - "message": "Bitwarden má nový vzhľad!" - }, - "bitwardenNewLookDesc": { - "message": "Automatické vypĺňanie a vyhľadávanie na karte Trezor je jednoduchšie a intuitívnejšie ako kedykoľvek predtým. Poobzerajte sa!" - }, "accountActions": { "message": "Operácie s účtom" }, diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 2d2ee455415..db8558b0a32 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 01d95a6ed1b..948956bb360 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Сајт $number$ (УРЛ)", @@ -4008,7 +4008,10 @@ "message": "Приступни кључ је уклоњен" }, "autofillSuggestions": { - "message": "Предлози за ауто-попуњавање" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Сачувајте ставку за пријаву за ову локацију за ауто-попуњавање" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Текст „Send“" }, - "bitwardenNewLook": { - "message": "Bitwarden има нови изглед!" - }, - "bitwardenNewLookDesc": { - "message": "Лакше је и интуитивније него икада да се аутоматски попуњава и тражи са картице Сефа. Проверите!" - }, "accountActions": { "message": "Акције везане за налог" }, diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index a443a8e6b2e..47e9dc2cff6 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Webbplats $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden har fått ett nytt utseende!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Kontoåtgärder" }, diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index e34751eea7d..ad7d2582146 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index 1b493de3d2c..b3cddf4e83a 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Website $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Autofill suggestions" }, + "itemSuggestions": { + "message": "Suggested items" + }, "autofillSuggestionsTip": { "message": "Save a login item for this site to autofill" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index 8095a9f6045..1d60fbed0e9 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -1275,7 +1275,7 @@ "message": "Bitwarden'ı desteklediğiniz için teşekkür ederiz." }, "premiumFeatures": { - "message": "Premium'a yükseltin ve şunları alın:" + "message": "Premium'a geçmenin avantajları:" }, "premiumPrice": { "message": "Bunların hepsi sadece yılda $PRICE$!", @@ -1502,13 +1502,13 @@ "description": "Overlay appearance select option for showing the field on click of the overlay icon" }, "enableAutoFillOnPageLoadSectionTitle": { - "message": "Sayfa yüklendiğinde otomatik doldur" + "message": "Sayfa yüklenince otomatik doldur" }, "enableAutoFillOnPageLoad": { - "message": "Sayfa yüklendiğinde otomatik doldur" + "message": "Sayfa yüklenince otomatik doldur" }, "enableAutoFillOnPageLoadDesc": { - "message": "Sayfa yüklendiğinde giriş formu tespit edilirse otomatik olarak formu doldur." + "message": "Sayfa yüklenince giriş formu tespit edilirse otomatik olarak formu doldur." }, "experimentalFeature": { "message": "Ele geçirilmiş veya güvenilmeyen web siteleri sayfa yüklenirken otomatik doldurmayı suistimal edebilir." @@ -1523,19 +1523,19 @@ "message": "Hesaplar için varsayılan otomatik doldurma ayarı" }, "defaultAutoFillOnPageLoadDesc": { - "message": "\"Sayfa yüklendiğinde otomatik doldur\"u her hesabın \"Düzenle\" görünümünden ayrı ayrı kapatabilirsiniz." + "message": "\"Sayfa yüklenince otomatik doldur\"u her hesabın \"Düzenle\" görünümünden ayrı ayrı kapatabilirsiniz." }, "itemAutoFillOnPageLoad": { - "message": "Sayfa yüklendiğinde otomatik doldur (Seçeneklerde ayarlanmışsa)" + "message": "Sayfa yüklenince otomatik doldur (Seçeneklerde ayarlanmışsa)" }, "autoFillOnPageLoadUseDefault": { "message": "Varsayılan ayarı kullan" }, "autoFillOnPageLoadYes": { - "message": "Sayfa yüklendiğinde otomatik doldur" + "message": "Sayfa yüklenince otomatik doldur" }, "autoFillOnPageLoadNo": { - "message": "Sayfa yüklendiğinde otomatik doldurma" + "message": "Sayfa yüklenince otomatik doldurma" }, "commandOpenPopup": { "message": "Kasayı açılır pencerede aç" @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Bu sitede otomatik doldurma engellenmiş." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Bunu ayarlardan değiştirebilirsiniz" }, "websiteItemLabel": { "message": "Web sitesi $number$ (URI)", @@ -3151,7 +3151,7 @@ } }, "autofillPageLoadPolicyActivated": { - "message": "Kuruluş ilkeleriniz, sayfa yüklendiğinde otomatik doldurmayı etkinleştirdi." + "message": "Kuruluş ilkeleriniz, sayfa yüklenince otomatik doldurmayı etkinleştirdi." }, "howToAutofill": { "message": "Otomatik doldurma nasıl yapılır?" @@ -3461,11 +3461,11 @@ "message": "Alias alan adı" }, "passwordRepromptDisabledAutofillOnPageLoad": { - "message": "Ana parolayı yeniden isteyen kayıtlar sayfa yüklendiğinde otomatik olarak doldurulamaz. Sayfa yüklendiğinde otomatik doldurma kapatıldı.", + "message": "Ana parolayı yeniden isteyen kayıtlar sayfa yüklenince otomatik olarak doldurulamaz. Sayfa yüklenince otomatik doldurma kapatıldı.", "description": "Toast message for describing that master password re-prompt cannot be autofilled on page load." }, "autofillOnPageLoadSetToDefault": { - "message": "Sayfa yüklendiğinde otomatik doldurma, varsayılan ayarı kullanacak şekilde ayarlandı.", + "message": "Sayfa yüklenince otomatik doldurma, varsayılan ayarı kullanacak şekilde ayarlandı.", "description": "Toast message for informing the user that autofill on page load has been set to the default setting." }, "turnOffMasterPasswordPromptToEditField": { @@ -3740,7 +3740,7 @@ "message": "Geçiş anahtarı" }, "accessing": { - "message": "Erişim" + "message": "Erişilen konum:" }, "loggedInExclamation": { "message": "Giriş yapıldı!" @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Önerileri otomatik doldur" }, + "itemSuggestions": { + "message": "Önerilen kayıtlar" + }, "autofillSuggestionsTip": { "message": "Otomatik doldurma için bu siteye ait bir hesap kaydededin" }, @@ -4333,7 +4336,7 @@ } }, "autoFillOnPageLoad": { - "message": "Sayfa yüklendiğinde otomatik doldur" + "message": "Sayfa yüklenince otomatik doldur" }, "cardExpiredTitle": { "message": "Kartın süresi dolmuş" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Metin Send'leri" }, - "bitwardenNewLook": { - "message": "Bitwarden'ın tasarımı güncellendi!" - }, - "bitwardenNewLookDesc": { - "message": "Otomatik doldurma ve kasanızda arama yapma artık eskisinden daha kolay. Yeni tasarıma göz atmayı unutmayın!" - }, "accountActions": { "message": "Hesap işlemleri" }, diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index d6b0b88ead2..2d35489e09a 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Автозаповнення та інші пов'язані функції не пропонуватимуться для цих вебсайтів. Вам слід оновити сторінку для застосування змін." }, - "autofillBlockedNotice": { - "message": "Автозаповнення заблоковано для цього вебсайту. Перегляньте або змініть це в налаштуваннях." + "autofillBlockedNoticeV2": { + "message": "Автозаповнення для цього вебсайту заблоковано." }, - "autofillBlockedTooltip": { - "message": "Автозаповнення заблоковано на цьому вебсайті. Перевірте налаштування." + "autofillBlockedNoticeGuidance": { + "message": "Змінити в налаштуваннях" }, "websiteItemLabel": { "message": "Вебсайт $number$ (URI)", @@ -2805,17 +2805,17 @@ "message": "Помилка" }, "decryptionError": { - "message": "Decryption error" + "message": "Помилка розшифрування" }, "couldNotDecryptVaultItemsBelow": { - "message": "Bitwarden could not decrypt the vault item(s) listed below." + "message": "Bitwarden не зміг розшифрувати вказані нижче елементи сховища." }, "contactCSToAvoidDataLossPart1": { - "message": "Contact customer success", + "message": "Зверніться до служби підтримки клієнтів,", "description": "This is part of a larger sentence. The full sentence will read 'Contact customer success to avoid additional data loss.'" }, "contactCSToAvoidDataLossPart2": { - "message": "to avoid additional data loss.", + "message": "щоб уникнути втрати даних.", "description": "This is part of a larger sentence. The full sentence will read 'Contact customer success to avoid additional data loss.'" }, "generateUsername": { @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "Пропозиції автозаповнення" }, + "itemSuggestions": { + "message": "Запропоновані записи" + }, "autofillSuggestionsTip": { "message": "Зберегти дані входу цього сайту для автозаповнення" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "Відправлення тексту" }, - "bitwardenNewLook": { - "message": "Bitwarden має новий вигляд!" - }, - "bitwardenNewLookDesc": { - "message": "Ще простіше автозаповнення та інтуїтивніший пошук у сховищі. Ознайомтеся!" - }, "accountActions": { "message": "Дії з обліковим записом" }, @@ -4671,22 +4668,22 @@ "message": "Вам не дозволено редагувати цей запис" }, "biometricsStatusHelptextUnlockNeeded": { - "message": "Biometric unlock is unavailable because PIN or password unlock is required first." + "message": "Біометричне розблокування недоступне, оскільки спочатку потрібно ввести PIN-код або пароль." }, "biometricsStatusHelptextHardwareUnavailable": { - "message": "Biometric unlock is currently unavailable." + "message": "Біометричне розблокування наразі недоступне." }, "biometricsStatusHelptextAutoSetupNeeded": { - "message": "Biometric unlock is unavailable due to misconfigured system files." + "message": "Біометричне розблокування недоступне через неправильно налаштовані системні файли." }, "biometricsStatusHelptextManualSetupNeeded": { - "message": "Biometric unlock is unavailable due to misconfigured system files." + "message": "Біометричне розблокування недоступне через неправильно налаштовані системні файли." }, "biometricsStatusHelptextDesktopDisconnected": { - "message": "Biometric unlock is unavailable because the Bitwarden desktop app is closed." + "message": "Біометричне розблокування недоступне, оскільки програму Bitwarden для комп'ютера закрито." }, "biometricsStatusHelptextNotEnabledInDesktop": { - "message": "Biometric unlock is unavailable because it is not enabled for $EMAIL$ in the Bitwarden desktop app.", + "message": "Біометричне розблокування недоступне, оскільки воно не увімкнене для $EMAIL$ у програмі Bitwarden для комп'ютера.", "placeholders": { "email": { "content": "$1", @@ -4695,7 +4692,7 @@ } }, "biometricsStatusHelptextUnavailableReasonUnknown": { - "message": "Biometric unlock is currently unavailable for an unknown reason." + "message": "Біометричне розблокування зараз недоступне з невідомої причини." }, "authenticating": { "message": "Аутентифікація" diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index 4ccdaf808f3..af33914d3e7 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." }, - "autofillBlockedNotice": { - "message": "Autofill is blocked for this website. Review or change this in settings." + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "Autofill is blocked on this website. Review in settings." + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "Trang Web $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "Đã xóa mã khoá" }, "autofillSuggestions": { - "message": "Gợi ý điền tự động" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "Lưu thông tin đăng nhập cho trang này để tự động điền" @@ -4586,12 +4589,6 @@ "textSends": { "message": "Text Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden has a new look!" - }, - "bitwardenNewLookDesc": { - "message": "It's easier and more intuitive than ever to autofill and search from the Vault tab. Take a look around!" - }, "accountActions": { "message": "Account actions" }, diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index dd6a2286c4a..14ad3927bec 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "将不会为这些网站提供自动填充和其他相关功能。您必须刷新页面才能使更改生效。" }, - "autofillBlockedNotice": { - "message": "该网站的自动填充功能已被阻止。请在设置中查看或更改。" + "autofillBlockedNoticeV2": { + "message": "该网站的自动填充已被屏蔽。" }, - "autofillBlockedTooltip": { - "message": "该网站的自动填充功能已被阻止。请在设置中查看。" + "autofillBlockedNoticeGuidance": { + "message": "在设置中更改它" }, "websiteItemLabel": { "message": "网站 $number$ (URI)", @@ -4010,6 +4010,9 @@ "autofillSuggestions": { "message": "自动填充建议" }, + "itemSuggestions": { + "message": "建议的项目" + }, "autofillSuggestionsTip": { "message": "将此站点保存为登录项目以用于自动填充" }, @@ -4586,12 +4589,6 @@ "textSends": { "message": "文本 Send" }, - "bitwardenNewLook": { - "message": "Bitwarden 拥有一个新的外观!" - }, - "bitwardenNewLookDesc": { - "message": "从密码库标签页自动填充和搜索比以往任何时候都更简单直观。来看看吧!" - }, "accountActions": { "message": "账户操作" }, diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index 467deffd815..d5903198e36 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -2339,11 +2339,11 @@ "blockedDomainsDesc": { "message": "自動填入及其它相關的功能無法在這些網站上使用。您必須重新整理頁面來使變更生效。" }, - "autofillBlockedNotice": { - "message": "自動填入已在此網站被封鎖。請在設定中檢視或更改此限制。" + "autofillBlockedNoticeV2": { + "message": "Autofill is blocked for this website." }, - "autofillBlockedTooltip": { - "message": "自動填入已在此網站被封鎖。請在設定中檢視。" + "autofillBlockedNoticeGuidance": { + "message": "Change this in settings" }, "websiteItemLabel": { "message": "網站 $number$ (URI)", @@ -4008,7 +4008,10 @@ "message": "密碼金鑰已移除" }, "autofillSuggestions": { - "message": "自動填入建議" + "message": "Autofill suggestions" + }, + "itemSuggestions": { + "message": "Suggested items" }, "autofillSuggestionsTip": { "message": "對此網站儲存登入項目為自動填入" @@ -4586,12 +4589,6 @@ "textSends": { "message": "文字 Sends" }, - "bitwardenNewLook": { - "message": "Bitwarden 有了新外觀!" - }, - "bitwardenNewLookDesc": { - "message": "更容易使用的自動填入及密碼庫搜尋體驗。試試看吧!" - }, "accountActions": { "message": "帳號動作" }, diff --git a/apps/browser/store/locales/ru/copy.resx b/apps/browser/store/locales/ru/copy.resx index 7c9480567e8..f67462c7502 100644 --- a/apps/browser/store/locales/ru/copy.resx +++ b/apps/browser/store/locales/ru/copy.resx @@ -124,48 +124,47 @@ Дома, на работе или в пути - Bitwarden всегда защитит ваши пароли, passkeys и конфиденциальную информацию. - Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! + Признан лучшим менеджером паролей по версии PCMag, WIRED, The Verge, CNET, G2 и других! -SECURE YOUR DIGITAL LIFE -Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access. +ЗАЩИТИТЕ СВОЮ ЦИФРОВУЮ ЖИЗНЬ +Защитите свою цифровую жизнь и защитите её от утечек данных, создавая уникальные, надёжные пароли для каждой учетной записи. Сохраните всё в зашифрованном сквозным шифрованием хранилище паролей, доступ к которому есть только у вас. -ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE -Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions. +ДОСТУП К СВОИМ ДАННЫМ В ЛЮБОМ МЕСТЕ, В ЛЮБОЕ ВРЕМЯ, НА ЛЮБОМ УСТРОЙСТВЕ +Легко управляйте, храните, защищайте и делитесь неограниченным количеством паролей на неограниченном количестве устройств без ограничений. -EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE -Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features. +КАЖДЫЙ ДОЛЖЕН ИМЕТЬ ИНСТРУМЕНТЫ ДЛЯ БЕЗОПАСНОСТИ В СЕТИ +Используйте Bitwarden бесплатно без рекламы или продажи данных. Bitwarden считает, что каждый должен иметь возможность оставаться в безопасности в сети. Премиум-планы предлагают доступ к расширенным функциям. -EMPOWER YOUR TEAMS WITH BITWARDEN -Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more. +РАСШИРЯЙТЕ ВОЗМОЖНОСТИ СВОИХ КОМАНД С ПОМОЩЬЮ BITWARDEN +Планы для Teams и Enterprise включают профессиональные бизнес-функции. Вот несколько примеров: интеграция SSO, собственный хостинг, интеграция каталогов и SCIM, глобальные политики, доступ через API, журналы событий и многое другое. -Use Bitwarden to secure your workforce and share sensitive information with colleagues. +Используйте Bitwarden для защиты своих сотрудников и обмена конфиденциальной информацией с коллегами. +Дополнительные причины выбрать Bitwarden: -More reasons to choose Bitwarden: +Шифрование мирового класса +Пароли защищены усовершенствованным сквозным шифрованием (AES-256, хэштег salt и PBKDF2 SHA-256), поэтому ваши данные остаются в безопасности и конфиденциальности. -World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Сторонние аудиты +Bitwarden регулярно проводит комплексные сторонние аудиты безопасности с известными фирмами по безопасности. Эти ежегодные аудиты включают оценку исходного кода и тестирование на проникновение по IP-адресам Bitwarden, серверам и веб-приложениям. -3rd-party Audits -Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. - -Advanced 2FA -Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey. +Расширенная 2FA +Защитите свой вход с помощью стороннего аутентификатора, кодов, отправленных по электронной почте, или учетных данных FIDO2 WebAuthn, таких как аппаратный ключ безопасности или ключ доступа. Bitwarden Send -Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure. +Передавайте данные другим без посредников, сохраняя сквозное шифрование и ограничивая раскрытие информации. -Built-in Generator -Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy. +Встроенный генератор паролей +Создавайте длинные, сложные и уникальные пароли и имена пользователей для каждого посещаемого вами сайта. Интегрируйтесь с поставщиками псевдонимов электронной почты для дополнительной конфиденциальности. -Global Translations -Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin. +Многоязычный перевод +Bitwarden переведён на более чем 60 языков, с помощью мирового сообщества через Crowdin. -Cross-Platform Applications -Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. +Кроссплатформенные приложения +Защищайте и делитесь конфиденциальными данными в вашем хранилище Bitwarden из любого браузера, мобильного устройства или настольной ОС и т. д. -Bitwarden secures more than just passwords -End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev! +Bitwarden защищает не только пароли +Решения со сквозным шифрованием для управления учётными данными от Bitwarden позволяют организациям защищать всё, включая секреты разработчиков и ключи доступа. Посетите Bitwarden.com, чтобы узнать больше о Bitwarden Secrets Manager и Bitwarden Passwordless.dev! From 2726b3a957b087def091fea57a2a28b1c54ba717 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Fri, 17 Jan 2025 11:22:03 +0100 Subject: [PATCH 03/17] Add no-sandbox to make electron work on ubuntu (#12908) --- apps/desktop/scripts/start.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/scripts/start.js b/apps/desktop/scripts/start.js index d2c984a6f24..0e11ebd9083 100644 --- a/apps/desktop/scripts/start.js +++ b/apps/desktop/scripts/start.js @@ -25,7 +25,7 @@ concurrently( }, { name: "Elec", - command: `npx wait-on ./build/main.js && npx electron --inspect=5858 ${args.join( + command: `npx wait-on ./build/main.js && npx electron --no-sandbox --inspect=5858 ${args.join( " ", )} ./build --watch`, prefixColor: "green", From dafeb1492a6319326df32c6b233f65c41b0771cf Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Fri, 17 Jan 2025 14:57:31 +0100 Subject: [PATCH 04/17] Add type=button to stories (#12930) --- .../platform/popup/layout/popup-layout.stories.ts | 6 +++--- .../src/directives/copy-click.directive.spec.ts | 14 ++++++++++---- .../src/dialog/dialog.service.stories.ts | 8 +++++--- .../simple-configurable-dialog.service.stories.ts | 1 + .../simple-dialog/simple-dialog.service.stories.ts | 8 +++++--- .../components/kitchen-sink-main.component.ts | 10 +++++----- .../components/kitchen-sink-table.component.ts | 12 ++++++++++-- .../kitchen-sink-toggle-list.component.ts | 2 +- libs/components/src/table/sortable.component.ts | 7 ++++++- 9 files changed, 46 insertions(+), 22 deletions(-) diff --git a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts index c1ac8823261..6a2d8162c7f 100644 --- a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts +++ b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts @@ -45,7 +45,7 @@ class ExtensionContainerComponent {} - - + + diff --git a/libs/angular/src/directives/copy-click.directive.spec.ts b/libs/angular/src/directives/copy-click.directive.spec.ts index 29466f7fbe3..09161ee261d 100644 --- a/libs/angular/src/directives/copy-click.directive.spec.ts +++ b/libs/angular/src/directives/copy-click.directive.spec.ts @@ -9,10 +9,16 @@ import { CopyClickDirective } from "./copy-click.directive"; @Component({ template: ` - - - - + + + + `, }) class TestCopyClickComponent { diff --git a/libs/components/src/dialog/dialog.service.stories.ts b/libs/components/src/dialog/dialog.service.stories.ts index 5e938412804..2b42faeccca 100644 --- a/libs/components/src/dialog/dialog.service.stories.ts +++ b/libs/components/src/dialog/dialog.service.stories.ts @@ -19,7 +19,7 @@ interface Animal { } @Component({ - template: ``, + template: ``, }) class StoryDialogComponent { constructor(public dialogService: DialogService) {} @@ -42,8 +42,10 @@ class StoryDialogComponent { Animal: {{ animal }} - - + + `, diff --git a/libs/components/src/dialog/simple-dialog/simple-configurable-dialog/simple-configurable-dialog.service.stories.ts b/libs/components/src/dialog/simple-dialog/simple-configurable-dialog/simple-configurable-dialog.service.stories.ts index 4f21b8611b3..9953fdd24ea 100644 --- a/libs/components/src/dialog/simple-dialog/simple-configurable-dialog/simple-configurable-dialog.service.stories.ts +++ b/libs/components/src/dialog/simple-dialog/simple-configurable-dialog/simple-configurable-dialog.service.stories.ts @@ -16,6 +16,7 @@ import { DialogModule } from "../../dialog.module";

{{ group.title }}

`, + template: ``, }) class StoryDialogComponent { constructor(public dialogService: DialogService) {} @@ -41,8 +41,10 @@ class StoryDialogComponent { Animal: {{ animal }} - - + + `, diff --git a/libs/components/src/stories/kitchen-sink/components/kitchen-sink-main.component.ts b/libs/components/src/stories/kitchen-sink/components/kitchen-sink-main.component.ts index 13f0a16a4d7..568c78566f6 100644 --- a/libs/components/src/stories/kitchen-sink/components/kitchen-sink-main.component.ts +++ b/libs/components/src/stories/kitchen-sink/components/kitchen-sink-main.component.ts @@ -15,8 +15,8 @@ import { KitchenSinkToggleList } from "./kitchen-sink-toggle-list.component"; Dialog body text goes here. - - + + `, @@ -42,7 +42,7 @@ class KitchenSinkDialog {

-
+

Bitwarden Kitchen Sink

Learn more
@@ -68,8 +68,8 @@ class KitchenSinkDialog {

About

- - + +

Companies using Bitwarden

diff --git a/libs/components/src/stories/kitchen-sink/components/kitchen-sink-table.component.ts b/libs/components/src/stories/kitchen-sink/components/kitchen-sink-table.component.ts index 3c6d6f11444..ba71483d7de 100644 --- a/libs/components/src/stories/kitchen-sink/components/kitchen-sink-table.component.ts +++ b/libs/components/src/stories/kitchen-sink/components/kitchen-sink-table.component.ts @@ -20,7 +20,11 @@ import { KitchenSinkSharedModule } from "../kitchen-sink-shared.module"; Password Manager Everyone - + Anchor link Another link @@ -33,7 +37,11 @@ import { KitchenSinkSharedModule } from "../kitchen-sink-shared.module"; Secrets Manager Developers - + Anchor link Another link diff --git a/libs/components/src/stories/kitchen-sink/components/kitchen-sink-toggle-list.component.ts b/libs/components/src/stories/kitchen-sink/components/kitchen-sink-toggle-list.component.ts index 2804c9e8351..6f0054912cf 100644 --- a/libs/components/src/stories/kitchen-sink/components/kitchen-sink-toggle-list.component.ts +++ b/libs/components/src/stories/kitchen-sink/components/kitchen-sink-toggle-list.component.ts @@ -7,7 +7,7 @@ import { KitchenSinkSharedModule } from "../kitchen-sink-shared.module"; selector: "bit-kitchen-sink-toggle-list", imports: [KitchenSinkSharedModule], template: ` -
+
All 3 diff --git a/libs/components/src/table/sortable.component.ts b/libs/components/src/table/sortable.component.ts index d3309c03aa9..bdfb87ac52f 100644 --- a/libs/components/src/table/sortable.component.ts +++ b/libs/components/src/table/sortable.component.ts @@ -10,7 +10,12 @@ import { TableComponent } from "./table.component"; @Component({ selector: "th[bitSortable]", template: ` - From 9eecfbc8afad3d2b8ce5a066f57c713363f30853 Mon Sep 17 00:00:00 2001 From: Daniel James Smith <2670567+djsmith85@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:56:09 +0100 Subject: [PATCH 05/17] [PM-17189] Remove LP fileless importer (#12918) * Remove LP fileless importer - Remove content scripts - Remove additions to message handlers and notifcation queue - Remove UI elements for the importer - Remove the actual importer code - Remove unsued keys from en/messages.json Remove feature flag "browser-fileless- import" Update webpack.config and manifest files to no longer include content scripts * Move feature flag idp-auto-submit-login under autofill grouping --------- Co-authored-by: Daniel James Smith --- apps/browser/src/_locales/en/messages.json | 32 -- .../abstractions/notification.background.ts | 9 +- .../background/notification.background.ts | 55 --- .../components/notification/container.ts | 2 - .../notification-queue-message-type.enum.ts | 1 - .../abstractions/notification-bar.ts | 1 - .../src/autofill/notification/bar.html | 10 - apps/browser/src/autofill/notification/bar.ts | 77 ---- .../browser/src/background/main.background.ts | 13 - apps/browser/src/manifest.json | 7 - apps/browser/src/manifest.v3.json | 6 - .../fileless-importer.background.ts | 34 -- .../fileless-importer.background.spec.ts | 339 ------------------ .../fileless-importer.background.ts | 265 -------------- .../fileless-importer-injected-scripts.ts | 25 -- .../abstractions/lp-fileless-importer.ts | 25 -- .../content/lp-fileless-importer.spec.ts | 211 ----------- .../src/tools/content/lp-fileless-importer.ts | 158 -------- ...-import-download-script-append.mv2.spec.ts | 23 -- ...press-import-download-script-append.mv2.ts | 9 - .../lp-suppress-import-download.spec.ts | 83 ----- .../content/lp-suppress-import-download.ts | 52 --- .../src/tools/enums/fileless-import.enums.ts | 12 - apps/browser/webpack.config.js | 4 - libs/common/src/enums/feature-flag.enum.ts | 6 +- 25 files changed, 3 insertions(+), 1456 deletions(-) delete mode 100644 apps/browser/src/tools/background/abstractions/fileless-importer.background.ts delete mode 100644 apps/browser/src/tools/background/fileless-importer.background.spec.ts delete mode 100644 apps/browser/src/tools/background/fileless-importer.background.ts delete mode 100644 apps/browser/src/tools/config/fileless-importer-injected-scripts.ts delete mode 100644 apps/browser/src/tools/content/abstractions/lp-fileless-importer.ts delete mode 100644 apps/browser/src/tools/content/lp-fileless-importer.spec.ts delete mode 100644 apps/browser/src/tools/content/lp-fileless-importer.ts delete mode 100644 apps/browser/src/tools/content/lp-suppress-import-download-script-append.mv2.spec.ts delete mode 100644 apps/browser/src/tools/content/lp-suppress-import-download-script-append.mv2.ts delete mode 100644 apps/browser/src/tools/content/lp-suppress-import-download.spec.ts delete mode 100644 apps/browser/src/tools/content/lp-suppress-import-download.ts delete mode 100644 apps/browser/src/tools/enums/fileless-import.enums.ts diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 51e1203673b..ecb47843df2 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -3425,38 +3425,6 @@ "message": "Toggle collapse", "description": "Toggling an expand/collapse state." }, - "filelessImport": { - "message": "Import your data to Bitwarden?", - "description": "Default notification title for triggering a fileless import." - }, - "lpFilelessImport": { - "message": "Protect your LastPass data and import to Bitwarden?", - "description": "LastPass specific notification title for triggering a fileless import." - }, - "lpCancelFilelessImport": { - "message": "Save as unencrypted file", - "description": "LastPass specific notification button text for cancelling a fileless import." - }, - "startFilelessImport": { - "message": "Import to Bitwarden", - "description": "Notification button text for starting a fileless import." - }, - "importing": { - "message": "Importing...", - "description": "Notification message for when an import is in progress." - }, - "dataSuccessfullyImported": { - "message": "Data successfully imported!", - "description": "Notification message for when an import has completed successfully." - }, - "dataImportFailed": { - "message": "Error importing. Check console for details.", - "description": "Notification message for when an import has failed." - }, - "importNetworkError": { - "message": "Network error encountered during import.", - "description": "Notification message for when an import has failed due to a network error." - }, "aliasDomain": { "message": "Alias domain" }, diff --git a/apps/browser/src/autofill/background/abstractions/notification.background.ts b/apps/browser/src/autofill/background/abstractions/notification.background.ts index ed9d8e6d84b..1b989283112 100644 --- a/apps/browser/src/autofill/background/abstractions/notification.background.ts +++ b/apps/browser/src/autofill/background/abstractions/notification.background.ts @@ -31,16 +31,10 @@ interface AddUnlockVaultQueueMessage extends NotificationQueueMessage { type: "unlock"; } -interface AddRequestFilelessImportQueueMessage extends NotificationQueueMessage { - type: "fileless-import"; - importType?: string; -} - type NotificationQueueMessageItem = | AddLoginQueueMessage | AddChangePasswordQueueMessage - | AddUnlockVaultQueueMessage - | AddRequestFilelessImportQueueMessage; + | AddUnlockVaultQueueMessage; type LockedVaultPendingNotificationsData = { commandToRetry: { @@ -122,7 +116,6 @@ export { AddChangePasswordQueueMessage, AddLoginQueueMessage, AddUnlockVaultQueueMessage, - AddRequestFilelessImportQueueMessage, NotificationQueueMessageItem, LockedVaultPendingNotificationsData, AdjustNotificationBarMessageData, diff --git a/apps/browser/src/autofill/background/notification.background.ts b/apps/browser/src/autofill/background/notification.background.ts index 5c6ff3c2c8c..0175b27bd69 100644 --- a/apps/browser/src/autofill/background/notification.background.ts +++ b/apps/browser/src/autofill/background/notification.background.ts @@ -37,7 +37,6 @@ import { AutofillService } from "../services/abstractions/autofill.service"; import { AddChangePasswordQueueMessage, AddLoginQueueMessage, - AddRequestFilelessImportQueueMessage, AddUnlockVaultQueueMessage, ChangePasswordMessageData, AddLoginMessageData, @@ -201,11 +200,6 @@ export default class NotificationBackground { case NotificationQueueMessageType.AddLogin: typeData.removeIndividualVault = await this.removeIndividualVault(); break; - case NotificationQueueMessageType.RequestFilelessImport: - typeData.importType = ( - notificationQueueMessage as AddRequestFilelessImportQueueMessage - ).importType; - break; } await BrowserApi.tabSendMessageData(tab, "openNotificationBar", { @@ -399,25 +393,6 @@ export default class NotificationBackground { } } - /** - * Sets up a notification to request a fileless import when the user - * attempts to trigger an import from a third party website. - * - * @param tab - The tab that we are sending the notification to - * @param importType - The type of import that is being requested - */ - async requestFilelessImport(tab: chrome.tabs.Tab, importType: string) { - const currentAuthStatus = await this.getAuthStatus(); - if (currentAuthStatus !== AuthenticationStatus.Unlocked || this.notificationQueue.length) { - return; - } - - const loginDomain = Utils.getDomain(tab.url); - if (loginDomain) { - await this.pushRequestFilelessImportToQueue(loginDomain, tab, importType); - } - } - private async pushChangePasswordToQueue( cipherId: string, loginDomain: string, @@ -456,36 +431,6 @@ export default class NotificationBackground { await this.sendNotificationQueueMessage(tab, message); } - /** - * Pushes a request to start a fileless import to the notification queue. - * This will display a notification bar to the user, prompting them to - * start the import. - * - * @param loginDomain - The domain of the tab that we are sending the notification to - * @param tab - The tab that we are sending the notification to - * @param importType - The type of import that is being requested - */ - private async pushRequestFilelessImportToQueue( - loginDomain: string, - tab: chrome.tabs.Tab, - importType?: string, - ) { - this.removeTabFromNotificationQueue(tab); - const launchTimestamp = new Date().getTime(); - const message: AddRequestFilelessImportQueueMessage = { - type: NotificationQueueMessageType.RequestFilelessImport, - domain: loginDomain, - tab, - launchTimestamp, - expires: new Date(launchTimestamp + 0.5 * 60000), // 30 seconds - wasVaultLocked: false, - importType, - }; - this.notificationQueue.push(message); - await this.checkNotificationQueue(tab); - this.removeTabFromNotificationQueue(tab); - } - /** * Saves a cipher based on the message sent from the notification bar. If the vault * is locked, the message will be added to the notification queue and the unlock diff --git a/apps/browser/src/autofill/content/components/notification/container.ts b/apps/browser/src/autofill/content/components/notification/container.ts index 0cce066cf3a..8bd07ab8296 100644 --- a/apps/browser/src/autofill/content/components/notification/container.ts +++ b/apps/browser/src/autofill/content/components/notification/container.ts @@ -91,8 +91,6 @@ function getHeaderMessage(i18n: { [key: string]: string }, type?: NotificationTy return i18n.updateLoginPrompt; case NotificationTypes.Unlock: return ""; - case NotificationTypes.FilelessImport: - return ""; default: return undefined; } diff --git a/apps/browser/src/autofill/enums/notification-queue-message-type.enum.ts b/apps/browser/src/autofill/enums/notification-queue-message-type.enum.ts index 1f5abac92b1..5a7b8fa990b 100644 --- a/apps/browser/src/autofill/enums/notification-queue-message-type.enum.ts +++ b/apps/browser/src/autofill/enums/notification-queue-message-type.enum.ts @@ -2,7 +2,6 @@ const NotificationQueueMessageType = { AddLogin: "add", ChangePassword: "change", UnlockVault: "unlock", - RequestFilelessImport: "fileless-import", } as const; type NotificationQueueMessageTypes = diff --git a/apps/browser/src/autofill/notification/abstractions/notification-bar.ts b/apps/browser/src/autofill/notification/abstractions/notification-bar.ts index 2e38adacb32..53948a26a2e 100644 --- a/apps/browser/src/autofill/notification/abstractions/notification-bar.ts +++ b/apps/browser/src/autofill/notification/abstractions/notification-bar.ts @@ -4,7 +4,6 @@ const NotificationTypes = { Add: "add", Change: "change", Unlock: "unlock", - FilelessImport: "fileless-import", } as const; type NotificationType = (typeof NotificationTypes)[keyof typeof NotificationTypes]; diff --git a/apps/browser/src/autofill/notification/bar.html b/apps/browser/src/autofill/notification/bar.html index 6b0e76b5169..b686e1ec2f5 100644 --- a/apps/browser/src/autofill/notification/bar.html +++ b/apps/browser/src/autofill/notification/bar.html @@ -55,14 +55,4 @@
- - diff --git a/apps/browser/src/autofill/notification/bar.ts b/apps/browser/src/autofill/notification/bar.ts index 2c0ebe8e8e7..3fc61c448fe 100644 --- a/apps/browser/src/autofill/notification/bar.ts +++ b/apps/browser/src/autofill/notification/bar.ts @@ -4,7 +4,6 @@ import { ThemeTypes } from "@bitwarden/common/platform/enums"; import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service"; import type { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; -import { FilelessImportPort, FilelessImportType } from "../../tools/enums/fileless-import.enums"; import { AdjustNotificationBarMessageData } from "../background/abstractions/notification.background"; import { buildSvgDomElement } from "../utils"; import { circleCheckIcon } from "../utils/svg-icons"; @@ -59,11 +58,6 @@ function initNotificationBar(message: NotificationBarWindowMessage) { notificationChangeDesc: chrome.i18n.getMessage("notificationChangeDesc"), notificationUnlock: chrome.i18n.getMessage("notificationUnlock"), notificationUnlockDesc: chrome.i18n.getMessage("notificationUnlockDesc"), - filelessImport: chrome.i18n.getMessage("filelessImport"), - lpFilelessImport: chrome.i18n.getMessage("lpFilelessImport"), - cancelFilelessImport: chrome.i18n.getMessage("no"), - lpCancelFilelessImport: chrome.i18n.getMessage("lpCancelFilelessImport"), - startFilelessImport: chrome.i18n.getMessage("startFilelessImport"), }; setupLogoLink(i18n); @@ -107,22 +101,6 @@ function initNotificationBar(message: NotificationBarWindowMessage) { unlockTemplate.content.getElementById("unlock-text").textContent = i18n.notificationUnlockDesc; - // i18n for "Fileless Import" (fileless-import) template - const isLpImport = initData.importType === FilelessImportType.LP; - const importTemplate = document.getElementById("template-fileless-import") as HTMLTemplateElement; - - const startImportButton = importTemplate.content.getElementById("start-fileless-import"); - startImportButton.textContent = i18n.startFilelessImport; - - const cancelImportButton = importTemplate.content.getElementById("cancel-fileless-import"); - cancelImportButton.textContent = isLpImport - ? i18n.lpCancelFilelessImport - : i18n.cancelFilelessImport; - - importTemplate.content.getElementById("fileless-import-text").textContent = isLpImport - ? i18n.lpFilelessImport - : i18n.filelessImport; - // i18n for body content const closeButton = document.getElementById("close-button"); closeButton.title = i18n.close; @@ -134,8 +112,6 @@ function initNotificationBar(message: NotificationBarWindowMessage) { handleTypeChange(); } else if (notificationType === "unlock") { handleTypeUnlock(); - } else if (notificationType === "fileless-import") { - handleTypeFilelessImport(); } closeButton.addEventListener("click", (e) => { @@ -249,59 +225,6 @@ function handleTypeUnlock() { }); } -/** - * Sets up a port to communicate with the fileless importer content script. - * This connection to the background script is used to trigger the action of - * downloading the CSV file from the LP importer or importing the data into - * the Bitwarden vault. - */ -function handleTypeFilelessImport() { - const importType = notificationBarIframeInitData.importType; - const port = chrome.runtime.connect({ name: FilelessImportPort.NotificationBar }); - setContent(document.getElementById("template-fileless-import") as HTMLTemplateElement); - - const startFilelessImportButton = document.getElementById("start-fileless-import"); - const startFilelessImport = () => { - port.postMessage({ command: "startFilelessImport", importType }); - document.getElementById("fileless-import-buttons").textContent = - chrome.i18n.getMessage("importing"); - startFilelessImportButton.removeEventListener("click", startFilelessImport); - }; - startFilelessImportButton.addEventListener("click", startFilelessImport); - - const cancelFilelessImportButton = document.getElementById("cancel-fileless-import"); - cancelFilelessImportButton.addEventListener("click", () => { - port.postMessage({ command: "cancelFilelessImport", importType }); - }); - - const handlePortMessage = (msg: any) => { - if (msg.command !== "filelessImportCompleted" && msg.command !== "filelessImportFailed") { - return; - } - - port.disconnect(); - - const filelessImportButtons = document.getElementById("fileless-import-buttons"); - const notificationBarOuterWrapper = document.getElementById("notification-bar-outer-wrapper"); - - if (msg.command === "filelessImportCompleted") { - filelessImportButtons.textContent = chrome.i18n.getMessage("dataSuccessfullyImported"); - filelessImportButtons.prepend(buildSvgDomElement(circleCheckIcon)); - filelessImportButtons.classList.add("success-message"); - notificationBarOuterWrapper.classList.add("success-event"); - adjustHeight(); - return; - } - - filelessImportButtons.textContent = chrome.i18n.getMessage("dataImportFailed"); - filelessImportButtons.classList.add("error-message"); - notificationBarOuterWrapper.classList.add("error-event"); - adjustHeight(); - logService.error(`Error Encountered During Import: ${msg.importErrorMessage}`); - }; - port.onMessage.addListener(handlePortMessage); -} - function setContent(template: HTMLTemplateElement) { const content = document.getElementById("content"); while (content.firstChild) { diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 5d09122bbd6..3a60cc52109 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -268,7 +268,6 @@ import { OffscreenStorageService } from "../platform/storage/offscreen-storage.s import { SyncServiceListener } from "../platform/sync/sync-service.listener"; import { fromChromeRuntimeMessaging } from "../platform/utils/from-chrome-runtime-messaging"; import VaultTimeoutService from "../services/vault-timeout/vault-timeout.service"; -import FilelessImporterBackground from "../tools/background/fileless-importer.background"; import { VaultFilterService } from "../vault/services/vault-filter.service"; import CommandsBackground from "./commands.background"; @@ -393,7 +392,6 @@ export default class MainBackground { private notificationBackground: NotificationBackground; private overlayBackground: OverlayBackgroundInterface; private overlayNotificationsBackground: OverlayNotificationsBackgroundInterface; - private filelessImporterBackground: FilelessImporterBackground; private runtimeBackground: RuntimeBackground; private tabsBackground: TabsBackground; private webRequestBackground: WebRequestBackground; @@ -1160,16 +1158,6 @@ export default class MainBackground { this.notificationBackground, ); - this.filelessImporterBackground = new FilelessImporterBackground( - this.configService, - this.authService, - this.policyService, - this.notificationBackground, - this.importService, - this.syncService, - this.scriptInjectorService, - ); - this.autoSubmitLoginBackground = new AutoSubmitLoginBackground( this.logService, this.autofillService, @@ -1296,7 +1284,6 @@ export default class MainBackground { await this.runtimeBackground.init(); await this.notificationBackground.init(); this.overlayNotificationsBackground.init(); - this.filelessImporterBackground.init(); this.commandsBackground.init(); this.contextMenusBackground?.init(); this.idleBackground.init(); diff --git a/apps/browser/src/manifest.json b/apps/browser/src/manifest.json index 86ea0eebbc8..016bf6dfe4b 100644 --- a/apps/browser/src/manifest.json +++ b/apps/browser/src/manifest.json @@ -29,12 +29,6 @@ "matches": ["*://*/*", "file:///*"], "exclude_matches": ["*://*/*.xml*", "file:///*.xml*"], "run_at": "document_start" - }, - { - "all_frames": false, - "js": ["content/lp-fileless-importer.js"], - "matches": ["https://lastpass.com/export.php"], - "run_at": "document_start" } ], "background": { @@ -140,7 +134,6 @@ }, "web_accessible_resources": [ "content/fido2-page-script.js", - "content/lp-suppress-import-download.js", "notification/bar.html", "images/icon38.png", "images/icon38_locked.png", diff --git a/apps/browser/src/manifest.v3.json b/apps/browser/src/manifest.v3.json index ae7c888eb9b..104036140bd 100644 --- a/apps/browser/src/manifest.v3.json +++ b/apps/browser/src/manifest.v3.json @@ -30,12 +30,6 @@ "matches": ["*://*/*", "file:///*"], "exclude_matches": ["*://*/*.xml*", "file:///*.xml*"], "run_at": "document_start" - }, - { - "all_frames": false, - "js": ["content/lp-fileless-importer.js"], - "matches": ["https://lastpass.com/export.php"], - "run_at": "document_start" } ], "background": { diff --git a/apps/browser/src/tools/background/abstractions/fileless-importer.background.ts b/apps/browser/src/tools/background/abstractions/fileless-importer.background.ts deleted file mode 100644 index 2ade5bf7672..00000000000 --- a/apps/browser/src/tools/background/abstractions/fileless-importer.background.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { FilelessImportTypeKeys } from "../../enums/fileless-import.enums"; - -type FilelessImportPortMessage = { - command?: string; - importType?: FilelessImportTypeKeys; - data?: string; -}; - -type FilelessImportPortMessageHandlerParams = { - message: FilelessImportPortMessage; - port: chrome.runtime.Port; -}; - -type ImportNotificationMessageHandlers = { - [key: string]: ({ message, port }: FilelessImportPortMessageHandlerParams) => void; - cancelFilelessImport: ({ message, port }: FilelessImportPortMessageHandlerParams) => void; -}; - -type LpImporterMessageHandlers = { - [key: string]: ({ message, port }: FilelessImportPortMessageHandlerParams) => void; - displayLpImportNotification: ({ port }: { port: chrome.runtime.Port }) => void; - startLpImport: ({ message }: { message: FilelessImportPortMessage }) => void; -}; - -interface FilelessImporterBackground { - init(): void; -} - -export { - FilelessImportPortMessage, - ImportNotificationMessageHandlers, - LpImporterMessageHandlers, - FilelessImporterBackground, -}; diff --git a/apps/browser/src/tools/background/fileless-importer.background.spec.ts b/apps/browser/src/tools/background/fileless-importer.background.spec.ts deleted file mode 100644 index 409fac9790f..00000000000 --- a/apps/browser/src/tools/background/fileless-importer.background.spec.ts +++ /dev/null @@ -1,339 +0,0 @@ -import { mock } from "jest-mock-extended"; -import { of } from "rxjs"; - -import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service"; -import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { AuthService } from "@bitwarden/common/auth/services/auth.service"; -import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; -import { Importer, ImportResult, ImportServiceAbstraction } from "@bitwarden/importer/core"; - -import NotificationBackground from "../../autofill/background/notification.background"; -import { createPortSpyMock } from "../../autofill/spec/autofill-mocks"; -import { - flushPromises, - sendPortMessage, - triggerRuntimeOnConnectEvent, -} from "../../autofill/spec/testing-utils"; -import { BrowserApi } from "../../platform/browser/browser-api"; -import { BrowserScriptInjectorService } from "../../platform/services/browser-script-injector.service"; -import { FilelessImportPort, FilelessImportType } from "../enums/fileless-import.enums"; - -import FilelessImporterBackground from "./fileless-importer.background"; - -describe("FilelessImporterBackground ", () => { - let filelessImporterBackground: FilelessImporterBackground; - const configService = mock(); - const domainSettingsService = mock(); - const authService = mock(); - const policyService = mock(); - const notificationBackground = mock(); - const importService = mock(); - const syncService = mock(); - const platformUtilsService = mock(); - const logService = mock(); - let scriptInjectorService: BrowserScriptInjectorService; - let tabMock: chrome.tabs.Tab; - - beforeEach(() => { - domainSettingsService.blockedInteractionsUris$ = of({}); - policyService.policyAppliesToActiveUser$.mockImplementation(() => of(true)); - scriptInjectorService = new BrowserScriptInjectorService( - domainSettingsService, - platformUtilsService, - logService, - ); - filelessImporterBackground = new FilelessImporterBackground( - configService, - authService, - policyService, - notificationBackground, - importService, - syncService, - scriptInjectorService, - ); - filelessImporterBackground.init(); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - describe("init", () => { - it("sets up the port message listeners on initialization of the class", () => { - expect(chrome.runtime.onConnect.addListener).toHaveBeenCalledWith(expect.any(Function)); - }); - }); - - describe("handle ports onConnect", () => { - let lpImporterPort: chrome.runtime.Port; - let manifestVersionSpy: jest.SpyInstance; - let executeScriptInTabSpy: jest.SpyInstance; - - beforeEach(() => { - lpImporterPort = createPortSpyMock(FilelessImportPort.LpImporter); - tabMock = lpImporterPort.sender.tab; - jest.spyOn(BrowserApi, "getTab").mockImplementation(async () => tabMock); - manifestVersionSpy = jest.spyOn(BrowserApi, "manifestVersion", "get"); - executeScriptInTabSpy = jest.spyOn(BrowserApi, "executeScriptInTab").mockResolvedValue(null); - jest.spyOn(authService, "getAuthStatus").mockResolvedValue(AuthenticationStatus.Unlocked); - jest.spyOn(configService, "getFeatureFlag").mockResolvedValue(true); - jest.spyOn(filelessImporterBackground as any, "removeIndividualVault"); - }); - - it("ignores the port connection if the port name is not present in the set of filelessImportNames", async () => { - const port = createPortSpyMock("some-other-port"); - - triggerRuntimeOnConnectEvent(port); - await flushPromises(); - - expect(port.postMessage).not.toHaveBeenCalled(); - }); - - it("posts a message to the port indicating that the fileless import feature is disabled if the user's auth status is not unlocked", async () => { - jest.spyOn(authService, "getAuthStatus").mockResolvedValue(AuthenticationStatus.Locked); - - triggerRuntimeOnConnectEvent(lpImporterPort); - await flushPromises(); - - expect(lpImporterPort.postMessage).toHaveBeenCalledWith({ - command: "verifyFeatureFlag", - filelessImportEnabled: false, - }); - }); - - it("posts a message to the port indicating that the fileless import feature is disabled if the user's policy removes individual vaults", async () => { - triggerRuntimeOnConnectEvent(lpImporterPort); - await flushPromises(); - - expect(lpImporterPort.postMessage).toHaveBeenCalledWith({ - command: "verifyFeatureFlag", - filelessImportEnabled: false, - }); - }); - - it("posts a message to the port indicating that the fileless import feature is disabled if the feature flag is turned off", async () => { - jest.spyOn(configService, "getFeatureFlag").mockResolvedValue(false); - - triggerRuntimeOnConnectEvent(lpImporterPort); - await flushPromises(); - - expect(lpImporterPort.postMessage).toHaveBeenCalledWith({ - command: "verifyFeatureFlag", - filelessImportEnabled: false, - }); - }); - - it("posts a message to the port indicating that the fileless import feature is enabled", async () => { - policyService.policyAppliesToActiveUser$.mockImplementationOnce(() => of(false)); - - triggerRuntimeOnConnectEvent(lpImporterPort); - await flushPromises(); - - expect(lpImporterPort.postMessage).toHaveBeenCalledWith({ - command: "verifyFeatureFlag", - filelessImportEnabled: true, - }); - }); - - it("triggers an injection of the `lp-suppress-import-download.js` script in manifest v3", async () => { - policyService.policyAppliesToActiveUser$.mockImplementationOnce(() => of(false)); - manifestVersionSpy.mockReturnValue(3); - - triggerRuntimeOnConnectEvent(lpImporterPort); - await flushPromises(); - - expect(executeScriptInTabSpy).toHaveBeenCalledWith( - lpImporterPort.sender.tab.id, - { file: "content/lp-suppress-import-download.js", runAt: "document_start", frameId: 0 }, - { world: "MAIN" }, - ); - }); - - it("triggers an injection of the `lp-suppress-import-download-script-append-mv2.js` script in manifest v2", async () => { - policyService.policyAppliesToActiveUser$.mockImplementationOnce(() => of(false)); - manifestVersionSpy.mockReturnValue(2); - - triggerRuntimeOnConnectEvent(lpImporterPort); - await flushPromises(); - - expect(executeScriptInTabSpy).toHaveBeenCalledWith(lpImporterPort.sender.tab.id, { - file: "content/lp-suppress-import-download-script-append-mv2.js", - runAt: "document_start", - frameId: 0, - }); - }); - }); - - describe("port messages", () => { - let notificationPort: chrome.runtime.Port; - let lpImporterPort: chrome.runtime.Port; - - beforeEach(async () => { - policyService.policyAppliesToActiveUser$.mockImplementation(() => of(false)); - jest.spyOn(authService, "getAuthStatus").mockResolvedValue(AuthenticationStatus.Unlocked); - jest.spyOn(configService, "getFeatureFlag").mockResolvedValue(true); - - triggerRuntimeOnConnectEvent(createPortSpyMock(FilelessImportPort.NotificationBar)); - triggerRuntimeOnConnectEvent(createPortSpyMock(FilelessImportPort.LpImporter)); - await flushPromises(); - notificationPort = filelessImporterBackground["importNotificationsPort"]; - lpImporterPort = filelessImporterBackground["lpImporterPort"]; - }); - - it("skips handling a message if a message handler is not associated with the port message command", () => { - sendPortMessage(notificationPort, { command: "commandNotFound" }); - - expect(chrome.tabs.sendMessage).not.toHaveBeenCalled(); - }); - - describe("import notification port messages", () => { - describe("startFilelessImport", () => { - it("sends a message to start the LastPass fileless import within the content script", () => { - sendPortMessage(notificationPort, { - command: "startFilelessImport", - importType: FilelessImportType.LP, - }); - - expect(lpImporterPort.postMessage).toHaveBeenCalledWith({ - command: "startLpFilelessImport", - }); - }); - }); - - describe("cancelFilelessImport", () => { - it("sends a message to close the notification bar", async () => { - sendPortMessage(notificationPort, { command: "cancelFilelessImport" }); - - expect(chrome.tabs.sendMessage).toHaveBeenCalledWith( - notificationPort.sender.tab.id, - { - command: "closeNotificationBar", - }, - null, - expect.anything(), - ); - expect(lpImporterPort.postMessage).not.toHaveBeenCalledWith({ - command: "triggerCsvDownload", - }); - }); - - it("sends a message to trigger a download of the LP importer CSV", () => { - sendPortMessage(notificationPort, { - command: "cancelFilelessImport", - importType: FilelessImportType.LP, - }); - - expect(lpImporterPort.postMessage).toHaveBeenCalledWith({ - command: "triggerCsvDownload", - }); - expect(lpImporterPort.disconnect).toHaveBeenCalled(); - }); - }); - }); - - describe("lp importer port messages", () => { - describe("displayLpImportNotification", () => { - it("creates a request fileless import notification", async () => { - jest.spyOn(filelessImporterBackground["notificationBackground"], "requestFilelessImport"); - - sendPortMessage(lpImporterPort, { - command: "displayLpImportNotification", - }); - await flushPromises(); - - expect( - filelessImporterBackground["notificationBackground"].requestFilelessImport, - ).toHaveBeenCalledWith(lpImporterPort.sender.tab, FilelessImportType.LP); - }); - }); - - describe("startLpImport", () => { - it("ignores the message if the message does not contain data", () => { - sendPortMessage(lpImporterPort, { - command: "startLpImport", - }); - - expect(filelessImporterBackground["importService"].import).not.toHaveBeenCalled(); - }); - - it("triggers the import of the LastPass vault", async () => { - const data = "url,username,password"; - const importer = mock(); - jest - .spyOn(filelessImporterBackground["importService"], "getImporter") - .mockReturnValue(importer); - jest.spyOn(filelessImporterBackground["importService"], "import").mockResolvedValue( - mock({ - success: true, - }), - ); - jest.spyOn(filelessImporterBackground["syncService"], "fullSync"); - - sendPortMessage(lpImporterPort, { - command: "startLpImport", - data, - }); - await flushPromises(); - - expect(filelessImporterBackground["importService"].import).toHaveBeenCalledWith( - importer, - data, - null, - null, - false, - ); - expect( - filelessImporterBackground["importNotificationsPort"].postMessage, - ).toHaveBeenCalledWith({ command: "filelessImportCompleted" }); - expect(filelessImporterBackground["syncService"].fullSync).toHaveBeenCalledWith(true); - }); - - it("posts a failed message if the import fails", async () => { - const data = "url,username,password"; - const importer = mock(); - jest - .spyOn(filelessImporterBackground["importService"], "getImporter") - .mockReturnValue(importer); - jest - .spyOn(filelessImporterBackground["importService"], "import") - .mockImplementation(() => { - throw new Error("error"); - }); - jest.spyOn(filelessImporterBackground["syncService"], "fullSync"); - - sendPortMessage(lpImporterPort, { - command: "startLpImport", - data, - }); - await flushPromises(); - - expect( - filelessImporterBackground["importNotificationsPort"].postMessage, - ).toHaveBeenCalledWith({ command: "filelessImportFailed" }); - }); - }); - }); - }); - - describe("handleImporterPortDisconnect", () => { - it("resets the port properties to null", () => { - const lpImporterPort = createPortSpyMock(FilelessImportPort.LpImporter); - const notificationPort = createPortSpyMock(FilelessImportPort.NotificationBar); - filelessImporterBackground["lpImporterPort"] = lpImporterPort; - filelessImporterBackground["importNotificationsPort"] = notificationPort; - - filelessImporterBackground["handleImporterPortDisconnect"](lpImporterPort); - - expect(filelessImporterBackground["lpImporterPort"]).toBeNull(); - expect(filelessImporterBackground["importNotificationsPort"]).not.toBeNull(); - - filelessImporterBackground["handleImporterPortDisconnect"](notificationPort); - - expect(filelessImporterBackground["importNotificationsPort"]).toBeNull(); - }); - }); -}); diff --git a/apps/browser/src/tools/background/fileless-importer.background.ts b/apps/browser/src/tools/background/fileless-importer.background.ts deleted file mode 100644 index 21d597ec8ae..00000000000 --- a/apps/browser/src/tools/background/fileless-importer.background.ts +++ /dev/null @@ -1,265 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { firstValueFrom } from "rxjs"; - -import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { PolicyType } from "@bitwarden/common/admin-console/enums"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; -import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; -import { ImportServiceAbstraction } from "@bitwarden/importer/core"; - -import NotificationBackground from "../../autofill/background/notification.background"; -import { BrowserApi } from "../../platform/browser/browser-api"; -import { ScriptInjectorService } from "../../platform/services/abstractions/script-injector.service"; -import { FilelessImporterInjectedScriptsConfig } from "../config/fileless-importer-injected-scripts"; -import { - FilelessImportPort, - FilelessImportType, - FilelessImportTypeKeys, -} from "../enums/fileless-import.enums"; - -import { - ImportNotificationMessageHandlers, - LpImporterMessageHandlers, - FilelessImporterBackground as FilelessImporterBackgroundInterface, - FilelessImportPortMessage, -} from "./abstractions/fileless-importer.background"; - -class FilelessImporterBackground implements FilelessImporterBackgroundInterface { - private static readonly filelessImporterPortNames: Set = new Set([ - FilelessImportPort.LpImporter, - FilelessImportPort.NotificationBar, - ]); - private importNotificationsPort: chrome.runtime.Port; - private lpImporterPort: chrome.runtime.Port; - private readonly importNotificationsPortMessageHandlers: ImportNotificationMessageHandlers = { - startFilelessImport: ({ message }) => this.startFilelessImport(message.importType), - cancelFilelessImport: ({ message, port }) => - this.cancelFilelessImport(message.importType, port.sender), - }; - private readonly lpImporterPortMessageHandlers: LpImporterMessageHandlers = { - displayLpImportNotification: ({ port }) => - this.displayFilelessImportNotification(port.sender.tab, FilelessImportType.LP), - startLpImport: ({ message }) => this.triggerLpImport(message.data), - }; - - /** - * Creates a new instance of the fileless importer background logic. - * - * @param configService - Identifies if the feature flag is enabled. - * @param authService - Verifies if the auth status of the user. - * @param policyService - Identifies if the user account has a policy that disables personal ownership. - * @param notificationBackground - Used to inject the notification bar into the tab. - * @param importService - Used to import the export data into the vault. - * @param syncService - Used to trigger a full sync after the import is completed. - * @param scriptInjectorService - Used to inject content scripts that initialize the import process - */ - constructor( - private configService: ConfigService, - private authService: AuthService, - private policyService: PolicyService, - private notificationBackground: NotificationBackground, - private importService: ImportServiceAbstraction, - private syncService: SyncService, - private scriptInjectorService: ScriptInjectorService, - ) {} - - /** - * Initializes the fileless importer background logic. - */ - init() { - this.setupPortMessageListeners(); - } - - /** - * Starts an import of the export data pulled from the tab. - * - * @param importType - The type of import to start. Identifies the used content script. - */ - private startFilelessImport(importType: FilelessImportTypeKeys) { - if (importType === FilelessImportType.LP) { - this.lpImporterPort?.postMessage({ command: "startLpFilelessImport" }); - } - } - - /** - * Cancels an import of the export data pulled from the tab. This closes any - * existing notifications that are present in the tab, and triggers importer - * specific behavior based on the import type. - * - * @param importType - The type of import to cancel. Identifies the used content script. - * @param sender - The sender of the message. - */ - private async cancelFilelessImport( - importType: FilelessImportTypeKeys, - sender: chrome.runtime.MessageSender, - ) { - if (importType === FilelessImportType.LP) { - this.triggerLpImporterCsvDownload(); - } - - await BrowserApi.tabSendMessage(sender.tab, { command: "closeNotificationBar" }); - } - - /** - * Injects the notification bar into the passed tab. - * - * @param tab - * @param importType - */ - private async displayFilelessImportNotification(tab: chrome.tabs.Tab, importType: string) { - await this.notificationBackground.requestFilelessImport(tab, importType); - } - - /** - * Triggers the download of the CSV file from the LP importer. This is triggered - * when the user opts to not save the export to Bitwarden within the notification bar. - */ - private triggerLpImporterCsvDownload() { - this.lpImporterPort?.postMessage({ command: "triggerCsvDownload" }); - this.lpImporterPort?.disconnect(); - } - - /** - * Completes the import process for the LP importer. This is triggered when the - * user opts to save the export to Bitwarden within the notification bar. - * - * @param data - The export data to import. - * @param sender - The sender of the message. - */ - private async triggerLpImport(data: string) { - if (!data) { - return; - } - - const promptForPassword_callback = async () => ""; - const importer = this.importService.getImporter( - "lastpasscsv", - promptForPassword_callback, - null, - ); - - try { - const result = await this.importService.import(importer, data, null, null, false); - if (result.success) { - this.importNotificationsPort?.postMessage({ command: "filelessImportCompleted" }); - await this.syncService.fullSync(true); - } - } catch (error) { - this.importNotificationsPort?.postMessage({ - command: "filelessImportFailed", - importErrorMessage: Object.values(error).length - ? error - : chrome.i18n.getMessage("importNetworkError"), - }); - } - } - - /** - * Identifies if the user account has a policy that disables personal ownership. - */ - private async removeIndividualVault(): Promise { - return await firstValueFrom( - this.policyService.policyAppliesToActiveUser$(PolicyType.PersonalOwnership), - ); - } - - /** - * Sets up onConnect listeners for the extension. - */ - private setupPortMessageListeners() { - chrome.runtime.onConnect.addListener(this.handlePortOnConnect); - } - - /** - * Handles connections from content scripts that affect the fileless importer behavior. - * Is used to facilitate the passing of data and user actions to enact the import - * of web content to the Bitwarden vault. Along with this, a check is made to ensure - * that the feature flag is enabled and the user is authenticated. - */ - private handlePortOnConnect = async (port: chrome.runtime.Port) => { - if (!FilelessImporterBackground.filelessImporterPortNames.has(port.name)) { - return; - } - - const filelessImportFeatureFlagEnabled = await this.configService.getFeatureFlag( - FeatureFlag.BrowserFilelessImport, - ); - const userAuthStatus = await this.authService.getAuthStatus(); - const removeIndividualVault = await this.removeIndividualVault(); - const filelessImportEnabled = - filelessImportFeatureFlagEnabled && - userAuthStatus === AuthenticationStatus.Unlocked && - !removeIndividualVault; - port.postMessage({ command: "verifyFeatureFlag", filelessImportEnabled }); - - if (!filelessImportEnabled) { - return; - } - - port.onMessage.addListener(this.handleImporterPortMessage); - port.onDisconnect.addListener(this.handleImporterPortDisconnect); - - switch (port.name) { - case FilelessImportPort.LpImporter: - this.lpImporterPort = port; - await this.scriptInjectorService.inject({ - tabId: port.sender.tab.id, - injectDetails: { runAt: "document_start" }, - mv2Details: FilelessImporterInjectedScriptsConfig.LpSuppressImportDownload.mv2, - mv3Details: FilelessImporterInjectedScriptsConfig.LpSuppressImportDownload.mv3, - }); - break; - case FilelessImportPort.NotificationBar: - this.importNotificationsPort = port; - break; - } - }; - - /** - * Handles messages that are sent from fileless importer content scripts. - * @param message - The message that was sent. - * @param port - The port that the message was sent from. - */ - private handleImporterPortMessage = ( - message: FilelessImportPortMessage, - port: chrome.runtime.Port, - ) => { - let handler: CallableFunction | undefined; - - switch (port.name) { - case FilelessImportPort.LpImporter: - handler = this.lpImporterPortMessageHandlers[message.command]; - break; - case FilelessImportPort.NotificationBar: - handler = this.importNotificationsPortMessageHandlers[message.command]; - break; - } - - if (!handler) { - return; - } - - handler({ message, port }); - }; - - /** - * Handles disconnections from fileless importer content scripts. - * @param port - The port that was disconnected. - */ - private handleImporterPortDisconnect = (port: chrome.runtime.Port) => { - switch (port.name) { - case FilelessImportPort.LpImporter: - this.lpImporterPort = null; - break; - case FilelessImportPort.NotificationBar: - this.importNotificationsPort = null; - break; - } - }; -} - -export default FilelessImporterBackground; diff --git a/apps/browser/src/tools/config/fileless-importer-injected-scripts.ts b/apps/browser/src/tools/config/fileless-importer-injected-scripts.ts deleted file mode 100644 index 898ee1205ab..00000000000 --- a/apps/browser/src/tools/config/fileless-importer-injected-scripts.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { - Mv2ScriptInjectionDetails, - Mv3ScriptInjectionDetails, -} from "../../platform/services/abstractions/script-injector.service"; - -type FilelessImporterInjectedScriptsConfigurations = { - LpSuppressImportDownload: { - mv2: Mv2ScriptInjectionDetails; - mv3: Mv3ScriptInjectionDetails; - }; -}; - -const FilelessImporterInjectedScriptsConfig: FilelessImporterInjectedScriptsConfigurations = { - LpSuppressImportDownload: { - mv2: { - file: "content/lp-suppress-import-download-script-append-mv2.js", - }, - mv3: { - file: "content/lp-suppress-import-download.js", - world: "MAIN", - }, - }, -} as const; - -export { FilelessImporterInjectedScriptsConfig }; diff --git a/apps/browser/src/tools/content/abstractions/lp-fileless-importer.ts b/apps/browser/src/tools/content/abstractions/lp-fileless-importer.ts deleted file mode 100644 index 018ea2c8d94..00000000000 --- a/apps/browser/src/tools/content/abstractions/lp-fileless-importer.ts +++ /dev/null @@ -1,25 +0,0 @@ -type LpFilelessImporterMessage = { - command?: string; - data?: string; - filelessImportEnabled?: boolean; -}; - -type LpFilelessImporterMessageHandlerParams = { - message: LpFilelessImporterMessage; - port: chrome.runtime.Port; -}; - -type LpFilelessImporterMessageHandlers = { - [key: string]: ({ message, port }: LpFilelessImporterMessageHandlerParams) => void; - verifyFeatureFlag: ({ message }: { message: LpFilelessImporterMessage }) => void; - triggerCsvDownload: () => void; - startLpFilelessImport: () => void; -}; - -interface LpFilelessImporter { - init(): void; - handleFeatureFlagVerification(message: LpFilelessImporterMessage): void; - triggerCsvDownload(): void; -} - -export { LpFilelessImporterMessage, LpFilelessImporterMessageHandlers, LpFilelessImporter }; diff --git a/apps/browser/src/tools/content/lp-fileless-importer.spec.ts b/apps/browser/src/tools/content/lp-fileless-importer.spec.ts deleted file mode 100644 index 21fa44b8d3f..00000000000 --- a/apps/browser/src/tools/content/lp-fileless-importer.spec.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { mock } from "jest-mock-extended"; - -import { createPortSpyMock } from "../../autofill/spec/autofill-mocks"; -import { sendPortMessage } from "../../autofill/spec/testing-utils"; -import { FilelessImportPort } from "../enums/fileless-import.enums"; - -import { LpFilelessImporter } from "./abstractions/lp-fileless-importer"; - -describe("LpFilelessImporter", () => { - let lpFilelessImporter: LpFilelessImporter & { [key: string]: any }; - const portSpy: chrome.runtime.Port = createPortSpyMock(FilelessImportPort.LpImporter); - chrome.runtime.connect = jest.fn(() => portSpy); - - beforeEach(() => { - // FIXME: Remove when updating file. Eslint update - // eslint-disable-next-line @typescript-eslint/no-require-imports - require("./lp-fileless-importer"); - lpFilelessImporter = (globalThis as any).lpFilelessImporter; - }); - - afterEach(() => { - (globalThis as any).lpFilelessImporter = undefined; - jest.clearAllMocks(); - jest.resetModules(); - Object.defineProperty(document, "readyState", { - value: "complete", - writable: true, - }); - }); - - describe("init", () => { - it("sets up the port connection with the background script", () => { - lpFilelessImporter.init(); - - expect(chrome.runtime.connect).toHaveBeenCalledWith({ - name: FilelessImportPort.LpImporter, - }); - }); - }); - - describe("handleFeatureFlagVerification", () => { - it("disconnects the message port when the fileless import feature is disabled", () => { - lpFilelessImporter.handleFeatureFlagVerification({ filelessImportEnabled: false }); - - expect(portSpy.disconnect).toHaveBeenCalled(); - }); - - it("sets up an event listener for DOMContentLoaded that triggers the importer when the document ready state is `loading`", () => { - Object.defineProperty(document, "readyState", { - value: "loading", - writable: true, - }); - const message = { - command: "verifyFeatureFlag", - filelessImportEnabled: true, - }; - jest.spyOn(document, "addEventListener"); - - lpFilelessImporter.handleFeatureFlagVerification(message); - - expect(document.addEventListener).toHaveBeenCalledWith( - "DOMContentLoaded", - (lpFilelessImporter as any).loadImporter, - ); - }); - - it("sets up a mutation observer to watch the document body for injection of the export content", () => { - const message = { - command: "verifyFeatureFlag", - filelessImportEnabled: true, - }; - jest.spyOn(document, "addEventListener"); - jest.spyOn(window, "MutationObserver").mockImplementationOnce(() => mock()); - - lpFilelessImporter.handleFeatureFlagVerification(message); - - expect(window.MutationObserver).toHaveBeenCalledWith( - (lpFilelessImporter as any).handleMutation, - ); - expect((lpFilelessImporter as any).mutationObserver.observe).toHaveBeenCalledWith( - document.body, - { childList: true, subtree: true }, - ); - }); - }); - - describe("triggerCsvDownload", () => { - it("posts a window message that triggers the download of the LastPass export", () => { - jest.spyOn(globalThis, "postMessage"); - - lpFilelessImporter.triggerCsvDownload(); - - expect(globalThis.postMessage).toHaveBeenCalledWith( - { command: "triggerCsvDownload" }, - "https://lastpass.com", - ); - }); - }); - - describe("handleMutation", () => { - beforeEach(() => { - lpFilelessImporter["mutationObserver"] = mock({ disconnect: jest.fn() }); - jest.spyOn(portSpy, "postMessage"); - }); - - it("ignores mutations that contain empty records", () => { - lpFilelessImporter["handleMutation"]([]); - - expect(portSpy.postMessage).not.toHaveBeenCalled(); - }); - - it("ignores mutations that have no added nodes in the mutation", () => { - lpFilelessImporter["handleMutation"]([{ addedNodes: [] }]); - - expect(portSpy.postMessage).not.toHaveBeenCalled(); - }); - - it("ignores mutations that have no added nodes with a tagname of `pre`", () => { - lpFilelessImporter["handleMutation"]([{ addedNodes: [{ nodeName: "div" }] }]); - - expect(portSpy.postMessage).not.toHaveBeenCalled(); - }); - - it("ignores mutations where the found `pre` element does not contain any textContent", () => { - lpFilelessImporter["handleMutation"]([{ addedNodes: [{ nodeName: "pre" }] }]); - - expect(portSpy.postMessage).not.toHaveBeenCalled(); - }); - - it("ignores mutations where the found `pre` element does not contain the expected header content", () => { - lpFilelessImporter["handleMutation"]([ - { addedNodes: [{ nodeName: "pre", textContent: "some other content" }] }, - ]); - - expect(portSpy.postMessage).not.toHaveBeenCalled(); - }); - - it("will store the export data, display the import notification, and disconnect the mutation observer when the export data is appended", () => { - const observerDisconnectSpy = jest.spyOn( - lpFilelessImporter["mutationObserver"], - "disconnect", - ); - - lpFilelessImporter["handleMutation"]([ - { addedNodes: [{ nodeName: "pre", textContent: "url,username,password" }] }, - ]); - - expect(lpFilelessImporter["exportData"]).toEqual("url,username,password"); - expect(portSpy.postMessage).toHaveBeenCalledWith({ command: "displayLpImportNotification" }); - expect(observerDisconnectSpy).toHaveBeenCalled(); - }); - }); - - describe("handlePortMessage", () => { - it("ignores messages that are not registered with the portMessageHandlers", () => { - const message = { command: "unknownCommand" }; - jest.spyOn(lpFilelessImporter, "handleFeatureFlagVerification"); - jest.spyOn(lpFilelessImporter, "triggerCsvDownload"); - - sendPortMessage(portSpy, message); - - expect(lpFilelessImporter.handleFeatureFlagVerification).not.toHaveBeenCalled(); - expect(lpFilelessImporter.triggerCsvDownload).not.toHaveBeenCalled(); - }); - - it("handles the port message that verifies the fileless import feature flag", () => { - const message = { command: "verifyFeatureFlag", filelessImportEnabled: true }; - jest.spyOn(lpFilelessImporter, "handleFeatureFlagVerification").mockImplementation(); - - sendPortMessage(portSpy, message); - - expect(lpFilelessImporter.handleFeatureFlagVerification).toHaveBeenCalledWith(message); - }); - - it("handles the port message that triggers the LastPass csv download", () => { - const message = { command: "triggerCsvDownload" }; - jest.spyOn(lpFilelessImporter, "triggerCsvDownload"); - - sendPortMessage(portSpy, message); - - expect(lpFilelessImporter.triggerCsvDownload).toHaveBeenCalled(); - }); - - describe("handles the port message that triggers the LastPass fileless import", () => { - beforeEach(() => { - jest.spyOn(lpFilelessImporter as any, "postPortMessage"); - }); - - it("skips the import of the export data is not populated", () => { - const message = { command: "startLpFilelessImport" }; - - sendPortMessage(portSpy, message); - - expect(lpFilelessImporter.postPortMessage).not.toHaveBeenCalled(); - }); - - it("starts the last pass fileless import", () => { - const message = { command: "startLpFilelessImport" }; - const exportData = "url,username,password"; - lpFilelessImporter["exportData"] = exportData; - - sendPortMessage(portSpy, message); - - expect(lpFilelessImporter.postPortMessage).toHaveBeenCalledWith({ - command: "startLpImport", - data: exportData, - }); - }); - }); - }); -}); diff --git a/apps/browser/src/tools/content/lp-fileless-importer.ts b/apps/browser/src/tools/content/lp-fileless-importer.ts deleted file mode 100644 index 497a499b337..00000000000 --- a/apps/browser/src/tools/content/lp-fileless-importer.ts +++ /dev/null @@ -1,158 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { FilelessImportPort } from "../enums/fileless-import.enums"; - -import { - LpFilelessImporter as LpFilelessImporterInterface, - LpFilelessImporterMessage, - LpFilelessImporterMessageHandlers, -} from "./abstractions/lp-fileless-importer"; - -class LpFilelessImporter implements LpFilelessImporterInterface { - private exportData: string; - private messagePort: chrome.runtime.Port; - private mutationObserver: MutationObserver; - private readonly portMessageHandlers: LpFilelessImporterMessageHandlers = { - verifyFeatureFlag: ({ message }) => this.handleFeatureFlagVerification(message), - triggerCsvDownload: () => this.triggerCsvDownload(), - startLpFilelessImport: () => this.startLpImport(), - }; - - /** - * Initializes the LP fileless importer. - */ - init() { - this.setupMessagePort(); - } - - /** - * Enacts behavior based on the feature flag verification message. If the feature flag is - * not enabled, the message port is disconnected. If the feature flag is enabled, the - * download of the CSV file is suppressed. - * - * @param message - The port message, contains the feature flag indicator. - */ - handleFeatureFlagVerification(message: LpFilelessImporterMessage) { - if (!message.filelessImportEnabled) { - this.messagePort?.disconnect(); - return; - } - - if (document.readyState === "loading") { - document.addEventListener("DOMContentLoaded", this.loadImporter); - return; - } - - this.loadImporter(); - } - - /** - * Posts a message to the LP importer to trigger the download of the CSV file. - */ - triggerCsvDownload() { - this.postWindowMessage({ command: "triggerCsvDownload" }); - } - - /** - * Initializes the importing mechanism used to import the CSV file into Bitwarden. - * This is done by observing the DOM for the addition of the LP importer element. - */ - private loadImporter = () => { - this.mutationObserver = new MutationObserver(this.handleMutation); - this.mutationObserver.observe(document.body, { - childList: true, - subtree: true, - }); - }; - - /** - * Handles mutations that are observed by the mutation observer. When the exported data - * element is added to the DOM, the export data is extracted and the import prompt is - * displayed. - * - * @param mutations - The mutations that were observed. - */ - private handleMutation = (mutations: MutationRecord[]) => { - let textContent: string; - for (let index = 0; index < mutations?.length; index++) { - const mutation: MutationRecord = mutations[index]; - - textContent = Array.from(mutation.addedNodes) - .filter((node) => node.nodeName.toLowerCase() === "pre") - .map((node) => (node as HTMLPreElement).textContent?.trim()) - .find((text) => text?.indexOf("url,username,password") >= 0); - - if (textContent) { - break; - } - } - - if (textContent) { - this.exportData = textContent; - this.postPortMessage({ command: "displayLpImportNotification" }); - this.mutationObserver.disconnect(); - } - }; - - /** - * If the export data is present, sends a message to the background with - * the export data to start the import process. - */ - private startLpImport() { - if (!this.exportData) { - return; - } - - this.postPortMessage({ command: "startLpImport", data: this.exportData }); - this.messagePort?.disconnect(); - } - - /** - * Posts a message to the background script. - * - * @param message - The message to post. - */ - private postPortMessage(message: LpFilelessImporterMessage) { - this.messagePort?.postMessage(message); - } - - /** - * Posts a message to the global context of the page. - * - * @param message - The message to post. - */ - private postWindowMessage(message: LpFilelessImporterMessage) { - globalThis.postMessage(message, "https://lastpass.com"); - } - - /** - * Sets up the message port that is used to facilitate communication between the - * background script and the content script. - */ - private setupMessagePort() { - this.messagePort = chrome.runtime.connect({ name: FilelessImportPort.LpImporter }); - this.messagePort.onMessage.addListener(this.handlePortMessage); - } - - /** - * Handles messages that are sent from the background script. - * - * @param message - The message that was sent. - * @param port - The port that the message was sent from. - */ - private handlePortMessage = (message: LpFilelessImporterMessage, port: chrome.runtime.Port) => { - const handler = this.portMessageHandlers[message.command]; - if (!handler) { - return; - } - - handler({ message, port }); - }; -} - -(function () { - if (!(globalThis as any).lpFilelessImporter) { - (globalThis as any).lpFilelessImporter = new LpFilelessImporter(); - (globalThis as any).lpFilelessImporter.init(); - } -})(); diff --git a/apps/browser/src/tools/content/lp-suppress-import-download-script-append.mv2.spec.ts b/apps/browser/src/tools/content/lp-suppress-import-download-script-append.mv2.spec.ts deleted file mode 100644 index 8479235cc17..00000000000 --- a/apps/browser/src/tools/content/lp-suppress-import-download-script-append.mv2.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -describe("LP Suppress Import Download for Manifest v2", () => { - it("appends the `lp-suppress-import-download.js` script to the document element", () => { - let createdScriptElement: HTMLScriptElement; - jest.spyOn(window.document, "createElement"); - jest.spyOn(window.document.documentElement, "appendChild").mockImplementation((node) => { - createdScriptElement = node as HTMLScriptElement; - return node; - }); - - // FIXME: Remove when updating file. Eslint update - // eslint-disable-next-line @typescript-eslint/no-require-imports - require("./lp-suppress-import-download-script-append.mv2"); - - expect(window.document.createElement).toHaveBeenCalledWith("script"); - expect(chrome.runtime.getURL).toHaveBeenCalledWith("content/lp-suppress-import-download.js"); - expect(window.document.documentElement.appendChild).toHaveBeenCalledWith( - expect.any(HTMLScriptElement), - ); - expect(createdScriptElement.src).toBe( - "chrome-extension://id/content/lp-suppress-import-download.js", - ); - }); -}); diff --git a/apps/browser/src/tools/content/lp-suppress-import-download-script-append.mv2.ts b/apps/browser/src/tools/content/lp-suppress-import-download-script-append.mv2.ts deleted file mode 100644 index cd641590ad1..00000000000 --- a/apps/browser/src/tools/content/lp-suppress-import-download-script-append.mv2.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * This script handles injection of the LP suppress import download script into the document. - * This is required for manifest v2, but will be removed when we migrate fully to manifest v3. - */ -(function (globalContext) { - const script = globalContext.document.createElement("script"); - script.src = chrome.runtime.getURL("content/lp-suppress-import-download.js"); - globalContext.document.documentElement.appendChild(script); -})(window); diff --git a/apps/browser/src/tools/content/lp-suppress-import-download.spec.ts b/apps/browser/src/tools/content/lp-suppress-import-download.spec.ts deleted file mode 100644 index ff0ed381599..00000000000 --- a/apps/browser/src/tools/content/lp-suppress-import-download.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { flushPromises, postWindowMessage } from "../../autofill/spec/testing-utils"; - -describe("LP Suppress Import Download", () => { - const downloadAttribute = "file.csv"; - const hrefAttribute = "https://example.com/file.csv"; - const overridenHrefAttribute = "javascript:void(0)"; - let anchor: HTMLAnchorElement; - - beforeEach(() => { - jest.spyOn(Element.prototype, "appendChild"); - jest.spyOn(window, "addEventListener"); - - // FIXME: Remove when updating file. Eslint update - // eslint-disable-next-line @typescript-eslint/no-require-imports - require("./lp-suppress-import-download"); - - anchor = document.createElement("a"); - anchor.download = downloadAttribute; - anchor.href = hrefAttribute; - anchor.click = jest.fn(); - }); - - afterEach(() => { - jest.resetModules(); - jest.clearAllMocks(); - }); - - it("disables the automatic download anchor", () => { - document.body.appendChild(anchor); - - expect(anchor.href).toBe(overridenHrefAttribute); - expect(anchor.download).toBe(""); - }); - - it("triggers the CSVDownload when receiving a `triggerCsvDownload` window message", async () => { - window.document.createElement = jest.fn(() => anchor); - jest.spyOn(window, "removeEventListener"); - - document.body.appendChild(anchor); - - // Precondition - Ensure the anchor in the document has overridden href and download attributes - expect(anchor.href).toBe(overridenHrefAttribute); - expect(anchor.download).toBe(""); - - postWindowMessage({ command: "triggerCsvDownload" }); - await flushPromises(); - - expect(anchor.click).toHaveBeenCalled(); - expect(anchor.href).toEqual(hrefAttribute); - expect(anchor.download).toEqual(downloadAttribute); - expect(window.removeEventListener).toHaveBeenCalledWith("message", expect.any(Function)); - }); - - it("skips subsequent calls to trigger a CSVDownload", async () => { - window.document.createElement = jest.fn(() => anchor); - - document.body.appendChild(anchor); - - postWindowMessage({ command: "triggerCsvDownload" }); - await flushPromises(); - - postWindowMessage({ command: "triggerCsvDownload" }); - await flushPromises(); - - expect(anchor.click).toHaveBeenCalledTimes(1); - }); - - it("skips triggering the CSV download for window messages that do not have the correct command", () => { - document.body.appendChild(anchor); - - postWindowMessage({ command: "notTriggerCsvDownload" }); - - expect(anchor.click).not.toHaveBeenCalled(); - }); - - it("skips triggering the CSV download for window messages that do not have a data value", () => { - document.body.appendChild(anchor); - - postWindowMessage(null); - - expect(anchor.click).not.toHaveBeenCalled(); - }); -}); diff --git a/apps/browser/src/tools/content/lp-suppress-import-download.ts b/apps/browser/src/tools/content/lp-suppress-import-download.ts deleted file mode 100644 index 1d5d449d199..00000000000 --- a/apps/browser/src/tools/content/lp-suppress-import-download.ts +++ /dev/null @@ -1,52 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -/** - * Handles intercepting the injection of the CSV download link, and ensures the - * download of the script is suppressed until the user opts to download the file. - * The download is triggered by a window message sent from the LpFilelessImporter - * content script. - */ -(function (globalContext) { - let csvDownload = ""; - let csvHref = ""; - let isCsvDownloadTriggered = false; - const defaultAppendChild = Element.prototype.appendChild; - Element.prototype.appendChild = function (newChild: Node) { - if (isAnchorElement(newChild) && newChild.download) { - csvDownload = newChild.download; - csvHref = newChild.href; - newChild.setAttribute("href", "javascript:void(0)"); - newChild.setAttribute("download", ""); - Element.prototype.appendChild = defaultAppendChild; - } - - return defaultAppendChild.call(this, newChild); - }; - - function isAnchorElement(node: Node): node is HTMLAnchorElement { - return node.nodeName.toLowerCase() === "a"; - } - - const handleWindowMessage = (event: MessageEvent) => { - const command = event.data?.command; - if ( - event.source !== globalContext || - command !== "triggerCsvDownload" || - isCsvDownloadTriggered - ) { - return; - } - - isCsvDownloadTriggered = true; - globalContext.removeEventListener("message", handleWindowMessage); - - const anchor = globalContext.document.createElement("a"); - anchor.setAttribute("href", csvHref); - anchor.setAttribute("download", csvDownload); - globalContext.document.body.appendChild(anchor); - anchor.click(); - globalContext.document.body.removeChild(anchor); - }; - - globalContext.addEventListener("message", handleWindowMessage); -})(window); diff --git a/apps/browser/src/tools/enums/fileless-import.enums.ts b/apps/browser/src/tools/enums/fileless-import.enums.ts deleted file mode 100644 index e20f4f15454..00000000000 --- a/apps/browser/src/tools/enums/fileless-import.enums.ts +++ /dev/null @@ -1,12 +0,0 @@ -const FilelessImportType = { - LP: "LP", -} as const; - -type FilelessImportTypeKeys = (typeof FilelessImportType)[keyof typeof FilelessImportType]; - -const FilelessImportPort = { - NotificationBar: "fileless-importer-notification-bar", - LpImporter: "lp-fileless-importer", -} as const; - -export { FilelessImportType, FilelessImportTypeKeys, FilelessImportPort }; diff --git a/apps/browser/webpack.config.js b/apps/browser/webpack.config.js index 6ba74d7df43..bce41d64d1f 100644 --- a/apps/browser/webpack.config.js +++ b/apps/browser/webpack.config.js @@ -206,9 +206,7 @@ const mainConfig = { "overlay/list": "./src/autofill/deprecated/overlay/pages/list/bootstrap-autofill-overlay-list.deprecated.ts", "encrypt-worker": "../../libs/common/src/platform/services/cryptography/encrypt.worker.ts", - "content/lp-fileless-importer": "./src/tools/content/lp-fileless-importer.ts", "content/send-on-installed-message": "./src/vault/content/send-on-installed-message.ts", - "content/lp-suppress-import-download": "./src/tools/content/lp-suppress-import-download.ts", }, optimization: { minimize: ENV !== "development", @@ -312,8 +310,6 @@ if (manifestVersion == 2) { // Manifest V2 background pages can be run through the regular build pipeline. // Since it's a standard webpage. mainConfig.entry.background = "./src/platform/background.ts"; - mainConfig.entry["content/lp-suppress-import-download-script-append-mv2"] = - "./src/tools/content/lp-suppress-import-download-script-append.mv2.ts"; mainConfig.entry["content/fido2-page-script-append-mv2"] = "./src/autofill/fido2/content/fido2-page-script-append.mv2.ts"; mainConfig.entry["content/fido2-page-script-delay-append-mv2"] = diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index d008a09d66c..2ac4f507cdb 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -9,6 +9,7 @@ export enum FeatureFlag { DelayFido2PageScriptInitWithinMv2 = "delay-fido2-page-script-init-within-mv2", EnableNewCardCombinedExpiryAutofill = "enable-new-card-combined-expiry-autofill", GenerateIdentityFillScriptRefactor = "generate-identity-fill-script-refactor", + IdpAutoSubmitLogin = "idp-auto-submit-login", InlineMenuFieldQualification = "inline-menu-field-qualification", InlineMenuPositioningImprovements = "inline-menu-positioning-improvements", InlineMenuTotp = "inline-menu-totp", @@ -16,7 +17,6 @@ export enum FeatureFlag { NotificationRefresh = "notification-refresh", UseTreeWalkerApiForPageDetailsCollection = "use-tree-walker-api-for-page-details-collection", - BrowserFilelessImport = "browser-fileless-import", ItemShare = "item-share", GeneratorToolsModernization = "generator-tools-modernization", AC1795_UpdatedSubscriptionStatusSection = "AC-1795_updated-subscription-status-section", @@ -27,7 +27,6 @@ export enum FeatureFlag { TwoFactorComponentRefactor = "two-factor-component-refactor", ProviderClientVaultPrivacyBanner = "ac-2833-provider-client-vault-privacy-banner", VaultBulkManagementAction = "vault-bulk-management-action", - IdpAutoSubmitLogin = "idp-auto-submit-login", UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh", AccountDeprovisioning = "pm-10308-account-deprovisioning", SSHKeyVaultItem = "ssh-key-vault-item", @@ -66,6 +65,7 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.DelayFido2PageScriptInitWithinMv2]: FALSE, [FeatureFlag.EnableNewCardCombinedExpiryAutofill]: FALSE, [FeatureFlag.GenerateIdentityFillScriptRefactor]: FALSE, + [FeatureFlag.IdpAutoSubmitLogin]: FALSE, [FeatureFlag.InlineMenuFieldQualification]: FALSE, [FeatureFlag.InlineMenuPositioningImprovements]: FALSE, [FeatureFlag.InlineMenuTotp]: FALSE, @@ -73,7 +73,6 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.NotificationRefresh]: FALSE, [FeatureFlag.UseTreeWalkerApiForPageDetailsCollection]: FALSE, - [FeatureFlag.BrowserFilelessImport]: FALSE, [FeatureFlag.ItemShare]: FALSE, [FeatureFlag.GeneratorToolsModernization]: FALSE, [FeatureFlag.AC1795_UpdatedSubscriptionStatusSection]: FALSE, @@ -84,7 +83,6 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.TwoFactorComponentRefactor]: FALSE, [FeatureFlag.ProviderClientVaultPrivacyBanner]: FALSE, [FeatureFlag.VaultBulkManagementAction]: FALSE, - [FeatureFlag.IdpAutoSubmitLogin]: FALSE, [FeatureFlag.UnauthenticatedExtensionUIRefresh]: FALSE, [FeatureFlag.AccountDeprovisioning]: FALSE, [FeatureFlag.SSHKeyVaultItem]: FALSE, From 87171289f028cec3a89188692cd5c6a374aeba70 Mon Sep 17 00:00:00 2001 From: Todd Martin <106564991+trmartin4@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:16:52 -0500 Subject: [PATCH 06/17] Revert Opera to Mv2 build (#12921) --- .github/workflows/build-browser.yml | 6 +++++- apps/browser/package.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-browser.yml b/.github/workflows/build-browser.yml index 64cbaa0c7f1..974e07829c1 100644 --- a/.github/workflows/build-browser.yml +++ b/.github/workflows/build-browser.yml @@ -208,7 +208,11 @@ jobs: - name: "opera" npm_command: "dist:opera" archive_name: "dist-opera.zip" - artifact_name: "dist-opera-MV3" + artifact_name: "dist-opera" + - name: "opera-mv3" + npm_command: "dist:opera:mv3" + archive_name: "dist-opera.zip" + artifact_name: "DO-NOT-USE-FOR-PROD-dist-opera-MV3" steps: - name: Check out repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 diff --git a/apps/browser/package.json b/apps/browser/package.json index 9ad1805362e..c37e7c24199 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -6,7 +6,7 @@ "build:chrome": "cross-env BROWSER=chrome MANIFEST_VERSION=3 webpack", "build:edge": "cross-env BROWSER=edge MANIFEST_VERSION=3 webpack", "build:firefox": "cross-env BROWSER=firefox webpack", - "build:opera": "cross-env BROWSER=opera MANIFEST_VERSION=3 webpack", + "build:opera": "cross-env BROWSER=opera webpack", "build:safari": "cross-env BROWSER=safari webpack", "build:watch": "npm run build:watch:chrome", "build:watch:chrome": "npm run build:chrome -- --watch", From e5f83ff08605424b6656d7b379fd1d95f3f4d1b5 Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Fri, 17 Jan 2025 16:42:31 +0100 Subject: [PATCH 07/17] [PM-17031] Create UI-common (#12831) Extract core functionality from `libs/angular` to allow teams to depend on `libs/ui-common` instead. Moves the following functionality to `ui-common`. - `I18nPipe`. `libs/angular` still has an old copy but `components` depends on the new variant from `ui-common`. - `safeProvider`, `SafeProvider` and `SafeInjectionToken`. `libs/angular`re-exports these to avoid needing to update all consumers. --- .github/CODEOWNERS | 1 + .github/whitelist-capital-letters.txt | 17 --- .github/workflows/lint.yml | 1 + .../popup/two-factor-auth-duo.component.ts | 4 - .../popup/two-factor-auth-email.component.ts | 4 - apps/browser/tsconfig.json | 15 +- .../src/auth/two-factor-auth.component.ts | 4 - apps/desktop/tsconfig.json | 9 +- .../integration-card.component.spec.ts | 2 +- .../integration-grid.component.spec.ts | 2 +- apps/web/tsconfig.json | 11 +- bitwarden_license/bit-common/tsconfig.json | 15 +- bitwarden_license/bit-web/tsconfig.json | 1 + libs/angular/src/platform/pipes/i18n.pipe.ts | 3 + .../src/platform/utils/safe-provider.ts | 138 +----------------- libs/angular/src/services/injection-tokens.ts | 15 +- .../src/services/jslib-services.module.ts | 2 +- libs/angular/tsconfig.json | 1 + libs/auth/tsconfig.json | 11 +- libs/common/tsconfig.json | 5 +- .../src/badge-list/badge-list.component.ts | 3 +- .../components/src/banner/banner.component.ts | 3 +- .../src/dialog/dialog/dialog.component.ts | 3 +- .../form-control/form-control.component.ts | 2 +- .../src/form-field/error-summary.component.ts | 2 +- .../src/form-field/form-field.component.ts | 3 +- .../multi-select/multi-select.component.ts | 2 +- .../src/navigation/nav-group.component.ts | 3 +- .../src/navigation/side-nav.component.ts | 3 +- .../src/radio-button/radio-group.component.ts | 3 +- .../components/src/search/search.component.ts | 2 +- libs/components/src/shared/shared.module.ts | 2 +- libs/components/tsconfig.json | 3 +- libs/importer/tsconfig.json | 1 + libs/key-management/tsconfig.json | 3 +- libs/shared/tsconfig.spec.json | 9 +- libs/tools/card/tsconfig.json | 3 +- .../vault-export-ui/tsconfig.json | 1 + libs/tools/generator/components/tsconfig.json | 3 +- libs/tools/send/send-ui/tsconfig.json | 3 +- libs/ui/README.md | 5 + libs/ui/common/package.json | 15 ++ libs/ui/common/src/di/index.ts | 2 + libs/ui/common/src/di/safe-injection-token.ts | 14 ++ libs/ui/common/src/di/safe-provider.ts | 138 ++++++++++++++++++ .../common/src/di}/safe-provider.type.spec.ts | 4 +- .../src/shared => ui/common/src}/i18n.pipe.ts | 8 +- libs/ui/common/src/index.ts | 2 + libs/ui/common/tsconfig.json | 10 ++ libs/vault/tsconfig.json | 1 + tsconfig.eslint.json | 17 ++- tsconfig.json | 13 +- 52 files changed, 300 insertions(+), 247 deletions(-) create mode 100644 libs/ui/README.md create mode 100644 libs/ui/common/package.json create mode 100644 libs/ui/common/src/di/index.ts create mode 100644 libs/ui/common/src/di/safe-injection-token.ts create mode 100644 libs/ui/common/src/di/safe-provider.ts rename libs/{angular/src/platform/utils => ui/common/src/di}/safe-provider.type.spec.ts (96%) rename libs/{components/src/shared => ui/common/src}/i18n.pipe.ts (77%) create mode 100644 libs/ui/common/src/index.ts create mode 100644 libs/ui/common/tsconfig.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index cb36d87b9e1..d7cca18960a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -111,6 +111,7 @@ apps/desktop/desktop_native/core/src/ssh_agent @bitwarden/team-autofill-dev @bit ## Component Library ## .storybook @bitwarden/team-design-system libs/components @bitwarden/team-design-system +libs/ui @bitwarden/team-design-system apps/browser/src/platform/popup/layout @bitwarden/team-design-system apps/browser/src/popup/app-routing.animations.ts @bitwarden/team-design-system apps/web/src/app/layouts @bitwarden/team-design-system diff --git a/.github/whitelist-capital-letters.txt b/.github/whitelist-capital-letters.txt index 73d323851e5..653f6591c7f 100644 --- a/.github/whitelist-capital-letters.txt +++ b/.github/whitelist-capital-letters.txt @@ -3,26 +3,12 @@ ./apps/browser/src/safari/desktop/Assets.xcassets/AppIcon.appiconset ./apps/browser/src/safari/desktop/Base.lproj ./apps/browser/store/windows/Assets -./bitwarden_license/README.md ./libs/angular/src/directives/cipherListVirtualScroll.directive.ts -./libs/admin-console/README.md -./libs/auth/README.md -./libs/billing/README.md -./libs/common/src/tools/integration/README.md -./libs/platform/README.md -./libs/key-management/README.md -./libs/tools/README.md -./libs/tools/export/vault-export/README.md -./libs/tools/send/README.md -./libs/tools/card/README.md -./libs/vault/README.md -./README.md ./LICENSE_BITWARDEN.txt ./CONTRIBUTING.md ./LICENSE_GPL.txt ./LICENSE.txt ./apps/web/Dockerfile -./apps/web/README.md ./apps/desktop/resources/installerSidebar.bmp ./apps/desktop/resources/appx/SplashScreen.png ./apps/desktop/resources/appx/BadgeLogo.png @@ -30,10 +16,7 @@ ./apps/desktop/resources/appx/StoreLogo.png ./apps/desktop/resources/appx/Wide310x150Logo.png ./apps/desktop/resources/appx/Square44x44Logo.png -./apps/desktop/README.md ./apps/cli/stores/chocolatey/tools/VERIFICATION.txt -./apps/cli/README.md -./apps/browser/README.md ./apps/browser/store/windows/AppxManifest.xml ./apps/browser/src/background/nativeMessaging.background.ts ./apps/browser/src/models/browserComponentState.ts diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 867de3844e7..5bc566202c6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -34,6 +34,7 @@ jobs: ! -path "*/.DS_Store" \ ! -path "*/*locales/*" \ ! -path "./.github/*" \ + ! -path "*/README.md" \ ! -path "*/Cargo.toml" \ ! -path "*/Cargo.lock" \ ! -path "./apps/desktop/macos/*" \ diff --git a/apps/browser/src/auth/popup/two-factor-auth-duo.component.ts b/apps/browser/src/auth/popup/two-factor-auth-duo.component.ts index 53aedc7a5f3..687dc683929 100644 --- a/apps/browser/src/auth/popup/two-factor-auth-duo.component.ts +++ b/apps/browser/src/auth/popup/two-factor-auth-duo.component.ts @@ -27,9 +27,6 @@ import { FormFieldModule } from "../../../../../libs/components/src/form-field"; import { LinkModule } from "../../../../../libs/components/src/link"; // FIXME: remove `src` and fix import // eslint-disable-next-line no-restricted-imports -import { I18nPipe } from "../../../../../libs/components/src/shared/i18n.pipe"; -// FIXME: remove `src` and fix import -// eslint-disable-next-line no-restricted-imports import { TypographyModule } from "../../../../../libs/components/src/typography"; import { ZonedMessageListenerService } from "../../platform/browser/zoned-message-listener.service"; @@ -50,7 +47,6 @@ import { ZonedMessageListenerService } from "../../platform/browser/zoned-messag AsyncActionsModule, FormsModule, ], - providers: [I18nPipe], }) export class TwoFactorAuthDuoComponent extends TwoFactorAuthDuoBaseComponent diff --git a/apps/browser/src/auth/popup/two-factor-auth-email.component.ts b/apps/browser/src/auth/popup/two-factor-auth-email.component.ts index 723152adfab..7afe1eb889e 100644 --- a/apps/browser/src/auth/popup/two-factor-auth-email.component.ts +++ b/apps/browser/src/auth/popup/two-factor-auth-email.component.ts @@ -23,9 +23,6 @@ import { FormFieldModule } from "../../../../../libs/components/src/form-field"; import { LinkModule } from "../../../../../libs/components/src/link"; // FIXME: remove `src` and fix import // eslint-disable-next-line no-restricted-imports -import { I18nPipe } from "../../../../../libs/components/src/shared/i18n.pipe"; -// FIXME: remove `src` and fix import -// eslint-disable-next-line no-restricted-imports import { TypographyModule } from "../../../../../libs/components/src/typography"; import BrowserPopupUtils from "../../platform/popup/browser-popup-utils"; @@ -46,7 +43,6 @@ import BrowserPopupUtils from "../../platform/popup/browser-popup-utils"; AsyncActionsModule, FormsModule, ], - providers: [I18nPipe], }) export class TwoFactorAuthEmailComponent extends TwoFactorAuthEmailBaseComponent implements OnInit { private dialogService = inject(DialogService); diff --git a/apps/browser/tsconfig.json b/apps/browser/tsconfig.json index c1ef1443acc..2326e68f55d 100644 --- a/apps/browser/tsconfig.json +++ b/apps/browser/tsconfig.json @@ -24,17 +24,18 @@ "@bitwarden/generator-history": ["../../libs/tools/generator/extensions/history/src"], "@bitwarden/generator-legacy": ["../../libs/tools/generator/extensions/legacy/src"], "@bitwarden/generator-navigation": ["../../libs/tools/generator/extensions/navigation/src"], + "@bitwarden/importer/core": ["../../libs/importer/src"], + "@bitwarden/importer/ui": ["../../libs/importer/src/components"], + "@bitwarden/key-management": ["../../libs/key-management/src"], + "@bitwarden/key-management/angular": ["../../libs/key-management/src/angular"], + "@bitwarden/platform": ["../../libs/platform/src"], + "@bitwarden/send-ui": ["../../libs/tools/send/send-ui/src"], + "@bitwarden/tools-card": ["../../libs/tools/card/src"], + "@bitwarden/ui-common": ["../../libs/ui/common/src"], "@bitwarden/vault-export-core": [ "../../libs/tools/export/vault-export/vault-export-core/src" ], "@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-ui/src"], - "@bitwarden/importer/core": ["../../libs/importer/src"], - "@bitwarden/importer/ui": ["../../libs/importer/src/components"], - "@bitwarden/platform": ["../../libs/platform/src"], - "@bitwarden/send-ui": ["../../libs/tools/send/send-ui/src"], - "@bitwarden/tools-card": ["../../libs/tools/card/src"], - "@bitwarden/key-management": ["../../libs/key-management/src"], - "@bitwarden/key-management/angular": ["../../libs/key-management/src/angular"], "@bitwarden/vault": ["../../libs/vault/src"] }, "plugins": [ diff --git a/apps/desktop/src/auth/two-factor-auth.component.ts b/apps/desktop/src/auth/two-factor-auth.component.ts index 9e0898c39e2..d8b80c28df1 100644 --- a/apps/desktop/src/auth/two-factor-auth.component.ts +++ b/apps/desktop/src/auth/two-factor-auth.component.ts @@ -42,9 +42,6 @@ import { FormFieldModule } from "../../../../libs/components/src/form-field"; import { LinkModule } from "../../../../libs/components/src/link"; // FIXME: remove `src` and fix import // eslint-disable-next-line no-restricted-imports -import { I18nPipe } from "../../../../libs/components/src/shared/i18n.pipe"; -// FIXME: remove `src` and fix import -// eslint-disable-next-line no-restricted-imports import { TypographyModule } from "../../../../libs/components/src/typography"; import { TwoFactorAuthDuoComponent } from "./two-factor-auth-duo.component"; @@ -73,6 +70,5 @@ import { TwoFactorAuthDuoComponent } from "./two-factor-auth-duo.component"; TwoFactorAuthDuoComponent, TwoFactorAuthWebAuthnComponent, ], - providers: [I18nPipe], }) export class TwoFactorAuthComponent extends BaseTwoFactorAuthComponent {} diff --git a/apps/desktop/tsconfig.json b/apps/desktop/tsconfig.json index da61ef22dd4..cbeb1034d6c 100644 --- a/apps/desktop/tsconfig.json +++ b/apps/desktop/tsconfig.json @@ -22,10 +22,6 @@ "@bitwarden/generator-history": ["../../libs/tools/generator/extensions/history/src"], "@bitwarden/generator-legacy": ["../../libs/tools/generator/extensions/legacy/src"], "@bitwarden/generator-navigation": ["../../libs/tools/generator/extensions/navigation/src"], - "@bitwarden/vault-export-core": [ - "../../libs/tools/export/vault-export/vault-export-core/src" - ], - "@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-ui/src"], "@bitwarden/importer/core": ["../../libs/importer/src"], "@bitwarden/importer/ui": ["../../libs/importer/src/components"], "@bitwarden/key-management": ["../../libs/key-management/src"], @@ -34,6 +30,11 @@ "@bitwarden/platform": ["../../libs/platform/src"], "@bitwarden/send-ui": ["../../libs/tools/send/send-ui/src"], "@bitwarden/tools-card": ["../../libs/tools/card/src"], + "@bitwarden/ui-common": ["../../libs/ui/common/src"], + "@bitwarden/vault-export-core": [ + "../../libs/tools/export/vault-export/vault-export-core/src" + ], + "@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-ui/src"], "@bitwarden/vault": ["../../libs/vault/src"] }, "plugins": [ diff --git a/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component.spec.ts b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component.spec.ts index c8b6a290427..b9d54744761 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component.spec.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component.spec.ts @@ -7,7 +7,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { ThemeType } from "@bitwarden/common/platform/enums"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; import { SharedModule } from "@bitwarden/components/src/shared"; -import { I18nPipe } from "@bitwarden/components/src/shared/i18n.pipe"; +import { I18nPipe } from "@bitwarden/ui-common"; import { IntegrationCardComponent } from "./integration-card.component"; diff --git a/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component.spec.ts b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component.spec.ts index c77ec455e00..ee124a41c0d 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component.spec.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component.spec.ts @@ -9,7 +9,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { ThemeTypes } from "@bitwarden/common/platform/enums"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; import { SharedModule } from "@bitwarden/components/src/shared"; -import { I18nPipe } from "@bitwarden/components/src/shared/i18n.pipe"; +import { I18nPipe } from "@bitwarden/ui-common"; import { IntegrationCardComponent } from "../integration-card/integration-card.component"; import { Integration } from "../models"; diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index 678db7c4af5..701808df132 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -7,8 +7,8 @@ "paths": { "@bitwarden/admin-console/common": ["../../libs/admin-console/src/common"], "@bitwarden/angular/*": ["../../libs/angular/src/*"], - "@bitwarden/auth/common": ["../../libs/auth/src/common"], "@bitwarden/auth/angular": ["../../libs/auth/src/angular"], + "@bitwarden/auth/common": ["../../libs/auth/src/common"], "@bitwarden/billing": ["../../libs/billing/src"], "@bitwarden/bit-common/*": ["../../bitwarden_license/bit-common/src/*"], "@bitwarden/common/*": ["../../libs/common/src/*"], @@ -18,10 +18,6 @@ "@bitwarden/generator-history": ["../../libs/tools/generator/extensions/history/src"], "@bitwarden/generator-legacy": ["../../libs/tools/generator/extensions/legacy/src"], "@bitwarden/generator-navigation": ["../../libs/tools/generator/extensions/navigation/src"], - "@bitwarden/vault-export-core": [ - "../../libs/tools/export/vault-export/vault-export-core/src" - ], - "@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-ui/src"], "@bitwarden/importer/core": ["../../libs/importer/src"], "@bitwarden/importer/ui": ["../../libs/importer/src/components"], "@bitwarden/key-management": ["../../libs/key-management/src"], @@ -29,6 +25,11 @@ "@bitwarden/platform": ["../../libs/platform/src"], "@bitwarden/send-ui": ["../../libs/tools/send/send-ui/src"], "@bitwarden/tools-card": ["../../libs/tools/card/src"], + "@bitwarden/ui-common": ["../../libs/ui/common/src"], + "@bitwarden/vault-export-core": [ + "../../libs/tools/export/vault-export/vault-export-core/src" + ], + "@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-ui/src"], "@bitwarden/vault": ["../../libs/vault/src"], "@bitwarden/web-vault/*": ["src/*"] } diff --git a/bitwarden_license/bit-common/tsconfig.json b/bitwarden_license/bit-common/tsconfig.json index 7791840950b..ec1d3787f82 100644 --- a/bitwarden_license/bit-common/tsconfig.json +++ b/bitwarden_license/bit-common/tsconfig.json @@ -9,6 +9,7 @@ "@bitwarden/angular/*": ["../../libs/angular/src/*"], "@bitwarden/auth": ["../../libs/auth/src"], "@bitwarden/billing": ["../../libs/billing/src"], + "@bitwarden/bit-common/*": ["../bit-common/src/*"], "@bitwarden/common/*": ["../../libs/common/src/*"], "@bitwarden/components": ["../../libs/components/src"], "@bitwarden/generator-components": ["../../libs/tools/generator/components/src"], @@ -16,18 +17,18 @@ "@bitwarden/generator-history": ["../../libs/tools/generator/extensions/history/src"], "@bitwarden/generator-legacy": ["../../libs/tools/generator/extensions/legacy/src"], "@bitwarden/generator-navigation": ["../../libs/tools/generator/extensions/navigation/src"], + "@bitwarden/key-management": ["../../libs/key-management/src"], + "@bitwarden/key-management/angular": ["../../libs/key-management/src/angular"], + "@bitwarden/platform": ["../../libs/platform/src"], + "@bitwarden/send-ui": ["../../libs/tools/send/send-ui/src"], + "@bitwarden/tools-card": ["../../libs/tools/card/src"], + "@bitwarden/ui-common": ["../../libs/ui/common/src"], "@bitwarden/vault-export-core": [ "../../libs/tools/export/vault-export/vault-export-core/src" ], "@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-core/src"], - "@bitwarden/send-ui": ["../../libs/tools/send/send-ui/src"], - "@bitwarden/tools-card": ["../../libs/tools/card/src"], - "@bitwarden/key-management": ["../../libs/key-management/src"], - "@bitwarden/key-management/angular": ["../../libs/key-management/src/angular"], - "@bitwarden/platform": ["../../libs/platform/src"], "@bitwarden/vault": ["../../libs/vault/src"], - "@bitwarden/web-vault/*": ["../../apps/web/src/*"], - "@bitwarden/bit-common/*": ["../bit-common/src/*"] + "@bitwarden/web-vault/*": ["../../apps/web/src/*"] } } } diff --git a/bitwarden_license/bit-web/tsconfig.json b/bitwarden_license/bit-web/tsconfig.json index c4304ec2bd9..13a6466b3b5 100644 --- a/bitwarden_license/bit-web/tsconfig.json +++ b/bitwarden_license/bit-web/tsconfig.json @@ -26,6 +26,7 @@ "@bitwarden/key-management": ["../../libs/key-management/src"], "@bitwarden/key-management/angular": ["../../libs/key-management/src/angular"], "@bitwarden/platform": ["../../libs/platform/src"], + "@bitwarden/ui-common": ["../../libs/ui/common/src"], "@bitwarden/send-ui": ["../../libs/tools/send/send-ui/src"], "@bitwarden/tools-card": ["../../libs/tools/card/src"], "@bitwarden/vault": ["../../libs/vault/src"], diff --git a/libs/angular/src/platform/pipes/i18n.pipe.ts b/libs/angular/src/platform/pipes/i18n.pipe.ts index 1f92bbb19a4..a6fdbc78255 100644 --- a/libs/angular/src/platform/pipes/i18n.pipe.ts +++ b/libs/angular/src/platform/pipes/i18n.pipe.ts @@ -2,6 +2,9 @@ import { Pipe, PipeTransform } from "@angular/core"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +/** + * @deprecated: Please use the I18nPipe from @bitwarden/ui-common + */ @Pipe({ name: "i18n", }) diff --git a/libs/angular/src/platform/utils/safe-provider.ts b/libs/angular/src/platform/utils/safe-provider.ts index e7547f9b828..82b5affcc22 100644 --- a/libs/angular/src/platform/utils/safe-provider.ts +++ b/libs/angular/src/platform/utils/safe-provider.ts @@ -1,138 +1,4 @@ -import { Provider } from "@angular/core"; -import { Constructor, Opaque } from "type-fest"; - -import { SafeInjectionToken } from "../../services/injection-tokens"; - /** - * The return type of the {@link safeProvider} helper function. - * Used to distinguish a type safe provider definition from a non-type safe provider definition. + * @deprecated: Please use the SafeProvider & safeProvider from @bitwarden/ui-common */ -export type SafeProvider = Opaque; - -// TODO: type-fest also provides a type like this when we upgrade >= 3.7.0 -type AbstractConstructor = abstract new (...args: any) => T; - -type MapParametersToDeps = { - [K in keyof T]: AbstractConstructor | SafeInjectionToken; -}; - -type SafeInjectionTokenType = T extends SafeInjectionToken ? J : never; - -/** - * Gets the instance type from a constructor, abstract constructor, or SafeInjectionToken - */ -type ProviderInstanceType = - T extends SafeInjectionToken - ? InstanceType> - : T extends Constructor | AbstractConstructor - ? InstanceType - : never; - -/** - * Represents a dependency provided with the useClass option. - */ -type SafeClassProvider< - A extends AbstractConstructor | SafeInjectionToken, - I extends Constructor>, - D extends MapParametersToDeps>, -> = { - provide: A; - useClass: I; - deps: D; -}; - -/** - * Represents a dependency provided with the useValue option. - */ -type SafeValueProvider, V extends SafeInjectionTokenType> = { - provide: A; - useValue: V; -}; - -/** - * Represents a dependency provided with the useFactory option. - */ -type SafeFactoryProvider< - A extends AbstractConstructor | SafeInjectionToken, - I extends (...args: any) => ProviderInstanceType, - D extends MapParametersToDeps>, -> = { - provide: A; - useFactory: I; - deps: D; - multi?: boolean; -}; - -/** - * Represents a dependency provided with the useExisting option. - */ -type SafeExistingProvider< - A extends Constructor | AbstractConstructor | SafeInjectionToken, - I extends Constructor> | AbstractConstructor>, -> = { - provide: A; - useExisting: I; -}; - -/** - * Represents a dependency where there is no abstract token, the token is the implementation - */ -type SafeConcreteProvider< - I extends Constructor, - D extends MapParametersToDeps>, -> = { - provide: I; - deps: D; -}; - -/** - * If useAngularDecorators: true is specified, do not require a deps array. - * This is a manual override for where @Injectable decorators are used - */ -type UseAngularDecorators = Omit & { - useAngularDecorators: true; -}; - -/** - * Represents a type with a deps array that may optionally be overridden with useAngularDecorators - */ -type AllowAngularDecorators = T | UseAngularDecorators; - -/** - * A factory function that creates a provider for the ngModule providers array. - * This (almost) guarantees type safety for your provider definition. It does nothing at runtime. - * Warning: the useAngularDecorators option provides an override where your class uses the Injectable decorator, - * however this cannot be enforced by the type system and will not cause an error if the decorator is not used. - * @example safeProvider({ provide: MyService, useClass: DefaultMyService, deps: [AnotherService] }) - * @param provider Your provider object in the usual shape (e.g. using useClass, useValue, useFactory, etc.) - * @returns The exact same object without modification (pass-through). - */ -export const safeProvider = < - // types for useClass - AClass extends AbstractConstructor | SafeInjectionToken, - IClass extends Constructor>, - DClass extends MapParametersToDeps>, - // types for useValue - AValue extends SafeInjectionToken, - VValue extends SafeInjectionTokenType, - // types for useFactory - AFactory extends AbstractConstructor | SafeInjectionToken, - IFactory extends (...args: any) => ProviderInstanceType, - DFactory extends MapParametersToDeps>, - // types for useExisting - AExisting extends Constructor | AbstractConstructor | SafeInjectionToken, - IExisting extends - | Constructor> - | AbstractConstructor>, - // types for no token - IConcrete extends Constructor, - DConcrete extends MapParametersToDeps>, ->( - provider: - | AllowAngularDecorators> - | SafeValueProvider - | AllowAngularDecorators> - | SafeExistingProvider - | AllowAngularDecorators> - | Constructor, -): SafeProvider => provider as SafeProvider; +export { SafeProvider, safeProvider } from "@bitwarden/ui-common"; diff --git a/libs/angular/src/services/injection-tokens.ts b/libs/angular/src/services/injection-tokens.ts index 3842c3250e1..2c740d5bb42 100644 --- a/libs/angular/src/services/injection-tokens.ts +++ b/libs/angular/src/services/injection-tokens.ts @@ -1,6 +1,5 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { InjectionToken } from "@angular/core"; import { Observable, Subject } from "rxjs"; import { LogoutReason } from "@bitwarden/auth/common"; @@ -14,17 +13,9 @@ import { Theme } from "@bitwarden/common/platform/enums"; import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; import { Message } from "@bitwarden/common/platform/messaging"; import { VaultTimeout } from "@bitwarden/common/types/vault-timeout.type"; - -declare const tag: unique symbol; -/** - * A (more) typesafe version of InjectionToken which will more strictly enforce the generic type parameter. - * @remarks The default angular implementation does not use the generic type to define the structure of the object, - * so the structural type system will not complain about a mismatch in the type parameter. - * This is solved by assigning T to an arbitrary private property. - */ -export class SafeInjectionToken extends InjectionToken { - private readonly [tag]: T; -} +import { SafeInjectionToken } from "@bitwarden/ui-common"; +// Re-export the SafeInjectionToken from ui-common +export { SafeInjectionToken } from "@bitwarden/ui-common"; export const WINDOW = new SafeInjectionToken("WINDOW"); export const OBSERVABLE_MEMORY_STORAGE = new SafeInjectionToken< diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 803808612cf..c1d25407c0e 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -293,6 +293,7 @@ import { UserAsymmetricKeysRegenerationApiService, DefaultUserAsymmetricKeysRegenerationApiService, } from "@bitwarden/key-management"; +import { SafeInjectionToken } from "@bitwarden/ui-common"; import { PasswordRepromptService } from "@bitwarden/vault"; import { VaultExportService, @@ -323,7 +324,6 @@ import { MEMORY_STORAGE, OBSERVABLE_DISK_STORAGE, OBSERVABLE_MEMORY_STORAGE, - SafeInjectionToken, SECURE_STORAGE, STATE_FACTORY, SUPPORTS_SECURE_STORAGE, diff --git a/libs/angular/tsconfig.json b/libs/angular/tsconfig.json index 6c510f81492..b638410a6a8 100644 --- a/libs/angular/tsconfig.json +++ b/libs/angular/tsconfig.json @@ -16,6 +16,7 @@ "@bitwarden/importer/core": ["../importer/src"], "@bitwarden/key-management": ["../key-management/src"], "@bitwarden/platform": ["../platform/src"], + "@bitwarden/ui-common": ["../ui/common/src"], "@bitwarden/vault-export-core": ["../tools/export/vault-export/vault-export-core/src"], "@bitwarden/vault": ["../vault/src"] } diff --git a/libs/auth/tsconfig.json b/libs/auth/tsconfig.json index 9be942d38de..8d08522ffce 100644 --- a/libs/auth/tsconfig.json +++ b/libs/auth/tsconfig.json @@ -4,17 +4,18 @@ "resolveJsonModule": true, "paths": { "@bitwarden/admin-console/common": ["../admin-console/src/common"], - "@bitwarden/auth/common": ["../auth/src/common"], - "@bitwarden/auth/angular": ["../auth/src/angular"], "@bitwarden/angular/*": ["../angular/src/*"], + "@bitwarden/auth/angular": ["../auth/src/angular"], + "@bitwarden/auth/common": ["../auth/src/common"], "@bitwarden/common/*": ["../common/src/*"], "@bitwarden/components": ["../components/src"], - "@bitwarden/key-management": ["../key-management/src"], - "@bitwarden/platform": ["../platform/src"], "@bitwarden/generator-core": ["../tools/generator/core/src"], "@bitwarden/generator-history": ["../tools/generator/extensions/history/src"], "@bitwarden/generator-legacy": ["../tools/generator/extensions/legacy/src"], - "@bitwarden/generator-navigation": ["../tools/generator/extensions/navigation/src"] + "@bitwarden/generator-navigation": ["../tools/generator/extensions/navigation/src"], + "@bitwarden/key-management": ["../key-management/src"], + "@bitwarden/platform": ["../platform/src"], + "@bitwarden/ui-common": ["../ui/common/src"] } }, "include": ["src", "spec"], diff --git a/libs/common/tsconfig.json b/libs/common/tsconfig.json index c28b60e28f8..2d1379f9c5f 100644 --- a/libs/common/tsconfig.json +++ b/libs/common/tsconfig.json @@ -6,9 +6,12 @@ "@bitwarden/auth/common": ["../auth/src/common"], // TODO: Remove once circular dependencies in admin-console, auth and key-management are resolved "@bitwarden/common/*": ["../common/src/*"], + // TODO: Remove once billing stops depending on components "@bitwarden/components": ["../components/src"], "@bitwarden/key-management": ["../key-management/src"], - "@bitwarden/platform": ["../platform/src"] + "@bitwarden/platform": ["../platform/src"], + // TODO: Remove once billing stops depending on components + "@bitwarden/ui-common": ["../ui/common/src"] } }, "include": ["src", "spec", "./custom-matchers.d.ts", "../key-management/src/index.ts"], diff --git a/libs/components/src/badge-list/badge-list.component.ts b/libs/components/src/badge-list/badge-list.component.ts index ac8cb3281ab..7d152761ed0 100644 --- a/libs/components/src/badge-list/badge-list.component.ts +++ b/libs/components/src/badge-list/badge-list.component.ts @@ -3,8 +3,9 @@ import { CommonModule } from "@angular/common"; import { Component, Input, OnChanges } from "@angular/core"; +import { I18nPipe } from "@bitwarden/ui-common"; + import { BadgeModule, BadgeVariant } from "../badge"; -import { I18nPipe } from "../shared/i18n.pipe"; @Component({ selector: "bit-badge-list", diff --git a/libs/components/src/banner/banner.component.ts b/libs/components/src/banner/banner.component.ts index d3f64329978..a7b710d6a74 100644 --- a/libs/components/src/banner/banner.component.ts +++ b/libs/components/src/banner/banner.component.ts @@ -3,8 +3,9 @@ import { CommonModule } from "@angular/common"; import { Component, Input, OnInit, Output, EventEmitter } from "@angular/core"; +import { I18nPipe } from "@bitwarden/ui-common"; + import { IconButtonModule } from "../icon-button"; -import { I18nPipe } from "../shared/i18n.pipe"; type BannerTypes = "premium" | "info" | "warning" | "danger"; diff --git a/libs/components/src/dialog/dialog/dialog.component.ts b/libs/components/src/dialog/dialog/dialog.component.ts index ed47201805a..e9e3e898257 100644 --- a/libs/components/src/dialog/dialog/dialog.component.ts +++ b/libs/components/src/dialog/dialog/dialog.component.ts @@ -4,8 +4,9 @@ import { coerceBooleanProperty } from "@angular/cdk/coercion"; import { CommonModule } from "@angular/common"; import { Component, HostBinding, Input } from "@angular/core"; +import { I18nPipe } from "@bitwarden/ui-common"; + import { BitIconButtonComponent } from "../../icon-button/icon-button.component"; -import { I18nPipe } from "../../shared/i18n.pipe"; import { TypographyDirective } from "../../typography/typography.directive"; import { fadeIn } from "../animations"; import { DialogCloseDirective } from "../directives/dialog-close.directive"; diff --git a/libs/components/src/form-control/form-control.component.ts b/libs/components/src/form-control/form-control.component.ts index 9b87c44157a..d22d49ac03a 100644 --- a/libs/components/src/form-control/form-control.component.ts +++ b/libs/components/src/form-control/form-control.component.ts @@ -5,8 +5,8 @@ import { NgClass, NgIf } from "@angular/common"; import { Component, ContentChild, HostBinding, Input } from "@angular/core"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { I18nPipe } from "@bitwarden/ui-common"; -import { I18nPipe } from "../shared/i18n.pipe"; import { TypographyDirective } from "../typography/typography.directive"; import { BitFormControlAbstraction } from "./form-control.abstraction"; diff --git a/libs/components/src/form-field/error-summary.component.ts b/libs/components/src/form-field/error-summary.component.ts index beed32a88ac..f9325d8f82a 100644 --- a/libs/components/src/form-field/error-summary.component.ts +++ b/libs/components/src/form-field/error-summary.component.ts @@ -4,7 +4,7 @@ import { NgIf } from "@angular/common"; import { Component, Input } from "@angular/core"; import { AbstractControl, UntypedFormGroup } from "@angular/forms"; -import { I18nPipe } from "../shared/i18n.pipe"; +import { I18nPipe } from "@bitwarden/ui-common"; @Component({ selector: "bit-error-summary", diff --git a/libs/components/src/form-field/form-field.component.ts b/libs/components/src/form-field/form-field.component.ts index 9f41c6cf6ac..4f7c2a67483 100644 --- a/libs/components/src/form-field/form-field.component.ts +++ b/libs/components/src/form-field/form-field.component.ts @@ -14,10 +14,11 @@ import { signal, } from "@angular/core"; +import { I18nPipe } from "@bitwarden/ui-common"; + import { BitHintComponent } from "../form-control/hint.component"; import { BitLabel } from "../form-control/label.component"; import { inputBorderClasses } from "../input/input.directive"; -import { I18nPipe } from "../shared/i18n.pipe"; import { BitErrorComponent } from "./error.component"; import { BitFormFieldControl } from "./form-field-control"; diff --git a/libs/components/src/multi-select/multi-select.component.ts b/libs/components/src/multi-select/multi-select.component.ts index 53e51bfe2f9..71b00404cfb 100644 --- a/libs/components/src/multi-select/multi-select.component.ts +++ b/libs/components/src/multi-select/multi-select.component.ts @@ -24,10 +24,10 @@ import { import { NgSelectComponent, NgSelectModule } from "@ng-select/ng-select"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { I18nPipe } from "@bitwarden/ui-common"; import { BadgeModule } from "../badge"; import { BitFormFieldControl } from "../form-field/form-field-control"; -import { I18nPipe } from "../shared/i18n.pipe"; import { SelectItemView } from "./models/select-item-view"; diff --git a/libs/components/src/navigation/nav-group.component.ts b/libs/components/src/navigation/nav-group.component.ts index d615bfe0582..37244f37c8d 100644 --- a/libs/components/src/navigation/nav-group.component.ts +++ b/libs/components/src/navigation/nav-group.component.ts @@ -12,8 +12,9 @@ import { SkipSelf, } from "@angular/core"; +import { I18nPipe } from "@bitwarden/ui-common"; + import { IconButtonModule } from "../icon-button"; -import { I18nPipe } from "../shared/i18n.pipe"; import { NavBaseComponent } from "./nav-base.component"; import { NavGroupAbstraction, NavItemComponent } from "./nav-item.component"; diff --git a/libs/components/src/navigation/side-nav.component.ts b/libs/components/src/navigation/side-nav.component.ts index c86a517100f..e8e4f131d6d 100644 --- a/libs/components/src/navigation/side-nav.component.ts +++ b/libs/components/src/navigation/side-nav.component.ts @@ -4,8 +4,9 @@ import { CdkTrapFocus } from "@angular/cdk/a11y"; import { CommonModule } from "@angular/common"; import { Component, ElementRef, Input, ViewChild } from "@angular/core"; +import { I18nPipe } from "@bitwarden/ui-common"; + import { BitIconButtonComponent } from "../icon-button/icon-button.component"; -import { I18nPipe } from "../shared/i18n.pipe"; import { NavDividerComponent } from "./nav-divider.component"; import { SideNavService } from "./side-nav.service"; diff --git a/libs/components/src/radio-button/radio-group.component.ts b/libs/components/src/radio-button/radio-group.component.ts index b9e48f46445..4ab626f7964 100644 --- a/libs/components/src/radio-button/radio-group.component.ts +++ b/libs/components/src/radio-button/radio-group.component.ts @@ -4,8 +4,9 @@ import { NgIf, NgTemplateOutlet } from "@angular/common"; import { Component, ContentChild, HostBinding, Input, Optional, Self } from "@angular/core"; import { ControlValueAccessor, NgControl, Validators } from "@angular/forms"; +import { I18nPipe } from "@bitwarden/ui-common"; + import { BitLabel } from "../form-control/label.component"; -import { I18nPipe } from "../shared/i18n.pipe"; let nextId = 0; diff --git a/libs/components/src/search/search.component.ts b/libs/components/src/search/search.component.ts index 9a811ce6777..7f1bd781e9d 100644 --- a/libs/components/src/search/search.component.ts +++ b/libs/components/src/search/search.component.ts @@ -9,10 +9,10 @@ import { } from "@angular/forms"; import { isBrowserSafariApi } from "@bitwarden/platform"; +import { I18nPipe } from "@bitwarden/ui-common"; import { InputModule } from "../input/input.module"; import { FocusableElement } from "../shared/focusable-element"; -import { I18nPipe } from "../shared/i18n.pipe"; let nextId = 0; diff --git a/libs/components/src/shared/shared.module.ts b/libs/components/src/shared/shared.module.ts index 253b049f8fe..99d052c3350 100644 --- a/libs/components/src/shared/shared.module.ts +++ b/libs/components/src/shared/shared.module.ts @@ -1,7 +1,7 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; -import { I18nPipe } from "./i18n.pipe"; +import { I18nPipe } from "@bitwarden/ui-common"; @NgModule({ imports: [CommonModule, I18nPipe], diff --git a/libs/components/tsconfig.json b/libs/components/tsconfig.json index 71eef15fac4..abd5830d425 100644 --- a/libs/components/tsconfig.json +++ b/libs/components/tsconfig.json @@ -20,7 +20,8 @@ "lib": ["es2020", "dom"], "paths": { "@bitwarden/common/*": ["../common/src/*"], - "@bitwarden/platform": ["../platform/src"] + "@bitwarden/platform": ["../platform/src"], + "@bitwarden/ui-common": ["../ui/common/src"] }, "plugins": [ { diff --git a/libs/importer/tsconfig.json b/libs/importer/tsconfig.json index 2235cccb5c7..09eb33e2884 100644 --- a/libs/importer/tsconfig.json +++ b/libs/importer/tsconfig.json @@ -13,6 +13,7 @@ "@bitwarden/generator-navigation": ["../tools/generator/extensions/navigation/src"], "@bitwarden/key-management": ["../key-management/src"], "@bitwarden/platform": ["../platform/src"], + "@bitwarden/ui-common": ["../ui/common/src"], "@bitwarden/vault-export-core": ["../tools/export/vault-export/vault-export-core/src"] } }, diff --git a/libs/key-management/tsconfig.json b/libs/key-management/tsconfig.json index 8279f14c786..e1e618314e8 100644 --- a/libs/key-management/tsconfig.json +++ b/libs/key-management/tsconfig.json @@ -13,7 +13,8 @@ "@bitwarden/generator-history": ["../tools/generator/extensions/history/src"], "@bitwarden/generator-legacy": ["../tools/generator/extensions/legacy/src"], "@bitwarden/generator-navigation": ["../tools/generator/extensions/navigation/src"], - "@bitwarden/platform": ["../platform/src"] + "@bitwarden/platform": ["../platform/src"], + "@bitwarden/ui-common": ["../ui/common/src"] } }, "include": ["src", "spec"], diff --git a/libs/shared/tsconfig.spec.json b/libs/shared/tsconfig.spec.json index 2366507918e..92c957c2975 100644 --- a/libs/shared/tsconfig.spec.json +++ b/libs/shared/tsconfig.spec.json @@ -5,8 +5,8 @@ "paths": { "@bitwarden/admin-console/common": ["../admin-console/src/common"], "@bitwarden/angular/*": ["../angular/src/*"], - "@bitwarden/auth/common": ["../auth/src/common"], "@bitwarden/auth/angular": ["../auth/src/angular"], + "@bitwarden/auth/common": ["../auth/src/common"], "@bitwarden/billing": ["../billing/src"], "@bitwarden/common/*": ["../common/src/*"], "@bitwarden/components": ["../components/src"], @@ -15,16 +15,17 @@ "@bitwarden/generator-history": ["../tools/generator/extensions/history/src"], "@bitwarden/generator-legacy": ["../tools/generator/extensions/legacy/src"], "@bitwarden/generator-navigation": ["../tools/generator/extensions/navigation/src"], - "@bitwarden/vault-export-core": ["../tools/export/vault-export/vault-export-core/src"], - "@bitwarden/vault-export-ui": ["../tools/export/vault-export/vault-export-ui/src"], "@bitwarden/importer/core": ["../importer/src"], "@bitwarden/importer/ui": ["../importer/src/components"], "@bitwarden/key-management": ["../key-management/src"], "@bitwarden/key-management/angular": ["../key-management/src/angular"], + "@bitwarden/node/*": ["../node/src/*"], "@bitwarden/platform": ["../platform/src"], "@bitwarden/send-ui": ["../tools/send/send-ui/src"], "@bitwarden/tools-card": ["../tools/card/src"], - "@bitwarden/node/*": ["../node/src/*"], + "@bitwarden/ui-common": ["../ui/common/src"], + "@bitwarden/vault-export-core": ["../tools/export/vault-export/vault-export-core/src"], + "@bitwarden/vault-export-ui": ["../tools/export/vault-export/vault-export-ui/src"], "@bitwarden/vault": ["../vault/src"] } } diff --git a/libs/tools/card/tsconfig.json b/libs/tools/card/tsconfig.json index 9c910521cc6..050a1748b7b 100644 --- a/libs/tools/card/tsconfig.json +++ b/libs/tools/card/tsconfig.json @@ -8,7 +8,8 @@ "@bitwarden/common/*": ["../../common/src/*"], "@bitwarden/components": ["../../components/src"], "@bitwarden/key-management": ["../../key-management/src"], - "@bitwarden/platform": ["../../platform/src"] + "@bitwarden/platform": ["../../platform/src"], + "@bitwarden/ui-common": ["../../ui/common/src"] } }, "include": ["src"], diff --git a/libs/tools/export/vault-export/vault-export-ui/tsconfig.json b/libs/tools/export/vault-export/vault-export-ui/tsconfig.json index 8c8a04d4b62..1732817986e 100644 --- a/libs/tools/export/vault-export/vault-export-ui/tsconfig.json +++ b/libs/tools/export/vault-export/vault-export-ui/tsconfig.json @@ -14,6 +14,7 @@ "@bitwarden/generator-navigation": ["../../../../tools/generator/extensions/navigation/src"], "@bitwarden/key-management": ["../../../../key-management/src"], "@bitwarden/platform": ["../../../../platform/src"], + "@bitwarden/ui-common": ["../../../../ui/common/src"], "@bitwarden/vault-export-core": [ "../../../../tools/export/vault-export/vault-export-core/src" ] diff --git a/libs/tools/generator/components/tsconfig.json b/libs/tools/generator/components/tsconfig.json index 76b060334f6..e0e4da268da 100644 --- a/libs/tools/generator/components/tsconfig.json +++ b/libs/tools/generator/components/tsconfig.json @@ -10,7 +10,8 @@ "@bitwarden/generator-core": ["../../../tools/generator/core/src"], "@bitwarden/generator-history": ["../../../tools/generator/extensions/history/src"], "@bitwarden/key-management": ["../../../key-management/src"], - "@bitwarden/platform": ["../../../platform/src"] + "@bitwarden/platform": ["../../../platform/src"], + "@bitwarden/ui-common": ["../../../ui/common/src"] } }, "include": ["src"], diff --git a/libs/tools/send/send-ui/tsconfig.json b/libs/tools/send/send-ui/tsconfig.json index 671154e0a04..e6d6680ad40 100644 --- a/libs/tools/send/send-ui/tsconfig.json +++ b/libs/tools/send/send-ui/tsconfig.json @@ -13,7 +13,8 @@ "@bitwarden/generator-legacy": ["../../../tools/generator/extensions/legacy/src"], "@bitwarden/generator-navigation": ["../../../tools/generator/extensions/navigation/src"], "@bitwarden/key-management": ["../../../key-management/src"], - "@bitwarden/platform": ["../../../platform/src"] + "@bitwarden/platform": ["../../../platform/src"], + "@bitwarden/ui-common": ["../../../ui/common/src"] } }, "include": ["src"], diff --git a/libs/ui/README.md b/libs/ui/README.md new file mode 100644 index 00000000000..e245aac71cb --- /dev/null +++ b/libs/ui/README.md @@ -0,0 +1,5 @@ +# UI Foundation + +Core UI libraries maintained by the UI Foundation team. + +- _ui-common_: Low-level utilities for Angular applications. diff --git a/libs/ui/common/package.json b/libs/ui/common/package.json new file mode 100644 index 00000000000..f1b03a3ebd0 --- /dev/null +++ b/libs/ui/common/package.json @@ -0,0 +1,15 @@ +{ + "name": "@bitwarden/ui-common", + "version": "0.0.0", + "description": "Low-level utilities for Angular applications", + "keywords": [ + "bitwarden" + ], + "author": "Bitwarden Inc.", + "homepage": "https://bitwarden.com", + "repository": { + "type": "git", + "url": "https://github.com/bitwarden/clients" + }, + "license": "GPL-3.0" +} diff --git a/libs/ui/common/src/di/index.ts b/libs/ui/common/src/di/index.ts new file mode 100644 index 00000000000..7b0705f1364 --- /dev/null +++ b/libs/ui/common/src/di/index.ts @@ -0,0 +1,2 @@ +export * from "./safe-injection-token"; +export * from "./safe-provider"; diff --git a/libs/ui/common/src/di/safe-injection-token.ts b/libs/ui/common/src/di/safe-injection-token.ts new file mode 100644 index 00000000000..aad081e1c76 --- /dev/null +++ b/libs/ui/common/src/di/safe-injection-token.ts @@ -0,0 +1,14 @@ +// FIXME: Update this file to be type safe and remove this and next line +// @ts-strict-ignore +import { InjectionToken } from "@angular/core"; + +declare const tag: unique symbol; +/** + * A (more) typesafe version of InjectionToken which will more strictly enforce the generic type parameter. + * @remarks The default angular implementation does not use the generic type to define the structure of the object, + * so the structural type system will not complain about a mismatch in the type parameter. + * This is solved by assigning T to an arbitrary private property. + */ +export class SafeInjectionToken extends InjectionToken { + private readonly [tag]: T; +} diff --git a/libs/ui/common/src/di/safe-provider.ts b/libs/ui/common/src/di/safe-provider.ts new file mode 100644 index 00000000000..002aa69a500 --- /dev/null +++ b/libs/ui/common/src/di/safe-provider.ts @@ -0,0 +1,138 @@ +import { Provider } from "@angular/core"; +import { Constructor, Opaque } from "type-fest"; + +import { SafeInjectionToken } from "./safe-injection-token"; + +/** + * The return type of the {@link safeProvider} helper function. + * Used to distinguish a type safe provider definition from a non-type safe provider definition. + */ +export type SafeProvider = Opaque; + +// TODO: type-fest also provides a type like this when we upgrade >= 3.7.0 +type AbstractConstructor = abstract new (...args: any) => T; + +type MapParametersToDeps = { + [K in keyof T]: AbstractConstructor | SafeInjectionToken; +}; + +type SafeInjectionTokenType = T extends SafeInjectionToken ? J : never; + +/** + * Gets the instance type from a constructor, abstract constructor, or SafeInjectionToken + */ +type ProviderInstanceType = + T extends SafeInjectionToken + ? InstanceType> + : T extends Constructor | AbstractConstructor + ? InstanceType + : never; + +/** + * Represents a dependency provided with the useClass option. + */ +type SafeClassProvider< + A extends AbstractConstructor | SafeInjectionToken, + I extends Constructor>, + D extends MapParametersToDeps>, +> = { + provide: A; + useClass: I; + deps: D; +}; + +/** + * Represents a dependency provided with the useValue option. + */ +type SafeValueProvider, V extends SafeInjectionTokenType> = { + provide: A; + useValue: V; +}; + +/** + * Represents a dependency provided with the useFactory option. + */ +type SafeFactoryProvider< + A extends AbstractConstructor | SafeInjectionToken, + I extends (...args: any) => ProviderInstanceType, + D extends MapParametersToDeps>, +> = { + provide: A; + useFactory: I; + deps: D; + multi?: boolean; +}; + +/** + * Represents a dependency provided with the useExisting option. + */ +type SafeExistingProvider< + A extends Constructor | AbstractConstructor | SafeInjectionToken, + I extends Constructor> | AbstractConstructor>, +> = { + provide: A; + useExisting: I; +}; + +/** + * Represents a dependency where there is no abstract token, the token is the implementation + */ +type SafeConcreteProvider< + I extends Constructor, + D extends MapParametersToDeps>, +> = { + provide: I; + deps: D; +}; + +/** + * If useAngularDecorators: true is specified, do not require a deps array. + * This is a manual override for where @Injectable decorators are used + */ +type UseAngularDecorators = Omit & { + useAngularDecorators: true; +}; + +/** + * Represents a type with a deps array that may optionally be overridden with useAngularDecorators + */ +type AllowAngularDecorators = T | UseAngularDecorators; + +/** + * A factory function that creates a provider for the ngModule providers array. + * This (almost) guarantees type safety for your provider definition. It does nothing at runtime. + * Warning: the useAngularDecorators option provides an override where your class uses the Injectable decorator, + * however this cannot be enforced by the type system and will not cause an error if the decorator is not used. + * @example safeProvider({ provide: MyService, useClass: DefaultMyService, deps: [AnotherService] }) + * @param provider Your provider object in the usual shape (e.g. using useClass, useValue, useFactory, etc.) + * @returns The exact same object without modification (pass-through). + */ +export const safeProvider = < + // types for useClass + AClass extends AbstractConstructor | SafeInjectionToken, + IClass extends Constructor>, + DClass extends MapParametersToDeps>, + // types for useValue + AValue extends SafeInjectionToken, + VValue extends SafeInjectionTokenType, + // types for useFactory + AFactory extends AbstractConstructor | SafeInjectionToken, + IFactory extends (...args: any) => ProviderInstanceType, + DFactory extends MapParametersToDeps>, + // types for useExisting + AExisting extends Constructor | AbstractConstructor | SafeInjectionToken, + IExisting extends + | Constructor> + | AbstractConstructor>, + // types for no token + IConcrete extends Constructor, + DConcrete extends MapParametersToDeps>, +>( + provider: + | AllowAngularDecorators> + | SafeValueProvider + | AllowAngularDecorators> + | SafeExistingProvider + | AllowAngularDecorators> + | Constructor, +): SafeProvider => provider as SafeProvider; diff --git a/libs/angular/src/platform/utils/safe-provider.type.spec.ts b/libs/ui/common/src/di/safe-provider.type.spec.ts similarity index 96% rename from libs/angular/src/platform/utils/safe-provider.type.spec.ts rename to libs/ui/common/src/di/safe-provider.type.spec.ts index 6fe6d0d0b6c..afc7071af1e 100644 --- a/libs/angular/src/platform/utils/safe-provider.type.spec.ts +++ b/libs/ui/common/src/di/safe-provider.type.spec.ts @@ -11,7 +11,7 @@ class FooFactory { } abstract class FooService { - createFoo: (str: string) => string; + abstract createFoo(str: string): string; } class DefaultFooService implements FooService { @@ -29,7 +29,7 @@ class BarFactory { } abstract class BarService { - createBar: (num: number) => number; + abstract createBar(num: number): number; } class DefaultBarService implements BarService { diff --git a/libs/components/src/shared/i18n.pipe.ts b/libs/ui/common/src/i18n.pipe.ts similarity index 77% rename from libs/components/src/shared/i18n.pipe.ts rename to libs/ui/common/src/i18n.pipe.ts index 91bf0b3198d..fdcfec0ceac 100644 --- a/libs/components/src/shared/i18n.pipe.ts +++ b/libs/ui/common/src/i18n.pipe.ts @@ -3,7 +3,13 @@ import { Pipe, PipeTransform } from "@angular/core"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; /** - * Temporarily duplicate this pipe + * Localizes the specified string. + * + * @example + * {{ 'key' | i18n }} + * + * @example + * {{ 'key' | i18n: 'param1' }} */ @Pipe({ name: "i18n", diff --git a/libs/ui/common/src/index.ts b/libs/ui/common/src/index.ts new file mode 100644 index 00000000000..97e55108116 --- /dev/null +++ b/libs/ui/common/src/index.ts @@ -0,0 +1,2 @@ +export * from "./di"; +export * from "./i18n.pipe"; diff --git a/libs/ui/common/tsconfig.json b/libs/ui/common/tsconfig.json new file mode 100644 index 00000000000..31062d41a1c --- /dev/null +++ b/libs/ui/common/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../shared/tsconfig", + "compilerOptions": { + "paths": { + "@bitwarden/common/*": ["../../common/src/*"] + } + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/libs/vault/tsconfig.json b/libs/vault/tsconfig.json index 8318212e81d..e1515183f22 100644 --- a/libs/vault/tsconfig.json +++ b/libs/vault/tsconfig.json @@ -15,6 +15,7 @@ "@bitwarden/generator-navigation": ["../tools/generator/extensions/navigation/src"], "@bitwarden/key-management": ["../key-management/src"], "@bitwarden/platform": ["../platform/src"], + "@bitwarden/ui-common": ["../ui/common/src"], "@bitwarden/vault": ["../vault/src"] } }, diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index a69452389f5..980d7832ace 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -20,6 +20,7 @@ "@bitwarden/angular/*": ["./libs/angular/src/*"], "@bitwarden/auth": ["./libs/auth/src"], "@bitwarden/billing": ["./libs/billing/src"], + "@bitwarden/bit-common/*": ["./bitwarden_license/bit-common/src/*"], "@bitwarden/common/*": ["./libs/common/src/*"], "@bitwarden/components": ["./libs/components/src"], "@bitwarden/generator-components": ["./libs/tools/generator/components/src"], @@ -27,18 +28,18 @@ "@bitwarden/generator-history": ["./libs/tools/generator/extensions/history/src"], "@bitwarden/generator-legacy": ["./libs/tools/generator/extensions/legacy/src"], "@bitwarden/generator-navigation": ["./libs/tools/generator/extensions/navigation/src"], - "@bitwarden/vault-export-core": [".libs/tools/export/vault-export/vault-export-core/src"], - "@bitwarden/vault-export-ui": [".libs/tools/export/vault-export/vault-export-ui/src"], "@bitwarden/importer/core": ["./libs/importer/src"], "@bitwarden/importer/ui": ["./libs/importer/src/components"], - "@bitwarden/send-ui": [".libs/tools/send/send-ui/src"], - "@bitwarden/tools-card": [".libs/tools/card/src"], - "@bitwarden/platform": ["./libs/platform/src"], - "@bitwarden/node/*": ["./libs/node/src/*"], - "@bitwarden/vault": ["./libs/vault/src"], "@bitwarden/key-management": ["./libs/key-management/src"], "@bitwarden/key-management/angular": ["./libs/key-management/src/angular"], - "@bitwarden/bit-common/*": ["./bitwarden_license/bit-common/src/*"] + "@bitwarden/node/*": ["./libs/node/src/*"], + "@bitwarden/platform": ["./libs/platform/src"], + "@bitwarden/send-ui": [".libs/tools/send/send-ui/src"], + "@bitwarden/tools-card": [".libs/tools/card/src"], + "@bitwarden/ui-common": ["./libs/ui/common/src"], + "@bitwarden/vault-export-core": [".libs/tools/export/vault-export/vault-export-core/src"], + "@bitwarden/vault-export-ui": [".libs/tools/export/vault-export/vault-export-ui/src"], + "@bitwarden/vault": ["./libs/vault/src"] }, "plugins": [ { diff --git a/tsconfig.json b/tsconfig.json index 91b4ee7dd6b..efa2ff70e1b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,9 +18,10 @@ "paths": { "@bitwarden/admin-console/common": ["./libs/admin-console/src/common"], "@bitwarden/angular/*": ["./libs/angular/src/*"], - "@bitwarden/auth/common": ["./libs/auth/src/common"], "@bitwarden/auth/angular": ["./libs/auth/src/angular"], + "@bitwarden/auth/common": ["./libs/auth/src/common"], "@bitwarden/billing": ["./libs/billing/src"], + "@bitwarden/bit-common/*": ["./bitwarden_license/bit-common/src/*"], "@bitwarden/common/*": ["./libs/common/src/*"], "@bitwarden/components": ["./libs/components/src"], "@bitwarden/generator-components": ["./libs/tools/generator/components/src"], @@ -28,19 +29,19 @@ "@bitwarden/generator-history": ["./libs/tools/generator/extensions/history/src"], "@bitwarden/generator-legacy": ["./libs/tools/generator/extensions/legacy/src"], "@bitwarden/generator-navigation": ["./libs/tools/generator/extensions/navigation/src"], - "@bitwarden/vault-export-core": ["./libs/tools/export/vault-export/vault-export-core/src"], - "@bitwarden/vault-export-ui": ["./libs/tools/export/vault-export/vault-export-ui/src"], "@bitwarden/importer/core": ["./libs/importer/src"], "@bitwarden/importer/ui": ["./libs/importer/src/components"], "@bitwarden/key-management": ["./libs/key-management/src"], "@bitwarden/key-management/angular": ["./libs/key-management/src/angular"], + "@bitwarden/node/*": ["./libs/node/src/*"], "@bitwarden/platform": ["./libs/platform/src"], "@bitwarden/send-ui": ["./libs/tools/send/send-ui/src"], "@bitwarden/tools-card": ["./libs/tools/card/src"], - "@bitwarden/node/*": ["./libs/node/src/*"], - "@bitwarden/web-vault/*": ["./apps/web/src/*"], + "@bitwarden/ui-common": ["./libs/ui/common/src"], + "@bitwarden/vault-export-core": ["./libs/tools/export/vault-export/vault-export-core/src"], + "@bitwarden/vault-export-ui": ["./libs/tools/export/vault-export/vault-export-ui/src"], "@bitwarden/vault": ["./libs/vault/src"], - "@bitwarden/bit-common/*": ["./bitwarden_license/bit-common/src/*"] + "@bitwarden/web-vault/*": ["./apps/web/src/*"] }, "plugins": [ { From 23227f50646bcf6e9e8e3579d391895c0a32e485 Mon Sep 17 00:00:00 2001 From: Danielle Flinn <43477473+danielleflinn@users.noreply.github.com> Date: Fri, 17 Jan 2025 07:50:20 -0800 Subject: [PATCH 08/17] [CL-256] Update Figma links in Storybook docs (#12901) * Update Figma links updated existing Figma links to point to the new file and added Figma links to components missing them * Added last missing Figma links --- .../src/platform/popup/layout/popup-layout.stories.ts | 4 ++++ libs/components/src/avatar/avatar.stories.ts | 2 +- libs/components/src/badge-list/badge-list.stories.ts | 2 +- libs/components/src/badge/badge.stories.ts | 2 +- libs/components/src/banner/banner.stories.ts | 2 +- libs/components/src/breadcrumbs/breadcrumbs.stories.ts | 6 ++++++ libs/components/src/button/button.stories.ts | 2 +- libs/components/src/callout/callout.stories.ts | 2 +- libs/components/src/card/card.stories.ts | 6 ++++++ libs/components/src/checkbox/checkbox.stories.ts | 2 +- libs/components/src/chip-select/chip-select.stories.ts | 6 ++++++ .../components/src/color-password/color-password.stories.ts | 2 +- libs/components/src/dialog/dialog.service.stories.ts | 2 +- libs/components/src/dialog/dialog/dialog.stories.ts | 2 +- .../simple-configurable-dialog.service.stories.ts | 2 +- .../dialog/simple-dialog/simple-dialog.service.stories.ts | 2 +- .../src/dialog/simple-dialog/simple-dialog.stories.ts | 2 +- libs/components/src/disclosure/disclosure.stories.ts | 6 ++++++ libs/components/src/form-field/bit-validators.stories.ts | 2 +- libs/components/src/form-field/error-summary.stories.ts | 2 +- libs/components/src/form-field/form-field.stories.ts | 2 +- libs/components/src/form-field/multi-select.stories.ts | 2 +- .../src/form-field/password-input-toggle.stories.ts | 2 +- libs/components/src/form/form.stories.ts | 2 +- libs/components/src/icon-button/icon-button.stories.ts | 2 +- libs/components/src/icon/icon.stories.ts | 6 ++++++ libs/components/src/item/item.stories.ts | 6 ++++++ libs/components/src/layout/layout.stories.ts | 4 ++++ libs/components/src/link/link.stories.ts | 2 +- libs/components/src/menu/menu.stories.ts | 2 +- libs/components/src/navigation/nav-group.stories.ts | 2 +- libs/components/src/navigation/nav-item.stories.ts | 2 +- libs/components/src/no-items/no-items.stories.ts | 6 ++++++ libs/components/src/popover/popover.stories.ts | 2 +- libs/components/src/progress/progress.stories.ts | 2 +- libs/components/src/radio-button/radio-button.stories.ts | 2 +- libs/components/src/section/section.stories.ts | 6 ++++++ libs/components/src/select/select.stories.ts | 2 +- libs/components/src/table/table.stories.ts | 2 +- libs/components/src/tabs/tabs.stories.ts | 2 +- libs/components/src/toast/toast.stories.ts | 2 +- libs/components/src/toggle-group/toggle-group.stories.ts | 2 +- 42 files changed, 88 insertions(+), 32 deletions(-) diff --git a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts index 6a2d8162c7f..43693ca223b 100644 --- a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts +++ b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts @@ -306,6 +306,10 @@ export default { // Disable tests while we troubleshoot their flaky-ness disableSnapshot: true, }, + design: { + type: "figma", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-38889&t=k6OTDDPZOTtypRqo-11", + }, }, decorators: [ moduleMetadata({ diff --git a/libs/components/src/avatar/avatar.stories.ts b/libs/components/src/avatar/avatar.stories.ts index d3a00fbe344..19a6f86d89c 100644 --- a/libs/components/src/avatar/avatar.stories.ts +++ b/libs/components/src/avatar/avatar.stories.ts @@ -13,7 +13,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A16994", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-26525&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/badge-list/badge-list.stories.ts b/libs/components/src/badge-list/badge-list.stories.ts index ede005f6fd6..f69ecde8377 100644 --- a/libs/components/src/badge-list/badge-list.stories.ts +++ b/libs/components/src/badge-list/badge-list.stories.ts @@ -33,7 +33,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/f32LSg3jaegICkMu7rPARm/Tailwind-Component-Library-Update?node-id=1881%3A16956", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-26440&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/badge/badge.stories.ts b/libs/components/src/badge/badge.stories.ts index 5d697f8ad8f..bff9eec6163 100644 --- a/libs/components/src/badge/badge.stories.ts +++ b/libs/components/src/badge/badge.stories.ts @@ -18,7 +18,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A16956", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-26440&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/banner/banner.stories.ts b/libs/components/src/banner/banner.stories.ts index c75d8b7034a..105d30bc04a 100644 --- a/libs/components/src/banner/banner.stories.ts +++ b/libs/components/src/banner/banner.stories.ts @@ -30,7 +30,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=2070%3A17207", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-26720&t=b5tDKylm5sWm2yKo-4", }, }, args: { diff --git a/libs/components/src/breadcrumbs/breadcrumbs.stories.ts b/libs/components/src/breadcrumbs/breadcrumbs.stories.ts index 9c8ccbccd3f..eb75a70ad75 100644 --- a/libs/components/src/breadcrumbs/breadcrumbs.stories.ts +++ b/libs/components/src/breadcrumbs/breadcrumbs.stories.ts @@ -35,6 +35,12 @@ export default { ], }), ], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-26962&t=b5tDKylm5sWm2yKo-4", + }, + }, args: { items: [], show: 3, diff --git a/libs/components/src/button/button.stories.ts b/libs/components/src/button/button.stories.ts index 3654442801c..469c2d1b51b 100644 --- a/libs/components/src/button/button.stories.ts +++ b/libs/components/src/button/button.stories.ts @@ -13,7 +13,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=5115%3A26950", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-28224&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/callout/callout.stories.ts b/libs/components/src/callout/callout.stories.ts index cb51e96e8da..3101d4316f1 100644 --- a/libs/components/src/callout/callout.stories.ts +++ b/libs/components/src/callout/callout.stories.ts @@ -30,7 +30,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A17484", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-28300&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/card/card.stories.ts b/libs/components/src/card/card.stories.ts index b33f5f4a198..3482eedfd54 100644 --- a/libs/components/src/card/card.stories.ts +++ b/libs/components/src/card/card.stories.ts @@ -34,6 +34,12 @@ export default { (story) => `
${story}
`, ), ], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-28355&t=b5tDKylm5sWm2yKo-4", + }, + }, } as Meta; type Story = StoryObj; diff --git a/libs/components/src/checkbox/checkbox.stories.ts b/libs/components/src/checkbox/checkbox.stories.ts index f3e5a5cb3f7..908085bb6df 100644 --- a/libs/components/src/checkbox/checkbox.stories.ts +++ b/libs/components/src/checkbox/checkbox.stories.ts @@ -83,7 +83,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=3930%3A16850&t=xXPx6GJYsJfuMQPE-4", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-35837&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/chip-select/chip-select.stories.ts b/libs/components/src/chip-select/chip-select.stories.ts index 598fa5b80be..e9b78235ccb 100644 --- a/libs/components/src/chip-select/chip-select.stories.ts +++ b/libs/components/src/chip-select/chip-select.stories.ts @@ -30,6 +30,12 @@ export default { ], }), ], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-29548&t=b5tDKylm5sWm2yKo-4", + }, + }, } as Meta; type Story = StoryObj; diff --git a/libs/components/src/color-password/color-password.stories.ts b/libs/components/src/color-password/color-password.stories.ts index 07418cad721..bb835d97d4a 100644 --- a/libs/components/src/color-password/color-password.stories.ts +++ b/libs/components/src/color-password/color-password.stories.ts @@ -14,7 +14,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/6fvTDa3zfvgWdizLQ7nSTP/Numbered-Password", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=21540-46261&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/dialog/dialog.service.stories.ts b/libs/components/src/dialog/dialog.service.stories.ts index 2b42faeccca..e7c5a17c308 100644 --- a/libs/components/src/dialog/dialog.service.stories.ts +++ b/libs/components/src/dialog/dialog.service.stories.ts @@ -93,7 +93,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-30495&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/dialog/dialog/dialog.stories.ts b/libs/components/src/dialog/dialog/dialog.stories.ts index 7cb6f40aa5b..03a88458f5a 100644 --- a/libs/components/src/dialog/dialog/dialog.stories.ts +++ b/libs/components/src/dialog/dialog/dialog.stories.ts @@ -68,7 +68,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-30495&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/dialog/simple-dialog/simple-configurable-dialog/simple-configurable-dialog.service.stories.ts b/libs/components/src/dialog/simple-dialog/simple-configurable-dialog/simple-configurable-dialog.service.stories.ts index 9953fdd24ea..b4bf199358b 100644 --- a/libs/components/src/dialog/simple-dialog/simple-configurable-dialog/simple-configurable-dialog.service.stories.ts +++ b/libs/components/src/dialog/simple-dialog/simple-configurable-dialog/simple-configurable-dialog.service.stories.ts @@ -176,7 +176,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=21514-19247&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/dialog/simple-dialog/simple-dialog.service.stories.ts b/libs/components/src/dialog/simple-dialog/simple-dialog.service.stories.ts index 3bc4999878c..680ebe9ed3b 100644 --- a/libs/components/src/dialog/simple-dialog/simple-dialog.service.stories.ts +++ b/libs/components/src/dialog/simple-dialog/simple-dialog.service.stories.ts @@ -89,7 +89,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=21514-19247&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/dialog/simple-dialog/simple-dialog.stories.ts b/libs/components/src/dialog/simple-dialog/simple-dialog.stories.ts index d86b56101b0..50016ef358d 100644 --- a/libs/components/src/dialog/simple-dialog/simple-dialog.stories.ts +++ b/libs/components/src/dialog/simple-dialog/simple-dialog.stories.ts @@ -17,7 +17,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=21514-19247&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/disclosure/disclosure.stories.ts b/libs/components/src/disclosure/disclosure.stories.ts index 974589a667c..bb3680c1f3b 100644 --- a/libs/components/src/disclosure/disclosure.stories.ts +++ b/libs/components/src/disclosure/disclosure.stories.ts @@ -13,6 +13,12 @@ export default { imports: [DisclosureTriggerForDirective, DisclosureComponent, IconButtonModule], }), ], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=21662-47329&t=k6OTDDPZOTtypRqo-11", + }, + }, } as Meta; type Story = StoryObj; diff --git a/libs/components/src/form-field/bit-validators.stories.ts b/libs/components/src/form-field/bit-validators.stories.ts index 642ff30bb5a..748f92f2523 100644 --- a/libs/components/src/form-field/bit-validators.stories.ts +++ b/libs/components/src/form-field/bit-validators.stories.ts @@ -35,7 +35,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/f32LSg3jaegICkMu7rPARm/Tailwind-Component-Library-Update?node-id=1881%3A17689", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=13213-55392&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/form-field/error-summary.stories.ts b/libs/components/src/form-field/error-summary.stories.ts index 4e1031abaf6..4b1a30c45b3 100644 --- a/libs/components/src/form-field/error-summary.stories.ts +++ b/libs/components/src/form-field/error-summary.stories.ts @@ -34,7 +34,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A17689", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=13213-55392&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/form-field/form-field.stories.ts b/libs/components/src/form-field/form-field.stories.ts index 6d8323e088e..738ac96bf76 100644 --- a/libs/components/src/form-field/form-field.stories.ts +++ b/libs/components/src/form-field/form-field.stories.ts @@ -108,7 +108,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A17689", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=13213-55392&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/form-field/multi-select.stories.ts b/libs/components/src/form-field/multi-select.stories.ts index da4776ab025..8d84aa735bf 100644 --- a/libs/components/src/form-field/multi-select.stories.ts +++ b/libs/components/src/form-field/multi-select.stories.ts @@ -56,7 +56,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=5600%3A24278", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=13213-55392&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/form-field/password-input-toggle.stories.ts b/libs/components/src/form-field/password-input-toggle.stories.ts index 094f939e0ea..d46ec92ab37 100644 --- a/libs/components/src/form-field/password-input-toggle.stories.ts +++ b/libs/components/src/form-field/password-input-toggle.stories.ts @@ -27,7 +27,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/f32LSg3jaegICkMu7rPARm/Tailwind-Component-Library-Update?node-id=1881%3A17689", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=13213-55392&t=b5tDKylm5sWm2yKo-4", }, docs: { description: { diff --git a/libs/components/src/form/form.stories.ts b/libs/components/src/form/form.stories.ts index 23b2cc8cea2..6aef140fe5f 100644 --- a/libs/components/src/form/form.stories.ts +++ b/libs/components/src/form/form.stories.ts @@ -64,7 +64,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A17689", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=13213-55392&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/icon-button/icon-button.stories.ts b/libs/components/src/icon-button/icon-button.stories.ts index 6274bb2b8d1..08c95c5d641 100644 --- a/libs/components/src/icon-button/icon-button.stories.ts +++ b/libs/components/src/icon-button/icon-button.stories.ts @@ -13,7 +13,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=4369%3A16686", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-37011&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/icon/icon.stories.ts b/libs/components/src/icon/icon.stories.ts index 54cdd7928cd..53454567b7f 100644 --- a/libs/components/src/icon/icon.stories.ts +++ b/libs/components/src/icon/icon.stories.ts @@ -6,6 +6,12 @@ import * as GenericIcons from "./icons"; export default { title: "Component Library/Icon", component: BitIconComponent, + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=21662-50335&t=k6OTDDPZOTtypRqo-11", + }, + }, } as Meta; type Story = StoryObj; diff --git a/libs/components/src/item/item.stories.ts b/libs/components/src/item/item.stories.ts index 5adf9d3c49d..3a64a334d0a 100644 --- a/libs/components/src/item/item.stories.ts +++ b/libs/components/src/item/item.stories.ts @@ -53,6 +53,12 @@ export default { }), componentWrapperDecorator((story) => `
${story}
`), ], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-37011&t=b5tDKylm5sWm2yKo-11", + }, + }, } as Meta; type Story = StoryObj; diff --git a/libs/components/src/layout/layout.stories.ts b/libs/components/src/layout/layout.stories.ts index 7fdad655548..e09055df596 100644 --- a/libs/components/src/layout/layout.stories.ts +++ b/libs/components/src/layout/layout.stories.ts @@ -31,6 +31,10 @@ export default { ], parameters: { chromatic: { viewports: [640, 1280] }, + design: { + type: "figma", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=21662-51009&t=k6OTDDPZOTtypRqo-11", + }, }, } as Meta; diff --git a/libs/components/src/link/link.stories.ts b/libs/components/src/link/link.stories.ts index cc3d26dc9d2..d07d33ae589 100644 --- a/libs/components/src/link/link.stories.ts +++ b/libs/components/src/link/link.stories.ts @@ -19,7 +19,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A17419", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-39582&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/menu/menu.stories.ts b/libs/components/src/menu/menu.stories.ts index 65fafd2d04d..f1f4d8df000 100644 --- a/libs/components/src/menu/menu.stories.ts +++ b/libs/components/src/menu/menu.stories.ts @@ -17,7 +17,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A17952", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-40144&t=b5tDKylm5sWm2yKo-11", }, }, } as Meta; diff --git a/libs/components/src/navigation/nav-group.stories.ts b/libs/components/src/navigation/nav-group.stories.ts index f412dbc20ba..6fbb89d4d9e 100644 --- a/libs/components/src/navigation/nav-group.stories.ts +++ b/libs/components/src/navigation/nav-group.stories.ts @@ -62,7 +62,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=4687%3A86642", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-40145&t=b5tDKylm5sWm2yKo-4", }, chromatic: { viewports: [640, 1280] }, }, diff --git a/libs/components/src/navigation/nav-item.stories.ts b/libs/components/src/navigation/nav-item.stories.ts index 376f121eb00..0f6f406b2eb 100644 --- a/libs/components/src/navigation/nav-item.stories.ts +++ b/libs/components/src/navigation/nav-item.stories.ts @@ -39,7 +39,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=4687%3A86642", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-40145&t=b5tDKylm5sWm2yKo-4", }, chromatic: { viewports: [640, 1280] }, }, diff --git a/libs/components/src/no-items/no-items.stories.ts b/libs/components/src/no-items/no-items.stories.ts index d8e5b59bdbf..48d52476b17 100644 --- a/libs/components/src/no-items/no-items.stories.ts +++ b/libs/components/src/no-items/no-items.stories.ts @@ -13,6 +13,12 @@ export default { imports: [ButtonModule, NoItemsModule], }), ], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=21665-25102&t=k6OTDDPZOTtypRqo-11", + }, + }, } as Meta; type Story = StoryObj; diff --git a/libs/components/src/popover/popover.stories.ts b/libs/components/src/popover/popover.stories.ts index 10b7b248b79..fca4d659607 100644 --- a/libs/components/src/popover/popover.stories.ts +++ b/libs/components/src/popover/popover.stories.ts @@ -30,7 +30,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1717-15868", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-40852&t=b5tDKylm5sWm2yKo-4", }, }, argTypes: { diff --git a/libs/components/src/progress/progress.stories.ts b/libs/components/src/progress/progress.stories.ts index 49a5398d2d9..1484dab0a21 100644 --- a/libs/components/src/progress/progress.stories.ts +++ b/libs/components/src/progress/progress.stories.ts @@ -8,7 +8,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A18185&t=AM0acaIJ00BUhZKz-4", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-40933&t=b5tDKylm5sWm2yKo-4", }, }, args: { diff --git a/libs/components/src/radio-button/radio-button.stories.ts b/libs/components/src/radio-button/radio-button.stories.ts index dcef13a19be..f5d7f6732f5 100644 --- a/libs/components/src/radio-button/radio-button.stories.ts +++ b/libs/components/src/radio-button/radio-button.stories.ts @@ -31,7 +31,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=3930%3A16850&t=xXPx6GJYsJfuMQPE-4", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-35836&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/section/section.stories.ts b/libs/components/src/section/section.stories.ts index 0d36d6e5a11..53e6bc078c5 100644 --- a/libs/components/src/section/section.stories.ts +++ b/libs/components/src/section/section.stories.ts @@ -22,6 +22,12 @@ export default { }), componentWrapperDecorator((story) => `
${story}
`), ], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=21666-19363&t=k6OTDDPZOTtypRqo-11", + }, + }, } as Meta; type Story = StoryObj; diff --git a/libs/components/src/select/select.stories.ts b/libs/components/src/select/select.stories.ts index 4bc85d8dba2..c030bea86c5 100644 --- a/libs/components/src/select/select.stories.ts +++ b/libs/components/src/select/select.stories.ts @@ -33,7 +33,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/3tWtMSYoLB0ZLEimLNzYsm/End-user-%26-admin-Vault-Refresh?t=7QEmGA69YTOF8sXU-0", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=13213-55392&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/table/table.stories.ts b/libs/components/src/table/table.stories.ts index 4ebc3045d13..e8ab24ee8b7 100644 --- a/libs/components/src/table/table.stories.ts +++ b/libs/components/src/table/table.stories.ts @@ -21,7 +21,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A18371", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-41282&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/tabs/tabs.stories.ts b/libs/components/src/tabs/tabs.stories.ts index 6b460d8ee00..250a7443065 100644 --- a/libs/components/src/tabs/tabs.stories.ts +++ b/libs/components/src/tabs/tabs.stories.ts @@ -74,7 +74,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A17922", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-41432&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; diff --git a/libs/components/src/toast/toast.stories.ts b/libs/components/src/toast/toast.stories.ts index 382e19097b0..abb737f5c23 100644 --- a/libs/components/src/toast/toast.stories.ts +++ b/libs/components/src/toast/toast.stories.ts @@ -63,7 +63,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-41506&t=b5tDKylm5sWm2yKo-11", }, }, } as Meta; diff --git a/libs/components/src/toggle-group/toggle-group.stories.ts b/libs/components/src/toggle-group/toggle-group.stories.ts index fc8ea0ea929..4860636c159 100644 --- a/libs/components/src/toggle-group/toggle-group.stories.ts +++ b/libs/components/src/toggle-group/toggle-group.stories.ts @@ -19,7 +19,7 @@ export default { parameters: { design: { type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A17157", + url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881-17157&t=b5tDKylm5sWm2yKo-4", }, }, } as Meta; From 83802fcdc51d95756e585e8f494738e73b9a20fe Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Fri, 17 Jan 2025 17:01:23 +0100 Subject: [PATCH 09/17] Fix i18n import of drawer component (#12932) Resolves main being broken after merging #12831 due to a new component depending on `I18nPipe`. --- libs/components/src/drawer/drawer-header.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/components/src/drawer/drawer-header.component.ts b/libs/components/src/drawer/drawer-header.component.ts index 73834b8487e..de112a448cf 100644 --- a/libs/components/src/drawer/drawer-header.component.ts +++ b/libs/components/src/drawer/drawer-header.component.ts @@ -1,8 +1,9 @@ import { CommonModule } from "@angular/common"; import { ChangeDetectionStrategy, Component, HostBinding, input } from "@angular/core"; +import { I18nPipe } from "@bitwarden/ui-common"; + import { IconButtonModule } from "../icon-button"; -import { I18nPipe } from "../shared/i18n.pipe"; import { TypographyModule } from "../typography"; import { DrawerCloseDirective } from "./drawer-close.directive"; From dbb341141a721299637ec3ffaf37ec909d584f2a Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:10:28 -0800 Subject: [PATCH 10/17] [PM-15572] - don't allow restore for 'edit except password' permission (#12851) * don't allow restore for 'edit except password' permission * show login credentials if only passkey is present * Revert "show login credentials if only passkey is present" This reverts commit dc2f2367c2092cb827cf95fe8c7bc82919949627. --- .../popup/components/vault-v2/view-v2/view-v2.component.ts | 6 +++++- .../trash-list-items-container.component.html | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/browser/src/vault/popup/components/vault-v2/view-v2/view-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/view-v2/view-v2.component.ts index 6532fb004cb..f3cd713dd5f 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/view-v2/view-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/view-v2/view-v2.component.ts @@ -235,7 +235,11 @@ export class ViewV2Component { } protected showFooter(): boolean { - return this.cipher && (!this.cipher.isDeleted || (this.cipher.isDeleted && this.cipher.edit)); + return ( + this.cipher && + (!this.cipher.isDeleted || + (this.cipher.isDeleted && this.cipher.edit && this.cipher.viewPassword)) + ); } /** diff --git a/apps/browser/src/vault/popup/settings/trash-list-items-container/trash-list-items-container.component.html b/apps/browser/src/vault/popup/settings/trash-list-items-container/trash-list-items-container.component.html index dcbda9fd96a..c77ac4f9755 100644 --- a/apps/browser/src/vault/popup/settings/trash-list-items-container/trash-list-items-container.component.html +++ b/apps/browser/src/vault/popup/settings/trash-list-items-container/trash-list-items-container.component.html @@ -31,7 +31,7 @@ > {{ cipher.subTitle }} - +
- + + @@ -62,7 +65,7 @@ type="button" buttonType="secondary" (click)="cancel()" - *ngIf="!showCipherView" + *ngIf="!showCipherView && !showRestore" > {{ "cancel" | i18n }} diff --git a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts index 59638aad653..a530fd0cc85 100644 --- a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts +++ b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts @@ -49,6 +49,8 @@ import { AttachmentDialogResult, AttachmentsV2Component, } from "../../individual-vault/attachments-v2.component"; +import { RoutedVaultFilterService } from "../../individual-vault/vault-filter/services/routed-vault-filter.service"; +import { RoutedVaultFilterModel } from "../../individual-vault/vault-filter/shared/models/routed-vault-filter.model"; import { WebCipherFormGenerationService } from "../../services/web-cipher-form-generation.service"; import { WebVaultPremiumUpgradePromptService } from "../../services/web-premium-upgrade-prompt.service"; import { WebViewPasswordHistoryService } from "../../services/web-view-password-history.service"; @@ -82,6 +84,11 @@ export interface VaultItemDialogParams { * If true, the dialog is being opened from the admin console. */ isAdminConsoleAction?: boolean; + + /** + * Function to restore a cipher from the trash. + */ + restore: (c: CipherView) => Promise; } export enum VaultItemDialogResult { @@ -99,6 +106,11 @@ export enum VaultItemDialogResult { * The dialog was closed to navigate the user the premium upgrade page. */ PremiumUpgrade = "premiumUpgrade", + + /** + * A cipher was restored + */ + Restored = "restored", } @Component({ @@ -121,6 +133,7 @@ export enum VaultItemDialogResult { { provide: PremiumUpgradePromptService, useClass: WebVaultPremiumUpgradePromptService }, { provide: ViewPasswordHistoryService, useClass: WebViewPasswordHistoryService }, { provide: CipherFormGenerationService, useClass: WebCipherFormGenerationService }, + RoutedVaultFilterService, ], }) export class VaultItemDialogComponent implements OnInit, OnDestroy { @@ -191,6 +204,20 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { ), ); + /** + * Determines if the user may restore the item. + * A user may restore items if they have delete permissions and the item is in the trash. + */ + protected async canUserRestore() { + return ( + this.filter?.type === "trash" && + this.cipher?.isDeleted && + (await firstValueFrom(this.canDeleteCipher$)) + ); + } + + protected showRestore: boolean; + protected get loadingForm() { return this.loadForm && !this.formReady; } @@ -230,6 +257,8 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { protected canDeleteCipher$: Observable; + protected filter: RoutedVaultFilterModel; + constructor( @Inject(DIALOG_DATA) protected params: VaultItemDialogParams, private dialogRef: DialogRef, @@ -246,6 +275,7 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { private cipherAuthorizationService: CipherAuthorizationService, private apiService: ApiService, private eventCollectionService: EventCollectionService, + private routedVaultFilterService: RoutedVaultFilterService, ) { this.updateTitle(); } @@ -283,6 +313,9 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { ); } + this.filter = await firstValueFrom(this.routedVaultFilterService.filter$); + + this.showRestore = await this.canUserRestore(); this.performingInitialLoad = false; } @@ -336,6 +369,11 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { this._formReadySubject.next(); } + restore = async () => { + await this.params.restore(this.cipher); + this.dialogRef.close(VaultItemDialogResult.Restored); + }; + delete = async () => { if (!this.cipher) { return; diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index 8c1d08b269c..46c678fd987 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -717,6 +717,7 @@ export class VaultComponent implements OnInit, OnDestroy { mode, formConfig, activeCollectionId, + restore: this.restore, }); const result = await lastValueFrom(this.vaultItemDialogRef.closed); diff --git a/apps/web/src/app/vault/org-vault/vault.component.ts b/apps/web/src/app/vault/org-vault/vault.component.ts index 14550968ba5..779266d830f 100644 --- a/apps/web/src/app/vault/org-vault/vault.component.ts +++ b/apps/web/src/app/vault/org-vault/vault.component.ts @@ -994,6 +994,7 @@ export class VaultComponent implements OnInit, OnDestroy { disableForm, activeCollectionId, isAdminConsoleAction: true, + restore: this.restore, }); const result = await lastValueFrom(this.vaultItemDialogRef.closed); @@ -1033,7 +1034,7 @@ export class VaultComponent implements OnInit, OnDestroy { }); } - async restore(c: CipherView): Promise { + restore = async (c: CipherView): Promise => { if (!c.isDeleted) { return; } @@ -1064,7 +1065,7 @@ export class VaultComponent implements OnInit, OnDestroy { } catch (e) { this.logService.error(e); } - } + }; async bulkRestore(ciphers: CipherView[]) { if ( From ce2ec07f74f251f01fb39f330284b6cf8e716148 Mon Sep 17 00:00:00 2001 From: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com> Date: Fri, 17 Jan 2025 18:32:29 +0100 Subject: [PATCH 13/17] [PM-17138][Defect] Submitting blank payment method is displaying unreadable validation message for Bank Account and Account Credit (#12937) * Changes to display descriptive message for bank account * resolve message for invalid message display * Add the paymentMethodType credit --------- Co-authored-by: Conner Turnbull <133619638+cturnbull-bitwarden@users.noreply.github.com> --- .../organization-plans.component.ts | 1 + .../shared/payment/payment-v2.component.ts | 32 +++++++++++++------ .../manage-tax-information.component.ts | 4 +++ 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/web/src/app/billing/organizations/organization-plans.component.ts b/apps/web/src/app/billing/organizations/organization-plans.component.ts index edc29b16049..94e8637e8a3 100644 --- a/apps/web/src/app/billing/organizations/organization-plans.component.ts +++ b/apps/web/src/app/billing/organizations/organization-plans.component.ts @@ -605,6 +605,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { submit = async () => { if (this.taxComponent && !this.taxComponent.validate()) { + this.taxComponent.markAllAsTouched(); return; } diff --git a/apps/web/src/app/billing/shared/payment/payment-v2.component.ts b/apps/web/src/app/billing/shared/payment/payment-v2.component.ts index 10cf7ccb702..f65a5743c35 100644 --- a/apps/web/src/app/billing/shared/payment/payment-v2.component.ts +++ b/apps/web/src/app/billing/shared/payment/payment-v2.component.ts @@ -113,16 +113,21 @@ export class PaymentV2Component implements OnInit, OnDestroy { const clientSecret = await this.billingApiService.createSetupIntent(type); if (this.usingBankAccount) { - const token = await this.stripeService.setupBankAccountPaymentMethod(clientSecret, { - accountHolderName: this.formGroup.value.bankInformation.accountHolderName, - routingNumber: this.formGroup.value.bankInformation.routingNumber, - accountNumber: this.formGroup.value.bankInformation.accountNumber, - accountHolderType: this.formGroup.value.bankInformation.accountHolderType, - }); - return { - type, - token, - }; + this.formGroup.markAllAsTouched(); + if (this.formGroup.valid) { + const token = await this.stripeService.setupBankAccountPaymentMethod(clientSecret, { + accountHolderName: this.formGroup.value.bankInformation.accountHolderName, + routingNumber: this.formGroup.value.bankInformation.routingNumber, + accountNumber: this.formGroup.value.bankInformation.accountNumber, + accountHolderType: this.formGroup.value.bankInformation.accountHolderType, + }); + return { + type, + token, + }; + } else { + throw "Invalid input provided, Please ensure all required fields are filled out correctly and try again."; + } } if (this.usingCard) { @@ -142,6 +147,13 @@ export class PaymentV2Component implements OnInit, OnDestroy { }; } + if (this.usingAccountCredit) { + return { + type: PaymentMethodType.Credit, + token: null, + }; + } + return null; } diff --git a/libs/angular/src/billing/components/manage-tax-information/manage-tax-information.component.ts b/libs/angular/src/billing/components/manage-tax-information/manage-tax-information.component.ts index 13a6d2d0cc3..885afb1ae67 100644 --- a/libs/angular/src/billing/components/manage-tax-information/manage-tax-information.component.ts +++ b/libs/angular/src/billing/components/manage-tax-information/manage-tax-information.component.ts @@ -72,6 +72,10 @@ export class ManageTaxInformationComponent implements OnInit, OnDestroy { } } + markAllAsTouched() { + this.formGroup.markAllAsTouched(); + } + async ngOnInit() { if (this.startWith) { this.formGroup.controls.country.setValue(this.startWith.country); From 8674fb51dba8713a551e7d9a31ecb25f11fd9076 Mon Sep 17 00:00:00 2001 From: Vijay Oommen Date: Fri, 17 Jan 2025 16:05:37 -0600 Subject: [PATCH 14/17] PM-17065 Display critical apps (#12867) --- .../all-applications.component.ts | 15 +++- .../app-at-risk-members-dialog.component.html | 4 +- .../application-table.mock.ts | 56 ------------ .../critical-applications.component.html | 38 ++++---- .../critical-applications.component.ts | 87 +++++++++++++++---- 5 files changed, 101 insertions(+), 99 deletions(-) delete mode 100644 bitwarden_license/bit-web/src/app/tools/access-intelligence/application-table.mock.ts diff --git a/bitwarden_license/bit-web/src/app/tools/access-intelligence/all-applications.component.ts b/bitwarden_license/bit-web/src/app/tools/access-intelligence/all-applications.component.ts index b22b94599f9..627495a6bde 100644 --- a/bitwarden_license/bit-web/src/app/tools/access-intelligence/all-applications.component.ts +++ b/bitwarden_license/bit-web/src/app/tools/access-intelligence/all-applications.component.ts @@ -57,10 +57,15 @@ export class AllApplicationsComponent implements OnInit { protected selectedUrls: Set = new Set(); protected searchControl = new FormControl("", { nonNullable: true }); protected loading = true; - protected organization = {} as Organization; + protected organization = new Organization(); noItemsIcon = Icons.Security; protected markingAsCritical = false; - protected applicationSummary = {} as ApplicationHealthReportSummary; + protected applicationSummary: ApplicationHealthReportSummary = { + totalMemberCount: 0, + totalAtRiskMemberCount: 0, + totalApplicationCount: 0, + totalAtRiskApplicationCount: 0, + }; destroyRef = inject(DestroyRef); isLoading$: Observable = of(false); @@ -90,8 +95,10 @@ export class AllApplicationsComponent implements OnInit { }), ) .subscribe(({ data, organization }) => { - this.dataSource.data = data ?? []; - this.applicationSummary = this.reportService.generateApplicationsSummary(data ?? []); + if (data) { + this.dataSource.data = data; + this.applicationSummary = this.reportService.generateApplicationsSummary(data); + } if (organization) { this.organization = organization; } diff --git a/bitwarden_license/bit-web/src/app/tools/access-intelligence/app-at-risk-members-dialog.component.html b/bitwarden_license/bit-web/src/app/tools/access-intelligence/app-at-risk-members-dialog.component.html index 383a1eccabe..fa58678be00 100644 --- a/bitwarden_license/bit-web/src/app/tools/access-intelligence/app-at-risk-members-dialog.component.html +++ b/bitwarden_license/bit-web/src/app/tools/access-intelligence/app-at-risk-members-dialog.component.html @@ -3,9 +3,7 @@
{{ "atRiskMembersWithCount" | i18n: members.length }} - {{ - "atRiskMembersDescriptionWithApp" | i18n: applicationName - }} + {{ "atRiskMembersDescriptionWithApp" | i18n: applicationName }}
{{ member.email }}
diff --git a/bitwarden_license/bit-web/src/app/tools/access-intelligence/application-table.mock.ts b/bitwarden_license/bit-web/src/app/tools/access-intelligence/application-table.mock.ts deleted file mode 100644 index 4dffa60b562..00000000000 --- a/bitwarden_license/bit-web/src/app/tools/access-intelligence/application-table.mock.ts +++ /dev/null @@ -1,56 +0,0 @@ -export const applicationTableMockData = [ - { - id: 1, - name: "google.com", - atRiskPasswords: 4, - totalPasswords: 10, - atRiskMembers: 2, - totalMembers: 5, - isMarkedAsCritical: false, - }, - { - id: 2, - name: "facebook.com", - atRiskPasswords: 3, - totalPasswords: 8, - atRiskMembers: 1, - totalMembers: 3, - isMarkedAsCritical: false, - }, - { - id: 3, - name: "twitter.com", - atRiskPasswords: 2, - totalPasswords: 6, - atRiskMembers: 0, - totalMembers: 2, - isMarkedAsCritical: false, - }, - { - id: 4, - name: "linkedin.com", - atRiskPasswords: 1, - totalPasswords: 4, - atRiskMembers: 0, - totalMembers: 1, - isMarkedAsCritical: false, - }, - { - id: 5, - name: "instagram.com", - atRiskPasswords: 0, - totalPasswords: 2, - atRiskMembers: 0, - totalMembers: 0, - isMarkedAsCritical: false, - }, - { - id: 6, - name: "tiktok.com", - atRiskPasswords: 0, - totalPasswords: 1, - atRiskMembers: 0, - totalMembers: 0, - isMarkedAsCritical: false, - }, -]; diff --git a/bitwarden_license/bit-web/src/app/tools/access-intelligence/critical-applications.component.html b/bitwarden_license/bit-web/src/app/tools/access-intelligence/critical-applications.component.html index 1c503f3d786..87b21c7c755 100644 --- a/bitwarden_license/bit-web/src/app/tools/access-intelligence/critical-applications.component.html +++ b/bitwarden_license/bit-web/src/app/tools/access-intelligence/critical-applications.component.html @@ -35,17 +35,19 @@
@@ -60,38 +62,38 @@ - {{ "application" | i18n }} - {{ "atRiskPasswords" | i18n }} - {{ "totalPasswords" | i18n }} - {{ "atRiskMembers" | i18n }} - {{ "totalMembers" | i18n }} + {{ "application" | i18n }} + {{ "atRiskPasswords" | i18n }} + {{ "totalPasswords" | i18n }} + {{ "atRiskMembers" | i18n }} + {{ "totalMembers" | i18n }} - + - + - - {{ r.name }} + + {{ r.applicationName }} - {{ r.atRiskPasswords }} + {{ r.atRiskPasswordCount }} - {{ r.totalPasswords }} + {{ r.passwordCount }} - {{ r.atRiskMembers }} + {{ r.atRiskMemberCount }} - {{ r.totalMembers }} + {{ r.memberCount }} diff --git a/bitwarden_license/bit-web/src/app/tools/access-intelligence/critical-applications.component.ts b/bitwarden_license/bit-web/src/app/tools/access-intelligence/critical-applications.component.ts index 99f68aa9c72..450f0d5d660 100644 --- a/bitwarden_license/bit-web/src/app/tools/access-intelligence/critical-applications.component.ts +++ b/bitwarden_license/bit-web/src/app/tools/access-intelligence/critical-applications.component.ts @@ -4,16 +4,32 @@ import { Component, DestroyRef, inject, OnInit } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { FormControl } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; -import { debounceTime, map } from "rxjs"; +import { combineLatest, debounceTime, map } from "rxjs"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { SearchModule, TableDataSource, NoItemsModule, Icons } from "@bitwarden/components"; +import { + CriticalAppsService, + RiskInsightsDataService, + RiskInsightsReportService, +} from "@bitwarden/bit-common/tools/reports/risk-insights"; +import { + ApplicationHealthReportDetailWithCriticalFlag, + ApplicationHealthReportSummary, +} from "@bitwarden/bit-common/tools/reports/risk-insights/models/password-health"; +import { + DialogService, + Icons, + NoItemsModule, + SearchModule, + TableDataSource, +} from "@bitwarden/components"; import { CardComponent } from "@bitwarden/tools-card"; import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module"; import { SharedModule } from "@bitwarden/web-vault/app/shared"; import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pipes/pipes.module"; -import { applicationTableMockData } from "./application-table.mock"; +import { openAppAtRiskMembersDialog } from "./app-at-risk-members-dialog.component"; +import { OrgAtRiskAppsDialogComponent } from "./org-at-risk-apps-dialog.component"; +import { OrgAtRiskMembersDialogComponent } from "./org-at-risk-members-dialog.component"; import { RiskInsightsTabType } from "./risk-insights.component"; @Component({ @@ -23,30 +39,38 @@ import { RiskInsightsTabType } from "./risk-insights.component"; imports: [CardComponent, HeaderModule, SearchModule, NoItemsModule, PipesModule, SharedModule], }) export class CriticalApplicationsComponent implements OnInit { - protected dataSource = new TableDataSource(); + protected dataSource = new TableDataSource(); protected selectedIds: Set = new Set(); protected searchControl = new FormControl("", { nonNullable: true }); private destroyRef = inject(DestroyRef); protected loading = false; protected organizationId: string; + protected applicationSummary = {} as ApplicationHealthReportSummary; noItemsIcon = Icons.Security; - // MOCK DATA - protected mockData = applicationTableMockData; - protected mockAtRiskMembersCount = 0; - protected mockAtRiskAppsCount = 0; - protected mockTotalMembersCount = 0; - protected mockTotalAppsCount = 0; ngOnInit() { - this.activatedRoute.paramMap + this.organizationId = this.activatedRoute.snapshot.paramMap.get("organizationId") ?? ""; + combineLatest([ + this.dataService.applications$, + this.criticalAppsService.getAppsListForOrg(this.organizationId), + ]) .pipe( takeUntilDestroyed(this.destroyRef), - map(async (params) => { - this.organizationId = params.get("organizationId"); - // TODO: use organizationId to fetch data + map(([applications, criticalApps]) => { + const criticalUrls = criticalApps.map((ca) => ca.uri); + const data = applications?.map((app) => ({ + ...app, + isMarkedAsCritical: criticalUrls.includes(app.applicationName), + })) as ApplicationHealthReportDetailWithCriticalFlag[]; + return data?.filter((app) => app.isMarkedAsCritical); }), ) - .subscribe(); + .subscribe((applications) => { + if (applications) { + this.dataSource.data = applications; + this.applicationSummary = this.reportService.generateApplicationsSummary(applications); + } + }); } goToAllAppsTab = async () => { @@ -57,13 +81,40 @@ export class CriticalApplicationsComponent implements OnInit { }; constructor( - protected i18nService: I18nService, protected activatedRoute: ActivatedRoute, protected router: Router, + protected dataService: RiskInsightsDataService, + protected criticalAppsService: CriticalAppsService, + protected reportService: RiskInsightsReportService, + protected dialogService: DialogService, ) { - this.dataSource.data = []; //applicationTableMockData; this.searchControl.valueChanges .pipe(debounceTime(200), takeUntilDestroyed()) .subscribe((v) => (this.dataSource.filter = v)); } + + showAppAtRiskMembers = async (applicationName: string) => { + openAppAtRiskMembersDialog(this.dialogService, { + members: + this.dataSource.data.find((app) => app.applicationName === applicationName) + ?.atRiskMemberDetails ?? [], + applicationName, + }); + }; + + showOrgAtRiskMembers = async () => { + this.dialogService.open(OrgAtRiskMembersDialogComponent, { + data: this.reportService.generateAtRiskMemberList(this.dataSource.data), + }); + }; + + showOrgAtRiskApps = async () => { + this.dialogService.open(OrgAtRiskAppsDialogComponent, { + data: this.reportService.generateAtRiskApplicationList(this.dataSource.data), + }); + }; + + trackByFunction(_: number, item: ApplicationHealthReportDetailWithCriticalFlag) { + return item.applicationName; + } } From a803e5b411e7179783c0c0020ffa2edc66d18038 Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:01:18 -0800 Subject: [PATCH 15/17] [PM-6565] migrate vault toasts to CL toastService (#10664) * migrate vault toasts to CL toastService * update component args * add missing toastService deps * add missing i18 key * remove moved files * remove duplicate args --- .../popup/settings/premium-v2.component.ts | 3 + .../vault/app/accounts/premium.component.ts | 4 +- .../app/vault/folder-add-edit.component.ts | 4 +- .../app/vault/password-history.component.ts | 4 +- .../filters/organization-filter.component.ts | 12 +-- .../src/vault/app/vault/vault.component.ts | 13 ++-- .../src/vault/app/vault/view.component.ts | 4 +- .../collection-dialog.component.ts | 46 ++++++----- .../individual-vault/add-edit.component.ts | 10 +-- .../bulk-delete-dialog.component.ts | 43 ++++++----- .../bulk-move-dialog.component.ts | 9 ++- .../bulk-share-dialog.component.ts | 15 ++-- .../folder-add-edit.component.ts | 11 +-- .../organization-options.component.ts | 22 ++++-- .../components/vault-filter.component.ts | 13 ++-- .../bulk-collections-dialog.component.ts | 9 ++- .../vault-filter/vault-filter.component.ts | 4 +- .../vault/settings/purge-vault.component.ts | 9 ++- apps/web/src/locales/en/messages.json | 3 + .../vault/components/add-edit.component.ts | 74 ++++++++++-------- .../vault/components/attachments.component.ts | 76 ++++++++++++------- .../components/folder-add-edit.component.ts | 29 ++++--- .../components/password-history.component.ts | 12 +-- .../src/vault/components/premium.component.ts | 9 ++- .../src/vault/components/view.component.ts | 69 +++++++++++------ .../components/password-reprompt.component.ts | 12 +-- 26 files changed, 317 insertions(+), 202 deletions(-) diff --git a/apps/browser/src/billing/popup/settings/premium-v2.component.ts b/apps/browser/src/billing/popup/settings/premium-v2.component.ts index f658f71a209..da3d2c07e4b 100644 --- a/apps/browser/src/billing/popup/settings/premium-v2.component.ts +++ b/apps/browser/src/billing/popup/settings/premium-v2.component.ts @@ -20,6 +20,7 @@ import { DialogService, ItemModule, SectionComponent, + ToastService, } from "@bitwarden/components"; import { PopOutComponent } from "../../../platform/popup/components/pop-out.component"; @@ -57,6 +58,7 @@ export class PremiumV2Component extends BasePremiumComponent { dialogService: DialogService, environmentService: EnvironmentService, billingAccountProfileStateService: BillingAccountProfileStateService, + toastService: ToastService, accountService: AccountService, ) { super( @@ -68,6 +70,7 @@ export class PremiumV2Component extends BasePremiumComponent { dialogService, environmentService, billingAccountProfileStateService, + toastService, accountService, ); diff --git a/apps/desktop/src/vault/app/accounts/premium.component.ts b/apps/desktop/src/vault/app/accounts/premium.component.ts index 4b547384545..bfdaf084648 100644 --- a/apps/desktop/src/vault/app/accounts/premium.component.ts +++ b/apps/desktop/src/vault/app/accounts/premium.component.ts @@ -9,7 +9,7 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; @Component({ selector: "app-premium", @@ -25,6 +25,7 @@ export class PremiumComponent extends BasePremiumComponent { dialogService: DialogService, environmentService: EnvironmentService, billingAccountProfileStateService: BillingAccountProfileStateService, + toastService: ToastService, accountService: AccountService, ) { super( @@ -36,6 +37,7 @@ export class PremiumComponent extends BasePremiumComponent { dialogService, environmentService, billingAccountProfileStateService, + toastService, accountService, ); } diff --git a/apps/desktop/src/vault/app/vault/folder-add-edit.component.ts b/apps/desktop/src/vault/app/vault/folder-add-edit.component.ts index 1cab5a940dd..cdb879693c0 100644 --- a/apps/desktop/src/vault/app/vault/folder-add-edit.component.ts +++ b/apps/desktop/src/vault/app/vault/folder-add-edit.component.ts @@ -8,7 +8,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; @Component({ @@ -26,6 +26,7 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent { logService: LogService, dialogService: DialogService, formBuilder: FormBuilder, + toastService: ToastService, ) { super( folderService, @@ -37,6 +38,7 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent { logService, dialogService, formBuilder, + toastService, ); } } diff --git a/apps/desktop/src/vault/app/vault/password-history.component.ts b/apps/desktop/src/vault/app/vault/password-history.component.ts index 12701ac5527..4a87617d8f4 100644 --- a/apps/desktop/src/vault/app/vault/password-history.component.ts +++ b/apps/desktop/src/vault/app/vault/password-history.component.ts @@ -5,6 +5,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { ToastService } from "@bitwarden/components"; @Component({ selector: "app-password-history", @@ -16,7 +17,8 @@ export class PasswordHistoryComponent extends BasePasswordHistoryComponent { platformUtilsService: PlatformUtilsService, i18nService: I18nService, accountService: AccountService, + toastService: ToastService, ) { - super(cipherService, platformUtilsService, i18nService, accountService, window); + super(cipherService, platformUtilsService, i18nService, accountService, window, toastService); } } diff --git a/apps/desktop/src/vault/app/vault/vault-filter/filters/organization-filter.component.ts b/apps/desktop/src/vault/app/vault/vault-filter/filters/organization-filter.component.ts index 92c75e30417..39f1c0200ea 100644 --- a/apps/desktop/src/vault/app/vault/vault-filter/filters/organization-filter.component.ts +++ b/apps/desktop/src/vault/app/vault/vault-filter/filters/organization-filter.component.ts @@ -7,6 +7,7 @@ import { DisplayMode } from "@bitwarden/angular/vault/vault-filter/models/displa import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { ToastService } from "@bitwarden/components"; @Component({ selector: "app-organization-filter", @@ -25,6 +26,7 @@ export class OrganizationFilterComponent extends BaseOrganizationFilterComponent constructor( private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, + private toastService: ToastService, ) { super(); } @@ -36,11 +38,11 @@ export class OrganizationFilterComponent extends BaseOrganizationFilterComponent // eslint-disable-next-line @typescript-eslint/no-floating-promises super.applyOrganizationFilter(organization); } else { - this.platformUtilsService.showToast( - "error", - null, - this.i18nService.t("disabledOrganizationFilterError"), - ); + this.toastService.showToast({ + variant: "error", + title: null, + message: this.i18nService.t("disabledOrganizationFilterError"), + }); } } } diff --git a/apps/desktop/src/vault/app/vault/vault.component.ts b/apps/desktop/src/vault/app/vault/vault.component.ts index c2260692fbd..da1f7bb3160 100644 --- a/apps/desktop/src/vault/app/vault/vault.component.ts +++ b/apps/desktop/src/vault/app/vault/vault.component.ts @@ -35,7 +35,7 @@ import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; import { DecryptionFailureDialogComponent, PasswordRepromptService } from "@bitwarden/vault"; import { SearchBarService } from "../../../app/layout/search/search-bar.service"; @@ -113,6 +113,7 @@ export class VaultComponent implements OnInit, OnDestroy { private apiService: ApiService, private dialogService: DialogService, private billingAccountProfileStateService: BillingAccountProfileStateService, + private toastService: ToastService, private configService: ConfigService, private accountService: AccountService, private cipherService: CipherService, @@ -809,11 +810,11 @@ export class VaultComponent implements OnInit, OnDestroy { } this.platformUtilsService.copyToClipboard(value); - this.platformUtilsService.showToast( - "info", - null, - this.i18nService.t("valueCopied", this.i18nService.t(labelI18nKey)), - ); + this.toastService.showToast({ + variant: "info", + title: null, + message: this.i18nService.t("valueCopied", this.i18nService.t(labelI18nKey)), + }); if (this.action === "view") { this.messagingService.send("minimizeOnCopy"); } diff --git a/apps/desktop/src/vault/app/vault/view.component.ts b/apps/desktop/src/vault/app/vault/view.component.ts index d3e8fff3495..ce9d3af8276 100644 --- a/apps/desktop/src/vault/app/vault/view.component.ts +++ b/apps/desktop/src/vault/app/vault/view.component.ts @@ -31,7 +31,7 @@ import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folde import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; import { DecryptionFailureDialogComponent, PasswordRepromptService } from "@bitwarden/vault"; @@ -68,6 +68,7 @@ export class ViewComponent extends BaseViewComponent implements OnInit, OnDestro datePipe: DatePipe, billingAccountProfileStateService: BillingAccountProfileStateService, accountService: AccountService, + toastService: ToastService, cipherAuthorizationService: CipherAuthorizationService, ) { super( @@ -94,6 +95,7 @@ export class ViewComponent extends BaseViewComponent implements OnInit, OnDestro datePipe, accountService, billingAccountProfileStateService, + toastService, cipherAuthorizationService, ); } diff --git a/apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.ts b/apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.ts index 42d033dc4c2..6141e983a68 100644 --- a/apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.ts +++ b/apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.ts @@ -29,7 +29,7 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { BitValidators, DialogService } from "@bitwarden/components"; +import { BitValidators, DialogService, ToastService } from "@bitwarden/components"; import { GroupApiService, GroupView } from "../../../admin-console/organizations/core"; import { PermissionMode } from "../../../admin-console/organizations/shared/components/access-selector/access-selector.component"; @@ -110,6 +110,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy { private organizationUserApiService: OrganizationUserApiService, private dialogService: DialogService, private changeDetectorRef: ChangeDetectorRef, + private toastService: ToastService, ) { this.tabIndex = params.initialTab ?? CollectionDialogTabType.Info; } @@ -274,17 +275,20 @@ export class CollectionDialogComponent implements OnInit, OnDestroy { const accessTabError = this.formGroup.controls.access.hasError("managePermissionRequired"); if (this.tabIndex === CollectionDialogTabType.Access && !accessTabError) { - this.platformUtilsService.showToast( - "error", - null, - this.i18nService.t("fieldOnTabRequiresAttention", this.i18nService.t("collectionInfo")), - ); + this.toastService.showToast({ + variant: "error", + title: null, + message: this.i18nService.t( + "fieldOnTabRequiresAttention", + this.i18nService.t("collectionInfo"), + ), + }); } else if (this.tabIndex === CollectionDialogTabType.Info && accessTabError) { - this.platformUtilsService.showToast( - "error", - null, - this.i18nService.t("fieldOnTabRequiresAttention", this.i18nService.t("access")), - ); + this.toastService.showToast({ + variant: "error", + title: null, + message: this.i18nService.t("fieldOnTabRequiresAttention", this.i18nService.t("access")), + }); } return; } @@ -309,14 +313,14 @@ export class CollectionDialogComponent implements OnInit, OnDestroy { const savedCollection = await this.collectionAdminService.save(collectionView); - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t( + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t( this.editMode ? "editedCollectionId" : "createdCollectionId", collectionView.name, ), - ); + }); this.close(CollectionDialogAction.Saved, savedCollection); }; @@ -339,11 +343,11 @@ export class CollectionDialogComponent implements OnInit, OnDestroy { await this.collectionAdminService.delete(this.params.organizationId, this.params.collectionId); - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("deletedCollectionId", this.collection?.name), - ); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("deletedCollectionId", this.collection?.name), + }); this.close(CollectionDialogAction.Deleted, this.collection); }; diff --git a/apps/web/src/app/vault/individual-vault/add-edit.component.ts b/apps/web/src/app/vault/individual-vault/add-edit.component.ts index 916c845e9d3..62ce55848f5 100644 --- a/apps/web/src/app/vault/individual-vault/add-edit.component.ts +++ b/apps/web/src/app/vault/individual-vault/add-edit.component.ts @@ -194,11 +194,11 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On } this.platformUtilsService.copyToClipboard(value, { window: window }); - this.platformUtilsService.showToast( - "info", - null, - this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)), - ); + this.toastService.showToast({ + variant: "info", + title: null, + message: this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)), + }); if (this.editMode) { if (typeI18nKey === "password") { diff --git a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.ts b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.ts index 913f106004d..becfcb8f588 100644 --- a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.ts +++ b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.ts @@ -10,7 +10,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherBulkDeleteRequest } from "@bitwarden/common/vault/models/request/cipher-bulk-delete.request"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; export interface BulkDeleteDialogParams { cipherIds?: string[]; @@ -60,6 +60,7 @@ export class BulkDeleteDialogComponent { private i18nService: I18nService, private apiService: ApiService, private collectionService: CollectionService, + private toastService: ToastService, ) { this.cipherIds = params.cipherIds ?? []; this.permanent = params.permanent; @@ -95,19 +96,19 @@ export class BulkDeleteDialogComponent { await Promise.all(deletePromises); if (this.cipherIds.length || this.unassignedCiphers.length) { - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t(this.permanent ? "permanentlyDeletedItems" : "deletedItems"), - ); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t(this.permanent ? "permanentlyDeletedItems" : "deletedItems"), + }); } if (this.collections.length) { await this.collectionService.delete(this.collections.map((c) => c.id)); - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("deletedCollections"), - ); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("deletedCollections"), + }); } this.close(BulkDeleteDialogResult.Deleted); }; @@ -134,11 +135,11 @@ export class BulkDeleteDialogComponent { // From org vault if (this.organization) { if (this.collections.some((c) => !c.canDelete(this.organization))) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("missingPermissions"), - ); + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("errorOccurred"), + message: this.i18nService.t("missingPermissions"), + }); return; } return await this.apiService.deleteManyCollections( @@ -151,11 +152,11 @@ export class BulkDeleteDialogComponent { for (const organization of this.organizations) { const orgCollections = this.collections.filter((o) => o.organizationId === organization.id); if (orgCollections.some((c) => !c.canDelete(organization))) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("missingPermissions"), - ); + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("errorOccurred"), + message: this.i18nService.t("missingPermissions"), + }); return; } const orgCollectionIds = orgCollections.map((c) => c.id); diff --git a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-move-dialog/bulk-move-dialog.component.ts b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-move-dialog/bulk-move-dialog.component.ts index b7f99fb7b44..295d3ccc435 100644 --- a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-move-dialog/bulk-move-dialog.component.ts +++ b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-move-dialog/bulk-move-dialog.component.ts @@ -11,7 +11,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; export interface BulkMoveDialogParams { cipherIds?: string[]; @@ -58,6 +58,7 @@ export class BulkMoveDialogComponent implements OnInit { private i18nService: I18nService, private folderService: FolderService, private formBuilder: FormBuilder, + private toastService: ToastService, private accountService: AccountService, ) { this.cipherIds = params.cipherIds ?? []; @@ -81,7 +82,11 @@ export class BulkMoveDialogComponent implements OnInit { } await this.cipherService.moveManyWithServer(this.cipherIds, this.formGroup.value.folderId); - this.platformUtilsService.showToast("success", null, this.i18nService.t("movedItems")); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("movedItems"), + }); this.close(BulkMoveDialogResult.Moved); }; diff --git a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-share-dialog/bulk-share-dialog.component.ts b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-share-dialog/bulk-share-dialog.component.ts index 62798c21bca..1dc15a7471a 100644 --- a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-share-dialog/bulk-share-dialog.component.ts +++ b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-share-dialog/bulk-share-dialog.component.ts @@ -10,11 +10,10 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { Checkable, isChecked } from "@bitwarden/common/types/checkable"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; export interface BulkShareDialogParams { ciphers: CipherView[]; @@ -59,12 +58,12 @@ export class BulkShareDialogComponent implements OnInit, OnDestroy { @Inject(DIALOG_DATA) params: BulkShareDialogParams, private dialogRef: DialogRef, private cipherService: CipherService, - private platformUtilsService: PlatformUtilsService, private i18nService: I18nService, private collectionService: CollectionService, private organizationService: OrganizationService, private logService: LogService, private accountService: AccountService, + private toastService: ToastService, ) { this.ciphers = params.ciphers ?? []; this.organizationId = params.organizationId; @@ -114,11 +113,11 @@ export class BulkShareDialogComponent implements OnInit, OnDestroy { const orgName = this.organizations.find((o) => o.id === this.organizationId)?.name ?? this.i18nService.t("organization"); - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("movedItemsToOrg", orgName), - ); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("movedItemsToOrg", orgName), + }); this.close(BulkShareDialogResult.Shared); } catch (e) { this.logService.error(e); diff --git a/apps/web/src/app/vault/individual-vault/folder-add-edit.component.ts b/apps/web/src/app/vault/individual-vault/folder-add-edit.component.ts index bc639ff2f61..272cfb130b9 100644 --- a/apps/web/src/app/vault/individual-vault/folder-add-edit.component.ts +++ b/apps/web/src/app/vault/individual-vault/folder-add-edit.component.ts @@ -45,6 +45,7 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent { logService, dialogService, formBuilder, + toastService, ); // FIXME: Remove when updating file. Eslint update // eslint-disable-next-line @typescript-eslint/no-unused-expressions @@ -89,11 +90,11 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent { const folder = await this.folderService.encrypt(this.folder, userKey); this.formPromise = this.folderApiService.save(folder, activeAccountId); await this.formPromise; - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t(this.editMode ? "editedFolder" : "addedFolder"), - ); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t(this.editMode ? "editedFolder" : "addedFolder"), + }); this.onSavedFolder.emit(this.folder); this.dialogRef.close(FolderAddEditDialogResult.Saved); } catch (e) { diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts b/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts index 6788471dd04..6255ee11c49 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts @@ -146,7 +146,11 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy { return this.syncService.fullSync(true); }); await this.actionPromise; - this.platformUtilsService.showToast("success", null, "Unlinked SSO"); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("unlinkedSso"), + }); } catch (e) { this.logService.error(e); } @@ -166,7 +170,11 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy { try { this.actionPromise = this.organizationApiService.leave(org.id); await this.actionPromise; - this.platformUtilsService.showToast("success", null, this.i18nService.t("leftOrganization")); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("leftOrganization"), + }); } catch (e) { this.logService.error(e); } @@ -199,11 +207,11 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy { ); try { await this.actionPromise; - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("withdrawPasswordResetSuccess"), - ); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("withdrawPasswordResetSuccess"), + }); await this.syncService.fullSync(true); } catch (e) { this.logService.error(e); diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts b/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts index f568ba159a6..f1241ef3280 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts @@ -13,7 +13,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; import { TrialFlowService } from "../../../../billing/services/trial-flow.service"; import { VaultFilterService } from "../services/abstractions/vault-filter.service"; @@ -98,6 +98,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy { protected policyService: PolicyService, protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService, + protected toastService: ToastService, protected billingApiService: BillingApiServiceAbstraction, protected dialogService: DialogService, protected configService: ConfigService, @@ -122,11 +123,11 @@ export class VaultFilterComponent implements OnInit, OnDestroy { applyOrganizationFilter = async (orgNode: TreeNode): Promise => { if (!orgNode?.node.enabled) { - this.platformUtilsService.showToast( - "error", - null, - this.i18nService.t("disabledOrganizationFilterError"), - ); + this.toastService.showToast({ + variant: "error", + title: null, + message: this.i18nService.t("disabledOrganizationFilterError"), + }); const metadata = await this.billingApiService.getOrganizationBillingMetadata(orgNode.node.id); await this.trialFlowService.handleUnpaidSubscriptionDialog(orgNode.node, metadata); } diff --git a/apps/web/src/app/vault/org-vault/bulk-collections-dialog/bulk-collections-dialog.component.ts b/apps/web/src/app/vault/org-vault/bulk-collections-dialog/bulk-collections-dialog.component.ts index 0fc7b6a31aa..d9ba8af49fa 100644 --- a/apps/web/src/app/vault/org-vault/bulk-collections-dialog/bulk-collections-dialog.component.ts +++ b/apps/web/src/app/vault/org-vault/bulk-collections-dialog/bulk-collections-dialog.component.ts @@ -14,7 +14,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; import { GroupApiService, GroupView } from "../../../admin-console/organizations/core"; import { @@ -68,6 +68,7 @@ export class BulkCollectionsDialogComponent implements OnDestroy { private platformUtilsService: PlatformUtilsService, private i18nService: I18nService, private collectionAdminService: CollectionAdminService, + private toastService: ToastService, ) { this.numCollections = this.params.collections.length; const organization$ = this.organizationService.get$(this.params.organizationId); @@ -119,7 +120,11 @@ export class BulkCollectionsDialogComponent implements OnDestroy { groups, ); - this.platformUtilsService.showToast("success", null, this.i18nService.t("editedCollections")); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("editedCollections"), + }); this.dialogRef.close(BulkCollectionsDialogResult.Saved); }; diff --git a/apps/web/src/app/vault/org-vault/vault-filter/vault-filter.component.ts b/apps/web/src/app/vault/org-vault/vault-filter/vault-filter.component.ts index 0a8a6c9da94..7e08af7c7f7 100644 --- a/apps/web/src/app/vault/org-vault/vault-filter/vault-filter.component.ts +++ b/apps/web/src/app/vault/org-vault/vault-filter/vault-filter.component.ts @@ -10,7 +10,7 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; import { VaultFilterComponent as BaseVaultFilterComponent } from "../../individual-vault/vault-filter/components/vault-filter.component"; //../../vault/vault-filter/components/vault-filter.component"; import { VaultFilterService } from "../../individual-vault/vault-filter/services/abstractions/vault-filter.service"; @@ -43,6 +43,7 @@ export class VaultFilterComponent protected policyService: PolicyService, protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService, + protected toastService: ToastService, protected billingApiService: BillingApiServiceAbstraction, protected dialogService: DialogService, protected configService: ConfigService, @@ -52,6 +53,7 @@ export class VaultFilterComponent policyService, i18nService, platformUtilsService, + toastService, billingApiService, dialogService, configService, diff --git a/apps/web/src/app/vault/settings/purge-vault.component.ts b/apps/web/src/app/vault/settings/purge-vault.component.ts index 80b0448a39c..83955c0dc94 100644 --- a/apps/web/src/app/vault/settings/purge-vault.component.ts +++ b/apps/web/src/app/vault/settings/purge-vault.component.ts @@ -11,7 +11,7 @@ import { Verification } from "@bitwarden/common/auth/types/verification"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { SyncService } from "@bitwarden/common/platform/sync"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; export interface PurgeVaultDialogData { organizationId: string; @@ -37,6 +37,7 @@ export class PurgeVaultComponent { private userVerificationService: UserVerificationService, private router: Router, private syncService: SyncService, + private toastService: ToastService, ) { this.organizationId = data && data.organizationId ? data.organizationId : null; } @@ -46,7 +47,11 @@ export class PurgeVaultComponent { .buildRequest(this.formGroup.value.masterPassword) .then((request) => this.apiService.postPurgeCiphers(request, this.organizationId)); await response; - this.platformUtilsService.showToast("success", null, this.i18nService.t("vaultPurged")); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("vaultPurged"), + }); await this.syncService.fullSync(true); if (this.organizationId != null) { await this.router.navigate(["organizations", this.organizationId, "vault"]); diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 15c5a7fcf6c..95378c90c97 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -3789,6 +3789,9 @@ } } }, + "unlinkedSso": { + "message": "Unlinked SSO." + }, "unlinkedSsoUser": { "message": "Unlinked SSO for user $ID$.", "placeholders": { diff --git a/libs/angular/src/vault/components/add-edit.component.ts b/libs/angular/src/vault/components/add-edit.component.ts index bf2e68b71cd..b86d48d3911 100644 --- a/libs/angular/src/vault/components/add-edit.component.ts +++ b/libs/angular/src/vault/components/add-edit.component.ts @@ -372,11 +372,11 @@ export class AddEditComponent implements OnInit, OnDestroy { } if (this.cipher.name == null || this.cipher.name === "") { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("nameRequired"), - ); + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("errorOccurred"), + message: this.i18nService.t("nameRequired"), + }); return false; } @@ -385,11 +385,11 @@ export class AddEditComponent implements OnInit, OnDestroy { !this.allowPersonal && this.cipher.organizationId == null ) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("personalOwnershipSubmitError"), - ); + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("errorOccurred"), + message: this.i18nService.t("personalOwnershipSubmitError"), + }); return false; } @@ -424,11 +424,11 @@ export class AddEditComponent implements OnInit, OnDestroy { this.formPromise = this.saveCipher(cipher); await this.formPromise; this.cipher.id = cipher.id; - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t(this.editMode && !this.cloneMode ? "editedItem" : "addedItem"), - ); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t(this.editMode && !this.cloneMode ? "editedItem" : "addedItem"), + }); this.onSavedCipher.emit(this.cipher); this.messagingService.send(this.editMode && !this.cloneMode ? "editedCipher" : "addedCipher"); return true; @@ -514,11 +514,13 @@ export class AddEditComponent implements OnInit, OnDestroy { try { this.deletePromise = this.deleteCipher(); await this.deletePromise; - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t(this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem"), - ); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t( + this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem", + ), + }); this.onDeletedCipher.emit(this.cipher); this.messagingService.send( this.cipher.isDeleted ? "permanentlyDeletedCipher" : "deletedCipher", @@ -538,7 +540,11 @@ export class AddEditComponent implements OnInit, OnDestroy { try { this.restorePromise = this.restoreCipher(); await this.restorePromise; - this.platformUtilsService.showToast("success", null, this.i18nService.t("restoredItem")); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("restoredItem"), + }); this.onRestoredCipher.emit(this.cipher); this.messagingService.send("restoredCipher"); } catch (e) { @@ -679,13 +685,17 @@ export class AddEditComponent implements OnInit, OnDestroy { this.checkPasswordPromise = null; if (matches > 0) { - this.platformUtilsService.showToast( - "warning", - null, - this.i18nService.t("passwordExposed", matches.toString()), - ); + this.toastService.showToast({ + variant: "warning", + title: null, + message: this.i18nService.t("passwordExposed", matches.toString()), + }); } else { - this.platformUtilsService.showToast("success", null, this.i18nService.t("passwordSafe")); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("passwordSafe"), + }); } } @@ -779,11 +789,11 @@ export class AddEditComponent implements OnInit, OnDestroy { const copyOptions = this.win != null ? { window: this.win } : null; this.platformUtilsService.copyToClipboard(value, copyOptions); - this.platformUtilsService.showToast( - "info", - null, - this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)), - ); + this.toastService.showToast({ + variant: "info", + title: null, + message: this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)), + }); if (typeI18nKey === "password") { void this.eventCollectionService.collectMany(EventType.Cipher_ClientCopiedPassword, [ diff --git a/libs/angular/src/vault/components/attachments.component.ts b/libs/angular/src/vault/components/attachments.component.ts index 1a4c428aae2..a3b635f151d 100644 --- a/libs/angular/src/vault/components/attachments.component.ts +++ b/libs/angular/src/vault/components/attachments.component.ts @@ -64,21 +64,21 @@ export class AttachmentsComponent implements OnInit { const fileEl = document.getElementById("file") as HTMLInputElement; const files = fileEl.files; if (files == null || files.length === 0) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("selectFile"), - ); + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("errorOccurred"), + message: this.i18nService.t("selectFile"), + }); return; } if (files[0].size > 524288000) { // 500 MB - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("maxFileSize"), - ); + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("errorOccurred"), + message: this.i18nService.t("maxFileSize"), + }); return; } @@ -91,7 +91,11 @@ export class AttachmentsComponent implements OnInit { this.cipher = await this.cipherDomain.decrypt( await this.cipherService.getKeyForCipherKeyDecryption(this.cipherDomain, activeUserId), ); - this.platformUtilsService.showToast("success", null, this.i18nService.t("attachmentSaved")); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("attachmentSaved"), + }); this.onUploadedAttachment.emit(); } catch (e) { this.logService.error(e); @@ -122,7 +126,11 @@ export class AttachmentsComponent implements OnInit { try { this.deletePromises[attachment.id] = this.deleteCipherAttachment(attachment.id); await this.deletePromises[attachment.id]; - this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedAttachment")); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("deletedAttachment"), + }); const i = this.cipher.attachments.indexOf(attachment); if (i > -1) { this.cipher.attachments.splice(i, 1); @@ -142,11 +150,11 @@ export class AttachmentsComponent implements OnInit { } if (!this.canAccessAttachments) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("premiumRequired"), - this.i18nService.t("premiumRequiredDesc"), - ); + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("premiumRequired"), + message: this.i18nService.t("premiumRequiredDesc"), + }); return; } @@ -171,7 +179,11 @@ export class AttachmentsComponent implements OnInit { a.downloading = true; const response = await fetch(new Request(url, { cache: "no-store" })); if (response.status !== 200) { - this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred")); + this.toastService.showToast({ + variant: "error", + title: null, + message: this.i18nService.t("errorOccurred"), + }); a.downloading = false; return; } @@ -195,7 +207,11 @@ export class AttachmentsComponent implements OnInit { // FIXME: Remove when updating file. Eslint update // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (e) { - this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred")); + this.toastService.showToast({ + variant: "error", + title: null, + message: this.i18nService.t("errorOccurred"), + }); } a.downloading = false; @@ -243,7 +259,11 @@ export class AttachmentsComponent implements OnInit { a.downloading = true; const response = await fetch(new Request(attachment.url, { cache: "no-store" })); if (response.status !== 200) { - this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred")); + this.toastService.showToast({ + variant: "error", + title: null, + message: this.i18nService.t("errorOccurred"), + }); a.downloading = false; return; } @@ -281,16 +301,20 @@ export class AttachmentsComponent implements OnInit { } } - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("attachmentSaved"), - ); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("attachmentSaved"), + }); this.onReuploadedAttachment.emit(); // FIXME: Remove when updating file. Eslint update // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (e) { - this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred")); + this.toastService.showToast({ + variant: "error", + title: null, + message: this.i18nService.t("errorOccurred"), + }); } a.downloading = false; diff --git a/libs/angular/src/vault/components/folder-add-edit.component.ts b/libs/angular/src/vault/components/folder-add-edit.component.ts index 205733ba48d..28ed0dc2aed 100644 --- a/libs/angular/src/vault/components/folder-add-edit.component.ts +++ b/libs/angular/src/vault/components/folder-add-edit.component.ts @@ -11,7 +11,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; @Directive() @@ -43,6 +43,7 @@ export class FolderAddEditComponent implements OnInit { protected logService: LogService, protected dialogService: DialogService, protected formBuilder: FormBuilder, + protected toastService: ToastService, ) {} async ngOnInit() { @@ -52,11 +53,11 @@ export class FolderAddEditComponent implements OnInit { async submit(): Promise { this.folder.name = this.formGroup.controls.name.value; if (this.folder.name == null || this.folder.name === "") { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("nameRequired"), - ); + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("errorOccurred"), + message: this.i18nService.t("nameRequired"), + }); return false; } @@ -66,11 +67,11 @@ export class FolderAddEditComponent implements OnInit { const folder = await this.folderService.encrypt(this.folder, userKey); this.formPromise = this.folderApiService.save(folder, activeUserId); await this.formPromise; - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t(this.editMode ? "editedFolder" : "addedFolder"), - ); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t(this.editMode ? "editedFolder" : "addedFolder"), + }); this.onSavedFolder.emit(this.folder); return true; } catch (e) { @@ -95,7 +96,11 @@ export class FolderAddEditComponent implements OnInit { const activeUserId = await firstValueFrom(this.activeUserId$); this.deletePromise = this.folderApiService.delete(this.folder.id, activeUserId); await this.deletePromise; - this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedFolder")); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("deletedFolder"), + }); this.onDeletedFolder.emit(this.folder); } catch (e) { this.logService.error(e); diff --git a/libs/angular/src/vault/components/password-history.component.ts b/libs/angular/src/vault/components/password-history.component.ts index 942a34c58bb..0b385688d0b 100644 --- a/libs/angular/src/vault/components/password-history.component.ts +++ b/libs/angular/src/vault/components/password-history.component.ts @@ -8,6 +8,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { PasswordHistoryView } from "@bitwarden/common/vault/models/view/password-history.view"; +import { ToastService } from "@bitwarden/components"; @Directive() export class PasswordHistoryComponent implements OnInit { @@ -20,6 +21,7 @@ export class PasswordHistoryComponent implements OnInit { protected i18nService: I18nService, protected accountService: AccountService, private win: Window, + private toastService: ToastService, ) {} async ngOnInit() { @@ -29,11 +31,11 @@ export class PasswordHistoryComponent implements OnInit { copy(password: string) { const copyOptions = this.win != null ? { window: this.win } : null; this.platformUtilsService.copyToClipboard(password, copyOptions); - this.platformUtilsService.showToast( - "info", - null, - this.i18nService.t("valueCopied", this.i18nService.t("password")), - ); + this.toastService.showToast({ + variant: "info", + title: null, + message: this.i18nService.t("valueCopied", this.i18nService.t("password")), + }); } protected async init() { diff --git a/libs/angular/src/vault/components/premium.component.ts b/libs/angular/src/vault/components/premium.component.ts index 8b1f215ef42..e86c6beda47 100644 --- a/libs/angular/src/vault/components/premium.component.ts +++ b/libs/angular/src/vault/components/premium.component.ts @@ -12,7 +12,7 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { DialogService, SimpleDialogOptions } from "@bitwarden/components"; +import { DialogService, SimpleDialogOptions, ToastService } from "@bitwarden/components"; @Directive() export class PremiumComponent implements OnInit { @@ -31,6 +31,7 @@ export class PremiumComponent implements OnInit { protected dialogService: DialogService, private environmentService: EnvironmentService, billingAccountProfileStateService: BillingAccountProfileStateService, + private toastService: ToastService, accountService: AccountService, ) { this.isPremium$ = accountService.activeAccount$.pipe( @@ -51,7 +52,11 @@ export class PremiumComponent implements OnInit { try { this.refreshPromise = this.apiService.refreshIdentityToken(); await this.refreshPromise; - this.platformUtilsService.showToast("success", null, this.i18nService.t("refreshComplete")); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("refreshComplete"), + }); } catch (e) { this.logService.error(e); } diff --git a/libs/angular/src/vault/components/view.component.ts b/libs/angular/src/vault/components/view.component.ts index ef9aff736ed..18caa875e03 100644 --- a/libs/angular/src/vault/components/view.component.ts +++ b/libs/angular/src/vault/components/view.component.ts @@ -40,7 +40,7 @@ import { AttachmentView } from "@bitwarden/common/vault/models/view/attachment.v import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; import { PasswordRepromptService } from "@bitwarden/vault"; @@ -115,6 +115,7 @@ export class ViewComponent implements OnDestroy, OnInit { protected datePipe: DatePipe, protected accountService: AccountService, private billingAccountProfileStateService: BillingAccountProfileStateService, + protected toastService: ToastService, private cipherAuthorizationService: CipherAuthorizationService, ) {} @@ -246,11 +247,13 @@ export class ViewComponent implements OnDestroy, OnInit { try { await this.deleteCipher(); - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t(this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem"), - ); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t( + this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem", + ), + }); this.onDeletedCipher.emit(this.cipher); } catch (e) { this.logService.error(e); @@ -266,7 +269,11 @@ export class ViewComponent implements OnDestroy, OnInit { try { await this.restoreCipher(); - this.platformUtilsService.showToast("success", null, this.i18nService.t("restoredItem")); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("restoredItem"), + }); this.onRestoredCipher.emit(this.cipher); } catch (e) { this.logService.error(e); @@ -349,13 +356,17 @@ export class ViewComponent implements OnDestroy, OnInit { const matches = await this.checkPasswordPromise; if (matches > 0) { - this.platformUtilsService.showToast( - "warning", - null, - this.i18nService.t("passwordExposed", matches.toString()), - ); + this.toastService.showToast({ + variant: "warning", + title: null, + message: this.i18nService.t("passwordExposed", matches.toString()), + }); } else { - this.platformUtilsService.showToast("success", null, this.i18nService.t("passwordSafe")); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("passwordSafe"), + }); } } @@ -385,11 +396,11 @@ export class ViewComponent implements OnDestroy, OnInit { const copyOptions = this.win != null ? { window: this.win } : null; this.platformUtilsService.copyToClipboard(value, copyOptions); - this.platformUtilsService.showToast( - "info", - null, - this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)), - ); + this.toastService.showToast({ + variant: "info", + title: null, + message: this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)), + }); if (typeI18nKey === "password") { // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. @@ -422,11 +433,11 @@ export class ViewComponent implements OnDestroy, OnInit { } if (this.cipher.organizationId == null && !this.canAccessPremium) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("premiumRequired"), - this.i18nService.t("premiumRequiredDesc"), - ); + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("premiumRequired"), + message: this.i18nService.t("premiumRequiredDesc"), + }); return; } @@ -450,7 +461,11 @@ export class ViewComponent implements OnDestroy, OnInit { a.downloading = true; const response = await fetch(new Request(url, { cache: "no-store" })); if (response.status !== 200) { - this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred")); + this.toastService.showToast({ + variant: "error", + title: null, + message: this.i18nService.t("errorOccurred"), + }); a.downloading = false; return; } @@ -469,7 +484,11 @@ export class ViewComponent implements OnDestroy, OnInit { // FIXME: Remove when updating file. Eslint update // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (e) { - this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred")); + this.toastService.showToast({ + variant: "error", + title: null, + message: this.i18nService.t("errorOccurred"), + }); } a.downloading = false; diff --git a/libs/vault/src/components/password-reprompt.component.ts b/libs/vault/src/components/password-reprompt.component.ts index abefac58747..6898d411719 100644 --- a/libs/vault/src/components/password-reprompt.component.ts +++ b/libs/vault/src/components/password-reprompt.component.ts @@ -13,6 +13,7 @@ import { DialogModule, FormFieldModule, IconButtonModule, + ToastService, } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; @@ -45,6 +46,7 @@ export class PasswordRepromptComponent { protected i18nService: I18nService, protected formBuilder: FormBuilder, protected dialogRef: DialogRef, + private toastService: ToastService, protected accountService: AccountService, ) {} @@ -72,11 +74,11 @@ export class PasswordRepromptComponent { userId, )) ) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("invalidMasterPassword"), - ); + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("errorOccurred"), + message: this.i18nService.t("invalidMasterPassword"), + }); return; } From 43a6a93944367afc1d26f85d0920d9288fe70bad Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:04:06 -0800 Subject: [PATCH 16/17] don't allow 'except password' permissions to view or copy hidden fields (#12899) --- .../components/custom-fields/custom-fields.component.ts | 4 ++++ .../cipher-view/custom-fields/custom-fields-v2.component.html | 2 ++ .../cipher-view/custom-fields/custom-fields-v2.component.ts | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.ts b/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.ts index d723bad5751..cd75fe8fba1 100644 --- a/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.ts +++ b/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.ts @@ -167,6 +167,10 @@ export class CustomFieldsComponent implements OnInit, AfterViewInit { ); }); + if (!this.cipherFormContainer.originalCipherView?.viewPassword) { + this.customFieldsForm.disable(); + } + // Disable the form if in partial-edit mode // Must happen after the initial fields are populated if (this.cipherFormContainer.config.mode === "partial-edit") { diff --git a/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.html b/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.html index 45ddc3c1dea..ab31ede57bb 100644 --- a/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.html +++ b/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.html @@ -38,6 +38,7 @@ type="button" bitIconButton bitPasswordInputToggle + *ngIf="canViewPassword" (toggledChange)="logHiddenEvent($event)" > diff --git a/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.ts b/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.ts index b41b351e197..313607ce3a6 100644 --- a/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.ts +++ b/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.ts @@ -59,6 +59,10 @@ export class CustomFieldV2Component implements OnInit { return this.i18nService.t(linkedType.i18nKey); } + get canViewPassword() { + return this.cipher.viewPassword; + } + async logHiddenEvent(hiddenFieldVisible: boolean) { if (hiddenFieldVisible) { await this.eventCollectionService.collect( From d820bfb69165948d3678fb4f86b97949fac019ef Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Mon, 20 Jan 2025 11:43:10 +0100 Subject: [PATCH 17/17] [PM-17346] Move A11yTitle and CopyClick to CL (#12936) * Move A11yTitle and CopyClick to CL --- libs/angular/src/jslib.module.ts | 8 ++++---- .../src/a11y}/a11y-title.directive.ts | 1 + libs/components/src/a11y/index.ts | 1 + .../src/copy-click}/copy-click.directive.spec.ts | 15 +++++++++------ .../src/copy-click}/copy-click.directive.ts | 4 +++- libs/components/src/copy-click/index.ts | 1 + libs/components/src/index.ts | 4 +++- .../login-credentials-view.component.spec.ts | 3 +-- 8 files changed, 23 insertions(+), 14 deletions(-) rename libs/{angular/src/directives => components/src/a11y}/a11y-title.directive.ts (98%) create mode 100644 libs/components/src/a11y/index.ts rename libs/{angular/src/directives => components/src/copy-click}/copy-click.directive.spec.ts (89%) rename libs/{angular/src/directives => components/src/copy-click}/copy-click.directive.ts (96%) create mode 100644 libs/components/src/copy-click/index.ts diff --git a/libs/angular/src/jslib.module.ts b/libs/angular/src/jslib.module.ts index 4f5a8f6673c..b06faacef19 100644 --- a/libs/angular/src/jslib.module.ts +++ b/libs/angular/src/jslib.module.ts @@ -25,15 +25,15 @@ import { TableModule, ToastModule, TypographyModule, + CopyClickDirective, + A11yTitleDirective, } from "@bitwarden/components"; import { TwoFactorIconComponent } from "./auth/components/two-factor-icon.component"; import { DeprecatedCalloutComponent } from "./components/callout.component"; import { A11yInvalidDirective } from "./directives/a11y-invalid.directive"; -import { A11yTitleDirective } from "./directives/a11y-title.directive"; import { ApiActionDirective } from "./directives/api-action.directive"; import { BoxRowDirective } from "./directives/box-row.directive"; -import { CopyClickDirective } from "./directives/copy-click.directive"; import { CopyTextDirective } from "./directives/copy-text.directive"; import { FallbackSrcDirective } from "./directives/fallback-src.directive"; import { IfFeatureDirective } from "./directives/if-feature.directive"; @@ -83,10 +83,11 @@ import { IconComponent } from "./vault/components/icon.component"; LinkModule, IconModule, TextDragDirective, + CopyClickDirective, + A11yTitleDirective, ], declarations: [ A11yInvalidDirective, - A11yTitleDirective, ApiActionDirective, AutofocusDirective, BoxRowDirective, @@ -105,7 +106,6 @@ import { IconComponent } from "./vault/components/icon.component"; StopClickDirective, StopPropDirective, TrueFalseValueDirective, - CopyClickDirective, LaunchClickDirective, UserNamePipe, PasswordStrengthComponent, diff --git a/libs/angular/src/directives/a11y-title.directive.ts b/libs/components/src/a11y/a11y-title.directive.ts similarity index 98% rename from libs/angular/src/directives/a11y-title.directive.ts rename to libs/components/src/a11y/a11y-title.directive.ts index f5f016b93c0..c3833f42ed2 100644 --- a/libs/angular/src/directives/a11y-title.directive.ts +++ b/libs/components/src/a11y/a11y-title.directive.ts @@ -4,6 +4,7 @@ import { Directive, ElementRef, Input, OnInit, Renderer2 } from "@angular/core"; @Directive({ selector: "[appA11yTitle]", + standalone: true, }) export class A11yTitleDirective implements OnInit { @Input() set appA11yTitle(title: string) { diff --git a/libs/components/src/a11y/index.ts b/libs/components/src/a11y/index.ts new file mode 100644 index 00000000000..6090fb65d4e --- /dev/null +++ b/libs/components/src/a11y/index.ts @@ -0,0 +1 @@ +export * from "./a11y-title.directive"; diff --git a/libs/angular/src/directives/copy-click.directive.spec.ts b/libs/components/src/copy-click/copy-click.directive.spec.ts similarity index 89% rename from libs/angular/src/directives/copy-click.directive.spec.ts rename to libs/components/src/copy-click/copy-click.directive.spec.ts index 09161ee261d..eab616b141e 100644 --- a/libs/angular/src/directives/copy-click.directive.spec.ts +++ b/libs/components/src/copy-click/copy-click.directive.spec.ts @@ -3,7 +3,8 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { ToastService } from "@bitwarden/components"; + +import { ToastService } from "../"; import { CopyClickDirective } from "./copy-click.directive"; @@ -20,12 +21,14 @@ import { CopyClickDirective } from "./copy-click.directive"; #toastWithLabel > `, + standalone: true, + imports: [CopyClickDirective], }) class TestCopyClickComponent { - @ViewChild("noToast") noToastButton: ElementRef; - @ViewChild("infoToast") infoToastButton: ElementRef; - @ViewChild("successToast") successToastButton: ElementRef; - @ViewChild("toastWithLabel") toastWithLabelButton: ElementRef; + @ViewChild("noToast") noToastButton!: ElementRef; + @ViewChild("infoToast") infoToastButton!: ElementRef; + @ViewChild("successToast") successToastButton!: ElementRef; + @ViewChild("toastWithLabel") toastWithLabelButton!: ElementRef; } describe("CopyClickDirective", () => { @@ -38,7 +41,7 @@ describe("CopyClickDirective", () => { showToast.mockClear(); await TestBed.configureTestingModule({ - declarations: [CopyClickDirective, TestCopyClickComponent], + imports: [TestCopyClickComponent], providers: [ { provide: I18nService, diff --git a/libs/angular/src/directives/copy-click.directive.ts b/libs/components/src/copy-click/copy-click.directive.ts similarity index 96% rename from libs/angular/src/directives/copy-click.directive.ts rename to libs/components/src/copy-click/copy-click.directive.ts index ece867c09fd..f91366360c5 100644 --- a/libs/angular/src/directives/copy-click.directive.ts +++ b/libs/components/src/copy-click/copy-click.directive.ts @@ -4,10 +4,12 @@ import { Directive, HostListener, Input } from "@angular/core"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { ToastService, ToastVariant } from "@bitwarden/components"; + +import { ToastService, ToastVariant } from "../"; @Directive({ selector: "[appCopyClick]", + standalone: true, }) export class CopyClickDirective { private _showToast = false; diff --git a/libs/components/src/copy-click/index.ts b/libs/components/src/copy-click/index.ts new file mode 100644 index 00000000000..82b971f1f5c --- /dev/null +++ b/libs/components/src/copy-click/index.ts @@ -0,0 +1 @@ +export * from "./copy-click.directive"; diff --git a/libs/components/src/index.ts b/libs/components/src/index.ts index ed844520444..7788f4986bf 100644 --- a/libs/components/src/index.ts +++ b/libs/components/src/index.ts @@ -1,3 +1,5 @@ +export { ButtonType } from "./shared/button-like.abstraction"; +export * from "./a11y"; export * from "./async-actions"; export * from "./avatar"; export * from "./badge-list"; @@ -5,13 +7,13 @@ export * from "./badge"; export * from "./banner"; export * from "./breadcrumbs"; export * from "./button"; -export { ButtonType } from "./shared/button-like.abstraction"; export * from "./callout"; export * from "./card"; export * from "./checkbox"; export * from "./chip-select"; export * from "./color-password"; export * from "./container"; +export * from "./copy-click"; export * from "./dialog"; export * from "./disclosure"; export * from "./drawer"; diff --git a/libs/vault/src/cipher-view/login-credentials/login-credentials-view.component.spec.ts b/libs/vault/src/cipher-view/login-credentials/login-credentials-view.component.spec.ts index 9bb96d1accd..39fcc39bf58 100644 --- a/libs/vault/src/cipher-view/login-credentials/login-credentials-view.component.spec.ts +++ b/libs/vault/src/cipher-view/login-credentials/login-credentials-view.component.spec.ts @@ -4,7 +4,6 @@ import { By } from "@angular/platform-browser"; import { mock } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; -import { CopyClickDirective } from "@bitwarden/angular/directives/copy-click.directive"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions"; @@ -17,7 +16,7 @@ import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { Fido2CredentialView } from "@bitwarden/common/vault/models/view/fido2-credential.view"; import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; -import { BitFormFieldComponent, ToastService } from "@bitwarden/components"; +import { CopyClickDirective, BitFormFieldComponent, ToastService } from "@bitwarden/components"; // FIXME: remove `src` and fix import // eslint-disable-next-line no-restricted-imports import { ColorPasswordComponent } from "@bitwarden/components/src/color-password/color-password.component";