1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 08:13:42 +00:00

Merge branch 'main' into autofill/pm-8027-inline-menu-appears-within-input-fields-that-do-not-relate-to-user-login

This commit is contained in:
Cesar Gonzalez
2024-06-13 08:08:58 -05:00
committed by GitHub
49 changed files with 1774 additions and 1183 deletions

View File

@@ -1,3 +1,5 @@
import { BillingHistoryResponse } from "@bitwarden/common/billing/models/response/billing-history.response";
import { OrganizationApiKeyRequest } from "../../../admin-console/models/request/organization-api-key.request";
import { OrganizationSsoRequest } from "../../../auth/models/request/organization-sso.request";
import { SecretVerificationRequest } from "../../../auth/models/request/secret-verification.request";
@@ -33,6 +35,7 @@ import { ProfileOrganizationResponse } from "../../models/response/profile-organ
export class OrganizationApiServiceAbstraction {
get: (id: string) => Promise<OrganizationResponse>;
getBilling: (id: string) => Promise<BillingResponse>;
getBillingHistory: (id: string) => Promise<BillingHistoryResponse>;
getSubscription: (id: string) => Promise<OrganizationSubscriptionResponse>;
getLicense: (id: string, installationId: string) => Promise<unknown>;
getAutoEnrollStatus: (identifier: string) => Promise<OrganizationAutoEnrollStatusResponse>;

View File

@@ -1,3 +1,5 @@
import { BillingHistoryResponse } from "@bitwarden/common/billing/models/response/billing-history.response";
import { ApiService } from "../../../abstractions/api.service";
import { OrganizationApiKeyRequest } from "../../../admin-console/models/request/organization-api-key.request";
import { OrganizationSsoRequest } from "../../../auth/models/request/organization-sso.request";
@@ -55,6 +57,17 @@ export class OrganizationApiService implements OrganizationApiServiceAbstraction
return new BillingResponse(r);
}
async getBillingHistory(id: string): Promise<BillingHistoryResponse> {
const r = await this.apiService.send(
"GET",
"/organizations/" + id + "/billing/history",
null,
true,
true,
);
return new BillingHistoryResponse(r);
}
async getSubscription(id: string): Promise<OrganizationSubscriptionResponse> {
const r = await this.apiService.send(
"GET",

View File

@@ -4,26 +4,12 @@ import { PaymentMethodType, TransactionType } from "../../enums";
export class BillingResponse extends BaseResponse {
balance: number;
paymentSource: BillingSourceResponse;
invoices: BillingInvoiceResponse[] = [];
transactions: BillingTransactionResponse[] = [];
constructor(response: any) {
super(response);
this.balance = this.getResponseProperty("Balance");
const paymentSource = this.getResponseProperty("PaymentSource");
const transactions = this.getResponseProperty("Transactions");
const invoices = this.getResponseProperty("Invoices");
this.paymentSource = paymentSource == null ? null : new BillingSourceResponse(paymentSource);
if (transactions != null) {
this.transactions = transactions.map((t: any) => new BillingTransactionResponse(t));
}
if (invoices != null) {
this.invoices = invoices.map((i: any) => new BillingInvoiceResponse(i));
}
}
get hasNoHistory() {
return this.invoices.length == 0 && this.transactions.length == 0;
}
}

View File

@@ -51,10 +51,18 @@ export class BadgeDirective implements FocusableElement {
.concat(this.hasHoverEffects ? hoverStyles[this.variant] : [])
.concat(this.truncate ? ["tw-truncate", this.maxWidthClass] : []);
}
@HostBinding("attr.title") get title() {
@HostBinding("attr.title") get titleAttr() {
if (this.title !== undefined) {
return this.title;
}
return this.truncate ? this.el.nativeElement.textContent.trim() : null;
}
/**
* Optional override for the automatic badge title when truncating.
*/
@Input() title?: string;
/**
* Variant, sets the background color of the badge.
*/

View File

@@ -1,5 +1,6 @@
import { FocusableOption } from "@angular/cdk/a11y";
import { Component, ElementRef, HostBinding } from "@angular/core";
import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { Component, ElementRef, HostBinding, Input } from "@angular/core";
@Component({
selector: "[bitMenuItem]",
@@ -32,6 +33,11 @@ export class MenuItemDirective implements FocusableOption {
];
@HostBinding("attr.role") role = "menuitem";
@HostBinding("tabIndex") tabIndex = "-1";
@HostBinding("attr.disabled") get disabledAttr() {
return this.disabled || null; // native disabled attr must be null when false
}
@Input({ transform: coerceBooleanProperty }) disabled?: boolean = false;
constructor(private elementRef: ElementRef) {}

View File

@@ -1,6 +1,7 @@
import { Directive, HostBinding, HostListener, Input, OnChanges } from "@angular/core";
import { Directive, HostBinding, HostListener, Input, OnChanges, Optional } from "@angular/core";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { MenuItemDirective } from "@bitwarden/components";
import { CopyAction, CopyCipherFieldService } from "@bitwarden/vault";
/**
@@ -9,6 +10,8 @@ import { CopyAction, CopyCipherFieldService } from "@bitwarden/vault";
*
* Automatically disables the host element if the field to copy is not available or null.
*
* If the host element is a menu item, it will be hidden when disabled.
*
* @example
* ```html
* <button appCopyField="username" [cipher]="cipher">Copy Username</button>
@@ -27,11 +30,23 @@ export class CopyCipherFieldDirective implements OnChanges {
@Input({ required: true }) cipher: CipherView;
constructor(private copyCipherFieldService: CopyCipherFieldService) {}
constructor(
private copyCipherFieldService: CopyCipherFieldService,
@Optional() private menuItemDirective?: MenuItemDirective,
) {}
@HostBinding("attr.disabled")
protected disabled: boolean | null = null;
/**
* Hide the element if it is disabled and is a menu item.
* @private
*/
@HostBinding("class.tw-hidden")
private get hidden() {
return this.disabled && this.menuItemDirective;
}
@HostListener("click")
async copy() {
const value = this.getValueToCopy();
@@ -49,6 +64,11 @@ export class CopyCipherFieldDirective implements OnChanges {
(this.action === "totp" && !(await this.copyCipherFieldService.totpAllowed(this.cipher)))
? true
: null;
// If the directive is used on a menu item, update the menu item to prevent keyboard navigation
if (this.menuItemDirective) {
this.menuItemDirective.disabled = this.disabled;
}
}
private getValueToCopy() {