mirror of
https://github.com/bitwarden/web
synced 2025-12-06 00:03:28 +00:00
Compare commits
12 Commits
feature/cm
...
v2.25.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23b30422d8 | ||
|
|
71375c718a | ||
|
|
ee28fdb88b | ||
|
|
d10dc94a48 | ||
|
|
c85051d6e2 | ||
|
|
778700f399 | ||
|
|
23048d46d6 | ||
|
|
e54586c7d2 | ||
|
|
494fc4b194 | ||
|
|
48b9393a48 | ||
|
|
b6b3184a7b | ||
|
|
66be24a1f5 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -329,7 +329,7 @@ jobs:
|
|||||||
- name: Get image tag
|
- name: Get image tag
|
||||||
id: image-tag
|
id: image-tag
|
||||||
run: |
|
run: |
|
||||||
IMAGE_TAG=$(echo "$GITHUB_REF" | awk '{split($0, a, "/"); print a[3];}')
|
IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g")
|
||||||
TAG_EXTENSION=${{ github.event.inputs.custom_tag_extension }}
|
TAG_EXTENSION=${{ github.event.inputs.custom_tag_extension }}
|
||||||
|
|
||||||
if [[ $TAG_EXTENSION ]]; then
|
if [[ $TAG_EXTENSION ]]; then
|
||||||
|
|||||||
16
.github/workflows/qa-deploy.yml
vendored
16
.github/workflows/qa-deploy.yml
vendored
@@ -9,8 +9,8 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
|
|
||||||
env:
|
env:
|
||||||
_QA_CLUSTER_RESOURCE_GROUP: "bitwarden-devops"
|
_QA_CLUSTER_RESOURCE_GROUP: "bw-env-qa"
|
||||||
_QA_CLUSTER_NAME: "dev-aks"
|
_QA_CLUSTER_NAME: "bw-aks-qa"
|
||||||
_QA_K8S_NAMESPACE: "bw-qa"
|
_QA_K8S_NAMESPACE: "bw-qa"
|
||||||
_QA_K8S_APP_NAME: "bw-web"
|
_QA_K8S_APP_NAME: "bw-web"
|
||||||
|
|
||||||
@@ -36,16 +36,16 @@ jobs:
|
|||||||
uses: Azure/get-keyvault-secrets@80ccd3fafe5662407cc2e55f202ee34bfff8c403
|
uses: Azure/get-keyvault-secrets@80ccd3fafe5662407cc2e55f202ee34bfff8c403
|
||||||
with:
|
with:
|
||||||
keyvault: "bitwarden-qa-kv"
|
keyvault: "bitwarden-qa-kv"
|
||||||
secrets: "dev-aks-kubectl-credentials"
|
secrets: "qa-aks-kubectl-credentials"
|
||||||
|
|
||||||
- name: Login to dev-aks-kubectl SP
|
- name: Login with qa-aks-kubectl-credentials SP
|
||||||
uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a
|
uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a
|
||||||
with:
|
with:
|
||||||
creds: ${{ env.dev-aks-kubectl-credentials }}
|
creds: ${{ env.qa-aks-kubectl-credentials }}
|
||||||
|
|
||||||
- name: Setup AKS access
|
- name: Setup AKS access
|
||||||
env:
|
#env:
|
||||||
USER_ID: ${{ env.qa-kubectl-managed-identity-clientId }}
|
# USER_ID: ${{ env.qa-kubectl-managed-identity-clientId }}
|
||||||
run: |
|
run: |
|
||||||
echo "---az install---"
|
echo "---az install---"
|
||||||
az aks install-cli --install-location ./kubectl --kubelogin-install-location ./kubelogin
|
az aks install-cli --install-location ./kubectl --kubelogin-install-location ./kubelogin
|
||||||
@@ -55,7 +55,7 @@ jobs:
|
|||||||
- name: Get image tag
|
- name: Get image tag
|
||||||
id: image_tag
|
id: image_tag
|
||||||
run: |
|
run: |
|
||||||
IMAGE_TAG=$(echo "$GITHUB_REF" | awk '{split($0, a, "/"); print a[3];}')
|
IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g")
|
||||||
TAG_EXTENSION=${{ github.event.inputs.image_extension }}
|
TAG_EXTENSION=${{ github.event.inputs.image_extension }}
|
||||||
|
|
||||||
if [[ $TAG_EXTENSION ]]; then
|
if [[ $TAG_EXTENSION ]]; then
|
||||||
|
|||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -116,8 +116,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Checkout Repo
|
- name: Checkout Repo
|
||||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
|
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
|
||||||
with:
|
|
||||||
ref: release
|
|
||||||
|
|
||||||
- name: Setup git config
|
- name: Setup git config
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
2
jslib
2
jslib
Submodule jslib updated: b4f475251a...f80dfb8fd9
6
package-lock.json
generated
6
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "bitwarden-web",
|
"name": "bitwarden-web",
|
||||||
"version": "2.24.4",
|
"version": "2.25.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "bitwarden-web",
|
"name": "bitwarden-web",
|
||||||
"version": "2.24.4",
|
"version": "2.25.1",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -20626,4 +20626,4 @@
|
|||||||
"integrity": "sha1-KOwXzwl0PtyrBW3dixsGJizHPDA="
|
"integrity": "sha1-KOwXzwl0PtyrBW3dixsGJizHPDA="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bitwarden-web",
|
"name": "bitwarden-web",
|
||||||
"version": "2.24.4",
|
"version": "2.25.1",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"repository": "https://github.com/bitwarden/web",
|
"repository": "https://github.com/bitwarden/web",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -85,4 +85,4 @@
|
|||||||
"node": "~14",
|
"node": "~14",
|
||||||
"npm": "~7"
|
"npm": "~7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
ViewContainerRef,
|
ViewContainerRef,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ActivatedRoute,
|
ActivatedRoute,
|
||||||
Router
|
Router
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
Output,
|
Output,
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
<ng-container *ngIf="subscription">
|
<ng-container *ngIf="subscription">
|
||||||
<dt>{{'status' | i18n}}</dt>
|
<dt>{{'status' | i18n}}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<span class="text-capitalize">{{subscription.status || '-'}}</span>
|
<span class="text-capitalize">{{isSponsoredSubscription ? 'sponsored' : subscription.status || '-'}}</span>
|
||||||
<span class="badge badge-warning"
|
<span class="badge badge-warning"
|
||||||
*ngIf="subscriptionMarkedForCancel">{{'pendingCancellation' |
|
*ngIf="subscriptionMarkedForCancel">{{'pendingCancellation' |
|
||||||
i18n}}</span>
|
i18n}}</span>
|
||||||
|
|||||||
@@ -6,7 +6,10 @@
|
|||||||
<i class="fa fa-spinner fa-spin fa-2x text-muted" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
<i class="fa fa-spinner fa-spin fa-2x text-muted" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||||
<span class="sr-only">{{'loading' | i18n}}</span>
|
<span class="sr-only">{{'loading' | i18n}}</span>
|
||||||
</div>
|
</div>
|
||||||
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate *ngIf="!loading">
|
<div *ngIf="!loading && badToken" class="mt-5 d-flex justify-content-center">
|
||||||
|
<span>{{'badToken' | i18n}}</span>
|
||||||
|
</div>
|
||||||
|
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate *ngIf="!loading && !badToken">
|
||||||
<p>
|
<p>
|
||||||
<span>{{'acceptBitwardenFamiliesHelp' | i18n}}</span>
|
<span>{{'acceptBitwardenFamiliesHelp' | i18n}}</span>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import { OrganizationPlansComponent } from 'src/app/settings/organization-plans.
|
|||||||
templateUrl: 'families-for-enterprise-setup.component.html',
|
templateUrl: 'families-for-enterprise-setup.component.html',
|
||||||
})
|
})
|
||||||
export class FamiliesForEnterpriseSetupComponent implements OnInit {
|
export class FamiliesForEnterpriseSetupComponent implements OnInit {
|
||||||
@ViewChild(OrganizationPlansComponent, { static: false })
|
@ViewChild(OrganizationPlansComponent, { static: false })
|
||||||
set organizationPlansComponent(value: OrganizationPlansComponent) {
|
set organizationPlansComponent(value: OrganizationPlansComponent) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return;
|
return;
|
||||||
@@ -55,6 +55,7 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit {
|
|||||||
@ViewChild('deleteOrganizationTemplate', { read: ViewContainerRef, static: true }) deleteModalRef: ViewContainerRef;
|
@ViewChild('deleteOrganizationTemplate', { read: ViewContainerRef, static: true }) deleteModalRef: ViewContainerRef;
|
||||||
|
|
||||||
loading = true;
|
loading = true;
|
||||||
|
badToken = false;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
|
|
||||||
token: string;
|
token: string;
|
||||||
@@ -89,6 +90,7 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit {
|
|||||||
this.token = qParams.token;
|
this.token = qParams.token;
|
||||||
|
|
||||||
await this.syncService.fullSync(true);
|
await this.syncService.fullSync(true);
|
||||||
|
this.badToken = !await this.apiService.postPreValidateSponsorshipToken(this.token);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
|
||||||
this.existingFamilyOrganizations = (await this.userService.getAllOrganizations())
|
this.existingFamilyOrganizations = (await this.userService.getAllOrganizations())
|
||||||
@@ -109,7 +111,7 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit {
|
|||||||
get selectedFamilyOrganizationId() {
|
get selectedFamilyOrganizationId() {
|
||||||
return this._selectedFamilyOrganizationId;
|
return this._selectedFamilyOrganizationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
set selectedFamilyOrganizationId(value: string) {
|
set selectedFamilyOrganizationId(value: string) {
|
||||||
this._selectedFamilyOrganizationId = value;
|
this._selectedFamilyOrganizationId = value;
|
||||||
this.showNewOrganization = value === 'createNew';
|
this.showNewOrganization = value === 'createNew';
|
||||||
|
|||||||
@@ -92,7 +92,7 @@
|
|||||||
</small>
|
</small>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<span *ngIf="selectableProduct.product != productTypes.Free">
|
<span *ngIf="selectableProduct.product != productTypes.Free">
|
||||||
<ng-container *ngIf="selectableProduct.basePrice">
|
<ng-container *ngIf="selectableProduct.basePrice && !acceptingSponsorship">
|
||||||
{{selectableProduct.basePrice / 12 | currency:'$'}} /{{'month' | i18n}},
|
{{selectableProduct.basePrice / 12 | currency:'$'}} /{{'month' | i18n}},
|
||||||
{{'includesXUsers' | i18n : selectableProduct.baseSeats}}
|
{{'includesXUsers' | i18n : selectableProduct.baseSeats}}
|
||||||
<ng-container *ngIf="selectableProduct.hasAdditionalSeatsOption">
|
<ng-container *ngIf="selectableProduct.hasAdditionalSeatsOption">
|
||||||
@@ -162,8 +162,14 @@
|
|||||||
{{'basePrice' | i18n}}: {{ selectablePlan.basePrice / 12 | currency:'$'}} × 12
|
{{'basePrice' | i18n}}: {{ selectablePlan.basePrice / 12 | currency:'$'}} × 12
|
||||||
{{'monthAbbr' | i18n}}
|
{{'monthAbbr' | i18n}}
|
||||||
=
|
=
|
||||||
{{selectablePlan.basePrice | currency:'$'}}
|
<ng-container *ngIf="acceptingSponsorship; else notAcceptingSponsorship">
|
||||||
/{{'year' | i18n}}
|
<span style="text-decoration: line-through;">{{selectablePlan.basePrice | currency:'$'}}</span>
|
||||||
|
{{'freeWithSponsorship' | i18n}}
|
||||||
|
</ng-container>
|
||||||
|
<ng-template #notAcceptingSponsorship>
|
||||||
|
{{selectablePlan.basePrice | currency:'$'}}
|
||||||
|
/{{'year' | i18n}}
|
||||||
|
</ng-template>
|
||||||
</small>
|
</small>
|
||||||
<small *ngIf="selectablePlan.hasAdditionalSeatsOption">
|
<small *ngIf="selectablePlan.hasAdditionalSeatsOption">
|
||||||
<span *ngIf="selectablePlan.baseSeats">{{'additionalUsers' | i18n}}:</span>
|
<span *ngIf="selectablePlan.baseSeats">{{'additionalUsers' | i18n}}:</span>
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export class OrganizationPlansComponent implements OnInit {
|
|||||||
productTypes = ProductType;
|
productTypes = ProductType;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
singleOrgPolicyBlock: boolean = false;
|
singleOrgPolicyBlock: boolean = false;
|
||||||
|
discount = 0;
|
||||||
|
|
||||||
plans: PlanResponse[];
|
plans: PlanResponse[];
|
||||||
|
|
||||||
@@ -120,14 +121,18 @@ export class OrganizationPlansComponent implements OnInit {
|
|||||||
validPlans = validPlans.filter(plan => plan.product !== ProductType.Free);
|
validPlans = validPlans.filter(plan => plan.product !== ProductType.Free);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.acceptingSponsorship) {
|
|
||||||
validPlans = validPlans.filter(plan => plan.product === ProductType.Families);
|
|
||||||
}
|
|
||||||
|
|
||||||
validPlans = validPlans
|
validPlans = validPlans
|
||||||
.filter(plan => !plan.legacyYear
|
.filter(plan => !plan.legacyYear
|
||||||
&& !plan.disabled
|
&& !plan.disabled
|
||||||
&& (plan.isAnnual || plan.product === this.productTypes.Free));
|
&& (plan.isAnnual || plan.product === this.productTypes.Free));
|
||||||
|
|
||||||
|
if (this.acceptingSponsorship) {
|
||||||
|
const familyPlan = this.plans.find(plan => plan.type === PlanType.FamiliesAnnually);
|
||||||
|
this.discount = familyPlan.basePrice;
|
||||||
|
validPlans = [
|
||||||
|
familyPlan,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return validPlans;
|
return validPlans;
|
||||||
}
|
}
|
||||||
@@ -177,7 +182,7 @@ export class OrganizationPlansComponent implements OnInit {
|
|||||||
if (this.selectedPlan.hasPremiumAccessOption && this.premiumAccessAddon) {
|
if (this.selectedPlan.hasPremiumAccessOption && this.premiumAccessAddon) {
|
||||||
subTotal += this.selectedPlan.premiumAccessOptionPrice;
|
subTotal += this.selectedPlan.premiumAccessOptionPrice;
|
||||||
}
|
}
|
||||||
return subTotal;
|
return subTotal - this.discount;
|
||||||
}
|
}
|
||||||
|
|
||||||
get freeTrial() {
|
get freeTrial() {
|
||||||
|
|||||||
@@ -17,43 +17,41 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate *ngIf="anyOrgsAvailable">
|
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate *ngIf="anyOrgsAvailable">
|
||||||
<div *ngIf="moreThanOneOrgAvailable" class="form-group col-6">
|
<div *ngIf="moreThanOneOrgAvailable" class="form-group col-7">
|
||||||
<label for="availableSponsorshipOrg">{{ 'sponsoredFamiliesSelectOffer' | i18n}}</label>
|
<label for="availableSponsorshipOrg">{{ 'familiesSponsoringOrgSelect' | i18n}}</label>
|
||||||
<select id="availableSponsorshipOrg" name="Available Sponsorship Organization"
|
<select id="availableSponsorshipOrg" name="Available Sponsorship Organization"
|
||||||
[(ngModel)]="selectedSponsorshipOrgId" class="form-control" required>
|
[(ngModel)]="selectedSponsorshipOrgId" class="form-control" required>
|
||||||
<option value="">-- {{'select' | i18n}} --</option>
|
<option value="">-- {{'select' | i18n}} --</option>
|
||||||
<option *ngFor="let o of availableSponsorshipOrgs" [ngValue]="o.id">{{o.name}}</option>
|
<option *ngFor="let o of availableSponsorshipOrgs" [ngValue]="o.id">{{o.name}}</option>
|
||||||
</select>
|
</select>
|
||||||
<small>{{'sponsoredFamiliesLeaveCopy' | i18n}}</small>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-6">
|
<div class="form-group col-7">
|
||||||
<label for="accountEmail">{{'sponsoredFamiliesEmail' | i18n}}:</label>
|
<label for="accountEmail">{{'sponsoredFamiliesEmail' | i18n}}:</label>
|
||||||
<input id="accountEmail" class="form-control" inputmode="email" [(ngModel)]="sponsorshipEmail"
|
<input id="accountEmail" class="form-control" inputmode="email" [(ngModel)]="sponsorshipEmail"
|
||||||
name="sponsorshipEmail" required>
|
name="sponsorshipEmail" required>
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label for="friendlyName">{{'friendlyName' | i18n}}:</label>
|
|
||||||
<input id="friendlyName" class="form-control" [(ngModel)]="friendlyName" name="friendlyName" required>
|
|
||||||
<button class="btn btn-primary btn-submit mt-4" type="submit" [disabled]="form.loading">
|
<button class="btn btn-primary btn-submit mt-4" type="submit" [disabled]="form.loading">
|
||||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||||
<span>{{'redeem' | i18n}}</span>
|
<span>{{'redeem' | i18n}}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div *ngIf="anyActiveSponsorships">
|
<ng-container *ngIf="anyActiveSponsorships">
|
||||||
<table class="table table-hover table-list">
|
<div class="border-bottom">
|
||||||
<thead>
|
<table class="table table-hover table-list">
|
||||||
<tr>
|
<thead>
|
||||||
<th>{{'friendlyName' | i18n}}</th>
|
<tr>
|
||||||
<th>{{'sponsoringOrg' | i18n}}</th>
|
<th>{{'recipient' | i18n}}</th>
|
||||||
<th></th>
|
<th>{{'sponsoringOrg' | i18n}}</th>
|
||||||
</tr>
|
<th></th>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody>
|
</thead>
|
||||||
<ng-container *ngFor="let o of activeSponsorshipOrgs">
|
<tbody>
|
||||||
<tr sponsoring-org-row [sponsoringOrg]="o" (sponsorshipRemoved)="load(true)"></tr>
|
<ng-container *ngFor="let o of activeSponsorshipOrgs">
|
||||||
</ng-container>
|
<tr sponsoring-org-row [sponsoringOrg]="o" (sponsorshipRemoved)="load(true)"></tr>
|
||||||
</tbody>
|
</ng-container>
|
||||||
</table>
|
</tbody>
|
||||||
</div>
|
</table>
|
||||||
|
</div>
|
||||||
|
<small>{{'sponsoredFamiliesLeaveCopy' | i18n}}</small>
|
||||||
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ export class SponsoredFamiliesComponent implements OnInit {
|
|||||||
activeSponsorshipOrgs: Organization[] = [];
|
activeSponsorshipOrgs: Organization[] = [];
|
||||||
selectedSponsorshipOrgId: string = '';
|
selectedSponsorshipOrgId: string = '';
|
||||||
sponsorshipEmail: string = '';
|
sponsorshipEmail: string = '';
|
||||||
friendlyName: string = '';
|
|
||||||
|
|
||||||
// Conditional display properties
|
// Conditional display properties
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
@@ -38,7 +37,7 @@ export class SponsoredFamiliesComponent implements OnInit {
|
|||||||
this.formPromise = this.apiService.postCreateSponsorship(this.selectedSponsorshipOrgId, {
|
this.formPromise = this.apiService.postCreateSponsorship(this.selectedSponsorshipOrgId, {
|
||||||
sponsoredEmail: this.sponsorshipEmail,
|
sponsoredEmail: this.sponsorshipEmail,
|
||||||
planSponsorshipType: PlanSponsorshipType.FamiliesForEnterprise,
|
planSponsorshipType: PlanSponsorshipType.FamiliesForEnterprise,
|
||||||
friendlyName: this.friendlyName,
|
friendlyName: this.sponsorshipEmail,
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.formPromise;
|
await this.formPromise;
|
||||||
@@ -72,7 +71,6 @@ export class SponsoredFamiliesComponent implements OnInit {
|
|||||||
|
|
||||||
private async resetForm() {
|
private async resetForm() {
|
||||||
this.sponsorshipEmail = '';
|
this.sponsorshipEmail = '';
|
||||||
this.friendlyName = '';
|
|
||||||
this.selectedSponsorshipOrgId = '';
|
this.selectedSponsorshipOrgId = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,16 +3,24 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>{{sponsoringOrg.name}}</td>
|
<td>{{sponsoringOrg.name}}</td>
|
||||||
<td class="table-action-right">
|
<td class="table-action-right">
|
||||||
<button #resendEmailBtn [appApiAction]="resendEmailPromise" class="btn btn-outline-primary btn-submit"
|
<div class="dropdown" appListDropdown>
|
||||||
[disabled]="resendEmailBtn.loading" (click)="resendEmail()"
|
<button class="btn btn-outline-secondary dropdown-toggle" type="button" id="dropdownMenuButton"
|
||||||
[attr.aria-label]="'resendEmailLabel' | i18n : sponsoringOrg.familySponsorshipFriendlyName">
|
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" appA11yTitle="{{'options' | i18n}}">
|
||||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
<i class="fa fa-cog fa-lg" aria-hidden="true"></i>
|
||||||
<span>{{'resendEmail' | i18n }}</span>
|
</button>
|
||||||
</button>
|
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
|
||||||
<button #revokeSponsorshipBtn [appApiAction]="revokeSponsorshipPromise" class="btn btn-outline-danger btn-submit"
|
<button #resendEmailBtn [appApiAction]="resendEmailPromise" class="dropdown-item btn-submit"
|
||||||
[disabled]="revokeSponsorshipBtn.loading" (click)="revokeSponsorship()"
|
[disabled]="resendEmailBtn.loading" (click)="resendEmail()"
|
||||||
[attr.aria-label]="'revokeAccount' | i18n : sponsoringOrg.familySponsorshipFriendlyName">
|
[attr.aria-label]="'resendEmailLabel' | i18n : sponsoringOrg.familySponsorshipFriendlyName">
|
||||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||||
<span>{{'remove' | i18n}}</span>
|
<span>{{'resendEmail' | i18n }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button #revokeSponsorshipBtn [appApiAction]="revokeSponsorshipPromise" class="dropdown-item text-danger btn-submit"
|
||||||
|
[disabled]="revokeSponsorshipBtn.loading" (click)="revokeSponsorship()"
|
||||||
|
[attr.aria-label]="'revokeAccount' | i18n : sponsoringOrg.familySponsorshipFriendlyName">
|
||||||
|
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||||
|
<span>{{'remove' | i18n}}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ export class SponsoringOrgRowComponent {
|
|||||||
try {
|
try {
|
||||||
this.revokeSponsorshipPromise = this.doRevokeSponsorship();
|
this.revokeSponsorshipPromise = this.doRevokeSponsorship();
|
||||||
await this.revokeSponsorshipPromise;
|
await this.revokeSponsorshipPromise;
|
||||||
this.toasterService.popAsync('success', null, this.i18nService.t('reclaimedFreePlan'));
|
|
||||||
this.sponsorshipRemoved.emit();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
}
|
}
|
||||||
@@ -50,7 +48,7 @@ export class SponsoringOrgRowComponent {
|
|||||||
|
|
||||||
private async doRevokeSponsorship() {
|
private async doRevokeSponsorship() {
|
||||||
const isConfirmed = await this.platformUtilsService.showDialog(
|
const isConfirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('revokeSponsorshipConfirmation'),
|
this.i18nService.t('revokeSponsorshipConfirmation'),
|
||||||
`${this.i18nService.t('remove')} ${this.sponsoringOrg.familySponsorshipFriendlyName}?`,
|
`${this.i18nService.t('remove')} ${this.sponsoringOrg.familySponsorshipFriendlyName}?`,
|
||||||
this.i18nService.t('remove'), this.i18nService.t('cancel'), 'warning');
|
this.i18nService.t('remove'), this.i18nService.t('cancel'), 'warning');
|
||||||
|
|
||||||
@@ -59,5 +57,7 @@ export class SponsoringOrgRowComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await this.apiService.deleteRevokeSponsorship(this.sponsoringOrg.id);
|
await this.apiService.deleteRevokeSponsorship(this.sponsoringOrg.id);
|
||||||
|
this.toasterService.popAsync('success', null, this.i18nService.t('reclaimedFreePlan'));
|
||||||
|
this.sponsorshipRemoved.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4506,6 +4506,9 @@
|
|||||||
"sponsoredFamiliesSharedCollections": {
|
"sponsoredFamiliesSharedCollections": {
|
||||||
"message": "Shared collections for Family secrets"
|
"message": "Shared collections for Family secrets"
|
||||||
},
|
},
|
||||||
|
"badToken": {
|
||||||
|
"message": "The link is no longer valid. Please have the sponsor resend the offer."
|
||||||
|
},
|
||||||
"reclaimedFreePlan": {
|
"reclaimedFreePlan": {
|
||||||
"message": "Reclaimed free plan"
|
"message": "Reclaimed free plan"
|
||||||
},
|
},
|
||||||
@@ -4515,11 +4518,14 @@
|
|||||||
"sponsoredFamiliesSelectOffer": {
|
"sponsoredFamiliesSelectOffer": {
|
||||||
"message": "Select the organization you would like sponsored"
|
"message": "Select the organization you would like sponsored"
|
||||||
},
|
},
|
||||||
|
"familiesSponsoringOrgSelect": {
|
||||||
|
"message": "Which Free Families offer would you like to redeem?"
|
||||||
|
},
|
||||||
"sponsoredFamiliesEmail": {
|
"sponsoredFamiliesEmail": {
|
||||||
"message": "Enter your personal email to redeem Bitwarden Families"
|
"message": "Enter your personal email to redeem Bitwarden Families"
|
||||||
},
|
},
|
||||||
"sponsoredFamiliesLeaveCopy": {
|
"sponsoredFamiliesLeaveCopy": {
|
||||||
"message": "If you leave or are removed from this organization, your Families plan will expire at the end of the billing period."
|
"message": "If you leave or are removed from the sponsoring organization, your Families plan will expire at the end of the billing period."
|
||||||
},
|
},
|
||||||
"acceptBitwardenFamiliesHelp": {
|
"acceptBitwardenFamiliesHelp": {
|
||||||
"message": "Accept offer for an existing organization or create a new Families organization."
|
"message": "Accept offer for an existing organization or create a new Families organization."
|
||||||
@@ -4540,7 +4546,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sponsoredFamiliesOffer": {
|
"sponsoredFamiliesOffer": {
|
||||||
"message": "Redeem Free Bitwarden Families Organization Offer"
|
"message": "Accept Free Bitwarden Families"
|
||||||
},
|
},
|
||||||
"sponsoredFamiliesOfferRedeemed": {
|
"sponsoredFamiliesOfferRedeemed": {
|
||||||
"message": "Free Bitwarden Families offer successfully redeemed"
|
"message": "Free Bitwarden Families offer successfully redeemed"
|
||||||
@@ -4575,8 +4581,8 @@
|
|||||||
"redeemNow": {
|
"redeemNow": {
|
||||||
"message": "Redeem Now"
|
"message": "Redeem Now"
|
||||||
},
|
},
|
||||||
"friendlyName": {
|
"recipient": {
|
||||||
"message": "Friendly Name"
|
"message": "Recipient"
|
||||||
},
|
},
|
||||||
"removeSponsorship": {
|
"removeSponsorship": {
|
||||||
"message": "Remove Sponsorship"
|
"message": "Remove Sponsorship"
|
||||||
@@ -4702,7 +4708,7 @@
|
|||||||
"message": "Please provide a payment method to associate with the organization. Don't worry, we won't charge you anything unless you select additional features or your sponsorship expires. "
|
"message": "Please provide a payment method to associate with the organization. Don't worry, we won't charge you anything unless you select additional features or your sponsorship expires. "
|
||||||
},
|
},
|
||||||
"orgCreatedSponsorshipInvalid": {
|
"orgCreatedSponsorshipInvalid": {
|
||||||
"message": "The sponsorship offer has expired you may delete the organization you created to avoid a charge at the end of your 7 day trial. Otherwise you may close this prompt to keep the organization and assume billing responsibility."
|
"message": "The sponsorship offer has expired. You may delete the organization you created to avoid a charge at the end of your 7 day trial. Otherwise you may close this prompt to keep the organization and assume billing responsibility."
|
||||||
},
|
},
|
||||||
"newFamiliesOrganization": {
|
"newFamiliesOrganization": {
|
||||||
"message": "New Families Organization"
|
"message": "New Families Organization"
|
||||||
@@ -4724,5 +4730,8 @@
|
|||||||
},
|
},
|
||||||
"sponsorshipTokenHasExpired": {
|
"sponsorshipTokenHasExpired": {
|
||||||
"message": "The sponsorship offer has expired."
|
"message": "The sponsorship offer has expired."
|
||||||
|
},
|
||||||
|
"freeWithSponsorship": {
|
||||||
|
"message": "FREE with sponsorship"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user