@linid-dm/directory-manager-client-core
Version:
Core package by providing a set of angular components for the Directory Manager app.
492 lines • 143 kB
JavaScript
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 { trigger } from '@angular/animations';
import { HttpErrorResponse } from '@angular/common/http';
import { Component, EventEmitter, Input, Output, ViewChild, } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';
import { Select } from '@ngxs/store';
import { Subject, catchError, concatMap, delay, filter, forkJoin, of, take, takeUntil, tap, throwError, } from 'rxjs';
import { DisplayedDetailArray, EComponentName, EUIComponent, EUpdateOperations, EUserAction, Error as ErrorActions, UiState, convertDataNodeToDataSourceRow, convertDataSourceRowToLinkObject, fadeIn, getActionType, getArrayAttributeDoingRequestsDetail, getArrayAttributeResourcesTypesIds, getAttributeValues, getClickableCellsEndpoints, getDataSourceArrayUsingDataFromBackend, getDataSourceForGenericArray, getDataSourceRowsWithAssociatedValue, getElementExternalId, getElementId, getNotSelectedRows, getOrderedKeysArrayAttributes, getRowId, getSelectedElements, getSucceededNotifications, isDataNode, setRequestsProperties, toScimPropertiesPatch, } from '../../shared';
import { ConfirmDialogComponent } from '../confirm-dialog/confirm-dialog.component';
import * as i0 from "@angular/core";
import * as i1 from "@ngxs/store";
import * as i2 from "@angular/router";
import * as i3 from "@angular/material/dialog";
import * as i4 from "../../shared";
import * as i5 from "@angular/common";
import * as i6 from "@angular/flex-layout/flex";
import * as i7 from "@angular/material/button";
import * as i8 from "@angular/material/icon";
import * as i9 from "@angular/material/tabs";
import * as i10 from "../../ui/generic-array-header/generic-array-header.component";
import * as i11 from "../ellipsis-menu/ellipsis-menu.component";
import * as i12 from "../generic-array/generic-array.component";
export class DataDetailArrayAttributesComponent {
set selectedEntryIds(selectedEntryIds) {
this._selectedEntryIds = selectedEntryIds;
this._requestsSubscription?.unsubscribe();
this.allAttributesDisplayedAsArray = [];
}
get selectedEntryIds() {
return this._selectedEntryIds;
}
set selectedResourceTypeId(selectedResourceTypeId) {
if (selectedResourceTypeId) {
this._selectedResourceTypeId = selectedResourceTypeId;
this._arrayAttributesConfig = this.configs.byId[this._selectedResourceTypeId].attributes.filter((attribute) => attribute.value.field.componentName === EComponentName.array);
}
}
get selectedResourceTypeId() {
return this._selectedResourceTypeId;
}
set dataDetail(dataDetail) {
this._dataDetail = dataDetail;
if (this._dataDetail) {
const config = this.configs.byId[this._selectedResourceTypeId];
this._addMandatoryArrays(config);
const orderKeysByAttributeId = getOrderedKeysArrayAttributes(this._arrayAttributesConfig, this._dataDetail);
const attributesDoingRequests = [];
this.allAttributesDisplayedAsArray = [];
this.canAssignOrMoveAuthorizedTypes = this.currentUser.canAssignOrMove;
const editableArrayProperties = {
selectedEntryExternalId: this.selectedEntryIds.externalId,
selectedEntryParentExternalId: !!this.selectedEntryParentIds
? this.selectedEntryParentIds.externalId
: null,
};
orderKeysByAttributeId.forEach((key) => {
// Get current attribute configuration
const attributeConfig = config.attributes.find((attribute) => attribute.modelRef === key);
const attributeComponentName = attributeConfig.value.field.componentName;
if (attributeComponentName === EComponentName.array) {
let allRequestsResourcesTypesIds = getArrayAttributeResourcesTypesIds(attributeConfig);
let attributeDoingRequestsDetails = getArrayAttributeDoingRequestsDetail(attributeConfig, this._dataDetail[key]);
let dataResources;
if (this._dataDetail[key].length > 0 &&
attributeConfig.props.isUsingDataFromBackend) {
dataResources = getDataSourceArrayUsingDataFromBackend(this._dataDetail[key], attributeConfig.value.field.props.columns.map((column) => column.id), allRequestsResourcesTypesIds, this.resourcesTypes, attributeConfig.value.field.props.keyForSquash);
}
if (attributeConfig.props.isUsingDataFromBackend ||
this.hasLoadedArray === false) {
this.allAttributesDisplayedAsArray.push(new DisplayedDetailArray(this._selectedResourceTypeId, this.configs, attributeDoingRequestsDetails, allRequestsResourcesTypesIds, dataResources, editableArrayProperties, this._dataDetail.meta.modifiableAttributes.includes(key)));
}
else if (allRequestsResourcesTypesIds.length > 0 &&
allRequestsResourcesTypesIds.every((resourceTypeId) => this.resourcesTypes.allIds.includes(resourceTypeId))) {
attributesDoingRequests.push(attributeDoingRequestsDetails);
}
}
});
if (attributesDoingRequests.length > 0) {
this._requestForArrayAttributes(attributesDoingRequests, editableArrayProperties);
}
else {
this.evtArrayAttributesProcessed.emit(true);
}
}
}
get dataDetail() {
return this._dataDetail;
}
constructor(_store$, _router, _dialog, _dataService, _interactionsService, _errorsHandlerService) {
this._store$ = _store$;
this._router = _router;
this._dialog = _dialog;
this._dataService = _dataService;
this._interactionsService = _interactionsService;
this._errorsHandlerService = _errorsHandlerService;
this._onDestroy$ = new Subject();
this.uiComponent = EUIComponent.DATA_DETAIL;
this.allAttributesDisplayedAsArray = [];
this.updateOperations = EUpdateOperations;
this.clickOnAssign = false;
this.evtArrayAttributesProcessed = new EventEmitter();
this.evtSuccess = new EventEmitter();
}
ngOnInit() {
this._interactionsService.processingRequest$
.pipe(takeUntil(this._onDestroy$), tap((isProcessingRequest) => (this.isProcessingRequest = isProcessingRequest)))
.subscribe();
}
ngOnDestroy() {
this._onDestroy$.next();
this._onDestroy$.complete();
}
openAssignDialog(title, placeholder, noSearchResult, cancelButtonText, confirmButtonText, previousStepButtonText, nextStepButtonText, action, endpoint, assignArrayViewProperties, displayedArrayRowsIds, displayedArray, attributeModelRef, assignedElementsAttributes, updateActionsParams, fieldForUpdate) {
const dialogRef = this._dialog.open(ConfirmDialogComponent, {
restoreFocus: false,
minWidth: '500px',
panelClass: 'confirm-dialog-container',
data: {
selectedElements: [],
title,
placeholder,
noSearchResult,
cancelButtonText,
confirmButtonText,
previousStepButtonText,
nextStepButtonText,
dialogAction: action,
endpoint,
assignArrayViewProperties,
displayedArrayRowsIds,
assignedElementsAttributes,
updateActionsParams,
attributeModelRef,
fieldForUpdate,
},
});
dialogRef
.afterClosed()
.pipe(tap(() => {
this.clickOnAssign = false;
}), delay(0), tap((_) => this.assignBtn.focus()))
.subscribe();
dialogRef.componentInstance.action$
.pipe(tap(() => {
const selectedElements = {
selectedElements: dialogRef.componentInstance.selectedElements,
formValues: dialogRef.componentInstance.editForm?.getRawValue(),
};
this.onUpdateArray(selectedElements, [EUpdateOperations.ADD], displayedArray, dialogRef);
}))
.subscribe();
}
assignNewElements(displayedArray) {
this.clickOnAssign = true;
this.openAssignDialog(displayedArray.actions.assign.title, displayedArray.actions.assign.placeholder, displayedArray.actions.assign.noSearchResult, displayedArray.actions.assign.dialogCancelBtn, displayedArray.actions.assign.dialogConfirmBtn, displayedArray.actions.assign.dialogPreviousStepBtn, displayedArray.actions.assign.dialogNextStepBtn, 'assign', displayedArray.endpoint, {
columns: displayedArray.viewProperties.getColumns(),
displayedColumns: displayedArray.viewProperties.getDisplayedColumns(),
name: displayedArray.typesLabels,
icon: displayedArray.icon,
resourceTypeConfig: displayedArray.resourceTypeConfig,
accessibility: displayedArray.viewProperties.getAccessibility(),
noFilterResult: displayedArray.actions.assign.noFilterResult,
}, displayedArray.viewProperties
.getDataSource()
.data.map((row) => row.selectionIds.id), displayedArray, displayedArray.attributeId, displayedArray.viewProperties.getDisplayedColumns(), displayedArray.updateParams, displayedArray.fieldForUpdate);
}
patchArrayAttribute(event, operationsTypes, displayedArray, dialogRef) {
displayedArray.succeededElements = [];
const selectedElements = getSelectedElements(event);
const selectedElementsIds = selectedElements.map((selectedElement) => getElementId(selectedElement));
if (operationsTypes.length > 0) {
of(...operationsTypes)
.pipe(take(operationsTypes.length), takeUntil(this._onDestroy$), concatMap((operationType) => this._patchOperationRequest(operationType, selectedElementsIds, selectedElements, event, displayedArray, operationsTypes, dialogRef)), catchError((err) => this._errorsHandlerService.handleError(err)), filter((_, index) => index === operationsTypes.length - 1), tap((_) => this.updateListAfterOperationsOnArray(operationsTypes, displayedArray)))
.subscribe();
}
}
updateArrayAttribute(event, operationsTypes, displayedArray, dialogRef) {
displayedArray.succeededElements = [];
const fieldToUpdate = displayedArray.attributeId;
let selectedElements = getSelectedElements(event);
const selectedElementsIds = selectedElements.map((selectedElement) => getElementId(selectedElement));
let newValue;
if (operationsTypes.length === 1) {
const notSeletedElements = getNotSelectedRows(displayedArray.viewProperties.getDataSource().data, selectedElementsIds);
switch (operationsTypes[0]) {
case EUpdateOperations.REMOVE:
newValue = notSeletedElements.map((row) => convertDataSourceRowToLinkObject(row, displayedArray.updateParams.selectionColumnId, displayedArray.updateParams));
break;
case EUpdateOperations.EDIT:
newValue = notSeletedElements
.concat(event)
.map((row) => convertDataSourceRowToLinkObject(row, displayedArray.updateParams.selectionColumnId, displayedArray.updateParams));
break;
case EUpdateOperations.ADD:
selectedElements = selectedElements.map((element) => convertDataNodeToDataSourceRow(element, displayedArray.viewProperties.getColumns(), this.resourcesTypes));
if (event.formValues) {
selectedElements = getDataSourceRowsWithAssociatedValue(selectedElements, displayedArray.updateParams, event.formValues);
}
newValue = notSeletedElements
.concat(selectedElements)
.map((row) => convertDataSourceRowToLinkObject(row, displayedArray.updateParams.selectionColumnId, displayedArray.updateParams));
break;
default:
break;
}
}
const requestBody = {
schemas: [this.resourcesTypes.byId[this.selectedResourceTypeId].schema],
id: this.selectedEntryIds.id,
externalId: this.selectedEntryIds.externalId,
[fieldToUpdate]: newValue,
};
this._interactionsService.isProcessingRequest(true);
this._dataService
.updateData(this.endpoint, this.selectedEntryIds.id, requestBody)
.pipe(takeUntil(this._onDestroy$), take(1), tap((_) => {
this._interactionsService.isProcessingRequest(false);
displayedArray.succeededElements = selectedElements;
this.updateListAfterOperationsOnArray(operationsTypes, displayedArray);
dialogRef?.close();
}), catchError((err) => {
this._interactionsService.isProcessingRequest(false);
this._store$.dispatch([
new ErrorActions.SetErrorDetail({
error: err,
userActionOnError: EUserAction.DETAIL_UPDATE_ARRAY,
}),
new ErrorActions.IsHandlingError(true),
]);
if (err.status === 404) {
dialogRef.close();
this._router.navigate([this._router.url.replace(/[^/]+$/g, 'not-found')], { replaceUrl: true });
}
return this._errorsHandlerService.handleError(err);
}))
.subscribe();
}
updateArrayElements(event, operationsTypes, displayedArray, dialogRef) {
displayedArray.succeededElements = [];
displayedArray.failedElements404 = [];
if (displayedArray.isEditableArray) {
const requestEndpoint = displayedArray.endpoint;
const fieldToUpdate = displayedArray.requestsParams.fieldForUpdate;
const selectedElements = getSelectedElements(event);
forkJoin(selectedElements.map((selectedElement) => {
let newValue;
if ('selectedNode' in event &&
event.selectedNode) {
newValue = event.selectedNode.ids.id;
}
else if ('selectedItem' in event &&
event.selectedItem) {
newValue = event.selectedItem.ids.id;
}
else {
newValue = this.selectedEntryIds.id;
}
if (!!newValue) {
return this._operationOnElement(operationsTypes, selectedElement, displayedArray, fieldToUpdate, newValue, requestEndpoint).pipe(takeUntil(this._onDestroy$), take(1), tap((_) => {
this._interactionsService.isProcessingRequest(false);
displayedArray.succeededElements = [
...displayedArray.succeededElements,
selectedElement,
];
}), catchError((err) => {
this._interactionsService.isProcessingRequest(false);
this._store$.dispatch([
new ErrorActions.SetErrorDetail({
error: err,
userActionOnError: EUserAction.DETAIL_UPDATE_OTHER_RESOURCE,
}),
new ErrorActions.IsHandlingError(true),
]);
if (err.status === 404) {
displayedArray.failedElements404 = [
...displayedArray.failedElements404,
selectedElement,
];
}
return this._errorsHandlerService.handleError(err);
}));
}
else {
return of(null);
}
}))
.pipe(tap((_) => {
this.updateListAfterOperationsOnArray(operationsTypes, displayedArray);
dialogRef?.close();
}))
.subscribe();
}
}
_operationOnElement(operationsTypes, selectedElement, displayedArray, fieldToUpdate, newValue, requestEndpoint) {
const selectedElementId = getElementId(selectedElement);
if (operationsTypes.includes(EUpdateOperations.REMOVE) &&
operationsTypes.length === 1) {
this._interactionsService.isProcessingRequest(true);
return this._dataService.removeData(requestEndpoint, selectedElementId);
}
else {
const requestBody = {
schemas: [
this.resourcesTypes.byId[displayedArray.requestsParams.requestResourceTypeId].schema,
],
id: selectedElementId,
externalId: getElementExternalId(selectedElement),
[fieldToUpdate]: newValue,
};
this._interactionsService.isProcessingRequest(true);
return this._dataService.updateData(requestEndpoint, selectedElementId, requestBody);
}
}
updateListAfterOperationsOnArray(operationsTypes, displayedArray) {
if (operationsTypes.includes(EUpdateOperations.ADD) &&
!operationsTypes.includes(EUpdateOperations.REMOVE)) {
displayedArray.initialSource = [
...displayedArray.succeededElements.map((elt) => isDataNode(elt)
? convertDataNodeToDataSourceRow(elt, displayedArray.viewProperties.getColumns(), this.resourcesTypes)
: elt),
...displayedArray.initialSource,
];
}
else {
const succeededElementIds = displayedArray.succeededElements.map((succeededElement) => getElementId(succeededElement));
const failedElement404Ids = displayedArray.failedElements404.map((failedElement) => getElementId(failedElement));
displayedArray.selectedElementsUiIds =
displayedArray.selectedElementsUiIds.filter((element) => !succeededElementIds.includes(element.id) &&
!failedElement404Ids.includes(element.id));
if (operationsTypes.length === 1 &&
operationsTypes.includes(EUpdateOperations.EDIT)) {
displayedArray.initialSource = displayedArray.initialSource.map((row) => {
const rowId = getRowId(row, displayedArray.updateParams?.selectionColumnId);
return (displayedArray.succeededElements.find((row) => row.selectionIds.id === rowId) ?? row);
});
}
else {
displayedArray.initialSource = displayedArray.initialSource.filter((row) => {
const rowId = getRowId(row, displayedArray.updateParams?.selectionColumnId);
return (!succeededElementIds.includes(rowId) &&
!failedElement404Ids.includes(rowId));
});
}
}
displayedArray.viewProperties.setDataSource(new MatTableDataSource(displayedArray.initialSource));
if (displayedArray.succeededElements.length > 0) {
const message = getSucceededNotifications(displayedArray.succeededElements, getActionType(displayedArray.succeededElements, displayedArray.actions, operationsTypes));
this.evtSuccess.emit(message);
}
}
onUpdateArray(event, operationsTypes, displayedArray, dialogRef) {
if (!this.editableAttributesFromBackend.includes(displayedArray.attributeId)) {
this.updateArrayElements(event, operationsTypes, displayedArray, dialogRef);
}
else if (!!displayedArray.updateParams.patchOperationsParams) {
this.patchArrayAttribute(event, operationsTypes, displayedArray, dialogRef);
}
else {
this.updateArrayAttribute(event, operationsTypes, displayedArray, dialogRef);
}
}
_patchOperationRequest(operationType, selectedElementsIds, selectedElements, event, displayedArray, operationsTypes, dialogRef) {
let patchedEntryId;
if (operationType === EUpdateOperations.ADD) {
if (event &&
'selectedNode' in event &&
event.selectedNode) {
patchedEntryId = event.selectedNode.ids.id;
}
else if (event &&
'selectedItem' in event &&
event.selectedItem) {
patchedEntryId = event.selectedItem.ids.id;
}
else {
patchedEntryId = this.selectedEntryIds.id;
}
}
else {
patchedEntryId = this.selectedEntryIds.id;
}
const currentPath = operationType === EUpdateOperations.REMOVE
? selectedElementsIds.map((id) => displayedArray.updateParams.patchOperationsParams.remove.replace('$1', '"' + id + '"'))
: selectedElements.map((_) => displayedArray.updateParams.patchOperationsParams.add);
this._interactionsService.isProcessingRequest(true);
return this._dataService
.patchData(this.endpoint, patchedEntryId, toScimPropertiesPatch(currentPath, selectedElementsIds, operationType))
.pipe(tap((_) => {
this._interactionsService.isProcessingRequest(false);
if ((operationType === EUpdateOperations.ADD ||
(operationType === EUpdateOperations.REMOVE &&
!operationsTypes.includes(EUpdateOperations.ADD))) &&
!!event) {
displayedArray.succeededElements = [...selectedElements];
dialogRef?.close();
}
}), catchError((err) => {
this._interactionsService.isProcessingRequest(false);
this._store$.dispatch([
new ErrorActions.SetErrorDetail({
error: err,
userActionOnError: EUserAction.DETAIL_PATCH,
}),
new ErrorActions.IsHandlingError(true),
]);
if (!!err &&
err instanceof HttpErrorResponse &&
err.status === 404 &&
this.selectedEntryIds.id === patchedEntryId) {
this._router.navigate([this._router.url.replace(/[^/]+$/g, 'not-found')], { replaceUrl: true });
dialogRef?.close();
}
if (operationType === EUpdateOperations.ADD &&
operationsTypes.includes(EUpdateOperations.REMOVE) &&
!!event) {
this._patchOperationRequest(EUpdateOperations.ADD, selectedElementsIds, selectedElements, null, displayedArray, operationsTypes, dialogRef)
.pipe(take(1), takeUntil(this._onDestroy$))
.subscribe();
}
return throwError(() => err);
}));
}
_requestForArrayAttributes(attributesDoingRequests, editableArrayProperties) {
this._requestsSubscription = forkJoin(attributesDoingRequests.map((attributeDoingRequests) => {
const requestsProperties = setRequestsProperties(attributeDoingRequests, this.selectedEntryIds.id);
this._interactionsService.isProcessingRequest(true);
return getAttributeValues(requestsProperties, this._dataService, this._errorsHandlerService, attributeDoingRequests, this._store$, attributeDoingRequests.attributeConfig).pipe(filter((dataList) => !(dataList instanceof Error ||
dataList instanceof HttpErrorResponse)), tap((dataList) => {
this._interactionsService.isProcessingRequest(false);
const clickableCellsEndpoints = getClickableCellsEndpoints(this.resourcesTypes, this.configs.allIds, this.configs.byId[requestsProperties.resourceTypeId]);
const dataResourcesAsFlatArray = getDataSourceForGenericArray(dataList, this.configs.byId[requestsProperties.resourceTypeId], clickableCellsEndpoints);
this.allAttributesDisplayedAsArray.push(new DisplayedDetailArray(this._selectedResourceTypeId, this.configs, attributeDoingRequests, [requestsProperties.resourceTypeId], dataResourcesAsFlatArray, editableArrayProperties, this._dataDetail.meta.modifiableAttributes.includes(attributeDoingRequests.idField)));
this.evtArrayAttributesProcessed.emit(true);
}));
})).subscribe();
}
selectedData(data, displayedArray) {
displayedArray.selectedElementsUiIds = data.map((data) => data?.selectionIds ?? data);
}
_addMandatoryArrays(config) {
const mandatoriesFields = config.attributes
.filter((attribute) => attribute.props.isMandatory)
.reduce((acc, currAttribute) => ({
...acc,
[currAttribute.modelRef]: currAttribute.value.field.componentName === EComponentName.array
? []
: null,
}), {});
this._dataDetail = { ...this._dataDetail, ...mandatoriesFields };
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: DataDetailArrayAttributesComponent, deps: [{ token: i1.Store }, { token: i2.Router }, { token: i3.MatDialog }, { token: i4.DataService }, { token: i4.InteractionsService }, { token: i4.ErrorsHandlerService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.4", type: DataDetailArrayAttributesComponent, selector: "dm-data-detail-array-attributes", inputs: { selectedEntryIds: "selectedEntryIds", selectedEntryParentIds: "selectedEntryParentIds", configs: "configs", currentUser: "currentUser", resourcesTypes: "resourcesTypes", editableAttributesFromBackend: "editableAttributesFromBackend", endpoint: "endpoint", areArrayAttributesProcessed: "areArrayAttributesProcessed", hasLoadedArray: "hasLoadedArray", notLoadedArrayString: "notLoadedArrayString", selectedResourceTypeId: "selectedResourceTypeId", dataDetail: "dataDetail", additionalBtns: "additionalBtns" }, outputs: { evtArrayAttributesProcessed: "evtArrayAttributesProcessed", evtSuccess: "evtSuccess" }, viewQueries: [{ propertyName: "assignBtn", first: true, predicate: ["assignBtn"], 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<div @fadeIn *ngIf=\"areArrayAttributesProcessed\" class=\"div-array-attributes\">\n <mat-tab-group\n *ngIf=\"allAttributesDisplayedAsArray?.length > 1; else singleArray\"\n color=\"accent\"\n animationDuration=\"0ms\"\n class=\"array-tab-group\"\n >\n <mat-tab *ngFor=\"let attributeArray of allAttributesDisplayedAsArray\">\n <ng-template mat-tab-label>\n <mat-icon class=\"mat-tab-icon-lable\">{{\n attributeArray.icon\n }}</mat-icon>\n {{ attributeArray.label }}\n </ng-template>\n <ng-template matTabContent>\n <ng-container\n [ngTemplateOutlet]=\"tabContent\"\n [ngTemplateOutletContext]=\"{ attributeArray: attributeArray }\"\n ></ng-container>\n </ng-template>\n </mat-tab>\n </mat-tab-group>\n</div>\n<ng-template #singleArray>\n <div *ngFor=\"let attributeArray of allAttributesDisplayedAsArray\">\n <ng-container\n [ngTemplateOutlet]=\"tabContent\"\n [ngTemplateOutletContext]=\"{ attributeArray: attributeArray }\"\n ></ng-container>\n </div>\n</ng-template>\n\n<ng-template #tabContent let-attributeArray=\"attributeArray\">\n <div\n *ngIf=\"attributeArray?.isEditableArray; else onlyArrayLabel\"\n [fxLayout]=\"\n attributeArray.selectedElementsUiIds.length > 0 ? 'row wrap' : 'row'\n \"\n fxLayoutAlign=\"start center\"\n class=\"div-table-title\"\n #divTableHeader\n >\n <div fxLayout=\"row\" fxLayoutAlign=\"start center\">\n <dm-generic-array-header\n [dataLength]=\"attributeArray.viewProperties.getDataSource().data.length\"\n [dataIcon]=\"attributeArray.icon\"\n [dataName]=\"attributeArray.label\"\n ></dm-generic-array-header>\n <dm-ellipsis-menu\n *ngIf=\"\n attributeArray?.viewProperties?.getDataSource()?.filteredData\n ?.length > 0\n \"\n [isProcessingRequest]=\"isProcessingRequest\"\n [dataViewProperties]=\"attributeArray.viewProperties\"\n [uiComponent]=\"uiComponent\"\n [updateActionsParams]=\"attributeArray.updateParams\"\n [options]=\"{\n canMove: canAssignOrMoveAuthorizedTypes.includes(\n selectedResourceTypeId\n ),\n canDelete: attributeArray.canDeleteEntries\n }\"\n [attributeId]=\"attributeArray.attributeId\"\n [selectedElementsUiIds]=\"attributeArray.selectedElementsUiIds\"\n [actions]=\"attributeArray.actions\"\n (evtMoveSelectedElements)=\"\n onUpdateArray(\n $event,\n [updateOperations.REMOVE, updateOperations.ADD],\n attributeArray,\n $event.dialogRef\n )\n \"\n (evtDeleteSelectedElements)=\"\n onUpdateArray(\n $event.entries,\n [updateOperations.REMOVE],\n attributeArray,\n $event.dialogRef\n )\n \"\n (evtDeleteSelectedElement)=\"\n onUpdateArray(\n [$event.entry],\n [updateOperations.REMOVE],\n attributeArray,\n $event.dialogRef\n )\n \"\n (evtEditSelectedElements)=\"\n onUpdateArray(\n $event.rows,\n [updateOperations.EDIT],\n attributeArray,\n $event.dialogRef\n )\n \"\n ></dm-ellipsis-menu>\n </div>\n <div fxLayout=\"row\" fxLayoutAlign=\"start center\">\n <button\n *ngIf=\"canAssignOrMoveAuthorizedTypes?.includes(selectedResourceTypeId)\"\n #assignBtn\n mat-raised-button\n color=\"accent\"\n [disabled]=\"clickOnAssign\"\n (click)=\"assignNewElements(attributeArray)\"\n class=\"btn-assign-new-elements\"\n >\n {{ attributeArray.actions.assign.btnLabel }}\n </button>\n <ng-container *ngTemplateOutlet=\"additionalBtns\"></ng-container>\n <ng-container\n *ngIf=\"arrayGenericAccessibility$ | async as arrayGenericAccessibility\"\n >\n <span\n *ngIf=\"attributeArray?.selectedElementsUiIds?.length > 0\"\n class=\"span-selected-elements\"\n >\n {{\n attributeArray?.selectedElementsUiIds?.length > 1\n ? arrayGenericAccessibility.multipleSelection\n : arrayGenericAccessibility.singleSelection\n }}{{ attributeArray.selectedElementsUiIds.length }}\n </span>\n </ng-container>\n </div>\n </div>\n <ng-template #onlyArrayLabel>\n <span class=\"display-label-name\">\n {{ attributeArray.label }}\n </span>\n </ng-template>\n\n <div class=\"div-generic-array\">\n <dm-generic-array\n *ngIf=\"attributeArray?.initialSource?.length > 0; else emptyArray\"\n [actionsColumnTemplate]=\"actionsColumn\"\n [updateAffectAnotherResourceType]=\"\n attributeArray.updateAffectAnotherResourceType\n \"\n [fieldForUpdate]=\"attributeArray.fieldForUpdate\"\n [selectionColumnId]=\"attributeArray.updateParams?.selectionColumnId\"\n [isClickableRow]=\"attributeArray.viewProperties.getIsClickableRow()\"\n [canAssignOrMoveEntries]=\"\n canAssignOrMoveAuthorizedTypes.includes(selectedResourceTypeId)\n \"\n [isEditableArray]=\"attributeArray.isEditableArray\"\n [endpoint]=\"attributeArray.endpoint\"\n [columns]=\"attributeArray.viewProperties.getColumns()\"\n [initialDisplayedColumns]=\"\n attributeArray.viewProperties.getDisplayedColumns()\n \"\n [resourcesTypesProperties]=\"resourcesTypes\"\n [configs]=\"configs\"\n [accessibility]=\"attributeArray.viewProperties.getAccessibility()\"\n [actions]=\"attributeArray.actions ? attributeArray.actions : null\"\n [selectedElementsUiIds]=\"attributeArray.selectedElementsUiIds\"\n [isAttributeArray]=\"true\"\n [dataSource]=\"attributeArray.viewProperties.getDataSource()\"\n (selectedData)=\"selectedData($event, attributeArray)\"\n ></dm-generic-array>\n <ng-template #actionsColumn let-row=\"row\">\n <dm-ellipsis-menu\n *ngIf=\"row.isRowEditable\"\n [uiComponent]=\"uiComponent\"\n [attributeId]=\"attributeArray.attributeId\"\n [updateActionsParams]=\"attributeArray.updateParams\"\n [options]=\"{\n canMove: row.canMoveEntry,\n canDelete: row.canDeleteEntry,\n isForRow: true\n }\"\n [selectedElementsUiIds]=\"[row.selectionIds]\"\n [selectedRow]=\"row\"\n [isProcessingRequest]=\"isProcessingRequest\"\n [actions]=\"attributeArray.actions ? attributeArray.actions : null\"\n (click)=\"$event.stopPropagation()\"\n (evtMoveSelectedElements)=\"\n onUpdateArray(\n $event,\n [updateOperations.REMOVE, updateOperations.ADD],\n attributeArray,\n $event.dialogRef\n )\n \"\n (evtDeleteSelectedElement)=\"\n onUpdateArray(\n [$event.entry],\n [updateOperations.REMOVE],\n attributeArray,\n $event.dialogRef\n )\n \"\n (evtEditSelectedElement)=\"\n onUpdateArray(\n [$event.row],\n [updateOperations.EDIT],\n attributeArray,\n $event.dialogRef\n )\n \"\n ></dm-ellipsis-menu>\n </ng-template>\n <ng-template #emptyArray>\n <div fxLayoutAlign=\"center start\">\n <span class=\"placeholder-text placeholder-detail-page-text\">\n {{\n hasLoadedArray != null && !hasLoadedArray\n ? notLoadedArrayString\n : attributeArray.emptyArrayPlaceholder\n }}\n </span>\n </div>\n </ng-template>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";.display-label-name{padding:16px 20px 0;font-weight:700}.div-table-title{padding:0 0 0 20px}.div-generic-array{height:fit-content;margin-bottom:20px}.btn-assign-new-elements{margin-left:4px;min-width:fit-content}.span-selected-elements{color:#00000080;margin-left:8px}\n"], dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i6.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: i6.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: "component", type: i7.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i9.MatTabContent, selector: "[matTabContent]" }, { kind: "directive", type: i9.MatTabLabel, selector: "[mat-tab-label], [matTabLabel]" }, { kind: "component", type: i9.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i9.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "component", type: i10.GenericArrayHeaderComponent, selector: "dm-generic-array-header", inputs: ["dataLength", "dataIcon", "dataName"] }, { kind: "component", type: i11.EllipsisMenuComponent, selector: "dm-ellipsis-menu", inputs: ["dataViewProperties", "selectedElementsUiIds", "selectedRow", "isProcessingRequest", "uiComponent", "updateActionsParams", "options", "node", "item", "attributeId", "actions"], outputs: ["clickOnAddResourceBtn", "evtDeleteSelectedElements", "evtDeleteSelectedElement", "evtMoveSelectedElements", "evtEditSelectedElements", "evtEditSelectedElement", "evtMoveDataNode"] }, { kind: "component", type: i12.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: "pipe", type: i5.AsyncPipe, name: "async" }], animations: [trigger('fadeIn', fadeIn(':enter'))] }); }
}
__decorate([
Select(UiState.getArrayAccessibility)
], DataDetailArrayAttributesComponent.prototype, "arrayGenericAccessibility$", void 0);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: DataDetailArrayAttributesComponent, decorators: [{
type: Component,
args: [{ selector: 'dm-data-detail-array-attributes', animations: [trigger('fadeIn', fadeIn(':enter'))], 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<div @fadeIn *ngIf=\"areArrayAttributesProcessed\" class=\"div-array-attributes\">\n <mat-tab-group\n *ngIf=\"allAttributesDisplayedAsArray?.length > 1; else singleArray\"\n color=\"accent\"\n animationDuration=\"0ms\"\n class=\"array-tab-group\"\n >\n <mat-tab *ngFor=\"let attributeArray of allAttributesDisplayedAsArray\">\n <ng-template mat-tab-label>\n <mat-icon class=\"mat-tab-icon-lable\">{{\n attributeArray.icon\n }}</mat-icon>\n {{ attributeArray.label }}\n </ng-template>\n <ng-template matTabContent>\n <ng-container\n [ngTemplateOutlet]=\"tabContent\"\n [ngTemplateOutletContext]=\"{ attributeArray: attributeArray }\"\n ></ng-container>\n </ng-template>\n </mat-tab>\n </mat-tab-group>\n</div>\n<ng-template #singleArray>\n <div *ngFor=\"let attributeArray of allAttributesDisplayedAsArray\">\n <ng-container\n [ngTemplateOutlet]=\"tabContent\"\n [ngTemplateOutletContext]=\"{ attributeArray: attributeArray }\"\n ></ng-container>\n </div>\n</ng-template>\n\n<ng-template #tabContent let-attributeArray=\"attributeArray\">\n <div\n *ngIf=\"attributeArray?.isEditableArray; else onlyArrayLabel\"\n [fxLayout]=\"\n attributeArray.selectedElementsUiIds.length > 0 ? 'row wrap' : 'row'\n \"\n fxLayoutAlign=\"start center\"\n class=\"div-table-title\"\n #divTableHeader\n >\n <div fxLayout=\"row\" fxLayoutAlign=\"start center\">\n <dm-generic-array-header\n [dataLength]=\"attributeArray.viewProperties.getDataSource().data.length\"\n [dataIcon]=\"attributeArray.icon\"\n [dataName]=\"attributeArray.label\"\n ></dm-generic-array-header>\n <dm-ellipsis-menu\n *ngIf=\"\n attributeArray?.viewProperties?.getDataSource()?.filteredData\n ?.length > 0\n \"\n [isProcessingRequest]=\"isProcessingRequest\"\n [dataViewProperties]=\"attributeArray.viewProperties\"\n [uiComponent]=\"uiComponent\"\n [updateActionsParams]=\"attributeArray.updateParams\"\n [options]=\"{\n canMove: canAssignOrMoveAuthorizedTypes.includes(\n selectedResourceTypeId\n ),\n canDelete: attributeArray.canDeleteEntries\n }\"\n [attributeId]=\"attributeArray.attributeId\"\n [selectedElementsUiIds]=\"attributeArray.selectedElementsUiIds\"\n [actions]=\"attributeArray.actions\"\n (evtMoveSelectedElements)=\"\n onUpdateArray(\n $event,\n [updateOperations.REMOVE, updateOperations.ADD],\n attributeArray,\n $event.dialogRef\n )\n \"\n (evtDeleteSelectedElements)=\"\n onUpdateArray(\n $event.entries,\n [updateOperations.REMOVE],\n attributeArray,\n $event.dialogRef\n )\n \"\n (evtDeleteSelectedElement)=\"\n onUpdateArray(\n [$event.entry],\n [updateOperations.REMOVE],\n attributeArray,\n $event.dialogRef\n )\n \"\n (evtEditSelectedElements)=\"\n onUpdateArray(\n $event.rows,\n [updateOperations.EDIT],\n attributeArray,\n $event.dialogRef\n )\n \"\n ></dm-ellipsis-menu>\n </div>\n <div fxLayout=\"row\" fxLayoutAlign=\"start center\">\n <button\n *ngIf=\"canAssignOrMoveAuthorizedTypes?.includes(selectedResourceTypeId)\"\n #assignBtn\n mat-raised-button\n color=\"accent\"\n [disabled]=\"clickOnAssign\"\n (click)=\"assignNewElements(attributeArray)\"\n class=\"btn-assign-new-elements\"\n >\n {{ attributeArray.actions.assign.btnLabel }}\n </button>\n <ng-container *ngTemplateOutlet=\"additionalBtns\"></ng-container>\n <ng-container\n *ngIf=\"arrayGenericAccessibility$ | async as arrayGenericAccessibility\"\n >\n <span\n *ngIf=\"attributeArray?.selectedElementsUiIds?.length > 0\"\n class=\"span-selected-elements\"\n >\n {{\n attributeArray?.selectedElementsUiIds?.length > 1\n ? arrayGenericAccessibility.multipleSelection\n : arrayGenericAccessibility.singleSelection\n }}{{ attributeArray.selectedElementsUiIds.length }}\n </span>\n </ng-container>\n </div>\n </div>\n <ng-template #onlyArrayLabel>\n <span