UNPKG

@linid-dm/directory-manager-client-core

Version:

Core package by providing a set of angular components for the Directory Manager app.

360 lines 119 kB
import { __decorate } from "tslib"; /** * Copyright (C) 2020-2024 Linagora * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version, provided you comply with the Additional Terms applicable for * LinID Directory Manager software by LINAGORA pursuant to Section 7 of the GNU * Affero General Public License, subsections (b), (c), and (e), pursuant to * which these Appropriate Legal Notices must notably (i) retain the display of * the "LinID™" trademark/logo at the top of the interface window, the display * of the “You are using the Open Source and free version of LinID™, powered by * Linagora © 2009–2013. Contribute to LinID R&D by subscribing to an Enterprise * offer!” infobox and in the e-mails sent with the Program, notice appended to * any type of outbound messages (e.g. e-mail and meeting requests) as well as * in the LinID Directory Manager user interface, (ii) retain all hypertext * links between LinID Directory Manager and https://linid.org/, as well as * between LINAGORA and LINAGORA.com, and (iii) refrain from infringing LINAGORA * intellectual property rights over its trademarks and commercial brands. Other * Additional Terms apply, see <http://www.linagora.com/licenses/> for more * details. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License and * its applicable Additional Terms for LinID Directory Manager along with this * program. If not, see <http://www.gnu.org/licenses/> for the GNU Affero * General Public License version 3 and <http://www.linagora.com/licenses/> for * the Additional Terms applicable to the LinID Directory Manager software. */ import { HttpErrorResponse } from '@angular/common/http'; import { Component, EventEmitter, Inject, Output, ViewChild, } from '@angular/core'; import { FormControl, Validators, } from '@angular/forms'; import { MAT_DIALOG_DATA } from '@angular/material/dialog'; import { MatTableDataSource } from '@angular/material/table'; import { Select } from '@ngxs/store'; import { Subject, catchError, defaultIfEmpty, filter, forkJoin, map, takeUntil, tap, } from 'rxjs'; import { ConfigsState, CustomValidators, Data, DataState, EEllipsisMenuActions, EResourceComponent, ETreeSelectMode, Error as ErrorActions, ResourcesTypesState, buildTree, cleanAssignDialogTree, convertDataNodeToDataItem, getClickableCellsEndpoints, getDataSourceForGenericArray, getElementIds, getFlattenTree, getFormFieldError, getNodeById, getRequestsDetails, getResponseAttributesIds, getUserActionOnResourceRequest, isDataNode, resourceRequest, toJsTable, } from '../../shared'; import * as i0 from "@angular/core"; import * as i1 from "../../shared"; import * as i2 from "@ngxs/store"; import * as i3 from "@angular/forms"; import * as i4 from "@angular/common"; import * as i5 from "@angular/flex-layout/flex"; import * as i6 from "@angular/flex-layout/extended"; import * as i7 from "@angular/material/button"; import * as i8 from "@angular/material/dialog"; import * as i9 from "@angular/material/form-field"; import * as i10 from "@angular/material/input"; import * as i11 from "../../shared/directives/omit-chars.directive"; import * as i12 from "../../ui/generic-array-header/generic-array-header.component"; import * as i13 from "../../ui/loading-spinner/loading-spinner.component"; import * as i14 from "../generic-array/generic-array.component"; import * as i15 from "../generic-list/generic-list.component"; import * as i16 from "../generic-tree/generic-tree.component"; import * as i17 from "../search-bar/search-bar.component"; var EBrowseState; (function (EBrowseState) { EBrowseState["PREVIOUS"] = "previous"; EBrowseState["NEXT"] = "NEXT"; })(EBrowseState || (EBrowseState = {})); export class ConfirmDialogComponent { constructor(data, _interactionsService, _store$, _dataService, _errorHandlerService, _fb) { this.data = data; this._interactionsService = _interactionsService; this._store$ = _store$; this._dataService = _dataService; this._errorHandlerService = _errorHandlerService; this._fb = _fb; this.onDestroy$ = new Subject(); this.dataSource = new MatTableDataSource(); this.selectedElementsIdsForEdit = []; this.selectedNodesId = []; this.selectedElements = []; this.selectedElementsUiIds = []; this.isActiveSearch = false; this.isAssignAction = false; this.isTwoStepsAssignAction = false; this.isReassignAction = false; this.isRemovingAction = false; this.isEditingAction = false; this.isMovingNodeAction = false; this.stepNumber = 1; this.browseStates = EBrowseState; this.resourcesComponents = EResourceComponent; this.treeSelectMode = ETreeSelectMode; this.isMovingToAnotherEntry = false; this.action$ = new EventEmitter(); } ngOnInit() { this.selectedElementsUiIds = this.data.selectedElementsUiIds; this.isAssignAction = this.data.dialogAction === 'assign'; this.isTwoStepsAssignAction = this.isAssignAction && this.data.updateActionsParams.assign.isMultipleStepsAssign; this.isReassignAction = this.data.dialogAction === EEllipsisMenuActions.SINGLE_REASSIGN || this.data.dialogAction === EEllipsisMenuActions.MULTIPLE_REASSIGN; this.isRemovingAction = this.data.dialogAction === EEllipsisMenuActions.DELETE || this.data.dialogAction === EEllipsisMenuActions.DELETE_CHILD || this.data.dialogAction === EEllipsisMenuActions.DELETE_CHILDREN || this.data.dialogAction === EEllipsisMenuActions.SINGLE_DELETE || this.data.dialogAction === EEllipsisMenuActions.MULTIPLE_DELETE || this.data.dialogAction === EEllipsisMenuActions.SINGLE_UNASSIGN || this.data.dialogAction === EEllipsisMenuActions.MULTIPLE_UNASSIGN; this.isEditingAction = this.data.dialogAction === EEllipsisMenuActions.SINGLE_EDIT || this.data.dialogAction === EEllipsisMenuActions.MULTIPLE_EDIT; this.isMovingNodeAction = this.data.dialogAction === EEllipsisMenuActions.MOVE_NODE; if (this.isReassignAction || this.isTwoStepsAssignAction || this.isEditingAction) { this.selectedResourceTypeId = this._store$.selectSnapshot(DataState.getSelectedResourceTypeId); } if (this.isEditingAction || this.isTwoStepsAssignAction) { const allAttributesConfig = this._store$.selectSnapshot(ConfigsState.getConfigsById)[this.selectedResourceTypeId]?.attributes; this.attributeConfig = allAttributesConfig.find((attribute) => attribute.modelRef === this.data.attributeModelRef); } if (this.isReassignAction) { switch (this.data.updateActionsParams.reassign.resourceTypeComponent) { case EResourceComponent.TREE: this._interactionsService.displayedDataTree$ .pipe(takeUntil(this.onDestroy$), tap((dataTree) => { this.dataTree = [...dataTree]; this.flattenDataTree = getFlattenTree(this.dataTree); })) .subscribe(); break; case EResourceComponent.LIST: this._interactionsService.displayedDataList$ .pipe(takeUntil(this.onDestroy$), tap((dataList) => (this.dataList = [...dataList]))) .subscribe(); break; } } else if (this.isMovingNodeAction) { const selectedResourceTypeId = this._store$.selectSnapshot(DataState.getSelectedResourceTypeId); this.resourceTypeComponent = this._store$.selectSnapshot(ConfigsState.getConfigsById)[selectedResourceTypeId]?.component; this._interactionsService.displayedDataTree$ .pipe(takeUntil(this.onDestroy$), tap((dataTree) => { this.dataTree = [...dataTree]; this.flattenDataTree = getFlattenTree(this.dataTree); const triggerNode = this.flattenDataTree.find((node) => node.ids.id === this.data.triggerElementId); if (triggerNode) { this.isMovingToAnotherEntry = triggerNode.parentIds.id === 'root'; } })) .subscribe(); } else if (this.isAssignAction && this.data.updateActionsParams.assign.resourceTypeComponent === EResourceComponent.TREE) { const resourcesTypes = this._store$.selectSnapshot(ResourcesTypesState.getResourcesTypesJsTable); const configs = this._store$.selectSnapshot(ConfigsState.getConfigsJsTable); const treeRequestsDetails = getRequestsDetails(this.data.updateActionsParams.assign.requestedResourceTypeId, configs, resourcesTypes, this.data.updateActionsParams.assign.assignedResourceTypeId); this._interactionsService.isProcessingRequest(true); let areTreeRequestsIn404Error = false; forkJoin(treeRequestsDetails.map((treeRequestDetail) => { const responseAttributesIds = getResponseAttributesIds(configs.byId[treeRequestDetail.resourceTypeId], treeRequestDetail.resourceTypeId); return resourceRequest(null, treeRequestDetail, responseAttributesIds, this._dataService).pipe(map((response) => 'body' in response ? response.body : response), catchError((error) => { if (!areTreeRequestsIn404Error) { this._store$.dispatch([ new ErrorActions.SetErrorDetail({ error, userActionOnError: getUserActionOnResourceRequest(this.data.updateActionsParams.assign .resourceTypeComponent), }), new ErrorActions.IsHandlingError(true), ]); } areTreeRequestsIn404Error = !areTreeRequestsIn404Error && error instanceof HttpErrorResponse && error.status === 404; return this._errorHandlerService.handleError(error); })); })) .pipe(takeUntil(this.onDestroy$), filter((resources) => { this._interactionsService.isProcessingRequest(false); const oneRequestFailed = resources.some((resource) => resource instanceof Error || resource instanceof HttpErrorResponse); if (oneRequestFailed) { this._store$.dispatch(new Data.FetchResourcesError()); this.dataTreeAssignAction = []; } return !oneRequestFailed; }), defaultIfEmpty([]), tap((resources) => { const resourcesAsJsTable = toJsTable(resources.reduce((acc, curr, index) => ({ ...acc, [treeRequestsDetails[index].resourceTypeId]: { ...curr, Resources: curr.Resources.filter((data) => !this.data.displayedArrayRowsIds.includes(data.id)), }, }), {})); this.dataTreeAssignAction = cleanAssignDialogTree(buildTree(resourcesAsJsTable, configs, treeRequestsDetails), this.data.updateActionsParams.assign.assignedResourceTypeId); this.flattenDataTree = getFlattenTree(this.dataTreeAssignAction); })) .subscribe(); } else if (this.isEditingAction) { this.selectedElementsIdsForEdit = this.data.selectedElementsUiIds; this._setEditForm(); } } ngOnDestroy() { this.onDestroy$.next(); this.onDestroy$.complete(); } onSelectedNode(node) { this.selectedNode = node; } onSelectedItem(item) { this.selectedItem = item; if (this.isMovingNodeAction) { switch (this.resourceTypeComponent) { case EResourceComponent.TREE: this.selectedNode = getNodeById(this.selectedItem.ids.id, this.dataTree); break; default: break; } } } onSearch(event) { if (this.isMovingNodeAction) { this.dataList = event.map((node) => convertDataNodeToDataItem(node, 'link')); } else if (this.isAssignAction) { if (this.data.fieldForUpdate) { event.Resources?.forEach((data) => { data = { ...data, meta: { ...data.meta, isModifiable: data.meta.isModifiable && data.meta.modifiableAttributes.includes(this.data.fieldForUpdate), }, }; }); } const dataResourcesAsFlatArray = getDataSourceForGenericArray(event, this.data.assignArrayViewProperties.resourceTypeConfig, getClickableCellsEndpoints(this._store$.selectSnapshot(ResourcesTypesState.getResourcesTypesJsTable), this._store$.selectSnapshot(ConfigsState.getConfigsAllIds), this.data.assignArrayViewProperties.resourceTypeConfig), true); this.dataSource = new MatTableDataSource(dataResourcesAsFlatArray.filter((resource) => !this.data.displayedArrayRowsIds.includes(resource.id))); } } onResetSearch() { this.dataSource.data = []; this.dataList = []; } onActiveSearch(event) { this.isActiveSearch = event; } selectedData(data) { if (this.data.updateActionsParams.assign.resourceTypeComponent === EResourceComponent.TREE) { this.selectedElements = data; this.selectedNodesId = this.selectedElements .filter((element) => isDataNode(element)) .map((node) => node.ids.id); } else { this.selectedElements = data; this.selectedElementsUiIds = this.selectedElements.map((element) => element.selectionIds); } } getChildHeight() { if (!!this.genericList) { return this.genericList.elementRef.nativeElement.offsetHeight; } else if (!!(this.divArrayHeader && this.searchBar && this.divContentArray)) { return (this.divArrayHeader.nativeElement.offsetHeight + this.searchBar.elementRef.nativeElement.offsetHeight + this.divContentArray.nativeElement.offsetHeight); } else { return 0; } } submitAction() { this.action$.emit(); } _setEditForm() { this.editForm = this._fb.group(this.selectedElementsIdsForEdit.reduce((acc, ids) => { this.formErrors = { ...this.formErrors, [ids.id]: null }; return { ...acc, [ids.id]: new FormControl(this.data.mapSelectedElementIdEditableValue?.get(ids.id), this._getValidators(this.data.updateActionsParams.edit)), }; }, {})); } changeAssignStep(state) { if (state === EBrowseState.NEXT) { this.selectedElementsIdsForEdit = []; this.selectedElements.forEach((element) => { const ids = getElementIds(element); this.selectedElementsIdsForEdit.push(ids); if (!!this.editForm && !this.editForm.contains(ids.id)) { this.formErrors = { ...this.formErrors, [ids.id]: null }; this.editForm.addControl(ids.id, new FormControl(null, this._getValidators(this.data.updateActionsParams.edit))); } }); if (!!this.editForm) { const selectedElementsId = this.selectedElementsIdsForEdit.map((ids) => ids.id); Object.keys(this.editForm.controls).forEach((id) => { if (!selectedElementsId.includes(id)) { this.editForm.removeControl(id); delete this.formErrors[id]; } }); } else { this._setEditForm(); } this.stepNumber++; } else if (state === EBrowseState.PREVIOUS) { this.stepNumber--; if (this.isMovingNodeAction) { this.isMovingToAnotherEntry = false; this.dataList = []; } } } _getValidators(editParams) { let validators = [Validators.required]; if (editParams.props.isInteger) { validators.push(Validators.compose([ Validators.min(editParams.props.min), CustomValidators.validIntegerCharacters(), ])); } return validators; } checkFormValue(fieldId) { this.formErrors[fieldId] = getFormFieldError(this.editForm.get(fieldId), this.attributeConfig); } moveToRoot() { this.selectedNode = null; this.action$.emit(); } moveToAnotherEntry() { this.stepNumber++; this.isMovingToAnotherEntry = true; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ConfirmDialogComponent, deps: [{ token: MAT_DIALOG_DATA }, { token: i1.InteractionsService }, { token: i2.Store }, { token: i1.DataService }, { token: i1.ErrorsHandlerService }, { token: i3.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.4", type: ConfirmDialogComponent, selector: "dm-confirm-dialog", outputs: { action$: "action$" }, viewQueries: [{ propertyName: "searchBar", first: true, predicate: ["searchBar"], descendants: true }, { propertyName: "divArrayHeader", first: true, predicate: ["divArrayHeader"], descendants: true }, { propertyName: "divContentArray", first: true, predicate: ["divContentArray"], descendants: true }, { propertyName: "genericList", first: true, predicate: ["genericList"], descendants: true }, { propertyName: "assignTree", first: true, predicate: ["assignTree"], descendants: true }], ngImport: i0, template: "<!-- Copyright (C) 2020-2024 Linagora\n\nThis program is free software: you can redistribute it and/or modify it under\nthe terms of the GNU Affero General Public License as published by the Free\nSoftware Foundation, either version 3 of the License, or (at your option) any\nlater version, provided you comply with the Additional Terms applicable for\nLinID Directory Manager software by LINAGORA pursuant to Section 7 of the GNU\nAffero General Public License, subsections (b), (c), and (e), pursuant to\nwhich these Appropriate Legal Notices must notably (i) retain the display of\nthe \"LinID\u2122\" trademark/logo at the top of the interface window, the display\nof the \u201CYou are using the Open Source and free version of LinID\u2122, powered by\nLinagora \u00A9 2009\u20132013. Contribute to LinID R&D by subscribing to an Enterprise\noffer!\u201D infobox and in the e-mails sent with the Program, notice appended to\nany type of outbound messages (e.g. e-mail and meeting requests) as well as\nin the LinID Directory Manager user interface, (ii) retain all hypertext\nlinks between LinID Directory Manager and https://linid.org/, as well as\nbetween LINAGORA and LINAGORA.com, and (iii) refrain from infringing LINAGORA\nintellectual property rights over its trademarks and commercial brands. Other\nAdditional Terms apply, see <http://www.linagora.com/licenses/> for more\ndetails.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT\nANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\nFOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more\ndetails.\n\nYou should have received a copy of the GNU Affero General Public License and\nits applicable Additional Terms for LinID Directory Manager along with this\nprogram. If not, see <http://www.gnu.org/licenses/> for the GNU Affero\nGeneral Public License version 3 and <http://www.linagora.com/licenses/> for\nthe Additional Terms applicable to the LinID Directory Manager software. -->\n\n<h3 mat-dialog-title [innerHTML]=\"data.title\" class=\"title\"></h3>\n<mat-dialog-content class=\"mat-dialog-content\">\n <div\n *ngIf=\"\n !isEditingAction &&\n !isMovingNodeAction &&\n !(isAssignAction && dataSource?.data?.length > 0)\n \"\n class=\"div-selected-elements\"\n >\n <span *ngFor=\"let element of selectedElementsUiIds; let i = index\">\n <span *ngIf=\"i < 10\">\n <span\n *ngIf=\"\n i < 9 && i < selectedElementsUiIds?.length - 1;\n else lastElement\n \"\n >\n {{ element.label }},\n </span>\n <ng-template #lastElement>{{ element.label }}</ng-template>\n </span>\n </span>\n <span *ngIf=\"selectedElementsUiIds?.length > 10\">\n {{ '... (+' + (selectedElementsUiIds.length - 10) + ')' }}\n </span>\n </div>\n <ng-container *ngIf=\"isReassignAction\">\n <ng-container\n *ngIf=\"\n data.updateActionsParams.reassign.resourceTypeComponent ===\n resourcesComponents.TREE;\n else genericListTemplate\n \"\n >\n <div class=\"div-content-tree\">\n <dm-generic-tree\n [isSelectOnlyModeEnabled]=\"true\"\n [selectMode]=\"treeSelectMode.SINGLE\"\n [selectedNodeId]=\"selectedEntryId$ | async\"\n [selectedResourceTypeId]=\"selectedResourceTypeId\"\n [flattenInitialDataTree]=\"flattenDataTree\"\n [initialDataTree]=\"dataTree\"\n (selectedNode)=\"onSelectedNode($event)\"\n ></dm-generic-tree>\n </div>\n </ng-container>\n <ng-template #genericListTemplate>\n <div class=\"div-content-list\">\n <dm-generic-list\n [isSelectOnlyModeEnabled]=\"true\"\n [initialDataList]=\"dataList\"\n [selectedItemId]=\"selectedEntryId$ | async\"\n (selectedItem)=\"onSelectedItem($event)\"\n #genericList\n ></dm-generic-list>\n </div>\n </ng-template>\n </ng-container>\n <ng-container *ngIf=\"isAssignAction && stepNumber === 1\">\n <ng-container\n *ngIf=\"\n data.updateActionsParams.assign.resourceTypeComponent ===\n resourcesComponents.ARRAY;\n else genericTreeTemplate\n \"\n ><div\n [ngClass]=\"{\n 'div-assign-search-bar':\n selectedElementsUiIds?.length > 0 && dataSource?.data?.length === 0\n }\"\n >\n <dm-search-bar\n [endpoint]=\"data.endpoint\"\n [placeholder]=\"data.placeholder\"\n [config]=\"data.assignArrayViewProperties.resourceTypeConfig\"\n [searchRequestAttributes]=\"data.assignedElementsAttributes\"\n [extendedMeta]=\"data.fieldForUpdate != null\"\n (searchResult)=\"onSearch($event)\"\n (resetSearch)=\"onResetSearch()\"\n (isActiveSearch)=\"onActiveSearch($event)\"\n #searchBar\n ></dm-search-bar>\n </div>\n\n <ng-container *ngIf=\"isActiveSearch && !searchBar.isFetchingResources\">\n <div\n *ngIf=\"dataSource?.data?.length === 0; else displayArray\"\n fxLayout=\"row\"\n fxLayoutAlign=\"center start\"\n >\n <span class=\"no-search-result\">{{ data.noSearchResult }}</span>\n </div>\n <ng-template #displayArray>\n <div\n *ngIf=\"dataSource?.data?.length > 0\"\n class=\"div-generic-array-header\"\n #divArrayHeader\n >\n <dm-generic-array-header\n [dataLength]=\"dataSource.data.length\"\n [dataIcon]=\"data.assignArrayViewProperties.icon\"\n [dataName]=\"data.assignArrayViewProperties.name\"\n ></dm-generic-array-header>\n </div>\n <div class=\"div-content-array\" #divContentArray>\n <div *ngIf=\"dataSource?.data?.length > 0\" class=\"div-generic-array\">\n <dm-generic-array\n [isSelectOnlyModeEnabled]=\"true\"\n [endpoint]=\"data.endpoint\"\n [columns]=\"data.assignArrayViewProperties.columns\"\n [accessibility]=\"data.assignArrayViewProperties.accessibility\"\n [initialDisplayedColumns]=\"\n data.assignArrayViewProperties.displayedColumns\n \"\n [selectedElementsUiIds]=\"selectedElementsUiIds\"\n [isAttributeArray]=\"true\"\n [updateAffectAnotherResourceType]=\"\n data.updateActionsParams.updateAffectAnotherResourceType\n \"\n [fieldForUpdate]=\"data.fieldForUpdate\"\n [dataSource]=\"dataSource\"\n [actions]=\"{\n assign: {\n noFilterResult:\n data.assignArrayViewProperties.noFilterResult\n }\n }\"\n (selectedData)=\"selectedData($event)\"\n ></dm-generic-array>\n </div>\n </div>\n </ng-template>\n </ng-container>\n </ng-container>\n <ng-template #genericTreeTemplate>\n <div class=\"div-content-tree\">\n <dm-generic-tree\n *ngIf=\"dataTreeAssignAction; else loadingSpinner\"\n [isSelectOnlyModeEnabled]=\"true\"\n [selectMode]=\"treeSelectMode.MULTIPLE\"\n [selectedResourceTypeId]=\"\n data.updateActionsParams?.assign?.assignedResourceTypeId\n \"\n [selectedNodesId]=\"selectedNodesId\"\n [flattenInitialDataTree]=\"flattenDataTree\"\n [initialDataTree]=\"dataTreeAssignAction\"\n (selectedNodes)=\"selectedData($event)\"\n #assignTree\n ></dm-generic-tree>\n </div>\n <ng-template #loadingSpinner>\n <div class=\"div-loading-spinner\">\n <dm-loading-spinner></dm-loading-spinner>\n </div>\n </ng-template>\n </ng-template>\n </ng-container>\n <ng-container\n *ngIf=\"isEditingAction || (isTwoStepsAssignAction && stepNumber === 2)\"\n >\n <form [formGroup]=\"editForm\" (keydown.tab)=\"$event.stopPropagation()\">\n <div\n *ngFor=\"let selectedElementIds of selectedElementsIdsForEdit\"\n fxLayout=\"row\"\n fxLayoutAlign=\"center center\"\n [ngStyle.gt-xs]=\"{ 'padding-bottom.px': 4 }\"\n [ngStyle.xs]=\"{ 'padding-bottom.px': 2 }\"\n class=\"div-form-field\"\n >\n <span fxFlex class=\"edited-entry-id ellipsis\">{{\n selectedElementIds.label\n }}</span>\n <mat-form-field fxFlex color=\"accent\" class=\"custom-form-field\">\n <mat-label fxLayout=\"row\">\n {{ data.updateActionsParams.edit.props.label }}\n </mat-label>\n <input\n matInput\n appOmitChars\n [formControlName]=\"selectedElementIds.id\"\n [type]=\"data.updateActionsParams.edit.props.type\"\n [min]=\"data.updateActionsParams.edit.props.min\"\n [invalidChars]=\"\n data.updateActionsParams.edit.props.invalidCharacters\n \"\n (ngModelChange)=\"checkFormValue(selectedElementIds.id)\"\n class=\"ellipsis\"\n />\n <mat-error>{{ formErrors[selectedElementIds.id] }}</mat-error>\n </mat-form-field>\n </div>\n </form>\n </ng-container>\n <ng-container *ngIf=\"isMovingNodeAction\">\n <ng-template #moveMenu>\n <div fxLayout=\"column\">\n <button\n mat-button\n color=\"accent\"\n (click)=\"moveToRoot()\"\n class=\"move-node-menu-btn\"\n >\n {{ data.moveToRootButtonText }}\n </button>\n <button\n mat-button\n color=\"accent\"\n (click)=\"moveToAnotherEntry()\"\n class=\"move-node-menu-btn\"\n >\n {{ data.moveToAnotherEntryButtonText }}\n </button>\n </div>\n </ng-template>\n <ng-container *ngIf=\"isMovingToAnotherEntry; else moveMenu\">\n <dm-search-bar\n [placeholder]=\"data.placeholder\"\n [isLocalSearchModeEnabled]=\"true\"\n [dataToFilter]=\"dataTree\"\n [triggerElementId]=\"data.triggerElementId\"\n [resourceTypeComponent]=\"resourceTypeComponent\"\n (searchResult)=\"onSearch($event)\"\n (resetSearch)=\"onResetSearch()\"\n (isActiveSearch)=\"onActiveSearch($event)\"\n ></dm-search-bar>\n <div\n *ngIf=\"isActiveSearch && dataList?.length === 0; else displayList\"\n fxLayout=\"row\"\n fxLayoutAlign=\"center start\"\n >\n <span class=\"no-search-result\">{{ data.noSearchResult }}</span>\n </div>\n <ng-template #displayList>\n <div class=\"div-content-list\">\n <dm-generic-list\n [isSelectOnlyModeEnabled]=\"true\"\n [initialDataList]=\"dataList\"\n (selectedItem)=\"onSelectedItem($event)\"\n #genericList\n ></dm-generic-list>\n </div>\n </ng-template>\n </ng-container>\n </ng-container>\n</mat-dialog-content>\n<mat-dialog-actions\n *ngIf=\"!isMovingNodeAction || isMovingToAnotherEntry\"\n [ngStyle]=\"\n (isTwoStepsAssignAction || isMovingNodeAction) && stepNumber > 1\n ? { 'justify-content': 'space-between' }\n : { 'justify-content': 'flex-end' }\n \"\n>\n <button\n *ngIf=\"(isTwoStepsAssignAction || isMovingNodeAction) && stepNumber > 1\"\n mat-raised-button\n class=\"assign-edit-unassign-move-action-confirm-btn\"\n (click)=\"changeAssignStep(browseStates.PREVIOUS)\"\n >\n {{ data.previousStepButtonText }}\n </button>\n <div>\n <button\n cdkFocusInitial\n mat-button\n color=\"accent\"\n [mat-dialog-close]=\"false\"\n class=\"btn-close-confirm-dialog\"\n >\n {{ data.cancelButtonText }}\n </button>\n <button\n *ngIf=\"\n isTwoStepsAssignAction &&\n stepNumber < data.updateActionsParams.assign.nbSteps;\n else confirmBtn\n \"\n mat-raised-button\n [disabled]=\"selectedElements.length === 0\"\n (click)=\"changeAssignStep(browseStates.NEXT)\"\n class=\"assign-edit-unassign-move-action-confirm-btn\"\n >\n {{ data.nextStepButtonText }}\n </button>\n <ng-template #confirmBtn>\n <button\n mat-raised-button\n [disabled]=\"\n ((isReassignAction || isMovingNodeAction) &&\n !selectedNode &&\n !selectedItem) ||\n (isAssignAction && selectedElements.length === 0) ||\n ((isTwoStepsAssignAction || isEditingAction) &&\n (editForm.pristine || !editForm.valid))\n \"\n [ngClass]=\"\n isRemovingAction\n ? 'delete-action-confirm-btn'\n : 'assign-edit-unassign-move-action-confirm-btn'\n \"\n (click)=\"submitAction()\"\n >\n {{ data.confirmButtonText }}\n </button>\n </ng-template>\n </div>\n</mat-dialog-actions>\n", styles: ["@charset \"UTF-8\";.title{font-weight:700}.div-generic-array-header{padding:8px 0}.mdc-dialog__content{display:flex;flex-direction:column}.div-generic-array{height:100%}.div-content-array,.div-content-tree,.div-content-list{margin-bottom:20px}.div-content-list{overflow-y:auto}.no-search-result{color:#0003;font-size:20px;padding:20px 0}.btn-close-confirm-dialog{margin-right:8px}.div-loading-spinner{height:64px}.edited-entry-id{text-align:center}.move-node-menu-btn{margin-bottom:20px}.div-assign-search-bar{margin-top:10px}.div-selected-elements{overflow:hidden;text-overflow:ellipsis}\n"], dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i5.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i5.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { kind: "directive", type: i5.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i6.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "directive", type: i6.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { kind: "component", type: i7.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: i8.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i8.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i8.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i8.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "component", type: i9.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i9.MatLabel, selector: "mat-label" }, { kind: "directive", type: i9.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i10.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: i11.OmitCharsDirective, selector: "[appOmitChars]", inputs: ["invalidChars", "validChars", "regexString"] }, { kind: "component", type: i12.GenericArrayHeaderComponent, selector: "dm-generic-array-header", inputs: ["dataLength", "dataIcon", "dataName"] }, { kind: "component", type: i13.LoadingSpinnerComponent, selector: "dm-loading-spinner" }, { kind: "component", type: i14.GenericArrayComponent, selector: "dm-generic-array", inputs: ["isClickableRow", "isSelectOnlyModeEnabled", "selectedElementsUiIds", "dataSource", "columns", "initialDisplayedColumns", "processingRequest$", "actions", "resourcesTypesProperties", "configs", "accessibility", "endpoint", "canAssignOrMoveEntries", "selectedResourceRootTypeId", "isAttributeArray", "updateAffectAnotherResourceType", "fieldForUpdate", "isEditableArray", "selectionColumnId", "actionsColumnTemplate"], outputs: ["selectedData"] }, { kind: "component", type: i15.GenericListComponent, selector: "dm-generic-list", inputs: ["selectedItemId", "initialDataList", "search", "isSelectOnlyModeEnabled", "isLargeScreen", "actionsMenuTemplate"], outputs: ["selectedItem"] }, { kind: "component", type: i16.GenericTreeComponent, selector: "dm-generic-tree", inputs: ["viewportHeight", "allNodesIdsNames", "selectedNodeId", "flattenInitialDataTree", "initialDataTree", "search", "expandedTreeNodesUuids", "actions", "selectedResourceRootTypeId", "selectedResourceTypeId", "isSelectOnlyModeEnabled", "isAdvancedSearchActivated", "selectMode", "refresh", "nodesIdsMatchingAdvancedSearch", "advancedSearch", "isLargeScreen", "selectedNodesId", "isFilteringOnExternalId", "isScrollDisable", "actionsMenuTemplate"], outputs: ["widthUpdated", "selectedNode", "selectedNodes"] }, { kind: "component", type: i17.SearchBarComponent, selector: "dm-search-bar", inputs: ["placeholder", "triggerElementId", "config", "endpoint", "searchRequestAttributes", "extendedMeta", "isLocalSearchModeEnabled", "dataToFilter", "resourceTypeComponent"], outputs: ["searchResult", "resetSearch", "isActiveSearch"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }] }); } } __decorate([ Select(DataState.getSelectedEntryId) ], ConfirmDialogComponent.prototype, "selectedEntryId$", void 0); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ConfirmDialogComponent, decorators: [{ type: Component, args: [{ selector: 'dm-confirm-dialog', template: "<!-- Copyright (C) 2020-2024 Linagora\n\nThis program is free software: you can redistribute it and/or modify it under\nthe terms of the GNU Affero General Public License as published by the Free\nSoftware Foundation, either version 3 of the License, or (at your option) any\nlater version, provided you comply with the Additional Terms applicable for\nLinID Directory Manager software by LINAGORA pursuant to Section 7 of the GNU\nAffero General Public License, subsections (b), (c), and (e), pursuant to\nwhich these Appropriate Legal Notices must notably (i) retain the display of\nthe \"LinID\u2122\" trademark/logo at the top of the interface window, the display\nof the \u201CYou are using the Open Source and free version of LinID\u2122, powered by\nLinagora \u00A9 2009\u20132013. Contribute to LinID R&D by subscribing to an Enterprise\noffer!\u201D infobox and in the e-mails sent with the Program, notice appended to\nany type of outbound messages (e.g. e-mail and meeting requests) as well as\nin the LinID Directory Manager user interface, (ii) retain all hypertext\nlinks between LinID Directory Manager and https://linid.org/, as well as\nbetween LINAGORA and LINAGORA.com, and (iii) refrain from infringing LINAGORA\nintellectual property rights over its trademarks and commercial brands. Other\nAdditional Terms apply, see <http://www.linagora.com/licenses/> for more\ndetails.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT\nANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\nFOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more\ndetails.\n\nYou should have received a copy of the GNU Affero General Public License and\nits applicable Additional Terms for LinID Directory Manager along with this\nprogram. If not, see <http://www.gnu.org/licenses/> for the GNU Affero\nGeneral Public License version 3 and <http://www.linagora.com/licenses/> for\nthe Additional Terms applicable to the LinID Directory Manager software. -->\n\n<h3 mat-dialog-title [innerHTML]=\"data.title\" class=\"title\"></h3>\n<mat-dialog-content class=\"mat-dialog-content\">\n <div\n *ngIf=\"\n !isEditingAction &&\n !isMovingNodeAction &&\n !(isAssignAction && dataSource?.data?.length > 0)\n \"\n class=\"div-selected-elements\"\n >\n <span *ngFor=\"let element of selectedElementsUiIds; let i = index\">\n <span *ngIf=\"i < 10\">\n <span\n *ngIf=\"\n i < 9 && i < selectedElementsUiIds?.length - 1;\n else lastElement\n \"\n >\n {{ element.label }},\n </span>\n <ng-template #lastElement>{{ element.label }}</ng-template>\n </span>\n </span>\n <span *ngIf=\"selectedElementsUiIds?.length > 10\">\n {{ '... (+' + (selectedElementsUiIds.length - 10) + ')' }}\n </span>\n </div>\n <ng-container *ngIf=\"isReassignAction\">\n <ng-container\n *ngIf=\"\n data.updateActionsParams.reassign.resourceTypeComponent ===\n resourcesComponents.TREE;\n else genericListTemplate\n \"\n >\n <div class=\"div-content-tree\">\n <dm-generic-tree\n [isSelectOnlyModeEnabled]=\"true\"\n [selectMode]=\"treeSelectMode.SINGLE\"\n [selectedNodeId]=\"selectedEntryId$ | async\"\n [selectedResourceTypeId]=\"selectedResourceTypeId\"\n [flattenInitialDataTree]=\"flattenDataTree\"\n [initialDataTree]=\"dataTree\"\n (selectedNode)=\"onSelectedNode($event)\"\n ></dm-generic-tree>\n </div>\n </ng-container>\n <ng-template #genericListTemplate>\n <div class=\"div-content-list\">\n <dm-generic-list\n [isSelectOnlyModeEnabled]=\"true\"\n [initialDataList]=\"dataList\"\n [selectedItemId]=\"selectedEntryId$ | async\"\n (selectedItem)=\"onSelectedItem($event)\"\n #genericList\n ></dm-generic-list>\n </div>\n </ng-template>\n </ng-container>\n <ng-container *ngIf=\"isAssignAction && stepNumber === 1\">\n <ng-container\n *ngIf=\"\n data.updateActionsParams.assign.resourceTypeComponent ===\n resourcesComponents.ARRAY;\n else genericTreeTemplate\n \"\n ><div\n [ngClass]=\"{\n 'div-assign-search-bar':\n selectedElementsUiIds?.length > 0 && dataSource?.data?.length === 0\n }\"\n >\n <dm-search-bar\n [endpoint]=\"data.endpoint\"\n [placeholder]=\"data.placeholder\"\n [config]=\"data.assignArrayViewProperties.resourceTypeConfig\"\n [searchRequestAttributes]=\"data.assignedElementsAttributes\"\n [extendedMeta]=\"data.fieldForUpdate != null\"\n (searchResult)=\"onSearch($event)\"\n (resetSearch)=\"onResetSearch()\"\n (isActiveSearch)=\"onActiveSearch($event)\"\n #searchBar\n ></dm-search-bar>\n </div>\n\n <ng-container *ngIf=\"isActiveSearch && !searchBar.isFetchingResources\">\n <div\n *ngIf=\"dataSource?.data?.length === 0; else displayArray\"\n fxLayout=\"row\"\n fxLayoutAlign=\"center start\"\n >\n <span class=\"no-search-result\">{{ data.noSearchResult }}</span>\n </div>\n <ng-template #displayArray>\n <div\n *ngIf=\"dataSource?.data?.length > 0\"\n class=\"div-generic-array-header\"\n #divArrayHeader\n >\n <dm-generic-array-header\n [dataLength]=\"dataSource.data.length\"\n [dataIcon]=\"data.assignArrayViewProperties.icon\"\n [dataName]=\"data.assignArrayViewProperties.name\"\n ></dm-generic-array-header>\n </div>\n <div class=\"div-content-array\" #divContentArray>\n <div *ngIf=\"dataSource?.data?.length > 0\" class=\"div-generic-array\">\n <dm-generic-array\n [isSelectOnlyModeEnabled]=\"true\"\n [endpoint]=\"data.endpoint\"\n [columns]=\"data.assignArrayViewProperties.columns\"\n [accessibility]=\"data.assignArrayViewProperties.accessibility\"\n [initialDisplayedColumns]=\"\n data.assignArrayViewProperties.displayedColumns\n \"\n [selectedElementsUiIds]=\"selectedElementsUiIds\"\n [isAttributeArray]=\"true\"\n [updateAffectAnotherResourceType]=\"\n data.updateActionsParams.updateAffectAnotherResourceType\n \"\n [fieldForUpdate]=\"data.fieldForUpdate\"\n [dataSource]=\"dataSource\"\n [actions]=\"{\n assign: {\n noFilterResult:\n data.assignArrayViewProperties.noFilterResult\n }\n }\"\n (selectedData)=\"selectedData($event)\"\n ></dm-generic-array>\n </div>\n </div>\n </ng-template>\n </ng-container>\n </ng-container>\n <ng-template #genericTreeTemplate>\n <div class=\"div-content-tree\">\n <dm-generic-tree\n *ngIf=\"dataTreeAssignAction; else loadingSpinner\"\n [isSelectOnlyModeEnabled]=\"true\"\n [selectMode]=\"treeSelectMode.MULTIPLE\"\n [selectedResourceTypeId]=\"\n data.updateActionsParams?.assign?.assignedResourceTypeId\n \"\n [selectedNodesId]=\"selectedNodesId\"\n [flattenInitialDataTree]=\"flattenDataTree\"\n [initialDataTree]=\"dataTreeAssignAction\"\n (selectedNodes)=\"selectedData($event)\"\n #assignTree\n ></dm-generic-tree>\n </div>\n <ng-template #loadingSpinner>\n <div class=\"div-loading-spinner\">\n <dm-loading-spinner></dm-loading-spinner>\n </div>\n </ng-template>\n </ng-template>\n </ng-container>\n <ng-container\n *ngIf=\"isEditingAction || (isTwoStepsAssignAction && stepNumber === 2)\"\n >\n <form [formGroup]=\"editForm\" (keydown.tab)=\"$event.stopPropagation()\">\n <div\n *ngFor=\"let selectedElementIds of selectedElementsIdsForEdit\"\n fxLayout=\"row\"\n fxLayoutAlign=\"center center\"\n [ngStyle.gt-xs]=\"{ 'padding-bottom.px': 4 }\"\n [ngStyle.xs]=\"{ 'padding-bottom.px': 2 }\"\n class=\"div-form-field\"\n >\n <span fxFlex class=\"edited-entry-id ellipsis\">{{\n selectedElementIds.label\n }}</span>\n <mat-form-field fxFlex color=\"accent\" class=\"custom-form-field\">\n <mat-label fxLayout=\"row\">\n {{ data.updateActionsParams.edit.props.label }}\n </mat-label>\n <input\n matInput\n appOmitChars\n [formControlName]=\"selectedElementIds.id\"\n [type]=\"data.updateActionsParams.edit.props.type\"\n [min]=\"data.updateActionsParams.edit.props.min\"\n [invalidChars]=\"\n data.updateActionsParams.edit.props.invalidCharacters\n