From 5ffa3ccd200d70c7c043584002dbcf3569e13b88 Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Tue, 27 Sep 2022 11:17:43 +1000 Subject: [PATCH 01/10] Prevent banned imports into libs/common (#3599) Also fix typescript-eslint/parser config and fix linting errors --- .eslintrc.json | 35 +++++++++++++++++-- ...bitwardenPasswordProtectedImporter.spec.ts | 2 +- libs/common/spec/models/domain/cipher.spec.ts | 2 +- .../spec/models/domain/encString.spec.ts | 2 +- libs/common/spec/models/domain/login.spec.ts | 2 +- libs/common/spec/models/domain/send.spec.ts | 2 +- .../spec/models/domain/sendAccess.spec.ts | 2 +- .../spec/services/import.service.spec.ts | 2 +- libs/common/spec/utils.ts | 2 +- .../webCryptoFunction.service.spec.ts | 2 +- 10 files changed, 42 insertions(+), 11 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 3a1c197326d..fae64d869e8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,7 +4,7 @@ "browser": true, "webextensions": true }, - "plugins": ["@typescript-eslint", "rxjs", "rxjs-angular"], + "plugins": ["@typescript-eslint", "rxjs", "rxjs-angular", "import"], "parser": "@typescript-eslint/parser", "parserOptions": { "project": ["./tsconfig.eslint.json"], @@ -18,6 +18,16 @@ "prettier", "plugin:rxjs/recommended" ], + "settings": { + "import/parsers": { + "@typescript-eslint/parser": [".ts"] + }, + "import/resolver": { + "typescript": { + "alwaysTryTypes": true + } + } + }, "rules": { "@typescript-eslint/no-explicit-any": "off", // TODO: This should be re-enabled "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }], @@ -65,6 +75,27 @@ "selector": "CallExpression[callee.name='svgIcon']" } ], - "curly": ["error", "all"] + "curly": ["error", "all"], + "import/namespace": ["off"], // This doesn't resolve namespace imports correctly, but TS will throw for this anyway + "import/no-restricted-paths": [ + "error", + { + "zones": [ + // Do not allow angular/node/electron code to be imported into common + { + "target": "./libs/common/**/*", + "from": "./libs/angular/**/*" + }, + { + "target": "./libs/common/**/*", + "from": "./libs/node/**/*" + }, + { + "target": "./libs/common/**/*", + "from": "./libs/electron/**/*" + } + ] + } + ] } } diff --git a/libs/common/spec/importers/bitwardenPasswordProtectedImporter.spec.ts b/libs/common/spec/importers/bitwardenPasswordProtectedImporter.spec.ts index 820f8db38cc..67e03d030c5 100644 --- a/libs/common/spec/importers/bitwardenPasswordProtectedImporter.spec.ts +++ b/libs/common/spec/importers/bitwardenPasswordProtectedImporter.spec.ts @@ -1,4 +1,4 @@ -import Substitute, { Arg, SubstituteOf } from "@fluffy-spoon/substitute"; +import { Substitute, Arg, SubstituteOf } from "@fluffy-spoon/substitute"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; diff --git a/libs/common/spec/models/domain/cipher.spec.ts b/libs/common/spec/models/domain/cipher.spec.ts index c7c0d36714f..0158945d8ce 100644 --- a/libs/common/spec/models/domain/cipher.spec.ts +++ b/libs/common/spec/models/domain/cipher.spec.ts @@ -1,4 +1,4 @@ -import Substitute, { Arg } from "@fluffy-spoon/substitute"; +import { Substitute, Arg } from "@fluffy-spoon/substitute"; import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType"; import { CipherType } from "@bitwarden/common/enums/cipherType"; diff --git a/libs/common/spec/models/domain/encString.spec.ts b/libs/common/spec/models/domain/encString.spec.ts index adcfaf0706e..413d091d68b 100644 --- a/libs/common/spec/models/domain/encString.spec.ts +++ b/libs/common/spec/models/domain/encString.spec.ts @@ -1,4 +1,4 @@ -import Substitute, { Arg } from "@fluffy-spoon/substitute"; +import { Substitute, Arg } from "@fluffy-spoon/substitute"; import { mock, MockProxy } from "jest-mock-extended"; import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service"; diff --git a/libs/common/spec/models/domain/login.spec.ts b/libs/common/spec/models/domain/login.spec.ts index 6021a4b2908..b2235e75831 100644 --- a/libs/common/spec/models/domain/login.spec.ts +++ b/libs/common/spec/models/domain/login.spec.ts @@ -1,4 +1,4 @@ -import Substitute, { Arg } from "@fluffy-spoon/substitute"; +import { Substitute, Arg } from "@fluffy-spoon/substitute"; import { UriMatchType } from "@bitwarden/common/enums/uriMatchType"; import { LoginData } from "@bitwarden/common/models/data/loginData"; diff --git a/libs/common/spec/models/domain/send.spec.ts b/libs/common/spec/models/domain/send.spec.ts index 575821abc96..903043f86c8 100644 --- a/libs/common/spec/models/domain/send.spec.ts +++ b/libs/common/spec/models/domain/send.spec.ts @@ -1,4 +1,4 @@ -import Substitute, { Arg, SubstituteOf } from "@fluffy-spoon/substitute"; +import { Substitute, Arg, SubstituteOf } from "@fluffy-spoon/substitute"; import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; diff --git a/libs/common/spec/models/domain/sendAccess.spec.ts b/libs/common/spec/models/domain/sendAccess.spec.ts index 7772fe428ac..32b01d13fd4 100644 --- a/libs/common/spec/models/domain/sendAccess.spec.ts +++ b/libs/common/spec/models/domain/sendAccess.spec.ts @@ -1,4 +1,4 @@ -import Substitute, { Arg } from "@fluffy-spoon/substitute"; +import { Substitute, Arg } from "@fluffy-spoon/substitute"; import { SendType } from "@bitwarden/common/enums/sendType"; import { SendAccess } from "@bitwarden/common/models/domain/sendAccess"; diff --git a/libs/common/spec/services/import.service.spec.ts b/libs/common/spec/services/import.service.spec.ts index 654c1b6124f..2b47518bc5d 100644 --- a/libs/common/spec/services/import.service.spec.ts +++ b/libs/common/spec/services/import.service.spec.ts @@ -1,4 +1,4 @@ -import Substitute, { SubstituteOf } from "@fluffy-spoon/substitute"; +import { Substitute, SubstituteOf } from "@fluffy-spoon/substitute"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; diff --git a/libs/common/spec/utils.ts b/libs/common/spec/utils.ts index 0ea16b4d725..4f9dc4076f1 100644 --- a/libs/common/spec/utils.ts +++ b/libs/common/spec/utils.ts @@ -1,4 +1,4 @@ -import Substitute, { Arg } from "@fluffy-spoon/substitute"; +import { Substitute, Arg } from "@fluffy-spoon/substitute"; import { EncString } from "@bitwarden/common/models/domain/encString"; diff --git a/libs/common/spec/web/services/webCryptoFunction.service.spec.ts b/libs/common/spec/web/services/webCryptoFunction.service.spec.ts index 964364a1faf..ce131472d4b 100644 --- a/libs/common/spec/web/services/webCryptoFunction.service.spec.ts +++ b/libs/common/spec/web/services/webCryptoFunction.service.spec.ts @@ -1,4 +1,4 @@ -import Substitute from "@fluffy-spoon/substitute"; +import { Substitute } from "@fluffy-spoon/substitute"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { Utils } from "@bitwarden/common/misc/utils"; From b5de573497b770b723684d2a00eb95a85bb46db4 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Tue, 27 Sep 2022 11:22:31 +0200 Subject: [PATCH 02/10] fix: icon button style incompats (#3611) --- libs/components/src/icon-button/icon-button.component.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libs/components/src/icon-button/icon-button.component.ts b/libs/components/src/icon-button/icon-button.component.ts index cd6f1be402a..6696935257f 100644 --- a/libs/components/src/icon-button/icon-button.component.ts +++ b/libs/components/src/icon-button/icon-button.component.ts @@ -72,7 +72,7 @@ const sizes: Record = { @Component({ selector: "button[bitIconButton]", - template: ``, + template: ``, }) export class BitIconButtonComponent { @Input("bitIconButton") icon: string; @@ -106,10 +106,15 @@ export class BitIconButtonComponent { "before:tw-rounded-md", "before:tw-transition", "before:tw-ring", + "before:tw-ring-transparent", "focus-visible:before:tw-ring-text-contrast", "focus-visible:tw-z-10", ] .concat(styles[this.buttonType]) .concat(sizes[this.size]); } + + get iconClass() { + return [this.icon, "!tw-m-0"]; + } } From cd7c9bfd9f45754057671c21a53b5da8db0d40f7 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Tue, 27 Sep 2022 11:25:53 +0200 Subject: [PATCH 03/10] [EC-556] refactor cl button (#3537) * [EC-556] feat: convert button into component * [EC-556] feat: implement loading state * [EC-556] feat: remove loading from submit button * [EC-556] fix: add missing import * [EC-556] fix: disabling button using regular attribute * [EC-556] fix: missing loading input in story templates * [EC-556] feat: remove and replace submit button * Fix packaging on Build Web workflow (#3613) (cherry picked from commit 67c447d54ce0f08b99e2efc63b28cafac3411486) * [EC-556] fix: replaced buttons should be primary Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> --- .../register-form.component.html | 8 ++- .../trial-initiation/billing.component.html | 4 +- .../settings/account.component.html | 4 +- ...nroll-master-password-reset.component.html | 4 +- .../pages/breach-report.component.html | 4 +- .../exposed-passwords-report.component.html | 4 +- .../app/settings/change-kdf.component.html | 4 +- .../settings/change-password.component.html | 4 +- .../emergency-access-add-edit.component.html | 10 +++- .../organization-plans.component.html | 12 +++- .../src/app/settings/premium.component.html | 8 +-- .../settings/two-factor-setup.component.html | 10 +++- apps/web/src/app/shared/shared.module.ts | 3 - .../organizations/manage/scim.component.html | 10 +++- .../src/button/button.component.html | 8 +++ ...ctive.spec.ts => button.component.spec.ts} | 57 ++++++++++++++++++- ...utton.directive.ts => button.component.ts} | 15 ++++- libs/components/src/button/button.module.ts | 6 +- libs/components/src/button/button.stories.ts | 57 ++++++++++++++----- libs/components/src/button/index.ts | 2 +- libs/components/src/index.ts | 1 - libs/components/src/submit-button/index.ts | 1 - .../submit-button.component.html | 16 ------ .../submit-button/submit-button.component.ts | 19 ------- .../src/submit-button/submit-button.module.ts | 13 ----- .../submit-button/submit-button.stories.ts | 45 --------------- 26 files changed, 181 insertions(+), 148 deletions(-) create mode 100644 libs/components/src/button/button.component.html rename libs/components/src/button/{button.directive.spec.ts => button.component.spec.ts} (65%) rename libs/components/src/button/{button.directive.ts => button.component.ts} (82%) delete mode 100644 libs/components/src/submit-button/index.ts delete mode 100644 libs/components/src/submit-button/submit-button.component.html delete mode 100644 libs/components/src/submit-button/submit-button.component.ts delete mode 100644 libs/components/src/submit-button/submit-button.module.ts delete mode 100644 libs/components/src/submit-button/submit-button.stories.ts diff --git a/apps/web/src/app/accounts/register-form/register-form.component.html b/apps/web/src/app/accounts/register-form/register-form.component.html index 56364086ff9..d9456d5a6e9 100644 --- a/apps/web/src/app/accounts/register-form/register-form.component.html +++ b/apps/web/src/app/accounts/register-form/register-form.component.html @@ -114,7 +114,9 @@
- {{ "createAccount" | i18n }} + - {{ "logIn" | i18n }} +
diff --git a/apps/web/src/app/accounts/trial-initiation/billing.component.html b/apps/web/src/app/accounts/trial-initiation/billing.component.html index 4486d0672dd..0eb203f72ca 100644 --- a/apps/web/src/app/accounts/trial-initiation/billing.component.html +++ b/apps/web/src/app/accounts/trial-initiation/billing.component.html @@ -40,7 +40,9 @@
- {{ "startTrial" | i18n }} +
diff --git a/apps/web/src/app/organizations/settings/account.component.html b/apps/web/src/app/organizations/settings/account.component.html index 73a2f7872e7..1f2e145ae7a 100644 --- a/apps/web/src/app/organizations/settings/account.component.html +++ b/apps/web/src/app/organizations/settings/account.component.html @@ -66,9 +66,9 @@ - +
diff --git a/apps/web/src/app/organizations/users/enroll-master-password-reset.component.html b/apps/web/src/app/organizations/users/enroll-master-password-reset.component.html index 72f1bbdbda7..4d24e66764e 100644 --- a/apps/web/src/app/organizations/users/enroll-master-password-reset.component.html +++ b/apps/web/src/app/organizations/users/enroll-master-password-reset.component.html @@ -32,9 +32,9 @@
- +

{{ "reportError" | i18n }}...

diff --git a/apps/web/src/app/reports/pages/exposed-passwords-report.component.html b/apps/web/src/app/reports/pages/exposed-passwords-report.component.html index 2c5547efc7c..0fce002310b 100644 --- a/apps/web/src/app/reports/pages/exposed-passwords-report.component.html +++ b/apps/web/src/app/reports/pages/exposed-passwords-report.component.html @@ -2,9 +2,9 @@

{{ "exposedPasswordsReport" | i18n }}

{{ "exposedPasswordsReportDesc" | i18n }}

- +
{{ "noExposedPasswords" | i18n }} diff --git a/apps/web/src/app/settings/change-kdf.component.html b/apps/web/src/app/settings/change-kdf.component.html index b06cf01d060..1b3b62a03fb 100644 --- a/apps/web/src/app/settings/change-kdf.component.html +++ b/apps/web/src/app/settings/change-kdf.component.html @@ -71,7 +71,7 @@
- + diff --git a/apps/web/src/app/settings/change-password.component.html b/apps/web/src/app/settings/change-password.component.html index 6f36236a7ae..e74881db025 100644 --- a/apps/web/src/app/settings/change-password.component.html +++ b/apps/web/src/app/settings/change-password.component.html @@ -100,7 +100,7 @@
- + diff --git a/apps/web/src/app/settings/emergency-access-add-edit.component.html b/apps/web/src/app/settings/emergency-access-add-edit.component.html index 410489321a1..b438cee937c 100644 --- a/apps/web/src/app/settings/emergency-access-add-edit.component.html +++ b/apps/web/src/app/settings/emergency-access-add-edit.component.html @@ -100,9 +100,15 @@
- {{ - "submit" | i18n - }} + diff --git a/apps/web/src/app/settings/premium.component.html b/apps/web/src/app/settings/premium.component.html index 63995b457ac..13266fd9ca5 100644 --- a/apps/web/src/app/settings/premium.component.html +++ b/apps/web/src/app/settings/premium.component.html @@ -68,9 +68,9 @@ "licenseFileDesc" | i18n: "bitwarden_premium_license.json" }}
- +
@@ -118,7 +118,7 @@

