1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-10 05:30:01 +00:00

Merge branch 'main' into dirt/pm-21287/ngrx-poc

This commit is contained in:
Leslie Tilton
2025-06-02 13:54:14 -05:00
237 changed files with 2941 additions and 4036 deletions

View File

@@ -7,7 +7,6 @@ const sharedConfig = require("../../libs/shared/jest.config.angular");
/** @type {import('jest').Config} */
module.exports = {
...sharedConfig,
preset: "jest-preset-angular",
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
moduleNameMapper: pathsToModuleNameMapper(
{ "@bitwarden/common/spec": ["../../libs/common/spec"], ...(compilerOptions?.paths ?? {}) },

View File

@@ -5,7 +5,6 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
@@ -35,7 +34,6 @@ describe("AutoSubmitLoginBackground", () => {
let scriptInjectorService: MockProxy<ScriptInjectorService>;
let authStatus$: BehaviorSubject<AuthenticationStatus>;
let authService: MockProxy<AuthService>;
let configService: MockProxy<ConfigService>;
let platformUtilsService: MockProxy<PlatformUtilsService>;
let policyDetails: MockProxy<Policy>;
let automaticAppLogInPolicy$: BehaviorSubject<Policy[]>;
@@ -56,9 +54,6 @@ describe("AutoSubmitLoginBackground", () => {
authStatus$ = new BehaviorSubject(AuthenticationStatus.Unlocked);
authService = mock<AuthService>();
authService.activeAccountStatus$ = authStatus$;
configService = mock<ConfigService>({
getFeatureFlag: jest.fn().mockResolvedValue(true),
});
platformUtilsService = mock<PlatformUtilsService>();
policyDetails = mock<Policy>({
enabled: true,
@@ -78,7 +73,6 @@ describe("AutoSubmitLoginBackground", () => {
autofillService,
scriptInjectorService,
authService,
configService,
platformUtilsService,
policyService,
accountService,
@@ -89,7 +83,7 @@ describe("AutoSubmitLoginBackground", () => {
jest.clearAllMocks();
});
describe("when the AutoSubmitLoginBackground feature is disabled", () => {
describe("when conditions prevent auto-submit policy activation", () => {
it("destroys all event listeners when the AutomaticAppLogIn policy is not enabled", async () => {
automaticAppLogInPolicy$.next([mock<Policy>({ ...policyDetails, enabled: false })]);
@@ -115,7 +109,7 @@ describe("AutoSubmitLoginBackground", () => {
});
});
describe("when the AutoSubmitLoginBackground feature is enabled", () => {
describe("when the AutomaticAppLogIn policy is valid and active", () => {
let webRequestDetails: chrome.webRequest.WebRequestBodyDetails;
describe("starting the auto-submit login workflow", () => {
@@ -268,7 +262,6 @@ describe("AutoSubmitLoginBackground", () => {
autofillService,
scriptInjectorService,
authService,
configService,
platformUtilsService,
policyService,
accountService,

View File

@@ -10,8 +10,6 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
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 { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@@ -42,7 +40,6 @@ export class AutoSubmitLoginBackground implements AutoSubmitLoginBackgroundAbstr
private autofillService: AutofillService,
private scriptInjectorService: ScriptInjectorService,
private authService: AuthService,
private configService: ConfigService,
private platformUtilsService: PlatformUtilsService,
private policyService: PolicyService,
private accountService: AccountService,
@@ -51,25 +48,19 @@ export class AutoSubmitLoginBackground implements AutoSubmitLoginBackgroundAbstr
}
/**
* Initializes the auto-submit login policy. Will return early if
* the feature flag is not set. If the policy is not enabled, it
* Initializes the auto-submit login policy. If the policy is not enabled, it
* will trigger a removal of any established listeners.
*/
async init() {
const featureFlagEnabled = await this.configService.getFeatureFlag(
FeatureFlag.IdpAutoSubmitLogin,
);
if (featureFlagEnabled) {
this.accountService.activeAccount$
.pipe(
getUserId,
switchMap((userId) =>
this.policyService.policiesByType$(PolicyType.AutomaticAppLogIn, userId),
),
getFirstPolicy,
)
.subscribe(this.handleAutoSubmitLoginPolicySubscription.bind(this));
}
this.accountService.activeAccount$
.pipe(
getUserId,
switchMap((userId) =>
this.policyService.policiesByType$(PolicyType.AutomaticAppLogIn, userId),
),
getFirstPolicy,
)
.subscribe(this.handleAutoSubmitLoginPolicySubscription.bind(this));
}
/**

View File

@@ -3,7 +3,6 @@ import { BehaviorSubject } from "rxjs";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { Fido2ActiveRequestManager } from "@bitwarden/common/platform/abstractions/fido2/fido2-active-request-manager.abstraction";
import {
AssertCredentialParams,
@@ -60,7 +59,6 @@ describe("Fido2Background", () => {
let fido2ClientService!: MockProxy<Fido2ClientService<BrowserFido2ParentWindowReference>>;
let vaultSettingsService!: MockProxy<VaultSettingsService>;
let scriptInjectorServiceMock!: MockProxy<BrowserScriptInjectorService>;
let configServiceMock!: MockProxy<ConfigService>;
let enablePasskeysMock$!: BehaviorSubject<boolean>;
let activeAccountStatusMock$: BehaviorSubject<AuthenticationStatus>;
let authServiceMock!: MockProxy<AuthService>;
@@ -80,7 +78,6 @@ describe("Fido2Background", () => {
abortController = mock<AbortController>();
registeredContentScripsMock = mock<browser.contentScripts.RegisteredContentScript>();
scriptInjectorServiceMock = mock<BrowserScriptInjectorService>();
configServiceMock = mock<ConfigService>();
enablePasskeysMock$ = new BehaviorSubject(true);
vaultSettingsService.enablePasskeys$ = enablePasskeysMock$;
@@ -95,7 +92,6 @@ describe("Fido2Background", () => {
fido2ClientService,
vaultSettingsService,
scriptInjectorServiceMock,
configServiceMock,
authServiceMock,
);
fido2Background["abortManager"] = abortManagerMock;
@@ -186,7 +182,7 @@ describe("Fido2Background", () => {
expect(scriptInjectorServiceMock.inject).toHaveBeenCalledWith({
tabId: tabMock.id,
injectDetails: sharedScriptInjectionDetails,
mv2Details: { file: Fido2ContentScript.PageScriptAppend },
mv2Details: { file: Fido2ContentScript.PageScriptDelayAppend },
mv3Details: { file: Fido2ContentScript.PageScript, world: "MAIN" },
});
expect(scriptInjectorServiceMock.inject).toHaveBeenCalledWith({
@@ -202,22 +198,6 @@ describe("Fido2Background", () => {
enablePasskeysMock$.next(true);
await flushPromises();
expect(BrowserApi.registerContentScriptsMv2).toHaveBeenCalledWith({
js: [
{ file: Fido2ContentScript.PageScriptAppend },
{ file: Fido2ContentScript.ContentScript },
],
...sharedRegistrationOptions,
});
});
it("registers the page-script-delay-append-mv2.js content script when the DelayFido2PageScriptInitWithinMv2 feature flag is enabled", async () => {
configServiceMock.getFeatureFlag.mockResolvedValue(true);
isManifestVersionSpy.mockImplementation((manifestVersion) => manifestVersion === 2);
enablePasskeysMock$.next(true);
await flushPromises();
expect(BrowserApi.registerContentScriptsMv2).toHaveBeenCalledWith({
js: [
{ file: Fido2ContentScript.PageScriptDelayAppend },

View File

@@ -5,8 +5,6 @@ import { pairwise } from "rxjs/operators";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { Fido2ActiveRequestManager } from "@bitwarden/common/platform/abstractions/fido2/fido2-active-request-manager.abstraction";
import {
AssertCredentialParams,
@@ -60,7 +58,6 @@ export class Fido2Background implements Fido2BackgroundInterface {
private fido2ClientService: Fido2ClientService<BrowserFido2ParentWindowReference>,
private vaultSettingsService: VaultSettingsService,
private scriptInjectorService: ScriptInjectorService,
private configService: ConfigService,
private authService: AuthService,
) {}
@@ -403,14 +400,6 @@ export class Fido2Background implements Fido2BackgroundInterface {
* delayed append script if the associated feature flag is enabled.
*/
private async getFido2PageScriptAppendFileName() {
const shouldDelayInit = await this.configService.getFeatureFlag(
FeatureFlag.DelayFido2PageScriptInitWithinMv2,
);
if (shouldDelayInit) {
return Fido2ContentScript.PageScriptDelayAppend;
}
return Fido2ContentScript.PageScriptAppend;
return Fido2ContentScript.PageScriptDelayAppend;
}
}

View File

@@ -24,7 +24,7 @@ describe("FIDO2 page-script for manifest v2", () => {
// FIXME: Remove when updating file. Eslint update
// eslint-disable-next-line @typescript-eslint/no-require-imports
require("./fido2-page-script-append.mv2");
require("./fido2-page-script-delay-append.mv2.ts");
expect(window.document.createElement).not.toHaveBeenCalled();
});
@@ -37,7 +37,7 @@ describe("FIDO2 page-script for manifest v2", () => {
// FIXME: Remove when updating file. Eslint update
// eslint-disable-next-line @typescript-eslint/no-require-imports
require("./fido2-page-script-append.mv2");
require("./fido2-page-script-delay-append.mv2.ts");
expect(window.document.createElement).toHaveBeenCalledWith("script");
expect(chrome.runtime.getURL).toHaveBeenCalledWith(Fido2ContentScript.PageScript);
@@ -54,7 +54,7 @@ describe("FIDO2 page-script for manifest v2", () => {
// FIXME: Remove when updating file. Eslint update
// eslint-disable-next-line @typescript-eslint/no-require-imports
require("./fido2-page-script-append.mv2");
require("./fido2-page-script-delay-append.mv2.ts");
expect(window.document.createElement).toHaveBeenCalledWith("script");
expect(chrome.runtime.getURL).toHaveBeenCalledWith(Fido2ContentScript.PageScript);

View File

@@ -1,17 +0,0 @@
/**
* This script handles injection of the FIDO2 override page script into the document.
* This is required for manifest v2, but will be removed when we migrate fully to manifest v3.
*/
(function (globalContext) {
if (globalContext.document.contentType !== "text/html") {
return;
}
const script = globalContext.document.createElement("script");
script.src = chrome.runtime.getURL("content/fido2-page-script.js");
script.async = false;
const scriptInsertionPoint =
globalContext.document.head || globalContext.document.documentElement;
scriptInsertionPoint.prepend(script);
})(globalThis);

View File

@@ -1,6 +1,5 @@
export const Fido2ContentScript = {
PageScript: "content/fido2-page-script.js",
PageScriptAppend: "content/fido2-page-script-append-mv2.js",
PageScriptDelayAppend: "content/fido2-page-script-delay-append-mv2.js",
ContentScript: "content/fido2-content-script.js",
} as const;

View File

@@ -1156,7 +1156,6 @@ export default class MainBackground {
this.fido2ClientService,
this.vaultSettingsService,
this.scriptInjectorService,
this.configService,
this.authService,
);
@@ -1239,7 +1238,6 @@ export default class MainBackground {
this.autofillService,
this.scriptInjectorService,
this.authService,
this.configService,
this.platformUtilsService,
this.policyService,
this.accountService,

View File

@@ -10,7 +10,6 @@ import BrowserPopupUtils from "../browser-popup-utils";
@Component({
selector: "app-pop-out",
templateUrl: "pop-out.component.html",
standalone: true,
imports: [CommonModule, JslibModule, IconButtonModule],
})
export class PopOutComponent implements OnInit {

View File

@@ -11,7 +11,6 @@ import { enableAccountSwitching } from "../flags";
@Component({
selector: "app-header",
templateUrl: "header.component.html",
standalone: true,
imports: [CommonModule, CurrentAccountComponent],
})
export class HeaderComponent {

View File

@@ -9,7 +9,6 @@ import { PopupRouterCacheService } from "../view-cache/popup-router-cache.servic
/** Navigate the browser popup to the previous page when the component is clicked. */
@Directive({
selector: "[popupBackAction]",
standalone: true,
})
export class PopupBackBrowserDirective extends BitActionDirective {
constructor(

View File

@@ -3,7 +3,6 @@ import { Component } from "@angular/core";
@Component({
selector: "popup-footer",
templateUrl: "popup-footer.component.html",
standalone: true,
imports: [],
})
export class PopupFooterComponent {}

View File

@@ -19,7 +19,6 @@ import { PopupPageComponent } from "./popup-page.component";
@Component({
selector: "popup-header",
templateUrl: "popup-header.component.html",
standalone: true,
imports: [TypographyModule, CommonModule, IconButtonModule, JslibModule, AsyncActionsModule],
})
export class PopupHeaderComponent {

View File

@@ -36,7 +36,6 @@ import { PopupTabNavigationComponent } from "./popup-tab-navigation.component";
<ng-content></ng-content>
</div>
`,
standalone: true,
})
class ExtensionContainerComponent {}
@@ -71,7 +70,6 @@ class ExtensionContainerComponent {}
</bit-item-group>
</bit-section>
`,
standalone: true,
imports: [CommonModule, ItemModule, BadgeModule, IconButtonModule, SectionComponent],
})
class VaultComponent {
@@ -86,7 +84,6 @@ class VaultComponent {
Add
</button>
`,
standalone: true,
imports: [ButtonModule],
})
class MockAddButtonComponent {}
@@ -102,7 +99,6 @@ class MockAddButtonComponent {}
aria-label="Pop out"
></button>
`,
standalone: true,
imports: [IconButtonModule],
})
class MockPopoutButtonComponent {}
@@ -114,7 +110,6 @@ class MockPopoutButtonComponent {}
<bit-avatar text="Ash Ketchum" size="small"></bit-avatar>
</button>
`,
standalone: true,
imports: [AvatarModule],
})
class MockCurrentAccountComponent {}
@@ -122,7 +117,6 @@ class MockCurrentAccountComponent {}
@Component({
selector: "mock-search",
template: ` <bit-search placeholder="Search"> </bit-search> `,
standalone: true,
imports: [SearchModule],
})
class MockSearchComponent {}
@@ -134,7 +128,6 @@ class MockSearchComponent {}
This is an important note about these ciphers
</bit-banner>
`,
standalone: true,
imports: [BannerModule],
})
class MockBannerComponent {}
@@ -154,7 +147,6 @@ class MockBannerComponent {}
<vault-placeholder></vault-placeholder>
</popup-page>
`,
standalone: true,
imports: [
PopupPageComponent,
PopupHeaderComponent,
@@ -180,7 +172,6 @@ class MockVaultPageComponent {}
<vault-placeholder></vault-placeholder>
</popup-page>
`,
standalone: true,
imports: [
PopupPageComponent,
PopupHeaderComponent,
@@ -205,7 +196,6 @@ class MockVaultPagePoppedComponent {}
<div class="tw-text-main">Generator content here</div>
</popup-page>
`,
standalone: true,
imports: [
PopupPageComponent,
PopupHeaderComponent,
@@ -230,7 +220,6 @@ class MockGeneratorPageComponent {}
<div class="tw-text-main">Send content here</div>
</popup-page>
`,
standalone: true,
imports: [
PopupPageComponent,
PopupHeaderComponent,
@@ -255,7 +244,6 @@ class MockSendPageComponent {}
<div class="tw-text-main">Settings content here</div>
</popup-page>
`,
standalone: true,
imports: [
PopupPageComponent,
PopupHeaderComponent,
@@ -283,7 +271,6 @@ class MockSettingsPageComponent {}
</popup-footer>
</popup-page>
`,
standalone: true,
imports: [
PopupPageComponent,
PopupHeaderComponent,

View File

@@ -6,7 +6,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
@Component({
selector: "popup-page",
templateUrl: "popup-page.component.html",
standalone: true,
host: {
class: "tw-h-full tw-flex tw-flex-col tw-overflow-y-hidden",
},

View File

@@ -17,7 +17,6 @@ export type NavButton = {
@Component({
selector: "popup-tab-navigation",
templateUrl: "popup-tab-navigation.component.html",
standalone: true,
imports: [CommonModule, LinkModule, RouterModule, JslibModule, IconModule],
host: {
class: "tw-block tw-h-full tw-w-full tw-flex tw-flex-col",

View File

@@ -17,7 +17,6 @@ export type DesktopSyncVerificationDialogParams = {
@Component({
templateUrl: "desktop-sync-verification-dialog.component.html",
standalone: true,
imports: [JslibModule, ButtonModule, DialogModule],
})
export class DesktopSyncVerificationDialogComponent implements OnDestroy, OnInit {

View File

@@ -1,5 +1,5 @@
import { WritableSignal, signal } from "@angular/core";
import { TestBed, discardPeriodicTasks, fakeAsync, tick } from "@angular/core/testing";
import { TestBed } from "@angular/core/testing";
import { mock } from "jest-mock-extended";
import { BehaviorSubject, firstValueFrom, timeout } from "rxjs";
@@ -483,22 +483,15 @@ describe("VaultPopupItemsService", () => {
});
});
it("should update searchText$ when applyFilter is called", fakeAsync(() => {
let latestValue: string | null;
it("should update searchText$ when applyFilter is called", (done) => {
service.searchText$.subscribe((val) => {
latestValue = val;
expect(val).toEqual("test search");
expect(viewCacheService.mockSignal()).toEqual("test search");
done();
});
tick();
expect(latestValue!).toEqual("");
service.applyFilter("test search");
tick();
expect(latestValue!).toEqual("test search");
expect(viewCacheService.mockSignal()).toEqual("test search");
discardPeriodicTasks();
}));
});
});
// A function to generate a list of ciphers of different types

View File

@@ -1,7 +1,9 @@
{
"extends": "./tsconfig.json",
"files": ["./test.setup.ts"],
"compilerOptions": {
"isolatedModules": true,
"emitDecoratorMetadata": false,
"esModuleInterop": true
}
},
"files": ["./test.setup.ts"]
}

View File

@@ -324,8 +324,6 @@ if (manifestVersion == 2) {
// Manifest V2 background pages can be run through the regular build pipeline.
// Since it's a standard webpage.
mainConfig.entry.background = "./src/platform/background.ts";
mainConfig.entry["content/fido2-page-script-append-mv2"] =
"./src/autofill/fido2/content/fido2-page-script-append.mv2.ts";
mainConfig.entry["content/fido2-page-script-delay-append-mv2"] =
"./src/autofill/fido2/content/fido2-page-script-delay-append.mv2.ts";

View File

@@ -7,7 +7,6 @@ const sharedConfig = require("../../libs/shared/jest.config.angular");
/** @type {import('jest').Config} */
module.exports = {
...sharedConfig,
preset: "jest-preset-angular",
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
moduleNameMapper: pathsToModuleNameMapper(
{ "@bitwarden/common/spec": ["../../libs/common/spec"], ...(compilerOptions?.paths ?? {}) },

View File

@@ -9,7 +9,6 @@ export type BrowserSyncVerificationDialogParams = {
@Component({
templateUrl: "browser-sync-verification-dialog.component.html",
standalone: true,
imports: [JslibModule, ButtonModule, DialogModule],
})
export class BrowserSyncVerificationDialogComponent {

View File

@@ -13,7 +13,6 @@ import { FormFieldModule } from "@bitwarden/components";
*/
@Component({
selector: "app-user-verification",
standalone: true,
imports: [CommonModule, JslibModule, ReactiveFormsModule, FormFieldModule, FormsModule],
templateUrl: "user-verification.component.html",
providers: [

View File

@@ -9,7 +9,6 @@ export type VerifyNativeMessagingDialogData = {
@Component({
templateUrl: "verify-native-messaging-dialog.component.html",
standalone: true,
imports: [JslibModule, ButtonModule, DialogModule],
})
export class VerifyNativeMessagingDialogComponent {

View File

@@ -7,7 +7,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
@Component({
selector: "app-nav",
templateUrl: "nav.component.html",
standalone: true,
imports: [CommonModule, RouterLink, RouterLinkActive],
})
export class NavComponent {

View File

@@ -24,7 +24,6 @@ export interface ApproveSshRequestParams {
@Component({
selector: "app-approve-ssh-request",
templateUrl: "approve-ssh-request.html",
standalone: true,
imports: [
DialogModule,
CommonModule,

View File

@@ -1,4 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"isolatedModules": true,
"emitDecoratorMetadata": false
},
"files": ["./test.setup.ts"]
}

View File

@@ -7,7 +7,6 @@ const sharedConfig = require("../../libs/shared/jest.config.angular");
/** @type {import('jest').Config} */
module.exports = {
...sharedConfig,
preset: "jest-preset-angular",
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
moduleNameMapper: {
// Replace ESM SDK with Node compatible SDK

View File

@@ -1,6 +1,6 @@
{
"name": "@bitwarden/web-vault",
"version": "2025.5.1",
"version": "2025.6.0",
"scripts": {
"build:oss": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" webpack",
"build:bit": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" webpack -c ../../bitwarden_license/bit-web/webpack.config.js",

View File

@@ -11,7 +11,9 @@ import { DialogService, SimpleDialogOptions } from "@bitwarden/components";
import { OrganizationWarningsService } from "./organization-warnings.service";
describe("OrganizationWarningsService", () => {
// Skipped since Angular complains about `TypeError: Cannot read properties of undefined (reading 'ngModule')`
// which is typically a sign of circular dependencies. The problem seems to be originating from `ChangePlanDialogComponent`.
describe.skip("OrganizationWarningsService", () => {
let dialogService: MockProxy<DialogService>;
let i18nService: MockProxy<I18nService>;
let organizationApiService: MockProxy<OrganizationApiServiceAbstraction>;

View File

@@ -10,7 +10,6 @@ import { SharedModule } from "../shared";
type SizeTypes = "xlarge" | "large" | "default" | "small" | "xsmall";
@Component({
selector: "dynamic-avatar",
standalone: true,
imports: [SharedModule],
template: `<span [title]="title">
<bit-avatar

View File

@@ -15,7 +15,6 @@ import { SharedModule } from "../../shared";
@Component({
selector: "environment-selector",
templateUrl: "environment-selector.component.html",
standalone: true,
imports: [SharedModule],
})
export class EnvironmentSelectorComponent implements OnInit {

View File

@@ -19,6 +19,7 @@ import { NotificationsService } from "@bitwarden/common/platform/notifications";
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service";
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
import { TaskService } from "@bitwarden/common/vault/tasks";
import { KeyService as KeyServiceAbstraction } from "@bitwarden/key-management";
import { VersionService } from "../platform/version.service";
@@ -43,6 +44,7 @@ export class InitService {
private sdkLoadService: SdkLoadService,
private configService: ConfigService,
private bulkEncryptService: BulkEncryptService,
private taskService: TaskService,
@Inject(DOCUMENT) private document: Document,
) {}
@@ -75,6 +77,7 @@ export class InitService {
this.themingService.applyThemeChangesTo(this.document);
this.versionService.applyVersionToWindow();
void this.ipcService.init();
this.taskService.listenForTaskNotifications();
const containerService = new ContainerService(this.keyService, this.encryptService);
containerService.attachToGlobal(this.win);

View File

@@ -10,7 +10,6 @@ import { SharedModule } from "../shared";
@Component({
selector: "app-frontend-layout",
templateUrl: "frontend-layout.component.html",
standalone: true,
imports: [SharedModule, EnvironmentSelectorComponent],
})
export class FrontendLayoutComponent implements OnInit, OnDestroy {

View File

@@ -49,13 +49,13 @@ class MockStateService {
@Component({
selector: "product-switcher",
template: `<button type="button" bitIconButton="bwi-filter"></button>`,
standalone: false,
})
class MockProductSwitcher {}
@Component({
selector: "dynamic-avatar",
template: `<bit-avatar [text]="name$ | async"></bit-avatar>`,
standalone: true,
imports: [CommonModule, AvatarModule],
})
class MockDynamicAvatar implements Partial<DynamicAvatarComponent> {

View File

@@ -17,7 +17,6 @@ import { TrialFlowService } from "./../../billing/services/trial-flow.service";
@Component({
selector: "org-switcher",
templateUrl: "org-switcher.component.html",
standalone: true,
imports: [CommonModule, JslibModule, NavigationModule],
})
export class OrgSwitcherComponent {

View File

@@ -12,7 +12,6 @@ import { NavigationModule } from "@bitwarden/components";
*ngIf="isDev"
(click)="toggleWidth()"
></bit-nav-item>`,
standalone: true,
imports: [CommonModule, NavigationModule],
})
export class ToggleWidthComponent {

View File

@@ -19,7 +19,6 @@ import { WebLayoutModule } from "./web-layout.module";
@Component({
selector: "app-user-layout",
templateUrl: "user-layout.component.html",
standalone: true,
imports: [
CommonModule,
RouterModule,

View File

@@ -8,7 +8,6 @@ import { ProductSwitcherModule } from "./product-switcher/product-switcher.modul
@Component({
selector: "app-layout",
templateUrl: "web-layout.component.html",
standalone: true,
imports: [CommonModule, LayoutComponent, ProductSwitcherModule],
})
export class WebLayoutComponent {

View File

@@ -9,7 +9,6 @@ import { ToggleWidthComponent } from "./toggle-width.component";
@Component({
selector: "app-side-nav",
templateUrl: "web-side-nav.component.html",
standalone: true,
imports: [CommonModule, NavigationModule, ProductSwitcherModule, ToggleWidthComponent],
})
export class WebSideNavComponent {

View File

@@ -8,6 +8,9 @@ import { AccessComponent } from "./tools/send/send-access/access.component";
import { OrganizationBadgeModule } from "./vault/individual-vault/organization-badge/organization-badge.module";
import { VaultFilterModule } from "./vault/individual-vault/vault-filter/vault-filter.module";
// Register the locales for the application
import "./shared/locales";
@NgModule({
imports: [
SharedModule,

View File

@@ -15,7 +15,6 @@ import { SharedModule } from "../shared";
@Component({
selector: "app-domain-rules",
templateUrl: "domain-rules.component.html",
standalone: true,
imports: [SharedModule, HeaderModule],
})
export class DomainRulesComponent implements OnInit {

View File

@@ -41,7 +41,6 @@ import { SharedModule } from "../shared";
@Component({
selector: "app-preferences",
templateUrl: "preferences.component.html",
standalone: true,
imports: [SharedModule, HeaderModule, VaultTimeoutInputComponent],
})
export class PreferencesComponent implements OnInit, OnDestroy {

View File

@@ -9,7 +9,6 @@ import { SharedModule } from "../../shared.module";
@Component({
selector: "app-account-fingerprint",
templateUrl: "account-fingerprint.component.html",
standalone: true,
imports: [SharedModule],
})
export class AccountFingerprintComponent implements OnInit {

View File

@@ -32,9 +32,6 @@ import {
TypographyModule,
} from "@bitwarden/components";
// Register the locales for the application
import "./locales";
/**
* This NgModule should contain the most basic shared directives, pipes, and components. They
* should be widely used by other modules to be considered for adding to this module. If in doubt

View File

@@ -1,4 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"isolatedModules": true,
"emitDecoratorMetadata": false
},
"files": ["./test.setup.ts"]
}

View File

@@ -7,7 +7,6 @@ const sharedConfig = require("../../libs/shared/jest.config.angular");
/** @type {import('jest').Config} */
module.exports = {
...sharedConfig,
preset: "jest-preset-angular",
setupFilesAfterEnv: ["../../apps/web/test.setup.ts"],
moduleNameMapper: pathsToModuleNameMapper(
{

View File

@@ -1,6 +1,5 @@
import { Component, OnInit } from "@angular/core";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { AppComponent as BaseAppComponent } from "@bitwarden/web-vault/app/app.component";
import { ActivateAutofillPolicy } from "./admin-console/policies/activate-autofill.component";
@@ -25,13 +24,8 @@ export class AppComponent extends BaseAppComponent implements OnInit {
new ActivateAutofillPolicy(),
]);
this.configService.getFeatureFlag(FeatureFlag.IdpAutoSubmitLogin).then((enabled) => {
if (
enabled &&
!this.policyListService.getPolicies().some((p) => p instanceof AutomaticAppLoginPolicy)
) {
this.policyListService.addPolicies([new AutomaticAppLoginPolicy()]);
}
});
if (!this.policyListService.getPolicies().some((p) => p instanceof AutomaticAppLoginPolicy)) {
this.policyListService.addPolicies([new AutomaticAppLoginPolicy()]);
}
}
}

View File

@@ -59,7 +59,6 @@
type="button"
[buttonType]="'primary'"
bitButton
*ngIf="isCriticalAppsFeatureEnabled"
[disabled]="!selectedUrls.size"
[loading]="markingAsCritical"
(click)="markAppsAsCritical()"
@@ -74,7 +73,6 @@
[showRowCheckBox]="true"
[showRowMenuForCriticalApps]="false"
[selectedUrls]="selectedUrls"
[isCriticalAppsFeatureEnabled]="isCriticalAppsFeatureEnabled"
[isDrawerIsOpenForThisRecord]="isDrawerOpenForTableRow"
[checkboxChange]="onCheckboxChange"
[showAppAtRiskMembers]="showAppAtRiskMembers"

View File

@@ -21,7 +21,6 @@ import {
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
@@ -74,13 +73,8 @@ export class AllApplicationsComponent implements OnInit {
destroyRef = inject(DestroyRef);
isLoading$: Observable<boolean> = of(false);
isCriticalAppsFeatureEnabled = false;
async ngOnInit() {
this.isCriticalAppsFeatureEnabled = await this.configService.getFeatureFlag(
FeatureFlag.CriticalApps,
);
const organizationId = this.activatedRoute.snapshot.paramMap.get("organizationId") ?? "";
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));

View File

@@ -1,7 +1,7 @@
<ng-container>
<bit-table-scroll [dataSource]="dataSource" [rowSize]="53">
<ng-container header>
<th *ngIf="isCriticalAppsFeatureEnabled"></th>
<th></th>
<th bitCell></th>
<th bitSortable="applicationName" bitCell>{{ "application" | i18n }}</th>
<th bitSortable="atRiskPasswordCount" bitCell>{{ "atRiskPasswords" | i18n }}</th>
@@ -12,7 +12,7 @@
<ng-template bitRowDef let-row>
<td
bitCell
*ngIf="isCriticalAppsFeatureEnabled && showRowCheckBox"
*ngIf="showRowCheckBox"
[ngClass]="{ 'tw-bg-primary-100': isDrawerIsOpenForThisRecord(row.applicationName) }"
>
<input

View File

@@ -18,7 +18,6 @@ export class AppTableRowScrollableComponent {
@Input() showRowMenuForCriticalApps: boolean = false;
@Input() showRowCheckBox: boolean = false;
@Input() selectedUrls: Set<string> = new Set<string>();
@Input() isCriticalAppsFeatureEnabled: boolean = false;
@Input() isDrawerIsOpenForThisRecord!: (applicationName: string) => boolean;
@Input() showAppAtRiskMembers!: (applicationName: string) => void;
@Input() unmarkAsCriticalApp!: (applicationName: string) => void;

View File

@@ -82,7 +82,6 @@
[dataSource]="dataSource"
[showRowCheckBox]="false"
[showRowMenuForCriticalApps]="true"
[isCriticalAppsFeatureEnabled]="true"
[isDrawerIsOpenForThisRecord]="isDrawerOpenForTableRow"
[showAppAtRiskMembers]="showAppAtRiskMembers"
[unmarkAsCriticalApp]="unmarkAsCriticalApp"

View File

@@ -38,7 +38,7 @@
<bit-tab label="{{ 'allApplicationsWithCount' | i18n: appsCount }}">
<tools-all-applications></tools-all-applications>
</bit-tab>
<bit-tab *ngIf="isCriticalAppsFeatureEnabled">
<bit-tab>
<ng-template bitTabLabel>
<i class="bwi bwi-star"></i>
{{ "criticalApplicationsWithCount" | i18n: (criticalApps$ | async)?.length ?? 0 }}

View File

@@ -15,7 +15,6 @@ import {
DrawerType,
PasswordHealthReportApplicationsResponse,
} from "@bitwarden/bit-common/dirt/reports/risk-insights/models/password-health";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { devFlagEnabled } from "@bitwarden/common/platform/misc/flags";
import { OrganizationId } from "@bitwarden/common/types/guid";
@@ -70,7 +69,6 @@ export class RiskInsightsComponent implements OnInit {
dataLastUpdated: Date = new Date();
isCriticalAppsFeatureEnabled: boolean = false;
criticalApps$: Observable<PasswordHealthReportApplicationsResponse[]> = new Observable();
showDebugTabs: boolean = false;
@@ -100,10 +98,6 @@ export class RiskInsightsComponent implements OnInit {
}
async ngOnInit() {
this.isCriticalAppsFeatureEnabled = await this.configService.getFeatureFlag(
FeatureFlag.CriticalApps,
);
this.showDebugTabs = devFlagEnabled("showRiskInsightsDebug");
this.route.paramMap

View File

@@ -1,4 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"isolatedModules": true,
"emitDecoratorMetadata": false
},
"files": ["../../apps/web/test.setup.ts"]
}

View File

@@ -70,6 +70,7 @@ export default tseslint.config(
"@angular-eslint/no-output-on-prefix": 0,
"@angular-eslint/no-output-rename": 0,
"@angular-eslint/no-outputs-metadata-property": 0,
"@angular-eslint/prefer-standalone": 0,
"@angular-eslint/use-lifecycle-interface": "error",
"@angular-eslint/use-pipe-transform-interface": 0,
"@bitwarden/platform/required-using": "error",

View File

@@ -8,7 +8,6 @@ const sharedConfig = require("../../libs/shared/jest.config.angular");
module.exports = {
...sharedConfig,
displayName: "libs/admin-console tests",
preset: "jest-preset-angular",
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
moduleNameMapper: pathsToModuleNameMapper(
// lets us use @bitwarden/common/spec in tests

View File

@@ -1,4 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"isolatedModules": true,
"emitDecoratorMetadata": false
},
"files": ["./test.setup.ts"]
}

View File

@@ -8,7 +8,6 @@ const sharedConfig = require("../../libs/shared/jest.config.angular");
module.exports = {
...sharedConfig,
displayName: "libs/angular tests",
preset: "jest-preset-angular",
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
moduleNameMapper: pathsToModuleNameMapper(
// lets us use @bitwarden/common/spec in tests

View File

@@ -13,7 +13,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
import { activeAuthGuard } from "./active-auth.guard";
@Component({ template: "" })
@Component({ template: "", standalone: false })
class EmptyComponent {}
describe("activeAuthGuard", () => {

View File

@@ -27,6 +27,7 @@ const testStringFeatureValue = "test-value";
</div>
</div>
`,
standalone: false,
})
class TestComponent {
testBooleanFeature = testBooleanFeature;

View File

@@ -2,7 +2,6 @@ import { Directive, HostListener, Input } from "@angular/core";
@Directive({
selector: "[appTextDrag]",
standalone: true,
host: {
draggable: "true",
class: "tw-cursor-move",

View File

@@ -2,7 +2,6 @@ import { Pipe, PipeTransform } from "@angular/core";
@Pipe({
name: "pluralize",
standalone: true,
})
export class PluralizePipe implements PipeTransform {
transform(count: number, singular: string, plural: string): string {

View File

@@ -12,7 +12,7 @@ import { I18nMockService, ToastService } from "@bitwarden/components/src";
import { canAccessFeature } from "./feature-flag.guard";
@Component({ template: "" })
@Component({ template: "", standalone: false })
export class EmptyComponent {}
describe("canAccessFeature", () => {

View File

@@ -1,4 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"isolatedModules": true,
"emitDecoratorMetadata": false
},
"files": ["./test.setup.ts"]
}

View File

@@ -8,7 +8,6 @@ const sharedConfig = require("../../libs/shared/jest.config.angular");
module.exports = {
...sharedConfig,
displayName: "libs/auth tests",
preset: "jest-preset-angular",
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
moduleNameMapper: pathsToModuleNameMapper(
// lets us use @bitwarden/common/spec in tests

View File

@@ -44,7 +44,7 @@ import { TwoFactorAuthComponentCacheService } from "./two-factor-auth-component-
import { TwoFactorAuthComponentService } from "./two-factor-auth-component.service";
import { TwoFactorAuthComponent } from "./two-factor-auth.component";
@Component({})
@Component({ standalone: false })
class TestTwoFactorComponent extends TwoFactorAuthComponent {}
describe("TwoFactorAuthComponent", () => {

View File

@@ -11,7 +11,7 @@ import { LoginStrategyServiceAbstraction } from "../../common";
import { TwoFactorAuthGuard } from "./two-factor-auth.guard";
@Component({ template: "" })
@Component({ template: "", standalone: true })
export class EmptyComponent {}
describe("TwoFactorAuthGuard", () => {

View File

@@ -1,4 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"isolatedModules": true,
"emitDecoratorMetadata": false
},
"files": ["./test.setup.ts"]
}

View File

@@ -8,7 +8,6 @@ const sharedConfig = require("../../libs/shared/jest.config.angular");
module.exports = {
...sharedConfig,
displayName: "libs/billing tests",
preset: "jest-preset-angular",
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, {
prefix: "<rootDir>/",

View File

@@ -1,4 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"isolatedModules": true,
"emitDecoratorMetadata": false
},
"files": ["./test.setup.ts"]
}

View File

@@ -208,7 +208,7 @@ export abstract class ApiService {
deleteManyCiphersAdmin: (request: CipherBulkDeleteRequest) => Promise<any>;
putMoveCiphers: (request: CipherBulkMoveRequest) => Promise<any>;
putShareCipher: (id: string, request: CipherShareRequest) => Promise<CipherResponse>;
putShareCiphers: (request: CipherBulkShareRequest) => Promise<any>;
putShareCiphers: (request: CipherBulkShareRequest) => Promise<CipherResponse[]>;
putCipherCollections: (
id: string,
request: CipherCollectionsRequest,

View File

@@ -21,9 +21,7 @@ export enum FeatureFlag {
/* Autofill */
BlockBrowserInjectionsByDomain = "block-browser-injections-by-domain",
DelayFido2PageScriptInitWithinMv2 = "delay-fido2-page-script-init-within-mv2",
EnableNewCardCombinedExpiryAutofill = "enable-new-card-combined-expiry-autofill",
IdpAutoSubmitLogin = "idp-auto-submit-login",
NotificationRefresh = "notification-refresh",
UseTreeWalkerApiForPageDetailsCollection = "use-tree-walker-api-for-page-details-collection",
MacOsNativeCredentialSync = "macos-native-credential-sync",
@@ -37,7 +35,6 @@ export enum FeatureFlag {
UseOrganizationWarningsService = "use-organization-warnings-service",
/* Data Insights and Reporting */
CriticalApps = "pm-14466-risk-insights-critical-application",
EnableRiskInsightsNotifications = "enable-risk-insights-notifications",
/* Key Management */
@@ -87,15 +84,12 @@ export const DefaultFeatureFlagValue = {
/* Autofill */
[FeatureFlag.BlockBrowserInjectionsByDomain]: FALSE,
[FeatureFlag.DelayFido2PageScriptInitWithinMv2]: FALSE,
[FeatureFlag.EnableNewCardCombinedExpiryAutofill]: FALSE,
[FeatureFlag.IdpAutoSubmitLogin]: FALSE,
[FeatureFlag.NotificationRefresh]: FALSE,
[FeatureFlag.UseTreeWalkerApiForPageDetailsCollection]: FALSE,
[FeatureFlag.MacOsNativeCredentialSync]: FALSE,
/* Data Insights and Reporting */
[FeatureFlag.CriticalApps]: FALSE,
[FeatureFlag.EnableRiskInsightsNotifications]: FALSE,
/* Tools */

View File

@@ -532,8 +532,8 @@ export class ApiService implements ApiServiceAbstraction {
return new CipherResponse(r);
}
putShareCiphers(request: CipherBulkShareRequest): Promise<any> {
return this.send("PUT", "/ciphers/share", request, true, false);
async putShareCiphers(request: CipherBulkShareRequest): Promise<CipherResponse[]> {
return await this.send("PUT", "/ciphers/share", request, true, true);
}
async putCipherCollections(

View File

@@ -836,7 +836,7 @@ export class CipherService implements CipherServiceAbstraction {
organizationId: string,
collectionIds: string[],
userId: UserId,
): Promise<any> {
) {
const promises: Promise<any>[] = [];
const encCiphers: Cipher[] = [];
for (const cipher of ciphers) {
@@ -851,7 +851,16 @@ export class CipherService implements CipherServiceAbstraction {
await Promise.all(promises);
const request = new CipherBulkShareRequest(encCiphers, collectionIds, userId);
try {
await this.apiService.putShareCiphers(request);
const response = await this.apiService.putShareCiphers(request);
const responseMap = new Map(response.map((c) => [c.id, c]));
encCiphers.forEach((cipher) => {
const matchingCipher = responseMap.get(cipher.id);
if (matchingCipher) {
cipher.revisionDate = new Date(matchingCipher.revisionDate);
}
});
await this.upsert(encCiphers.map((c) => c.toCipherData()));
} catch (e) {
for (const cipher of ciphers) {
cipher.organizationId = null;
@@ -859,7 +868,6 @@ export class CipherService implements CipherServiceAbstraction {
}
throw e;
}
await this.upsert(encCiphers.map((c) => c.toCipherData()));
}
saveAttachmentWithServer(

View File

@@ -1,4 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"isolatedModules": true,
"emitDecoratorMetadata": false
},
"files": ["./test.setup.ts"]
}

View File

@@ -8,7 +8,6 @@ const sharedConfig = require("../../libs/shared/jest.config.angular");
module.exports = {
...sharedConfig,
displayName: "libs/components tests",
preset: "jest-preset-angular",
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, {
prefix: "<rootDir>/",

View File

@@ -6,7 +6,6 @@ import { FocusableElement } from "../shared/focusable-element";
@Directive({
selector: "bitA11yCell",
standalone: true,
providers: [{ provide: FocusableElement, useExisting: A11yCellDirective }],
})
export class A11yCellDirective implements FocusableElement {

View File

@@ -15,7 +15,6 @@ import { A11yRowDirective } from "./a11y-row.directive";
@Directive({
selector: "bitA11yGrid",
standalone: true,
})
export class A11yGridDirective implements AfterViewInit {
@HostBinding("attr.role")

View File

@@ -13,7 +13,6 @@ import { A11yCellDirective } from "./a11y-cell.directive";
@Directive({
selector: "bitA11yRow",
standalone: true,
})
export class A11yRowDirective implements AfterViewInit {
@HostBinding("attr.role")

View File

@@ -4,7 +4,6 @@ import { Directive, ElementRef, Input, OnInit, Renderer2 } from "@angular/core";
@Directive({
selector: "[appA11yTitle]",
standalone: true,
})
export class A11yTitleDirective implements OnInit {
@Input() set appA11yTitle(title: string) {

View File

@@ -15,7 +15,6 @@ import { FunctionReturningAwaitable, functionToObservable } from "../utils/funct
*/
@Directive({
selector: "[bitAction]",
standalone: true,
})
export class BitActionDirective implements OnDestroy {
private destroy$ = new Subject<void>();

View File

@@ -14,7 +14,6 @@ import { FunctionReturningAwaitable, functionToObservable } from "../utils/funct
*/
@Directive({
selector: "[formGroup][bitSubmit]",
standalone: true,
})
export class BitSubmitDirective implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();

View File

@@ -25,7 +25,6 @@ import { BitSubmitDirective } from "./bit-submit.directive";
*/
@Directive({
selector: "button[bitFormButton]",
standalone: true,
})
export class BitFormButtonDirective implements OnDestroy {
private destroy$ = new Subject<void>();

View File

@@ -30,11 +30,11 @@ const template = `
<button type="button" bitSuffix bitIconButton="bwi-refresh" bitFormButton [bitAction]="refresh"></button>
</bit-form-field>
<button class="tw-mr-2" type="submit" buttonType="primary" bitButton bitFormButton>Submit</button>
<button class="tw-mr-2" type="button" buttonType="secondary" bitButton bitFormButton>Cancel</button>
<button class="tw-mr-2" type="button" buttonType="danger" bitButton bitFormButton [bitAction]="delete">Delete</button>
<button class="tw-mr-2" type="button" buttonType="secondary" bitButton bitFormButton [disabled]="true">Disabled</button>
<button class="tw-mr-2" type="button" buttonType="secondary" bitIconButton="bwi-star" bitFormButton [bitAction]="delete">Delete</button>
<button class="tw-me-2" type="submit" buttonType="primary" bitButton bitFormButton>Submit</button>
<button class="tw-me-2" type="button" buttonType="secondary" bitButton bitFormButton>Cancel</button>
<button class="tw-me-2" type="button" buttonType="danger" bitButton bitFormButton [bitAction]="delete">Delete</button>
<button class="tw-me-2" type="button" buttonType="secondary" bitButton bitFormButton [disabled]="true">Disabled</button>
<button class="tw-me-2" type="button" buttonType="secondary" bitIconButton="bwi-star" bitFormButton [bitAction]="delete">Delete</button>
</form>`;
@Component({

View File

@@ -12,7 +12,7 @@ import { IconButtonModule } from "../icon-button";
import { BitActionDirective } from "./bit-action.directive";
const template = /*html*/ `
<button bitButton buttonType="primary" [bitAction]="action" class="tw-mr-2">
<button bitButton buttonType="primary" [bitAction]="action" class="tw-me-2">
Perform action {{ statusEmoji }}
</button>
<button bitIconButton="bwi-trash" buttonType="danger" [bitAction]="action"></button>`;

View File

@@ -27,7 +27,6 @@ const SizeClasses: Record<SizeTypes, string[]> = {
template: `@if (src) {
<img [src]="src" title="{{ title || text }}" [ngClass]="classList" />
}`,
standalone: true,
imports: [NgClass],
})
export class AvatarComponent implements OnChanges {

View File

@@ -10,7 +10,6 @@ import { BadgeModule, BadgeVariant } from "../badge";
@Component({
selector: "bit-badge-list",
templateUrl: "badge-list.component.html",
standalone: true,
imports: [BadgeModule, I18nPipe],
})
export class BadgeListComponent implements OnChanges {

View File

@@ -51,16 +51,15 @@ const hoverStyles: Record<BadgeVariant, string[]> = {
* The Badge directive can be used on a `<span>` (non clickable events), or an `<a>` or `<button>` tag
* > `NOTE:` The Focus and Hover states only apply to badges used for interactive events.
*
*
* > `NOTE:` The `disabled` state only applies to buttons.
*
*
*/
@Component({
selector: "span[bitBadge], a[bitBadge], button[bitBadge]",
providers: [{ provide: FocusableElement, useExisting: BadgeComponent }],
imports: [CommonModule],
templateUrl: "badge.component.html",
standalone: true,
})
export class BadgeComponent implements FocusableElement {
@HostBinding("class") get classList() {

View File

@@ -1,5 +1,5 @@
<div
class="tw-flex tw-items-center tw-gap-2 tw-p-2 tw-pl-4 tw-text-main tw-border-transparent tw-bg-clip-padding tw-border-solid tw-border-b tw-border-0"
class="tw-flex tw-items-center tw-gap-2 tw-p-2 tw-ps-4 tw-text-main tw-border-transparent tw-bg-clip-padding tw-border-solid tw-border-b tw-border-0"
[ngClass]="bannerClass"
[attr.role]="useAlertRole ? 'status' : null"
[attr.aria-live]="useAlertRole ? 'polite' : null"

View File

@@ -28,7 +28,6 @@ const defaultIcon: Record<BannerType, string> = {
@Component({
selector: "bit-banner",
templateUrl: "./banner.component.html",
standalone: true,
imports: [CommonModule, IconButtonModule, I18nPipe],
})
export class BannerComponent implements OnInit {

View File

@@ -1,6 +1,6 @@
<ng-template>
@if (icon) {
<i class="bwi {{ icon }} !tw-mr-2" aria-hidden="true"></i>
<i class="bwi {{ icon }} !tw-me-2" aria-hidden="true"></i>
}
<ng-content></ng-content>
</ng-template>

View File

@@ -7,7 +7,6 @@ import { QueryParamsHandling } from "@angular/router";
@Component({
selector: "bit-breadcrumb",
templateUrl: "./breadcrumb.component.html",
standalone: true,
})
export class BreadcrumbComponent {
@Input()

View File

@@ -16,7 +16,6 @@ import { BreadcrumbComponent } from "./breadcrumb.component";
@Component({
selector: "bit-breadcrumbs",
templateUrl: "./breadcrumbs.component.html",
standalone: true,
imports: [CommonModule, LinkModule, RouterModule, IconButtonModule, MenuModule],
})
export class BreadcrumbsComponent {

View File

@@ -85,6 +85,7 @@ describe("Button", () => {
<button id="disabled" type="button" bitButton disabled>Button</button>
`,
standalone: false,
})
class TestApp {
buttonType: string;

View File

@@ -52,7 +52,6 @@ const buttonStyles: Record<ButtonType, string[]> = {
selector: "button[bitButton], a[bitButton]",
templateUrl: "button.component.html",
providers: [{ provide: ButtonLikeAbstraction, useExisting: ButtonComponent }],
standalone: true,
imports: [NgClass],
host: {
"[attr.disabled]": "disabledAttr()",

View File

@@ -88,13 +88,13 @@ export const DisabledWithAttribute: Story = {
props: args,
template: `
@if (disabled) {
<button bitButton disabled [loading]="loading" [block]="block" buttonType="primary" class="tw-mr-2">Primary</button>
<button bitButton disabled [loading]="loading" [block]="block" buttonType="secondary" class="tw-mr-2">Secondary</button>
<button bitButton disabled [loading]="loading" [block]="block" buttonType="danger" class="tw-mr-2">Danger</button>
<button bitButton disabled [loading]="loading" [block]="block" buttonType="primary" class="tw-me-2">Primary</button>
<button bitButton disabled [loading]="loading" [block]="block" buttonType="secondary" class="tw-me-2">Secondary</button>
<button bitButton disabled [loading]="loading" [block]="block" buttonType="danger" class="tw-me-2">Danger</button>
} @else {
<button bitButton [loading]="loading" [block]="block" buttonType="primary" class="tw-mr-2">Primary</button>
<button bitButton [loading]="loading" [block]="block" buttonType="secondary" class="tw-mr-2">Secondary</button>
<button bitButton [loading]="loading" [block]="block" buttonType="danger" class="tw-mr-2">Danger</button>
<button bitButton [loading]="loading" [block]="block" buttonType="primary" class="tw-me-2">Primary</button>
<button bitButton [loading]="loading" [block]="block" buttonType="secondary" class="tw-me-2">Secondary</button>
<button bitButton [loading]="loading" [block]="block" buttonType="danger" class="tw-me-2">Danger</button>
}
`,
}),
@@ -110,10 +110,10 @@ export const Block: Story = {
template: `
<span class="tw-flex">
<button bitButton [buttonType]="buttonType" [block]="block">[block]="true" Button</button>
<a bitButton [buttonType]="buttonType" [block]="block" href="#" class="tw-ml-2">[block]="true" Link</a>
<a bitButton [buttonType]="buttonType" [block]="block" href="#" class="tw-ms-2">[block]="true" Link</a>
<button bitButton [buttonType]="buttonType" block class="tw-ml-2">block Button</button>
<a bitButton [buttonType]="buttonType" block href="#" class="tw-ml-2">block Link</a>
<button bitButton [buttonType]="buttonType" block class="tw-ms-2">block Button</button>
<a bitButton [buttonType]="buttonType" block href="#" class="tw-ms-2">block Link</a>
</span>
`,
}),

View File

@@ -1,5 +1,5 @@
<aside
class="tw-mb-4 tw-box-border tw-rounded-lg tw-border tw-border-l-4 tw-border-solid tw-bg-background tw-pl-3 tw-pr-2 tw-py-2 tw-leading-5 tw-text-main"
class="tw-mb-4 tw-box-border tw-rounded-lg tw-border tw-border-l-4 tw-border-solid tw-bg-background tw-ps-3 tw-pe-2 tw-py-2 tw-leading-5 tw-text-main"
[ngClass]="calloutClass"
[attr.aria-labelledby]="titleId"
>

Some files were not shown because too many files have changed in this diff Show More