1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-21 16:18:28 +01:00

[PM-4209] Enable importing on browser (#6503)

* Split up import/export into separate modules

* Fix routing and apply PR feedback

* Renamed OrganizationExport exports to OrganizationVaultExport

* Make import dialogs standalone and move them to libs/importer

* Make import.component re-usable

- Move functionality which was previously present on the org-import.component into import.component
- Move import.component into libs/importer
Make import.component standalone
Create import-web.component to represent Web UI
Fix module imports and routing
Remove unused org-import-files

* Enable importing on browser

Create import-dialog
Add routing and routing animations
Settings import items no longer navigates to help page but opens import page
Extend messages.json to include all the necessary messages from shared components

* Fix back navigation

* Renamed filenames according to export rename

* Make ImportWebComponent standalone, simplify routing

* Pass organizationId as Input to ImportComponent

* use formLoading and formDisabled outputs

* add loading and disabled state to import-browser

* override popup header styles

* Emit an event when the import succeeds

Remove Angular router from base-component as other clients might not have routing (i.e. desktop)
Move logic that happened on web successful import into the import-web.component

* Enable importing on browser

Create import-dialog
Add routing and routing animations
Settings import items no longer navigates to help page but opens import page
Extend messages.json to include all the necessary messages from shared components

* Fix back navigation

* add loading and disabled state to import-browser

* override popup header styles

* Add missing message for importBlockedByPolicy callout

* Implement onSuccessfulImport to navigate back to settings

* fix table themes on desktop & browser

* fix fileSelector button styles

* update selectors to use tools prefix; remove unused selectors

* rename selector

* Wall off UI components in libs/importer

Create barrel-file for libs/importer/components
Remove components and dialog exports from libs/importer/index.ts
Extend libs/shared/tsconfig.libs.json to include @bitwarden/importer/ui -> libs/importer/components
Extend apps/web/tsconfig.ts to include @bitwarden/importer/ui
Update all usages

* Rename @bitwarden/importer to @bitwarden/importer/core

Create more barrel files in libs/importer/*
Update imports within libs/importer
Extend tsconfig files
Update imports in web, desktop, browser and cli

* Lazy-load the ImportWebComponent via both routes

* Fix import path for ImportComponent

* Navigate to import opens in popout when navigated from the popup

Make import call async and await router navigate
- If the user has the popup open and selects import, it will navigate to the import page and popout into a new window. This is necessary as any focus-loss (i.e Choose file) would close the popup.
- If the user is using the for example the sidebar or an already popped out window, just navigate to import page

* Use SharedModule as import in import-web.component

* File selector should be displayed as secondary

* Update description of "importData" in messages.json

* Add missing messages for file-password-prompt

* Add missing messages for import-error-dialog

* Add missing message for import-success-dialog

* Use bitSubmit to override submit preventDefault (#6607)

Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>

* Add missing importWarning

---------

Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
Co-authored-by: William Martin <contact@willmartian.com>
This commit is contained in:
Daniel James Smith 2023-10-19 22:33:41 +02:00 committed by GitHub
parent cdcd1809f0
commit 87dbe8997d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 182 additions and 3 deletions

View File

@ -1656,6 +1656,9 @@
"personalOwnershipPolicyInEffect": {
"message": "An organization policy is affecting your ownership options."
},
"personalOwnershipPolicyInEffectImports": {
"message": "An organization policy has blocked importing items into your individual vault."
},
"excludedDomains": {
"message": "Excluded domains"
},
@ -2449,6 +2452,114 @@
"message": "Turn off master password re-prompt to edit this field",
"description": "Message appearing below the autofill on load message when master password reprompt is set for a vault item."
},
"importData": {
"message": "Import data",
"description": "Used for the header of the import dialog, the import button and within the file-password-prompt"
},
"importError": {
"message": "Import error"
},
"importErrorDesc": {
"message": "There was a problem with the data you tried to import. Please resolve the errors listed below in your source file and try again."
},
"resolveTheErrorsBelowAndTryAgain": {
"message": "Resolve the errors below and try again."
},
"description": {
"message": "Description"
},
"importSuccess": {
"message": "Data successfully imported"
},
"importSuccessNumberOfItems": {
"message": "A total of $AMOUNT$ items were imported.",
"placeholders": {
"amount": {
"content": "$1",
"example": "2"
}
}
},
"total": {
"message": "Total"
},
"importWarning": {
"message": "You are importing data to $ORGANIZATION$. Your data may be shared with members of this organization. Do you want to proceed?",
"placeholders": {
"organization": {
"content": "$1",
"example": "My Org Name"
}
}
},
"importFormatError": {
"message": "Data is not formatted correctly. Please check your import file and try again."
},
"importNothingError": {
"message": "Nothing was imported."
},
"importEncKeyError": {
"message": "Error decrypting the exported file. Your encryption key does not match the encryption key used export the data."
},
"importDestination": {
"message": "Import destination"
},
"learnAboutImportOptions": {
"message": "Learn about your import options"
},
"selectImportFolder": {
"message": "Select a folder"
},
"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"
}
}
},
"importUnassignedItemsError": {
"message": "File contains unassigned items."
},
"selectFormat": {
"message": "Select the format of the import file"
},
"selectImportFile": {
"message": "Select the import file"
},
"chooseFile": {
"message": "Choose File"
},
"noFileChosen": {
"message": "No file chosen"
},
"orCopyPasteFileContents": {
"message": "or copy/paste the import file contents"
},
"instructionsFor": {
"message": "$NAME$ Instructions",
"description": "The title for the import tool instructions.",
"placeholders": {
"name": {
"content": "$1",
"example": "LastPass (csv)"
}
}
},
"confirmVaultImport": {
"message": "Confirm vault import"
},
"confirmVaultImportDesc": {
"message": "This file is password-protected. Please enter the file password to import data."
},
"confirmFilePassword": {
"message": "Confirm file password"
},
"passkeyNotCopied": {
"message": "Passkey will not be copied"
},

View File

@ -174,6 +174,9 @@ export const routerTransition = trigger("routerTransition", [
transition("clone-cipher => attachments, clone-cipher => collections", inSlideLeft),
transition("attachments => clone-cipher, collections => clone-cipher", outSlideRight),
transition("tabs => import", inSlideLeft),
transition("import => tabs", outSlideRight),
transition("tabs => export", inSlideLeft),
transition("export => tabs", outSlideRight),

View File

@ -32,6 +32,7 @@ import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.componen
import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component";
import { SendTypeComponent } from "../tools/popup/send/send-type.component";
import { ExportComponent } from "../tools/popup/settings/export.component";
import { ImportBrowserComponent } from "../tools/popup/settings/import/import-browser.component";
import { Fido2Component } from "../vault/popup/components/fido2/fido2.component";
import { AddEditComponent } from "../vault/popup/components/vault/add-edit.component";
import { AttachmentsComponent } from "../vault/popup/components/vault/attachments.component";
@ -222,6 +223,12 @@ const routes: Routes = [
canActivate: [AuthGuard],
data: { state: "generator-history" },
},
{
path: "import",
component: ImportBrowserComponent,
canActivate: [AuthGuard],
data: { state: "import" },
},
{
path: "export",
component: ExportComponent,

View File

@ -175,7 +175,7 @@ cdk-virtual-scroll-viewport::-webkit-scrollbar-thumb,
}
}
header {
header:not(bit-callout header) {
min-height: 44px;
max-height: 44px;
display: flex;

View File

@ -473,8 +473,11 @@ export class SettingsComponent implements OnInit {
BrowserApi.createNewTab(url);
}
import() {
BrowserApi.createNewTab("https://bitwarden.com/help/import-data/");
async import() {
await this.router.navigate(["/import"]);
if (await BrowserApi.isPopupOpen()) {
this.popupUtilsService.popOut(window);
}
}
export() {

View File

@ -0,0 +1,24 @@
<header>
<div class="left">
<button type="button" routerLink="/tabs/settings">
<span class="header-icon" aria-hidden="true"><i class="bwi bwi-angle-left"></i></span>
<span>{{ "back" | i18n }}</span>
</button>
</div>
<h1 class="center">
<span class="title">{{ "importData" | i18n }}</span>
</h1>
<div class="right">
<button form="importForm" type="submit" [disabled]="disabled">
<span [hidden]="loading">{{ "importData" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!loading" aria-hidden="true"></i>
</button>
</div>
</header>
<div tabindex="-1" class="tw-p-4">
<tools-import
(formDisabled)="this.disabled = $event"
(formLoading)="this.loading = $event"
(onSuccessfulImport)="this.onSuccessfulImport($event)"
></tools-import>
</div>

View File

@ -0,0 +1,31 @@
import { CommonModule } from "@angular/common";
import { Component } from "@angular/core";
import { Router, RouterLink } from "@angular/router";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { AsyncActionsModule, ButtonModule, DialogModule } from "@bitwarden/components";
import { ImportComponent } from "@bitwarden/importer/ui";
@Component({
templateUrl: "import-browser.component.html",
standalone: true,
imports: [
CommonModule,
RouterLink,
JslibModule,
DialogModule,
AsyncActionsModule,
ButtonModule,
ImportComponent,
],
})
export class ImportBrowserComponent {
protected disabled = false;
protected loading = false;
constructor(private router: Router) {}
protected async onSuccessfulImport(organizationId: string): Promise<void> {
this.router.navigate(["/tabs/settings"]);
}
}