UNPKG

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

Version:

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

393 lines 97.7 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 { SelectionModel } from '@angular/cdk/collections'; import { Component, ElementRef, EventEmitter, Input, Output, ViewChild, ViewChildren, } from '@angular/core'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { MatRow } from '@angular/material/table'; import { Select } from '@ngxs/store'; import { Subject, debounceTime, distinctUntilChanged, filter, map, takeUntil, tap, } from 'rxjs'; import { Data, DataState, UiState, canDeleteEntry, canMoveEntry, emptyJsTable, getSelectedElementIds, getSelectedElementsDependsOnMode, getUpdatedDisplayedColumns, isRowEditable, mergeInto, optionsPaginator, sortData, } from '../../shared'; import * as i0 from "@angular/core"; import * as i1 from "@ngxs/store"; import * as i2 from "@angular/router"; import * as i3 from "@angular/common"; import * as i4 from "@angular/forms"; 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/checkbox"; import * as i9 from "@angular/material/form-field"; import * as i10 from "@angular/material/icon"; import * as i11 from "@angular/material/input"; import * as i12 from "@angular/material/paginator"; import * as i13 from "@angular/material/sort"; import * as i14 from "@angular/material/table"; import * as i15 from "@angular/material/tooltip"; import * as i16 from "../../shared/pipes/type-casting"; /** * This class is a generic and configurable table to be used for every data table. */ export class GenericArrayComponent { set selectedElementsUiIds(selectedElementsUiIds) { if (selectedElementsUiIds) { this._selectedElementsUiIds = selectedElementsUiIds; } } get selectedElementsUiIds() { return this._selectedElementsUiIds; } set dataSource(dataSource) { if (dataSource) { this._dataSource = dataSource; this.dataSource.data = this.dataSource.data.map((row) => { const canEditRow = isRowEditable(this.isAttributeArray, this.updateAffectAnotherResourceType, this.fieldForUpdate, this.isEditableArray, row); return { ...row, isRowEditable: canEditRow, canMoveEntry: canMoveEntry(this.actions, this.canAssignOrMoveEntries, this.isSelectOnlyModeEnabled, canEditRow), canDeleteEntry: canDeleteEntry(this.actions, this.isSelectOnlyModeEnabled, canEditRow), selectionIds: getSelectedElementIds(row, this.selectionColumnId), }; }); this.displayedColumns = getUpdatedDisplayedColumns(this.actions, this.initialDisplayedColumns, this.isSelectOnlyModeEnabled, this.canAssignOrMoveEntries, this.isEditableArray, this.updateAffectAnotherResourceType, this.isAttributeArray, this.dataSource.data); this.dataSource.filterPredicate = (data, filter) => this.initialDisplayedColumns .filter((columnId) => columnId !== 'select' && columnId !== 'actions') .some((columnId) => !!data[columnId] && ((Array.isArray(data[columnId]) && data[columnId].some((cellElt) => { const value = typeof cellElt === 'string' ? cellElt : cellElt.value; return value .getRidOfDiacritics() .toLocaleUpperCase() .includes(filter.getRidOfDiacritics().toLocaleUpperCase()); })) || (typeof data[columnId] === 'string' && data[columnId] .getRidOfDiacritics() .toLocaleUpperCase() .includes(filter.getRidOfDiacritics().toLocaleUpperCase())))); this.dataSource.sortData = (data, sort) => sortData(data, sort); if (this.filter && this.filter !== '') { this.dataSource.filter = this.filter.trim(); } const nbTotalResults = dataSource.data.length; this.optionsNbItemsPerPage = optionsPaginator(nbTotalResults); const pageSize = nbTotalResults > 10 ? 10 : nbTotalResults; this.paginator._changePageSize(pageSize); this._dataSource.paginator = this.paginator; } this.selection = new SelectionModel(true, this._selectedElementsUiIds && this._selectedElementsUiIds.length > 0 ? this.dataSource.filteredData.filter((elt) => this._selectedElementsUiIds.find((selectedElementUiIds) => selectedElementUiIds.id === elt.selectionIds.id)) : []); } get dataSource() { return this._dataSource; } set selectedResourceRootTypeId(selectedResourceRootTypeId) { if (selectedResourceRootTypeId) { this.filter = this._dataJsTable.byId[selectedResourceRootTypeId] ? this._dataJsTable.byId[selectedResourceRootTypeId].filterValue : ''; this._selectedResourceRootTypeId = selectedResourceRootTypeId; } } get selectedResourceRootTypeId() { return this._selectedResourceRootTypeId; } constructor(_store$, _router) { this._store$ = _store$; this._router = _router; this.filter = ''; this.isClickableRow = false; this.isSelectOnlyModeEnabled = false; this.canAssignOrMoveEntries = false; this.isAttributeArray = false; this.isEditableArray = false; this.selectedData = new EventEmitter(); this.optionsNbItemsPerPage = []; this.displayEllipsisFromTableRow = true; this._selectedDataBeforeApplyFilter = new Set(); this._dataJsTable = emptyJsTable(); this._modelChanged = new Subject(); this._onDestroy$ = new Subject(); } ngOnInit() { if (!this.isAttributeArray) { this._modelChanged .pipe(debounceTime(300), takeUntil(this._onDestroy$), tap((currentSearch) => { this._store$.dispatch(new Data.SetFilterValue({ filterValue: currentSearch, dataTypeId: this.selectedResourceRootTypeId, })); })) .subscribe(); this.dataJsTable$ .pipe(takeUntil(this._onDestroy$), map((dataJsTable) => { this._dataJsTable = mergeInto(this._dataJsTable, dataJsTable); return !!this.selectedResourceRootTypeId && this._dataJsTable.byId[this.selectedResourceRootTypeId] ?.filterValue ? this._dataJsTable.byId[this.selectedResourceRootTypeId] .filterValue : ''; }), distinctUntilChanged((prev, curr) => prev === curr), filter((filterValue) => !this.isSelectOnlyModeEnabled && filterValue !== undefined && filterValue !== null), tap((filterValue) => { this.filter = filterValue; this.applyFilter(); })) .subscribe(); } } ngAfterViewInit() { if (this._dataSource != null) { this._dataSource.sort = this.sort; } } updateArraySearch(search) { if (this.isAttributeArray) { this.filter = search; this.applyFilter(); } else { this._modelChanged.next(search); } } applyFilter() { this.dataSource.filter = this.filter; this.displayedColumns = getUpdatedDisplayedColumns(this.actions, this.initialDisplayedColumns, this.isSelectOnlyModeEnabled, this.canAssignOrMoveEntries, this.isEditableArray, this.updateAffectAnotherResourceType, this.isAttributeArray, this.dataSource.filteredData); const filteredDataIds = this.dataSource.filteredData.map((data) => data.id); this.selection.selected.forEach((selectedData) => { if (!filteredDataIds.includes(selectedData.id)) { this._selectedDataBeforeApplyFilter.add(selectedData); this.selection.deselect(selectedData); } }); this._resetSelectedElementsBeforeFiltering(filteredDataIds); this.selectedData.emit(getSelectedElementsDependsOnMode(this.isSelectOnlyModeEnabled, this.selection)); } clearFilterInput() { this._modelChanged.next(''); this.filter = ''; this.dataSource.filter = ''; this.displayedColumns = getUpdatedDisplayedColumns(this.actions, this.initialDisplayedColumns, this.isSelectOnlyModeEnabled, this.canAssignOrMoveEntries, this.isEditableArray, this.updateAffectAnotherResourceType, this.isAttributeArray, this.dataSource.filteredData); this._resetSelectedElementsBeforeFiltering(this.dataSource.filteredData.map((data) => data.id)); this.selectedData.emit(getSelectedElementsDependsOnMode(this.isSelectOnlyModeEnabled, this.selection)); } /** Whether the number of selected elements matches the total number of rows. */ isAllSelected() { let numSelected = 0; let numRows = 0; if (this.dataSource) { numSelected = this.selection.selected.length; numRows = this.dataSource.filteredData && this.dataSource.filteredData !== undefined ? this.dataSource.filteredData.filter((data) => data.isRowEditable).length : 0; } return numSelected === numRows && numSelected !== 0 && numRows !== 0; } /** Selects all rows if they are not all selected; otherwise clear selection. */ masterToggle() { if (this.dataSource) { this.isAllSelected() ? this.selection.clear() : this.dataSource.filteredData.forEach((row) => { if (row.isRowEditable) { this.selection.select(row); } }); } else { this.selection.clear(); } this.selectedData.emit(getSelectedElementsDependsOnMode(this.isSelectOnlyModeEnabled, this.selection)); } /** The label for the checkbox on the passed row */ checkboxLabel(row) { const arrayGenericAccessibility = this._store$.selectSnapshot(UiState.getArrayAccessibility); if (!row) { return this.isAllSelected() ? arrayGenericAccessibility.multipleDeselectionLabel : arrayGenericAccessibility.multipleSelectionLabel; } return `${this.selection.isSelected(row) ? arrayGenericAccessibility.singleDeselectionLabel : arrayGenericAccessibility.singleSelectionLabel} ${row.externalId}`; } checkSelection() { this.selectedData.emit(getSelectedElementsDependsOnMode(this.isSelectOnlyModeEnabled, this.selection)); } onKeyRedirect(link, id) { this._router.navigateByUrl(link); this.setEntryIdInStore(id); } onKeyRedirectFromRow(link, ids) { this._router.navigateByUrl(link); this.setEntryIdsInStore(ids); } onKeyArrowDown(index) { if (index < this.matRows.length - 1) { const newRow = this.matRows.get(index + 1).nativeElement; if (newRow) { newRow.focus(); } } } onKeyArrowUp(index) { if (index > 0) { const newRow = this.matRows.get(index - 1).nativeElement; if (newRow) { newRow.focus(); } } } getRowLink(externalId) { let link = ''; return link.concat('/home', '/', this.endpoint, '/', encodeURIComponent(externalId)); } isCellValueAnArray(elementValue) { return Array.isArray(elementValue); } getDisplayedValueForArray(index, arrayLength, currentValue) { return index === arrayLength - 1 ? currentValue : currentValue.concat(', '); } setEntryIdInStore(id, event = null) { this._store$.dispatch(new Data.SetSelectedEntryId({ id })); if (event !== null) { event.stopPropagation(); } } setEntryIdsInStore(ids) { this._store$.dispatch(new Data.SetSelectedEntryIds({ ids })); } getCellTitle(cellValue) { if (cellValue == null) { return ''; } return Array.isArray(cellValue) ? cellValue.map((elt) => elt.value).join(', ') : cellValue; } getTableMinHeight() { const rowHeight = 48; const tableHeaderHeight = 56; let minHeight = 0; if (!this.isSelectOnlyModeEnabled) { minHeight = this.dataSource.filteredData.length < 10 ? tableHeaderHeight + rowHeight * this.dataSource.filteredData.length : tableHeaderHeight + rowHeight * 10; } return minHeight; } _resetSelectedElementsBeforeFiltering(filteredIds) { this._selectedDataBeforeApplyFilter.forEach((selectedData) => { if (filteredIds.includes(selectedData.id)) { this.selection.select(selectedData); this._selectedDataBeforeApplyFilter.delete(selectedData); } }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: GenericArrayComponent, deps: [{ token: i1.Store }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.4", type: GenericArrayComponent, selector: "dm-generic-array", inputs: { isClickableRow: "isClickableRow", isSelectOnlyModeEnabled: "isSelectOnlyModeEnabled", selectedElementsUiIds: "selectedElementsUiIds", dataSource: "dataSource", columns: "columns", initialDisplayedColumns: "initialDisplayedColumns", processingRequest$: "processingRequest$", actions: "actions", resourcesTypesProperties: "resourcesTypesProperties", configs: "configs", accessibility: "accessibility", endpoint: "endpoint", canAssignOrMoveEntries: "canAssignOrMoveEntries", selectedResourceRootTypeId: "selectedResourceRootTypeId", isAttributeArray: "isAttributeArray", updateAffectAnotherResourceType: "updateAffectAnotherResourceType", fieldForUpdate: "fieldForUpdate", isEditableArray: "isEditableArray", selectionColumnId: "selectionColumnId", actionsColumnTemplate: "actionsColumnTemplate" }, outputs: { selectedData: "selectedData" }, viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, static: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true }, { propertyName: "matRows", predicate: MatRow, descendants: true, read: ElementRef }], 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 fxLayout=\"row wrap\" class=\"div-table-filter\">\n <mat-form-field\n *ngIf=\"filterAccessibility$ | async as filterAccessibility\"\n color=\"accent\"\n class=\"filter\"\n >\n <mat-label>\n <mat-icon aria-hidden=\"true\">filter_list_alt</mat-icon>\n {{ filterAccessibility.label }}\n </mat-label>\n <input\n type=\"text\"\n matInput\n [ngModel]=\"filter\"\n (ngModelChange)=\"updateArraySearch($event)\"\n />\n <button\n *ngIf=\"filter\"\n matSuffix\n mat-icon-button\n [attr.aria-label]=\"filterAccessibility.clearSearch\"\n (click)=\"clearFilterInput()\"\n class=\"reset-input-btn\"\n matTooltip=\"{{ filterAccessibility.clearSearch }}\"\n >\n <mat-icon aria-hidden=\"true\"> clear </mat-icon>\n </button>\n </mat-form-field>\n <mat-paginator\n color=\"accent\"\n [pageSizeOptions]=\"optionsNbItemsPerPage\"\n showFirstLastButtons\n ></mat-paginator>\n</div>\n<div\n *ngIf=\"arrayGenericAccessibility$ | async as arrayGenericAccessibility\"\n class=\"div-table\"\n>\n <table\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n [attr.role]=\"accessibility.table\"\n >\n <caption>\n {{\n accessibility.table\n }}\n </caption>\n <ng-container matColumnDef=\"select\">\n <th\n mat-header-cell\n [attr.role]=\"arrayGenericAccessibility.selectColumn\"\n scope=\"col\"\n *matHeaderCellDef\n >\n <mat-checkbox\n [aria-label]=\"checkboxLabel()\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n (change)=\"$event ? masterToggle() : null\"\n >\n </mat-checkbox>\n </th>\n <td\n mat-cell\n [attr.role]=\"arrayGenericAccessibility.selectRow\"\n *matCellDef=\"let row\"\n (click)=\"$event.stopPropagation()\"\n >\n <mat-checkbox\n *ngIf=\"row.isRowEditable\"\n [aria-label]=\"checkboxLabel(row)\"\n [checked]=\"selection.isSelected(row)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? selection.toggle(row) : null; checkSelection()\"\n >\n </mat-checkbox>\n </td>\n </ng-container>\n\n <ng-container [matColumnDef]=\"column.id\" *ngFor=\"let column of columns\">\n <th\n mat-header-cell\n scope=\"col\"\n [attr.role]=\"\n arrayGenericAccessibility.columnHeader +\n column.label.toLocaleLowerCase()\n \"\n *matHeaderCellDef\n mat-sort-header\n [style.width]=\"column.width\"\n >\n {{ column.label }}\n </th>\n <td\n mat-cell\n [attr.role]=\"\n arrayGenericAccessibility.cell + column.label.toLocaleLowerCase()\n \"\n [title]=\"getCellTitle(element[column.id])\"\n [style.width]=\"column.width\"\n *matCellDef=\"let element\"\n >\n <div\n *ngIf=\"isCellValueAnArray(element[column?.id]); else oneStringValue\"\n >\n <span\n *ngFor=\"let cellObject of element[column.id]; let i = index\"\n [ngClass]=\"{\n 'element-link':\n !isSelectOnlyModeEnabled && cellObject.isClickable,\n element: i > 0\n }\"\n [routerLink]=\"\n !isSelectOnlyModeEnabled && cellObject.isClickable\n ? cellObject.routerLinkValue\n : []\n \"\n (click)=\"\n !isSelectOnlyModeEnabled && cellObject.isClickable\n ? setEntryIdInStore(cellObject.id, $event)\n : null\n \"\n (keydown.enter)=\"\n !isSelectOnlyModeEnabled && cellObject.isClickable\n ? onKeyRedirect(cellObject.routerLinkValue, cellObject.id)\n : null\n \"\n >\n {{\n getDisplayedValueForArray(\n i,\n element[column.id].length,\n cellObject.value || cellObject\n )\n }}\n </span>\n </div>\n <ng-template #oneStringValue>\n <span>\n {{ element[column.id] }}\n </span>\n </ng-template>\n </td>\n </ng-container>\n\n <ng-container *ngIf=\"actionsColumnTemplate != null\" matColumnDef=\"actions\">\n <th\n mat-header-cell\n [attr.role]=\"arrayGenericAccessibility.actionsColumn\"\n scope=\"col\"\n *matHeaderCellDef\n >\n {{ arrayGenericAccessibility.actionsColumnLabel }}\n </th>\n <td\n mat-cell\n [attr.role]=\"arrayGenericAccessibility.actionsMenu\"\n *matCellDef=\"let row\"\n (click)=\"$event.stopPropagation()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"actionsColumnTemplate\"\n [ngTemplateOutletContext]=\"{\n row\n }\"\n >\n </ng-container></td\n ></ng-container>\n\n <tr\n mat-header-row\n [attr.role]=\"accessibility.headerRow\"\n *matHeaderRowDef=\"displayedColumns; sticky: true\"\n ></tr>\n <tr\n mat-row\n *matRowDef=\"let row; columns: displayedColumns; let i = index\"\n [id]=\"i\"\n [attr.role]=\"\n row.externalId ? accessibility.row + row.externalId : accessibility.row\n \"\n [ngClass]=\"{\n highlighted: selection.isSelected(row),\n hovered: !selection.isSelected(row) && isClickableRow,\n 'clickable-row-pointer': isClickableRow\n }\"\n [routerLink]=\"isClickableRow ? getRowLink(row.externalId) : []\"\n (click)=\"\n isClickableRow\n ? setEntryIdsInStore({ id: row.id, externalId: row.externalId })\n : null\n \"\n (keydown.enter)=\"\n isClickableRow\n ? onKeyRedirectFromRow(getRowLink(row.externalId), {\n id: row.id,\n externalId: row.externalId\n })\n : null\n \"\n (keydown.arrowdown)=\"onKeyArrowDown(i)\"\n (keydown.arrowup)=\"onKeyArrowUp(i)\"\n ></tr>\n\n <tr class=\"mat-row\" *matNoDataRow>\n <div fxLayoutAlign=\"center start\">\n <span\n class=\"placeholder-text\"\n [ngClass]=\"{ 'placeholder-detail-page-text': isAttributeArray }\"\n >\n {{\n isSelectOnlyModeEnabled && isAttributeArray\n ? (actions | asAttributeActions).assign.noFilterResult\n : actions.search.filter.noResult\n }}\n </span>\n </div>\n </tr>\n </table>\n</div>\n", styles: ["@charset \"UTF-8\";:host{min-width:100%;width:fit-content;display:flex;flex-direction:column}.div-table-filter{min-width:fit-content}table{box-shadow:none}table th:not(.mat-column-select,.mat-column-actions){cursor:pointer}.clickable-row-pointer{cursor:pointer}.filter{min-width:auto;flex-grow:1}.element{padding-left:4px}.element-link{cursor:pointer}.element-link:hover,.element-link:focus{font-weight:700}caption{margin:20px 0 10px;font-weight:700}mat-label{display:flex}.reset-input-btn{height:1.5em;width:1.5em;padding:0;display:flex;align-items:center;justify-content:center}.reset-input-btn mat-icon{font-size:inherit;height:auto;width:auto}\n"], dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i4.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: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { 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: 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: "component", type: i7.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i8.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { 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.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i11.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: "component", type: i12.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "directive", type: i13.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i13.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "component", type: i14.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i14.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i14.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i14.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i14.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i14.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i14.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i14.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i14.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i14.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i14.MatNoDataRow, selector: "ng-template[matNoDataRow]" }, { kind: "directive", type: i15.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i16.CastToIAttributeActions, name: "asAttributeActions" }] }); } } __decorate([ Select(DataState.getDataJsTable) ], GenericArrayComponent.prototype, "dataJsTable$", void 0); __decorate([ Select(UiState.getFilterAccessibility) ], GenericArrayComponent.prototype, "filterAccessibility$", void 0); __decorate([ Select(UiState.getArrayAccessibility) ], GenericArrayComponent.prototype, "arrayGenericAccessibility$", void 0); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: GenericArrayComponent, decorators: [{ type: Component, args: [{ selector: 'dm-generic-array', 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 fxLayout=\"row wrap\" class=\"div-table-filter\">\n <mat-form-field\n *ngIf=\"filterAccessibility$ | async as filterAccessibility\"\n color=\"accent\"\n class=\"filter\"\n >\n <mat-label>\n <mat-icon aria-hidden=\"true\">filter_list_alt</mat-icon>\n {{ filterAccessibility.label }}\n </mat-label>\n <input\n type=\"text\"\n matInput\n [ngModel]=\"filter\"\n (ngModelChange)=\"updateArraySearch($event)\"\n />\n <button\n *ngIf=\"filter\"\n matSuffix\n mat-icon-button\n [attr.aria-label]=\"filterAccessibility.clearSearch\"\n (click)=\"clearFilterInput()\"\n class=\"reset-input-btn\"\n matTooltip=\"{{ filterAccessibility.clearSearch }}\"\n >\n <mat-icon aria-hidden=\"true\"> clear </mat-icon>\n </button>\n </mat-form-field>\n <mat-paginator\n color=\"accent\"\n [pageSizeOptions]=\"optionsNbItemsPerPage\"\n showFirstLastButtons\n ></mat-paginator>\n</div>\n<div\n *ngIf=\"arrayGenericAccessibility$ | async as arrayGenericAccessibility\"\n class=\"div-table\"\n>\n <table\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n [attr.role]=\"accessibility.table\"\n >\n <caption>\n {{\n accessibility.table\n }}\n </caption>\n <ng-container matColumnDef=\"select\">\n <th\n mat-header-cell\n [attr.role]=\"arrayGenericAccessibility.selectColumn\"\n scope=\"col\"\n *matHeaderCellDef\n >\n <mat-checkbox\n [aria-label]=\"checkboxLabel()\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n (change)=\"$event ? masterToggle() : null\"\n >\n </mat-checkbox>\n </th>\n <td\n mat-cell\n [attr.role]=\"arrayGenericAccessibility.selectRow\"\n *matCellDef=\"let row\"\n (click)=\"$event.stopPropagation()\"\n >\n <mat-checkbox\n *ngIf=\"row.isRowEditable\"\n [aria-label]=\"checkboxLabel(row)\"\n [checked]=\"selection.isSelected(row)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? selection.toggle(row) : null; checkSelection()\"\n >\n </mat-checkbox>\n </td>\n </ng-container>\n\n <ng-container [matColumnDef]=\"column.id\" *ngFor=\"let column of columns\">\n <th\n mat-header-cell\n scope=\"col\"\n [attr.role]=\"\n arrayGenericAccessibility.columnHeader +\n column.label.toLocaleLowerCase()\n \"\n *matHeaderCellDef\n mat-sort-header\n [style.width]=\"column.width\"\n >\n {{ column.label }}\n </th>\n <td\n mat-cell\n [attr.role]=\"\n arrayGenericAccessibility.cell + column.label.toLocaleLowerCase()\n \"\n [title]=\"getCellTitle(element[column.id])\"\n [style.width]=\"column.width\"\n *matCellDef=\"let element\"\n >\n <div\n *ngIf=\"isCellValueAnArray(element[column?.id]); else oneStringValue\"\n >\n <span\n *ngFor=\"let cellObject of element[column.id]; let i = index\"\n [ngClass]=\"{\n 'element-link':\n !isSelectOnlyModeEnabled && cellObject.isClickable,\n element: i > 0\n }\"\n [routerLink]=\"\n !isSelectOnlyModeEnabled && cellObject.isClickable\n ? cellObject.routerLinkValue\n : []\n \"\n (click)=\"\n !isSelectOnlyModeEnabled && cellObject.isClickable\n ? setEntryIdInStore(cellObject.id, $event)\n : null\n \"\n (keydown.enter)=\"\n !isSelectOnlyModeEnabled && cellObject.isClickable\n ? onKeyRedirect(cellObject.routerLinkValue, cellObject.id)\n : null\n \"\n >\n {{\n getDisplayedValueForArray(\n i,\n element[column.id].length,\n cellObject.value || cellObject\n )\n }}\n </span>\n </div>\n <ng-template #oneStringValue>\n <span>\n {{ element[column.id] }}\n </span>\n </ng-template>\n </td>\n </ng-container>\n\n <ng-container *ngIf=\"actionsColumnTemplate != null\" matColumnDef=\"actions\">\n <th\n mat-header-cell\n [attr.role]=\"arrayGenericAccessibility.actionsColumn\"\n scope=\"col\"\n *matHeaderCellDef\n >\n {{ arrayGenericAccessibility.actionsColumnLabel }}\n </th>\n <td\n mat-cell\n [attr.role]=\"arrayGenericAccessibility.actionsMenu\"\n *matCellDef=\"let row\"\n (click)=\"$event.stopPropagation()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"actionsColumnTemplate\"\n [ngTemplateOutletContext]=\"{\n row\n }\"\n >\n </ng-container></td\n ></ng-container>\n\n <tr\n mat-header-row\n [attr.role]=\"accessibility.headerRow\"\n *matHeaderRowDef=\"displayedColumns; sticky: true\"\n ></tr>\n <tr\n mat-row\n *matRowDef=\"let row; columns: displayedColumns; let i = index\"\n [id]=\"i\"\n [attr.role]=\"\n row.externalId ? accessibility.row + row.externalId : accessibility.row\n \"\n [ngClass]=\"{\n highlighted: selection.isSelected(row),\n hovered: !selection.isSelected(row) && isClickableRow,\n 'clickable-row-pointer': isClickableRow\n }\"\n [routerLink]=\"isClickableRow ? getRowLink(row.externalId) : []\"\n (click)=\"\n isClickableRow\n ? setEntryIdsInStore({ id: row.id, externalId: row.externalId })\n : null\n \"\n (keydown.enter)=\"\n isClickableRow\n ? onKeyRedirectFromRow(getRowLink(row.externalId), {\n id: row.id,\n externalId: row.externalId\n })\n : null\n \"\n (keydown.arrowdown)=\"onKeyArrowDown(i)\"\n (keydown.arrowup)=\"onKeyArrowUp(i)\"\n ></tr>\n\n <tr class=\"mat-row\" *matNoDataRow>\n <div fxLayoutAlign=\"center start\">\n <span\n class=\"placeholder-text\"\n [ngClass]=\"{ 'placeholder-detail-page-text': isAttributeArray }\"\n >\n {{\n isSelectOnlyModeEnabled && isAttributeArray\n ? (actions | asAttributeActions).assign.noFilterResult\n : actions.search.filter.noResult\n }}\n </span>\n </div>\n </tr>\n </table>\n</div>\n", styles: ["@charset \"UTF-8\";:host{min-width:100%;width:fit-content;display:flex;flex-direction:column}.div-table-filter{min-width:fit-content}table{box-shadow:none}table th:not(.mat-column-select,.mat-column-actions){cursor:pointer}.clickable-row-pointer{cursor:pointer}.filter{min-width:auto;flex-grow:1}.element{padding-left:4px}.element-link{cursor:pointer}.element-link:hover,.element-link:focus{font-weight:700}caption{margin:20px 0 10px;font-weight:700}mat-label{display:flex}.reset-input-btn{height:1.5em;width:1.5em;padding:0;display:flex;align-items:center;justify-content:center}.reset-input-btn mat-icon{font-size:inherit;height:auto;width:auto}\n"] }] }], ctorParameters: () => [{ type: i1.Store }, { type: i2.Router }], propDecorators: { dataJsTable$: [], filterAccessibility$: [], arrayGenericAccessibility$: [], isClickableRow: [{ type: Input }], isSelectOnlyModeEnabled: [{ type: Input }], selectedElementsUiIds: [{ type: Input }], dataSource: [{ type: Input }], columns: [{ type: Input }], initialDisplayedColumns: [{ type: Input }], processingRequest$: [{ type: Input }], actions: [{ type: Input }], resourcesTypesProperties: [{ type: Input }], configs: [{ type: Input }], accessibility: [{ type: Input }], endpoint: [{ type: Input }], canAssignOrMoveEntries: [{ type: Input }], selectedResourceRootTypeId: [{ type: Input }], isAttributeArray: [{ type: Input }], updateAffectAnotherResourceType: [{ type: Input }], fieldForUpdate: [{ type: Input }], isEditableArray: [{ type: Input }], selectionColumnId: [{ type: Input }], actionsColumnTemplate: [{ type: Input }], selectedData: [{ type: Output }], paginator: [{ type: ViewChild, args: [MatPaginator, { static: true }] }], sort: [{ type: ViewChild, args: [MatSort] }], matRows: [{ type: ViewChildren, args: [MatRow, { read: ElementRef }] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJpYy1hcnJheS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9saWJzL2NsaWVudC1jb3JlL3NyYy9saWIvZmVhdHVyZS9nZW5lcmljLWFycmF5L2dlbmVyaWMtYXJyYXkuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvbGlicy9jbGllbnQtY29yZS9zcmMvbGliL2ZlYXR1cmUvZ2VuZXJpYy1hcnJheS9nZW5lcmljLWFycmF5LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQ0c7QUFFSCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDMUQsT0FBTyxFQUVMLFNBQVMsRUFDVCxVQUFVLEVBQ1YsWUFBWSxFQUNaLEtBQUssRUFFTCxNQUFNLEVBR04sU0FBUyxFQUNULFlBQVksR0FDYixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDM0QsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2pELE9BQU8sRUFBRSxNQUFNLEVBQXNCLE1BQU0seUJBQXlCLENBQUM7QUFFckUsT0FBTyxFQUFFLE1BQU0sRUFBUyxNQUFNLGFBQWEsQ0FBQztBQUM1QyxPQUFPLEVBRUwsT0FBTyxFQUNQLFlBQVksRUFDWixvQkFBb0IsRUFDcEIsTUFBTSxFQUNOLEdBQUcsRUFDSCxTQUFTLEVBQ1QsR0FBRyxHQUNKLE1BQU0sTUFBTSxDQUFDO0FBQ2QsT0FBTyxFQUNMLElBQUksRUFDSixTQUFTLEVBZVQsT0FBTyxFQUNQLGNBQWMsRUFDZCxZQUFZLEVBQ1osWUFBWSxFQUNaLHFCQUFxQixFQUNyQixnQ0FBZ0MsRUFDaEMsMEJBQTBCLEVBQzFCLGFBQWEs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