{{ "paymentChargedAnnually" | i18n }} - + diff --git a/apps/web/src/app/settings/two-factor-setup.component.html b/apps/web/src/app/settings/two-factor-setup.component.html index 698e7fd9c07..b846fdb9816 100644 --- a/apps/web/src/app/settings/two-factor-setup.component.html +++ b/apps/web/src/app/settings/two-factor-setup.component.html @@ -77,9 +77,15 @@ {{ "deviceVerificationDesc" | i18n }} - + diff --git a/apps/web/src/app/shared/shared.module.ts b/apps/web/src/app/shared/shared.module.ts index 342948bb515..c0a076e545e 100644 --- a/apps/web/src/app/shared/shared.module.ts +++ b/apps/web/src/app/shared/shared.module.ts @@ -12,7 +12,6 @@ import { ButtonModule, CalloutModule, FormFieldModule, - SubmitButtonModule, MenuModule, IconModule, } from "@bitwarden/components"; @@ -44,7 +43,6 @@ import "./locales"; ButtonModule, MenuModule, FormFieldModule, - SubmitButtonModule, IconModule, ], exports: [ @@ -63,7 +61,6 @@ import "./locales"; ButtonModule, MenuModule, FormFieldModule, - SubmitButtonModule, IconModule, ], providers: [DatePipe], diff --git a/bitwarden_license/bit-web/src/app/organizations/manage/scim.component.html b/bitwarden_license/bit-web/src/app/organizations/manage/scim.component.html index 54fe44e073c..3d27448753f 100644 --- a/bitwarden_license/bit-web/src/app/organizations/manage/scim.component.html +++ b/bitwarden_license/bit-web/src/app/organizations/manage/scim.component.html @@ -81,7 +81,13 @@ {{ "scimApiKeyHelperText" | i18n }} - + diff --git a/libs/components/src/button/button.component.html b/libs/components/src/button/button.component.html new file mode 100644 index 00000000000..4875c159e92 --- /dev/null +++ b/libs/components/src/button/button.component.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/libs/components/src/button/button.directive.spec.ts b/libs/components/src/button/button.component.spec.ts similarity index 65% rename from libs/components/src/button/button.directive.spec.ts rename to libs/components/src/button/button.component.spec.ts index a7c3024e480..48aa8928e90 100644 --- a/libs/components/src/button/button.directive.spec.ts +++ b/libs/components/src/button/button.component.spec.ts @@ -8,6 +8,7 @@ describe("Button", () => { let fixture: ComponentFixture; let testAppComponent: TestApp; let buttonDebugElement: DebugElement; + let disabledButtonDebugElement: DebugElement; let linkDebugElement: DebugElement; beforeEach(waitForAsync(() => { @@ -20,6 +21,7 @@ describe("Button", () => { fixture = TestBed.createComponent(TestApp); testAppComponent = fixture.debugElement.componentInstance; buttonDebugElement = fixture.debugElement.query(By.css("button")); + disabledButtonDebugElement = fixture.debugElement.query(By.css("button#disabled")); linkDebugElement = fixture.debugElement.query(By.css("a")); })); @@ -60,16 +62,67 @@ describe("Button", () => { expect(buttonDebugElement.nativeElement.classList.contains("tw-block")).toBe(false); expect(linkDebugElement.nativeElement.classList.contains("tw-block")).toBe(false); }); + + it("should not be disabled when loading and disabled are false", () => { + testAppComponent.loading = false; + testAppComponent.disabled = false; + fixture.detectChanges(); + + expect(buttonDebugElement.attributes["loading"]).toBeFalsy(); + expect(linkDebugElement.attributes["loading"]).toBeFalsy(); + expect(buttonDebugElement.nativeElement.disabled).toBeFalsy(); + }); + + it("should be disabled when disabled is true", () => { + testAppComponent.disabled = true; + fixture.detectChanges(); + + expect(buttonDebugElement.nativeElement.disabled).toBeTruthy(); + // Anchor tags cannot be disabled. + }); + + it("should be disabled when attribute disabled is true", () => { + expect(disabledButtonDebugElement.nativeElement.disabled).toBeTruthy(); + }); + + it("should be disabled when loading is true", () => { + testAppComponent.loading = true; + fixture.detectChanges(); + + expect(buttonDebugElement.nativeElement.disabled).toBeTruthy(); + }); }); @Component({ selector: "test-app", template: ` - - Link + + + Link + + + `, }) class TestApp { buttonType: string; block: boolean; + disabled: boolean; + loading: boolean; } diff --git a/libs/components/src/button/button.directive.ts b/libs/components/src/button/button.component.ts similarity index 82% rename from libs/components/src/button/button.directive.ts rename to libs/components/src/button/button.component.ts index 5c4b0039aef..eeba83b8156 100644 --- a/libs/components/src/button/button.directive.ts +++ b/libs/components/src/button/button.component.ts @@ -1,4 +1,4 @@ -import { Input, HostBinding, Directive } from "@angular/core"; +import { Input, HostBinding, Component } from "@angular/core"; export type ButtonTypes = "primary" | "secondary" | "danger"; @@ -38,10 +38,11 @@ const buttonStyles: Record = { ], }; -@Directive({ +@Component({ selector: "button[bitButton], a[bitButton]", + templateUrl: "button.component.html", }) -export class ButtonDirective { +export class ButtonComponent { @HostBinding("class") get classList() { return [ "tw-font-semibold", @@ -65,6 +66,14 @@ export class ButtonDirective { .concat(buttonStyles[this.buttonType ?? "secondary"]); } + @HostBinding("attr.disabled") + get disabledAttr() { + const disabled = this.disabled != null && this.disabled !== false; + return disabled || this.loading ? true : null; + } + @Input() buttonType: ButtonTypes = null; @Input() block?: boolean; + @Input() loading = false; + @Input() disabled = false; } diff --git a/libs/components/src/button/button.module.ts b/libs/components/src/button/button.module.ts index c9c3822abfa..448e7c9dcf6 100644 --- a/libs/components/src/button/button.module.ts +++ b/libs/components/src/button/button.module.ts @@ -1,11 +1,11 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; -import { ButtonDirective } from "./button.directive"; +import { ButtonComponent } from "./button.component"; @NgModule({ imports: [CommonModule], - exports: [ButtonDirective], - declarations: [ButtonDirective], + exports: [ButtonComponent], + declarations: [ButtonComponent], }) export class ButtonModule {} diff --git a/libs/components/src/button/button.stories.ts b/libs/components/src/button/button.stories.ts index f09b8701b1b..4b9b88d48b1 100644 --- a/libs/components/src/button/button.stories.ts +++ b/libs/components/src/button/button.stories.ts @@ -1,12 +1,14 @@ import { Meta, Story } from "@storybook/angular"; -import { ButtonDirective } from "./button.directive"; +import { ButtonComponent } from "./button.component"; export default { title: "Component Library/Button", - component: ButtonDirective, + component: ButtonComponent, args: { buttonType: "primary", + disabled: false, + loading: false, }, parameters: { design: { @@ -16,11 +18,11 @@ export default { }, } as Meta; -const Template: Story = (args: ButtonDirective) => ({ +const Template: Story = (args: ButtonComponent) => ({ props: args, template: ` - - Link + + Link `, }); @@ -39,21 +41,50 @@ Danger.args = { buttonType: "danger", }; -const DisabledTemplate: Story = (args) => ({ +const AllStylesTemplate: Story = (args) => ({ props: args, template: ` - - - + + + `, }); -export const Disabled = DisabledTemplate.bind({}); -Disabled.args = { - size: "small", +export const Loading = AllStylesTemplate.bind({}); +Loading.args = { + disabled: false, + loading: true, }; -const BlockTemplate: Story = (args: ButtonDirective) => ({ +export const Disabled = AllStylesTemplate.bind({}); +Disabled.args = { + disabled: true, + loading: false, +}; + +const DisabledWithAttributeTemplate: Story = (args) => ({ + props: args, + template: ` + + + + + + + + + + + `, +}); + +export const DisabledWithAttribute = DisabledWithAttributeTemplate.bind({}); +DisabledWithAttribute.args = { + disabled: true, + loading: false, +}; + +const BlockTemplate: Story = (args: ButtonComponent) => ({ props: args, template: ` diff --git a/libs/components/src/button/index.ts b/libs/components/src/button/index.ts index 1bdd62ddbcf..ff86120cb11 100644 --- a/libs/components/src/button/index.ts +++ b/libs/components/src/button/index.ts @@ -1,2 +1,2 @@ -export * from "./button.directive"; +export * from "./button.component"; export * from "./button.module"; diff --git a/libs/components/src/index.ts b/libs/components/src/index.ts index 1f1ae6a8d2b..264c655d80f 100644 --- a/libs/components/src/index.ts +++ b/libs/components/src/index.ts @@ -7,7 +7,6 @@ export * from "./icon"; export * from "./icon-button"; export * from "./menu"; export * from "./dialog"; -export * from "./submit-button"; export * from "./link"; export * from "./tabs"; export * from "./toggle-group"; diff --git a/libs/components/src/submit-button/index.ts b/libs/components/src/submit-button/index.ts deleted file mode 100644 index ae7d96d2c1a..00000000000 --- a/libs/components/src/submit-button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./submit-button.module"; diff --git a/libs/components/src/submit-button/submit-button.component.html b/libs/components/src/submit-button/submit-button.component.html deleted file mode 100644 index 9d9657ba7ee..00000000000 --- a/libs/components/src/submit-button/submit-button.component.html +++ /dev/null @@ -1,16 +0,0 @@ - diff --git a/libs/components/src/submit-button/submit-button.component.ts b/libs/components/src/submit-button/submit-button.component.ts deleted file mode 100644 index 27408349da7..00000000000 --- a/libs/components/src/submit-button/submit-button.component.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Component, HostBinding, Input } from "@angular/core"; - -import { ButtonTypes } from "../button"; - -@Component({ - selector: "bit-submit-button", - templateUrl: "./submit-button.component.html", -}) -export class SubmitButtonComponent { - @Input() buttonType: ButtonTypes = "primary"; - @Input() disabled = false; - @Input() loading: boolean; - - @Input() block?: boolean; - - @HostBinding("class") get classList() { - return this.block == null || this.block === false ? [] : ["tw-w-full", "tw-block"]; - } -} diff --git a/libs/components/src/submit-button/submit-button.module.ts b/libs/components/src/submit-button/submit-button.module.ts deleted file mode 100644 index c7ab7567e64..00000000000 --- a/libs/components/src/submit-button/submit-button.module.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { CommonModule } from "@angular/common"; -import { NgModule } from "@angular/core"; - -import { ButtonModule } from "../button"; - -import { SubmitButtonComponent } from "./submit-button.component"; - -@NgModule({ - imports: [CommonModule, ButtonModule], - exports: [SubmitButtonComponent], - declarations: [SubmitButtonComponent], -}) -export class SubmitButtonModule {} diff --git a/libs/components/src/submit-button/submit-button.stories.ts b/libs/components/src/submit-button/submit-button.stories.ts deleted file mode 100644 index cf19b1c8e4b..00000000000 --- a/libs/components/src/submit-button/submit-button.stories.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Meta, moduleMetadata, Story } from "@storybook/angular"; - -import { SubmitButtonComponent } from "./submit-button.component"; -import { SubmitButtonModule } from "./submit-button.module"; - -export default { - title: "Component Library/Submit Button", - component: SubmitButtonComponent, - decorators: [ - moduleMetadata({ - imports: [SubmitButtonModule], - }), - ], - args: { - buttonType: "primary", - loading: false, - block: false, - }, - parameters: { - design: { - type: "figma", - url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A16733", - }, - }, -} as Meta; - -const Template: Story = (args: SubmitButtonComponent) => ({ - props: args, - template: ` - Submit - `, -}); - -export const Primary = Template.bind({}); -Primary.args = {}; - -export const Loading = Template.bind({}); -Loading.args = { - loading: true, -}; - -export const Disabled = Template.bind({}); -Disabled.args = { - disabled: true, -}; From 701d795000912a4a1043cef235cfeee84dbb0d2c Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Tue, 27 Sep 2022 14:42:15 +0200 Subject: [PATCH 04/10] Fix storybook (#3625) --- apps/web/src/app/accounts/login/login.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/web/src/app/accounts/login/login.component.ts b/apps/web/src/app/accounts/login/login.component.ts index 8664ae4a572..2568d5a3e74 100644 --- a/apps/web/src/app/accounts/login/login.component.ts +++ b/apps/web/src/app/accounts/login/login.component.ts @@ -22,8 +22,7 @@ import { Policy } from "@bitwarden/common/models/domain/policy"; import { ListResponse } from "@bitwarden/common/models/response/listResponse"; import { PolicyResponse } from "@bitwarden/common/models/response/policyResponse"; -import { flagEnabled } from "src/utils/flags"; - +import { flagEnabled } from "../../../utils/flags"; import { RouterService, StateService } from "../../core"; @Component({ From d168d5ee9b2525c3290e2f65e6de8337eff9fbe2 Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Tue, 27 Sep 2022 11:09:48 -0400 Subject: [PATCH 05/10] Fix last seen & spacing issue (#3567) * Fix last seen & spacing issue * Address PR comments, moving try catch to config service --- apps/browser/src/_locales/en/messages.json | 2 +- .../src/popup/settings/about.component.html | 6 +++--- .../common/src/services/config/config.service.ts | 16 +++++++++------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index a23bfa56501..3749bb4ae00 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -2017,7 +2017,7 @@ } }, "lastSeenOn": { - "message": "last seen on $DATE$", + "message": "last seen on: $DATE$", "placeholders": { "date": { "content": "$1", diff --git a/apps/browser/src/popup/settings/about.component.html b/apps/browser/src/popup/settings/about.component.html index ed2ceb40bec..c11b68e9c1f 100644 --- a/apps/browser/src/popup/settings/about.component.html +++ b/apps/browser/src/popup/settings/about.component.html @@ -14,7 +14,7 @@

{{ "serverVersion" | i18n }}: {{ this.serverConfig?.version }} - ({{ "lastSeenOn" | i18n }}: {{ serverConfig.utcDate | date: "mediumDate" }}) + ({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }})

@@ -24,7 +24,7 @@ {{ "serverVersion" | i18n }} ({{ "thirdParty" | i18n }}): {{ this.serverConfig?.version }} - ({{ "lastSeenOn" | i18n }}: {{ serverConfig.utcDate | date: "mediumDate" }}) + ({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }})

@@ -36,7 +36,7 @@ {{ "serverVersion" | i18n }} ({{ "selfHosted" | i18n }}): {{ this.serverConfig?.version }} - ({{ "lastSeenOn" | i18n }}: {{ serverConfig.utcDate | date: "mediumDate" }}) + ({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }})

diff --git a/libs/common/src/services/config/config.service.ts b/libs/common/src/services/config/config.service.ts index 9f9e0938b5a..a5ac5445713 100644 --- a/libs/common/src/services/config/config.service.ts +++ b/libs/common/src/services/config/config.service.ts @@ -48,14 +48,16 @@ export class ConfigService implements ConfigServiceAbstraction { } private async fetchServerConfig(): Promise { - const response = await this.configApiService.get(); - const data = new ServerConfigData(response); + try { + const response = await this.configApiService.get(); - if (data != null) { - await this.stateService.setServerConfig(data); - return new ServerConfig(data); + if (response != null) { + const data = new ServerConfigData(response); + await this.stateService.setServerConfig(data); + return new ServerConfig(data); + } + } catch { + return null; } - - return null; } } From cb746824e88a1f50d27ecfc045df6cb785d8e595 Mon Sep 17 00:00:00 2001 From: Todd Martin <106564991+trmartin4@users.noreply.github.com> Date: Tue, 27 Sep 2022 13:44:13 -0400 Subject: [PATCH 06/10] Added CSP rule for DDG email fowarder API (#3630) Co-authored-by: Todd Martin <> --- apps/web/webpack.config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/web/webpack.config.js b/apps/web/webpack.config.js index a7b6212943e..3b472c45d4e 100644 --- a/apps/web/webpack.config.js +++ b/apps/web/webpack.config.js @@ -273,7 +273,8 @@ const devServer = https://app.simplelogin.io/api/alias/random/new https://quack.duckduckgo.com/api/email/addresses https://app.anonaddy.com/api/v1/aliases - https://api.fastmail.com; + https://api.fastmail.com + https://quack.duckduckgo.com/api/email/addresses; object-src 'self' blob:;`, From 2c68518f875518257e87dd8bf6e47c4f191950a2 Mon Sep 17 00:00:00 2001 From: Gbubemi Smith Date: Tue, 27 Sep 2022 19:10:19 +0100 Subject: [PATCH 07/10] corrected typos (#3633) --- .../src/app/accounts/login/login-with-device.component.html | 2 +- apps/web/src/locales/en/messages.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/src/app/accounts/login/login-with-device.component.html b/apps/web/src/app/accounts/login/login-with-device.component.html index 3105a639ad3..3e5f48d597c 100644 --- a/apps/web/src/app/accounts/login/login-with-device.component.html +++ b/apps/web/src/app/accounts/login/login-with-device.component.html @@ -36,7 +36,7 @@
- {{ "loginWithDevciceEnabledInfo" | i18n }} + {{ "loginWithDeviceEnabledInfo" | i18n }} {{ "viewAllLoginOptions" | i18n }}
diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 3b8c2f772d7..efced93ca43 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -572,8 +572,8 @@ "loginWithDevice" : { "message": "Log in with device" }, - "loginWithDevciceEnabledInfo": { - "message": "Log in with device must be enabled in the settings of the Biwarden mobile app. Need another option?" + "loginWithDeviceEnabledInfo": { + "message": "Log in with device must be enabled in the settings of the Bitwarden mobile app. Need another option?" }, "createAccount": { "message": "Create Account" From c6dccc354c0ecc7f6e58bf3f3d80fed16ad25c8a Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Tue, 27 Sep 2022 16:25:19 -0400 Subject: [PATCH 08/10] [PS-1092] Organization Service Observables (#3462) * Update imports * Implement observables in a few places * Add tests * Get all clients working * Use _destroy * Address PR feedback * Address PR feedback * Address feedback --- .../browser/src/background/main.background.ts | 12 +- .../organization-service.factory.ts | 15 +- .../sync-notifier-service.factory.ts | 17 ++ .../src/popup/services/services.module.ts | 2 +- .../src/popup/vault/add-edit.component.ts | 2 +- .../src/popup/vault/ciphers.component.ts | 4 +- .../src/popup/vault/current-tab.component.ts | 4 +- .../src/popup/vault/share.component.html | 134 +++++------ .../src/popup/vault/share.component.ts | 2 +- .../popup/vault/vault-select.component.html | 129 ++++++----- .../src/popup/vault/vault-select.component.ts | 111 ++++----- .../src/services/vaultFilter.service.ts | 2 +- apps/cli/src/bw.ts | 12 +- .../commands/convertToKeyConnector.command.ts | 1 - apps/cli/src/commands/get.command.ts | 2 +- apps/cli/src/commands/import.command.ts | 2 +- apps/cli/src/commands/list.command.ts | 2 +- .../src/app/vault/add-edit.component.ts | 2 +- .../src/app/vault/share.component.html | 134 +++++------ apps/desktop/src/app/vault/share.component.ts | 2 +- .../trial-initiation/billing.component.ts | 2 +- .../src/app/common/base.people.component.ts | 7 +- .../organization-switcher.component.html | 6 +- .../organization-switcher.component.ts | 22 +- .../web/src/app/layouts/navbar.component.html | 8 +- apps/web/src/app/layouts/navbar.component.ts | 39 +--- .../guards/org-permissions.guard.spec.ts | 16 +- .../guards/org-permissions.guard.ts | 9 +- .../organization-layout.component.html | 78 ++++--- .../layouts/organization-layout.component.ts | 94 ++++---- .../manage/collection-add-edit.component.ts | 2 +- .../manage/collections.component.ts | 2 +- .../organizations/manage/events.component.ts | 2 +- .../organizations/manage/manage.component.ts | 2 +- .../organizations/manage/people.component.ts | 2 +- .../manage/policies.component.ts | 2 +- .../organizations/navigation-permissions.ts | 29 --- .../organization-routing.module.ts | 12 +- .../policies/master-password.component.ts | 2 +- .../policies/reset-password.component.ts | 2 +- .../settings/account.component.ts | 16 +- .../settings/delete-organization.component.ts | 2 +- .../organization-subscription.component.ts | 4 +- .../settings/settings.component.ts | 2 +- ...milies-for-enterprise-setup.component.html | 4 +- ...families-for-enterprise-setup.component.ts | 28 ++- .../exposed-passwords-report.component.ts | 2 +- .../import-export/org-import.component.ts | 2 +- .../inactive-two-factor-report.component.ts | 2 +- .../reused-passwords-report.component.ts | 2 +- .../organizations/tools/tools.component.ts | 2 +- .../unsecured-websites-report.component.ts | 2 +- .../tools/weak-passwords-report.component.ts | 2 +- .../organizations/vault/add-edit.component.ts | 2 +- .../organizations/vault/ciphers.component.ts | 2 +- .../organizations/vault/vault.component.ts | 2 +- .../src/app/settings/add-credit.component.ts | 2 +- .../app/settings/change-password.component.ts | 2 +- .../settings/emergency-access.component.ts | 2 +- .../settings/emergency-add-edit.component.ts | 2 +- .../settings/organization-plans.component.ts | 2 +- .../src/app/settings/settings.component.ts | 2 +- .../sponsored-families.component.html | 12 +- .../settings/sponsored-families.component.ts | 118 +++++----- apps/web/src/app/vault/add-edit.component.ts | 2 +- .../web/src/app/vault/bulk-share.component.ts | 17 +- apps/web/src/app/vault/ciphers.component.ts | 2 +- apps/web/src/app/vault/share.component.html | 145 ++++++------ apps/web/src/app/vault/share.component.ts | 2 +- .../organization-options.component.ts | 4 +- .../shared/vault-filter.service.ts | 2 +- apps/web/src/app/vault/vault.component.ts | 2 +- .../app/organizations/manage/sso.component.ts | 2 +- .../organizations-routing.module.ts | 2 +- .../providers/clients/clients.component.ts | 2 +- .../src/components/add-edit.component.ts | 2 +- .../export-scope-callout.component.ts | 6 +- .../components/remove-password.component.ts | 6 +- .../angular/src/components/share.component.ts | 57 +++-- .../src/services/jslib-services.module.ts | 20 +- .../services/vault-filter.service.ts | 6 +- .../organization/organization.service.spec.ts | 210 ++++++++++++++++++ .../src/abstractions/organization.service.ts | 11 - .../organization.service.abstraction.ts | 53 +++++ libs/common/src/abstractions/state.service.ts | 6 + .../sync/sync.service.abstraction.ts | 5 - .../sync/syncNotifier.service.abstraction.ts | 8 + libs/common/src/misc/utils.ts | 12 +- libs/common/src/services/event.service.ts | 2 +- .../src/services/keyConnector.service.ts | 2 +- .../src/services/organization.service.ts | 56 ----- .../organization/organization-api.service.ts | 22 +- .../organization/organization.service.ts | 119 ++++++++++ .../src/services/policy/policy-api.service.ts | 2 +- .../src/services/policy/policy.service.ts | 2 +- libs/common/src/services/state.service.ts | 6 + libs/common/src/services/sync/sync.service.ts | 32 +-- .../src/services/sync/syncNotifier.service.ts | 18 ++ libs/common/src/types/checkable.ts | 9 + libs/common/src/types/syncEventArgs.ts | 37 ++- 100 files changed, 1225 insertions(+), 813 deletions(-) create mode 100644 apps/browser/src/background/service_factories/sync-notifier-service.factory.ts delete mode 100644 apps/web/src/app/organizations/navigation-permissions.ts create mode 100644 libs/common/spec/services/organization/organization.service.spec.ts delete mode 100644 libs/common/src/abstractions/organization.service.ts create mode 100644 libs/common/src/abstractions/organization/organization.service.abstraction.ts create mode 100644 libs/common/src/abstractions/sync/syncNotifier.service.abstraction.ts delete mode 100644 libs/common/src/services/organization.service.ts create mode 100644 libs/common/src/services/organization/organization.service.ts create mode 100644 libs/common/src/services/sync/syncNotifier.service.ts create mode 100644 libs/common/src/types/checkable.ts diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 99114bc007f..cf83b6e78d1 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -16,7 +16,7 @@ import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarde import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service"; import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/abstractions/messaging.service"; import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service"; -import { OrganizationService as OrganizationServiceAbstraction } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService as OrganizationServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/abstractions/platformUtils.service"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction"; @@ -27,6 +27,7 @@ import { SendService as SendServiceAbstraction } from "@bitwarden/common/abstrac import { SettingsService as SettingsServiceAbstraction } from "@bitwarden/common/abstractions/settings.service"; import { AbstractStorageService } from "@bitwarden/common/abstractions/storage.service"; import { SyncService as SyncServiceAbstraction } from "@bitwarden/common/abstractions/sync/sync.service.abstraction"; +import { SyncNotifierService as SyncNotifierServiceAbstraction } from "@bitwarden/common/abstractions/sync/syncNotifier.service.abstraction"; import { SystemService as SystemServiceAbstraction } from "@bitwarden/common/abstractions/system.service"; import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/abstractions/token.service"; import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/abstractions/totp.service"; @@ -58,7 +59,7 @@ import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.s import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service"; import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service"; -import { OrganizationService } from "@bitwarden/common/services/organization.service"; +import { OrganizationService } from "@bitwarden/common/services/organization/organization.service"; import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service"; import { PolicyApiService } from "@bitwarden/common/services/policy/policy-api.service"; import { PolicyService } from "@bitwarden/common/services/policy/policy.service"; @@ -68,6 +69,7 @@ import { SendService } from "@bitwarden/common/services/send.service"; import { SettingsService } from "@bitwarden/common/services/settings.service"; import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service"; import { SyncService } from "@bitwarden/common/services/sync/sync.service"; +import { SyncNotifierService } from "@bitwarden/common/services/sync/syncNotifier.service"; import { SystemService } from "@bitwarden/common/services/system.service"; import { TokenService } from "@bitwarden/common/services/token.service"; import { TotpService } from "@bitwarden/common/services/totp.service"; @@ -158,6 +160,7 @@ export default class MainBackground { folderApiService: FolderApiServiceAbstraction; policyApiService: PolicyApiServiceAbstraction; userVerificationApiService: UserVerificationApiServiceAbstraction; + syncNotifierService: SyncNotifierServiceAbstraction; // Passed to the popup for Safari to workaround issues with theming, downloading, etc. backgroundWindow = window; @@ -298,7 +301,8 @@ export default class MainBackground { this.cryptoFunctionService, this.stateService ); - this.organizationService = new OrganizationService(this.stateService); + this.syncNotifierService = new SyncNotifierService(); + this.organizationService = new OrganizationService(this.stateService, this.syncNotifierService); this.policyService = new PolicyService(this.stateService, this.organizationService); this.policyApiService = new PolicyApiService( this.policyService, @@ -388,9 +392,9 @@ export default class MainBackground { this.logService, this.keyConnectorService, this.stateService, - this.organizationService, this.providerService, this.folderApiService, + this.syncNotifierService, logoutCallback ); this.eventService = new EventService( diff --git a/apps/browser/src/background/service_factories/organization-service.factory.ts b/apps/browser/src/background/service_factories/organization-service.factory.ts index 87692e64391..2e7c31b596e 100644 --- a/apps/browser/src/background/service_factories/organization-service.factory.ts +++ b/apps/browser/src/background/service_factories/organization-service.factory.ts @@ -1,12 +1,17 @@ -import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/abstractions/organization.service"; -import { OrganizationService } from "@bitwarden/common/services/organization.service"; +import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; +import { OrganizationService } from "@bitwarden/common/services/organization/organization.service"; import { FactoryOptions, CachedServices, factory } from "./factory-options"; import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; +import { + syncNotifierServiceFactory, + SyncNotifierServiceInitOptions, +} from "./sync-notifier-service.factory"; type OrganizationServiceFactoryOptions = FactoryOptions; export type OrganizationServiceInitOptions = OrganizationServiceFactoryOptions & + SyncNotifierServiceInitOptions & StateServiceInitOptions; export function organizationServiceFactory( @@ -17,6 +22,10 @@ export function organizationServiceFactory( cache, "organizationService", opts, - async () => new OrganizationService(await stateServiceFactory(cache, opts)) + async () => + new OrganizationService( + await stateServiceFactory(cache, opts), + await syncNotifierServiceFactory(cache, opts) + ) ); } diff --git a/apps/browser/src/background/service_factories/sync-notifier-service.factory.ts b/apps/browser/src/background/service_factories/sync-notifier-service.factory.ts new file mode 100644 index 00000000000..58699bdff58 --- /dev/null +++ b/apps/browser/src/background/service_factories/sync-notifier-service.factory.ts @@ -0,0 +1,17 @@ +import { SyncNotifierService as AbstractSyncNotifierService } from "@bitwarden/common/abstractions/sync/syncNotifier.service.abstraction"; +import { SyncNotifierService } from "@bitwarden/common/services/sync/syncNotifier.service"; + +import { FactoryOptions, CachedServices, factory } from "./factory-options"; + +type SyncNotifierServiceFactoryOptions = FactoryOptions; + +export type SyncNotifierServiceInitOptions = SyncNotifierServiceFactoryOptions; + +export function syncNotifierServiceFactory( + cache: { syncNotifierService?: AbstractSyncNotifierService } & CachedServices, + opts: SyncNotifierServiceInitOptions +): Promise { + return factory(cache, "syncNotifierService", opts, () => + Promise.resolve(new SyncNotifierService()) + ); +} diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 87c1dd17e93..a79028a26d1 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -26,7 +26,7 @@ import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; diff --git a/apps/browser/src/popup/vault/add-edit.component.ts b/apps/browser/src/popup/vault/add-edit.component.ts index f5062051c2e..d220a24a0d8 100644 --- a/apps/browser/src/popup/vault/add-edit.component.ts +++ b/apps/browser/src/popup/vault/add-edit.component.ts @@ -12,7 +12,7 @@ import { FolderService } from "@bitwarden/common/abstractions/folder/folder.serv import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; diff --git a/apps/browser/src/popup/vault/ciphers.component.ts b/apps/browser/src/popup/vault/ciphers.component.ts index 4346ad7a668..60a92e238c2 100644 --- a/apps/browser/src/popup/vault/ciphers.component.ts +++ b/apps/browser/src/popup/vault/ciphers.component.ts @@ -10,7 +10,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { CipherType } from "@bitwarden/common/enums/cipherType"; @@ -78,7 +78,7 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On async ngOnInit() { this.searchTypeSearch = !this.platformUtilsService.isSafari(); - this.showOrganizations = await this.organizationService.hasOrganizations(); + this.showOrganizations = this.organizationService.hasOrganizations(); this.vaultFilter = this.vaultFilterService.getVaultFilter(); // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe this.route.queryParams.pipe(first()).subscribe(async (params) => { diff --git a/apps/browser/src/popup/vault/current-tab.component.ts b/apps/browser/src/popup/vault/current-tab.component.ts index 2f3569841f4..f3e97dd233d 100644 --- a/apps/browser/src/popup/vault/current-tab.component.ts +++ b/apps/browser/src/popup/vault/current-tab.component.ts @@ -4,7 +4,7 @@ import { Router } from "@angular/router"; import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; @@ -219,7 +219,7 @@ export class CurrentTabComponent implements OnInit, OnDestroy { const otherTypes: CipherType[] = []; const dontShowCards = await this.stateService.getDontShowCardsCurrentTab(); const dontShowIdentities = await this.stateService.getDontShowIdentitiesCurrentTab(); - this.showOrganizations = await this.organizationService.hasOrganizations(); + this.showOrganizations = this.organizationService.hasOrganizations(); if (!dontShowCards) { otherTypes.push(CipherType.Card); } diff --git a/apps/browser/src/popup/vault/share.component.html b/apps/browser/src/popup/vault/share.component.html index ad1447f6f65..dcec42415c0 100644 --- a/apps/browser/src/popup/vault/share.component.html +++ b/apps/browser/src/popup/vault/share.component.html @@ -1,70 +1,76 @@
-
-
- -
-

- {{ "moveToOrganization" | i18n }} -

-
- -
-
-
-
-
-
- {{ "noOrganizationsList" | i18n }} -
+ +
+
+
-
-
- - -
-
- -
-
-

- {{ "collections" | i18n }} -

-
-
- {{ "noCollectionsInList" | i18n }} -
-
-
-
+ {{ "moveToOrganization" | i18n }} + +
+ +
+ +
+
+
+
+ {{ "noOrganizationsList" | i18n }} +
+
+
+
+ + +
+
+
-
-
+
+

+ {{ "collections" | i18n }} +

+
+
+ {{ "noCollectionsInList" | i18n }} +
+
+
+
+ + +
+
+
+ +
diff --git a/apps/browser/src/popup/vault/share.component.ts b/apps/browser/src/popup/vault/share.component.ts index bfff215533e..112b432c0e0 100644 --- a/apps/browser/src/popup/vault/share.component.ts +++ b/apps/browser/src/popup/vault/share.component.ts @@ -7,7 +7,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; @Component({ diff --git a/apps/browser/src/popup/vault/vault-select.component.html b/apps/browser/src/popup/vault/vault-select.component.html index d5698e79288..95d1effd7fd 100644 --- a/apps/browser/src/popup/vault/vault-select.component.html +++ b/apps/browser/src/popup/vault/vault-select.component.html @@ -1,71 +1,70 @@ -
- - - + + + + +
+ diff --git a/apps/browser/src/popup/vault/vault-select.component.ts b/apps/browser/src/popup/vault/vault-select.component.ts index d12463f2c11..04ae04d0fab 100644 --- a/apps/browser/src/popup/vault/vault-select.component.ts +++ b/apps/browser/src/popup/vault/vault-select.component.ts @@ -5,19 +5,19 @@ import { Component, ElementRef, EventEmitter, - NgZone, OnInit, Output, TemplateRef, ViewChild, ViewContainerRef, HostListener, + OnDestroy, } from "@angular/core"; -import { merge } from "rxjs"; +import { BehaviorSubject, concatMap, map, merge, Observable, Subject, takeUntil } from "rxjs"; import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; -import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { Organization } from "@bitwarden/common/models/domain/organization"; @@ -47,20 +47,22 @@ import { VaultFilterService } from "../../services/vaultFilter.service"; ]), ], }) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class VaultSelectComponent implements OnInit { +export class VaultSelectComponent implements OnInit, OnDestroy { @Output() onVaultSelectionChanged = new EventEmitter(); @ViewChild("toggleVaults", { read: ElementRef }) buttonRef: ElementRef; @ViewChild("vaultSelectorTemplate", { read: TemplateRef }) templateRef: TemplateRef; + private _selectedVault = new BehaviorSubject(null); + isOpen = false; loaded = false; - organizations: Organization[]; + organizations$: Observable; + selectedVault$: Observable = this._selectedVault.asObservable(); + vaultFilter: VaultFilter = new VaultFilter(); - vaultFilterDisplay = ""; - enforcePersonalOwnwership = false; + enforcePersonalOwnership = false; overlayPostition: ConnectedPosition[] = [ { originX: "start", @@ -71,22 +73,22 @@ export class VaultSelectComponent implements OnInit { ]; private overlayRef: OverlayRef; + private _destroy = new Subject(); - get show() { + shouldShow(organizations: Organization[]): boolean { return ( - (this.organizations.length > 0 && !this.enforcePersonalOwnwership) || - (this.organizations.length > 1 && this.enforcePersonalOwnwership) + (organizations.length > 0 && !this.enforcePersonalOwnership) || + (organizations.length > 1 && this.enforcePersonalOwnership) ); } constructor( private vaultFilterService: VaultFilterService, private i18nService: I18nService, - private ngZone: NgZone, - private broadcasterService: BroadcasterService, private overlay: Overlay, private viewContainerRef: ViewContainerRef, - private platformUtilsService: PlatformUtilsService + private platformUtilsService: PlatformUtilsService, + private organizationService: OrganizationService ) {} @HostListener("document:keydown.escape", ["$event"]) @@ -98,46 +100,45 @@ export class VaultSelectComponent implements OnInit { } async ngOnInit() { - await this.load(); - this.broadcasterService.subscribe(this.constructor.name, (message: any) => { - this.ngZone.run(async () => { - switch (message.command) { - case "syncCompleted": - await this.load(); - break; - default: - break; - } - }); - }); + this.organizations$ = this.organizationService.organizations$ + .pipe(takeUntil(this._destroy)) + .pipe(map((orgs) => orgs.sort((a, b) => a.name.localeCompare(b.name)))); + + this.organizations$ + .pipe( + concatMap(async (organizations) => { + this.enforcePersonalOwnership = + await this.vaultFilterService.checkForPersonalOwnershipPolicy(); + + if (this.shouldShow(organizations)) { + if (this.enforcePersonalOwnership && !this.vaultFilter.myVaultOnly) { + const firstOrganization = organizations[0]; + this._selectedVault.next(firstOrganization.name); + this.vaultFilterService.setVaultFilter(firstOrganization.id); + this.vaultFilter.selectedOrganizationId = firstOrganization.id; + } else if (this.vaultFilter.myVaultOnly) { + this._selectedVault.next(this.i18nService.t(this.vaultFilterService.myVault)); + } else if (this.vaultFilter.selectedOrganizationId != null) { + const selectedOrganization = organizations.find( + (o) => o.id === this.vaultFilter.selectedOrganizationId + ); + this._selectedVault.next(selectedOrganization.name); + } else { + this._selectedVault.next(this.i18nService.t(this.vaultFilterService.allVaults)); + } + } + }) + ) + .pipe(takeUntil(this._destroy)) + .subscribe(); + + this.loaded = true; } - async load() { - this.vaultFilter = this.vaultFilterService.getVaultFilter(); - this.organizations = (await this.vaultFilterService.buildOrganizations()).sort((a, b) => - a.name.localeCompare(b.name) - ); - this.enforcePersonalOwnwership = - await this.vaultFilterService.checkForPersonalOwnershipPolicy(); - - if (this.show) { - if (this.enforcePersonalOwnwership && !this.vaultFilter.myVaultOnly) { - this.vaultFilterService.setVaultFilter(this.organizations[0].id); - this.vaultFilter.selectedOrganizationId = this.organizations[0].id; - this.vaultFilterDisplay = this.organizations.find( - (o) => o.id === this.vaultFilter.selectedOrganizationId - ).name; - } else if (this.vaultFilter.myVaultOnly) { - this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.myVault); - } else if (this.vaultFilter.selectedOrganizationId != null) { - this.vaultFilterDisplay = this.organizations.find( - (o) => o.id === this.vaultFilter.selectedOrganizationId - ).name; - } else { - this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.allVaults); - } - } - this.loaded = true; + ngOnDestroy(): void { + this._destroy.next(); + this._destroy.complete(); + this._selectedVault.complete(); } openOverlay() { @@ -191,20 +192,20 @@ export class VaultSelectComponent implements OnInit { this.i18nService.t("disabledOrganizationFilterError") ); } else { - this.vaultFilterDisplay = organization.name; + this._selectedVault.next(organization.name); this.vaultFilterService.setVaultFilter(organization.id); this.onVaultSelectionChanged.emit(); this.close(); } } selectAllVaults() { - this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.allVaults); + this._selectedVault.next(this.i18nService.t(this.vaultFilterService.allVaults)); this.vaultFilterService.setVaultFilter(this.vaultFilterService.allVaults); this.onVaultSelectionChanged.emit(); this.close(); } selectMyVault() { - this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.myVault); + this._selectedVault.next(this.i18nService.t(this.vaultFilterService.myVault)); this.vaultFilterService.setVaultFilter(this.vaultFilterService.myVault); this.onVaultSelectionChanged.emit(); this.close(); diff --git a/apps/browser/src/services/vaultFilter.service.ts b/apps/browser/src/services/vaultFilter.service.ts index b921a21292d..77016638d8f 100644 --- a/apps/browser/src/services/vaultFilter.service.ts +++ b/apps/browser/src/services/vaultFilter.service.ts @@ -3,7 +3,7 @@ import { VaultFilterService as BaseVaultFilterService } from "@bitwarden/angular import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { CipherView } from "@bitwarden/common/models/view/cipherView"; diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 734a030943d..489f92fac9d 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -30,8 +30,8 @@ import { ImportService } from "@bitwarden/common/services/import.service"; import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service"; import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service"; import { NoopMessagingService } from "@bitwarden/common/services/noopMessaging.service"; -import { OrganizationService } from "@bitwarden/common/services/organization.service"; import { OrganizationApiService } from "@bitwarden/common/services/organization/organization-api.service"; +import { OrganizationService } from "@bitwarden/common/services/organization/organization.service"; import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service"; import { PolicyService } from "@bitwarden/common/services/policy/policy.service"; import { ProviderService } from "@bitwarden/common/services/provider.service"; @@ -41,6 +41,7 @@ import { SettingsService } from "@bitwarden/common/services/settings.service"; import { StateService } from "@bitwarden/common/services/state.service"; import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service"; import { SyncService } from "@bitwarden/common/services/sync/sync.service"; +import { SyncNotifierService } from "@bitwarden/common/services/sync/syncNotifier.service"; import { TokenService } from "@bitwarden/common/services/token.service"; import { TotpService } from "@bitwarden/common/services/totp.service"; import { TwoFactorService } from "@bitwarden/common/services/twoFactor.service"; @@ -113,6 +114,7 @@ export class Main { folderApiService: FolderApiService; userVerificationApiService: UserVerificationApiService; organizationApiService: OrganizationApiServiceAbstraction; + syncNotifierService: SyncNotifierService; constructor() { let p = null; @@ -191,7 +193,9 @@ export class Main { customUserAgent ); - this.organizationApiService = new OrganizationApiService(this.apiService); + this.syncNotifierService = new SyncNotifierService(); + + this.organizationApiService = new OrganizationApiService(this.apiService, this.syncService); this.containerService = new ContainerService(this.cryptoService, this.encryptService); @@ -231,7 +235,7 @@ export class Main { this.providerService = new ProviderService(this.stateService); - this.organizationService = new OrganizationService(this.stateService); + this.organizationService = new OrganizationService(this.stateService, this.syncNotifierService); this.policyService = new PolicyService(this.stateService, this.organizationService); @@ -311,9 +315,9 @@ export class Main { this.logService, this.keyConnectorService, this.stateService, - this.organizationService, this.providerService, this.folderApiService, + this.syncNotifierService, async (expired: boolean) => await this.logout() ); diff --git a/apps/cli/src/commands/convertToKeyConnector.command.ts b/apps/cli/src/commands/convertToKeyConnector.command.ts index 6339fa9b9aa..00fb2f72910 100644 --- a/apps/cli/src/commands/convertToKeyConnector.command.ts +++ b/apps/cli/src/commands/convertToKeyConnector.command.ts @@ -74,7 +74,6 @@ export class ConvertToKeyConnectorCommand { } else if (answer.convert === "leave") { await this.organizationApiService.leave(organization.id); await this.keyConnectorService.removeConvertAccountRequired(); - await this.syncService.fullSync(true); return Response.success(); } else { await this.logout(); diff --git a/apps/cli/src/commands/get.command.ts b/apps/cli/src/commands/get.command.ts index 7cfcd9fb6e3..510cb10da3f 100644 --- a/apps/cli/src/commands/get.command.ts +++ b/apps/cli/src/commands/get.command.ts @@ -4,7 +4,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; diff --git a/apps/cli/src/commands/import.command.ts b/apps/cli/src/commands/import.command.ts index f3b04a5f564..6fb17fa2cd9 100644 --- a/apps/cli/src/commands/import.command.ts +++ b/apps/cli/src/commands/import.command.ts @@ -2,7 +2,7 @@ import * as program from "commander"; import * as inquirer from "inquirer"; import { ImportService } from "@bitwarden/common/abstractions/import.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { ImportType } from "@bitwarden/common/enums/importOptions"; import { Importer } from "@bitwarden/common/importers/importer"; import { Response } from "@bitwarden/node/cli/models/response"; diff --git a/apps/cli/src/commands/list.command.ts b/apps/cli/src/commands/list.command.ts index 4e2d7cb02e0..dd779ec0576 100644 --- a/apps/cli/src/commands/list.command.ts +++ b/apps/cli/src/commands/list.command.ts @@ -2,7 +2,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { Utils } from "@bitwarden/common/misc/utils"; import { CollectionData } from "@bitwarden/common/models/data/collectionData"; diff --git a/apps/desktop/src/app/vault/add-edit.component.ts b/apps/desktop/src/app/vault/add-edit.component.ts index aa76d2ba7dd..5a2153fadc4 100644 --- a/apps/desktop/src/app/vault/add-edit.component.ts +++ b/apps/desktop/src/app/vault/add-edit.component.ts @@ -11,7 +11,7 @@ import { FolderService } from "@bitwarden/common/abstractions/folder/folder.serv import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; diff --git a/apps/desktop/src/app/vault/share.component.html b/apps/desktop/src/app/vault/share.component.html index f80c3b48296..f460703d5d3 100644 --- a/apps/desktop/src/app/vault/share.component.html +++ b/apps/desktop/src/app/vault/share.component.html @@ -1,78 +1,80 @@