[PM-9455] Back Navigation in extension (#10496)
* refactor open-attachments component to push attachments route before opening the popout * use popupRouterCache for navigating the user back * use the PopupRouterCache for navigating the user after an attachment
This commit is contained in:
parent
59aa7ebc57
commit
8f07c78cc5
|
@ -1,4 +1,4 @@
|
|||
import { CommonModule, Location } from "@angular/common";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { FormsModule } from "@angular/forms";
|
||||
|
@ -27,6 +27,7 @@ import { PopOutComponent } from "../../../../../platform/popup/components/pop-ou
|
|||
import { PopupFooterComponent } from "../../../../../platform/popup/layout/popup-footer.component";
|
||||
import { PopupHeaderComponent } from "../../../../../platform/popup/layout/popup-header.component";
|
||||
import { PopupPageComponent } from "../../../../../platform/popup/layout/popup-page.component";
|
||||
import { PopupRouterCacheService } from "../../../../../platform/popup/view-cache/popup-router-cache.service";
|
||||
import { PopupCloseWarningService } from "../../../../../popup/services/popup-close-warning.service";
|
||||
import { BrowserCipherFormGenerationService } from "../../../services/browser-cipher-form-generation.service";
|
||||
import { BrowserTotpCaptureService } from "../../../services/browser-totp-capture.service";
|
||||
|
@ -150,11 +151,11 @@ export class AddEditV2Component implements OnInit {
|
|||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private location: Location,
|
||||
private popupRouterCacheService: PopupRouterCacheService,
|
||||
private i18nService: I18nService,
|
||||
private addEditFormConfigService: CipherFormConfigService,
|
||||
private router: Router,
|
||||
private popupCloseWarningService: PopupCloseWarningService,
|
||||
private router: Router,
|
||||
) {
|
||||
this.subscribeToParams();
|
||||
}
|
||||
|
@ -200,13 +201,7 @@ export class AddEditV2Component implements OnInit {
|
|||
return;
|
||||
}
|
||||
|
||||
if (history.length === 1) {
|
||||
await this.router.navigate(["/view-cipher"], {
|
||||
queryParams: { cipherId: this.originalCipherId },
|
||||
});
|
||||
} else {
|
||||
this.location.back();
|
||||
}
|
||||
await this.popupRouterCacheService.back();
|
||||
}
|
||||
|
||||
async onCipherSaved(cipher: CipherView) {
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
<popup-page>
|
||||
<popup-header
|
||||
slot="header"
|
||||
[pageTitle]="'attachments' | i18n"
|
||||
showBackButton
|
||||
[backAction]="handleBackButton.bind(this)"
|
||||
>
|
||||
<popup-header slot="header" [pageTitle]="'attachments' | i18n" showBackButton>
|
||||
<app-pop-out slot="end" />
|
||||
</popup-header>
|
||||
|
||||
|
@ -12,7 +7,7 @@
|
|||
*ngIf="cipherId"
|
||||
[cipherId]="cipherId"
|
||||
[submitBtn]="submitButton"
|
||||
(onUploadSuccess)="navigateToEditScreen()"
|
||||
(onUploadSuccess)="navigateBack()"
|
||||
></app-cipher-attachments>
|
||||
|
||||
<popup-footer slot="footer">
|
||||
|
|
|
@ -10,12 +10,12 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { ButtonComponent } from "@bitwarden/components";
|
||||
import { CipherAttachmentsComponent } from "@bitwarden/vault";
|
||||
|
||||
import { PopupFooterComponent } from "../../../../../platform/popup/layout/popup-footer.component";
|
||||
import { PopupHeaderComponent } from "../../../../../platform/popup/layout/popup-header.component";
|
||||
import { PopupRouterCacheService } from "../../../../../platform/popup/view-cache/popup-router-cache.service";
|
||||
|
||||
import { AttachmentsV2Component } from "./attachments-v2.component";
|
||||
|
||||
|
@ -44,16 +44,10 @@ describe("AttachmentsV2Component", () => {
|
|||
const queryParams = new BehaviorSubject<{ cipherId: string }>({ cipherId: "5555-444-3333" });
|
||||
let cipherAttachment: CipherAttachmentsComponent;
|
||||
const navigate = jest.fn();
|
||||
|
||||
const cipherDomain = {
|
||||
type: CipherType.Login,
|
||||
name: "Test Login",
|
||||
};
|
||||
|
||||
const cipherServiceGet = jest.fn().mockResolvedValue(cipherDomain);
|
||||
const back = jest.fn().mockResolvedValue(undefined);
|
||||
|
||||
beforeEach(async () => {
|
||||
cipherServiceGet.mockClear();
|
||||
back.mockClear();
|
||||
navigate.mockClear();
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
|
@ -62,6 +56,8 @@ describe("AttachmentsV2Component", () => {
|
|||
{ provide: LogService, useValue: mock<LogService>() },
|
||||
{ provide: ConfigService, useValue: mock<ConfigService>() },
|
||||
{ provide: PlatformUtilsService, useValue: mock<PlatformUtilsService>() },
|
||||
{ provide: CipherService, useValue: mock<CipherService>() },
|
||||
{ provide: PopupRouterCacheService, useValue: { back } },
|
||||
{ provide: I18nService, useValue: { t: (key: string) => key } },
|
||||
{ provide: Router, useValue: { navigate } },
|
||||
{
|
||||
|
@ -70,12 +66,6 @@ describe("AttachmentsV2Component", () => {
|
|||
queryParams,
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: CipherService,
|
||||
useValue: {
|
||||
get: cipherServiceGet,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
.overrideComponent(AttachmentsV2Component, {
|
||||
|
@ -115,9 +105,6 @@ describe("AttachmentsV2Component", () => {
|
|||
|
||||
tick();
|
||||
|
||||
expect(navigate).toHaveBeenCalledWith(["/edit-cipher"], {
|
||||
queryParams: { cipherId: "5555-444-3333", type: CipherType.Login },
|
||||
replaceUrl: true,
|
||||
});
|
||||
expect(back).toHaveBeenCalledTimes(1);
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import { CommonModule, Location } from "@angular/common";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { first } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { CipherId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { ButtonModule } from "@bitwarden/components";
|
||||
import { CipherAttachmentsComponent } from "@bitwarden/vault";
|
||||
|
||||
|
@ -14,6 +13,7 @@ import { PopOutComponent } from "../../../../../platform/popup/components/pop-ou
|
|||
import { PopupFooterComponent } from "../../../../../platform/popup/layout/popup-footer.component";
|
||||
import { PopupHeaderComponent } from "../../../../../platform/popup/layout/popup-header.component";
|
||||
import { PopupPageComponent } from "../../../../../platform/popup/layout/popup-page.component";
|
||||
import { PopupRouterCacheService } from "../../../../../platform/popup/view-cache/popup-router-cache.service";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
|
@ -38,9 +38,7 @@ export class AttachmentsV2Component {
|
|||
cipherId: CipherId;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private cipherService: CipherService,
|
||||
private location: Location,
|
||||
private popupRouterCacheService: PopupRouterCacheService,
|
||||
route: ActivatedRoute,
|
||||
) {
|
||||
route.queryParams.pipe(takeUntilDestroyed(), first()).subscribe(({ cipherId }) => {
|
||||
|
@ -48,30 +46,8 @@ export class AttachmentsV2Component {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to previous view or edit-cipher path
|
||||
* depending on the history length.
|
||||
*
|
||||
* This can happen when history is lost due to the extension being
|
||||
* forced into a popout window.
|
||||
*/
|
||||
async handleBackButton() {
|
||||
if (history.length === 1) {
|
||||
await this.navigateToEditScreen();
|
||||
} else {
|
||||
this.location.back();
|
||||
}
|
||||
}
|
||||
|
||||
/** Navigate the user back to the edit screen after uploading an attachment */
|
||||
async navigateToEditScreen() {
|
||||
const cipherDomain = await this.cipherService.get(this.cipherId);
|
||||
|
||||
void this.router.navigate(["/edit-cipher"], {
|
||||
queryParams: { cipherId: this.cipherId, type: cipherDomain.type },
|
||||
// "replaceUrl" so the /attachments route is not in the history, thus when a back button
|
||||
// is clicked, the user is taken to the view screen instead of the attachments screen
|
||||
replaceUrl: true,
|
||||
});
|
||||
async navigateBack() {
|
||||
await this.popupRouterCacheService.back();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,11 +102,10 @@ describe("OpenAttachmentsComponent", () => {
|
|||
|
||||
await component.openAttachments();
|
||||
|
||||
expect(router.navigate).not.toHaveBeenCalled();
|
||||
expect(openCurrentPagePopout).toHaveBeenCalledWith(
|
||||
window,
|
||||
"http:/localhost//attachments?cipherId=5555-444-3333",
|
||||
);
|
||||
expect(router.navigate).toHaveBeenCalledWith(["/attachments"], {
|
||||
queryParams: { cipherId: "5555-444-3333" },
|
||||
});
|
||||
expect(openCurrentPagePopout).toHaveBeenCalledWith(window);
|
||||
});
|
||||
|
||||
it("opens attachments in same window", async () => {
|
||||
|
|
|
@ -94,16 +94,13 @@ export class OpenAttachmentsComponent implements OnInit {
|
|||
return;
|
||||
}
|
||||
|
||||
await this.router.navigate(["/attachments"], { queryParams: { cipherId: this.cipherId } });
|
||||
|
||||
// Open the attachments page in a popout
|
||||
// This is done after the router navigation to ensure that the navigation
|
||||
// is included in the `PopupRouterCacheService` history
|
||||
if (this.openAttachmentsInPopout) {
|
||||
const destinationUrl = this.router
|
||||
.createUrlTree(["/attachments"], { queryParams: { cipherId: this.cipherId } })
|
||||
.toString();
|
||||
|
||||
const currentBaseUrl = window.location.href.replace(this.router.url, "");
|
||||
|
||||
await BrowserPopupUtils.openCurrentPagePopout(window, currentBaseUrl + destinationUrl);
|
||||
} else {
|
||||
await this.router.navigate(["/attachments"], { queryParams: { cipherId: this.cipherId } });
|
||||
await BrowserPopupUtils.openCurrentPagePopout(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue