mirror of
https://github.com/bitwarden/browser
synced 2025-12-14 07:13:32 +00:00
SG-680 - Domain verification progress - (1) Table layout + loading working for the most part (more translations needed (2) Add & edit opening dialog (3) Dialog first draft of save and verify
This commit is contained in:
@@ -5557,7 +5557,25 @@
|
|||||||
"message": "Bitwarden will attempt to verify the domain 3 times during the first 72 hours. If the domain can’t be verified, check the DNS record in your host and manually verify."
|
"message": "Bitwarden will attempt to verify the domain 3 times during the first 72 hours. If the domain can’t be verified, check the DNS record in your host and manually verify."
|
||||||
},
|
},
|
||||||
"invalidDomainNameMessage": {
|
"invalidDomainNameMessage": {
|
||||||
"message": "'https://', 'http://', or 'www.' domain prefixes not allowed."
|
"message": "Input is not a valid format. Example: mydomain.com. Subdomains require separate entries to be verified."
|
||||||
|
},
|
||||||
|
"domainRemoved": {
|
||||||
|
"message": "Domain removed"
|
||||||
|
},
|
||||||
|
"domainSaved": {
|
||||||
|
"message": "Domain saved"
|
||||||
|
},
|
||||||
|
"domainVerified": {
|
||||||
|
"message": "Domain verified"
|
||||||
|
},
|
||||||
|
"domainNotVerified": {
|
||||||
|
"message": "$DOMAIN$ not verified. Check your DNS record.",
|
||||||
|
"placeholders": {
|
||||||
|
"DOMAIN": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "bitwarden.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,20 @@
|
|||||||
<bit-dialog [dialogSize]="dialogSize" [disablePadding]="disablePadding">
|
<bit-dialog [dialogSize]="dialogSize" [disablePadding]="disablePadding">
|
||||||
<span bitDialogTitle>{{ "newDomain" | i18n }}</span>
|
<span bitDialogTitle>
|
||||||
|
<span *ngIf="!data.orgDomain">{{ "newDomain" | i18n }}</span>
|
||||||
|
<span *ngIf="data.orgDomain"> {{ "verifyDomain" | i18n }}</span>
|
||||||
|
|
||||||
|
<span *ngIf="data.orgDomain" class="tw-text-xs tw-text-muted">{{
|
||||||
|
data.orgDomain.domainName
|
||||||
|
}}</span>
|
||||||
|
|
||||||
|
<!-- TODO: get status badge here -->
|
||||||
|
</span>
|
||||||
<div bitDialogContent>
|
<div bitDialogContent>
|
||||||
<form [formGroup]="domainForm">
|
<form [formGroup]="domainForm" [bitSubmit]="verifyDomain">
|
||||||
|
<!-- <input bitInput formControlName="domainName" /> -->
|
||||||
|
<!-- <span *ngIf="domainNameCtrl.touched && domainNameCtrl.invalid">Error</span> -->
|
||||||
|
|
||||||
|
<!-- TODO: investigate why bit-form-field breaks touched -->
|
||||||
<bit-form-field>
|
<bit-form-field>
|
||||||
<bit-label>{{ "domainName" | i18n }}</bit-label>
|
<bit-label>{{ "domainName" | i18n }}</bit-label>
|
||||||
<input bitInput formControlName="domainName" />
|
<input bitInput formControlName="domainName" />
|
||||||
@@ -29,10 +42,17 @@
|
|||||||
</bit-callout>
|
</bit-callout>
|
||||||
</div>
|
</div>
|
||||||
<div bitDialogFooter class="tw-flex tw-flex-row tw-items-center tw-gap-2">
|
<div bitDialogFooter class="tw-flex tw-flex-row tw-items-center tw-gap-2">
|
||||||
<button bitButton buttonType="primary" [disabled]="domainForm.invalid">
|
<button
|
||||||
|
type="submit"
|
||||||
|
bitButton
|
||||||
|
buttonType="primary"
|
||||||
|
[disabled]="domainForm.invalid"
|
||||||
|
(click)="data.orgDomain ? verifyDomain() : saveDomain()"
|
||||||
|
[loading]="submitting"
|
||||||
|
>
|
||||||
{{ "verifyDomain" | i18n }}
|
{{ "verifyDomain" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
<button bitButton buttonType="secondary" (click)="dialogRef.close()">
|
<button bitButton buttonType="secondary" [disabled]="submitting" (click)="dialogRef.close()">
|
||||||
{{ "cancel" | i18n }}
|
{{ "cancel" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -43,6 +63,9 @@
|
|||||||
size="default"
|
size="default"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
aria-label="Delete"
|
aria-label="Delete"
|
||||||
|
(click)="deleteDomain()"
|
||||||
|
[disabled]="submitting"
|
||||||
|
[loading]="deleting"
|
||||||
></button>
|
></button>
|
||||||
</div>
|
</div>
|
||||||
</bit-dialog>
|
</bit-dialog>
|
||||||
|
|||||||
@@ -4,14 +4,17 @@ import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms"
|
|||||||
|
|
||||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
|
import { OrgDomainApiServiceAbstraction } from "@bitwarden/common/abstractions/organization-domain/org-domain-api.service.abstraction";
|
||||||
import { OrganizationDomainResponse } from "@bitwarden/common/abstractions/organization-domain/responses/organization-domain.response";
|
import { OrganizationDomainResponse } from "@bitwarden/common/abstractions/organization-domain/responses/organization-domain.response";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { Utils } from "@bitwarden/common/misc/utils";
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
|
import { OrganizationDomainRequest } from "@bitwarden/common/services/organization-domain/requests/organization-domain.request";
|
||||||
|
|
||||||
import { domainNameValidator } from "./domain-name.validator";
|
import { domainNameValidator } from "./domain-name.validator";
|
||||||
export interface DomainAddEditDialogData {
|
export interface DomainAddEditDialogData {
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
orgDomain: OrganizationDomainResponse;
|
orgDomain: OrganizationDomainResponse;
|
||||||
|
existingDomainNames: Array<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -22,6 +25,8 @@ export class DomainAddEditDialogComponent implements OnInit {
|
|||||||
dialogSize: "small" | "default" | "large" = "default";
|
dialogSize: "small" | "default" | "large" = "default";
|
||||||
disablePadding = false;
|
disablePadding = false;
|
||||||
|
|
||||||
|
// TODO: should invalidDomainNameMessage have something like: "'https://', 'http://', or 'www.' domain prefixes not allowed."
|
||||||
|
// TODO: write separate uniqueIn validator w/ translated msg: "You can’t claim the same domain twice."
|
||||||
domainForm: FormGroup = this.formBuilder.group({
|
domainForm: FormGroup = this.formBuilder.group({
|
||||||
domainName: [
|
domainName: [
|
||||||
"",
|
"",
|
||||||
@@ -37,13 +42,17 @@ export class DomainAddEditDialogComponent implements OnInit {
|
|||||||
return this.domainForm.controls.txt as FormControl;
|
return this.domainForm.controls.txt as FormControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
submitting = false;
|
||||||
|
deleting = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialogRef: DialogRef,
|
public dialogRef: DialogRef,
|
||||||
@Inject(DIALOG_DATA) public data: DomainAddEditDialogData,
|
@Inject(DIALOG_DATA) public data: DomainAddEditDialogData,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private cryptoFunctionService: CryptoFunctionServiceAbstraction,
|
private cryptoFunctionService: CryptoFunctionServiceAbstraction,
|
||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService,
|
||||||
private i18nService: I18nService
|
private i18nService: I18nService,
|
||||||
|
private orgDomainApiService: OrgDomainApiServiceAbstraction
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit(): Promise<void> {
|
async ngOnInit(): Promise<void> {
|
||||||
@@ -55,6 +64,7 @@ export class DomainAddEditDialogComponent implements OnInit {
|
|||||||
if (this.data.orgDomain) {
|
if (this.data.orgDomain) {
|
||||||
// Edit
|
// Edit
|
||||||
this.domainForm.patchValue(this.data.orgDomain);
|
this.domainForm.patchValue(this.data.orgDomain);
|
||||||
|
this.domainForm.disable();
|
||||||
} else {
|
} else {
|
||||||
// Add
|
// Add
|
||||||
|
|
||||||
@@ -69,12 +79,78 @@ export class DomainAddEditDialogComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
copyDnsTxt() {
|
copyDnsTxt(): void {
|
||||||
this.platformUtilsService.copyToClipboard(this.txtCtrl.value);
|
this.platformUtilsService.copyToClipboard(this.txtCtrl.value);
|
||||||
this.platformUtilsService.showToast(
|
this.platformUtilsService.showToast(
|
||||||
"info",
|
"success",
|
||||||
null,
|
null,
|
||||||
this.i18nService.t("valueCopied", this.i18nService.t("dnsTxtRecord"))
|
this.i18nService.t("valueCopied", this.i18nService.t("dnsTxtRecord"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: error handling?
|
||||||
|
|
||||||
|
// TODO: probably will be a need to split into different actions: save == save + verify
|
||||||
|
// and if edit true, then verify is verify.
|
||||||
|
|
||||||
|
// Need to display verified status somewhere
|
||||||
|
// If verified, no action can be taken but delete
|
||||||
|
// If saved & unverified, can prompt verification
|
||||||
|
|
||||||
|
async saveDomain(): Promise<void> {
|
||||||
|
this.submitting = true;
|
||||||
|
this.domainForm.disable();
|
||||||
|
|
||||||
|
const request: OrganizationDomainRequest = new OrganizationDomainRequest(
|
||||||
|
this.txtCtrl.value,
|
||||||
|
this.domainNameCtrl.value
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.orgDomainApiService.post(this.data.organizationId, request);
|
||||||
|
|
||||||
|
//TODO: figure out how to handle DomainVerifiedException
|
||||||
|
|
||||||
|
this.platformUtilsService.showToast("success", null, this.i18nService.t("domainSaved"));
|
||||||
|
this.submitting = false;
|
||||||
|
|
||||||
|
// TODO: verify before closing modal; close if successful
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyDomain(): Promise<void> {
|
||||||
|
this.submitting = true;
|
||||||
|
this.domainForm.disable();
|
||||||
|
|
||||||
|
const success: boolean = await this.orgDomainApiService.verify(
|
||||||
|
this.data.organizationId,
|
||||||
|
this.data.orgDomain.id
|
||||||
|
);
|
||||||
|
|
||||||
|
this.submitting = false;
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
this.platformUtilsService.showToast("success", null, this.i18nService.t("domainVerified"));
|
||||||
|
this.dialogRef.close();
|
||||||
|
} else {
|
||||||
|
this.platformUtilsService.showToast(
|
||||||
|
"error",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("domainNotVerified", this.domainNameCtrl.value)
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: discuss with Danielle / Gbubemi:
|
||||||
|
// Someone else is using [domain]. Use a different domain to continue.
|
||||||
|
// I only have a bool to indicate success or failure.. not why it failed.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteDomain(): Promise<void> {
|
||||||
|
// TODO: Do I need an are you sure prompt?
|
||||||
|
|
||||||
|
this.deleting = true;
|
||||||
|
await this.orgDomainApiService.delete(this.data.organizationId, this.data.orgDomain.id);
|
||||||
|
this.deleting = false;
|
||||||
|
this.platformUtilsService.showToast("success", null, this.i18nService.t("domainRemoved"));
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,8 @@
|
|||||||
<span class="sr-only">{{ "loading" | i18n }}</span>
|
<span class="sr-only">{{ "loading" | i18n }}</span>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- <div *ngIf="orgDomains$ | async as orgDomains; else loading">
|
|
||||||
{{ obs }}
|
|
||||||
</div>
|
|
||||||
<ng-template #loading>Loading...</ng-template> -->
|
|
||||||
|
|
||||||
<ng-container *ngIf="!loading">
|
<ng-container *ngIf="!loading">
|
||||||
|
<ng-container *ngIf="orgDomains$ | async as orgDomains">
|
||||||
<div class="tw-flex tw-flex-row">
|
<div class="tw-flex tw-flex-row">
|
||||||
<bit-table class="tw-w-full tw-table-auto">
|
<bit-table class="tw-w-full tw-table-auto">
|
||||||
<ng-container header>
|
<ng-container header>
|
||||||
@@ -33,19 +29,56 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container body>
|
<ng-container body>
|
||||||
<!-- [alignContent]="alignRowContent" -->
|
<!-- [alignContent]="alignRowContent" -->
|
||||||
<tr bitRow *ngFor="let orgDomain of orgDomains$ | async; index as i">
|
<tr bitRow *ngFor="let orgDomain of orgDomains; index as i">
|
||||||
<td bitCell>{{ orgDomain.domainName }}</td>
|
|
||||||
<td bitCell>
|
<td bitCell>
|
||||||
{{ orgDomain.domainName }}
|
<a bitLink href appStopClick linkType="primary" (click)="editDomain(orgDomain)">{{
|
||||||
|
orgDomain.domainName
|
||||||
|
}}</a>
|
||||||
|
</td>
|
||||||
|
<td bitCell>
|
||||||
|
<span *ngIf="!orgDomain?.verifiedDate" bitBadge badgeType="warning">Unverified</span>
|
||||||
|
<span *ngIf="orgDomain?.verifiedDate" bitBadge badgeType="success">Verified</span>
|
||||||
|
</td>
|
||||||
|
<td bitCell>
|
||||||
|
<!-- TODO: next run date != last checked... -->
|
||||||
|
{{ orgDomain.nextRunDate | date: "medium" }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td bitCell class="table-list-options">
|
||||||
|
<button
|
||||||
|
[bitMenuTriggerFor]="orgDomainOptions"
|
||||||
|
class="tw-border-none tw-bg-transparent tw-text-main"
|
||||||
|
type="button"
|
||||||
|
appA11yTitle="{{ 'options' | i18n }}"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-ellipsis-v bwi-lg" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
<bit-menu #orgDomainOptions>
|
||||||
|
<button bitMenuItem>
|
||||||
|
<i class="bwi bwi-fw bwi-clone" aria-hidden="true"></i>
|
||||||
|
Copy DNS TXT record
|
||||||
|
</button>
|
||||||
|
<button bitMenuItem>
|
||||||
|
<i class="bwi bwi-fw bwi-check text-success" aria-hidden="true"></i>
|
||||||
|
Verify domain
|
||||||
|
</button>
|
||||||
|
<button bitMenuItem>
|
||||||
|
<span class="tw-text-danger">
|
||||||
|
<i class="bwi bwi-fw bwi-close" aria-hidden="true"></i>
|
||||||
|
{{ "remove" | i18n }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</bit-menu>
|
||||||
</td>
|
</td>
|
||||||
<td bitCell>test</td>
|
|
||||||
<td bitCell>test</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</bit-table>
|
</bit-table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tw-mt-6 tw-flex tw-flex-col tw-items-center tw-justify-center">
|
<div
|
||||||
|
class="tw-mt-6 tw-flex tw-flex-col tw-items-center tw-justify-center"
|
||||||
|
*ngIf="orgDomains?.length == 0"
|
||||||
|
>
|
||||||
<img src="../../images/domain-verification/domain.svg" class="tw-mb-4" alt="domain" />
|
<img src="../../images/domain-verification/domain.svg" class="tw-mb-4" alt="domain" />
|
||||||
|
|
||||||
<div class="tw-mb-2 tw-flex tw-flex-row tw-justify-center">
|
<div class="tw-mb-2 tw-flex tw-flex-row tw-justify-center">
|
||||||
@@ -62,5 +95,5 @@
|
|||||||
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i> {{ "newDomain" | i18n }}
|
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i> {{ "newDomain" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
¸
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@@ -68,6 +68,19 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
|||||||
const domainAddEditDialogData: DomainAddEditDialogData = {
|
const domainAddEditDialogData: DomainAddEditDialogData = {
|
||||||
organizationId: this.organizationId,
|
organizationId: this.organizationId,
|
||||||
orgDomain: null,
|
orgDomain: null,
|
||||||
|
existingDomainNames: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
this.dialogService.open(DomainAddEditDialogComponent, {
|
||||||
|
data: domainAddEditDialogData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
editDomain(orgDomain: OrganizationDomainResponse) {
|
||||||
|
const domainAddEditDialogData: DomainAddEditDialogData = {
|
||||||
|
organizationId: this.organizationId,
|
||||||
|
orgDomain: orgDomain,
|
||||||
|
existingDomainNames: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dialogService.open(DomainAddEditDialogComponent, {
|
this.dialogService.open(DomainAddEditDialogComponent, {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { OrganizationDomainRequest } from "../../services/organization-domain/requests/organization-domain.request";
|
||||||
|
|
||||||
import { OrganizationDomainResponse } from "./responses/organization-domain.response";
|
import { OrganizationDomainResponse } from "./responses/organization-domain.response";
|
||||||
|
|
||||||
export abstract class OrgDomainApiServiceAbstraction {
|
export abstract class OrgDomainApiServiceAbstraction {
|
||||||
@@ -6,7 +8,10 @@ export abstract class OrgDomainApiServiceAbstraction {
|
|||||||
orgId: string,
|
orgId: string,
|
||||||
orgDomainId: string
|
orgDomainId: string
|
||||||
) => Promise<OrganizationDomainResponse>;
|
) => Promise<OrganizationDomainResponse>;
|
||||||
post: (orgId: string, orgDomain: OrganizationDomainResponse) => Promise<any>;
|
post: (
|
||||||
|
orgId: string,
|
||||||
|
orgDomain: OrganizationDomainRequest
|
||||||
|
) => Promise<OrganizationDomainResponse>;
|
||||||
verify: (orgId: string, orgDomainId: string) => Promise<boolean>;
|
verify: (orgId: string, orgDomainId: string) => Promise<boolean>;
|
||||||
delete: (orgId: string, orgDomainId: string) => Promise<any>;
|
delete: (orgId: string, orgDomainId: string) => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,13 +45,14 @@ export class OrgDomainApiService implements OrgDomainApiServiceAbstraction {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
async post(orgId: string, orgDomain: OrganizationDomainResponse): Promise<any> {
|
async post(
|
||||||
const request = new OrganizationDomainRequest(orgDomain);
|
orgId: string,
|
||||||
|
orgDomainReq: OrganizationDomainRequest
|
||||||
|
): Promise<OrganizationDomainResponse> {
|
||||||
const result = await this.apiService.send(
|
const result = await this.apiService.send(
|
||||||
"POST",
|
"POST",
|
||||||
`/organizations/${orgId}`,
|
`/organizations/${orgId}/domain`,
|
||||||
request,
|
orgDomainReq,
|
||||||
true,
|
true,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@@ -66,7 +67,7 @@ export class OrgDomainApiService implements OrgDomainApiServiceAbstraction {
|
|||||||
async verify(orgId: string, orgDomainId: string): Promise<boolean> {
|
async verify(orgId: string, orgDomainId: string): Promise<boolean> {
|
||||||
const result: boolean = await this.apiService.send(
|
const result: boolean = await this.apiService.send(
|
||||||
"POST",
|
"POST",
|
||||||
`/organizations/${orgId}/${orgDomainId}/verify`,
|
`/organizations/${orgId}/domain/${orgDomainId}/verify`,
|
||||||
null,
|
null,
|
||||||
true,
|
true,
|
||||||
true
|
true
|
||||||
@@ -76,7 +77,13 @@ export class OrgDomainApiService implements OrgDomainApiServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async delete(orgId: string, orgDomainId: string): Promise<any> {
|
async delete(orgId: string, orgDomainId: string): Promise<any> {
|
||||||
this.apiService.send("DELETE", `/organizations/${orgId}/${orgDomainId}`, null, true, false);
|
this.apiService.send(
|
||||||
|
"DELETE",
|
||||||
|
`/organizations/${orgId}/domain/${orgDomainId}`,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
);
|
||||||
this.orgDomainService.delete([orgDomainId]);
|
this.orgDomainService.delete([orgDomainId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { OrganizationDomainResponse } from "../../../abstractions/organization-domain/responses/organization-domain.response";
|
|
||||||
|
|
||||||
export class OrganizationDomainRequest {
|
export class OrganizationDomainRequest {
|
||||||
txt: string;
|
txt: string;
|
||||||
domainName: string;
|
domainName: string;
|
||||||
|
|
||||||
constructor(orgDomainResponse: OrganizationDomainResponse) {
|
constructor(txt: string, domainName: string) {
|
||||||
this.txt = orgDomainResponse.txt;
|
this.txt = txt;
|
||||||
this.domainName = orgDomainResponse.domainName;
|
this.domainName = domainName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user