diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4b956fd577a..d6028d106db 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -101,6 +101,7 @@ libs/guid @bitwarden/team-platform-dev libs/client-type @bitwarden/team-platform-dev libs/core-test-utils @bitwarden/team-platform-dev libs/state @bitwarden/team-platform-dev +libs/state-internal @bitwarden/team-platform-dev libs/state-test-utils @bitwarden/team-platform-dev # Web utils used across app and connectors apps/web/src/utils/ @bitwarden/team-platform-dev @@ -156,6 +157,7 @@ apps/desktop/desktop_native/core/src/ssh_agent @bitwarden/team-autofill-dev @bit ## UI Foundation ## .storybook @bitwarden/team-ui-foundation libs/components @bitwarden/team-ui-foundation +libs/assets @bitwarden/team-ui-foundation libs/ui @bitwarden/team-ui-foundation apps/browser/src/platform/popup/layout @bitwarden/team-ui-foundation apps/browser/src/popup/app-routing.animations.ts @bitwarden/team-ui-foundation diff --git a/apps/browser/package.json b/apps/browser/package.json index 46c92ca8902..320b6be4f7c 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/browser", - "version": "2025.8.0", + "version": "2025.8.1", "scripts": { "build": "npm run build:chrome", "build:chrome": "cross-env BROWSER=chrome MANIFEST_VERSION=3 NODE_OPTIONS=\"--max-old-space-size=8192\" webpack", diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index ee723217f2a..9b0efbd8148 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "اختر مجموعة" }, - "importTargetHint": { - "message": "حدد هذا الخيار إذا كنت تريد نقل محتويات الملف المستورد إلى $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "الملف يحتوي على عناصر غير مسندة." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index 1d26f50bca6..8a3c5dcb3c6 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Bir kolleksiya seçin" }, - "importTargetHint": { - "message": "Daxilə köçürülən fayl məzmununun $DESTINATION$ yerinə daşınmasını istəyirsinizsə bu variantı seçin", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Daxilə köçürülən fayl məzmunlarının bir kolleksiyaya daşınmasını istəyirsinizsə bu variantı seçin" + }, + "importTargetHintFolder": { + "message": "Daxilə köçürülən fayl məzmunlarının bir qovluğa daşınmasını istəyirsinizsə bu variantı seçin" }, "importUnassignedItemsError": { "message": "Faylda təyin edilməmiş elementlər var." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Daha az göstər" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index d6090123878..ed6ac29ea1e 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Выбраць калекцыю" }, - "importTargetHint": { - "message": "Выберыце гэты параметр, калі вы хочаце, каб змесціва імпартаванага файла было перамешчанага ў $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Файл змяшчае непадпісаныя элементы." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 3b411cd088c..97d8c1a3a43 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Изберете колекция" }, - "importTargetHint": { - "message": "Изберете тази опция, ако искате съдържанието на внесения файл да бъде преместено в $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Изберете тази опция, ако искате съдържанието на внесения файл да бъде преместено в колекция" + }, + "importTargetHintFolder": { + "message": "Изберете тази опция, ако искате съдържанието на внесения файл да бъде преместено в папка" }, "importUnassignedItemsError": { "message": "Файлът съдържа невъзложени елементи." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Показване на по-малко" + }, + "moreBreadcrumbs": { + "message": "Още елементи в пътечката", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index 55baca0dad2..b816b274766 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index 7ad375dabf0..347fc68924f 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index 3edfb98eba2..0a9500e3c03 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Selecciona una col·lecció" }, - "importTargetHint": { - "message": "Seleccioneu aquesta opció si voleu que el contingut del fitxer importat es desplace a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "El fitxer conté elements no assignats." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index 916f765ea21..b31c18524cf 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Zvolte sbírku" }, - "importTargetHint": { - "message": "Pokud chcete obsah importovaného souboru přesunout do: \"$DESTINATION$\", vyberte tuto volbu", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Pokud chcete obsah importovaného souboru přesunout do sbírky, vyberte tuto volbu" + }, + "importTargetHintFolder": { + "message": "Pokud chcete obsah importovaného souboru přesunout do složky, vyberte tuto volbu" }, "importUnassignedItemsError": { "message": "Soubor obsahuje nepřiřazené položky." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Zobrazit méně" + }, + "moreBreadcrumbs": { + "message": "Více...", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json index 8307b994fe0..c1ea7f6036c 100644 --- a/apps/browser/src/_locales/cy/messages.json +++ b/apps/browser/src/_locales/cy/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index 0ff87e6e14f..52ca548a080 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Vælg en samling" }, - "importTargetHint": { - "message": "Vælg denne indstilling, hvis importeret filindhold skal flyttet til en $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Fil indeholder ikke-tildelte emner." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index ffaf490fbf8..16f572fea2e 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Sammlung auswählen" }, - "importTargetHint": { - "message": "Wähle diese Option, wenn der importierte Dateiinhalt in eine(n) $DESTINATION$ verschoben werden soll", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Die Datei enthält nicht zugewiesene Einträge." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Weniger anzeigen" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index 3d46b63ec45..6a34fbd4fd0 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Επιλέξτε μια συλλογή" }, - "importTargetHint": { - "message": "Επιλέξτε αυτή την επιλογή εάν θέλετε τα περιεχόμενα του εισαγόμενου αρχείου να μετακινηθούν στο $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Το αρχείο περιέχει μη συσχετισμένα στοιχεία." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index 8acf75e2ee5..c74a39779a0 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 281caeac0d5..57f92159031 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index 0e1185148df..96885ea5e37 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Selecciona una colección" }, - "importTargetHint": { - "message": "Selecciona esta opción si deseas que el contenido del archivo importado se mueva a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "El archivo contiene elementos no asignados." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index 09e77bd361f..4631cbfe018 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -111,13 +111,13 @@ "message": "Kaart" }, "vault": { - "message": "Seif" + "message": "Hoidla" }, "myVault": { - "message": "Minu seif" + "message": "Minu hoidla" }, "allVaults": { - "message": "Kõik seifid" + "message": "Kõik hoidlad" }, "tools": { "message": "Tööriistad" @@ -671,7 +671,7 @@ "message": "Hoidla on lukus. Jätkamiseks sisesta ülemparool." }, "yourVaultIsLockedV2": { - "message": "Your vault is locked" + "message": "Sinu hoidla on lukus" }, "yourAccountIsLocked": { "message": "Your account is locked" @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4476,13 +4472,13 @@ "message": "Pääsuvõti on eemaldatud" }, "autofillSuggestions": { - "message": "Autofill suggestions" + "message": "Automaatse täitmise soovitused" }, "itemSuggestions": { "message": "Suggested items" }, "autofillSuggestionsTip": { - "message": "Save a login item for this site to autofill" + "message": "Automaatseks täitmiseks salvesta kirje selle saidi jaoks" }, "yourVaultIsEmpty": { "message": "Your vault is empty" @@ -4649,7 +4645,7 @@ } }, "new": { - "message": "New" + "message": "Uus" }, "removeItem": { "message": "Remove $NAME$", @@ -4690,7 +4686,7 @@ "message": "Item history" }, "lastEdited": { - "message": "Last edited" + "message": "Viimati muudetud" }, "ownerYou": { "message": "Owner: You" @@ -5490,7 +5486,7 @@ "message": "Import now" }, "hasItemsVaultNudgeTitle": { - "message": "Welcome to your vault!" + "message": "Tere tulemast sinu hoidlasse!" }, "hasItemsVaultNudgeBodyOne": { "message": "Autofill items for the current page" @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index 1cd1439e972..70ce920c7a6 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index cfae87fd1a5..e62839f1f31 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "انتخاب یک مجموعه" }, - "importTargetHint": { - "message": "اگر می‌خواهید محتوای پرونده درون ریزی شده به $DESTINATION$ منتقل شود، این گزینه را انتخاب کنید", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "پرونده حاوی موارد اختصاص نیافته است." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index ffd5caea1d3..6454e78dcdb 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Valitse kokoelma" }, - "importTargetHint": { - "message": "Valitse tämä, jos haluat tuoda tiedoston sisällön kohteeseen \"$DESTINATION$\".", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Tiedosto sisältää määrittämättömiä kohteita." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 1682d21aa7f..9ce7ee5d427 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index 1a4f466a41c..42a11655ca1 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Sélectionner une collection" }, - "importTargetHint": { - "message": "Sélectionnez cette option si vous voulez que le contenu du fichier importé soit déplacé vers un(e) $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Sélectionnez cette option si vous voulez que le contenu du fichier importé soit déplacé vers une collection" + }, + "importTargetHintFolder": { + "message": "Sélectionnez cette option si vous voulez que le contenu du fichier importé soit déplacé vers un dossier" }, "importUnassignedItemsError": { "message": "Le fichier contient des éléments non assignés." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index 0698191f53e..0b1b754a41e 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Seleccionar unha colección" }, - "importTargetHint": { - "message": "Selecciona esta opción se queres que o contido importado se mova a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "O arquivo contén entradas sen asignar." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index 96dc5215051..28667c2b2a4 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "בחר אוסף" }, - "importTargetHint": { - "message": "בחר באפשרות זו אם ברצונך להעביר את תוכן הקובץ המיובא אל $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "קובץ מכיל פריטים לא מוקצים." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index 35d7e8b2911..4aed6e60763 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index d38461ab553..c1244477098 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Odaberi zbirku" }, - "importTargetHint": { - "message": "Odaberi ovu opciju ako sadržaj uvezene datoteke želiš spremiti u $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Datoteka sadrži nedodijeljene stavke." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Pokaži manje" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index a0fc88e047a..87020472c53 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Gyűjtemény kiválasztása" }, - "importTargetHint": { - "message": "Válasszuk ezt a lehetőséget, ha azt akarjuk, hogy az importált fájl tartalma $DESTINATION$ helyre kerüljön", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Válasszuk ezt az opciót, ha azt akarjuk, hogy az importált fájl tartalma egy gyűjteménybe kerüljön." + }, + "importTargetHintFolder": { + "message": "Válasszuk ezt az opciót, ha azt akarjuk, hogy az importált fájl tartalma egy mappába kerüljön." }, "importUnassignedItemsError": { "message": "A fájl hozzá nem rendelt elemeket tartalmaz." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Kevesebb megjelenítése" + }, + "moreBreadcrumbs": { + "message": "További morzsamenük", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index 297b2d458e1..5698286283c 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -3789,7 +3789,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendsBodyNoItems": { - "message": "Bagikan berkas-berkas dan data secara aman dengan siapa saja, pada platform apapun. Informasi Anda akan tetap terenkripsi dari ujung-ke-ujung sembari membatasi paparan.", + "message": "Bagikan berkas-berkas dan data secara aman dengan siapa saja, pada platform apa pun. Informasi Anda akan tetap terenkripsi dari ujung ke ujung sembari membatasi paparan.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "inputRequired": { @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Pilih koleksi" }, - "importTargetHint": { - "message": "Pilih pilihan ini jika Anda ingin isi dari berkas yang diimpor dipindah ke $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Berkas berisi benda-benda yang belum ditetapkan." @@ -5575,9 +5571,13 @@ "description": "'WebAssembly' is a technical term and should not be translated." }, "showMore": { - "message": "Show more" + "message": "Tampilkan lebih banyak" }, "showLess": { - "message": "Show less" + "message": "Tampilkan lebih sedikit" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index 4e1c1d63e50..4742b7c6433 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Seleziona una raccolta" }, - "importTargetHint": { - "message": "Seleziona questa opzione se vuoi che i contenuti del file di importazione siano spostati in una $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Seleziona questa opzione se vuoi che i contenuti dell'importazione siano salvati in una raccolta" + }, + "importTargetHintFolder": { + "message": "Seleziona questa opzione se vuoi che i contenuti dell'importazione siano salvati in una cartella" }, "importUnassignedItemsError": { "message": "Il file contiene elementi non assegnati." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Mostra di meno" + }, + "moreBreadcrumbs": { + "message": "Ulteriori segmenti", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index 9370a3ae6b1..174c13d64ce 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "コレクションを選択" }, - "importTargetHint": { - "message": "インポートしたファイルコンテンツを $DESTINATION$ に移動したい場合は、このオプションを選択してください。", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "割り当てられていないアイテムがファイルに含まれています。" @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index 6bbdb6f67f3..a71f9a9d0e0 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "აირჩიეთ კოლექცია" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index d076ef01ef2..9170fd20734 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index f4ab488884a..279c5b28824 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 50725e73064..d39f111101b 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "컬렉션 선택" }, - "importTargetHint": { - "message": "가져온 파일의 내용을 $DESTINATION$로 이동하려면 이 옵션을 선택하세요.", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "파일에 할당되지 않은 항목이 포함되어 있습니다." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index fa53a42a4b7..913d442c88f 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -3,14 +3,14 @@ "message": "Bitwarden" }, "appLogoLabel": { - "message": "Bitwarden logotipas" + "message": "„Bitwarden“ logotipas" }, "extName": { "message": "„Bitwarden“ slaptažodžių tvarkyklė", "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "Namuose, darbe ar kelyje, Bitwarden apsaugo jūsų slaptažodžius, raktažodžius ir svarbią informaciją", + "message": "Namuose, darbe ar kelyje, „Bitwarden“ apsaugo jūsų slaptažodžius, raktažodžius ir svarbią informaciją", "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { @@ -23,13 +23,13 @@ "message": "Sukurti paskyrą" }, "newToBitwarden": { - "message": "Pirmą kartą Bitwarden?" + "message": "Pirmą kartą „Bitwarden“?" }, "logInWithPasskey": { "message": "Prisijungti naudojant prieigos raktą" }, "useSingleSignOn": { - "message": "Use single sign-on" + "message": "Naudoti vieningo prisijungimo sistemą" }, "welcomeBack": { "message": "Sveiki sugrįžę" @@ -38,7 +38,7 @@ "message": "Nustatyti stiprų slaptažodį" }, "finishCreatingYourAccountBySettingAPassword": { - "message": "Baigkite kurti paskyrą nustatydami slaptažodį" + "message": "Baikite kurti paskyrą nustatydami slaptažodį" }, "enterpriseSingleSignOn": { "message": "Vienkartinis įmonės prisijungimas" @@ -59,10 +59,10 @@ "message": "Pagrindinis slaptažodis" }, "masterPassDesc": { - "message": "Pagrindinis slaptažodis yra slaptažodis, kurį naudojate norėdami pasiekti savo saugyklą. Labai svarbu nepamiršti pagrindinio slaptažodžio. Nėra galimybių atkurti slaptažodį, jei jį pamiršite." + "message": "Pagrindinis slaptažodis yra slaptažodis, kurį naudojate norėdami pasiekti savo saugyklą. Labai svarbu nepamiršti pagrindinio slaptažodžio. Nėra galimybių atkurti slaptažodžio, jei jį pamiršite." }, "masterPassHintDesc": { - "message": "Pagrindinio slaptažodžio užuomina gali padėti Jums prisiminti slaptažodį, jei jį pamiršite." + "message": "Pagrindinio slaptažodžio užuomina gali padėti jums prisiminti slaptažodį, jei jį pamiršite." }, "masterPassHintText": { "message": "Jei pamiršote slaptažodį, slaptažodžio užuomina gali būti išsiųsta į jūsų el. paštą. $CURRENT$ / $MAXIMUM$ didžiausias simbolių skaičius.", @@ -105,7 +105,7 @@ } }, "finishJoiningThisOrganizationBySettingAMasterPassword": { - "message": "Baigėte prisijungimą prie organizacijos nustatant pagrindinį slaptažodį." + "message": "Užbaikite prisijungimą prie organizacijos nustatydami pagrindinį slaptažodį." }, "tab": { "message": "Skirtukas" @@ -132,7 +132,7 @@ "message": "Kopijuoti slaptažodį" }, "copyPassphrase": { - "message": "Kopijuoti slaptažodžio frazę" + "message": "Kopijuoti slaptą frazę" }, "copyNote": { "message": "Kopijuoti pastabą" @@ -156,13 +156,13 @@ "message": "Kopijuoti įmonę" }, "copySSN": { - "message": "Kopijuoti socialinės apsaugos numerį" + "message": "Kopijuoti asmens kodo numerį" }, "copyPassportNumber": { "message": "Kopijuoti paso numerį" }, "copyLicenseNumber": { - "message": "Kopijuoti licenzijos numerį" + "message": "Kopijuoti licencijos numerį" }, "copyPrivateKey": { "message": "Kopijuoti privatų raktą" @@ -193,7 +193,7 @@ "description": "Copy to clipboard" }, "fill": { - "message": "Fill", + "message": "Užpildyti", "description": "This string is used on the vault page to indicate autofilling. Horizontal space is limited in the interface here so try and keep translations as concise as possible." }, "autoFill": { @@ -209,10 +209,10 @@ "message": "Tapatybės automatinis užpildymas" }, "fillVerificationCode": { - "message": "Fill verification code" + "message": "Užpildyti patvirtinimo kodą" }, "fillVerificationCodeAria": { - "message": "Fill Verification Code", + "message": "Užpildyti patvirtinimo kodą", "description": "Aria label for the heading displayed the inline menu for totp code autofill" }, "generatePasswordCopied": { @@ -240,10 +240,10 @@ "message": "Pridėti tapatybę" }, "unlockVaultMenu": { - "message": "Atrakinti Jūsų saugyklą" + "message": "Atrakinti jūsų saugyklą" }, "loginToVaultMenu": { - "message": "Prisijungti prie Jūsų saugyklos" + "message": "Prisijungti prie jūsų saugyklos" }, "autoFillInfo": { "message": "Nėra galimų prisijungimų prie dabartinio naršyklės skirtuko." @@ -255,16 +255,16 @@ "message": "Pridėti elementą" }, "accountEmail": { - "message": "Account email" + "message": "Paskyros el. paštas" }, "requestHint": { - "message": "Request hint" + "message": "Duoti užuominą" }, "requestPasswordHint": { - "message": "Request password hint" + "message": "Duoti slaptažodžio užuominą" }, "enterYourAccountEmailAddressAndYourPasswordHintWillBeSentToYou": { - "message": "Enter your account email address and your password hint will be sent to you" + "message": "Įveskite savo paskyros el. pašą ir jūsų slaptažodžio užuomina bus atsiųsta jums" }, "getMasterPasswordHint": { "message": "Gauti pagrindinio slaptažodžio užuominą" @@ -291,25 +291,25 @@ "message": "Keisti pagrindinį slaptažodį" }, "continueToWebApp": { - "message": "Tęsti į žiniatinklio programėlę?" + "message": "Tęsti į žiniatinklio programą?" }, "continueToWebAppDesc": { - "message": "Atraskite daugiau savo Bitwarden paskyros funkcijų web programoje." + "message": "Atraskite daugiau savo „Bitwarden“ paskyros funkcijų žiniatinklio programoje." }, "continueToHelpCenter": { "message": "Eiti į pagalbos centrą?" }, "continueToHelpCenterDesc": { - "message": "Pagalbos Centre sužinokite daugiau kaip naudotis Bitwarden." + "message": "Pagalbos centre sužinokite daugiau, kaip naudotis „Bitwarden“." }, "continueToBrowserExtensionStore": { "message": "Eiti į naršyklės plėtinių svetainę?" }, "continueToBrowserExtensionStoreDesc": { - "message": "Padėkite kitiems sužinoti ar Bitwarden yra jiems tinkamas. Apsilankykite naršyklės plėtinių svetainėje ir įvertinkite Bitwarden." + "message": "Padėkite kitiems sužinoti ar B„itwarden“ yra jiems tinkamas. Apsilankykite naršyklės plėtinių svetainėje ir įvertinkite „Bitwarden“." }, "changeMasterPasswordOnWebConfirmation": { - "message": "Pagrindinį slaptažodį galite pakeisti „Bitwarden“ žiniatinklio programėlėje." + "message": "Pagrindinį slaptažodį galite pakeisti „Bitwarden“ žiniatinklio programoje." }, "fingerprintPhrase": { "message": "Pirštų atspaudų frazė", @@ -383,7 +383,7 @@ "message": "Redaguoti aplankalą" }, "editFolderWithName": { - "message": "Edit folder: $FOLDERNAME$", + "message": "Redaguoti aplanką: $FOLDERNAME$", "placeholders": { "foldername": { "content": "$1", @@ -392,10 +392,10 @@ } }, "newFolder": { - "message": "New folder" + "message": "Naujas aplankas" }, "folderName": { - "message": "Folder name" + "message": "Aplanko vardas" }, "folderHintText": { "message": "Nest a folder by adding the parent folder's name followed by a “/”. Example: Social/Forums" @@ -677,7 +677,7 @@ "message": "Your account is locked" }, "or": { - "message": "or" + "message": "arba" }, "unlock": { "message": "Atrakinti" @@ -702,7 +702,7 @@ "message": "Atsijungta nuo saugyklos" }, "vaultTimeout1": { - "message": "Timeout" + "message": "Skirtas laikas" }, "lockNow": { "message": "Užrakinti dabar" @@ -799,10 +799,10 @@ "message": "Jūsų paskyra sukurta! Galite prisijungti." }, "newAccountCreated2": { - "message": "Your new account has been created!" + "message": "Jūsų nauja paskyra buvo sukurta!" }, "youHaveBeenLoggedIn": { - "message": "You have been logged in!" + "message": "Jūs prisijungėte!" }, "youSuccessfullyLoggedIn": { "message": "Jūs sėkmingai prisijungėte" @@ -845,7 +845,7 @@ "message": "Nuskaitykite autentifikatoriaus QR kodą iš dabartinio tinklalapio" }, "totpHelperTitle": { - "message": "Make 2-step verification seamless" + "message": "Padaryti dviejų veiksnių patvirtinimą sklandų" }, "totpHelper": { "message": "Bitwarden can store and fill 2-step verification codes. Copy and paste the key into this field." @@ -872,19 +872,19 @@ "message": "Prisijungti" }, "logInToBitwarden": { - "message": "Log in to Bitwarden" + "message": "Prisijungti prie „Bitwarden“" }, "enterTheCodeSentToYourEmail": { - "message": "Enter the code sent to your email" + "message": "Įveskite kodą išsiųstą jums el. paštu" }, "enterTheCodeFromYourAuthenticatorApp": { - "message": "Enter the code from your authenticator app" + "message": "Įveskite kodą iš autentifikacijos programėlės" }, "pressYourYubiKeyToAuthenticate": { - "message": "Press your YubiKey to authenticate" + "message": "Palieskite savo „YubiKey“, kad autentifikuotumėtės" }, "duoTwoFactorRequiredPageSubtitle": { - "message": "Duo two-step login is required for your account. Follow the steps below to finish logging in." + "message": "„Duo“ dviejų veiksnių prisijungimas yra privalomas jūsų paskyrai. Sekite žingsnius žemiau, kad užbaigtumėte prisijungimą." }, "followTheStepsBelowToFinishLoggingIn": { "message": "Follow the steps below to finish logging in." @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Pasirinkti rinkinį" }, - "importTargetHint": { - "message": "Pasirinkite šį pasirinkimą, jei norite, jog importuoto failo turinys, būtų perkeltas į $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Faile yra nepriskirtų elementų." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index 68d5a0db2e3..14bf2293c41 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Atlasīt krājumu" }, - "importTargetHint": { - "message": "Šī iespēja jāatlasa, ja ir vēlēšanās ievietotās datnes saturu pārvietot uz $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Šī iespēja jāatlasa, ja ir vēlēšanās ievietotās datnes saturu ievietot krājumā" + }, + "importTargetHintFolder": { + "message": "Šī iespēja jāatlasa, ja ir vēlēšanās ievietotās datnes saturu ievietot mapē" }, "importUnassignedItemsError": { "message": "Datne satur nepiešķirtus vienumus." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Rādīt mazāk" + }, + "moreBreadcrumbs": { + "message": "Vairāk norāžu", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index ca1bbc69297..55abe605aa7 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json index 70059b1552e..0c2336ab264 100644 --- a/apps/browser/src/_locales/mr/messages.json +++ b/apps/browser/src/_locales/mr/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json index d076ef01ef2..9170fd20734 100644 --- a/apps/browser/src/_locales/my/messages.json +++ b/apps/browser/src/_locales/my/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index 9e617957dc8..b27422f36a1 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Velg en samling" }, - "importTargetHint": { - "message": "Velg dette alternativet hvis du vil flytte den importerte filens innhold til en $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Filen inneholder utildelte elementer." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index d076ef01ef2..9170fd20734 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index 4b38d8491aa..c01d1edf217 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -1022,7 +1022,7 @@ "message": "Opslaan in kluisopties" }, "addLoginNotificationDesc": { - "message": "\"Melding bij nieuwe login\" vraagt automatisch om nieuwe sites in de kluis op te slaan wanneer je ergens voor de eerste keer inlogt." + "message": "Vraag om een item toe te voegen als deze niet in je kluis is gevonden." }, "addLoginNotificationDescAlt": { "message": "Vraag om een item toe te voegen als het niet is gevonden is je kluis. Dit geld voor alle ingelogde accounts." @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Collectie selecteren" }, - "importTargetHint": { - "message": "Kies deze optie als je de geïmporteerde bestandsinhoud wilt verplaatsen naar een $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Kies deze optie als je de geïmporteerde bestandsinhoud naar een collectie wilt verplaatsen" + }, + "importTargetHintFolder": { + "message": "Kies deze optie als je de geïmporteerde bestandsinhoud naar een map wilt verplaatsen" }, "importUnassignedItemsError": { "message": "Bestand bevat niet-toegewezen items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Minder weergeven" + }, + "moreBreadcrumbs": { + "message": "Meer broodkruimels", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index d076ef01ef2..9170fd20734 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json index d076ef01ef2..9170fd20734 100644 --- a/apps/browser/src/_locales/or/messages.json +++ b/apps/browser/src/_locales/or/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index 97875409529..71e07ceb352 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -270,7 +270,7 @@ "message": "Uzyskaj podpowiedź do hasła głównego" }, "continue": { - "message": "Kontynuuj" + "message": "Przejdź" }, "sendVerificationCode": { "message": "Wyślij kod weryfikacyjny na adres e-mail" @@ -1022,10 +1022,10 @@ "message": "Opcje zapisywania w sejfie" }, "addLoginNotificationDesc": { - "message": "Proponuj dodanie elementu, jeśli nie ma go w sejfie." + "message": "Proponuj zapisywanie danych logowania, jeśli nie ma ich w sejfie." }, "addLoginNotificationDescAlt": { - "message": "Proponuj dodanie elementu, jeśli nie ma go w sejfie. Dotyczy wszystkich zalogowanych kont." + "message": "Proponuj zapisywanie danych logowania, jeśli nie ma ich w sejfie. Dotyczy wszystkich zalogowanych kont." }, "showCardsInVaultViewV2": { "message": "Zawsze pokazuj karty w sugestiach autouzupełniania" @@ -1405,7 +1405,7 @@ "message": "Specjalne opcje logowania dwustopniowego, takie jak YubiKey i Duo." }, "ppremiumSignUpReports": { - "message": "Raporty bezpieczeństwa haseł, stanu konta i raporty wycieków danych, aby Twoje dane były bezpieczne." + "message": "Raporty bezpieczeństwa haseł, konta i wycieków danych, aby Twoje dane były bezpieczne." }, "ppremiumSignUpTotp": { "message": "Generator kodów weryfikacyjnych TOTP dla danych logowania w sejfie." @@ -1684,7 +1684,7 @@ "message": "Możesz wyłączyć autouzupełnianie po załadowaniu strony dla poszczególnych elementów w opcjach konkretnych elementów." }, "itemAutoFillOnPageLoad": { - "message": "Automatycznie uzupełniaj po załadowaniu strony (jeśli włączono w opcjach)" + "message": "Uzupełniaj po załadowaniu strony (jeśli włączono w opcjach)" }, "autoFillOnPageLoadUseDefault": { "message": "Użyj domyślnego ustawienia" @@ -1758,7 +1758,7 @@ "message": "Kliknięcie poza okno, w celu sprawdzenia wiadomość z kodem weryfikacyjnym spowoduje, że zostanie ono zamknięte. Czy chcesz otworzyć nowe okno tak, aby się nie zamknęło?" }, "popupU2fCloseMessage": { - "message": "Ta przeglądarka nie może przetworzyć żądania U2F w wyskakującym oknie. Czy chcesz otworzyć nowe okno przeglądarki, aby zalogować się przy pomocy klucza U2F?" + "message": "Przeglądarka nie może przetworzyć żądań U2F. Czy chcesz otworzyć nowe okno, aby zalogować się za pomocą U2F?" }, "enableFavicon": { "message": "Pokaż ikony stron internetowych" @@ -3467,7 +3467,7 @@ "message": "Prośba została wysłana" }, "loginRequestApprovedForEmailOnDevice": { - "message": "Logowanie potwierdzone dla $EMAIL$ na $DEVICE$", + "message": "Potwierdzono logowanie $EMAIL$ ($DEVICE$)", "placeholders": { "email": { "content": "$1", @@ -3480,7 +3480,7 @@ } }, "youDeniedLoginAttemptFromAnotherDevice": { - "message": "Odrzucono próby logowania z innego urządzenia. Jeśli to naprawdę Ty, spróbuj ponownie zalogować się za pomocą urządzenia." + "message": "Odrzucono próbę logowania z innego urządzenia. Zaloguj się ponownie z tego urządzenia." }, "device": { "message": "Urządzenie" @@ -3773,7 +3773,7 @@ "message": "Organizacja nie jest zaufana" }, "emergencyAccessTrustWarning": { - "message": "Dla bezpieczeństwa Twojego konta potwierdź tylko, jeśli przyznano temu użytkownikowi dostęp awaryjny i jego odcisk palca pasuje do tego, co widnieje na jego koncie" + "message": "Potwierdź tylko wtedy, gdy chcesz przyznać użytkownikowi dostęp awaryjny i jego unikalny identyfikator konta jest prawidłowy." }, "orgTrustWarning": { "message": "Kontynuuj tylko wtedy, gdy jesteś członkiem organizacji, masz włączone odzyskiwanie konta, a unikalny identyfikator pasuje do organizacji." @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Wybierz kolekcję" }, - "importTargetHint": { - "message": "Wybierz tę opcję, jeśli chcesz przenieść dane do $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Wybierz tę opcję, jeśli chcesz przenieść dane do kolekcji" + }, + "importTargetHintFolder": { + "message": "Wybierz tę opcję, jeśli chcesz przenieść dane do folderu" }, "importUnassignedItemsError": { "message": "Plik zawiera nieprzypisane elementy." @@ -4185,7 +4181,7 @@ "message": "Klucz dostępu" }, "accessing": { - "message": "Logowanie na" + "message": "Serwer" }, "loggedInExclamation": { "message": "Zalogowano!" @@ -4197,7 +4193,7 @@ "message": "Klucz dostępu nie zostanie skopiowany do sklonowanego elementu. Czy chcesz kontynuować klonowanie elementu?" }, "passkeyFeatureIsNotImplementedForAccountsWithoutMasterPassword": { - "message": "Weryfikacja jest wymagana przez stronę inicjującą. Ta funkcja nie jest jeszcze zaimplementowana dla kont bez hasła głównego." + "message": "Weryfikacja jest wymagana przez stronę inicjującą. Ta funkcja nie jest jeszcze dostępna dla kont bez hasła głównego." }, "logInWithPasskeyQuestion": { "message": "Zalogować się kluczem dostępu?" @@ -4439,7 +4435,7 @@ "description": "Title for the dialog that appears when the user has not granted the extension permission to set privacy settings" }, "privacyPermissionAdditionNotGrantedDescription": { - "message": "Musisz przyznać Bitwarden uprawnienia do prywatności przeglądarki, aby ustawić go jako domyślnego menedżera haseł.", + "message": "Aby ustawić Bitwarden jako domyślny menedżer haseł, przyznaj rozszerzeniu uprawnienie do zmiany ustawień prywatności.", "description": "Description for the dialog that appears when the user has not granted the extension permission to set privacy settings" }, "makeDefault": { @@ -4990,7 +4986,7 @@ } }, "reorderToggleButton": { - "message": "Zmień kolejność pola $LABEL$. Użyj klawiszy ze strzałkami, aby przenieść element w górę lub w dół.", + "message": "Reorder $LABEL$. Use arrow key to move item up or down.", "placeholders": { "label": { "content": "$1", @@ -4999,7 +4995,7 @@ } }, "reorderWebsiteUriButton": { - "message": "Zmień kolejność URI stron internetowych. Użyj klawiszy ze strzałkami, aby przenieść element w górę lub w dół." + "message": "Zmień kolejność stron internetowych. Użyj klawiszy ze strzałkami, aby przenieść element w górę lub w dół." }, "reorderFieldUp": { "message": "Pole $LABEL$ zostało przeniesione w górę. Pozycja $INDEX$ z $LENGTH$", @@ -5427,7 +5423,7 @@ "message": "Klucz SSH został zaimportowany" }, "cannotRemoveViewOnlyCollections": { - "message": "Nie można usunąć kolekcji z uprawnieniami tylko do przeglądania: $COLLECTIONS$", + "message": "Nie możesz usunąć następujących kolekcji z uprawnieniami tylko do odczytu: $COLLECTIONS$", "placeholders": { "collections": { "content": "$1", @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Pokaż mniej" + }, + "moreBreadcrumbs": { + "message": "Więcej nawigacji", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index ac5afdc9fce..ef13c22f3dc 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -1037,7 +1037,7 @@ "message": "Exibir itens de cartão em páginas com abas para simplificar o preenchimento automático" }, "showIdentitiesInVaultViewV2": { - "message": "Sempre mostrar identidades como sugestões de preenchimento automático na Tela do Cofre" + "message": "Sempre mostrar identidades como sugestões de preenchimento automático na tela do Cofre" }, "showIdentitiesCurrentTab": { "message": "Exibir Identidades na Aba Atual" @@ -3785,11 +3785,11 @@ "message": "Trust user" }, "sendsTitleNoItems": { - "message": "Envie informações sensíveis com segurança", + "message": "Envie informações confidencias, com segurança", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendsBodyNoItems": { - "message": "Compartilhe arquivos e dados com segurança, com qualquer pessoa e em qualquer plataforma. Suas informações ficarão sempre criptografadas de ponta a ponta, garantindo exposição mínima.", + "message": "Compartilhe arquivos e dados de forma segura com qualquer pessoa, em qualquer plataforma. Suas informações permanecerão criptografadas de ponta a ponta enquanto limitam a exposição.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "inputRequired": { @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Selecione uma coleção" }, - "importTargetHint": { - "message": "Selecione esta opção se você quer o conteúdo do arquivo importado movido para $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Arquivo contém itens não atribuídos." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index d3ce5ec3e48..5ab801b268f 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -65,7 +65,7 @@ "message": "Uma dica da palavra-passe mestra pode ajudá-lo a lembrar-se da sua palavra-passe, caso se esqueça dela." }, "masterPassHintText": { - "message": "Se se esquecer da sua palavra-passe, a dica da palavra-passe pode ser enviada para o seu e-mail. Máximo de $CURRENT$/$MAXIMUM$ carateres.", + "message": "Se se esquecer da sua palavra-passe, a dica da palavra-passe pode ser enviada para o seu e-mail. Máximo de $CURRENT$/$MAXIMUM$ caracteres.", "placeholders": { "current": { "content": "$1", @@ -490,7 +490,7 @@ "description": "Card header for password generator include block" }, "uppercaseDescription": { - "message": "Incluir carateres em maiúsculas", + "message": "Incluir caracteres em maiúsculas", "description": "Tooltip for the password generator uppercase character checkbox" }, "uppercaseLabel": { @@ -498,7 +498,7 @@ "description": "Label for the password generator uppercase character checkbox" }, "lowercaseDescription": { - "message": "Incluir carateres em minúsculas", + "message": "Incluir caracteres em minúsculas", "description": "Full description for the password generator lowercase character checkbox" }, "lowercaseLabel": { @@ -514,7 +514,7 @@ "description": "Label for the password generator numbers checkbox" }, "specialCharactersDescription": { - "message": "Incluir carateres especiais", + "message": "Incluir caracteres especiais", "description": "Full description for the password generator special characters checkbox" }, "numWords": { @@ -534,10 +534,10 @@ "message": "Mínimo de números" }, "minSpecial": { - "message": "Mínimo de carateres especiais" + "message": "Mínimo de caracteres especiais" }, "avoidAmbiguous": { - "message": "Evitar carateres ambíguos", + "message": "Evitar caracteres ambíguos", "description": "Label for the avoid ambiguous characters checkbox." }, "generatorPolicyInEffect": { @@ -783,7 +783,7 @@ "message": "É necessário reescrever a palavra-passe mestra." }, "masterPasswordMinlength": { - "message": "A palavra-passe mestra deve ter pelo menos $VALUE$ carateres.", + "message": "A palavra-passe mestra deve ter pelo menos $VALUE$ caracteres.", "description": "The Master Password must be at least a specific number of characters long.", "placeholders": { "value": { @@ -2344,16 +2344,16 @@ } }, "policyInEffectUppercase": { - "message": "Contém um ou mais carateres em maiúsculas" + "message": "Contém um ou mais caracteres em maiúsculas" }, "policyInEffectLowercase": { - "message": "Contém um ou mais carateres em minúsculas" + "message": "Contém um ou mais caracteres em minúsculas" }, "policyInEffectNumbers": { "message": "Contém um ou mais números" }, "policyInEffectSpecial": { - "message": "Contém um ou mais dos seguintes carateres especiais $CHARS$", + "message": "Contém um ou mais dos seguintes caracteres especiais $CHARS$", "placeholders": { "chars": { "content": "$1", @@ -3097,7 +3097,7 @@ "message": "Saiu da organização." }, "toggleCharacterCount": { - "message": "Mostrar/ocultar contagem de carateres" + "message": "Mostrar/ocultar contagem de caracteres" }, "sessionTimeout": { "message": "A sua sessão expirou. Por favor, volte atrás e tente iniciar sessão novamente." @@ -3173,7 +3173,7 @@ } }, "passwordLengthRecommendationHint": { - "message": " Utilize $RECOMMENDED$ carateres ou mais para gerar uma palavra-passe forte.", + "message": " Utilize $RECOMMENDED$ caracteres ou mais para gerar uma palavra-passe forte.", "description": "Appended to `spinboxBoundariesHint` to recommend a length to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -3513,7 +3513,7 @@ "message": "A sua palavra-passe mestra não pode ser recuperada se a esquecer!" }, "characterMinimum": { - "message": "$LENGTH$ carateres no mínimo", + "message": "$LENGTH$ caracteres no mínimo", "placeholders": { "length": { "content": "$1", @@ -3802,7 +3802,7 @@ "message": "Procurar" }, "inputMinLength": { - "message": "O campo deve ter pelo menos $COUNT$ carateres.", + "message": "O campo deve ter pelo menos $COUNT$ caracteres.", "placeholders": { "count": { "content": "$1", @@ -3811,7 +3811,7 @@ } }, "inputMaxLength": { - "message": "O campo não pode exceder os $COUNT$ carateres de comprimento.", + "message": "O campo não pode exceder os $COUNT$ caracteres de comprimento.", "placeholders": { "count": { "content": "$1", @@ -3820,7 +3820,7 @@ } }, "inputForbiddenCharacters": { - "message": "Não são permitidos os seguintes carateres: $CHARACTERS$", + "message": "Não são permitidos os seguintes caracteres: $CHARACTERS$", "placeholders": { "characters": { "content": "$1", @@ -3829,7 +3829,7 @@ } }, "inputMinValue": { - "message": "O valor do campo tem de ser, pelo menos, $MIN$ carateres.", + "message": "O valor do campo tem de ser, pelo menos, $MIN$ caracteres.", "placeholders": { "min": { "content": "$1", @@ -3838,7 +3838,7 @@ } }, "inputMaxValue": { - "message": "O valor do campo não pode exceder os $MAX$ carateres.", + "message": "O valor do campo não pode exceder os $MAX$ caracteres.", "placeholders": { "max": { "content": "$1", @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Selecionar uma coleção" }, - "importTargetHint": { - "message": "Selecione esta opção se pretender que o conteúdo do ficheiro importado seja transferido para $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Selecione esta opção se pretender que o conteúdo do ficheiro importado seja transferido para uma coleção" + }, + "importTargetHintFolder": { + "message": "Selecione esta opção se pretender que o conteúdo do ficheiro importado seja transferido para uma pasta" }, "importUnassignedItemsError": { "message": "O ficheiro contém itens não atribuídos." @@ -5163,10 +5159,10 @@ "message": "Ficheiro guardado no dispositivo. Gira-o a partir das transferências do seu dispositivo." }, "showCharacterCount": { - "message": "Mostrar contagem de carateres" + "message": "Mostrar contagem de caracteres" }, "hideCharacterCount": { - "message": "Ocultar contagem de carateres" + "message": "Ocultar contagem de caracteres" }, "itemsInTrash": { "message": "Itens no lixo" @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Mostrar menos" + }, + "moreBreadcrumbs": { + "message": "Mais da navegação estrutural", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index 741b491da13..d2769583bcb 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index 88fa89ac73e..d18cf24eb9b 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Выберите коллекцию" }, - "importTargetHint": { - "message": "Выберите эту опцию, если хотите, чтобы содержимое импортированного файла было перемещено в $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Выберите эту опцию, если хотите, чтобы содержимое импортированного файла было перемещено в коллекцию" + }, + "importTargetHintFolder": { + "message": "Выберите эту опцию, если хотите, чтобы содержимое импортированного файла было перемещено в папку" }, "importUnassignedItemsError": { "message": "Файл содержит неназначенные элементы." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Меньше" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index dd2df6f309c..0e4a60b8261 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index e12a0c97ac4..98babaff777 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Vyberte zbierku" }, - "importTargetHint": { - "message": "Zvoľte túto možnosť, ak chcete obsah importovaného súboru presunúť do $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Zvoľte túto možnosť, ak chcete obsah importovaného súboru presunúť do zbierky" + }, + "importTargetHintFolder": { + "message": "Zvoľte túto možnosť, ak chcete obsah importovaného súboru presunúť do priečinka" }, "importUnassignedItemsError": { "message": "Súbor obsahuje nepriradené položky." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Zobraziť menej" + }, + "moreBreadcrumbs": { + "message": "Viac", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 3af24b85889..0a7387ee831 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 12d0c5b015e..e058a805533 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Изабери колекцију" }, - "importTargetHint": { - "message": "Изаберите ову опцију ако желите да се садржај увезене датотеке премести у $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Датотека садржи недодељене ставке." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index 1174b6ac077..d6a0b691572 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Välj en samling" }, - "importTargetHint": { - "message": "Välj det här alternativet om du vill att innehållet i den importerade filen ska flyttas till en $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Välj detta alternativ om du vill att innehållet i den importerade filen ska flyttas till en samling" + }, + "importTargetHintFolder": { + "message": "Välj detta alternativ om du vill att innehållet i den importerade filen ska flyttas till en mapp" }, "importUnassignedItemsError": { "message": "Filen innehåller otilldelade objekt." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Visa mindre" + }, + "moreBreadcrumbs": { + "message": "Fler länkstigar", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index d076ef01ef2..9170fd20734 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index 2cea91a424e..02eb0664472 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index 22a083959a9..4ed2fa9ef11 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Bir koleksiyon seçin" }, - "importTargetHint": { - "message": "İçe aktarılan dosya içeriklerinin $DESTINATION$ konumuna taşınmasını istiyorsanız bu seçeneği seçin", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "İçe aktarılan dosya içeriklerinin bir koleksiyona taşınmasını istiyorsanız bu seçeneği seçin" + }, + "importTargetHintFolder": { + "message": "İçe aktarılan dosya içeriklerinin bir klasöre taşınmasını istiyorsanız bu seçeneği seçin" }, "importUnassignedItemsError": { "message": "Dosya atanmamış öğeler içeriyor." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Daha az göster" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index 537a9bfd5cf..79353e6af91 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Вибрати збірку" }, - "importTargetHint": { - "message": "Оберіть цю опцію, якщо ви хочете, щоб вміст імпортованого файлу було збережено в $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Файл містить непризначені записи." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Згорнути" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index 7a596d7c23d..ed717455620 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -216,7 +216,7 @@ "description": "Aria label for the heading displayed the inline menu for totp code autofill" }, "generatePasswordCopied": { - "message": "Tạo mật khẩu (đã sao chép)" + "message": "Tạo mật khẩu (cũng sao chép)" }, "copyElementIdentifier": { "message": "Sao chép tên trường tùy chỉnh" @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Chọn bộ sưu tập" }, - "importTargetHint": { - "message": "Chọn tùy chọn này nếu bạn muốn nội dung của tệp đã nhập được di chuyển đến $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Tập tin chứa các mục không xác định." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Thu gọn" + }, + "moreBreadcrumbs": { + "message": "Thêm mục điều hướng", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index fff87a949ce..2d2591b403a 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "选择一个集合" }, - "importTargetHint": { - "message": "如果您希望将导入的文件内容移动到某个 $DESTINATION$,请选择此选项", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "如果希望将导入的文件内容移动到集合中,请选择此选项" + }, + "importTargetHintFolder": { + "message": "如果希望将导入的文件内容移动到文件夹中,请选择此选项" }, "importUnassignedItemsError": { "message": "文件包含未分配项目。" @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "显示更少" + }, + "moreBreadcrumbs": { + "message": "进一步的指引", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index e8873d74e92..97ef68eb6c2 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "選擇一個分類" }, - "importTargetHint": { - "message": "如果您要將匯入檔案的內容移動到 $DESTINATION$,請選擇此選項", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "檔案包含未指派項目。" @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/auth/popup/settings/account-security.component.spec.ts b/apps/browser/src/auth/popup/settings/account-security.component.spec.ts index 014f2a7638b..63666440a76 100644 --- a/apps/browser/src/auth/popup/settings/account-security.component.spec.ts +++ b/apps/browser/src/auth/popup/settings/account-security.component.spec.ts @@ -24,7 +24,6 @@ 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 { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { MessageSender } from "@bitwarden/common/platform/messaging"; import { Utils } from "@bitwarden/common/platform/misc/utils"; @@ -79,7 +78,6 @@ describe("AccountSecurityComponent", () => { { provide: PlatformUtilsService, useValue: platformUtilsService }, { provide: PolicyService, useValue: policyService }, { provide: PopupRouterCacheService, useValue: mock() }, - { provide: StateService, useValue: mock() }, { provide: ToastService, useValue: mock() }, { provide: UserVerificationService, useValue: mock() }, { provide: VaultTimeoutService, useValue: mock() }, diff --git a/apps/browser/src/auth/popup/settings/account-security.component.ts b/apps/browser/src/auth/popup/settings/account-security.component.ts index b41cfe14c4f..72a389ecf71 100644 --- a/apps/browser/src/auth/popup/settings/account-security.component.ts +++ b/apps/browser/src/auth/popup/settings/account-security.component.ts @@ -44,9 +44,9 @@ import { import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { DialogRef, @@ -149,7 +149,6 @@ export class AccountSecurityComponent implements OnInit, OnDestroy { public messagingService: MessagingService, private environmentService: EnvironmentService, private keyService: KeyService, - private stateService: StateService, private userVerificationService: UserVerificationService, private dialogService: DialogService, private changeDetectorRef: ChangeDetectorRef, @@ -159,6 +158,7 @@ export class AccountSecurityComponent implements OnInit, OnDestroy { private vaultNudgesService: NudgesService, private validationService: ValidationService, private configService: ConfigService, + private logService: LogService, ) {} async ngOnInit() { @@ -683,10 +683,16 @@ export class AccountSecurityComponent implements OnInit, OnDestroy { } async openAcctFingerprintDialog() { - const activeUserId = await firstValueFrom( - this.accountService.activeAccount$.pipe(map((a) => a?.id)), - ); + const activeUserId = await firstValueFrom(getUserId(this.accountService.activeAccount$)); const publicKey = await firstValueFrom(this.keyService.userPublicKey$(activeUserId)); + if (publicKey == null) { + this.logService.error( + "[AccountSecurityComponent] No public key available for the user: " + + activeUserId + + " fingerprint can't be displayed.", + ); + return; + } const fingerprint = await this.keyService.getFingerprint(activeUserId, publicKey); const dialogRef = FingerprintDialogComponent.open(this.dialogService, { diff --git a/apps/browser/src/autofill/overlay/inline-menu/content/autofill-inline-menu-content.service.spec.ts b/apps/browser/src/autofill/overlay/inline-menu/content/autofill-inline-menu-content.service.spec.ts index 62f9dbec824..2c9484c3a8b 100644 --- a/apps/browser/src/autofill/overlay/inline-menu/content/autofill-inline-menu-content.service.spec.ts +++ b/apps/browser/src/autofill/overlay/inline-menu/content/autofill-inline-menu-content.service.spec.ts @@ -41,6 +41,10 @@ describe("AutofillInlineMenuContentService", () => { autofillInlineMenuContentService as any, "sendExtensionMessage", ); + jest.spyOn(autofillInlineMenuContentService as any, "getPageIsOpaque"); + jest + .spyOn(autofillInlineMenuContentService as any, "getPageTopLayerInUse") + .mockResolvedValue(false); }); afterEach(() => { @@ -386,30 +390,45 @@ describe("AutofillInlineMenuContentService", () => { expect(globalThis.document.body.insertBefore).not.toHaveBeenCalled(); }); + it("closes the inline menu if the page has content in the top layer", async () => { + document.querySelector("html").style.opacity = "1"; + document.body.style.opacity = "1"; + + jest + .spyOn(autofillInlineMenuContentService as any, "getPageTopLayerInUse") + .mockResolvedValue(true); + + await autofillInlineMenuContentService["handlePageMutations"]([mockBodyMutationRecord]); + + expect(autofillInlineMenuContentService["getPageIsOpaque"]).toHaveReturnedWith(true); + expect(autofillInlineMenuContentService["closeInlineMenu"]).toHaveBeenCalled(); + }); + it("closes the inline menu if the page body is not sufficiently opaque", async () => { document.querySelector("html").style.opacity = "0.9"; document.body.style.opacity = "0"; - autofillInlineMenuContentService["handlePageMutations"]([mockBodyMutationRecord]); + await autofillInlineMenuContentService["handlePageMutations"]([mockBodyMutationRecord]); - expect(autofillInlineMenuContentService["pageIsOpaque"]).toBe(false); + expect(autofillInlineMenuContentService["getPageIsOpaque"]).toHaveReturnedWith(false); expect(autofillInlineMenuContentService["closeInlineMenu"]).toHaveBeenCalled(); }); it("closes the inline menu if the page html is not sufficiently opaque", async () => { document.querySelector("html").style.opacity = "0.3"; document.body.style.opacity = "0.7"; - autofillInlineMenuContentService["handlePageMutations"]([mockHTMLMutationRecord]); + await autofillInlineMenuContentService["handlePageMutations"]([mockHTMLMutationRecord]); - expect(autofillInlineMenuContentService["pageIsOpaque"]).toBe(false); + expect(autofillInlineMenuContentService["getPageIsOpaque"]).toHaveReturnedWith(false); expect(autofillInlineMenuContentService["closeInlineMenu"]).toHaveBeenCalled(); }); it("does not close the inline menu if the page html and body is sufficiently opaque", async () => { document.querySelector("html").style.opacity = "0.9"; document.body.style.opacity = "1"; - autofillInlineMenuContentService["handlePageMutations"]([mockBodyMutationRecord]); + await autofillInlineMenuContentService["handlePageMutations"]([mockBodyMutationRecord]); + await waitForIdleCallback(); - expect(autofillInlineMenuContentService["pageIsOpaque"]).toBe(true); + expect(autofillInlineMenuContentService["getPageIsOpaque"]).toHaveReturnedWith(true); expect(autofillInlineMenuContentService["closeInlineMenu"]).not.toHaveBeenCalled(); }); diff --git a/apps/browser/src/autofill/overlay/inline-menu/content/autofill-inline-menu-content.service.ts b/apps/browser/src/autofill/overlay/inline-menu/content/autofill-inline-menu-content.service.ts index de401bf7e28..c531215af88 100644 --- a/apps/browser/src/autofill/overlay/inline-menu/content/autofill-inline-menu-content.service.ts +++ b/apps/browser/src/autofill/overlay/inline-menu/content/autofill-inline-menu-content.service.ts @@ -33,7 +33,6 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte private listElement?: HTMLElement; private htmlMutationObserver: MutationObserver; private bodyMutationObserver: MutationObserver; - private pageIsOpaque = true; private inlineMenuElementsMutationObserver: MutationObserver; private containerElementMutationObserver: MutationObserver; private mutationObserverIterations = 0; @@ -52,7 +51,6 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte }; constructor() { - this.checkPageOpacity(); this.setupMutationObserver(); } @@ -405,20 +403,35 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte }); }; - private checkPageOpacity = () => { - this.pageIsOpaque = this.getPageIsOpaque(); + private checkPageRisks = async () => { + const pageIsOpaque = await this.getPageIsOpaque(); + const pageTopLayerInUse = await this.getPageTopLayerInUse(); - if (!this.pageIsOpaque) { + const risksFound = !pageIsOpaque || pageTopLayerInUse; + + if (risksFound) { this.closeInlineMenu(); } + + return risksFound; + }; + + /* + * Checks for known risks at the page level + */ + private handlePageMutations = async (mutations: MutationRecord[]) => { + if (mutations.some(({ type }) => type === "attributes")) { + await this.checkPageRisks(); + } }; - private handlePageMutations = (mutations: MutationRecord[]) => { - for (const mutation of mutations) { - if (mutation.type === "attributes") { - this.checkPageOpacity(); - } - } + /** + * Checks if the page top layer has content (will obscure/overlap the inline menu) + */ + private getPageTopLayerInUse = () => { + const pageHasOpenPopover = !!globalThis.document.querySelector(":popover-open"); + + return pageHasOpenPopover; }; /** @@ -427,7 +440,7 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte * of parents below the body. Assumes the target element will be a direct child of the page * `body` (enforced elsewhere). */ - private getPageIsOpaque() { + private getPageIsOpaque = () => { // These are computed style values, so we don't need to worry about non-float values // for `opacity`, here const htmlOpacity = globalThis.window.getComputedStyle( @@ -441,17 +454,16 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte const opacityThreshold = 0.6; return parseFloat(htmlOpacity) > opacityThreshold && parseFloat(bodyOpacity) > opacityThreshold; - } + }; /** * Processes the mutation of the element that contains the inline menu. Will trigger when an * idle moment in the execution of the main thread is detected. */ private processContainerElementMutation = async (containerElement: HTMLElement) => { - // If the computed opacity of the body and parent is not sufficiently opaque, tear - // down and prevent building the inline menu experience. - this.checkPageOpacity(); - if (!this.pageIsOpaque) { + // If the page contains risks, tear down and prevent building the inline menu experience. + const pageRisksFound = await this.checkPageRisks(); + if (pageRisksFound) { return; } diff --git a/apps/browser/src/autofill/popup/fido2/fido2.component.ts b/apps/browser/src/autofill/popup/fido2/fido2.component.ts index ac38fe2f894..11e00749bdf 100644 --- a/apps/browser/src/autofill/popup/fido2/fido2.component.ts +++ b/apps/browser/src/autofill/popup/fido2/fido2.component.ts @@ -18,6 +18,7 @@ import { } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { NoResults } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; @@ -36,7 +37,6 @@ import { SecureNoteView } from "@bitwarden/common/vault/models/view/secure-note. import { ButtonModule, DialogService, - Icons, ItemModule, NoItemsModule, SearchModule, @@ -102,7 +102,7 @@ export class Fido2Component implements OnInit, OnDestroy { protected equivalentDomainsURL: string; protected hostname: string; protected loading = false; - protected noResultsIcon = Icons.NoResults; + protected noResultsIcon = NoResults; protected passkeyAction: PasskeyActionValue = PasskeyActions.Register; protected PasskeyActions = PasskeyActions; protected hasSearched = false; diff --git a/apps/browser/src/autofill/utils/index.ts b/apps/browser/src/autofill/utils/index.ts index 614a5b014f2..0e102dcfd99 100644 --- a/apps/browser/src/autofill/utils/index.ts +++ b/apps/browser/src/autofill/utils/index.ts @@ -37,9 +37,7 @@ export function requestIdleCallbackPolyfill( return globalThis.requestIdleCallback(() => callback(), options); } - const timeoutDelay = options?.timeout || 1; - - return globalThis.setTimeout(() => callback(), timeoutDelay); + return globalThis.setTimeout(() => callback(), 1); } /** diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 915cf6cc432..3511833ae8e 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -146,23 +146,6 @@ import { DefaultSdkService } from "@bitwarden/common/platform/services/sdk/defau import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; import { SystemService } from "@bitwarden/common/platform/services/system.service"; import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service"; -import { - ActiveUserStateProvider, - DefaultStateService, - DerivedStateProvider, - GlobalStateProvider, - SingleUserStateProvider, - StateEventRunnerService, - StateProvider, -} from "@bitwarden/common/platform/state"; -/* eslint-disable import/no-restricted-paths -- We need the implementation to inject, but generally these should not be accessed */ -import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-active-user-state.provider"; -import { DefaultGlobalStateProvider } from "@bitwarden/common/platform/state/implementations/default-global-state.provider"; -import { DefaultSingleUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-single-user-state.provider"; -import { DefaultStateProvider } from "@bitwarden/common/platform/state/implementations/default-state.provider"; -import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/inline-derived-state"; -import { StateEventRegistrarService } from "@bitwarden/common/platform/state/state-event-registrar.service"; -/* eslint-enable import/no-restricted-paths */ import { PrimarySecondaryStorageService } from "@bitwarden/common/platform/storage/primary-secondary-storage.service"; import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service"; import { SyncService } from "@bitwarden/common/platform/sync"; @@ -235,6 +218,24 @@ import { KeyService as KeyServiceAbstraction, } from "@bitwarden/key-management"; import { BackgroundSyncService } from "@bitwarden/platform/background-sync"; +import { + ActiveUserStateProvider, + DerivedStateProvider, + GlobalStateProvider, + SingleUserStateProvider, + StateEventRunnerService, + StateProvider, +} from "@bitwarden/state"; +import { + DefaultActiveUserStateProvider, + DefaultGlobalStateProvider, + DefaultSingleUserStateProvider, + DefaultStateEventRegistrarService, + DefaultStateEventRunnerService, + DefaultStateProvider, + DefaultStateService, + InlineDerivedStateProvider, +} from "@bitwarden/state-internal"; import { IndividualVaultExportService, IndividualVaultExportServiceAbstraction, @@ -301,7 +302,6 @@ import { OffscreenStorageService } from "../platform/storage/offscreen-storage.s import { SyncServiceListener } from "../platform/sync/sync-service.listener"; import { BrowserSystemNotificationService } from "../platform/system-notifications/browser-system-notification.service"; import { fromChromeRuntimeMessaging } from "../platform/utils/from-chrome-runtime-messaging"; -import { VaultFilterService } from "../vault/services/vault-filter.service"; import CommandsBackground from "./commands.background"; import IdleBackground from "./idle.background"; @@ -367,7 +367,6 @@ export default class MainBackground { providerService: ProviderServiceAbstraction; keyConnectorService: KeyConnectorServiceAbstraction; userVerificationService: UserVerificationServiceAbstraction; - vaultFilterService: VaultFilterService; usernameGenerationService: UsernameGenerationServiceAbstraction; encryptService: EncryptService; folderApiService: FolderApiServiceAbstraction; @@ -573,12 +572,12 @@ export default class MainBackground { this.logService, ); - const stateEventRegistrarService = new StateEventRegistrarService( + const stateEventRegistrarService = new DefaultStateEventRegistrarService( this.globalStateProvider, storageServiceProvider, ); - this.stateEventRunnerService = new StateEventRunnerService( + this.stateEventRunnerService = new DefaultStateEventRunnerService( this.globalStateProvider, storageServiceProvider, ); @@ -783,6 +782,7 @@ export default class MainBackground { this.accountService, this.kdfConfigService, this.keyService, + this.stateProvider, ); this.passwordStrengthService = new PasswordStrengthService(); @@ -921,18 +921,6 @@ export default class MainBackground { this.biometricsService, ); - this.vaultFilterService = new VaultFilterService( - this.organizationService, - this.folderService, - this.cipherService, - this.collectionService, - this.policyService, - this.stateProvider, - this.accountService, - this.configService, - this.i18nService, - ); - this.vaultSettingsService = new VaultSettingsService( this.stateProvider, this.restrictedItemTypesService, @@ -1398,6 +1386,11 @@ export default class MainBackground { this.authService, ); + // Synchronous startup + if (this.webPushConnectionService instanceof WorkerWebPushConnectionService) { + this.webPushConnectionService.start(); + } + // Putting this here so that all other services are initialized prior to trying to hook up // subscriptions to the notification chrome events. this.initNotificationSubscriptions(); @@ -1617,7 +1610,6 @@ export default class MainBackground { this.cipherService.clear(userBeingLoggedOut), this.folderService.clear(userBeingLoggedOut), this.vaultTimeoutSettingsService.clear(userBeingLoggedOut), - this.vaultFilterService.clear(), this.biometricStateService.logout(userBeingLoggedOut), this.popupViewCacheBackgroundService.clearState(), /* We intentionally do not clear: diff --git a/apps/browser/src/manifest.json b/apps/browser/src/manifest.json index 2820be6dfe6..8eb970de6d2 100644 --- a/apps/browser/src/manifest.json +++ b/apps/browser/src/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_extName__", "short_name": "Bitwarden", - "version": "2025.8.0", + "version": "2025.8.1", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/browser/src/manifest.v3.json b/apps/browser/src/manifest.v3.json index 5af56a1ad96..c4c47f7aacf 100644 --- a/apps/browser/src/manifest.v3.json +++ b/apps/browser/src/manifest.v3.json @@ -3,7 +3,7 @@ "minimum_chrome_version": "102.0", "name": "__MSG_extName__", "short_name": "Bitwarden", - "version": "2025.8.0", + "version": "2025.8.1", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", 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 7455921b08b..a7103fdfd3c 100644 --- a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts +++ b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts @@ -4,6 +4,16 @@ import { Component, importProvidersFrom } from "@angular/core"; import { RouterModule } from "@angular/router"; import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular"; +import { + GeneratorActive, + GeneratorInactive, + SendActive, + SendInactive, + SettingsActive, + SettingsInactive, + VaultActive, + VaultInactive, +} from "@bitwarden/assets/svg"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; @@ -13,7 +23,6 @@ import { BannerModule, ButtonModule, I18nMockService, - Icons, IconButtonModule, ItemModule, NoItemsModule, @@ -404,26 +413,26 @@ const navButtons = (showBerry = false) => [ { label: "vault", page: "/tabs/vault", - icon: Icons.VaultInactive, - iconActive: Icons.VaultActive, + icon: VaultInactive, + iconActive: VaultActive, }, { label: "generator", page: "/tabs/generator", - icon: Icons.GeneratorInactive, - iconActive: Icons.GeneratorActive, + icon: GeneratorInactive, + iconActive: GeneratorActive, }, { label: "send", page: "/tabs/send", - icon: Icons.SendInactive, - iconActive: Icons.SendActive, + icon: SendInactive, + iconActive: SendActive, }, { label: "settings", page: "/tabs/settings", - icon: Icons.SettingsInactive, - iconActive: Icons.SettingsActive, + icon: SettingsInactive, + iconActive: SettingsActive, showBerry: showBerry, }, ]; diff --git a/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts index 8a897e2e21b..742b12bb7ad 100644 --- a/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts +++ b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts @@ -3,8 +3,9 @@ import { Component, Input } from "@angular/core"; import { RouterModule } from "@angular/router"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { Icon } from "@bitwarden/assets/svg"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { Icon, IconModule, LinkModule } from "@bitwarden/components"; +import { IconModule, LinkModule } from "@bitwarden/components"; export type NavButton = { label: string; diff --git a/apps/browser/src/platform/storage/background-memory-storage.service.ts b/apps/browser/src/platform/storage/background-memory-storage.service.ts index 9c0cac0d044..ec1da43391f 100644 --- a/apps/browser/src/platform/storage/background-memory-storage.service.ts +++ b/apps/browser/src/platform/storage/background-memory-storage.service.ts @@ -1,14 +1,14 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -// eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage specifically for browser backgrounds -import { MemoryStorageService } from "@bitwarden/common/platform/state/storage/memory-storage.service"; + +import { SerializedMemoryStorageService } from "@bitwarden/storage-core"; import { BrowserApi } from "../browser/browser-api"; import { MemoryStoragePortMessage } from "./port-messages"; import { portName } from "./port-name"; -export class BackgroundMemoryStorageService extends MemoryStorageService { +export class BackgroundMemoryStorageService extends SerializedMemoryStorageService { private _ports: chrome.runtime.Port[] = []; constructor() { diff --git a/apps/browser/src/platform/storage/browser-storage-service.provider.ts b/apps/browser/src/platform/storage/browser-storage-service.provider.ts index 5854669138a..66a1bf3f2a7 100644 --- a/apps/browser/src/platform/storage/browser-storage-service.provider.ts +++ b/apps/browser/src/platform/storage/browser-storage-service.provider.ts @@ -1,13 +1,10 @@ import { AbstractStorageService, + ClientLocations, ObservableStorageService, -} from "@bitwarden/common/platform/abstractions/storage.service"; -import { PossibleLocation, StorageServiceProvider, -} from "@bitwarden/common/platform/services/storage-service.provider"; -// eslint-disable-next-line import/no-restricted-paths -import { ClientLocations } from "@bitwarden/common/platform/state/state-definition"; +} from "@bitwarden/storage-core"; export class BrowserStorageServiceProvider extends StorageServiceProvider { constructor( diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index e2f4561e86c..34a37da425e 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -17,28 +17,31 @@ import { SetInitialPasswordComponent } from "@bitwarden/angular/auth/password-ma import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard"; import { DevicesIcon, + RegistrationLockAltIcon, + RegistrationUserAddIcon, + TwoFactorTimeoutIcon, + DeviceVerificationIcon, + UserLockIcon, + VaultIcon, + LockIcon, +} from "@bitwarden/assets/svg"; +import { LoginComponent, LoginDecryptionOptionsComponent, LoginSecondaryContentComponent, LoginViaAuthRequestComponent, PasswordHintComponent, RegistrationFinishComponent, - RegistrationLockAltIcon, RegistrationStartComponent, RegistrationStartSecondaryComponent, RegistrationStartSecondaryComponentData, - RegistrationUserAddIcon, SsoComponent, - TwoFactorTimeoutIcon, TwoFactorAuthComponent, TwoFactorAuthGuard, NewDeviceVerificationComponent, - DeviceVerificationIcon, - UserLockIcon, - VaultIcon, } from "@bitwarden/auth/angular"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { AnonLayoutWrapperData, Icons } from "@bitwarden/components"; +import { AnonLayoutWrapperData } from "@bitwarden/components"; import { LockComponent } from "@bitwarden/key-management-ui"; import { AccountSwitcherComponent } from "../auth/popup/account-switching/account-switcher.component"; @@ -497,7 +500,7 @@ const routes: Routes = [ path: "lock", canActivate: [lockGuard()], data: { - pageIcon: Icons.LockIcon, + pageIcon: LockIcon, pageTitle: { key: "yourVaultIsLockedV2", }, diff --git a/apps/browser/src/popup/app.component.ts b/apps/browser/src/popup/app.component.ts index fa1e6c237c9..ee75dbaf7af 100644 --- a/apps/browser/src/popup/app.component.ts +++ b/apps/browser/src/popup/app.component.ts @@ -49,7 +49,6 @@ import { BiometricsService, BiometricStateService, KeyService } from "@bitwarden import { PopupCompactModeService } from "../platform/popup/layout/popup-compact-mode.service"; import { PopupSizeService } from "../platform/popup/layout/popup-size.service"; import { initPopupClosedListener } from "../platform/services/popup-view-cache-background.service"; -import { VaultBrowserStateService } from "../vault/services/vault-browser-state.service"; import { routerTransition } from "./app-routing.animations"; import { DesktopSyncVerificationDialogComponent } from "./components/desktop-sync-verification-dialog.component"; @@ -103,7 +102,6 @@ export class AppComponent implements OnInit, OnDestroy { private i18nService: I18nService, private router: Router, private readonly tokenService: TokenService, - private vaultBrowserStateService: VaultBrowserStateService, private cipherService: CipherService, private changeDetectorRef: ChangeDetectorRef, private ngZone: NgZone, @@ -135,10 +133,6 @@ export class AppComponent implements OnInit, OnDestroy { this.compactModeService.init(); await this.popupSizeService.setHeight(); - // Component states must not persist between closing and reopening the popup, otherwise they become dead objects - // Clear them aggressively to make sure this doesn't occur - await this.clearComponentStates(); - this.accountService.activeAccount$.pipe(takeUntil(this.destroy$)).subscribe((account) => { this.activeUserId = account?.id; }); @@ -249,13 +243,6 @@ export class AppComponent implements OnInit, OnDestroy { this.router.events.pipe(takeUntil(this.destroy$)).subscribe(async (event) => { if (event instanceof NavigationEnd) { const url = event.urlAfterRedirects || event.url || ""; - if ( - url.startsWith("/tabs/") && - (window as any).previousPopupUrl != null && - (window as any).previousPopupUrl.startsWith("/tabs/") - ) { - await this.clearComponentStates(); - } if (url.startsWith("/tabs/")) { await this.cipherService.setAddEditCipherInfo(null, this.activeUserId); } @@ -320,17 +307,6 @@ export class AppComponent implements OnInit, OnDestroy { return firstValueFrom(dialogRef.closed); } - private async clearComponentStates() { - if (!(await firstValueFrom(this.tokenService.hasAccessToken$(this.activeUserId)))) { - return; - } - - await Promise.all([ - this.vaultBrowserStateService.setBrowserGroupingsComponentState(null), - this.vaultBrowserStateService.setBrowserVaultItemsComponentState(null), - ]); - } - // Displaying toasts isn't super useful on the popup due to the reloads we do. // However, it is visible for a moment on the FF sidebar logout. private async displayLogoutReason(logoutReason: LogoutReason) { diff --git a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component.ts b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component.ts index 7a98f570fda..3b84eac2217 100644 --- a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component.ts +++ b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component.ts @@ -5,10 +5,9 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { ActivatedRoute, Data, NavigationEnd, Router, RouterModule } from "@angular/router"; import { Subject, filter, switchMap, takeUntil, tap } from "rxjs"; +import { ExtensionBitwardenLogo, Icon } from "@bitwarden/assets/svg"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { - Icon, - Icons, IconModule, Translation, AnonLayoutComponent, @@ -63,7 +62,7 @@ export class ExtensionAnonLayoutWrapperComponent implements OnInit, OnDestroy { protected hideCardWrapper: boolean = false; protected theme: string; - protected logo = Icons.ExtensionBitwardenLogo; + protected logo = ExtensionBitwardenLogo; constructor( private router: Router, diff --git a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts index 2c3d09b79fb..4e6f2fb452d 100644 --- a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts +++ b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts @@ -9,6 +9,7 @@ import { } from "@storybook/angular"; import { of } from "rxjs"; +import { LockIcon, RegistrationCheckEmailIcon } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AvatarService } from "@bitwarden/common/auth/abstractions/avatar.service"; @@ -22,12 +23,7 @@ import { import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { UserId } from "@bitwarden/common/types/guid"; -import { - AnonLayoutWrapperDataService, - ButtonModule, - Icons, - I18nMockService, -} from "@bitwarden/components"; +import { AnonLayoutWrapperDataService, ButtonModule, I18nMockService } from "@bitwarden/components"; import { AccountSwitcherService } from "../../../auth/popup/account-switching/services/account-switcher.service"; import { PopupRouterCacheService } from "../../../platform/popup/view-cache/popup-router-cache.service"; @@ -244,7 +240,7 @@ const initialData: ExtensionAnonLayoutWrapperData = { pageSubtitle: { key: "finishCreatingYourAccountBySettingAPassword", }, - pageIcon: Icons.LockIcon, + pageIcon: LockIcon, showAcctSwitcher: true, showBackButton: true, showLogo: true, @@ -258,7 +254,7 @@ const changedData: ExtensionAnonLayoutWrapperData = { pageSubtitle: { key: "checkYourEmail", }, - pageIcon: Icons.RegistrationCheckEmailIcon, + pageIcon: RegistrationCheckEmailIcon, showAcctSwitcher: false, showBackButton: false, showLogo: false, diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 98512596cf5..1372059d867 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -39,7 +39,6 @@ import { import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { DefaultOrganizationService } from "@bitwarden/common/admin-console/services/organization/default-organization.service"; import { AccountService, AccountService as AccountServiceAbstraction, @@ -104,13 +103,6 @@ import { ContainerService } from "@bitwarden/common/platform/services/container. import { DefaultSdkClientFactory } from "@bitwarden/common/platform/services/sdk/default-sdk-client-factory"; import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; -import { - DerivedStateProvider, - GlobalStateProvider, - StateProvider, -} from "@bitwarden/common/platform/state"; -// eslint-disable-next-line import/no-restricted-paths -- Used for dependency injection -import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/inline-derived-state"; import { PrimarySecondaryStorageService } from "@bitwarden/common/platform/storage/primary-secondary-storage.service"; import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service"; import { SyncService } from "@bitwarden/common/platform/sync"; @@ -119,10 +111,7 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; -import { - FolderService as FolderServiceAbstraction, - InternalFolderService, -} from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/vault/abstractions/totp.service"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; import { TotpService } from "@bitwarden/common/vault/services/totp.service"; @@ -140,6 +129,8 @@ import { KeyService, } from "@bitwarden/key-management"; import { LockComponentService } from "@bitwarden/key-management-ui"; +import { DerivedStateProvider, GlobalStateProvider, StateProvider } from "@bitwarden/state"; +import { InlineDerivedStateProvider } from "@bitwarden/state-internal"; import { DefaultSshImportPromptService, PasswordRepromptService, @@ -191,8 +182,6 @@ import { BrowserSystemNotificationService } from "../../platform/system-notifica import { fromChromeRuntimeMessaging } from "../../platform/utils/from-chrome-runtime-messaging"; import { FilePopoutUtilsService } from "../../tools/popup/services/file-popout-utils.service"; import { Fido2UserVerificationService } from "../../vault/services/fido2-user-verification.service"; -import { VaultBrowserStateService } from "../../vault/services/vault-browser-state.service"; -import { VaultFilterService } from "../../vault/services/vault-filter.service"; import { ExtensionAnonLayoutWrapperDataService } from "../components/extension-anon-layout-wrapper/extension-anon-layout-wrapper-data.service"; import { DebounceNavigationService } from "./debounce-navigation.service"; @@ -407,21 +396,6 @@ const safeProviders: SafeProvider[] = [ useClass: ForegroundVaultTimeoutService, deps: [MessagingServiceAbstraction], }), - safeProvider({ - provide: VaultFilterService, - useClass: VaultFilterService, - deps: [ - DefaultOrganizationService, - FolderServiceAbstraction, - CipherService, - CollectionService, - PolicyService, - StateProvider, - AccountServiceAbstraction, - ConfigService, - I18nServiceAbstraction, - ], - }), safeProvider({ provide: SECURE_STORAGE, useExisting: AbstractStorageService, // Secure storage is not available in the browser, so we use normal storage instead and warn users when it is used. @@ -459,13 +433,6 @@ const safeProviders: SafeProvider[] = [ provide: OBSERVABLE_DISK_STORAGE, useExisting: AbstractStorageService, }), - safeProvider({ - provide: VaultBrowserStateService, - useFactory: (stateProvider: StateProvider) => { - return new VaultBrowserStateService(stateProvider); - }, - deps: [StateProvider], - }), safeProvider({ provide: FileDownloadService, useClass: BrowserFileDownloadService, diff --git a/apps/browser/src/popup/tabs-v2.component.ts b/apps/browser/src/popup/tabs-v2.component.ts index 860b71794ff..f1e42799b35 100644 --- a/apps/browser/src/popup/tabs-v2.component.ts +++ b/apps/browser/src/popup/tabs-v2.component.ts @@ -2,9 +2,18 @@ import { Component } from "@angular/core"; import { map, Observable, startWith, switchMap } from "rxjs"; import { NudgesService } from "@bitwarden/angular/vault"; +import { + VaultInactive, + VaultActive, + GeneratorInactive, + GeneratorActive, + SendInactive, + SendActive, + SettingsInactive, + SettingsActive, +} from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { Icons } from "@bitwarden/components"; import { NavButton } from "../platform/popup/layout/popup-tab-navigation.component"; @@ -24,26 +33,26 @@ export class TabsV2Component { { label: "vault", page: "/tabs/vault", - icon: Icons.VaultInactive, - iconActive: Icons.VaultActive, + icon: VaultInactive, + iconActive: VaultActive, }, { label: "generator", page: "/tabs/generator", - icon: Icons.GeneratorInactive, - iconActive: Icons.GeneratorActive, + icon: GeneratorInactive, + iconActive: GeneratorActive, }, { label: "send", page: "/tabs/send", - icon: Icons.SendInactive, - iconActive: Icons.SendActive, + icon: SendInactive, + iconActive: SendActive, }, { label: "settings", page: "/tabs/settings", - icon: Icons.SettingsInactive, - iconActive: Icons.SettingsActive, + icon: SettingsInactive, + iconActive: SettingsActive, showBerry: hasBadges, }, ]; diff --git a/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.ts b/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.ts index dd9e95b64a1..30359e98fa0 100644 --- a/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.ts +++ b/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.ts @@ -7,13 +7,13 @@ import { ActivatedRoute, Router, RouterModule } from "@angular/router"; import { firstValueFrom } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { ActiveSendIcon } from "@bitwarden/assets/svg"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { ButtonModule, IconModule, ToastService } from "@bitwarden/components"; -import { ActiveSendIcon } from "@bitwarden/send-ui"; import { PopOutComponent } from "../../../../platform/popup/components/pop-out.component"; import { PopupFooterComponent } from "../../../../platform/popup/layout/popup-footer.component"; diff --git a/apps/browser/src/tools/popup/send-v2/send-v2.component.ts b/apps/browser/src/tools/popup/send-v2/send-v2.component.ts index 2fca3e41f88..5bd5386b1e0 100644 --- a/apps/browser/src/tools/popup/send-v2/send-v2.component.ts +++ b/apps/browser/src/tools/popup/send-v2/send-v2.component.ts @@ -4,15 +4,15 @@ import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { combineLatest, switchMap } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { NoResults, NoSendsIcon } from "@bitwarden/assets/svg"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; -import { ButtonModule, CalloutModule, Icons, NoItemsModule } from "@bitwarden/components"; +import { ButtonModule, CalloutModule, NoItemsModule } from "@bitwarden/components"; import { NewSendDropdownComponent, - NoSendsIcon, SendItemsService, SendListFiltersComponent, SendListFiltersService, @@ -59,7 +59,7 @@ export class SendV2Component implements OnDestroy { protected sendsLoading$ = this.sendItemsService.loading$; protected title: string = "allSends"; protected noItemIcon = NoSendsIcon; - protected noResultsIcon = Icons.NoResults; + protected noResultsIcon = NoResults; protected sendsDisabled = false; diff --git a/apps/browser/src/vault/popup/components/vault-v2/attachments/open-attachments/open-attachments.component.html b/apps/browser/src/vault/popup/components/vault-v2/attachments/open-attachments/open-attachments.component.html index 6345c3ea4e1..2650345e94b 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/attachments/open-attachments/open-attachments.component.html +++ b/apps/browser/src/vault/popup/components/vault-v2/attachments/open-attachments/open-attachments.component.html @@ -1,5 +1,10 @@ - diff --git a/apps/web/src/app/auth/settings/account/profile.component.ts b/apps/web/src/app/auth/settings/account/profile.component.ts index a0572b846db..54f9ac58291 100644 --- a/apps/web/src/app/auth/settings/account/profile.component.ts +++ b/apps/web/src/app/auth/settings/account/profile.component.ts @@ -12,7 +12,10 @@ import { UpdateProfileRequest } from "@bitwarden/common/auth/models/request/upda import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { ProfileResponse } from "@bitwarden/common/models/response/profile.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { UserPublicKey } from "@bitwarden/common/types/key"; import { DialogService, ToastService } from "@bitwarden/components"; +import { KeyService } from "@bitwarden/key-management"; import { DynamicAvatarComponent } from "../../../components/dynamic-avatar.component"; import { SharedModule } from "../../../shared"; @@ -29,6 +32,7 @@ export class ProfileComponent implements OnInit, OnDestroy { loading = true; profile: ProfileResponse; fingerprintMaterial: string; + userPublicKey: UserPublicKey; managingOrganization$: Observable; private destroy$ = new Subject(); @@ -44,16 +48,24 @@ export class ProfileComponent implements OnInit, OnDestroy { private dialogService: DialogService, private toastService: ToastService, private organizationService: OrganizationService, + private keyService: KeyService, + private logService: LogService, ) {} async ngOnInit() { this.profile = await this.apiService.getProfile(); - this.loading = false; - this.fingerprintMaterial = await firstValueFrom( - this.accountService.activeAccount$.pipe(map((a) => a?.id)), - ); - const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$)); + this.fingerprintMaterial = userId; + const publicKey = await firstValueFrom(this.keyService.userPublicKey$(userId)); + if (publicKey == null) { + this.logService.error( + "[ProfileComponent] No public key available for the user: " + + userId + + " fingerprint can't be displayed.", + ); + } else { + this.userPublicKey = publicKey; + } this.managingOrganization$ = this.organizationService .organizations$(userId) @@ -70,6 +82,8 @@ export class ProfileComponent implements OnInit, OnDestroy { .subscribe((name) => { this.profile.name = name; }); + + this.loading = false; } openChangeAvatar = async () => { diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.html b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.html index 767934cf3da..eec9f74dd60 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.html +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.html @@ -13,9 +13,6 @@ > {{ "twoStepLoginProviderEnabled" | i18n }} - -

