nm-searchfavorites-dialog
src/app/shared/widgets/search/favorites/dialog/search-favorites-dialog.component.ts
changeDetection | ChangeDetectionStrategy.OnPush |
selector | nm-searchfavorites-dialog |
styleUrls | search-favorites-dialog.component.scss |
templateUrl | ./search-favorites-dialog.component.html |
Widget inputs |
Widget outputs |
Properties |
|
Methods |
HostListeners |
constructor(dialogRef: MatDialogRef
|
|||||||||||||||||||||||||||
Parameters :
|
document:keydown.escape |
Arguments : '$event'
|
document:keydown.escape(event: )
|
acceptSend |
acceptSend()
|
Returns :
void
|
addFavorite |
addFavorite()
|
Returns :
void
|
back |
back()
|
Returns :
void
|
beforeActionExecute | ||||
beforeActionExecute(action: )
|
||||
Parameters :
Returns :
void
|
checkboxChange | ||||||
checkboxChange(template: , checked: )
|
||||||
Parameters :
Returns :
void
|
createSearchTemplate | ||||
createSearchTemplate(template: )
|
||||
Parameters :
Returns :
void
|
disableSendToButton |
disableSendToButton()
|
Returns :
boolean
|
displayAction | ||||||
displayAction(act: , template: )
|
||||||
Parameters :
Returns :
boolean
|
displayRole | ||||
displayRole(template: )
|
||||
Parameters :
Returns :
boolean
|
edit | ||||
edit(template: )
|
||||
Parameters :
Returns :
void
|
getChipValue | ||||
getChipValue(template: )
|
||||
Parameters :
Returns :
any
|
handleSelectAttributeProfile | ||||
handleSelectAttributeProfile(resp: )
|
||||
Parameters :
Returns :
void
|
loadWorkboxRoles |
loadWorkboxRoles()
|
Returns :
void
|
ngAfterViewInit |
ngAfterViewInit()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
saveEdit | ||||
saveEdit(template: )
|
||||
Parameters :
Returns :
void
|
selectAll | ||||
selectAll(event: )
|
||||
Parameters :
Returns :
void
|
sendTo |
sendTo()
|
Returns :
void
|
stopEdit |
stopEdit()
|
Returns :
void
|
updateSearchTemplate | ||||||
updateSearchTemplate(template: , payload: )
|
||||||
Parameters :
Returns :
void
|
userCheckboxChange | ||||||
userCheckboxChange(user: , checked: )
|
||||||
Parameters :
Returns :
void
|
Public allSelected |
allSelected:
|
Type : boolean
|
Default value : false
|
Public dialogRef |
dialogRef:
|
Type : MatDialogRef<SearchFavoritesDialogComponent>
|
Public dialogService |
dialogService:
|
Type : DialogService
|
Public editingTemplate |
editingTemplate:
|
Public filterText |
filterText:
|
Public formData |
formData:
|
Public groupIndex |
groupIndex:
|
Type : number
|
Default value : 0
|
Public hasCreateRoleBasedTemplate |
hasCreateRoleBasedTemplate:
|
Type : boolean
|
Public infoText |
infoText:
|
Type : string
|
inputList |
inputList:
|
Type : QueryList<HTMLInputElement>
|
Decorators : ViewChildren
|
Public isListSearch |
isListSearch:
|
Private loadFavorites |
loadFavorites:
|
Default value : new Subject<void>()
|
Public loading |
loading:
|
Default value : false
|
Public onFavoriteChange |
onFavoriteChange:
|
Default value : this.onFavoriteChangeSub.pipe(
takeUntil(this.unsubscribe)
)
|
Private onFavoriteChangeSub |
onFavoriteChangeSub:
|
Default value : new Subject<void>()
|
Public rolesOptions |
rolesOptions:
|
Type : []
|
Default value : []
|
Public searchTemplatesUri |
searchTemplatesUri:
|
Type : string
|
Public selected |
selected:
|
Type : []
|
Default value : []
|
Public selectedFavorite |
selectedFavorite:
|
Public selectedUser |
selectedUser:
|
Type : []
|
Default value : []
|
Public sending |
sending:
|
Default value : false
|
Public templates |
templates:
|
Private unsubscribe |
unsubscribe:
|
Default value : NgUnsubscribe.create()
|
Public userfilterText |
userfilterText:
|
Public users |
users:
|
Type : []
|
Default value : []
|
Public userTranslation |
userTranslation:
|
Type : string
|
Default value : ""
|
viewPort |
viewPort:
|
Type : CdkFixedSizeVirtualScroll
|
Decorators : ViewChild
|
data |
getdata()
|
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
HostListener,
Injectable,
OnInit,
QueryList,
ViewChild,
ViewChildren,
} from "@angular/core";
import { MatDialog, MatDialogRef } from "@angular/material/dialog";
import { WidgetframeService } from "../../../widgetframe/widgetframe.service";
import {
deepCopy,
UtilService,
} from "../../../../components/util/util.service";
import { CurrentLocaleService } from "../../../../components/i18n/currentLocale.service";
import { NgUnsubscribe } from "../../../../ng-unsubscribe";
import { filter, flatMap, map, takeUntil } from "rxjs/operators";
import { HalService } from "../../../../components/hal/hal.service";
import * as uriTemplates_ from "uri-templates";
import { NotificationsService } from "../../../../components/notifications/services/notifications.service";
import { combineLatest, Subject } from "rxjs";
import { AppdataStore } from "../../../../components/appdata/appdata.store";
import { CdkFixedSizeVirtualScroll } from "@angular/cdk/scrolling";
import { TranslateService } from "@ngx-translate/core";
import {
DynamicFormTabsContext,
DynamicFormTabsDialog,
} from "../../../dynamic-form/dynamic-form-tabs-dialog/dynamic-form-tabs-dialog.component";
import { DialogService } from "../../../../../shared/components/dialog/dialog.service";
const uriTemplates = uriTemplates_;
@Component({
selector: "nm-searchfavorites-dialog",
templateUrl: "./search-favorites-dialog.component.html",
styleUrls: ["./search-favorites-dialog.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SearchFavoritesDialogComponent implements OnInit, AfterViewInit {
public searchTemplatesUri: string;
public hasCreateRoleBasedTemplate: boolean;
public dialogService: DialogService;
public groupIndex = 0;
public templates;
public filterText;
public userfilterText;
public formData;
public isListSearch;
public selected = [];
public selectedUser = [];
public editingTemplate;
public users = [];
public selectedFavorite;
public infoText: string;
public sending = false;
public loading = false;
public userTranslation: string = "";
public rolesOptions = [];
private unsubscribe = NgUnsubscribe.create();
public allSelected: boolean = false;
private onFavoriteChangeSub = new Subject<void>();
public onFavoriteChange = this.onFavoriteChangeSub.pipe(
takeUntil(this.unsubscribe)
);
private loadFavorites = new Subject<void>();
@ViewChildren("input") inputList: QueryList<HTMLInputElement>;
@ViewChild(CdkFixedSizeVirtualScroll) viewPort: CdkFixedSizeVirtualScroll;
constructor(
public dialogRef: MatDialogRef<SearchFavoritesDialogComponent>,
private widgetframeService: WidgetframeService,
private localeService: CurrentLocaleService,
private halservice: HalService,
private notificationService: NotificationsService,
private appStore: AppdataStore,
private cd: ChangeDetectorRef,
private translateService: TranslateService
) {}
ngOnInit(): void {
this.userTranslation = this.translateService.instant("label.user");
this.dialogRef.afterClosed().subscribe(() => {
this.unsubscribe.destroy();
});
this.halservice
.getActionEvents()
.pipe(
takeUntil(this.unsubscribe),
filter(
(e) =>
e.name == "delete" ||
e.name == "update" ||
e.name == "add-to-dashboard" ||
e.name == "remove-from-dashboard"
)
)
.subscribe((resp) => {
if (resp.response.body) {
this.notificationService.success(
resp.response.body.title,
resp.response.body.message
);
this.loadFavorites.next();
this.onFavoriteChangeSub.next();
this.selected = [];
}
});
this.halservice
.getActionEvents()
.pipe(
takeUntil(this.unsubscribe),
filter((e) => e.name == "select-attribute-profile")
)
.subscribe((resp) => this.handleSelectAttributeProfile(resp));
if (this.searchTemplatesUri) {
combineLatest(
this.localeService.getCurrentLocale(),
this.loadFavorites.asObservable()
)
.pipe(takeUntil(this.unsubscribe))
.subscribe(([locale, load]) => {
const url = UtilService.setUrlParam(
this.searchTemplatesUri,
"locale",
locale
);
this.widgetframeService.getData(url).subscribe((data) => {
this.loading = false;
this.templates = data;
if (this.rolesOptions.length === 0) {
this.loadWorkboxRoles();
}
if (this.selectedFavorite) {
const template = this.templates._embedded.templates.find(
(entry) => entry.identifier === this.selectedFavorite
);
if (template) {
template.checked = true;
}
this.selected = [template];
}
this.cd.markForCheck();
});
});
this.loadFavorites.next();
} else {
console.error("searchTemplatesUri is not defined but needed");
}
}
get data() {
if (!this.templates) {
return [];
}
return this.templates._embedded.templates;
}
edit(template) {
if (this.editingTemplate) {
this.editingTemplate.edit = false;
this.editingTemplate = null;
}
this.editingTemplate = template;
template.edit = true;
template.editText = template.text;
template.chip.value = this.getChipValue(template);
}
@HostListener("document:keydown.escape", ["$event"]) onKeydownHandler(event) {
if (this.editingTemplate) {
this.stopEdit();
} else {
this.dialogRef.close(null);
}
}
saveEdit(template) {
if (!template.editText) {
if (!template.identifier) {
this.data.shift();
// Change the reference for the change detection
this.templates._embedded.templates = [].concat(this.data);
}
this.stopEdit();
return;
}
if (!template.identifier) {
//create new search template
this.createSearchTemplate(template);
} else {
//update current search template
template.text = template.editText;
template.chip.value = this.getChipValue(template);
const payload = {
name: template.editText,
roleId: template.roleId,
attributeProfileId: template.attributeProfileId,
};
this.updateSearchTemplate(template, payload);
}
this.stopEdit();
}
stopEdit() {
if (!this.editingTemplate.identifier) {
this.data.shift();
// Change the reference for the change detection
this.templates._embedded.templates = [].concat(this.data);
}
this.editingTemplate.edit = false;
this.editingTemplate = null;
}
createSearchTemplate(template) {
let action;
let params;
if (this.isListSearch) {
action = this.templates._actions["create-list"];
params = this.formData.listvalue;
} else {
action = this.templates._actions["create-standard"];
params = deepCopy(this.formData.fields);
if (this.formData.attributes) {
params.attributes = this.formData.attributes;
}
if (this.formData.fields && this.formData.fields.category) {
params.publication = this.formData.fields.category.publication;
params.category = this.formData.fields.category.category;
}
}
this.loading = true;
action.payload = {
params,
identifier: template.editText,
roleId: template.roleId,
};
this.halservice
.execute("create-searchfavorite", action)
.subscribe((resp) => {
template.text = template.editText;
if (resp.response.body) {
this.loading = false;
this.notificationService.success(
resp.response.body.title,
resp.response.body.message
);
this.loadFavorites.next();
this.onFavoriteChangeSub.next();
}
});
}
updateSearchTemplate(template, payload) {
const action = template._actions.rename;
action.payload = payload;
this.halservice.execute("save-searchfavorite", action).subscribe((resp) => {
if (resp.response.body) {
this.notificationService.success(
resp.response.body.title,
resp.response.body.message
);
this.onFavoriteChangeSub.next();
}
});
}
getChipValue(template) {
if (template.roleId) {
return this.rolesOptions.find((role) => role.pimRef === template.roleId)
?.name;
} else {
return this.userTranslation;
}
}
addFavorite() {
const template = {
edit: true,
editText: "",
text: "",
};
this.templates._embedded.templates = [template].concat(
this.templates._embedded.templates
);
this.filterText = "";
this.editingTemplate = template;
}
sendTo() {
if (this.users.length === 0) {
this.appStore
.getAppdata()
.pipe(
map((data) => data.portal._links.users.href),
flatMap((url) => this.widgetframeService.getData(url)),
map((data) => data._embedded.users)
)
.subscribe((data) => {
this.users = data;
});
}
this.groupIndex = 1;
}
checkboxChange(template, checked) {
template.checked = checked;
if (checked) {
this.selected.push(template);
} else {
this.selected.splice(this.selected.indexOf(template), 1);
}
this.allSelected = this.selected.length === this.data.length;
}
userCheckboxChange(user, checked) {
user.checked = checked;
if (checked) {
this.selectedUser.push(user);
} else {
this.selected.splice(this.selectedUser.indexOf(user), 1);
}
}
ngAfterViewInit(): void {
this.inputList.changes
.pipe(takeUntil(this.unsubscribe))
.subscribe((data) => {
if (data.first) {
data.first.nativeElement.focus();
}
});
}
acceptSend() {
const action = this.templates._actions["send-to"];
action.payload = this.selectedUser.map((entry) => entry.name);
const tmpl = uriTemplates(action.href);
action.href = tmpl.fill({
source: this.selected.map((entry) => entry.identifier),
});
this.sending = true;
this.halservice.execute("send-searchfavorite", action).subscribe((resp) => {
if (resp.response.body) {
this.notificationService.success(
resp.response.body.title,
resp.response.body.message
);
this.sending = false;
this.groupIndex = 0;
this.selectedUser.forEach((user) => (user.checked = false));
this.selected.forEach((entry) => (entry.checked = false));
this.selectedUser = [];
this.selected = [];
this.cd.markForCheck();
}
});
}
selectAll(event) {
this.allSelected = event.checked;
this.templates._embedded.templates.forEach((template) => {
template.checked = this.allSelected;
});
this.selected = [];
if (this.allSelected) {
this.selected.push(...this.data);
}
}
beforeActionExecute(action) {
if (action.key === "update") {
if (this.isListSearch) {
action.value.payload = this.formData.listvalue;
} else {
const payload = deepCopy(this.formData.fields);
if (payload.category) {
payload.publication = payload.category.publication;
payload.category = payload.category.category;
}
action.value.payload = payload;
if (this.formData.attributes) {
action.value.payload.attributes = this.formData.attributes;
}
if (this.formData.visibleFields) {
action.value.payload.visibleFields = this.formData.visibleFields;
}
}
}
}
back() {
this.groupIndex = 0;
}
displayAction(act, template) {
if (act.key === "update") {
return template.listsearch === this.isListSearch;
}
return act.key !== "rename" && act.key !== "load";
}
displayRole(template) {
return (
(template.roleId || !template.identifier) &&
this.hasCreateRoleBasedTemplate
);
}
disableSendToButton(): boolean {
return (
this.selected.length === 0 ||
this.selected.filter((template) => template.roleId).length > 0
);
}
loadWorkboxRoles() {
this.appStore
.getAppdata()
.pipe(
map((data) => data.portal._links["workbox-roles"].href),
flatMap((url) => this.widgetframeService.getData(url))
)
.subscribe((data) => {
this.rolesOptions = data;
});
}
handleSelectAttributeProfile(resp) {
const templateId = resp?.action?.payload;
const template = this.templates._embedded.templates.find(
(template) => template.identifier === templateId
);
let dialogRef = this.dialogService.open(DynamicFormTabsDialog, {
data: {
identifier: "select-attribute-profile",
title: "placeholder.attribute.profile",
dialogConfig: {
tabs: [
{
type: "form",
fields: [
{
label: "placeholder.attribute.profile",
field: "attributeProfile",
type: "lookup",
lookupOptions: resp?.response?.body?._embedded?.profiles,
identifierField: "pimRef",
descriptionField: "identifier",
lookupAllowEmpty: true,
required: false,
floatingLabel: true,
defaultValue: template?.attributeProfileId,
},
],
},
],
},
},
});
dialogRef.afterClosed().subscribe((data) => {
if (!data) {
return;
}
template.attributeProfileId = data?.values?.attributeProfile;
const payload = {
attributeProfileId: template.attributeProfileId,
};
this.updateSearchTemplate(template, payload);
});
}
}
export function buildStandardSearchUriParameter(data): any {
const form = data[0] ? data[0] : {};
if (form.category) {
if (!form.category.category) {
form.category.category = "";
}
if (!form.category.publication) {
form.category.publication = "";
}
}
const attributes = data[1];
const uriParams = form ? form : {};
let attributeFilters = {};
if (attributes && attributes.length > 0) {
for (let attribute of attributes) {
buildAttributeFilter(attribute, attributeFilters);
}
uriParams["attributes"] = JSON.stringify(attributeFilters);
}
return uriParams;
}
export function buildStandardSearchUri(data, templateUrl): string {
const template = uriTemplates(templateUrl);
return template.fill(buildStandardSearchUriParameter(data));
}
function buildAttributeFilter(attribute, attributeFilters) {
if (attribute.displayRange) {
let from = findValueEncoded(attribute.from);
if (from) {
attributeFilters[attribute.identifier] = from;
}
let to = findValueEncoded(attribute.to);
if (to) {
attributeFilters[attribute.identifier] = to;
}
return;
}
const filter = findValueEncoded(attribute);
if (filter) {
attributeFilters[attribute.identifier] = filter;
}
}
function findValueEncoded(attribute) {
if (attribute.source["0"]) {
if (attribute.source["0"].value) {
return encodeURIComponent(attribute.source["0"].value);
}
}
}
<nm-dialog
[dialogRef]="dialogRef"
[infoText]="infoText"
[infoTitle]="'search-favorites' | translate"
class="nm-dialog nm-searchFavoritesDialog"
>
<ng-container slot="title">
{{ "search-favorites" | translate }}
</ng-container>
<ng-container slot="content">
<mat-tab-group style="width: 100%" [selectedIndex]="groupIndex">
<mat-tab>
<ng-template matTabContent>
<div class="nm-searchFavoritesDialog-input">
<div class="nm-filter-input">
<mat-form-field>
<input
matInput
name="filter"
[(ngModel)]="filterText"
autocomplete="off"
placeholder="{{ 'placeholder.search' | translate }}"
/>
<button
mat-icon-button
color="primary"
matSuffix
class="remove-action"
*ngIf="filterText"
(click)="filterText = ''"
tabIndex="-1"
>
<mat-icon class="fade-in">close</mat-icon>
</button>
</mat-form-field>
</div>
<button
mat-mini-fab
color="primary"
class="nm-searchFavoritesDialog__button"
matTooltip="{{ 'button.add.searchfavorite' | translate }}"
type="button"
color="primary"
[disabled]="editingTemplate || loading"
(click)="addFavorite()"
[disableRipple]="true"
>
<mat-icon>add</mat-icon>
</button>
</div>
<div style="clear: both; display: block"></div>
<div class="nm-searchFavoritesDialog__listWrapper--searchfavorite">
<mat-list>
<mat-list-item style="height: 32px">
<div class="list-text mat-body">
<span
class="checkbox-container"
[class.forceRender]="allSelected"
>
<mat-checkbox
color="primary"
[checked]=""
(change)="selectAll($event)"
disableRipple
></mat-checkbox>
</span>
<div
class="mat-body"
style="margin-left: 15px; display: inline-block"
>
{{ "label.select.all" | translate }}
</div>
</div>
</mat-list-item>
</mat-list>
<mat-list
[style.overflow]="'hidden'"
[style.position]="'relative'"
class="nm-searchFavoritesDialog__list--searchfavorite"
>
<cdk-virtual-scroll-viewport itemSize="45" style="height: 100%">
<mat-list-item
*cdkVirtualFor="
let template of data | customFilter: 'text':filterText
"
style="margin-top: 10px"
>
<ng-container
*ngIf="template.edit; else noEdit"
style="margin-top: 20px"
>
<mat-form-field style="margin-right: 20px">
<input
matInput
placeholder="{{ 'table.head.identifier' | translate }}"
[(ngModel)]="template.editText"
(keydown.enter)="
saveEdit(template); $event.stopPropagation()
"
(keydown.escape)="stopEdit(); $event.stopPropagation()"
#input
/>
</mat-form-field>
<mat-form-field *ngIf="displayRole(template)">
<nm-combo
class="combo"
name="role"
placeholder="{{ 'placeholder.user-roles' | translate }}"
[options]="rolesOptions"
[valueKey]="'pimRef'"
[displayKey]="'name'"
[clearable]="false"
[(ngModel)]="template.roleId"
>
</nm-combo>
</mat-form-field>
<button
mat-icon-button
color="primary"
matSuffix
style="font-size: 24px"
(click)="saveEdit(template)"
[matTooltip]="'button.save' | translate"
tabIndex="-1"
>
<mat-icon>check</mat-icon>
</button>
<button
mat-icon-button
matSuffix
style="font-size: 24px"
color="primary"
(click)="stopEdit()"
[matTooltip]="'button.cancel' | translate"
tabIndex="-1"
>
<mat-icon>close</mat-icon>
</button>
</ng-container>
<ng-template #noEdit>
<div
class="list-text mat-body"
(click)="checkboxChange(template, !template.checked)"
>
<span
class="checkbox-container"
[class.forceRender]="template.checked"
>
<mat-checkbox
color="primary"
[checked]="template.checked"
(change)="$event.preventDefault()"
(click)="$event.preventDefault()"
disableRipple
></mat-checkbox>
</span>
<div class="list-text-container">
<nm-ellipsis
content="{{ template.text }} [{{ template.type }}]"
>
</nm-ellipsis>
</div>
</div>
<div>
<nm-chip
[modifier]="template.chip.color"
[content]="template.chip.value"
[toUpperCase]="true"
width="200px"
>
</nm-chip>
</div>
<div class="list-actions" *ngIf="template._actions">
<mat-icon
color="primary"
class="nm-toolbox-icon-button"
style="cursor: pointer"
(click)="edit(template)"
[matTooltip]="template._actions.rename.description"
container="body"
triggers="mouseenter:mouseleave"
>edit
</mat-icon>
<span
*ngFor="let act of template._actions | iterable"
class="nm-toolbox-icon-button"
>
<nm-action-icon
class="nm-toolbox-icon-button"
(beforeExecute)="beforeActionExecute(act)"
*ngIf="displayAction(act, template)"
[action]="act.value"
[name]="act.key"
></nm-action-icon>
</span>
</div>
</ng-template>
</mat-list-item>
</cdk-virtual-scroll-viewport>
</mat-list>
</div>
</ng-template>
</mat-tab>
<mat-tab>
<ng-template matTabContent>
<mat-form-field>
<input
matInput
name="filter"
[(ngModel)]="userfilterText"
autocomplete="off"
placeholder="{{ 'placeholder.comparison.filter' | translate }}"
[nmAutofocus]="true"
/>
</mat-form-field>
<div
class="nm-searchFavoritesDialog__listWrapper--user"
style="position: relative; width: 100%"
>
<mat-list>
<cdk-virtual-scroll-viewport itemSize="45" style="height: 100%">
<mat-list-item
*cdkVirtualFor="
let user of users | customFilter: 'name':userfilterText
"
>
<div
class="list-text"
(click)="userCheckboxChange(user, !user.checked)"
>
<mat-checkbox
color="primary"
[checked]="user.checked"
(change)="$event.preventDefault()"
(click)="$event.preventDefault()"
disableRipple
></mat-checkbox>
<div class="list-text-container">
<nm-ellipsis content="{{ user.name }}"> </nm-ellipsis>
</div>
</div>
</mat-list-item>
</cdk-virtual-scroll-viewport>
</mat-list>
</div>
</ng-template>
</mat-tab>
</mat-tab-group>
</ng-container>
<ng-container slot="actions">
<mat-tab-group style="width: 100%" [selectedIndex]="groupIndex">
<mat-tab>
<ng-template matTabContent>
<div class="nm-button-group">
<button
mat-button
type="button"
[disabled]="disableSendToButton()"
(click)="sendTo()"
>
<mat-icon>send</mat-icon>
{{ "button.send.to" | translate }}
</button>
<div style="flex-grow: 1"></div>
<button
mat-button
type="button"
style="float: right"
(click)="dialogRef.close()"
>
{{ "button.cancel" | translate }}
</button>
</div>
</ng-template>
</mat-tab>
<mat-tab>
<ng-template matTabContent>
<div class="nm-button-group">
<button mat-button type="button" (click)="back()">
{{ "button.back" | translate }}
</button>
<div style="flex-grow: 1"></div>
<button
mat-button
type="button"
style="float: right"
(click)="dialogRef.close()"
>
{{ "button.cancel" | translate }}
</button>
<button
mat-raised-button
type="button"
color="primary"
style="float: right"
[disabled]="sending || selectedUser.length === 0"
(click)="acceptSend()"
>
{{ "button.send" | translate }}
</button>
</div>
</ng-template>
</mat-tab>
</mat-tab-group>
</ng-container>
</nm-dialog>