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:
@@ -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>;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user