{{ "twoFactorWebAuthnWarning1" | i18n }}

-
FIDO2 WebAuthn logo
  • diff --git a/apps/web/src/app/auth/settings/verify-email.component.html b/apps/web/src/app/auth/settings/verify-email.component.html index a691c30695c..42a546fc281 100644 --- a/apps/web/src/app/auth/settings/verify-email.component.html +++ b/apps/web/src/app/auth/settings/verify-email.component.html @@ -4,10 +4,9 @@ id="sendBtn" bitLink linkType="secondary" - bitButton type="button" buttonType="unstyled" - [bitAction]="send" + (click)="send()" > {{ "sendEmail" | i18n }} diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts index 22c3b4376c5..35e5048b1af 100644 --- a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts @@ -4,6 +4,7 @@ import { Component, OnInit } from "@angular/core"; import { FormBuilder, Validators } from "@angular/forms"; import { firstValueFrom, map, Observable } from "rxjs"; +import { CreatePasskeyFailedIcon, CreatePasskeyIcon } from "@bitwarden/assets/svg"; import { PrfKeySet } from "@bitwarden/auth/common"; import { Verification } from "@bitwarden/common/auth/types/verification"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; @@ -16,9 +17,6 @@ import { WebauthnLoginAdminService } from "../../../core"; import { CredentialCreateOptionsView } from "../../../core/views/credential-create-options.view"; import { PendingWebauthnLoginCredentialView } from "../../../core/views/pending-webauthn-login-credential.view"; -import { CreatePasskeyFailedIcon } from "./create-passkey-failed.icon"; -import { CreatePasskeyIcon } from "./create-passkey.icon"; - // FIXME: update to use a const object instead of a typescript enum // eslint-disable-next-line @bitwarden/platform/no-enums export enum CreateCredentialDialogResult { @@ -38,7 +36,10 @@ type Step = export class CreateCredentialDialogComponent implements OnInit { protected readonly NameMaxCharacters = 50; protected readonly CreateCredentialDialogResult = CreateCredentialDialogResult; - protected readonly Icons = { CreatePasskeyIcon, CreatePasskeyFailedIcon }; + protected readonly Icons = { + CreatePasskeyIcon, + CreatePasskeyFailedIcon, + }; protected currentStep: Step = "userVerification"; protected invalidSecret = false; diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey-failed.icon.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey-failed.icon.ts deleted file mode 100644 index 65902a64c9f..00000000000 --- a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey-failed.icon.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { svgIcon } from "@bitwarden/components"; - -export const CreatePasskeyFailedIcon = svgIcon` - - - - - - - - - - - -`; diff --git a/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.html b/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.html index 64a9781b7cf..0c1a4270662 100644 --- a/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.html +++ b/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.html @@ -51,6 +51,7 @@

    {{ "paymentType" | i18n }}

    diff --git a/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.ts b/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.ts index e13fac41f75..7e25a422477 100644 --- a/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.ts +++ b/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.ts @@ -259,6 +259,15 @@ export class TrialBillingStepComponent implements OnInit, OnDestroy { return planType ? this.applicablePlans.find((plan) => plan.type === planType) : null; } + protected get showTaxIdField(): boolean { + switch (this.organizationInfo.type) { + case ProductTierType.Families: + return false; + default: + return true; + } + } + private getBillingInformationFromTaxInfoComponent(): BillingInformation { return { postalCode: this.taxInfoComponent.getTaxInformation()?.postalCode, diff --git a/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.ts b/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.ts index 19c4ba04799..509fecb88fe 100644 --- a/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.ts +++ b/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.ts @@ -5,6 +5,7 @@ import { ActivatedRoute } from "@angular/router"; import { firstValueFrom, lastValueFrom, Subject } from "rxjs"; import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; +import { SubscriptionHiddenIcon } from "@bitwarden/assets/svg"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { @@ -39,7 +40,6 @@ import { import { BillingSyncApiKeyComponent } from "./billing-sync-api-key.component"; import { ChangePlanDialogResultType, openChangePlanDialog } from "./change-plan-dialog.component"; import { DownloadLicenceDialogComponent } from "./download-license.component"; -import { SubscriptionHiddenIcon } from "./icons/subscription-hidden.icon"; import { SecretsManagerSubscriptionOptions } from "./sm-adjust-subscription.component"; @Component({ diff --git a/apps/web/src/app/billing/organizations/subscription-hidden.component.ts b/apps/web/src/app/billing/organizations/subscription-hidden.component.ts index 1455d76d67e..f68b20635ba 100644 --- a/apps/web/src/app/billing/organizations/subscription-hidden.component.ts +++ b/apps/web/src/app/billing/organizations/subscription-hidden.component.ts @@ -2,30 +2,7 @@ // @ts-strict-ignore import { Component, Input } from "@angular/core"; -import { svgIcon } from "@bitwarden/components"; - -const SubscriptionHiddenIcon = svgIcon` - - - - - - - - - - - - - - - - - - - - -`; +import { SubscriptionHiddenIcon } from "@bitwarden/assets/svg"; @Component({ selector: "app-org-subscription-hidden", diff --git a/apps/web/src/app/billing/shared/sm-subscribe.component.ts b/apps/web/src/app/billing/shared/sm-subscribe.component.ts index 1ecf3648bd2..d1e5566a235 100644 --- a/apps/web/src/app/billing/shared/sm-subscribe.component.ts +++ b/apps/web/src/app/billing/shared/sm-subscribe.component.ts @@ -5,13 +5,12 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms"; import { Subject, startWith, takeUntil } from "rxjs"; import { ControlsOf } from "@bitwarden/angular/types/controls-of"; +import { SecretsManagerAlt } from "@bitwarden/assets/svg"; import { ProductTierType } from "@bitwarden/common/billing/enums"; import { BillingCustomerDiscount } from "@bitwarden/common/billing/models/response/organization-subscription.response"; import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { SecretsManagerLogo } from "../../layouts/secrets-manager-logo"; - export interface SecretsManagerSubscription { enabled: boolean; userSeats: number; @@ -42,7 +41,7 @@ export class SecretsManagerSubscribeComponent implements OnInit, OnDestroy { @Input() selectedPlan: PlanResponse; @Input() customerDiscount: BillingCustomerDiscount; - logo = SecretsManagerLogo; + logo = SecretsManagerAlt; productTypes = ProductTierType; private destroy$ = new Subject(); diff --git a/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.ts b/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.ts index ce02ee8715a..799577fc7c4 100644 --- a/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.ts +++ b/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.ts @@ -4,7 +4,7 @@ import { StepperSelectionEvent } from "@angular/cdk/stepper"; import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core"; import { FormBuilder, Validators } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; -import { combineLatest, firstValueFrom, map, Subject, switchMap, takeUntil } from "rxjs"; +import { firstValueFrom, map, Subject, switchMap, takeUntil } from "rxjs"; import { InputPasswordFlow, @@ -101,9 +101,6 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy { protected trialPaymentOptional$ = this.configService.getFeatureFlag$( FeatureFlag.TrialPaymentOptional, ); - protected allowTrialLengthZero$ = this.configService.getFeatureFlag$( - FeatureFlag.AllowTrialLengthZero, - ); constructor( protected router: Router, @@ -337,14 +334,11 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy { return this.productTier; } - readonly showBillingStep$ = combineLatest([ - this.trialPaymentOptional$, - this.allowTrialLengthZero$, - ]).pipe( - map(([trialPaymentOptional, allowTrialLengthZero]) => { + readonly showBillingStep$ = this.trialPaymentOptional$.pipe( + map((trialPaymentOptional) => { return ( (!trialPaymentOptional && !this.isSecretsManagerFree) || - (trialPaymentOptional && allowTrialLengthZero && this.trialLength === 0) + (trialPaymentOptional && this.trialLength === 0) ); }), ); diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index 965a9d5c99d..22386144732 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -45,6 +45,7 @@ import { import { OrganizationIntegrationApiService } from "@bitwarden/bit-common/dirt/integrations"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { InternalPolicyService, @@ -93,10 +94,7 @@ import { DefaultSdkClientFactory } from "@bitwarden/common/platform/services/sdk import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; import { NoopSdkLoadService } from "@bitwarden/common/platform/services/sdk/noop-sdk-load.service"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; -/* eslint-disable import/no-restricted-paths -- Implementation for memory storage */ import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state"; -import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service"; -/* eslint-enable import/no-restricted-paths -- Implementation for memory storage */ import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service"; import { DefaultThemeStateService, @@ -110,6 +108,7 @@ import { BiometricsService, } from "@bitwarden/key-management"; import { LockComponentService } from "@bitwarden/key-management-ui"; +import { SerializedMemoryStorageService } from "@bitwarden/storage-core"; import { DefaultSshImportPromptService, SshImportPromptService } from "@bitwarden/vault"; import { WebOrganizationInviteService } from "@bitwarden/web-vault/app/auth/core/services/organization-invite/web-organization-invite.service"; @@ -186,7 +185,7 @@ const safeProviders: SafeProvider[] = [ }), safeProvider({ provide: OBSERVABLE_MEMORY_STORAGE, - useClass: MemoryStorageServiceForStateProviders, + useClass: SerializedMemoryStorageService, deps: [], }), safeProvider({ @@ -319,7 +318,13 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: CollectionAdminService, useClass: DefaultCollectionAdminService, - deps: [ApiService, KeyServiceAbstraction, EncryptService, CollectionService], + deps: [ + ApiService, + KeyServiceAbstraction, + EncryptService, + CollectionService, + OrganizationService, + ], }), safeProvider({ provide: SdkLoadService, diff --git a/apps/web/src/app/dirt/reports/reports.ts b/apps/web/src/app/dirt/reports/reports.ts index c47928af1e9..d7437382961 100644 --- a/apps/web/src/app/dirt/reports/reports.ts +++ b/apps/web/src/app/dirt/reports/reports.ts @@ -1,10 +1,13 @@ -import { ReportBreach } from "./icons/report-breach.icon"; -import { ReportExposedPasswords } from "./icons/report-exposed-passwords.icon"; -import { ReportInactiveTwoFactor } from "./icons/report-inactive-two-factor.icon"; -import { MemberAccess } from "./icons/report-member-access.icon"; -import { ReportReusedPasswords } from "./icons/report-reused-passwords.icon"; -import { ReportUnsecuredWebsites } from "./icons/report-unsecured-websites.icon"; -import { ReportWeakPasswords } from "./icons/report-weak-passwords.icon"; +import { + MemberAccess, + ReportBreach, + ReportExposedPasswords, + ReportInactiveTwoFactor, + ReportReusedPasswords, + ReportUnsecuredWebsites, + ReportWeakPasswords, +} from "@bitwarden/assets/svg"; + import { ReportEntry } from "./shared"; // FIXME: update to use a const object instead of a typescript enum diff --git a/apps/web/src/app/dirt/reports/shared/models/report-entry.ts b/apps/web/src/app/dirt/reports/shared/models/report-entry.ts index d4da4e36763..fd1e57991fb 100644 --- a/apps/web/src/app/dirt/reports/shared/models/report-entry.ts +++ b/apps/web/src/app/dirt/reports/shared/models/report-entry.ts @@ -1,4 +1,4 @@ -import { Icon } from "@bitwarden/components"; +import { Icon } from "@bitwarden/assets/svg"; import { ReportVariant } from "./report-variant"; diff --git a/apps/web/src/app/dirt/reports/shared/report-card/report-card.component.ts b/apps/web/src/app/dirt/reports/shared/report-card/report-card.component.ts index 92e6ddb0028..e8ffcd01068 100644 --- a/apps/web/src/app/dirt/reports/shared/report-card/report-card.component.ts +++ b/apps/web/src/app/dirt/reports/shared/report-card/report-card.component.ts @@ -2,7 +2,7 @@ // @ts-strict-ignore import { Component, Input } from "@angular/core"; -import { Icon } from "@bitwarden/components"; +import { Icon } from "@bitwarden/assets/svg"; import { ReportVariant } from "../models/report-variant"; diff --git a/apps/web/src/app/layouts/password-manager-logo.ts b/apps/web/src/app/layouts/password-manager-logo.ts deleted file mode 100644 index d93e2d5bb30..00000000000 --- a/apps/web/src/app/layouts/password-manager-logo.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { svgIcon } from "@bitwarden/components"; - -export const PasswordManagerLogo = svgIcon` - -`; diff --git a/apps/web/src/app/layouts/user-layout.component.ts b/apps/web/src/app/layouts/user-layout.component.ts index db4c181cd0f..37b35ee41be 100644 --- a/apps/web/src/app/layouts/user-layout.component.ts +++ b/apps/web/src/app/layouts/user-layout.component.ts @@ -6,10 +6,11 @@ import { RouterModule } from "@angular/router"; import { Observable, switchMap } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { PasswordManagerLogo } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { SyncService } from "@bitwarden/common/platform/sync"; -import { IconModule, PasswordManagerLogo } from "@bitwarden/components"; +import { IconModule } from "@bitwarden/components"; import { BillingFreeFamiliesNavItemComponent } from "../billing/shared/billing-free-families-nav-item.component"; diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts index 4c1ed1a7472..9536ba19cc8 100644 --- a/apps/web/src/app/oss-routing.module.ts +++ b/apps/web/src/app/oss-routing.module.ts @@ -12,6 +12,19 @@ import { } from "@bitwarden/angular/auth/guards"; import { ChangePasswordComponent } from "@bitwarden/angular/auth/password-management/change-password"; import { SetInitialPasswordComponent } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.component"; +import { + DevicesIcon, + RegistrationLockAltIcon, + RegistrationUserAddIcon, + TwoFactorTimeoutIcon, + DeviceVerificationIcon, + UserLockIcon, + VaultIcon, + RegistrationExpiredLinkIcon, + SsoKeyIcon, + LockIcon, + BrowserExtensionIcon, +} from "@bitwarden/assets/svg"; import { PasswordHintComponent, RegistrationFinishComponent, @@ -21,25 +34,15 @@ import { RegistrationLinkExpiredComponent, LoginComponent, LoginSecondaryContentComponent, - TwoFactorTimeoutIcon, - UserLockIcon, - SsoKeyIcon, LoginViaAuthRequestComponent, - DevicesIcon, - RegistrationUserAddIcon, - RegistrationLockAltIcon, - RegistrationExpiredLinkIcon, SsoComponent, - VaultIcon, LoginDecryptionOptionsComponent, TwoFactorAuthComponent, TwoFactorAuthGuard, NewDeviceVerificationComponent, - DeviceVerificationIcon, } from "@bitwarden/auth/angular"; -import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, Icons } from "@bitwarden/components"; +import { AnonLayoutWrapperComponent, AnonLayoutWrapperData } from "@bitwarden/components"; import { LockComponent } from "@bitwarden/key-management-ui"; -import { VaultIcons } from "@bitwarden/vault"; import { flagEnabled, Flags } from "../utils/flags"; @@ -374,7 +377,7 @@ const routes: Routes = [ pageTitle: { key: "yourVaultIsLockedV2", }, - pageIcon: Icons.LockIcon, + pageIcon: LockIcon, showReadonlyHostname: true, } satisfies AnonLayoutWrapperData, }, @@ -533,7 +536,7 @@ const routes: Routes = [ { path: "browser-extension-prompt", data: { - pageIcon: VaultIcons.BrowserExtensionIcon, + pageIcon: BrowserExtensionIcon, } satisfies AnonLayoutWrapperData, children: [ { diff --git a/apps/web/src/app/platform/web-storage-service.provider.spec.ts b/apps/web/src/app/platform/web-storage-service.provider.spec.ts index 53f047d137d..e28b8772b16 100644 --- a/apps/web/src/app/platform/web-storage-service.provider.spec.ts +++ b/apps/web/src/app/platform/web-storage-service.provider.spec.ts @@ -2,14 +2,11 @@ import { mock } from "jest-mock-extended"; import { AbstractStorageService, - ObservableStorageService, -} from "@bitwarden/common/platform/abstractions/storage.service"; -import { PossibleLocation } from "@bitwarden/common/platform/services/storage-service.provider"; -import { ClientLocations, + ObservableStorageService, + PossibleLocation, StorageLocation, - // eslint-disable-next-line import/no-restricted-paths -} from "@bitwarden/common/platform/state/state-definition"; +} from "@bitwarden/storage-core"; import { WebStorageServiceProvider } from "./web-storage-service.provider"; diff --git a/apps/web/src/app/platform/web-storage-service.provider.ts b/apps/web/src/app/platform/web-storage-service.provider.ts index da9a8517856..2e5ccaf5720 100644 --- a/apps/web/src/app/platform/web-storage-service.provider.ts +++ b/apps/web/src/app/platform/web-storage-service.provider.ts @@ -1,15 +1,10 @@ import { AbstractStorageService, + ClientLocations, ObservableStorageService, -} from "@bitwarden/common/platform/abstractions/storage.service"; -import { PossibleLocation, StorageServiceProvider, -} from "@bitwarden/common/platform/services/storage-service.provider"; -import { - ClientLocations, - // eslint-disable-next-line import/no-restricted-paths -} from "@bitwarden/common/platform/state/state-definition"; +} from "@bitwarden/storage-core"; export class WebStorageServiceProvider extends StorageServiceProvider { constructor( diff --git a/apps/web/src/app/tools/send/send-access/access.component.ts b/apps/web/src/app/tools/send/send-access/access.component.ts index bc2851f0df7..1636ac37b87 100644 --- a/apps/web/src/app/tools/send/send-access/access.component.ts +++ b/apps/web/src/app/tools/send/send-access/access.component.ts @@ -4,6 +4,7 @@ import { Component, OnInit } from "@angular/core"; import { FormBuilder } from "@angular/forms"; import { ActivatedRoute } from "@angular/router"; +import { ExpiredSendIcon } from "@bitwarden/assets/svg"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -18,7 +19,6 @@ import { SEND_KDF_ITERATIONS } from "@bitwarden/common/tools/send/send-kdf"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { AnonLayoutWrapperDataService, NoItemsModule, ToastService } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; -import { ExpiredSendIcon } from "@bitwarden/send-ui"; import { SharedModule } from "../../../shared"; diff --git a/apps/web/src/app/tools/send/send-access/routes.ts b/apps/web/src/app/tools/send/send-access/routes.ts index 4f794aecd23..e94453c9351 100644 --- a/apps/web/src/app/tools/send/send-access/routes.ts +++ b/apps/web/src/app/tools/send/send-access/routes.ts @@ -1,7 +1,7 @@ import { Routes } from "@angular/router"; +import { ActiveSendIcon } from "@bitwarden/assets/svg"; import { AnonLayoutWrapperData } from "@bitwarden/components"; -import { ActiveSendIcon } from "@bitwarden/send-ui"; import { RouteDataProperties } from "../../../core"; diff --git a/apps/web/src/app/tools/send/send.component.ts b/apps/web/src/app/tools/send/send.component.ts index b74a3b80ee3..20b93a10975 100644 --- a/apps/web/src/app/tools/send/send.component.ts +++ b/apps/web/src/app/tools/send/send.component.ts @@ -4,6 +4,7 @@ import { Component, NgZone, OnInit, OnDestroy } from "@angular/core"; import { lastValueFrom } from "rxjs"; import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component"; +import { NoSendsIcon } from "@bitwarden/assets/svg"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; @@ -26,7 +27,6 @@ import { } from "@bitwarden/components"; import { DefaultSendFormConfigService, - NoSendsIcon, SendFormConfig, SendAddEditDialogComponent, SendItemDialogResult, diff --git a/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.ts b/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.ts index 22041b61198..646ff76311e 100644 --- a/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.ts +++ b/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.ts @@ -1,8 +1,8 @@ import { Component } from "@angular/core"; +import { BitwardenIcon } from "@bitwarden/assets/svg"; import { IconModule } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; -import { VaultIcons } from "@bitwarden/vault"; @Component({ selector: "vault-manually-open-extension", @@ -10,5 +10,5 @@ import { VaultIcons } from "@bitwarden/vault"; imports: [I18nPipe, IconModule], }) export class ManuallyOpenExtensionComponent { - protected BitwardenIcon = VaultIcons.BitwardenIcon; + protected BitwardenIcon = BitwardenIcon; } diff --git a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts index 8bb80e6fb44..43ffe8fe71c 100644 --- a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts +++ b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts @@ -3,16 +3,14 @@ import { By } from "@angular/platform-browser"; import { Router, RouterModule } from "@angular/router"; import { BehaviorSubject } from "rxjs"; +import { BrowserExtensionIcon } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { DeviceType } from "@bitwarden/common/enums"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; 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 { StateProvider } from "@bitwarden/common/platform/state"; import { AnonLayoutWrapperDataService } from "@bitwarden/components"; -import { VaultIcons } from "@bitwarden/vault"; import { WebBrowserInteractionService } from "../../services/web-browser-interaction.service"; @@ -22,7 +20,6 @@ describe("SetupExtensionComponent", () => { let fixture: ComponentFixture; let component: SetupExtensionComponent; - const getFeatureFlag = jest.fn().mockResolvedValue(false); const navigate = jest.fn().mockResolvedValue(true); const openExtension = jest.fn().mockResolvedValue(true); const update = jest.fn().mockResolvedValue(true); @@ -34,14 +31,12 @@ describe("SetupExtensionComponent", () => { openExtension.mockClear(); update.mockClear(); setAnonLayoutWrapperData.mockClear(); - getFeatureFlag.mockClear().mockResolvedValue(true); window.matchMedia = jest.fn().mockReturnValue(false); await TestBed.configureTestingModule({ imports: [SetupExtensionComponent, RouterModule.forRoot([])], providers: [ { provide: I18nService, useValue: { t: (key: string) => key } }, - { provide: ConfigService, useValue: { getFeatureFlag } }, { provide: WebBrowserInteractionService, useValue: { extensionInstalled$, openExtension } }, { provide: PlatformUtilsService, useValue: { getDevice: () => DeviceType.UnknownBrowser } }, { provide: AnonLayoutWrapperDataService, useValue: { setAnonLayoutWrapperData } }, @@ -74,19 +69,8 @@ describe("SetupExtensionComponent", () => { }); describe("initialization", () => { - it("redirects to the vault if the feature flag is disabled", async () => { - Utils.isMobileBrowser = false; - getFeatureFlag.mockResolvedValue(false); - navigate.mockClear(); - - await component.ngOnInit(); - - expect(navigate).toHaveBeenCalledWith(["/vault"]); - }); - it("redirects to the vault if the user is on a mobile browser", async () => { Utils.isMobileBrowser = true; - getFeatureFlag.mockResolvedValue(true); navigate.mockClear(); await component.ngOnInit(); @@ -96,12 +80,10 @@ describe("SetupExtensionComponent", () => { it("does not redirect the user", async () => { Utils.isMobileBrowser = false; - getFeatureFlag.mockResolvedValue(true); navigate.mockClear(); await component.ngOnInit(); - expect(getFeatureFlag).toHaveBeenCalledWith(FeatureFlag.PM19315EndUserActivationMvp); expect(navigate).not.toHaveBeenCalled(); }); }); @@ -156,7 +138,7 @@ describe("SetupExtensionComponent", () => { pageTitle: { key: "somethingWentWrong", }, - pageIcon: VaultIcons.BrowserExtensionIcon, + pageIcon: BrowserExtensionIcon, hideIcon: false, hideCardWrapper: false, maxWidth: "md", diff --git a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts index 67d13ef1e4f..558f0eb06c9 100644 --- a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts +++ b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts @@ -5,10 +5,9 @@ import { Router, RouterModule } from "@angular/router"; import { firstValueFrom, pairwise, startWith } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { BrowserExtensionIcon, Party } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { StateProvider } from "@bitwarden/common/platform/state"; @@ -22,7 +21,6 @@ import { IconModule, LinkModule, } from "@bitwarden/components"; -import { VaultIcons } from "@bitwarden/vault"; import { SETUP_EXTENSION_DISMISSED } from "../../guards/setup-extension-redirect.guard"; import { WebBrowserInteractionService } from "../../services/web-browser-interaction.service"; @@ -59,7 +57,6 @@ type SetupExtensionState = UnionOfValues; }) export class SetupExtensionComponent implements OnInit, OnDestroy { private webBrowserExtensionInteractionService = inject(WebBrowserInteractionService); - private configService = inject(ConfigService); private router = inject(Router); private destroyRef = inject(DestroyRef); private platformUtilsService = inject(PlatformUtilsService); @@ -70,7 +67,7 @@ export class SetupExtensionComponent implements OnInit, OnDestroy { private anonLayoutWrapperDataService = inject(AnonLayoutWrapperDataService); protected SetupExtensionState = SetupExtensionState; - protected PartyIcon = VaultIcons.Party; + protected PartyIcon = Party; /** The current state of the setup extension component. */ protected state: SetupExtensionState = SetupExtensionState.Loading; @@ -134,12 +131,9 @@ export class SetupExtensionComponent implements OnInit, OnDestroy { /** Conditionally redirects the user to the vault upon landing on the page. */ async conditionallyRedirectUser() { - const isFeatureEnabled = await this.configService.getFeatureFlag( - FeatureFlag.PM19315EndUserActivationMvp, - ); const isMobile = Utils.isMobileBrowser; - if (!isFeatureEnabled || isMobile) { + if (isMobile) { await this.dismissExtensionPage(); await this.router.navigate(["/vault"]); } @@ -167,7 +161,7 @@ export class SetupExtensionComponent implements OnInit, OnDestroy { pageTitle: { key: "somethingWentWrong", }, - pageIcon: VaultIcons.BrowserExtensionIcon, + pageIcon: BrowserExtensionIcon, hideIcon: false, hideCardWrapper: false, maxWidth: "md", diff --git a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.html b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.html index 06d5f5ea81a..b2a57ffb875 100644 --- a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.html +++ b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.html @@ -16,9 +16,15 @@ [submitBtn]="submitBtn" (formReady)="onFormReady()" (cipherSaved)="onCipherSaved($event)" + (formStatusChange$)="formStatusChanged($event)" > - @@ -104,6 +105,7 @@ [label]="'reorderToggleButton' | i18n: field.value.name" (keydown)="handleKeyDown($event, field.value.name, i)" data-testid="reorder-toggle-button" + [disabled]="parentFormDisabled" *ngIf="canEdit(field.value.type)" > @@ -113,7 +115,8 @@ bitLink linkType="primary" (click)="openAddEditCustomFieldDialog()" - *ngIf="!isPartialEdit" + data-testid="add-field-button" + *ngIf="!isPartialEdit && !parentFormDisabled" > {{ "addField" | i18n }} diff --git a/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.spec.ts b/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.spec.ts index ced8763f895..1d1bcfa1ee0 100644 --- a/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.spec.ts +++ b/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.spec.ts @@ -4,6 +4,7 @@ import { DebugElement } from "@angular/core"; import { ComponentFixture, TestBed } from "@angular/core/testing"; import { By } from "@angular/platform-browser"; import { mock } from "jest-mock-extended"; +import { BehaviorSubject } from "rxjs"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -16,7 +17,12 @@ import { } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FieldView } from "@bitwarden/common/vault/models/view/field.view"; -import { DialogRef, BitPasswordInputToggleDirective, DialogService } from "@bitwarden/components"; +import { + DialogRef, + BitPasswordInputToggleDirective, + DialogService, + BitIconButtonComponent, +} from "@bitwarden/components"; import { CipherFormConfig } from "../../abstractions/cipher-form-config.service"; import { CipherFormContainer } from "../../cipher-form-container"; @@ -39,6 +45,7 @@ describe("CustomFieldsComponent", () => { let announce: jest.Mock; let patchCipher: jest.Mock; let config: CipherFormConfig; + const formStatusChange$ = new BehaviorSubject<"disabled" | "enabled">("enabled"); beforeEach(async () => { open = jest.fn(); @@ -65,6 +72,7 @@ describe("CustomFieldsComponent", () => { registerChildForm: jest.fn(), config, getInitialCipherView: jest.fn(() => originalCipherView), + formStatusChange$, }, }, { @@ -552,4 +560,54 @@ describe("CustomFieldsComponent", () => { expect(editButtons).toHaveLength(3); }); }); + + describe("parent form disabled", () => { + beforeEach(() => { + originalCipherView!.fields = mockFieldViews; + formStatusChange$.next("disabled"); + component.ngOnInit(); + + fixture.detectChanges(); + }); + + afterEach(() => { + formStatusChange$.next("enabled"); + fixture.detectChanges(); + }); + + it("disables edit and reorder buttons", () => { + const reorderButtonQuery = By.directive(BitIconButtonComponent); + const editButtonQuery = By.directive(BitIconButtonComponent); + + let reorderButton = fixture.debugElement.query(reorderButtonQuery); + let editButton = fixture.debugElement.query(editButtonQuery); + + expect(reorderButton.componentInstance.disabled()).toBe(true); + expect(editButton.componentInstance.disabled()).toBe(true); + + formStatusChange$.next("enabled"); + fixture.detectChanges(); + + reorderButton = fixture.debugElement.query(reorderButtonQuery); + editButton = fixture.debugElement.query(editButtonQuery); + + expect(reorderButton.componentInstance.disabled()).toBe(false); + expect(editButton.componentInstance.disabled()).toBe(false); + }); + + it("hides add field button", () => { + const query = By.css('button[data-testid="add-field-button"]'); + + let addFieldButton = fixture.debugElement.query(query); + + expect(addFieldButton).toBeNull(); + + formStatusChange$.next("enabled"); + fixture.detectChanges(); + + addFieldButton = fixture.debugElement.query(query); + + expect(addFieldButton).not.toBeNull(); + }); + }); }); 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 c8edba6c9fd..e3612e75a1b 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 @@ -113,6 +113,9 @@ export class CustomFieldsComponent implements OnInit, AfterViewInit { /** Emits when a new custom field should be focused */ private focusOnNewInput$ = new Subject(); + /** Tracks the disabled status of the edit cipher form */ + protected parentFormDisabled: boolean = false; + disallowHiddenField?: boolean; destroyed$: DestroyRef; @@ -133,6 +136,10 @@ export class CustomFieldsComponent implements OnInit, AfterViewInit { // getRawValue ensures disabled fields are included this.updateCipher(this.fields.getRawValue()); }); + + this.cipherFormContainer.formStatusChange$.pipe(takeUntilDestroyed()).subscribe((status) => { + this.parentFormDisabled = status === "disabled"; + }); } /** Fields form array, referenced via a getter to avoid type-casting in multiple places */ diff --git a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.html b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.html index fc208bd9b92..9bf6dc32758 100644 --- a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.html +++ b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.html @@ -11,6 +11,7 @@ [attr.aria-checked]="itemDetailsForm.value.favorite" [label]="'favorite' | i18n" (click)="toggleFavorite()" + [disabled]="favoriteButtonDisabled" > diff --git a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.spec.ts b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.spec.ts index 6aa7175d373..e3d863a0af3 100644 --- a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.spec.ts +++ b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.spec.ts @@ -33,23 +33,24 @@ const createMockCollection = ( readOnly = false, canEdit = true, ): CollectionView => { - return { - id: id as CollectionId, + const cv = new CollectionView({ name, organizationId: organizationId as OrganizationId, - externalId: "", - readOnly, - hidePasswords: false, - manage: true, - assigned: true, - type: CollectionTypes.DefaultUserCollection, - isDefaultCollection: true, - canEditItems: jest.fn().mockReturnValue(canEdit), - canEdit: jest.fn(), - canDelete: jest.fn(), - canViewCollectionInfo: jest.fn(), - encrypt: jest.fn(), - }; + id: id as CollectionId, + }); + cv.readOnly = readOnly; + cv.manage = true; + cv.type = CollectionTypes.DefaultUserCollection; + cv.externalId = ""; + cv.hidePasswords = false; + cv.assigned = true; + cv.canEditName = jest.fn().mockReturnValue(true); + cv.canEditItems = jest.fn().mockReturnValue(canEdit); + cv.canEdit = jest.fn(); + cv.canDelete = jest.fn(); + cv.canViewCollectionInfo = jest.fn(); + + return cv; }; describe("ItemDetailsSectionComponent", () => { diff --git a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.ts b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.ts index 4fd999ae601..bc5e7c43d12 100644 --- a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.ts +++ b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.ts @@ -82,6 +82,8 @@ export class ItemDetailsSectionComponent implements OnInit { protected userId: UserId; + protected favoriteButtonDisabled = false; + @Input({ required: true }) config: CipherFormConfig; @@ -241,15 +243,19 @@ export class ItemDetailsSectionComponent implements OnInit { /** * When the cipher does not belong to an organization but the user's organization * requires all ciphers to be owned by an organization, disable the entire form - * until the user selects an organization. + * until the user selects an organization. Once the organization is set, enable the form. + * Ensure to properly set the collections control state when the form is enabled. */ private setFormState() { if (this.config.originalCipher && !this.allowPersonalOwnership) { if (this.itemDetailsForm.controls.organizationId.value === null) { this.cipherFormContainer.disableFormFields(); this.itemDetailsForm.controls.organizationId.enable(); + this.favoriteButtonDisabled = true; } else { this.cipherFormContainer.enableFormFields(); + this.favoriteButtonDisabled = false; + this.setCollectionControlState(); } } } @@ -305,7 +311,6 @@ export class ItemDetailsSectionComponent implements OnInit { }); const orgId = this.itemDetailsForm.controls.organizationId.value as OrganizationId; - const organization = this.organizations.find((o) => o.id === orgId); const initializedWithCachedCipher = this.cipherFormContainer.initializedWithCachedCipher(); // Configure form for clone mode. @@ -327,9 +332,7 @@ export class ItemDetailsSectionComponent implements OnInit { await this.updateCollectionOptions(prefillCollections); - if (!organization?.canEditAllCiphers && !prefillCipher.canAssignToCollections) { - this.itemDetailsForm.controls.collectionIds.disable(); - } + this.setCollectionControlState(); if (this.partialEdit) { this.itemDetailsForm.disable(); @@ -344,22 +347,34 @@ export class ItemDetailsSectionComponent implements OnInit { c.readOnly && this.originalCipherView.collectionIds.includes(c.id as CollectionId), ); - - // When Owners/Admins access setting is turned on. - // Disable Collections Options if Owner/Admin does not have Edit/Manage permissions on item - // Disable Collections Options if Custom user does not have Edit/Manage permissions on item - if ( - (organization?.allowAdminAccessToAllCollectionItems && - (!this.originalCipherView.viewPassword || !this.originalCipherView.edit)) || - (organization?.type === OrganizationUserType.Custom && - !this.originalCipherView.viewPassword) - ) { - this.itemDetailsForm.controls.collectionIds.disable(); - } } } } + private setCollectionControlState() { + const initialCipherView = this.cipherFormContainer.getInitialCipherView(); + const orgId = this.itemDetailsForm.controls.organizationId.value as OrganizationId; + const organization = this.organizations.find((o) => o.id === orgId); + if (!organization || !initialCipherView) { + return; + } + // Disable the collection control if either of the following apply: + // 1. The organization does not allow editing all ciphers and the existing cipher cannot be assigned to + // collections + // 2. When Owners/Admins access setting is turned on. + // AND either: + // a. Disable Collections Options if Owner/Admin does not have Edit/Manage permissions on item + // b. Disable Collections Options if Custom user does not have Edit/Manage permissions on item + if ( + (!organization.canEditAllCiphers && !initialCipherView.canAssignToCollections) || + (organization.allowAdminAccessToAllCollectionItems && + (!initialCipherView.viewPassword || !initialCipherView.edit)) || + (organization.type === OrganizationUserType.Custom && !initialCipherView.viewPassword) + ) { + this.itemDetailsForm.controls.collectionIds.disable(); + } + } + /** * Updates the collection options based on the selected organization. * @param startingSelection - Optional starting selection of collectionIds to be automatically selected. diff --git a/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.spec.ts b/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.spec.ts index c5b1fc7897b..b07a50fd383 100644 --- a/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.spec.ts +++ b/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.spec.ts @@ -3,6 +3,7 @@ import { Component } from "@angular/core"; import { ComponentFixture, fakeAsync, TestBed, tick } from "@angular/core/testing"; import { By } from "@angular/platform-browser"; import { mock, MockProxy } from "jest-mock-extended"; +import { BehaviorSubject } from "rxjs"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; @@ -47,6 +48,7 @@ describe("LoginDetailsSectionComponent", () => { getInitialCipherView.mockClear(); cipherFormContainer = mock({ getInitialCipherView, + formStatusChange$: new BehaviorSubject<"enabled" | "disabled">("enabled"), website: "example.com", }); diff --git a/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.ts b/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.ts index e74d9915cdb..061a8c4abf4 100644 --- a/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.ts +++ b/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.ts @@ -1,7 +1,7 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore import { DatePipe, NgIf } from "@angular/common"; -import { Component, inject, OnInit, Optional } from "@angular/core"; +import { Component, DestroyRef, inject, OnInit, Optional } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { FormBuilder, ReactiveFormsModule } from "@angular/forms"; import { map } from "rxjs"; @@ -81,6 +81,8 @@ export class LoginDetailsSectionComponent implements OnInit { */ private existingFido2Credentials?: Fido2CredentialView[]; + private destroyRef = inject(DestroyRef); + get hasPasskey(): boolean { return this.existingFido2Credentials != null && this.existingFido2Credentials.length > 0; } @@ -148,6 +150,19 @@ export class LoginDetailsSectionComponent implements OnInit { if (this.cipherFormContainer.config.mode === "partial-edit") { this.loginDetailsForm.disable(); } + + // If the form is enabled, ensure to disable password or TOTP + // for hidden password users + this.cipherFormContainer.formStatusChange$ + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((status) => { + if (status === "enabled") { + if (!this.viewHiddenFields) { + this.loginDetailsForm.controls.password.disable(); + this.loginDetailsForm.controls.totp.disable(); + } + } + }); } private initFromExistingCipher(existingLogin: LoginView) { diff --git a/libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.ts b/libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.ts index f83f93267c9..f92c4420d03 100644 --- a/libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.ts +++ b/libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.ts @@ -98,9 +98,13 @@ export class SshKeySectionComponent implements OnInit { // Disable the form if the cipher form container is enabled // to prevent user interaction - this.cipherFormContainer.formEnabled$ + this.cipherFormContainer.formStatusChange$ .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(() => this.sshKeyForm.disable()); + .subscribe((status) => { + if (status === "enabled") { + this.sshKeyForm.disable(); + } + }); } /** Set form initial form values from the current cipher */ diff --git a/libs/vault/src/components/carousel/carousel-button/carousel-button.component.ts b/libs/vault/src/components/carousel/carousel-button/carousel-button.component.ts index 7b5f7d3b164..ae2ce12cba8 100644 --- a/libs/vault/src/components/carousel/carousel-button/carousel-button.component.ts +++ b/libs/vault/src/components/carousel/carousel-button/carousel-button.component.ts @@ -2,9 +2,9 @@ import { FocusableOption } from "@angular/cdk/a11y"; import { CommonModule } from "@angular/common"; import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from "@angular/core"; +import { CarouselIcon } from "@bitwarden/assets/svg"; import { IconModule } from "@bitwarden/components"; -import { CarouselIcon } from "../carousel-icons/carousel-icon"; import { VaultCarouselSlideComponent } from "../carousel-slide/carousel-slide.component"; @Component({ diff --git a/libs/vault/src/components/download-attachment/download-attachment.component.html b/libs/vault/src/components/download-attachment/download-attachment.component.html index 47ee3c4761c..c2c2f1d4ebd 100644 --- a/libs/vault/src/components/download-attachment/download-attachment.component.html +++ b/libs/vault/src/components/download-attachment/download-attachment.component.html @@ -1,4 +1,5 @@