1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-22 16:29:09 +01:00

[PM-4197] Enable importing on deskop (#6502)

* 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 deskop

Create import-dialog
Create file-menu entry to open import-dialog
Extend messages.json to include all the necessary messages from shared components

* Renamed filenames according to export rename

* Make ImportWebComponent standalone, simplify routing

* Pass organizationId as Input to ImportComponent

* use formLoading and formDisabled outputs

* use formLoading & formDisabled in desktop

* 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 deskop

Create import-dialog
Create file-menu entry to open import-dialog
Extend messages.json to include all the necessary messages from shared components

* use formLoading & formDisabled in desktop

* Add missing message for importBlockedByPolicy callout

* Remove commented code for submit button

* Implement onSuccessfulImport to close dialog on success

* fix table themes on desktop & browser

* fix fileSelector button styles

* update selectors to use tools prefix; remove unused selectors

* update selectors

* 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

* Use SharedModule as import in import-web.component

* File selector should be displayed as secondary

* 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>

* Use large dialogSize

* PM-4398 - 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 15:00:06 +02:00 committed by GitHub
parent 9e290a3fed
commit e357819251
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 184 additions and 0 deletions

View File

@ -55,6 +55,7 @@ import { FolderAddEditComponent } from "../vault/app/vault/folder-add-edit.compo
import { SettingsComponent } from "./accounts/settings.component"; import { SettingsComponent } from "./accounts/settings.component";
import { ExportComponent } from "./tools/export/export.component"; import { ExportComponent } from "./tools/export/export.component";
import { GeneratorComponent } from "./tools/generator.component"; import { GeneratorComponent } from "./tools/generator.component";
import { ImportDesktopComponent } from "./tools/import/import-desktop.component";
import { PasswordGeneratorHistoryComponent } from "./tools/password-generator-history.component"; import { PasswordGeneratorHistoryComponent } from "./tools/password-generator-history.component";
const BroadcasterSubscriptionId = "AppComponent"; const BroadcasterSubscriptionId = "AppComponent";
@ -328,6 +329,9 @@ export class AppComponent implements OnInit, OnDestroy {
} }
this.messagingService.send("scheduleNextSync"); this.messagingService.send("scheduleNextSync");
break; break;
case "importVault":
await this.dialogService.open(ImportDesktopComponent);
break;
case "exportVault": case "exportVault":
await this.openExportVault(); await this.openExportVault();
break; break;

View File

@ -0,0 +1,26 @@
<bit-dialog #dialog dialogSize="large">
<span bitDialogTitle>{{ "importData" | i18n }}</span>
<ng-container bitDialogContent>
<tools-import
(formLoading)="this.loading = $event"
(formDisabled)="this.disabled = $event"
(onSuccessfulImport)="this.onSuccessfulImport($event)"
></tools-import>
</ng-container>
<ng-container bitDialogFooter>
<button
[disabled]="disabled"
[loading]="loading"
form="importForm"
bitButton
type="submit"
bitFormButton
buttonType="primary"
>
{{ "importData" | i18n }}
</button>
<button type="button" bitButton bitFormButton buttonType="secondary" bitDialogClose>
{{ "cancel" | i18n }}
</button>
</ng-container>
</bit-dialog>

View File

@ -0,0 +1,33 @@
import { DialogRef } from "@angular/cdk/dialog";
import { CommonModule } from "@angular/common";
import { Component } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { AsyncActionsModule, ButtonModule, DialogModule } from "@bitwarden/components";
import { ImportComponent } from "@bitwarden/importer/ui";
@Component({
templateUrl: "import-desktop.component.html",
standalone: true,
imports: [
CommonModule,
JslibModule,
DialogModule,
AsyncActionsModule,
ButtonModule,
ImportComponent,
],
})
export class ImportDesktopComponent {
protected disabled = false;
protected loading = false;
constructor(public dialogRef: DialogRef) {}
/**
* Callback that is called after a successful import.
*/
protected async onSuccessfulImport(organizationId: string): Promise<void> {
this.dialogRef.close();
}
}

View File

@ -1662,6 +1662,9 @@
"personalOwnershipPolicyInEffect": { "personalOwnershipPolicyInEffect": {
"message": "An organization policy is affecting your ownership options." "message": "An organization policy is affecting your ownership options."
}, },
"personalOwnershipPolicyInEffectImports": {
"message": "An organization policy has blocked importing items into your individual vault."
},
"allSends": { "allSends": {
"message": "All Sends", "message": "All Sends",
"description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
@ -2427,5 +2430,113 @@
}, },
"aliasDomain": { "aliasDomain": {
"message": "Alias domain" "message": "Alias domain"
},
"importData": {
"message": "Import data",
"description": "Used for the desktop menu item and the header of the import dialog"
},
"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"
} }
} }

View File

@ -24,6 +24,7 @@ export class FileMenu extends FirstMenu implements IMenubarMenu {
this.addNewFolder, this.addNewFolder,
this.separator, this.separator,
this.syncVault, this.syncVault,
this.importVault,
this.exportVault, this.exportVault,
]; ];
@ -123,6 +124,15 @@ export class FileMenu extends FirstMenu implements IMenubarMenu {
}; };
} }
private get importVault(): MenuItemConstructorOptions {
return {
id: "importVault",
label: this.localize("importData"),
click: () => this.sendMessage("importVault"),
enabled: !this._isLocked,
};
}
private get exportVault(): MenuItemConstructorOptions { private get exportVault(): MenuItemConstructorOptions {
return { return {
id: "exportVault", id: "exportVault",