mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
PM-19378 remove v1 notification bar path (#13973)
* PM-19378 - Remove NotificationBarAddLoginImproments flag - Remove divergent paths in various files - Fix tests to reflect new singular path * PM-19378 - Remove applyRedesign from relevant files - Update styling to reflect changes * remove notification-bar * edit styling for to accodmmodate v3 in iframe
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
import { mock, MockProxy } from "jest-mock-extended";
|
import { mock, MockProxy } from "jest-mock-extended";
|
||||||
import { BehaviorSubject } from "rxjs";
|
|
||||||
|
|
||||||
import { CLEAR_NOTIFICATION_LOGIN_DATA_DURATION } from "@bitwarden/common/autofill/constants";
|
import { CLEAR_NOTIFICATION_LOGIN_DATA_DURATION } from "@bitwarden/common/autofill/constants";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
|
||||||
import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config";
|
import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { EnvironmentServerConfigData } from "@bitwarden/common/platform/models/data/server-config.data";
|
import { EnvironmentServerConfigData } from "@bitwarden/common/platform/models/data/server-config.data";
|
||||||
@@ -25,8 +23,6 @@ import { OverlayNotificationsBackground } from "./overlay-notifications.backgrou
|
|||||||
|
|
||||||
describe("OverlayNotificationsBackground", () => {
|
describe("OverlayNotificationsBackground", () => {
|
||||||
let logService: MockProxy<LogService>;
|
let logService: MockProxy<LogService>;
|
||||||
let getFeatureFlagMock$: BehaviorSubject<boolean>;
|
|
||||||
let configService: MockProxy<ConfigService>;
|
|
||||||
let notificationBackground: NotificationBackground;
|
let notificationBackground: NotificationBackground;
|
||||||
let getEnableChangedPasswordPromptSpy: jest.SpyInstance;
|
let getEnableChangedPasswordPromptSpy: jest.SpyInstance;
|
||||||
let getEnableAddedLoginPromptSpy: jest.SpyInstance;
|
let getEnableAddedLoginPromptSpy: jest.SpyInstance;
|
||||||
@@ -35,10 +31,6 @@ describe("OverlayNotificationsBackground", () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
logService = mock<LogService>();
|
logService = mock<LogService>();
|
||||||
getFeatureFlagMock$ = new BehaviorSubject(true);
|
|
||||||
configService = mock<ConfigService>({
|
|
||||||
getFeatureFlag$: jest.fn().mockReturnValue(getFeatureFlagMock$),
|
|
||||||
});
|
|
||||||
notificationBackground = mock<NotificationBackground>();
|
notificationBackground = mock<NotificationBackground>();
|
||||||
getEnableChangedPasswordPromptSpy = jest
|
getEnableChangedPasswordPromptSpy = jest
|
||||||
.spyOn(notificationBackground, "getEnableChangedPasswordPrompt")
|
.spyOn(notificationBackground, "getEnableChangedPasswordPrompt")
|
||||||
@@ -48,10 +40,8 @@ describe("OverlayNotificationsBackground", () => {
|
|||||||
.mockResolvedValue(true);
|
.mockResolvedValue(true);
|
||||||
overlayNotificationsBackground = new OverlayNotificationsBackground(
|
overlayNotificationsBackground = new OverlayNotificationsBackground(
|
||||||
logService,
|
logService,
|
||||||
configService,
|
|
||||||
notificationBackground,
|
notificationBackground,
|
||||||
);
|
);
|
||||||
configService.getFeatureFlag.mockResolvedValue(true);
|
|
||||||
await overlayNotificationsBackground.init();
|
await overlayNotificationsBackground.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -60,27 +50,6 @@ describe("OverlayNotificationsBackground", () => {
|
|||||||
jest.clearAllTimers();
|
jest.clearAllTimers();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("feature flag behavior", () => {
|
|
||||||
let runtimeRemoveListenerSpy: jest.SpyInstance;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
runtimeRemoveListenerSpy = jest.spyOn(chrome.runtime.onMessage, "removeListener");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("removes the extension listeners if the current flag value is set to `false`", () => {
|
|
||||||
getFeatureFlagMock$.next(false);
|
|
||||||
|
|
||||||
expect(runtimeRemoveListenerSpy).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("ignores the feature flag change if the previous flag value is equal to the current flag value", () => {
|
|
||||||
getFeatureFlagMock$.next(false);
|
|
||||||
getFeatureFlagMock$.next(false);
|
|
||||||
|
|
||||||
expect(runtimeRemoveListenerSpy).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("setting up the form submission listeners", () => {
|
describe("setting up the form submission listeners", () => {
|
||||||
let fields: MockProxy<AutofillField>[];
|
let fields: MockProxy<AutofillField>[];
|
||||||
let details: MockProxy<AutofillPageDetails>;
|
let details: MockProxy<AutofillPageDetails>;
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { startWith, Subject, Subscription, switchMap, timer } from "rxjs";
|
import { Subject, switchMap, timer } from "rxjs";
|
||||||
import { pairwise } from "rxjs/operators";
|
|
||||||
|
|
||||||
import { CLEAR_NOTIFICATION_LOGIN_DATA_DURATION } from "@bitwarden/common/autofill/constants";
|
import { CLEAR_NOTIFICATION_LOGIN_DATA_DURATION } from "@bitwarden/common/autofill/constants";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
|
|
||||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||||
@@ -26,7 +23,6 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg
|
|||||||
private websiteOriginsWithFields: WebsiteOriginsWithFields = new Map();
|
private websiteOriginsWithFields: WebsiteOriginsWithFields = new Map();
|
||||||
private activeFormSubmissionRequests: ActiveFormSubmissionRequests = new Set();
|
private activeFormSubmissionRequests: ActiveFormSubmissionRequests = new Set();
|
||||||
private modifyLoginCipherFormData: ModifyLoginCipherFormDataForTab = new Map();
|
private modifyLoginCipherFormData: ModifyLoginCipherFormDataForTab = new Map();
|
||||||
private featureFlagState$: Subscription;
|
|
||||||
private clearLoginCipherFormDataSubject: Subject<void> = new Subject();
|
private clearLoginCipherFormDataSubject: Subject<void> = new Subject();
|
||||||
private notificationFallbackTimeout: number | NodeJS.Timeout | null;
|
private notificationFallbackTimeout: number | NodeJS.Timeout | null;
|
||||||
private readonly formSubmissionRequestMethods: Set<string> = new Set(["POST", "PUT", "PATCH"]);
|
private readonly formSubmissionRequestMethods: Set<string> = new Set(["POST", "PUT", "PATCH"]);
|
||||||
@@ -38,7 +34,6 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private configService: ConfigService,
|
|
||||||
private notificationBackground: NotificationBackground,
|
private notificationBackground: NotificationBackground,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -46,35 +41,13 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg
|
|||||||
* Initialize the overlay notifications background service.
|
* Initialize the overlay notifications background service.
|
||||||
*/
|
*/
|
||||||
async init() {
|
async init() {
|
||||||
this.featureFlagState$ = this.configService
|
this.setupExtensionListeners();
|
||||||
.getFeatureFlag$(FeatureFlag.NotificationBarAddLoginImprovements)
|
|
||||||
.pipe(startWith(undefined), pairwise())
|
|
||||||
.subscribe(([prev, current]) => this.handleInitFeatureFlagChange(prev, current));
|
|
||||||
this.clearLoginCipherFormDataSubject
|
this.clearLoginCipherFormDataSubject
|
||||||
.pipe(switchMap(() => timer(CLEAR_NOTIFICATION_LOGIN_DATA_DURATION)))
|
.pipe(switchMap(() => timer(CLEAR_NOTIFICATION_LOGIN_DATA_DURATION)))
|
||||||
.subscribe(() => this.modifyLoginCipherFormData.clear());
|
.subscribe(() => this.modifyLoginCipherFormData.clear());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles enabling/disabling the extension listeners that trigger the
|
|
||||||
* overlay notifications based on the feature flag state.
|
|
||||||
*
|
|
||||||
* @param previousValue - The previous value of the feature flag
|
|
||||||
* @param currentValue - The current value of the feature flag
|
|
||||||
*/
|
|
||||||
private handleInitFeatureFlagChange = (previousValue: boolean, currentValue: boolean) => {
|
|
||||||
if (previousValue === currentValue) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentValue) {
|
|
||||||
this.setupExtensionListeners();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.removeExtensionListeners();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the response from the content script with the page details. Triggers an initialization
|
* Handles the response from the content script with the page details. Triggers an initialization
|
||||||
* of the add login or change password notification if the conditions are met.
|
* of the add login or change password notification if the conditions are met.
|
||||||
@@ -520,15 +493,6 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg
|
|||||||
chrome.tabs.onUpdated.addListener(this.handleTabUpdated);
|
chrome.tabs.onUpdated.addListener(this.handleTabUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the listeners for the extension messages and the tab events.
|
|
||||||
*/
|
|
||||||
private removeExtensionListeners() {
|
|
||||||
BrowserApi.removeListener(chrome.runtime.onMessage, this.handleExtensionMessage);
|
|
||||||
chrome.tabs.onRemoved.removeListener(this.handleTabRemoved);
|
|
||||||
chrome.tabs.onUpdated.removeListener(this.handleTabUpdated);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles messages that are sent to the extension background.
|
* Handles messages that are sent to the extension background.
|
||||||
*
|
*
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,6 @@ const NotificationTypes = {
|
|||||||
type NotificationType = (typeof NotificationTypes)[keyof typeof NotificationTypes];
|
type NotificationType = (typeof NotificationTypes)[keyof typeof NotificationTypes];
|
||||||
|
|
||||||
type NotificationBarIframeInitData = {
|
type NotificationBarIframeInitData = {
|
||||||
applyRedesign?: boolean;
|
|
||||||
ciphers?: NotificationCipherData[];
|
ciphers?: NotificationCipherData[];
|
||||||
folders?: FolderView[];
|
folders?: FolderView[];
|
||||||
importType?: string;
|
importType?: string;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="notification-bar-outer-wrapper" class="outer-wrapper">
|
<div id="notification-bar-outer-wrapper" class="outer-wrapper">
|
||||||
<div class="logo">
|
<div class="logo-wrapper">
|
||||||
<a href="https://vault.bitwarden.com" target="_blank" id="logo-link" rel="noreferrer">
|
<a href="https://vault.bitwarden.com" target="_blank" id="logo-link" rel="noreferrer">
|
||||||
<img id="logo" alt="Bitwarden" />
|
<img id="logo" alt="Bitwarden" />
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
@import "../shared/styles/variables";
|
@import "../shared/styles/variables";
|
||||||
|
|
||||||
body {
|
body {
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
@@ -14,16 +14,30 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
font-family: $font-family-sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
.outer-wrapper {
|
.outer-wrapper {
|
||||||
padding: 0 10px;
|
display: block;
|
||||||
border-bottom: 2px solid transparent;
|
position: relative;
|
||||||
display: grid;
|
padding: 8px;
|
||||||
grid-template-columns: 24px auto 55px;
|
|
||||||
grid-column-gap: 10px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
@include themify($themes) {
|
@include themify($themes) {
|
||||||
|
border-color: themed("borderColor");
|
||||||
border-bottom-color: themed("primaryColor");
|
border-bottom-color: themed("primaryColor");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,20 +64,34 @@ body {
|
|||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
|
||||||
border: 0;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logo {
|
#logo {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logo-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
left: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
#close-button {
|
#close-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
@include themify($themes) {
|
||||||
|
border-color: rgba(themed("textColor"), 0.2);
|
||||||
|
background-color: rgba(themed("textColor"), 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#close {
|
#close {
|
||||||
@@ -78,15 +106,79 @@ img {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#close-button:hover {
|
.notification-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content .inner-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
.notification-body {
|
||||||
|
width: 100%;
|
||||||
|
padding: 4px 38px 24px 42px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-actions {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
#never-save {
|
||||||
|
margin-right: auto;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#select-folder {
|
||||||
|
width: 125px;
|
||||||
|
margin-right: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
appearance: none;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center right 4px;
|
||||||
|
background-size: 16px;
|
||||||
|
|
||||||
@include themify($themes) {
|
@include themify($themes) {
|
||||||
border-color: rgba(themed("textColor"), 0.2);
|
color: themed("mutedTextColor");
|
||||||
background-color: rgba(themed("textColor"), 0.2);
|
border-color: themed("mutedTextColor");
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not([disabled]) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary,
|
||||||
|
.secondary {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary {
|
||||||
|
margin-right: 6px;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary {
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.success-message,
|
||||||
|
&.error-message {
|
||||||
|
padding: 4px 36px 6px 42px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
padding: 0.35rem 15px;
|
padding: 4px 8px;
|
||||||
border-radius: $border-radius;
|
border-radius: $border-radius;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -133,14 +225,13 @@ button.neutral {
|
|||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
|
|
||||||
@include themify($themes) {
|
@include themify($themes) {
|
||||||
background-color: transparent;
|
|
||||||
color: darken(themed("primaryColor"), 6%);
|
color: darken(themed("primaryColor"), 6%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
padding: 0.35rem;
|
padding: 4px 6px;
|
||||||
border: 1px solid #000000;
|
border: 1px solid #000000;
|
||||||
border-radius: $border-radius;
|
border-radius: $border-radius;
|
||||||
|
|
||||||
@@ -151,16 +242,9 @@ select {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
select,
|
|
||||||
button {
|
|
||||||
font-size: $font-size-base;
|
|
||||||
font-family: $font-family-sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.success-message {
|
.success-message {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
align-content: center;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
@include themify($themes) {
|
@include themify($themes) {
|
||||||
@@ -184,6 +268,13 @@ button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.success-event,
|
||||||
|
.error-event {
|
||||||
|
.notification-body {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px) {
|
||||||
#select-folder {
|
#select-folder {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -196,131 +287,8 @@ button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-bar-redesign {
|
|
||||||
button {
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
padding: 4px 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.outer-wrapper {
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
padding: 8px;
|
|
||||||
border-top: 1px solid transparent;
|
|
||||||
border-left: 1px solid transparent;
|
|
||||||
border-right: 1px solid transparent;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
@include themify($themes) {
|
|
||||||
border-top-color: themed("borderColor");
|
|
||||||
border-left-color: themed("borderColor");
|
|
||||||
border-right-color: themed("borderColor");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
left: 10px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-close {
|
|
||||||
position: absolute;
|
|
||||||
top: 6px;
|
|
||||||
right: 6px;
|
|
||||||
|
|
||||||
#close-button {
|
|
||||||
display: flex;
|
|
||||||
align-content: center;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#content .inner-wrapper {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
align-content: flex-start;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
.notification-body {
|
|
||||||
width: 100%;
|
|
||||||
padding: 4px 38px 24px 42px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
.notification-actions {
|
|
||||||
display: flex;
|
|
||||||
align-items: stretch;
|
|
||||||
align-content: stretch;
|
|
||||||
justify-content: flex-end;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
#never-save {
|
|
||||||
margin-right: auto;
|
|
||||||
padding: 0;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#select-folder {
|
|
||||||
width: 125px;
|
|
||||||
margin-right: 6px;
|
|
||||||
font-size: 12px;
|
|
||||||
appearance: none;
|
|
||||||
background-size: 16px;
|
|
||||||
background-position: center right 4px;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
|
|
||||||
@include themify($themes) {
|
|
||||||
color: themed("mutedTextColor");
|
|
||||||
border-color: themed("mutedTextColor");
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not([disabled]) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary,
|
|
||||||
.secondary {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary {
|
|
||||||
margin-right: 6px;
|
|
||||||
border-width: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
margin-right: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.success-message,
|
|
||||||
&.error-message {
|
|
||||||
padding: 4px 36px 6px 42px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.success-event,
|
|
||||||
.error-event {
|
|
||||||
.notification-body {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme_light {
|
.theme_light {
|
||||||
.notification-bar-redesign #content .inner-wrapper {
|
#content .inner-wrapper {
|
||||||
#select-folder {
|
#select-folder {
|
||||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHhtbG5zOnhsaW5rPSdodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rJyB3aWR0aD0nMTYnIGhlaWdodD0nMTYnIGZpbGw9J25vbmUnPjxwYXRoIHN0cm9rZT0nIzIxMjUyOScgZD0nbTUgNiAzIDMgMy0zJy8+PC9zdmc+");
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHhtbG5zOnhsaW5rPSdodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rJyB3aWR0aD0nMTYnIGhlaWdodD0nMTYnIGZpbGw9J25vbmUnPjxwYXRoIHN0cm9rZT0nIzIxMjUyOScgZD0nbTUgNiAzIDMgMy0zJy8+PC9zdmc+");
|
||||||
}
|
}
|
||||||
@@ -328,7 +296,7 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.theme_dark {
|
.theme_dark {
|
||||||
.notification-bar-redesign #content .inner-wrapper {
|
#content .inner-wrapper {
|
||||||
#select-folder {
|
#select-folder {
|
||||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxNicgaGVpZ2h0PScxNicgZmlsbD0nbm9uZSc+PHBhdGggc3Ryb2tlPScjZmZmZmZmJyBkPSdtNSA2IDMgMyAzLTMnLz48L3N2Zz4=");
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxNicgaGVpZ2h0PScxNicgZmlsbD0nbm9uZSc+PHBhdGggc3Ryb2tlPScjZmZmZmZmJyBkPSdtNSA2IDMgMyAzLTMnLz48L3N2Zz4=");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -507,10 +507,6 @@ function setNotificationBarTheme() {
|
|||||||
const theme = getTheme(globalThis, notificationBarIframeInitData.theme);
|
const theme = getTheme(globalThis, notificationBarIframeInitData.theme);
|
||||||
|
|
||||||
document.documentElement.classList.add(`theme_${theme}`);
|
document.documentElement.classList.add(`theme_${theme}`);
|
||||||
|
|
||||||
if (notificationBarIframeInitData.applyRedesign) {
|
|
||||||
document.body.classList.add("notification-bar-redesign");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function postMessageToParent(message: NotificationBarWindowMessage) {
|
function postMessageToParent(message: NotificationBarWindowMessage) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export class OverlayNotificationsContentService
|
|||||||
private notificationBarIframeElement: HTMLIFrameElement | null = null;
|
private notificationBarIframeElement: HTMLIFrameElement | null = null;
|
||||||
private currentNotificationBarType: string | null = null;
|
private currentNotificationBarType: string | null = null;
|
||||||
private removeTabFromNotificationQueueTypes = new Set(["add", "change"]);
|
private removeTabFromNotificationQueueTypes = new Set(["add", "change"]);
|
||||||
|
private notificationRefreshFlag: boolean;
|
||||||
private notificationBarElementStyles: Partial<CSSStyleDeclaration> = {
|
private notificationBarElementStyles: Partial<CSSStyleDeclaration> = {
|
||||||
height: "82px",
|
height: "82px",
|
||||||
width: "430px",
|
width: "430px",
|
||||||
@@ -54,6 +55,9 @@ export class OverlayNotificationsContentService
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
void sendExtensionMessage("checkNotificationQueue");
|
void sendExtensionMessage("checkNotificationQueue");
|
||||||
|
void sendExtensionMessage("notificationRefreshFlagValue").then((notificationRefreshFlag) => {
|
||||||
|
this.notificationRefreshFlag = !!notificationRefreshFlag;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,7 +88,6 @@ export class OverlayNotificationsContentService
|
|||||||
theme: typeData.theme,
|
theme: typeData.theme,
|
||||||
removeIndividualVault: typeData.removeIndividualVault,
|
removeIndividualVault: typeData.removeIndividualVault,
|
||||||
importType: typeData.importType,
|
importType: typeData.importType,
|
||||||
applyRedesign: true,
|
|
||||||
launchTimestamp: typeData.launchTimestamp,
|
launchTimestamp: typeData.launchTimestamp,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -192,7 +195,13 @@ export class OverlayNotificationsContentService
|
|||||||
{ transform: "translateX(0)", opacity: "1" },
|
{ transform: "translateX(0)", opacity: "1" },
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
setElementStyles(this.notificationBarElement, { boxShadow: "2px 4px 6px 0px #0000001A" }, true);
|
if (!this.notificationRefreshFlag) {
|
||||||
|
setElementStyles(
|
||||||
|
this.notificationBarElement,
|
||||||
|
{ boxShadow: "2px 4px 6px 0px #0000001A" },
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
this.notificationBarIframeElement.removeEventListener(
|
this.notificationBarIframeElement.removeEventListener(
|
||||||
EVENTS.LOAD,
|
EVENTS.LOAD,
|
||||||
this.handleNotificationBarIframeOnLoad,
|
this.handleNotificationBarIframeOnLoad,
|
||||||
@@ -206,7 +215,13 @@ export class OverlayNotificationsContentService
|
|||||||
if (this.notificationBarIframeElement) {
|
if (this.notificationBarIframeElement) {
|
||||||
this.notificationBarElement = globalThis.document.createElement("div");
|
this.notificationBarElement = globalThis.document.createElement("div");
|
||||||
this.notificationBarElement.id = "bit-notification-bar";
|
this.notificationBarElement.id = "bit-notification-bar";
|
||||||
|
|
||||||
setElementStyles(this.notificationBarElement, this.notificationBarElementStyles, true);
|
setElementStyles(this.notificationBarElement, this.notificationBarElementStyles, true);
|
||||||
|
|
||||||
|
if (this.notificationRefreshFlag) {
|
||||||
|
setElementStyles(this.notificationBarElement, { height: "400px", right: "0" }, true);
|
||||||
|
}
|
||||||
|
|
||||||
this.notificationBarElement.appendChild(this.notificationBarIframeElement);
|
this.notificationBarElement.appendChild(this.notificationBarIframeElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ describe("AutofillService", () => {
|
|||||||
const autofillOverlayMenuBootstrapScript = "bootstrap-autofill-overlay-menu.js";
|
const autofillOverlayMenuBootstrapScript = "bootstrap-autofill-overlay-menu.js";
|
||||||
const autofillOverlayNotificationsBootstrapScript =
|
const autofillOverlayNotificationsBootstrapScript =
|
||||||
"bootstrap-autofill-overlay-notifications.js";
|
"bootstrap-autofill-overlay-notifications.js";
|
||||||
const defaultAutofillScripts = ["autofiller.js", "notificationBar.js", "contextMenuHandler.js"];
|
const defaultAutofillScripts = ["autofiller.js", "contextMenuHandler.js"];
|
||||||
const defaultExecuteScriptOptions = { runAt: "document_start" };
|
const defaultExecuteScriptOptions = { runAt: "document_start" };
|
||||||
let tabMock: chrome.tabs.Tab;
|
let tabMock: chrome.tabs.Tab;
|
||||||
let sender: chrome.runtime.MessageSender;
|
let sender: chrome.runtime.MessageSender;
|
||||||
@@ -400,13 +400,9 @@ describe("AutofillService", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("accepts an extension message sender and injects the autofill scripts into the tab of the sender", async () => {
|
it("accepts an extension message sender and injects the autofill scripts into the tab of the sender", async () => {
|
||||||
configService.getFeatureFlag.mockImplementation(async (_feature) => {
|
enableChangedPasswordPromptMock$.next(false);
|
||||||
if (_feature === FeatureFlag.NotificationBarAddLoginImprovements) {
|
enableAddedLoginPromptMock$.next(false);
|
||||||
return false as FeatureFlagValueType<any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true as FeatureFlagValueType<any>;
|
|
||||||
});
|
|
||||||
await autofillService.injectAutofillScripts(sender.tab, sender.frameId, true);
|
await autofillService.injectAutofillScripts(sender.tab, sender.frameId, true);
|
||||||
|
|
||||||
[autofillOverlayMenuBootstrapScript, ...defaultAutofillScripts].forEach((scriptName) => {
|
[autofillOverlayMenuBootstrapScript, ...defaultAutofillScripts].forEach((scriptName) => {
|
||||||
@@ -457,25 +453,12 @@ describe("AutofillService", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("will inject the bootstrap-autofill script if the user does not have the autofill overlay enabled", async () => {
|
it("will inject the overlay script if the user does not have the autofill overlay enabled", async () => {
|
||||||
jest
|
jest
|
||||||
.spyOn(autofillService, "getInlineMenuVisibility")
|
.spyOn(autofillService, "getInlineMenuVisibility")
|
||||||
.mockResolvedValue(AutofillOverlayVisibility.Off);
|
.mockResolvedValue(AutofillOverlayVisibility.Off);
|
||||||
configService.getFeatureFlag.mockImplementation(async (_feature) => {
|
|
||||||
if (_feature === FeatureFlag.NotificationBarAddLoginImprovements) {
|
|
||||||
return false as FeatureFlagValueType<any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true as FeatureFlagValueType<any>;
|
|
||||||
});
|
|
||||||
|
|
||||||
await autofillService.injectAutofillScripts(sender.tab, sender.frameId);
|
await autofillService.injectAutofillScripts(sender.tab, sender.frameId);
|
||||||
|
|
||||||
expect(BrowserApi.executeScriptInTab).toHaveBeenCalledWith(tabMock.id, {
|
|
||||||
file: `content/${autofillBootstrapScript}`,
|
|
||||||
frameId: sender.frameId,
|
|
||||||
...defaultExecuteScriptOptions,
|
|
||||||
});
|
|
||||||
expect(BrowserApi.executeScriptInTab).not.toHaveBeenCalledWith(tabMock.id, {
|
expect(BrowserApi.executeScriptInTab).not.toHaveBeenCalledWith(tabMock.id, {
|
||||||
file: `content/${autofillOverlayBootstrapScript}`,
|
file: `content/${autofillOverlayBootstrapScript}`,
|
||||||
frameId: sender.frameId,
|
frameId: sender.frameId,
|
||||||
|
|||||||
@@ -236,13 +236,8 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
const authStatus = await firstValueFrom(this.authService.activeAccountStatus$);
|
const authStatus = await firstValueFrom(this.authService.activeAccountStatus$);
|
||||||
const accountIsUnlocked = authStatus === AuthenticationStatus.Unlocked;
|
const accountIsUnlocked = authStatus === AuthenticationStatus.Unlocked;
|
||||||
let autoFillOnPageLoadIsEnabled = false;
|
let autoFillOnPageLoadIsEnabled = false;
|
||||||
const addLoginImprovementsFlagActive = await this.configService.getFeatureFlag(
|
|
||||||
FeatureFlag.NotificationBarAddLoginImprovements,
|
|
||||||
);
|
|
||||||
|
|
||||||
const injectedScripts = [
|
const injectedScripts = [await this.getBootstrapAutofillContentScript(activeAccount)];
|
||||||
await this.getBootstrapAutofillContentScript(activeAccount, addLoginImprovementsFlagActive),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (activeAccount && accountIsUnlocked) {
|
if (activeAccount && accountIsUnlocked) {
|
||||||
autoFillOnPageLoadIsEnabled = await this.getAutofillOnPageLoad();
|
autoFillOnPageLoadIsEnabled = await this.getAutofillOnPageLoad();
|
||||||
@@ -259,10 +254,6 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!addLoginImprovementsFlagActive) {
|
|
||||||
injectedScripts.push("notificationBar.js");
|
|
||||||
}
|
|
||||||
|
|
||||||
injectedScripts.push("contextMenuHandler.js");
|
injectedScripts.push("contextMenuHandler.js");
|
||||||
|
|
||||||
for (const injectedScript of injectedScripts) {
|
for (const injectedScript of injectedScripts) {
|
||||||
@@ -283,11 +274,9 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
* enabled.
|
* enabled.
|
||||||
*
|
*
|
||||||
* @param activeAccount - The active account
|
* @param activeAccount - The active account
|
||||||
* @param addLoginImprovementsFlagActive - Whether the add login improvements feature flag is active
|
|
||||||
*/
|
*/
|
||||||
private async getBootstrapAutofillContentScript(
|
private async getBootstrapAutofillContentScript(
|
||||||
activeAccount: { id: UserId | undefined } & AccountInfo,
|
activeAccount: { id: UserId | undefined } & AccountInfo,
|
||||||
addLoginImprovementsFlagActive = false,
|
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
let inlineMenuVisibility: InlineMenuVisibilitySetting = AutofillOverlayVisibility.Off;
|
let inlineMenuVisibility: InlineMenuVisibilitySetting = AutofillOverlayVisibility.Off;
|
||||||
|
|
||||||
@@ -310,8 +299,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
const enableAddedLoginPrompt = await firstValueFrom(
|
const enableAddedLoginPrompt = await firstValueFrom(
|
||||||
this.userNotificationSettingsService.enableAddedLoginPrompt$,
|
this.userNotificationSettingsService.enableAddedLoginPrompt$,
|
||||||
);
|
);
|
||||||
const isNotificationBarEnabled =
|
const isNotificationBarEnabled = enableChangedPasswordPrompt || enableAddedLoginPrompt;
|
||||||
addLoginImprovementsFlagActive && (enableChangedPasswordPrompt || enableAddedLoginPrompt);
|
|
||||||
|
|
||||||
if (!inlineMenuVisibility && !isNotificationBarEnabled) {
|
if (!inlineMenuVisibility && !isNotificationBarEnabled) {
|
||||||
return "bootstrap-autofill.js";
|
return "bootstrap-autofill.js";
|
||||||
|
|||||||
@@ -1195,7 +1195,6 @@ export default class MainBackground {
|
|||||||
|
|
||||||
this.overlayNotificationsBackground = new OverlayNotificationsBackground(
|
this.overlayNotificationsBackground = new OverlayNotificationsBackground(
|
||||||
this.logService,
|
this.logService,
|
||||||
this.configService,
|
|
||||||
this.notificationBackground,
|
this.notificationBackground,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -201,7 +201,6 @@ const mainConfig = {
|
|||||||
"./src/autofill/deprecated/content/bootstrap-legacy-autofill-overlay.ts",
|
"./src/autofill/deprecated/content/bootstrap-legacy-autofill-overlay.ts",
|
||||||
"content/autofiller": "./src/autofill/content/autofiller.ts",
|
"content/autofiller": "./src/autofill/content/autofiller.ts",
|
||||||
"content/auto-submit-login": "./src/autofill/content/auto-submit-login.ts",
|
"content/auto-submit-login": "./src/autofill/content/auto-submit-login.ts",
|
||||||
"content/notificationBar": "./src/autofill/content/notification-bar.ts",
|
|
||||||
"content/contextMenuHandler": "./src/autofill/content/context-menu-handler.ts",
|
"content/contextMenuHandler": "./src/autofill/content/context-menu-handler.ts",
|
||||||
"content/content-message-handler": "./src/autofill/content/content-message-handler.ts",
|
"content/content-message-handler": "./src/autofill/content/content-message-handler.ts",
|
||||||
"content/fido2-content-script": "./src/autofill/fido2/content/fido2-content-script.ts",
|
"content/fido2-content-script": "./src/autofill/fido2/content/fido2-content-script.ts",
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ export enum FeatureFlag {
|
|||||||
GenerateIdentityFillScriptRefactor = "generate-identity-fill-script-refactor",
|
GenerateIdentityFillScriptRefactor = "generate-identity-fill-script-refactor",
|
||||||
IdpAutoSubmitLogin = "idp-auto-submit-login",
|
IdpAutoSubmitLogin = "idp-auto-submit-login",
|
||||||
InlineMenuPositioningImprovements = "inline-menu-positioning-improvements",
|
InlineMenuPositioningImprovements = "inline-menu-positioning-improvements",
|
||||||
NotificationBarAddLoginImprovements = "notification-bar-add-login-improvements",
|
|
||||||
NotificationRefresh = "notification-refresh",
|
NotificationRefresh = "notification-refresh",
|
||||||
UseTreeWalkerApiForPageDetailsCollection = "use-tree-walker-api-for-page-details-collection",
|
UseTreeWalkerApiForPageDetailsCollection = "use-tree-walker-api-for-page-details-collection",
|
||||||
MacOsNativeCredentialSync = "macos-native-credential-sync",
|
MacOsNativeCredentialSync = "macos-native-credential-sync",
|
||||||
@@ -86,7 +85,6 @@ export const DefaultFeatureFlagValue = {
|
|||||||
[FeatureFlag.GenerateIdentityFillScriptRefactor]: FALSE,
|
[FeatureFlag.GenerateIdentityFillScriptRefactor]: FALSE,
|
||||||
[FeatureFlag.IdpAutoSubmitLogin]: FALSE,
|
[FeatureFlag.IdpAutoSubmitLogin]: FALSE,
|
||||||
[FeatureFlag.InlineMenuPositioningImprovements]: FALSE,
|
[FeatureFlag.InlineMenuPositioningImprovements]: FALSE,
|
||||||
[FeatureFlag.NotificationBarAddLoginImprovements]: FALSE,
|
|
||||||
[FeatureFlag.NotificationRefresh]: FALSE,
|
[FeatureFlag.NotificationRefresh]: FALSE,
|
||||||
[FeatureFlag.UseTreeWalkerApiForPageDetailsCollection]: FALSE,
|
[FeatureFlag.UseTreeWalkerApiForPageDetailsCollection]: FALSE,
|
||||||
[FeatureFlag.MacOsNativeCredentialSync]: FALSE,
|
[FeatureFlag.MacOsNativeCredentialSync]: FALSE,
|
||||||
|
|||||||
Reference in New Issue
Block a user