[ACS-7381][ADF] Break DataTable dependency on Material Module (#9657)

* [ACS-7381] remove MaterialModule dependency and convert components to standalone

* [ACS-7381] remove MaterialModule dependency and convert components to standalone

* [ACS-7381] tests fixes

* [ACS-7381] tests fixes

* [ACS-7381] tests fixes

* [ACS-7381] tests fixes

* [ACS-7381] tests fixes

* [ACS-7381] tests fixes

* [ACS-7381] tests fixes

* [ACS-7381] tests fixes

* [ACS-7381] tests fixes

* [ACS-7381] fix e2e tests

* [ACS-7381] update e2e tests

* [ACS-7381] update e2e tests

* [ACS-7381] update e2e tests

* [ACS-7381] update e2e tests

* [ACS-7381] update e2e tests

* [ACS-7381] fix for checkboxes

* [ACS-7381] fix e2e

* [ACS-7381] fix e2e

* [ACS-7381] fix e2e

* [ACS-7381] fix e2e

* [ACS-7381] fix for e2e

* [ACS-7381] fix for e2e
This commit is contained in:
tamaragruszka 2024-06-24 10:40:59 +02:00 committed by GitHub
parent 785b5821a0
commit f27d62585b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
82 changed files with 1398 additions and 1258 deletions

View File

@ -1,24 +1,24 @@
<div class="app-container">
<div
id="document-list-container"
class="app-document-list-container">
class="app-document-list-container"
id="document-list-container">
<adf-upload-drag-area
[disabled]="disableDragArea"
[acceptedFilesType]="getFileFiltering()"
[rootFolderId]="currentFolderId"
[versioning]="versioning"
[adf-check-allowable-operation]="'create'"
[adf-nodes]="disableDragArea ? getCurrentDocumentListNode() : []"
(updateFileVersion)="onUploadNewVersion($event)">
(updateFileVersion)="onUploadNewVersion($event)"
[acceptedFilesType]="getFileFiltering()"
[adf-check-allowable-operation]="'create'"
[adf-nodes]="disableDragArea ? getCurrentDocumentListNode() : []"
[disabled]="disableDragArea"
[rootFolderId]="currentFolderId"
[versioning]="versioning">
<div *ngIf="errorMessage" class="app-error-message">
<button (click)="resetError()" mat-icon-button>
<mat-icon>highlight_off</mat-icon>
</button>
<span class="app-error-message--text">{{errorMessage}}</span>
<span class="app-error-message--text">{{ errorMessage }}</span>
</div>
<adf-toolbar *ngIf="!disableDragArea" class="app-files-toolbar">
<adf-toolbar-title>
<adf-breadcrumb root="Personal Files" [target]="documentList">
<adf-breadcrumb [target]="documentList" root="Personal Files">
</adf-breadcrumb>
<adf-dropdown-breadcrumb [target]="documentList">
</adf-dropdown-breadcrumb>
@ -26,221 +26,223 @@
<div class="app-document-action-buttons">
<button
data-automation-id="create-new-folder"
mat-icon-button
[disabled]="!canCreateContent(documentList.folderNode)"
title="New folder"
(error)="openSnackMessageError($event)"
(success)="documentList.reload()"
[adf-create-folder]="currentFolderId">
[adf-create-folder]="currentFolderId"
[disabled]="!canCreateContent(documentList.folderNode)"
data-automation-id="create-new-folder"
mat-icon-button
title="New folder">
<mat-icon>create_new_folder</mat-icon>
</button>
<button mat-icon-button
<button [adfNodeDownload]="documentList.selection"
[disabled]="!hasSelection(documentList.selection)"
title="Download"
[adfNodeDownload]="documentList.selection">
mat-icon-button
title="Download">
<mat-icon>get_app</mat-icon>
</button>
<button mat-icon-button
data-automation-id="delete-toolbar-button"
adf-check-allowable-operation="delete"
[permanent]="true"
<button (delete)="onDeleteActionSuccess($event)"
[adf-delete]="documentList.selection"
[adf-nodes]="documentList.selection"
title="Delete"
(delete)="onDeleteActionSuccess($event)"
[adf-delete]="documentList.selection">
[permanent]="true"
adf-check-allowable-operation="delete"
data-automation-id="delete-toolbar-button"
mat-icon-button
title="Delete">
<mat-icon>delete</mat-icon>
</button>
</div>
<button mat-icon-button (click)="showVersions = !showVersions" class="app-show-versions-button"
title="Toggle metadata">
<button (click)="showVersions = !showVersions" class="app-show-versions-button" mat-icon-button
title="Toggle metadata">
<mat-icon>{{ showVersions ? 'chevron_right' : 'chevron_left' }}</mat-icon>
</button>
<adf-toolbar-divider class="app-toolbar-divider-before-more-menu"></adf-toolbar-divider>
<button class="app-toolbar-more-menu-button" mat-icon-button [matMenuTriggerFor]="menu">
<button [matMenuTriggerFor]="menu" class="app-toolbar-more-menu-button" mat-icon-button>
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item
adf-check-allowable-operation="delete"
<button (delete)="onDeleteActionSuccess($event)"
[adf-delete]="documentList.selection"
[adf-nodes]="documentList.selection"
(delete)="onDeleteActionSuccess($event)"
[adf-delete]="documentList.selection">
adf-check-allowable-operation="delete"
mat-menu-item>
<mat-icon>delete</mat-icon>
<span>Delete</span>
</button>
</mat-menu>
</adf-toolbar>
<div class="app-document-list-container-in-upload-drag-area app-document-list-container" [ngClass]="{'adf-sticky-document-list': stickyHeader }">
<div [ngClass]="{'adf-sticky-document-list': stickyHeader }"
class="app-document-list-container-in-upload-drag-area app-document-list-container">
<adf-document-list
#documentList
class="app-file-list-container"
[permissionsStyle]="permissionsStyle"
[currentFolderId]="currentFolderId"
[contextMenuActions]="true"
[contentActions]="true"
[allowDropFiles]="allowDropFiles"
[selectionMode]="selectionMode"
[multiselect]="multiselect"
[node]="nodeResult"
[includeFields]="includeFields"
[sorting]="sorting"
[sortingMode]="sortingMode"
[showHeader]="showHeader"
[stickyHeader]="stickyHeader"
[headerFilters]="headerFilters"
[filterValue]="paramValues"
(error)="onNavigationError($event)"
(success)="resetError()"
(ready)="emitReadyEvent($event)"
(preview)="showFile($event)"
(folderChange)="onFolderChange($event)"
(permissionError)="handlePermissionError($event)"
(name-click)="documentList.onNodeDblClick($any($event).detail?.node)"
(filterSelection)="onFilterSelected($event)">
#documentList
(error)="onNavigationError($event)"
(filterSelection)="onFilterSelected($event)"
(folderChange)="onFolderChange($event)"
(name-click)="documentList.onNodeDblClick($any($event).detail?.node)"
(permissionError)="handlePermissionError($event)"
(preview)="showFile($event)"
(ready)="emitReadyEvent($event)"
(success)="resetError()"
[allowDropFiles]="allowDropFiles"
[contentActions]="true"
[contextMenuActions]="true"
[currentFolderId]="currentFolderId"
[filterValue]="paramValues"
[headerFilters]="headerFilters"
[includeFields]="includeFields"
[multiselect]="multiselect"
[node]="nodeResult"
[permissionsStyle]="permissionsStyle"
[selectionMode]="selectionMode"
[showHeader]="showHeader"
[sortingMode]="sortingMode"
[sorting]="sorting"
[stickyHeader]="stickyHeader"
class="app-file-list-container">
<adf-custom-empty-content-template *ngIf="disableDragArea">
<div class="app-empty_template">
<div class="app-no-result-message">{{ 'SEARCH.NO_RESULT' | translate }}</div>
</div>
</adf-custom-empty-content-template>
<data-columns>
<data-column
key="$thumbnail"
type="image"
[sortable]="false">
</data-column>
<data-column
key="name"
sortingKey="name"
title="Display name"
class="adf-expand-cell-5">
</data-column>
<data-column
key="content.sizeInBytes"
title="Size"
type="fileSize"
sortingKey="sizeInBytes"
class="adf-ellipsis-cell">
</data-column>
<data-column
*ngIf="searchTerm"
key="search"
title="Search"
class="adf-expand-cell-3">
<ng-template let-entry="$implicit">
<div [innerHTML]="searchResultsHighlight(entry.row.node.entry.search) | highlight:searchTerm">
</div>
</ng-template>
</data-column>
<adf-custom-empty-content-template *ngIf="disableDragArea">
<div class="app-empty_template">
<div class="app-no-result-message">{{ 'SEARCH.NO_RESULT' | translate }}</div>
</div>
</adf-custom-empty-content-template>
<data-columns>
<data-column
[sortable]="false"
key="$thumbnail"
type="image">
</data-column>
<data-column
class="adf-expand-cell-5"
key="name"
sortingKey="name"
title="Display name">
</data-column>
<data-column
class="adf-ellipsis-cell"
key="content.sizeInBytes"
sortingKey="sizeInBytes"
title="Size"
type="fileSize">
</data-column>
<data-column
*ngIf="searchTerm"
class="adf-expand-cell-3"
key="search"
title="Search">
<ng-template let-entry="$implicit">
<div
[innerHTML]="searchResultsHighlight(entry.row.node.entry.search) | highlight:searchTerm">
</div>
</ng-template>
</data-column>
<data-column
class="app-full-width adf-ellipsis-cell adf-desktop-only"
title="Node id"
[sortable]="false"
key="id">
</data-column>
<data-column
[sortable]="false"
class="app-full-width adf-ellipsis-cell adf-desktop-only"
key="id"
title="Node id">
</data-column>
<data-column
title="Lock"
key="lock"
[focus]="false"
[sortable]="false"
class="adf-ellipsis-cell">
<ng-template let-entry="$implicit">
<button mat-icon-button [adf-node-lock]="entry.row.node.entry" class="app-lock-button">
<mat-icon *ngIf="entry.row.getValue('isLocked')">lock</mat-icon>
<mat-icon *ngIf="!entry.row.getValue('isLocked')">lock_open</mat-icon>
</button>
</ng-template>
</data-column>
<data-column
title="Created by"
key="createdByUser.displayName"
sortingKey="createdByUser"
class="adf-ellipsis-cell">
</data-column>
<data-column
title="Created"
key="createdAt"
sortingKey="createdAt"
type="date"
[format]="'timeAgo'"
class="adf-ellipsis-cell">
</data-column>
<data-column
[focus]="false"
[sortable]="false"
class="adf-ellipsis-cell"
key="lock"
title="Lock">
<ng-template let-entry="$implicit">
<button [adf-node-lock]="entry.row.node.entry" class="app-lock-button" mat-icon-button>
<mat-icon *ngIf="entry.row.getValue('isLocked')">lock</mat-icon>
<mat-icon *ngIf="!entry.row.getValue('isLocked')">lock_open</mat-icon>
</button>
</ng-template>
</data-column>
<data-column
class="adf-ellipsis-cell"
key="createdByUser.displayName"
sortingKey="createdByUser"
title="Created by">
</data-column>
<data-column
[format]="'timeAgo'"
class="adf-ellipsis-cell"
key="createdAt"
sortingKey="createdAt"
title="Created"
type="date">
</data-column>
</data-columns>
</data-columns>
<content-actions>
<content-action
icon="get_app"
title="Download"
handler="download">
</content-action>
<content-action
icon="delete"
permission="delete"
[disableWithNoPermission]="true"
title="Delete"
(permissionEvent)="handlePermissionError($event)"
(success)="onDeleteActionSuccess($event)"
handler="delete">
</content-action>
<content-action
icon="supervisor_account"
title="Permission"
permission="copy"
(error)="onContentActionError($event)"
(execute)="onPermissionRequested($event)">
</content-action>
<!-- document actions -->
<content-action
icon="storage"
target="document"
title="Manage versions"
(execute)="onManageVersions($event)">
</content-action>
<content-action
icon="beach_access"
target="document"
title="Update Aspects"
(execute)="onAspectUpdate($event)">
</content-action>
</content-actions>
</adf-document-list>
</div>
<content-actions>
<content-action
handler="download"
icon="get_app"
title="Download">
</content-action>
<content-action
(permissionEvent)="handlePermissionError($event)"
(success)="onDeleteActionSuccess($event)"
[disableWithNoPermission]="true"
handler="delete"
icon="delete"
permission="delete"
title="Delete">
</content-action>
<content-action
(error)="onContentActionError($event)"
(execute)="onPermissionRequested($event)"
icon="supervisor_account"
permission="copy"
title="Permission">
</content-action>
<!-- document actions -->
<content-action
(execute)="onManageVersions($event)"
icon="storage"
target="document"
title="Manage versions">
</content-action>
<content-action
(execute)="onAspectUpdate($event)"
icon="beach_access"
target="document"
title="Update Aspects">
</content-action>
</content-actions>
</adf-document-list>
</div>
<adf-pagination
[target]="documentList"
(changePageSize)="onChangePageSize($event)"
(changePageNumber)="onChangePageNumber($event)"
(changePageSize)="onChangePageSize($event)"
(nextPage)="onNextPage($event)"
(prevPage)="onPrevPage($event)">
(prevPage)="onPrevPage($event)"
[target]="documentList">
</adf-pagination>
</adf-upload-drag-area>
<adf-info-drawer-layout *ngIf="showVersions" class="app-manage-versions-sidebar">
<div info-drawer-content>
<adf-info-drawer [title]="'Details'" *ngIf="documentList.selection[0]">
<adf-info-drawer *ngIf="documentList.selection[0]" [title]="'Details'">
<adf-info-drawer-tab label="Properties">
<adf-content-metadata
[node]="documentList.selection[0].entry"
[displayCategories]="true"
[displayEmpty]="displayEmptyMetadata"
[displayTags]="true"
[displayCategories]="true">
[node]="documentList.selection[0].entry">
</adf-content-metadata>
</adf-info-drawer-tab>
<adf-info-drawer-tab label="Versions">
<ng-container *ngIf="hasOneFileSelected();else choose_document_template">
<ng-container *ngIf="userHasPermissionToManageVersions(); else no_permission_to_versions">
<adf-version-manager
[allowDownload]="allowVersionDownload"
[node]="documentList.selection[0].entry"
[showComments]="true"
[allowDownload]="allowVersionDownload">
[showComments]="true">
</adf-version-manager>
</ng-container>
</ng-container>
@ -277,37 +279,37 @@
<div class="app-container">
<section>
<mat-slide-toggle data-automation-id="multiSelectToggle" [(ngModel)]="multiselect">
<mat-slide-toggle [(ngModel)]="multiselect" data-automation-id="multiSelectToggle">
Multiselect (with checkboxes)
</mat-slide-toggle>
</section>
<section>
<mat-slide-toggle id="adf-multiple-upload-switch" [(ngModel)]="multipleFileUpload" >
<mat-slide-toggle [(ngModel)]="multipleFileUpload" id="adf-multiple-upload-switch">
Multiple File Upload
</mat-slide-toggle>
</section>
<section>
<mat-slide-toggle id="adf-folder-upload-switch" [(ngModel)]="folderUpload">
<mat-slide-toggle [(ngModel)]="folderUpload" id="adf-folder-upload-switch">
Folder upload
</mat-slide-toggle>
</section>
<section>
<mat-slide-toggle id="adf-extension-filter-upload-switch" [(ngModel)]="acceptedFilesTypeShow">
<mat-slide-toggle [(ngModel)]="acceptedFilesTypeShow" id="adf-extension-filter-upload-switch">
Custom extensions filter
</mat-slide-toggle>
</section>
<section>
<mat-slide-toggle id="adf-max-size-filter-upload-switch" [(ngModel)]="maxSizeShow">
<mat-slide-toggle [(ngModel)]="maxSizeShow" id="adf-max-size-filter-upload-switch">
Max size filter
</mat-slide-toggle>
</section>
<section>
<mat-slide-toggle id="adf-version-upload-switch" [(ngModel)]="versioning">
<mat-slide-toggle [(ngModel)]="versioning" id="adf-version-upload-switch">
Enable versioning
</mat-slide-toggle>
</section>
@ -333,48 +335,48 @@
<h5>Upload</h5>
<section *ngIf="acceptedFilesTypeShow">
<mat-form-field floatPlaceholder="float">
<input matInput
placeholder="Extension accepted"
[(ngModel)]="acceptedFilesType"
data-automation-id="accepted-files-type">
<input [(ngModel)]="acceptedFilesType"
data-automation-id="accepted-files-type"
matInput
placeholder="Extension accepted">
</mat-form-field>
</section>
<section *ngIf="maxSizeShow">
<mat-form-field>
<input matInput type="number" placeholder="Max file size" [(ngModel)]="maxFilesSize"
data-automation-id="max-files-size">
<input [(ngModel)]="maxFilesSize" data-automation-id="max-files-size" matInput placeholder="Max file size"
type="number">
</mat-form-field>
</section>
<div *ngIf="!acceptedFilesTypeShow">
<adf-upload-button
[disabled]="!enableUpload"
[rootFolderId]="documentList.currentFolderId"
[multipleFiles]="multipleFileUpload"
[uploadFolders]="folderUpload"
[maxFilesSize]="maxSizeShow ? maxFilesSize : null"
(error)="openSnackMessageError($event)"
[versioning]="versioning"
(permissionEvent)="handlePermissionError($event)"
[adf-check-allowable-operation]="'create'"
[adf-nodes]="enableUpload ? getCurrentDocumentListNode() : []"
(permissionEvent)="handlePermissionError($event)">
[disabled]="!enableUpload"
[maxFilesSize]="maxSizeShow ? maxFilesSize : null"
[multipleFiles]="multipleFileUpload"
[rootFolderId]="documentList.currentFolderId"
[uploadFolders]="folderUpload"
[versioning]="versioning">
</adf-upload-button>
</div>
<div *ngIf="acceptedFilesTypeShow">
<adf-upload-button
[disabled]="!enableUpload"
[rootFolderId]="documentList.currentFolderId"
[acceptedFilesType]="acceptedFilesType"
[multipleFiles]="multipleFileUpload"
[uploadFolders]="folderUpload"
[versioning]="versioning"
(error)="openSnackMessageError($event)"
(permissionEvent)="handlePermissionError($event)"
[acceptedFilesType]="acceptedFilesType"
[adf-check-allowable-operation]="'create'"
[adf-nodes]="enableUpload ? getCurrentDocumentListNode() : []"
(permissionEvent)="handlePermissionError($event)">
[disabled]="!enableUpload"
[multipleFiles]="multipleFileUpload"
[rootFolderId]="documentList.currentFolderId"
[uploadFolders]="folderUpload"
[versioning]="versioning">
</adf-upload-button>
</div>
<section>
<mat-checkbox id="adf-disable-upload" [(ngModel)]="enableUpload">
<mat-checkbox [(ngModel)]="enableUpload" id="adf-disable-upload">
Enable upload
</mat-checkbox>
</section>
@ -383,9 +385,9 @@
<div class="app-p-10">
<p>Use Cmd (Mac) or Ctrl (Windows) to toggle selection of multiple items</p>
<mat-form-field>
<mat-select placeholder="Selection Mode" [(ngModel)]="selectionMode" name="food">
<mat-select [(ngModel)]="selectionMode" name="food" placeholder="Selection Mode">
<mat-option *ngFor="let mode of selectionModes" [value]="mode.value">
{{mode.viewValue}}
{{ mode.viewValue }}
</mat-option>
</mat-select>
</mat-form-field>

View File

@ -15,11 +15,11 @@
* limitations under the License.
*/
import { BrowserActions, createApiService, LoginPage, UploadActions, UserModel, UsersActions, ViewerPage } from '@alfresco/adf-testing';
import { browser, by, element, protractor } from 'protractor';
import { createApiService, BrowserActions, LoginPage, UploadActions, UserModel, UsersActions, ViewerPage } from '@alfresco/adf-testing';
import { ContentServicesPage } from '../../core/pages/content-services.page';
import { FileModel } from '../../models/ACS/file.model';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
import { FileModel } from '../../models/ACS/file.model';
describe('Content Services Viewer', () => {
const acsUser = new UserModel();
@ -362,7 +362,7 @@ describe('Content Services Viewer', () => {
});
it('[C269109] Should not be able to open thumbnail panel before the pdf is loaded', async () => {
const fileView = element.all(by.css(`#document-list-container div[data-automation-id="${pdfFile.name}"]`)).first();
const fileView = element.all(by.css(`#document-list-container td[data-automation-id="${pdfFile.name}"]`)).first();
await BrowserActions.click(fileView);
await browser.actions().sendKeys(protractor.Key.ENTER).perform();

View File

@ -271,7 +271,7 @@ export class ContentServicesPage {
}
async checkLockIsDisplayedForElement(name: string): Promise<void> {
const lockButton = $(`div.adf-datatable-cell[data-automation-id="${name}"] button`);
const lockButton = $(`td.adf-datatable-cell[data-automation-id="${name}"] button`);
await BrowserVisibility.waitUntilElementIsVisible(lockButton);
}
@ -290,7 +290,7 @@ export class ContentServicesPage {
async getAttributeValueForElement(elementName: string, propertyName: string): Promise<string> {
const elementSize = $(
`.app-document-list-container div.adf-datatable-cell[data-automation-id="${elementName}"][title="${propertyName}"] span`
`.app-document-list-container td.adf-datatable-cell[data-automation-id="${elementName}"][title="${propertyName}"] span`
);
return BrowserActions.getText(elementSize);
}
@ -306,7 +306,7 @@ export class ContentServicesPage {
}
async selectFolder(folderName: string): Promise<void> {
const folderSelected = $(`div[data-automation-id="${folderName}"] .adf-datatable-center-img-ie`);
const folderSelected = $(`td[data-automation-id="${folderName}"] .adf-datatable-center-img-ie`);
await BrowserVisibility.waitUntilElementIsVisible(folderSelected);
await BrowserActions.click(folderSelected);
}

View File

@ -32,7 +32,7 @@ export class NavigationBarPage {
async clickNavigationBarItem(title: string, untilElementIsVisible?: ElementFinder): Promise<void> {
Logger.log(`clickNavigationBarItem ${title}`);
const menu = $(`.app-sidenav-link[data-automation-id="${title}"]`);
const menu = this.getMenuItemLocator(title);
await BrowserActions.closeMenuAndDialogs();
if (untilElementIsVisible) {

View File

@ -20,13 +20,12 @@ import * as path from 'path';
import { BrowserVisibility, BrowserActions } from '@alfresco/adf-testing';
export class AttachmentListPage {
attachFileButton = $('input[type=\'file\']');
buttonMenu = $('button[data-automation-id=\'action_menu_0\']');
viewButton = $('button[data-automation-id*=\'MENU_ACTIONS.VIEW_CONTENT\']');
removeButton = $('button[data-automation-id*=\'MENU_ACTIONS.REMOVE_CONTENT\']');
downloadButton = $('button[data-automation-id*=\'MENU_ACTIONS.DOWNLOAD_CONTENT\']');
noContentContainer = $('div[class*=\'adf-no-content-container\']');
attachFileButton = $('input[type="file"]');
buttonMenu = $('button[data-automation-id="action_menu_0"]');
viewButton = $('button[data-automation-id*="MENU_ACTIONS.VIEW_CONTENT"]');
removeButton = $('button[data-automation-id*="MENU_ACTIONS.REMOVE_CONTENT"]');
downloadButton = $('button[data-automation-id*="MENU_ACTIONS.DOWNLOAD_CONTENT"]');
noContentContainer = $('td[class*="adf-no-content-container"]');
async checkEmptyAttachmentList(): Promise<void> {
await BrowserVisibility.waitUntilElementIsVisible(this.noContentContainer);
@ -39,7 +38,7 @@ export class AttachmentListPage {
}
async checkFileIsAttached(name: string): Promise<void> {
const fileAttached = $$('div[data-automation-id="' + name + '"]').first();
const fileAttached = $$('td[data-automation-id="' + name + '"]').first();
await BrowserVisibility.waitUntilElementIsVisible(fileAttached);
}
@ -49,7 +48,7 @@ export class AttachmentListPage {
async viewFile(name: string): Promise<void> {
await BrowserActions.closeMenuAndDialogs();
await BrowserActions.click($$('div[data-automation-id="' + name + '"]').first());
await BrowserActions.click($$('td[data-automation-id="' + name + '"]').first());
await BrowserActions.click(this.buttonMenu);
await browser.sleep(500);
await BrowserActions.click(this.viewButton);
@ -58,7 +57,7 @@ export class AttachmentListPage {
async removeFile(name: string): Promise<void> {
await BrowserActions.closeMenuAndDialogs();
await BrowserActions.click($$('div[data-automation-id="' + name + '"]').first());
await BrowserActions.click($$('td[data-automation-id="' + name + '"]').first());
await BrowserActions.click(this.buttonMenu);
await browser.sleep(500);
await BrowserActions.click(this.removeButton);
@ -67,7 +66,7 @@ export class AttachmentListPage {
async downloadFile(name: string): Promise<void> {
await BrowserActions.closeMenuAndDialogs();
await BrowserActions.click($$('div[data-automation-id="' + name + '"]').first());
await BrowserActions.click($$('td[data-automation-id="' + name + '"]').first());
await BrowserActions.click(this.buttonMenu);
await browser.sleep(500);
await BrowserActions.click(this.downloadButton);
@ -75,15 +74,14 @@ export class AttachmentListPage {
async doubleClickFile(name: string): Promise<void> {
await BrowserActions.closeMenuAndDialogs();
await BrowserVisibility.waitUntilElementIsVisible($$(`div[data-automation-id="${name}"]`).first());
const fileAttached = $$(`div[data-automation-id="${name}"]`).first();
await BrowserVisibility.waitUntilElementIsVisible($$(`td[data-automation-id="${name}"]`).first());
const fileAttached = $$(`td[data-automation-id="${name}"]`).first();
await BrowserActions.click(fileAttached);
await browser.actions().sendKeys(protractor.Key.ENTER).perform();
}
async checkFileIsRemoved(name: string): Promise<void> {
const fileAttached = $$(`div[data-automation-id="${name}"]`).first();
const fileAttached = $$(`td[data-automation-id="${name}"]`).first();
await BrowserVisibility.waitUntilElementIsNotVisible(fileAttached);
}
}

View File

@ -1907,11 +1907,11 @@ describe('DocumentListComponent rendering', () => {
const rows = fixture.nativeElement.querySelectorAll('.adf-datatable-body adf-datatable-row');
expect(rows).toBeDefined();
expect(rows.length).toBe(3);
const cell1 = fixture.nativeElement.querySelector('div[title="Name"][data-automation-id="Name 1"]');
const cell1 = fixture.nativeElement.querySelector('td[title="Name"][data-automation-id="Name 1"]');
expect(cell1.innerText).toBe('Name 1');
const cell2 = fixture.nativeElement.querySelector('div[title="Name"][data-automation-id="Name 2"]');
const cell2 = fixture.nativeElement.querySelector('td[title="Name"][data-automation-id="Name 2"]');
expect(cell2.innerText).toBe('Name 2');
const cell3 = fixture.nativeElement.querySelector('div[title="Id"][data-automation-id="Name 3"]');
const cell3 = fixture.nativeElement.querySelector('td[title="Id"][data-automation-id="Name 3"]');
expect(cell3.innerText).toBe('3');
});
});

View File

@ -1,10 +1,11 @@
<ng-container *ngIf="value$ | async as amount">
<span [title]="amount">
{{ amount | currency:
(currencyConfig?.code || defaultCurrencyConfig.code):
(currencyConfig?.display || defaultCurrencyConfig.display):
(currencyConfig?.digitsInfo || defaultCurrencyConfig.digitsInfo):
(currencyConfig?.locale || defaultCurrencyConfig.locale)
{{
amount | currency:
(currencyConfig?.code || defaultCurrencyConfig.code):
(currencyConfig?.display || defaultCurrencyConfig.display):
(currencyConfig?.digitsInfo || defaultCurrencyConfig.digitsInfo):
(currencyConfig?.locale || defaultCurrencyConfig.locale)
}}
</span>
</ng-container>

View File

@ -15,13 +15,13 @@
* limitations under the License.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AmountCellComponent } from './amount-cell.component';
import { CurrencyConfig } from '../../data/data-column.model';
import { BehaviorSubject } from 'rxjs';
import { LOCALE_ID } from '@angular/core';
import { registerLocaleData } from '@angular/common';
import localePL from '@angular/common/locales/pl';
import { LOCALE_ID } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BehaviorSubject } from 'rxjs';
import { CurrencyConfig } from '../../data/data-column.model';
import { AmountCellComponent } from './amount-cell.component';
describe('AmountCellComponent', () => {
let component: AmountCellComponent;
@ -58,7 +58,14 @@ describe('AmountCellComponent', () => {
});
it('should render currency value with custom currency code', () => {
renderAndCheckCurrencyValue({ code: 'MY CUSTOM CURRENCY', display: 'symbol' }, 123.45, 'MY CUSTOM CURRENCY123.45');
renderAndCheckCurrencyValue(
{
code: 'MY CUSTOM CURRENCY',
display: 'symbol'
},
123.45,
'MY CUSTOM CURRENCY123.45'
);
});
it('should render currency value with custom display code', () => {

View File

@ -15,15 +15,15 @@
* limitations under the License.
*/
import { ChangeDetectionStrategy, Component, ViewEncapsulation, Input, OnInit, DEFAULT_CURRENCY_CODE, inject } from '@angular/core';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
import { AsyncPipe, CurrencyPipe, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, Component, DEFAULT_CURRENCY_CODE, inject, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { CurrencyConfig } from '../../data/data-column.model';
import { CommonModule } from '@angular/common';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
@Component({
standalone: true,
imports: [CommonModule],
selector: 'adf-amount-cell',
standalone: true,
imports: [AsyncPipe, CurrencyPipe, NgIf],
templateUrl: './amount-cell.component.html',
host: { class: 'adf-datatable-content-cell' },
encapsulation: ViewEncapsulation.None,

View File

@ -16,9 +16,9 @@
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BooleanCellComponent } from './boolean-cell.component';
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
import { ObjectDataColumn } from '../../data/object-datacolumn.model';
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
import { BooleanCellComponent } from './boolean-cell.component';
describe('BooleanCellComponent', () => {
let component: BooleanCellComponent;

View File

@ -15,15 +15,15 @@
* limitations under the License.
*/
import { AsyncPipe, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation } from '@angular/core';
import { BooleanPipe } from '../../../pipes';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
import { CommonModule } from '@angular/common';
import { BooleanPipe } from '../../../pipes/boolean.pipe';
@Component({
standalone: true,
imports: [CommonModule, BooleanPipe],
selector: 'adf-boolean-cell',
standalone: true,
imports: [AsyncPipe, BooleanPipe, NgIf],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<ng-container *ngIf="value$ | async | adfBoolean as value">
@ -36,7 +36,6 @@ import { BooleanPipe } from '../../../pipes/boolean.pipe';
host: { class: 'adf-datatable-content-cell' }
})
export class BooleanCellComponent extends DataTableCellComponent implements OnInit {
ngOnInit() {
super.ngOnInit();
}

View File

@ -1,21 +1,17 @@
<div
class="adf-columns-selector"
data-automation-id="adf-columns-selector"
tabindex="0"
role="button"
(keyup.enter)="$event.stopPropagation()"
(click)="$event.stopPropagation();"
>
<div class="adf-columns-selector"
data-automation-id="adf-columns-selector"
tabindex="0"
role="button"
(keyup.enter)="$event.stopPropagation()"
(click)="$event.stopPropagation();">
<div class="adf-columns-selector-header">
<span class="adf-columns-selector-header-label">
{{"ADF-DATATABLE.COLUMNS_SELECTOR.COLUMNS" | translate}}
{{ 'ADF-DATATABLE.COLUMNS_SELECTOR.COLUMNS' | translate }}
</span>
<button
data-automation-id="adf-columns-selector-close-button"
mat-icon-button
(click)="closeMenu()"
>
<button data-automation-id="adf-columns-selector-close-button"
mat-icon-button
(click)="closeMenu()">
<mat-icon>close</mat-icon>
</button>
</div>
@ -23,32 +19,28 @@
<mat-divider class="adf-columns-selector-divider"></mat-divider>
<div class="adf-columns-selector-search-input-container">
<mat-icon
class="adf-columns-selector-search-input-icon">
<mat-icon class="adf-columns-selector-search-input-icon">
search
</mat-icon>
<input
[formControl]="searchInputControl"
class="adf-columns-selector-search-input"
data-automation-id="adf-columns-selector-search-input"
type="text"
[placeholder]='"ADF-DATATABLE.COLUMNS_SELECTOR.SEARCH" | translate'>
<input [formControl]="searchInputControl"
class="adf-columns-selector-search-input"
data-automation-id="adf-columns-selector-search-input"
type="text"
[placeholder]="'ADF-DATATABLE.COLUMNS_SELECTOR.SEARCH' | translate">
</div>
<div class="adf-columns-selector-list-container">
<ng-container *ngFor="let column of columnItems">
<div
*ngIf="(column.title | translate | filterString:searchQuery) as translatedTitle"
class="adf-columns-selector-list-item">
<mat-checkbox
color="primary"
class="adf-columns-selector-column-checkbox"
[attr.data-automation-id]="'adf-columns-selector-column-checkbox-' + column.title"
[checked]="!column.isHidden"
[disabled]="isCheckboxDisabled(column)"
(change)="changeColumnVisibility(column)">
<div class="adf-columns-selector-list-content">{{translatedTitle}}</div>
<div *ngIf="(column.title | translate | filterString:searchQuery) as translatedTitle"
class="adf-columns-selector-list-item">
<mat-checkbox color="primary"
class="adf-columns-selector-column-checkbox"
[attr.data-automation-id]="'adf-columns-selector-column-checkbox-' + column.title"
[checked]="!column.isHidden"
[disabled]="isCheckboxDisabled(column)"
(change)="changeColumnVisibility(column)">
<div class="adf-columns-selector-list-content">{{ translatedTitle }}</div>
</mat-checkbox>
</div>
</ng-container>
@ -57,12 +49,11 @@
<mat-divider class="adf-columns-selector-divider"></mat-divider>
<div class="adf-columns-selector-footer">
<button
mat-flat-button
data-automation-id="adf-columns-selector-apply-button"
color="primary"
(click)="apply()">
{{"ADF-DATATABLE.COLUMNS_SELECTOR.APPLY" | translate}}
<button mat-flat-button
data-automation-id="adf-columns-selector-apply-button"
color="primary"
(click)="apply()">
{{ 'ADF-DATATABLE.COLUMNS_SELECTOR.APPLY' | translate }}
</button>
</div>
</div>

View File

@ -15,16 +15,16 @@
* limitations under the License.
*/
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { ColumnsSelectorComponent } from './columns-selector.component';
import { DataColumn } from '../../data/data-column.model';
import { Observable, Subject } from 'rxjs';
import { MatMenuTrigger } from '@angular/material/menu';
import { CoreTestingModule } from '../../../testing';
import { By } from '@angular/platform-browser';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
import { MatMenuTrigger } from '@angular/material/menu';
import { By } from '@angular/platform-browser';
import { Observable, Subject } from 'rxjs';
import { CoreTestingModule } from '../../../testing';
import { DataColumn } from '../../data/data-column.model';
import { ColumnsSelectorComponent } from './columns-selector.component';
describe('ColumnsSelectorComponent', () => {
let fixture: ComponentFixture<ColumnsSelectorComponent>;
@ -40,8 +40,7 @@ describe('ColumnsSelectorComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CoreTestingModule],
declarations: [ColumnsSelectorComponent]
imports: [CoreTestingModule, ColumnsSelectorComponent]
}).compileComponents();
fixture = TestBed.createComponent(ColumnsSelectorComponent);

View File

@ -15,16 +15,36 @@
* limitations under the License.
*/
import { NgForOf, NgIf } from '@angular/common';
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { ReactiveFormsModule, UntypedFormControl } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuTrigger } from '@angular/material/menu';
import { TranslateModule } from '@ngx-translate/core';
import { Subject } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators';
import { FilterStringPipe } from '../../../pipes';
import { DataColumn } from '../../data/data-column.model';
@Component({
selector: 'adf-datatable-column-selector',
standalone: true,
templateUrl: './columns-selector.component.html',
styleUrls: ['./columns-selector.component.scss'],
imports: [
MatButtonModule,
TranslateModule,
MatIconModule,
MatDividerModule,
ReactiveFormsModule,
MatCheckboxModule,
NgIf,
NgForOf,
FilterStringPipe
],
encapsulation: ViewEncapsulation.None
})
export class ColumnsSelectorComponent implements OnInit, OnDestroy {
@ -49,23 +69,16 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
searchQuery = '';
ngOnInit(): void {
this.mainMenuTrigger.menuOpened.pipe(
takeUntil(this.onDestroy$)
).subscribe(() => {
const columns = this.columns.map(column => ({...column}));
this.mainMenuTrigger.menuOpened.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
const columns = this.columns.map((column) => ({ ...column }));
this.columnItems = this.columnsSorting ? this.sortColumns(columns) : columns;
});
this.mainMenuTrigger.menuClosed.pipe(
takeUntil(this.onDestroy$)
).subscribe(() => {
this.mainMenuTrigger.menuClosed.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
this.searchInputControl.setValue('');
});
this.searchInputControl.valueChanges.pipe(
debounceTime(300),
takeUntil(this.onDestroy$)
).subscribe((searchQuery) => {
this.searchInputControl.valueChanges.pipe(debounceTime(300), takeUntil(this.onDestroy$)).subscribe((searchQuery) => {
this.searchQuery = searchQuery;
});
}
@ -89,12 +102,16 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
}
isCheckboxDisabled(column: DataColumn): boolean {
return this.maxColumnsVisible && column.isHidden && this.maxColumnsVisible === this.columnItems.filter(dataColumn => !dataColumn.isHidden).length;
return (
this.maxColumnsVisible &&
column.isHidden &&
this.maxColumnsVisible === this.columnItems.filter((dataColumn) => !dataColumn.isHidden).length
);
}
private sortColumns(columns: DataColumn[]): DataColumn[] {
const shownColumns = columns.filter(column => !column.isHidden);
const hiddenColumns = columns.filter(column => column.isHidden);
const shownColumns = columns.filter((column) => !column.isHidden);
const hiddenColumns = columns.filter((column) => column.isHidden);
return [...shownColumns, ...hiddenColumns];
}

View File

@ -0,0 +1,16 @@
<ng-container>
<span *ngIf="copyContent; else defaultCell"
adf-clipboard="CLIPBOARD.CLICK_TO_COPY"
[clipboard-notification]="'CLIPBOARD.SUCCESS_COPY'"
[attr.aria-label]="value$ | async"
[title]="tooltip"
class="adf-datatable-cell-value">
{{ value$ | async }}
</span>
</ng-container>
<ng-template #defaultCell>
<span [title]="tooltip"
class="adf-datatable-cell-value">
{{ value$ | async }}
</span>
</ng-template>

View File

@ -16,12 +16,12 @@
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DataTableCellComponent } from './datatable-cell.component';
import { DataRow } from '../../data/data-row.model';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { DataTableService } from '../../services/datatable.service';
import { DataRow } from '../../data/data-row.model';
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
import { DataTableService } from '../../services/datatable.service';
import { mockCarsData, mockCarsSchemaDefinition } from '../mocks/datatable.mock';
import { DataTableCellComponent } from './datatable-cell.component';
describe('DataTableCellComponent', () => {
let component: DataTableCellComponent;
@ -51,7 +51,7 @@ describe('DataTableCellComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [DataTableCellComponent],
imports: [DataTableCellComponent],
providers: [DataTableService]
});

View File

@ -15,34 +15,23 @@
* limitations under the License.
*/
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation, OnDestroy, inject } from '@angular/core';
import { AsyncPipe, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, Component, inject, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { BehaviorSubject, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { ClipboardModule } from '../../../clipboard';
import { DataColumn } from '../../data/data-column.model';
import { DataRow } from '../../data/data-row.model';
import { DataTableAdapter } from '../../data/datatable-adapter';
import { BehaviorSubject, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { DataTableService } from '../../services/datatable.service';
@Component({
selector: 'adf-datatable-cell',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<ng-container>
<span
*ngIf="copyContent; else defaultCell"
adf-clipboard="CLIPBOARD.CLICK_TO_COPY"
[clipboard-notification]="'CLIPBOARD.SUCCESS_COPY'"
[attr.aria-label]="value$ | async"
[title]="tooltip"
class="adf-datatable-cell-value"
>{{ value$ | async }}</span
>
</ng-container>
<ng-template #defaultCell>
<span [title]="tooltip" class="adf-datatable-cell-value">{{ value$ | async }}</span>
</ng-template>
`,
templateUrl: './datatable-cell.component.html',
encapsulation: ViewEncapsulation.None,
imports: [ClipboardModule, AsyncPipe, NgIf],
host: { class: 'adf-datatable-content-cell' }
})
export class DataTableCellComponent implements OnInit, OnDestroy {

View File

@ -15,9 +15,9 @@
* limitations under the License.
*/
import { DataTableRowComponent } from './datatable-row.component';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DataRow } from '../../data/data-row.model';
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { DataTableRowComponent } from './datatable-row.component';
describe('DataTableRowComponent', () => {
let fixture: ComponentFixture<DataTableRowComponent>;
@ -31,7 +31,7 @@ describe('DataTableRowComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [DataTableRowComponent]
imports: [DataTableRowComponent]
});
fixture = TestBed.createComponent(DataTableRowComponent);
@ -51,16 +51,14 @@ describe('DataTableRowComponent', () => {
component.row = row;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.classList.contains('adf-is-selected'))
.not.toBe(true);
expect(fixture.debugElement.nativeElement.classList.contains('adf-is-selected')).not.toBe(true);
});
it('should not have select class when row data is null', () => {
row.isSelected = false;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.classList.contains('adf-is-selected'))
.not.toBe(true);
expect(fixture.debugElement.nativeElement.classList.contains('adf-is-selected')).not.toBe(true);
});
it('should set aria selected to true when row is selected', () => {

View File

@ -15,21 +15,13 @@
* limitations under the License.
*/
import {
Component,
ViewEncapsulation,
ElementRef,
Input,
HostBinding,
HostListener,
Output,
EventEmitter
} from '@angular/core';
import { FocusableOption } from '@angular/cdk/a11y';
import { Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, Output, ViewEncapsulation } from '@angular/core';
import { DataRow } from '../../data/data-row.model';
@Component({
selector: 'adf-datatable-row',
standalone: true,
template: `<ng-content></ng-content>`,
encapsulation: ViewEncapsulation.None,
host: {
@ -57,13 +49,13 @@ export class DataTableRowComponent implements FocusableOption {
@HostBinding('attr.aria-selected')
get isAriaSelected(): boolean {
if (!this.row) {
return false;
return false;
}
return this.row.isSelected;
}
@HostBinding('attr.aria-label')
get ariaLabel(): string|null {
get ariaLabel(): string | null {
if (!this.row) {
return null;
}
@ -75,7 +67,7 @@ export class DataTableRowComponent implements FocusableOption {
}
@HostBinding('attr.tabindex')
get tabindex(): number|null {
get tabindex(): number | null {
return this.disabled ? null : 0;
}

View File

@ -1,406 +1,412 @@
<div
role="grid"
*ngIf="data"
class="adf-full-width adf-datatable-list"
[class.adf-sticky-header]="isStickyHeaderEnabled()"
[class.adf-datatable--empty]="(isEmpty() && !isHeaderVisible()) || loading"
[class.adf-datatable--empty--header-visible]="isEmpty() && isHeaderVisible()">
<div *ngIf="isHeaderVisible()" class="adf-datatable-header" role="rowgroup" [ngClass]="{ 'adf-sr-only': !isHeaderVisible() }">
<adf-datatable-row
cdkDropList
cdkDropListOrientation="horizontal"
[cdkDropListSortPredicate]="filterDisabledColumns"
data-automation-id="datatable-row-header"
[disabled]="!isHeaderVisible()"
class="adf-datatable-row"
role="row">
<div *ngIf="data"
role="table"
class="adf-full-width adf-datatable-list"
[class.adf-sticky-header]="isStickyHeaderEnabled()"
[class.adf-datatable--empty]="(isEmpty() && !isHeaderVisible()) || loading"
[class.adf-datatable--empty--header-visible]="isEmpty() && isHeaderVisible()">
<thead *ngIf="isHeaderVisible()"
class="adf-datatable-header"
[ngClass]="{ 'adf-sr-only': !isHeaderVisible() }">
<adf-datatable-row cdkDropList
cdkDropListOrientation="horizontal"
[cdkDropListSortPredicate]="filterDisabledColumns"
data-automation-id="datatable-row-header"
[disabled]="!isHeaderVisible()"
class="adf-datatable-row">
<!-- Actions (left) -->
<div *ngIf="actions && actionsPosition === 'left'" class="adf-actions-column adf-datatable-cell-header">
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate }}</span>
</div>
<!-- Actions (left) -->
<th *ngIf="actions && actionsPosition === 'left'"
class="adf-actions-column adf-datatable-cell-header"
[attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate">
</th>
<!-- Columns -->
<div *ngIf="multiselect" class="adf-datatable-cell-header adf-datatable-checkbox">
<mat-checkbox [indeterminate]="isSelectAllIndeterminate" [checked]="isSelectAllChecked" (change)="onSelectAllClick($event)" class="adf-checkbox-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.SELECT_ALL' | translate }}</mat-checkbox>
</div>
<!-- Columns -->
<th *ngIf="multiselect"
class="adf-datatable-cell-header adf-datatable-checkbox">
<mat-checkbox [indeterminate]="isSelectAllIndeterminate"
[checked]="isSelectAllChecked"
(change)="onSelectAllClick($event)"
[attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.SELECT_ALL' | translate"
[matTooltip]="'ADF-DATATABLE.ACCESSIBILITY.SELECT_ALL' | translate">
</mat-checkbox>
</th>
<div
class="adf-datatable-cell--{{col.type || 'text'}} {{col.cssClass}} adf-datatable-cell-header adf-datatable-cell-data"
*ngFor="
let col of (data.getColumns() | filterOutEvery:'isHidden':true);
let columnIndex = index
let lastColumn = last"
[attr.data-automation-id]="'auto_id_' + col.key"
[ngClass]="{
'adf-sortable': col.sortable,
'adf-datatable__cursor--pointer': !isResizing,
'adf-datatable__header--sorted-asc': isColumnSorted(col, 'asc'),
'adf-datatable__header--sorted-desc': isColumnSorted(col, 'desc')}"
[ngStyle]="(col.width) && !lastColumn && {'flex': getFlexValue(col)}"
[attr.aria-label]="col.title | translate"
(click)="onColumnHeaderClick(col, $event)"
(keyup.enter)="onColumnHeaderClick(col, $event)"
role="columnheader"
[attr.tabindex]="isHeaderVisible() ? 0 : null"
[attr.aria-sort]="col.sortable ? (getAriaSort(col) | translate) : null"
cdkDrag
cdkDragLockAxis="x"
(cdkDragStarted)="isDraggingHeaderColumn = true"
(cdkDragDropped)="onDropHeaderColumn($event)"
[cdkDragDisabled]="!col.draggable"
(mouseenter)="hoveredHeaderColumnIndex = columnIndex"
(mouseleave)="hoveredHeaderColumnIndex = -1"
adf-drop-zone dropTarget="header" [dropColumn]="col">
<th class="adf-datatable-cell--{{ col.type || 'text' }} {{ col.cssClass }} adf-datatable-cell-header adf-datatable-cell-data"
*ngFor="
let col of (data.getColumns() | filterOutEvery:'isHidden':true);
let columnIndex = index
let lastColumn = last"
[attr.data-automation-id]="'auto_id_' + col.key"
[ngClass]="{
'adf-sortable': col.sortable,
'adf-datatable__cursor--pointer': !isResizing,
'adf-datatable__header--sorted-asc': isColumnSorted(col, 'asc'),
'adf-datatable__header--sorted-desc': isColumnSorted(col, 'desc')}"
[ngStyle]="(col.width) && !lastColumn && {'flex': getFlexValue(col)}"
[attr.aria-label]="col.title | translate"
(click)="onColumnHeaderClick(col, $event)"
(keyup.enter)="onColumnHeaderClick(col, $event)"
[attr.tabindex]="isHeaderVisible() ? 0 : null"
[attr.aria-sort]="col.sortable ? (getAriaSort(col) | translate) : null"
cdkDrag
cdkDragLockAxis="x"
[cdkDragPreviewClass]="'adf-drag-preview'"
(cdkDragStarted)="isDraggingHeaderColumn = true"
(cdkDragDropped)="onDropHeaderColumn($event)"
[cdkDragDisabled]="!col.draggable"
(mouseenter)="hoveredHeaderColumnIndex = columnIndex"
(mouseleave)="hoveredHeaderColumnIndex = -1"
adf-drop-zone
dropTarget="header"
[dropColumn]="col">
<div
adf-resizable
#resizableElement="adf-resizable"
[coverPadding]="10"
(resizing)="onResizing($event, columnIndex)"
(resizeStart)="resizingColumnIndex = columnIndex"
(resizeEnd)="onResizingEnd()"
[attr.data-automation-id]="'auto_header_content_id_' + col.key"
class="adf-datatable-cell-header-content"
[ngClass]="{ 'adf-datatable-cell-header-content--hovered':
hoveredHeaderColumnIndex === columnIndex &&
!isDraggingHeaderColumn &&
!isResizing && col.sortable}"
>
<ng-container *ngIf="!col.header">
<span *ngIf="col.title" matTooltip="{{col.title | translate}}" class="adf-datatable-cell-value">{{col.title | translate}}</span>
<div adf-resizable
#resizableElement="adf-resizable"
[coverPadding]="10"
(resizing)="onResizing($event, columnIndex)"
(resizeStart)="resizingColumnIndex = columnIndex"
(resizeEnd)="onResizingEnd()"
[attr.data-automation-id]="'auto_header_content_id_' + col.key"
class="adf-datatable-cell-header-content"
[ngClass]="{ 'adf-datatable-cell-header-content--hovered':
hoveredHeaderColumnIndex === columnIndex &&
!isDraggingHeaderColumn &&
!isResizing && col.sortable}">
<ng-container *ngIf="!col.header">
<span *ngIf="col.title"
[matTooltip]="col.title | translate"
class="adf-datatable-cell-value">{{ col.title | translate }}</span>
<span *ngIf="col.title && col.sortable && isDraggingHeaderColumn" class="adf-sr-only" aria-live="polite">
{{ getSortLiveAnnouncement(col) | translate: { string: col.title | translate } }}
</span>
<span *ngIf="!col.title && !col.sortable && !headerFilterTemplate" [attr.title]="'ADF-DATATABLE.ACCESSIBILITY.EMPTY_HEADER' | translate"></span>
</ng-container>
<div *ngIf="col.header" class="adf-datatable-cell-value">
<ng-template [ngTemplateOutlet]="col.header" [ngTemplateOutletContext]="{$implicit: col}"></ng-template>
</div>
<span
[class.adf-datatable__header--sorted-asc]="isColumnSorted(col, 'asc')"
[class.adf-datatable__header--sorted-desc]="isColumnSorted(col, 'desc')">
<span *ngIf="col.title && col.sortable && isDraggingHeaderColumn"
class="adf-sr-only"
aria-live="polite">
{{ getSortLiveAnnouncement(col) | translate: { string: col.title | translate } }}
</span>
<ng-template *ngIf="allowFiltering" [ngTemplateOutlet]="headerFilterTemplate" [ngTemplateOutletContext]="{$implicit: col}"></ng-template>
<span *ngIf="!col.title && !col.sortable && !headerFilterTemplate"
[attr.title]="'ADF-DATATABLE.ACCESSIBILITY.EMPTY_HEADER' | translate"></span>
</ng-container>
<span
*ngIf="col.draggable"
cdkDragHandle
[ngClass]="{ 'adf-datatable-cell-header-drag-icon': !isResizing }"
>
<adf-icon
*ngIf="hoveredHeaderColumnIndex === columnIndex && !isResizing"
value="adf:drag_indicator"
[attr.data-automation-id]="'adf-datatable-cell-header-drag-icon-'+col.key">
</adf-icon>
</span>
<div *ngIf="col.header" class="adf-datatable-cell-value">
<ng-template [ngTemplateOutlet]="col.header"
[ngTemplateOutletContext]="{ $implicit: col }"></ng-template>
</div>
<div
*ngIf="isResizingEnabled && col.resizable && !lastColumn"
[ngClass]="hoveredHeaderColumnIndex === columnIndex && !isResizing || resizingColumnIndex === columnIndex ? 'adf-datatable__resize-handle-visible' : 'adf-datatable__resize-handle-hidden'"
adf-resize-handle
tabindex="0"
role="button"
(click)="$event.stopPropagation()"
(keyup.enter)="$event.stopPropagation()"
class="adf-datatable__resize-handle"
[resizableContainer]="resizableElement">
<div class="adf-datatable__resize-handle--divider"></div>
</div>
<div class="adf-drop-header-cell-placeholder" *cdkDragPlaceholder></div>
<span [class.adf-datatable__header--sorted-asc]="isColumnSorted(col, 'asc')"
[class.adf-datatable__header--sorted-desc]="isColumnSorted(col, 'desc')"></span>
<ng-template *ngIf="allowFiltering"
[ngTemplateOutlet]="headerFilterTemplate"
[ngTemplateOutletContext]="{ $implicit: col }"></ng-template>
<span *ngIf="col.draggable"
cdkDragHandle
[ngClass]="{ 'adf-datatable-cell-header-drag-icon': !isResizing }">
<adf-icon *ngIf="hoveredHeaderColumnIndex === columnIndex && !isResizing"
value="adf:drag_indicator"
[attr.data-automation-id]="'adf-datatable-cell-header-drag-icon-' + col.key">
</adf-icon>
</span>
</div>
<div *ngIf="isResizingEnabled && col.resizable && !lastColumn"
[ngClass]="hoveredHeaderColumnIndex === columnIndex && !isResizing || resizingColumnIndex === columnIndex ? 'adf-datatable__resize-handle-visible' : 'adf-datatable__resize-handle-hidden'"
adf-resize-handle
role="separator"
(click)="$event.stopPropagation()"
(keyup.enter)="$event.stopPropagation()"
class="adf-datatable__resize-handle"
[resizableContainer]="resizableElement">
<div class="adf-datatable__resize-handle--divider"></div>
</div>
<div class="adf-drop-header-cell-placeholder" *cdkDragPlaceholder></div>
</th>
<!-- Header actions (right) -->
<div
*ngIf="(actions && actionsPosition === 'right') ||
(mainActionTemplate && showMainDatatableActions)"
class="adf-actions-column adf-datatable-actions-menu adf-datatable-cell-header adf-datatable__actions-cell"
>
<ng-container *ngIf="mainActionTemplate">
<button
data-automation-id="adf-datatable-main-menu-button"
matTooltip="{{ 'ADF-DATATABLE.CONTENT-ACTIONS.SELECT_COLUMNS' | translate }}"
<!-- Header actions (right) -->
<th *ngIf="(actions && actionsPosition === 'right') || (mainActionTemplate && showMainDatatableActions)"
class="adf-actions-column adf-datatable-actions-menu adf-datatable-cell-header adf-datatable__actions-cell">
<ng-container *ngIf="mainActionTemplate">
<button data-automation-id="adf-datatable-main-menu-button"
[matTooltip]="'ADF-DATATABLE.CONTENT-ACTIONS.SELECT_COLUMNS' | translate"
[attr.aria-label]="'ADF-DATATABLE.CONTENT-ACTIONS.SELECT_COLUMNS' | translate"
mat-icon-button
#mainMenuTrigger="matMenuTrigger"
(keydown.enter)="mainMenuTrigger.openMenu()"
[matMenuTriggerFor]="mainMenu">
<mat-icon>view_week_outline</mat-icon>
<mat-icon>view_week_outline</mat-icon>
</button>
<mat-menu #mainMenu>
<ng-container [ngTemplateOutlet]="mainActionTemplate"
[ngTemplateOutletContext]="{ $implicit: mainMenuTrigger }">
</ng-container>
</mat-menu>
</ng-container>
</th>
</adf-datatable-row>
</thead>
<tbody class="adf-datatable-body"
[ngClass]="{ 'adf-blur-datatable-body': blurOnResize && (isDraggingHeaderColumn || isResizing) }">
<ng-container *ngIf="!loading && !noPermission">
<adf-datatable-row *ngFor="let row of data.getRows(); let idx = index"
[row]="row"
(select)="onEnterKeyPressed(row, $event)"
(keyup)="onRowKeyUp(row, $event)"
(keydown)="onRowEnterKeyDown(row, $event)"
[adf-upload]="rowAllowsDrop(row)"
[adf-upload-data]="row"
[ngStyle]="rowStyle"
[ngClass]="getRowStyle(row)"
[attr.data-automation-id]="'datatable-row-' + idx"
(contextmenu)="markRowAsContextMenuSource(row)">
<!-- Actions (left) -->
<td *ngIf="actions && actionsPosition === 'left'" class="adf-datatable-cell">
<button mat-icon-button
[matMenuTriggerFor]="menu"
#actionsMenuTrigger="matMenuTrigger"
[ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)"
[title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate"
[attr.id]="'action_menu_left_' + idx"
[attr.data-automation-id]="'action_menu_' + idx">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item
*ngFor="let action of getRowActions(row)"
[attr.data-automation-id]="action.title"
[disabled]="action.disabled"
(click)="onExecuteRowAction(row, action)">
<mat-icon *ngIf="action.icon">{{ action.icon }}</mat-icon>
<span>{{ action.title | translate }}</span>
</button>
<mat-menu #mainMenu>
<ng-container
[ngTemplateOutlet]="mainActionTemplate"
[ngTemplateOutletContext]="{
$implicit: mainMenuTrigger
}">
</mat-menu>
</td>
<td *ngIf="multiselect"
class="adf-datatable-cell adf-datatable-checkbox">
<mat-checkbox [id]="'select-file-' + idx"
[checked]="row.isSelected"
[attr.aria-checked]="row.isSelected"
(change)="onCheckboxChange(row, $event)"
[attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.SELECT_FILE' | translate"
[matTooltip]="'ADF-DATATABLE.ACCESSIBILITY.SELECT_FILE' | translate">
</mat-checkbox>
</td>
<td *ngFor="
let col of (data.getColumns() | filterOutEvery:'isHidden':true),
let lastColumn = last;"
class="adf-datatable-cell adf-datatable-cell--{{ col.type || 'text' }} {{ col.cssClass }} adf-datatable-cell-data"
[attr.title]="col.title | translate"
[attr.data-automation-id]="getAutomationValue(row)"
[attr.aria-selected]="row.isSelected"
[attr.aria-label]="col.title ? (col.title | translate) : null"
(click)="onRowClick(row, $event)"
tabindex="0"
(keydown.enter)="onEnterKeyPressed(row, $any($event))"
[adf-context-menu]="getContextMenuActions(row, col)"
[adf-context-menu-enabled]="contextMenu"
adf-drop-zone
dropTarget="cell"
[dropColumn]="col"
[dropRow]="row"
[ngStyle]="(col.width) && !lastColumn && {'flex': getFlexValue(col)}">
<div *ngIf="!col.template" class="adf-datatable-cell-container">
<ng-container [ngSwitch]="data.getColumnType(row, col)">
<div *ngSwitchCase="'image'" class="adf-cell-value">
<mat-icon *ngIf="isIconValue(row, col); else no_iconvalue">{{ asIconValue(row, col) }}
</mat-icon>
<ng-template #no_iconvalue>
<mat-icon class="adf-datatable-selected"
*ngIf="row.isSelected && !multiselect; else no_selected_row"
svgIcon="selected">
</mat-icon>
<ng-template #no_selected_row>
<img class="adf-datatable-center-img-ie"
[attr.aria-label]="(data.getValue(row, col) | fileType) === 'disable' ?
('ADF-DATATABLE.ACCESSIBILITY.ICON_DISABLED' | translate) :
'ADF-DATATABLE.ACCESSIBILITY.ICON_TEXT' | translate:{
type: 'ADF-DATATABLE.FILE_TYPE.' + (data.getValue(row, col) | fileType | uppercase) | translate
}"
[attr.alt]="(data.getValue(row, col) | fileType) === 'disable' ?
('ADF-DATATABLE.ACCESSIBILITY.ICON_DISABLED' | translate) :
'ADF-DATATABLE.ACCESSIBILITY.ICON_TEXT' | translate:{
type: 'ADF-DATATABLE.FILE_TYPE.' + (data.getValue(row, col) | fileType | uppercase) | translate
}"
src="{{ data.getValue(row, col) }}"
(error)="onImageLoadingError($event, row)">
</ng-template>
</ng-template>
</div>
<div *ngSwitchCase="'icon'" class="adf-cell-value">
<adf-icon-cell [data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)">
</adf-icon-cell>
</div>
<div *ngSwitchCase="'date'" class="adf-cell-value adf-cell-date"
[attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1"
[attr.data-automation-id]="'date_' + (data.getValue(row, col, resolverFn) | adfLocalizedDate: 'medium') ">
<adf-date-cell class="adf-datatable-center-date-column-ie"
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)"
[dateConfig]="col.dateConfig">
</adf-date-cell>
</div>
<div *ngSwitchCase="'location'"
[attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1" class="adf-cell-value"
[attr.data-automation-id]="'location' + data.getValue(row, col, resolverFn)">
<adf-location-cell [data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)">
</adf-location-cell>
</div>
<div *ngSwitchCase="'fileSize'"
[attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1" class="adf-cell-value"
[attr.data-automation-id]="'fileSize_' + data.getValue(row, col, resolverFn)">
<adf-filesize-cell class="adf-datatable-center-size-column-ie"
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)">
</adf-filesize-cell>
</div>
<div *ngSwitchCase="'text'"
class="adf-cell-value"
[attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1"
[attr.data-automation-id]="'text_' + data.getValue(row, col, resolverFn)">
<adf-datatable-cell [copyContent]="col.copyContent"
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)">
</adf-datatable-cell>
</div>
<div *ngSwitchCase="'boolean'"
class="adf-cell-value"
[attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1"
[attr.data-automation-id]="'boolean_' + data.getValue(row, col, resolverFn)">
<adf-boolean-cell [data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)">
</adf-boolean-cell>
</div>
<div *ngSwitchCase="'json'"
class="adf-cell-value"
[attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1">
<adf-json-cell [editable]="col.editable"
[data]="data"
[column]="col"
[resolverFn]="resolverFn"
[row]="row">
</adf-json-cell>
</div>
<div *ngSwitchCase="'amount'"
class="adf-cell-value"
[attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1"
[attr.data-automation-id]="'amount_' + data.getValue(row, col, resolverFn)">
<adf-amount-cell [data]="data"
[column]="col"
[resolverFn]="resolverFn"
[row]="row"
[currencyConfig]="col.currencyConfig">
</adf-amount-cell>
</div>
<div *ngSwitchCase="'number'"
class="adf-cell-value"
[attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1"
[attr.data-automation-id]="'number_' + data.getValue(row, col, resolverFn)">
<adf-number-cell [data]="data"
[column]="col"
[resolverFn]="resolverFn"
[row]="row"
[decimalConfig]="col.decimalConfig">
</adf-number-cell>
</div>
<span *ngSwitchDefault class="adf-cell-value">
<!-- empty cell for unknown column type -->
</span>
</ng-container>
</div>
<div *ngIf="col.template" class="adf-datatable-cell-container">
<div class="adf-cell-value"
[attr.tabindex]="col.focus ? 0 : null">
<ng-container [ngTemplateOutlet]="col.template"
[ngTemplateOutletContext]="{
$implicit: { data, row, col },
value: data.getValue(row, col, resolverFn)
}">
</ng-container>
</mat-menu>
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate }}</span>
</ng-container>
</div>
</div>
</div>
</td>
</adf-datatable-row>
</div>
<!-- Row actions (right) -->
<td *ngIf="(actions && actionsPosition === 'right') ||
(mainActionTemplate && showMainDatatableActions)"
class="adf-datatable-cell adf-datatable__actions-cell adf-datatable-center-actions-column-ie adf-datatable-actions-menu">
<div
class="adf-datatable-body"
[ngClass]="{ 'adf-blur-datatable-body': blurOnResize && (isDraggingHeaderColumn || isResizing) }"
role="rowgroup">
<ng-container *ngIf="!loading && !noPermission">
<adf-datatable-row *ngFor="let row of data.getRows(); let idx = index"
[row]="row"
(select)="onEnterKeyPressed(row, $event)"
(keyup)="onRowKeyUp(row, $event)"
(keydown)="onRowEnterKeyDown(row, $event)"
[adf-upload]="rowAllowsDrop(row)"
[adf-upload-data]="row"
[ngStyle]="rowStyle"
[ngClass]="getRowStyle(row)"
[attr.data-automation-id]="'datatable-row-' + idx"
(contextmenu)="markRowAsContextMenuSource(row)">
<!-- Actions (left) -->
<div *ngIf="actions && actionsPosition === 'left'" role="gridcell" class="adf-datatable-cell">
<button mat-icon-button [matMenuTriggerFor]="menu" #actionsMenuTrigger="matMenuTrigger"
<ng-container *ngIf="(actions && actionsPosition === 'right')">
<button mat-icon-button
[matMenuTriggerFor]="menu"
#actionsMenuTrigger="matMenuTrigger"
[ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)"
[attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.ROW_OPTION_BUTTON' | translate"
[title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate"
[attr.id]="'action_menu_left_' + idx"
[attr.data-automation-id]="'action_menu_' + idx">
[attr.id]="'action_menu_right_' + idx"
[attr.data-automation-id]="'action_menu_' + idx"
(keydown.enter)="actionsMenuTrigger.openMenu()">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item *ngFor="let action of getRowActions(row)"
[attr.data-automation-id]="action.title"
[attr.aria-label]="action.title | translate"
[disabled]="action.disabled"
(click)="onExecuteRowAction(row, action)">
<mat-icon *ngIf="action.icon">{{ action.icon }}</mat-icon>
<span>{{ action.title | translate }}</span>
</button>
</mat-menu>
</div>
<label *ngIf="multiselect" [for]="'select-file-' + idx" class="adf-datatable-cell adf-datatable-checkbox">
<mat-checkbox
[id]="'select-file-' + idx"
[checked]="row.isSelected"
[attr.aria-checked]="row.isSelected"
role="checkbox"
(change)="onCheckboxChange(row, $event)"
class="adf-checkbox-sr-only">
{{ 'ADF-DATATABLE.ACCESSIBILITY.SELECT_FILE' | translate }}
</mat-checkbox>
</label>
<div *ngFor="
let col of (data.getColumns() | filterOutEvery:'isHidden':true),
let lastColumn = last;"
role="gridcell"
class="adf-datatable-cell adf-datatable-cell--{{col.type || 'text'}} {{col.cssClass}} adf-datatable-cell-data"
[attr.title]="col.title | translate"
[attr.data-automation-id]="getAutomationValue(row)"
[attr.aria-selected]="row.isSelected"
[attr.aria-label]="col.title ? (col.title | translate) : null"
(click)="onRowClick(row, $event)"
tabindex="0"
(keydown.enter)="onEnterKeyPressed(row, $any($event))"
[adf-context-menu]="getContextMenuActions(row, col)"
[adf-context-menu-enabled]="contextMenu"
adf-drop-zone dropTarget="cell" [dropColumn]="col" [dropRow]="row"
[ngStyle]="(col.width) && !lastColumn && {'flex': getFlexValue(col)}">
<div *ngIf="!col.template" class="adf-datatable-cell-container">
<ng-container [ngSwitch]="data.getColumnType(row, col)">
<div *ngSwitchCase="'image'" class="adf-cell-value">
<mat-icon *ngIf="isIconValue(row, col); else no_iconvalue">{{ asIconValue(row, col) }}
</mat-icon>
<ng-template #no_iconvalue>
<mat-icon class="adf-datatable-selected"
*ngIf="row.isSelected && !multiselect; else no_selected_row" svgIcon="selected">
</mat-icon>
<ng-template #no_selected_row>
<img class="adf-datatable-center-img-ie"
[attr.aria-label]="(data.getValue(row, col) | fileType) === 'disable' ?
('ADF-DATATABLE.ACCESSIBILITY.ICON_DISABLED' | translate) :
'ADF-DATATABLE.ACCESSIBILITY.ICON_TEXT' | translate:{
type: 'ADF-DATATABLE.FILE_TYPE.' + (data.getValue(row, col) | fileType | uppercase) | translate
}"
[attr.alt]="(data.getValue(row, col) | fileType) === 'disable' ?
('ADF-DATATABLE.ACCESSIBILITY.ICON_DISABLED' | translate) :
'ADF-DATATABLE.ACCESSIBILITY.ICON_TEXT' | translate:{
type: 'ADF-DATATABLE.FILE_TYPE.' + (data.getValue(row, col) | fileType | uppercase) | translate
}"
src="{{ data.getValue(row, col) }}"
(error)="onImageLoadingError($event, row)">
</ng-template>
</ng-template>
</div>
<div *ngSwitchCase="'icon'" class="adf-cell-value">
<adf-icon-cell
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)">
</adf-icon-cell>
</div>
<div *ngSwitchCase="'date'" class="adf-cell-value adf-cell-date" [attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1"
[attr.data-automation-id]="'date_' + (data.getValue(row, col, resolverFn) | adfLocalizedDate: 'medium') ">
<adf-date-cell class="adf-datatable-center-date-column-ie"
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)"
[dateConfig]="col.dateConfig">
</adf-date-cell>
</div>
<div *ngSwitchCase="'location'" [attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1" class="adf-cell-value"
[attr.data-automation-id]="'location' + data.getValue(row, col, resolverFn)">
<adf-location-cell
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)">
</adf-location-cell>
</div>
<div *ngSwitchCase="'fileSize'" [attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1" class="adf-cell-value"
[attr.data-automation-id]="'fileSize_' + data.getValue(row, col, resolverFn)">
<adf-filesize-cell class="adf-datatable-center-size-column-ie"
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)">
</adf-filesize-cell>
</div>
<div *ngSwitchCase="'text'" [attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1" class="adf-cell-value"
[attr.data-automation-id]="'text_' + data.getValue(row, col, resolverFn)">
<adf-datatable-cell
[copyContent]="col.copyContent"
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)">
</adf-datatable-cell>
</div>
<div *ngSwitchCase="'boolean'" [attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1" class="adf-cell-value"
[attr.data-automation-id]="'boolean_' + data.getValue(row, col, resolverFn)">
<adf-boolean-cell
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)">
</adf-boolean-cell>
</div>
<div *ngSwitchCase="'json'" [attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1" class="adf-cell-value">
<adf-json-cell
[editable]="col.editable"
[data]="data"
[column]="col"
[resolverFn]="resolverFn"
[row]="row">
</adf-json-cell>
</div>
<div *ngSwitchCase="'amount'"
class="adf-cell-value"
[attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1"
[attr.data-automation-id]="'amount_' + data.getValue(row, col, resolverFn)">
<adf-amount-cell
[data]="data"
[column]="col"
[resolverFn]="resolverFn"
[row]="row"
[currencyConfig]="col.currencyConfig">
</adf-amount-cell>
</div>
<div *ngSwitchCase="'number'"
class="adf-cell-value"
[attr.tabindex]="data.getValue(row, col, resolverFn)? 0 : -1"
[attr.data-automation-id]="'number_' + data.getValue(row, col, resolverFn)">
<adf-number-cell
[data]="data"
[column]="col"
[resolverFn]="resolverFn"
[row]="row"
[decimalConfig]="col.decimalConfig">
</adf-number-cell>
</div>
<span *ngSwitchDefault class="adf-cell-value">
<!-- empty cell for unknown column type -->
</span>
</ng-container>
</div>
<div *ngIf="col.template" class="adf-datatable-cell-container">
<div class="adf-cell-value" [attr.tabindex]="col.focus ? 0 : null">
<ng-container
[ngTemplateOutlet]="col.template"
[ngTemplateOutletContext]="{ $implicit: { data: data, row: row, col: col }, value: data.getValue(row, col, resolverFn) }">
</ng-container>
</div>
</div>
</div>
<!-- Row actions (right) -->
<div *ngIf="
(actions && actionsPosition === 'right') ||
(mainActionTemplate && showMainDatatableActions)"
role="gridcell"
class="adf-datatable-cell adf-datatable__actions-cell adf-datatable-center-actions-column-ie adf-datatable-actions-menu">
<ng-container *ngIf="(actions && actionsPosition === 'right')">
<button mat-icon-button [matMenuTriggerFor]="menu" #actionsMenuTrigger="matMenuTrigger"
[ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)"
[attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.ROW_OPTION_BUTTON' | translate"
[title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate"
[attr.id]="'action_menu_right_' + idx"
[attr.data-automation-id]="'action_menu_' + idx"
(keydown.enter)="actionsMenuTrigger.openMenu()">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item *ngFor="let action of getRowActions(row)"
[attr.data-automation-id]="action.title"
[attr.aria-label]="action.title | translate"
[disabled]="action.disabled"
(click)="onExecuteRowAction(row, action)">
<mat-icon *ngIf="action.icon">{{ action.icon }}</mat-icon>
<span>{{ action.title | translate }}</span>
</button>
</mat-menu>
</ng-container>
</div>
</adf-datatable-row>
<div *ngIf="isEmpty()" role="row" class="adf-datatable-row">
<div class="adf-no-content-container adf-datatable-cell" role="gridcell">
<ng-template *ngIf="noContentTemplate"
ngFor [ngForOf]="[data]"
[ngForTemplate]="noContentTemplate">
</ng-template>
<ng-content select="adf-empty-list"></ng-content>
</div>
</div>
</ng-container>
<div *ngIf="!loading && noPermission"
role="row"
class="adf-datatable-row adf-no-permission__row">
<div class="adf-no-permission__cell adf-no-content-container adf-datatable-cell">
<ng-template *ngIf="noPermissionTemplate"
</ng-container>
</td>
</adf-datatable-row>
<tr *ngIf="isEmpty()" class="adf-datatable-row">
<td class="adf-no-content-container adf-datatable-cell">
<ng-template *ngIf="noContentTemplate"
ngFor [ngForOf]="[data]"
[ngForTemplate]="noPermissionTemplate">
[ngForTemplate]="noContentTemplate">
</ng-template>
</div>
</div>
<div *ngIf="loading" class="adf-datatable-row">
<div class="adf-no-content-container adf-datatable-cell">
<ng-template *ngIf="loadingTemplate"
ngFor [ngForOf]="[data]"
[ngForTemplate]="loadingTemplate">
</ng-template>
</div>
</div>
</div>
<ng-content select="adf-empty-list"></ng-content>
</td>
</tr>
</ng-container>
<tr *ngIf="!loading && noPermission"
class="adf-datatable-row adf-no-permission__row">
<td class="adf-no-permission__cell adf-no-content-container adf-datatable-cell">
<ng-template *ngIf="noPermissionTemplate"
ngFor [ngForOf]="[data]"
[ngForTemplate]="noPermissionTemplate">
</ng-template>
</td>
</tr>
<tr *ngIf="loading" class="adf-datatable-row">
<td class="adf-no-content-container adf-datatable-cell">
<ng-template *ngIf="loadingTemplate"
ngFor [ngForOf]="[data]"
[ngForTemplate]="loadingTemplate">
</ng-template>
</td>
</tr>
</tbody>
</div>

View File

@ -283,6 +283,11 @@ $data-table-cell-min-width-file-size: $data-table-cell-min-width-1 !default;
padding-right: 15px;
}
.adf-datatable-checkbox {
display: flex;
justify-content: center;
}
.adf-cell-value {
display: flex;
min-height: inherit;
@ -433,13 +438,13 @@ $data-table-cell-min-width-file-size: $data-table-cell-min-width-1 !default;
}
/* mobile phone */
@media all and (max-width: 768px) {
@media all and (width <= 768px) {
.adf-desktop-only.adf-ellipsis-cell {
display: none;
}
}
@media (max-device-width: 768px) {
@media (width <= 768px) {
.adf-desktop-only.adf-ellipsis-cell {
display: none;
}
@ -495,11 +500,6 @@ $data-table-cell-min-width-file-size: $data-table-cell-min-width-1 !default;
right: -3px;
}
&.adf-datatable-checkbox {
display: flex;
align-items: center;
}
.adf-datatable-cell-header-content {
display: flex;
flex-grow: 1;
@ -557,26 +557,12 @@ $data-table-cell-min-width-file-size: $data-table-cell-min-width-1 !default;
}
}
.cdk-drag-preview {
&.adf-datatable-cell-header {
border-radius: 6px;
background-color: var(--theme-background-color);
.adf-datatable-cell-header.adf-drag-preview {
border-radius: 6px;
background-color: var(--theme-background-color);
@include mat.elevation-transition;
@include mat.elevation(4);
}
}
/* [Accessibility] Material checkbox labels */
.adf-checkbox-sr-only .mat-checkbox-label {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
@include mat.elevation-transition;
@include mat.elevation(4);
}
.adf-sticky-header {
@ -620,7 +606,7 @@ $data-table-cell-min-width-file-size: $data-table-cell-min-width-1 !default;
align-items: center;
height: inherit;
.adf-datatable-body[role="rowgroup"] {
.adf-datatable-body[role='rowgroup'] {
.adf-datatable-row {
height: 100%;
background-color: var(--adf-theme-background-card-color);
@ -660,7 +646,7 @@ $data-table-cell-min-width-file-size: $data-table-cell-min-width-1 !default;
}
}
@media screen and (max-width: 380px) {
@media screen and (width <= 380px) {
.adf-datatable-header {
max-height: 50%;
}

View File

@ -15,34 +15,37 @@
* limitations under the License.
*/
import { CdkDrag, CdkDragDrop, CdkDropList } from '@angular/cdk/drag-drop';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { Component, NO_ERRORS_SCHEMA, QueryList, SimpleChange, TemplateRef, ViewChild } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { MatCheckboxChange } from '@angular/material/checkbox';
import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
import { By } from '@angular/platform-browser';
import { take } from 'rxjs/operators';
import { domSanitizerMock } from '../../../mock/dom-sanitizer-mock';
import { matIconRegistryMock } from '../../../mock/mat-icon-registry-mock';
import { CoreTestingModule } from '../../../testing';
import { DataColumnComponent, DataColumnListComponent } from '../../data-column';
import { DataColumn } from '../../data/data-column.model';
import { DataRow } from '../../data/data-row.model';
import { DataSorting } from '../../data/data-sorting.model';
import { ObjectDataColumn } from '../../data/object-datacolumn.model';
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
import { DataTableComponent, ShowHeaderMode } from './datatable.component';
import { CoreTestingModule } from '../../../testing/core.testing.module';
import { DataColumnListComponent } from '../../data-column/data-column-list.component';
import { DataColumnComponent } from '../../data-column/data-column.component';
import { domSanitizerMock } from '../../../mock/dom-sanitizer-mock';
import { matIconRegistryMock } from '../../../mock/mat-icon-registry-mock';
import { CdkDrag, CdkDragDrop, CdkDropList } from '@angular/cdk/drag-drop';
import { take } from 'rxjs/operators';
import { By } from '@angular/platform-browser';
import { mockCarsData, mockCarsSchemaDefinition } from '../mocks/datatable.mock';
import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { DataTableComponent, ShowHeaderMode } from './datatable.component';
@Component({ selector: 'adf-custom-column-template-component', template: ` <ng-template #tmplRef></ng-template> ` })
@Component({
selector: 'adf-custom-column-template-component',
template: ` <ng-template #tmplRef></ng-template>`
})
class CustomColumnTemplateComponent {
@ViewChild('tmplRef', { static: true }) templateRef: TemplateRef<any>;
}
@Component({
selector: 'adf-custom-column-header-component',
template: ` <ng-template #tmplRef> CUSTOM HEADER </ng-template> `
template: ` <ng-template #tmplRef> CUSTOM HEADER</ng-template>`
})
class CustomColumnHeaderComponent {
@ViewChild('tmplRef', { static: true }) templateRef: TemplateRef<any>;
@ -314,7 +317,12 @@ describe('DataTable', () => {
});
it('should emit "sorting-changed" DOM event', (done) => {
const column = new ObjectDataColumn({ key: 'name', sortable: true, direction: 'asc', sortingKey: 'displayName' });
const column = new ObjectDataColumn({
key: 'name',
sortable: true,
direction: 'asc',
sortingKey: 'displayName'
});
dataTable.data = new ObjectDataTableAdapter([{ name: '1' }, { name: '2' }], [column]);
dataTable.data.setSorting(new DataSorting('name', 'desc'));
@ -518,7 +526,15 @@ describe('DataTable', () => {
it('should unselect the row with [multiple] selection mode and modifier key', (done) => {
dataTable.selectionMode = 'multiple';
dataTable.data = new ObjectDataTableAdapter([{ name: '1', isSelected: true }], [new ObjectDataColumn({ key: 'name' })]);
dataTable.data = new ObjectDataTableAdapter(
[
{
name: '1',
isSelected: true
}
],
[new ObjectDataColumn({ key: 'name' })]
);
const rows = dataTable.data.getRows();
rows[0].isSelected = true;
@ -531,8 +547,7 @@ describe('DataTable', () => {
dataTable.onRowClick(rows[0], {
metaKey: true,
preventDefault: () => {},
composedPath: () => []
preventDefault: () => {}
} as any);
});
@ -573,7 +588,16 @@ describe('DataTable', () => {
it('should select multiple rows with [multiple] selection mode and modifier key', (done) => {
dataTable.selectionMode = 'multiple';
dataTable.data = new ObjectDataTableAdapter([{ name: '1', isSelected: true }, { name: '2' }], [new ObjectDataColumn({ key: 'name' })]);
dataTable.data = new ObjectDataTableAdapter(
[
{
name: '1',
isSelected: true
},
{ name: '2' }
],
[new ObjectDataColumn({ key: 'name' })]
);
const rows = dataTable.data.getRows();
rows[0].isSelected = true;
@ -738,7 +762,13 @@ describe('DataTable', () => {
it('should not sort upon clicking non-sortable column header', () => {
dataTable.data = new ObjectDataTableAdapter(
[{ name: '1' }, { name: '2' }],
[new ObjectDataColumn({ key: 'name', sortable: false }), new ObjectDataColumn({ key: 'other', sortable: true })]
[
new ObjectDataColumn({ key: 'name', sortable: false }),
new ObjectDataColumn({
key: 'other',
sortable: true
})
]
);
fixture.detectChanges();
dataTable.ngAfterViewInit();
@ -753,7 +783,15 @@ describe('DataTable', () => {
});
it('should set sorting upon column header clicked', () => {
dataTable.data = new ObjectDataTableAdapter([{ name: '1' }], [new ObjectDataColumn({ key: 'column_1', sortable: true })]);
dataTable.data = new ObjectDataTableAdapter(
[{ name: '1' }],
[
new ObjectDataColumn({
key: 'column_1',
sortable: true
})
]
);
fixture.detectChanges();
dataTable.ngAfterViewInit();
const adapter = dataTable.data;
@ -768,7 +806,15 @@ describe('DataTable', () => {
});
it('should invert sorting upon column header clicked', () => {
dataTable.data = new ObjectDataTableAdapter([{ name: '1' }], [new ObjectDataColumn({ key: 'column_1', sortable: true })]);
dataTable.data = new ObjectDataTableAdapter(
[{ name: '1' }],
[
new ObjectDataColumn({
key: 'column_1',
sortable: true
})
]
);
fixture.detectChanges();
dataTable.ngAfterViewInit();
@ -795,7 +841,13 @@ describe('DataTable', () => {
it('should indicate column that has sorting applied', () => {
dataTable.data = new ObjectDataTableAdapter(
[{ name: '1' }, { name: '2' }],
[new ObjectDataColumn({ key: 'name', sortable: true }), new ObjectDataColumn({ key: 'other', sortable: true })]
[
new ObjectDataColumn({ key: 'name', sortable: true }),
new ObjectDataColumn({
key: 'other',
sortable: true
})
]
);
fixture.detectChanges();
dataTable.ngAfterViewInit();
@ -813,7 +865,13 @@ describe('DataTable', () => {
it('should return false for columns that have no sorting', () => {
dataTable.data = new ObjectDataTableAdapter(
[{ name: '1' }, { name: '2' }],
[new ObjectDataColumn({ key: 'name', sortable: false }), new ObjectDataColumn({ key: 'other', sortable: false })]
[
new ObjectDataColumn({ key: 'name', sortable: false }),
new ObjectDataColumn({
key: 'other',
sortable: false
})
]
);
const [col1, col2] = dataTable.getSortableColumns();
@ -862,7 +920,13 @@ describe('DataTable', () => {
it('should have indeterminate state for "select all" when at least 1 row is selected or not all rows', () => {
dataTable.data = new ObjectDataTableAdapter(
[{ name: '1' }, { name: '2' }],
[new ObjectDataColumn({ key: 'name', sortable: false }), new ObjectDataColumn({ key: 'other', sortable: false })]
[
new ObjectDataColumn({ key: 'name', sortable: false }),
new ObjectDataColumn({
key: 'other',
sortable: false
})
]
);
const rows = dataTable.data.getRows();
@ -935,7 +999,7 @@ describe('DataTable', () => {
const column = {} as DataColumn;
const row: any = {
getValue: () => 'http://www.google.com'
getValue: () => 'https://www.google.com'
};
expect(dataTable.isIconValue(row, column)).toBeFalsy();
@ -955,7 +1019,7 @@ describe('DataTable', () => {
const column = {} as DataColumn;
const row: any = {
getValue: () => 'http://www.google.com'
getValue: () => 'https://www.google.com'
};
expect(dataTable.asIconValue(row, column)).toBe(null);
@ -1152,7 +1216,14 @@ describe('DataTable', () => {
{ id: 1, name: 'foo' },
{ id: 2, name: 'bar' }
],
[new ObjectDataColumn({ key: 'id', title: 'ID' }), new ObjectDataColumn({ key: 'name', title: 'Name', header: customHeader })]
[
new ObjectDataColumn({ key: 'id', title: 'ID' }),
new ObjectDataColumn({
key: 'name',
title: 'Name',
header: customHeader
})
]
);
fixture.detectChanges();
@ -1209,7 +1280,7 @@ describe('DataTable', () => {
dataTable.resetSelection();
const rowClickPromise = dataTable.rowClick.pipe(take(1)).toPromise();
const rowElement = fixture.debugElement.query(By.css(`[data-automation-id="datatable-row-0"] > div`)).nativeElement as HTMLElement;
const rowElement = fixture.debugElement.query(By.css(`[data-automation-id="datatable-row-0"] > td`)).nativeElement as HTMLElement;
rowElement.dispatchEvent(new MouseEvent('click'));
fixture.detectChanges();
await rowClickPromise;
@ -1220,7 +1291,7 @@ describe('DataTable', () => {
dataTable.resetSelection();
const cellClickPromise = dataTable.rowClick.pipe(take(1)).toPromise();
const cellElement = fixture.debugElement.query(By.css(`[data-automation-id="datatable-row-1"] > div`)).nativeElement as HTMLElement;
const cellElement = fixture.debugElement.query(By.css(`[data-automation-id="datatable-row-1"] > td`)).nativeElement as HTMLElement;
cellElement.dispatchEvent(new MouseEvent('click', { bubbles: true }));
fixture.detectChanges();
await cellClickPromise;
@ -1339,19 +1410,19 @@ describe('Accesibility', () => {
});
fixture.detectChanges();
const datatableAttributes = element.querySelector('.adf-datatable-list').attributes;
const datatableHeaderAttributes = element.querySelector('.adf-datatable-list .adf-datatable-header').attributes;
const datatableHeaderCellAttributes = element.querySelector('.adf-datatable-cell-header').attributes;
const datatableBodyAttributes = element.querySelector('.adf-datatable-body').attributes;
const datatableBodyRowAttributes = element.querySelector('.adf-datatable-body .adf-datatable-row').attributes;
const datatableBodyCellAttributes = element.querySelector('.adf-datatable-body .adf-datatable-cell').attributes;
const datatable = element.querySelector('.adf-datatable-list').attributes;
const header = element.querySelector('.adf-datatable-list .adf-datatable-header');
const headerCell = element.querySelector('.adf-datatable-cell-header');
const body = element.querySelector('.adf-datatable-body');
const row = element.querySelector('.adf-datatable-body .adf-datatable-row');
const cell = element.querySelector('.adf-datatable-body .adf-datatable-cell');
expect(datatableAttributes.getNamedItem('role').value).toEqual('grid');
expect(datatableHeaderAttributes.getNamedItem('role').value).toEqual('rowgroup');
expect(datatableHeaderCellAttributes.getNamedItem('role').value).toEqual('columnheader');
expect(datatableBodyAttributes.getNamedItem('role').value).toEqual('rowgroup');
expect(datatableBodyRowAttributes.getNamedItem('role').value).toEqual('row');
expect(datatableBodyCellAttributes.getNamedItem('role').value).toEqual('gridcell');
expect(datatable.getNamedItem('role').value).toEqual('table');
expect(header.tagName).toEqual('THEAD');
expect(headerCell.tagName).toEqual('TH');
expect(body.tagName).toEqual('TBODY');
expect(row.tagName).toEqual('ADF-DATATABLE-ROW');
expect(cell.tagName).toEqual('TD');
});
describe('aria-sort', () => {
@ -1480,7 +1551,16 @@ describe('Accesibility', () => {
dataTable.showHeader = ShowHeaderMode.Never;
const dataRows = [{ name: 'name1' }];
dataTable.data = new ObjectDataTableAdapter([], [new ObjectDataColumn({ key: 'name', template: columnCustomTemplate, focus: false })]);
dataTable.data = new ObjectDataTableAdapter(
[],
[
new ObjectDataColumn({
key: 'name',
template: columnCustomTemplate,
focus: false
})
]
);
dataTable.ngOnChanges({
rows: new SimpleChange(null, dataRows, false)
@ -1497,7 +1577,16 @@ describe('Accesibility', () => {
dataTable.showHeader = ShowHeaderMode.Never;
const dataRows = [{ name: 'name1' }];
dataTable.data = new ObjectDataTableAdapter([], [new ObjectDataColumn({ key: 'name', template: columnCustomTemplate, focus: true })]);
dataTable.data = new ObjectDataTableAdapter(
[],
[
new ObjectDataColumn({
key: 'name',
template: columnCustomTemplate,
focus: true
})
]
);
dataTable.ngOnChanges({
rows: new SimpleChange(null, dataRows, false)

View File

@ -15,14 +15,14 @@
* limitations under the License.
*/
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterTestingModule } from '@angular/router/testing';
import { Meta, moduleMetadata, Story } from '@storybook/angular';
import { CoreStoryModule } from '../../../testing/core.story.module';
import { DataTableComponent } from './datatable.component';
import { DataTableModule } from '../../datatable.module';
import { RouterTestingModule } from '@angular/router/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { mockPathInfos } from '../mocks/datatable.mock';
import { DataTableComponent } from './datatable.component';
export default {
component: DataTableComponent,
@ -150,9 +150,22 @@ export default {
cssClass: 'adf-ellipsis-cell',
copyContent: true
},
{ type: 'image', key: 'imageCol', title: 'Image Column', draggable: true, cssClass: 'adf-ellipsis-cell' },
{
type: 'image',
key: 'imageCol',
title: 'Image Column',
draggable: true,
cssClass: 'adf-ellipsis-cell'
},
{ type: 'icon', key: 'iconCol', title: 'Icon Column', draggable: true, cssClass: 'adf-ellipsis-cell' },
{ type: 'date', key: 'dateCol', title: 'Date Column', sortable: true, draggable: true, cssClass: 'adf-ellipsis-cell' },
{
type: 'date',
key: 'dateCol',
title: 'Date Column',
sortable: true,
draggable: true,
cssClass: 'adf-ellipsis-cell'
},
{
type: 'date',
key: 'dateCol',
@ -162,11 +175,43 @@ export default {
cssClass: 'adf-ellipsis-cell',
dateConfig: { format: 'timeAgo' }
},
{ type: 'fileSize', key: 'fileSizeCol', title: 'File Size Column', sortable: true, draggable: true, cssClass: 'adf-ellipsis-cell' },
{ type: 'location', format: '/files', key: 'locationCol', title: 'Location Column', draggable: true, cssClass: 'adf-ellipsis-cell' },
{ type: 'boolean', key: 'booleanCol', title: 'Boolean Column', draggable: true, cssClass: 'adf-ellipsis-cell' },
{ type: 'amount', key: 'amountCol', title: 'Amount Column', draggable: true, cssClass: 'adf-ellipsis-cell' },
{ type: 'number', key: 'numberCol', title: 'Number Column', draggable: true, cssClass: 'adf-ellipsis-cell' },
{
type: 'fileSize',
key: 'fileSizeCol',
title: 'File Size Column',
sortable: true,
draggable: true,
cssClass: 'adf-ellipsis-cell'
},
{
type: 'location',
format: '/files',
key: 'locationCol',
title: 'Location Column',
draggable: true,
cssClass: 'adf-ellipsis-cell'
},
{
type: 'boolean',
key: 'booleanCol',
title: 'Boolean Column',
draggable: true,
cssClass: 'adf-ellipsis-cell'
},
{
type: 'amount',
key: 'amountCol',
title: 'Amount Column',
draggable: true,
cssClass: 'adf-ellipsis-cell'
},
{
type: 'number',
key: 'numberCol',
title: 'Number Column',
draggable: true,
cssClass: 'adf-ellipsis-cell'
},
{ type: 'json', key: 'jsonCol', title: 'JSON Column', draggable: true, cssClass: 'adf-ellipsis-cell' }
],
table: {

View File

@ -17,6 +17,9 @@
/* eslint-disable @angular-eslint/no-conflicting-lifecycle */
import { FocusKeyManager } from '@angular/cdk/a11y';
import { CdkDrag, CdkDragDrop, CdkDropList, DragDropModule, moveItemInArray } from '@angular/cdk/drag-drop';
import { CommonModule } from '@angular/common';
import {
AfterContentInit,
AfterViewInit,
@ -39,28 +42,45 @@ import {
ViewChildren,
ViewEncapsulation
} from '@angular/core';
import { FocusKeyManager } from '@angular/cdk/a11y';
import { MatCheckboxChange } from '@angular/material/checkbox';
import { MatMenuTrigger } from '@angular/material/menu';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxChange, MatCheckboxModule } from '@angular/material/checkbox';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule, MatIconRegistry } from '@angular/material/icon';
import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
import { MatSelectModule } from '@angular/material/select';
import { MatTooltipModule } from '@angular/material/tooltip';
import { DomSanitizer } from '@angular/platform-browser';
import { TranslateModule } from '@ngx-translate/core';
import { Observable, Observer, Subscription } from 'rxjs';
import { DataColumnListComponent } from '../../data-column/data-column-list.component';
import { buffer, debounceTime, filter, map, share } from 'rxjs/operators';
import { ContextMenuModule } from '../../../context-menu';
import { DirectiveModule } from '../../../directives';
import { IconComponent } from '../../../icon';
import { FileTypePipe, FilterOutArrayObjectsByPropPipe, LocalizedDatePipe } from '../../../pipes';
import { DataColumnListComponent } from '../../data-column';
import { DataColumn } from '../../data/data-column.model';
import { DataRowEvent } from '../../data/data-row-event.model';
import { DataRow } from '../../data/data-row.model';
import { DataSorting } from '../../data/data-sorting.model';
import { DataTableAdapter } from '../../data/datatable-adapter';
import { DataTableRowComponent } from '../datatable-row/datatable-row.component';
import { ObjectDataRow } from '../../data/object-datarow.model';
import { ObjectDataColumn } from '../../data/object-datacolumn.model';
import { ObjectDataRow } from '../../data/object-datarow.model';
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
import { DropZoneDirective } from '../../directives/drop-zone.directive';
import { ResizableModule } from '../../directives/resizable/resizable.module';
import { ResizeEvent } from '../../directives/resizable/types';
import { AmountCellComponent } from '../amount-cell/amount-cell.component';
import { BooleanCellComponent } from '../boolean-cell/boolean-cell.component';
import { DataCellEvent } from '../data-cell.event';
import { DataRowActionEvent } from '../data-row-action.event';
import { buffer, debounceTime, filter, map, share } from 'rxjs/operators';
import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
import { ResizeEvent } from '../../directives/resizable/types';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
import { DataTableRowComponent } from '../datatable-row/datatable-row.component';
import { DateCellComponent } from '../date-cell/date-cell.component';
import { FileSizeCellComponent } from '../filesize-cell/filesize-cell.component';
import { IconCellComponent } from '../icon-cell/icon-cell.component';
import { JsonCellComponent } from '../json-cell/json-cell.component';
import { LocationCellComponent } from '../location-cell/location-cell.component';
import { NumberCellComponent } from '../number-cell/number-cell.component';
// eslint-disable-next-line no-shadow
export enum ShowHeaderMode {
@ -71,9 +91,40 @@ export enum ShowHeaderMode {
@Component({
selector: 'adf-datatable',
standalone: true,
templateUrl: './datatable.component.html',
styleUrls: ['./datatable.component.scss'],
encapsulation: ViewEncapsulation.None,
imports: [
CommonModule,
DragDropModule,
DataTableRowComponent,
TranslateModule,
MatCheckboxModule,
ResizableModule,
DropZoneDirective,
MatTooltipModule,
MatMenuModule,
MatIconModule,
MatButtonModule,
MatFormFieldModule,
MatSelectModule,
DirectiveModule,
ContextMenuModule,
IconCellComponent,
DateCellComponent,
LocationCellComponent,
FileSizeCellComponent,
DataTableCellComponent,
BooleanCellComponent,
JsonCellComponent,
AmountCellComponent,
NumberCellComponent,
LocalizedDatePipe,
FilterOutArrayObjectsByPropPipe,
FileTypePipe,
IconComponent
],
host: { class: 'adf-datatable' }
})
export class DataTableComponent implements OnInit, AfterContentInit, OnChanges, DoCheck, OnDestroy, AfterViewInit {

View File

@ -1,14 +1,12 @@
<ng-container *ngIf="value$ | async as date">
<span
[title]="tooltip | adfLocalizedDate: config.tooltipFormat: config.locale"
class="adf-datatable-cell-value"
*ngIf="config.format === 'timeAgo'; else standard_date">
<span [title]="tooltip | adfLocalizedDate: config.tooltipFormat: config.locale"
class="adf-datatable-cell-value"
*ngIf="config.format === 'timeAgo'; else standard_date">
{{ date | adfTimeAgo: config.locale }}
</span>
<ng-template #standard_date>
<span
class="adf-datatable-cell-value"
[title]="tooltip | adfLocalizedDate: config.tooltipFormat: config.locale">
<span class="adf-datatable-cell-value"
[title]="tooltip | adfLocalizedDate: config.tooltipFormat: config.locale">
{{ date | adfLocalizedDate: config.format: config.locale }}
</span>
</ng-template>

View File

@ -15,16 +15,16 @@
* limitations under the License.
*/
import { registerLocaleData } from '@angular/common';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import localePL from '@angular/common/locales/pl';
import { LOCALE_ID } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DateCellComponent } from './date-cell.component';
import { DataColumn, DateConfig } from '../../data/data-column.model';
import { BehaviorSubject } from 'rxjs';
import { AppConfigService } from '../../../app-config';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TranslateModule } from '@ngx-translate/core';
import { LOCALE_ID } from '@angular/core';
import { registerLocaleData } from '@angular/common';
import localePL from '@angular/common/locales/pl';
import { CoreTestingModule } from '../../../testing';
import { DataColumn, DateConfig } from '../../data/data-column.model';
import { DateCellComponent } from './date-cell.component';
let component: DateCellComponent;
let appConfigService: AppConfigService;
@ -62,11 +62,7 @@ const checkDisplayedTooltip = (expectedTooltip: string) => {
const configureTestingModule = (providers: any[]) => {
TestBed.configureTestingModule({
imports: [
DateCellComponent,
HttpClientTestingModule,
TranslateModule.forRoot()
],
imports: [CoreTestingModule, DateCellComponent, HttpClientTestingModule],
providers
});
fixture = TestBed.createComponent(DateCellComponent);

View File

@ -15,12 +15,12 @@
* limitations under the License.
*/
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
import { AppConfigService } from '../../../app-config/app-config.service';
import { DateConfig } from '../../data/data-column.model';
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, inject, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { AppConfigService } from '../../../app-config';
import { LocalizedDatePipe, TimeAgoPipe } from '../../../pipes';
import { DateConfig } from '../../data/data-column.model';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
@Component({
standalone: true,
@ -32,7 +32,6 @@ import { LocalizedDatePipe, TimeAgoPipe } from '../../../pipes';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DateCellComponent extends DataTableCellComponent implements OnInit {
@Input()
dateConfig: DateConfig;

View File

@ -16,8 +16,8 @@
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreTestingModule } from '../../../testing';
import { EmptyListComponent } from './empty-list.component';
import { CoreTestingModule } from '../../../testing/core.testing.module';
describe('EmptyListComponentComponent', () => {
let fixture: ComponentFixture<EmptyListComponent>;

View File

@ -19,12 +19,27 @@ import { Component, Directive, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'adf-empty-list',
standalone: true,
styleUrls: ['./empty-list.component.scss'],
templateUrl: './empty-list.component.html',
encapsulation: ViewEncapsulation.None
})
export class EmptyListComponent {}
@Directive({ selector: '[adf-empty-list-header]' }) export class EmptyListHeaderDirective {}
@Directive({ selector: '[adf-empty-list-body]' }) export class EmptyListBodyDirective {}
@Directive({ selector: '[adf-empty-list-footer]' }) export class EmptyListFooterDirective {}
@Directive({
selector: '[adf-empty-list-header]',
standalone: true
})
export class EmptyListHeaderDirective {}
@Directive({
selector: '[adf-empty-list-body]',
standalone: true
})
export class EmptyListBodyDirective {}
@Directive({
selector: '[adf-empty-list-footer]',
standalone: true
})
export class EmptyListFooterDirective {}

View File

@ -15,21 +15,24 @@
* limitations under the License.
*/
import { AsyncPipe, NgIf } from '@angular/common';
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { FileSizePipe } from '../../../pipes';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
@Component({
selector: 'adf-filesize-cell',
standalone: true,
template: `
<ng-container *ngIf="value$ | async | adfFileSize as fileSize">
<span [title]="tooltip">{{ fileSize }}</span>
</ng-container>
`,
encapsulation: ViewEncapsulation.None,
imports: [NgIf, AsyncPipe, FileSizePipe],
host: { class: 'adf-filesize-cell' }
})
export class FileSizeCellComponent extends DataTableCellComponent implements OnInit {
ngOnInit(): void {
super.ngOnInit();
}

View File

@ -15,14 +15,14 @@
* limitations under the License.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { IconCellComponent } from './icon-cell.component';
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
import { ObjectDataColumn } from '../../data/object-datacolumn.model';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatIconHarness } from '@angular/material/icon/testing';
import { ObjectDataColumn } from '../../data/object-datacolumn.model';
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
import { IconCellComponent } from './icon-cell.component';
describe('IconCellComponent', () => {
let component: IconCellComponent;

View File

@ -18,8 +18,8 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, ViewEncapsulation } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
import { takeUntil } from 'rxjs/operators';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
@Component({
standalone: true,

View File

@ -0,0 +1,7 @@
<ng-container *ngIf="value$ | async as value; else editEmpty">
<button mat-button color="primary" (click)="view()">json</button>
</ng-container>
<ng-template #editEmpty>
<button *ngIf="editable" mat-button color="primary" (click)="view()">json</button>
</ng-template>

View File

@ -15,14 +15,14 @@
* limitations under the License.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
import { ObjectDataColumn } from '../../data/object-datacolumn.model';
import { CoreTestingModule } from '../../../testing/core.testing.module';
import { JsonCellComponent } from './json-cell.component';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatButtonHarness } from '@angular/material/button/testing';
import { CoreTestingModule } from '../../../testing';
import { ObjectDataColumn } from '../../data/object-datacolumn.model';
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
import { JsonCellComponent } from './json-cell.component';
describe('JsonCellComponent', () => {
let loader: HarnessLoader;

View File

@ -15,25 +15,21 @@
* limitations under the License.
*/
import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation, Input } from '@angular/core';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
import { AsyncPipe, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog';
import { EditJsonDialogComponent, EditJsonDialogSettings } from '../../../dialogs/edit-json/edit-json.dialog';
import { EditJsonDialogComponent, EditJsonDialogSettings } from '../../../dialogs';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
@Component({
selector: 'adf-json-cell',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<ng-container *ngIf="value$ | async as value; else editEmpty">
<button mat-button color="primary" (click)="view()">json</button>
</ng-container>
<ng-template #editEmpty>
<button *ngIf="editable" mat-button color="primary" (click)="view()">json</button>
</ng-template>
`,
templateUrl: './json-cell.component.html',
styleUrls: ['./json-cell.component.scss'],
encapsulation: ViewEncapsulation.None,
imports: [AsyncPipe, MatButtonModule, NgIf],
host: { class: 'adf-datatable-content-cell' }
})
export class JsonCellComponent extends DataTableCellComponent implements OnInit {

View File

@ -16,10 +16,10 @@
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
import { CoreTestingModule } from '../../../testing';
import { ObjectDataColumn } from '../../data/object-datacolumn.model';
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
import { LocationCellComponent } from './location-cell.component';
import { CoreTestingModule } from '../../../testing/core.testing.module';
describe('LocationCellComponent', () => {
let component: LocationCellComponent;
@ -30,10 +30,7 @@ describe('LocationCellComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
LocationCellComponent,
CoreTestingModule
]
imports: [LocationCellComponent, CoreTestingModule]
});
fixture = TestBed.createComponent(LocationCellComponent);
component = fixture.componentInstance;
@ -52,12 +49,9 @@ describe('LocationCellComponent', () => {
}
};
columnData = { format: '/files', type: 'location', key: 'path'};
columnData = { format: '/files', type: 'location', key: 'path' };
dataTableAdapter = new ObjectDataTableAdapter(
[rowData],
[ new ObjectDataColumn(columnData) ]
);
dataTableAdapter = new ObjectDataTableAdapter([rowData], [new ObjectDataColumn(columnData)]);
component.link = [];
component.column = dataTableAdapter.getColumns()[0];
@ -78,7 +72,7 @@ describe('LocationCellComponent', () => {
it('should set router link', () => {
fixture.detectChanges();
expect(component.link).toEqual([ columnData.format , rowData.path.elements[2].id ]);
expect(component.link).toEqual([columnData.format, rowData.path.elements[2].id]);
});
it('should NOT set router link when format NOT provided', () => {
@ -99,7 +93,7 @@ describe('LocationCellComponent', () => {
expect(value).toBe('');
done();
});
});
});
it('should not setup cell when path is missing required properties', (done) => {
rowData.path = { someProp: '' };

View File

@ -15,15 +15,15 @@
* limitations under the License.
*/
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
import { AsyncPipe } from '@angular/common';
import { RouterModule } from '@angular/router';
import { PathInfo } from '@alfresco/js-api';
import { AsyncPipe } from '@angular/common';
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { RouterModule } from '@angular/router';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
@Component({
standalone: true,
imports: [AsyncPipe, RouterModule],
standalone: true,
selector: 'adf-location-cell',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `

View File

@ -22,11 +22,12 @@ export const mockCarsData: any = [
{
car_id: 1,
car_name: 'Fiat 126p (Process)',
car_price: 599.00,
car_price: 599.0,
fuel_consumption: 5.25789,
is_available: 'false',
production_start: '1972-04-23',
description: 'The Fiat 126 (Type 126) is a four-passenger, rear-engine, city car manufactured and marketed by Fiat over a twenty-eight year production run from 1972 until 2000, over a single generation.',
description:
'The Fiat 126 (Type 126) is a four-passenger, rear-engine, city car manufactured and marketed by Fiat over a twenty-eight year production run from 1972 until 2000, over a single generation.',
icon: 'airport_shuttle',
wikipedia_link: 'https://en.wikipedia.org/wiki/Fiat_126'
},
@ -48,7 +49,8 @@ export const mockCarsData: any = [
fuel_consumption: 6,
is_available: 'true',
production_start: '1998-06-25T12:25:20',
description: 'The Audi A3 is a subcompact executive/small family car (C-segment) manufactured and marketed by the German automaker Audi AG since September 1996, currently in its fourth generation.',
description:
'The Audi A3 is a subcompact executive/small family car (C-segment) manufactured and marketed by the German automaker Audi AG since September 1996, currently in its fourth generation.',
icon: 'directions_car',
wikipedia_link: 'https://en.wikipedia.org/wiki/Audi_A3'
}

View File

@ -1,8 +1,9 @@
<ng-container *ngIf="value$ | async as number">
<span [title]="number">
{{ number | number:
(decimalConfig?.digitsInfo || defaultDecimalConfig.digitsInfo):
(decimalConfig?.locale || defaultDecimalConfig.locale)
{{
number | number:
(decimalConfig?.digitsInfo || defaultDecimalConfig.digitsInfo):
(decimalConfig?.locale || defaultDecimalConfig.locale)
}}
</span>
</ng-container>

View File

@ -15,13 +15,13 @@
* limitations under the License.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NumberCellComponent } from './number-cell.component';
import { DecimalConfig } from '../../data/data-column.model';
import { BehaviorSubject } from 'rxjs';
import { LOCALE_ID } from '@angular/core';
import { registerLocaleData } from '@angular/common';
import localePL from '@angular/common/locales/pl';
import { LOCALE_ID } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BehaviorSubject } from 'rxjs';
import { DecimalConfig } from '../../data/data-column.model';
import { NumberCellComponent } from './number-cell.component';
describe('NumberCellComponent', () => {
let component: NumberCellComponent;

View File

@ -15,20 +15,14 @@
* limitations under the License.
*/
import {
ChangeDetectionStrategy,
Component,
ViewEncapsulation,
Input,
OnInit
} from '@angular/core';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
import { AsyncPipe, DecimalPipe, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { DecimalConfig } from '../../data/data-column.model';
import { CommonModule } from '@angular/common';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
@Component({
imports: [AsyncPipe, DecimalPipe, NgIf],
standalone: true,
imports: [CommonModule],
selector: 'adf-number-cell',
templateUrl: './number-cell.component.html',
host: { class: 'adf-datatable-content-cell' },
@ -36,7 +30,6 @@ import { CommonModule } from '@angular/common';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NumberCellComponent extends DataTableCellComponent implements OnInit {
@Input()
decimalConfig: DecimalConfig;

View File

@ -22,10 +22,10 @@ import { DataColumnComponent } from './data-column.component';
@Component({
selector: 'adf-data-column-header',
standalone: true,
template: ''
})
export class DateColumnHeaderComponent implements AfterContentInit {
@ContentChild(TemplateRef)
public header: TemplateRef<any>;

View File

@ -15,17 +15,16 @@
* limitations under the License.
*/
/* eslint-disable @angular-eslint/component-selector */
/* eslint-disable @angular-eslint/component-selector */
import { Component, ContentChildren, QueryList } from '@angular/core';
import { DataColumnComponent } from './data-column.component';
@Component({
selector: 'data-columns',
standalone: true,
template: ''
})
export class DataColumnListComponent {
@ContentChildren(DataColumnComponent) columns: QueryList<DataColumnComponent>;
}

View File

@ -15,9 +15,9 @@
* limitations under the License.
*/
import { DataColumnComponent } from './data-column.component';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { TestBed } from '@angular/core/testing';
import { CoreTestingModule } from '../../testing';
import { DataColumnComponent } from './data-column.component';
describe('DataColumnListComponent', () => {
beforeEach(() => {

View File

@ -15,30 +15,25 @@
* limitations under the License.
*/
import { Meta, moduleMetadata, Story } from '@storybook/angular';
import { DataColumnComponent } from './data-column.component';
import { DataTableModule } from '../datatable.module';
import { CoreStoryModule } from '../../testing/core.story.module';
import * as mockData from '../../mock/data-column.mock';
import { RouterTestingModule } from '@angular/router/testing';
import { Meta, moduleMetadata, Story } from '@storybook/angular';
import * as mockData from '../../mock/data-column.mock';
import { CoreStoryModule } from '../../testing/core.story.module';
import { DataTableModule } from '../datatable.module';
import { DataRow } from '../index';
import { DataColumnComponent } from './data-column.component';
export default {
component: DataColumnComponent,
title: 'Core/Data Column/Data Column',
decorators: [
moduleMetadata({
imports: [
CoreStoryModule,
DataTableModule,
RouterTestingModule
]
imports: [CoreStoryModule, DataTableModule, RouterTestingModule]
})
],
argTypes: {
copyContent: {
description:
'Enables/disables a Clipboard directive to allow copying of cell contents.',
description: 'Enables/disables a Clipboard directive to allow copying of cell contents.',
control: { type: 'boolean' },
defaultValue: false,
table: {
@ -49,8 +44,7 @@ export default {
}
},
cssClass: {
description:
'Additional CSS class to be applied to column (header and cells).',
description: 'Additional CSS class to be applied to column (header and cells).',
control: { type: 'text' },
defaultValue: '',
table: {
@ -61,8 +55,7 @@ export default {
}
},
customData: {
description:
'You can specify any custom data which can be used by any specific feature',
description: 'You can specify any custom data which can be used by any specific feature',
control: { disable: true },
table: {
category: 'Component Inputs',
@ -127,8 +120,7 @@ export default {
}
},
format: {
description:
'Used for location type. Setups root path for router navigation.',
description: 'Used for location type. Setups root path for router navigation.',
control: { type: 'text', disable: true },
table: {
category: 'Component Inputs',
@ -175,8 +167,7 @@ export default {
}
},
key: {
description:
'Data source key. Can be either a column/property key like title or a property path like `createdBy.name`.',
description: 'Data source key. Can be either a column/property key like title or a property path like `createdBy.name`.',
control: { type: 'text', disable: false },
table: {
category: 'Component Inputs',
@ -186,8 +177,7 @@ export default {
}
},
sortable: {
description:
'Toggles ability to sort by this column, for example by clicking the column header.',
description: 'Toggles ability to sort by this column, for example by clicking the column header.',
control: { type: 'boolean' },
defaultValue: true,
table: {
@ -201,8 +191,7 @@ export default {
}
},
sortingKey: {
description:
'When using server side sorting the column used by the api call where the sorting will be performed',
description: 'When using server side sorting the column used by the api call where the sorting will be performed',
control: { disable: true },
table: {
category: 'Component Inputs',
@ -241,18 +230,7 @@ export default {
description:
'Value type for the column. Possible settings are: `text`, `icon`, `image`, `date`, `fileSize`, `location`, `boolean`, `amount`, `number` and `json`.',
control: { type: 'select', disable: false },
options: [
'text',
'icon',
'image',
'date',
'fileSize',
'location',
'boolean',
'amount',
'number',
'json'
],
options: ['text', 'icon', 'image', 'date', 'fileSize', 'location', 'boolean', 'amount', 'number', 'json'],
table: {
category: 'Component Inputs',
type: {
@ -265,8 +243,7 @@ export default {
defaultValue: 'text'
},
currencyConfig: {
description:
`The currencyConfig input allows you to customize the formatting and display of currency values within the component.`,
description: `The currencyConfig input allows you to customize the formatting and display of currency values within the component.`,
control: { type: 'object', disable: true },
table: {
category: 'Component Inputs',
@ -285,8 +262,7 @@ export default {
}
},
decimalConfig: {
description:
`The decimalConfig input allows you to customize the formatting and display of decimal values within the component.`,
description: `The decimalConfig input allows you to customize the formatting and display of decimal values within the component.`,
control: { type: 'object', disable: true },
table: {
category: 'Component Inputs',
@ -303,8 +279,7 @@ export default {
}
},
dateConfig: {
description:
`The dateConfig input allows you to configure date formatting and localization for a component.`,
description: `The dateConfig input allows you to configure date formatting and localization for a component.`,
control: { type: 'object', disable: true },
table: {
category: 'Component Inputs',
@ -334,8 +309,7 @@ export default {
}
} as Meta;
const formatCustomTooltip = (row: DataRow): string =>
row ? 'This is ' + row.getValue('firstname') : null;
const formatCustomTooltip = (row: DataRow): string => (row ? 'This is ' + row.getValue('firstname') : null);
const template: Story<DataColumnComponent> = (args: DataColumnComponent & { rows: DataRow[] }) => ({
props: args,
@ -453,8 +427,8 @@ fileSizeColumn.args = {
export const locationColumn: Story = template.bind({});
locationColumn.argTypes = {
copyContent: { control: { disable: true } },
format: { control: { disable: false }},
sortable: { control: { disable: true }}
format: { control: { disable: false } },
sortable: { control: { disable: true } }
};
locationColumn.args = {
rows: mockData.locationColumnRows,
@ -514,4 +488,3 @@ numberColumn.args = {
type: 'number',
title: 'Number Column'
};

View File

@ -15,18 +15,18 @@
* limitations under the License.
*/
/* eslint-disable @angular-eslint/component-selector, @angular-eslint/no-input-rename */
/* eslint-disable @angular-eslint/component-selector, @angular-eslint/no-input-rename */
import { Component, ContentChild, Input, OnInit, TemplateRef } from '@angular/core';
import { DataColumnType } from '@alfresco/adf-extensions';
import { Component, ContentChild, Input, OnInit, TemplateRef } from '@angular/core';
import { CurrencyConfig, DateConfig, DecimalConfig } from '../data/data-column.model';
@Component({
selector: 'data-column',
standalone: true,
template: ''
})
export class DataColumnComponent implements OnInit {
/** Id of the Column */
@Input()
id: string = '';
@ -91,7 +91,7 @@ export class DataColumnComponent implements OnInit {
@Input('class')
cssClass: string;
/** Enables/disables a Clipboard directive to allow copying of cell contents. */
/** Enables/disables a Clipboard directive to allow copying of cell contents. */
@Input()
copyContent: boolean;

View File

@ -15,26 +15,13 @@
* limitations under the License.
*/
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { DateColumnHeaderComponent } from './data-column-header.component';
import { DataColumnListComponent } from './data-column-list.component';
import { DataColumnComponent } from './data-column.component';
import { DateColumnHeaderComponent } from './data-column-header.component';
@NgModule({
imports: [
CommonModule
],
declarations: [
DataColumnComponent,
DataColumnListComponent,
DateColumnHeaderComponent
],
exports: [
DataColumnComponent,
DataColumnListComponent,
DateColumnHeaderComponent
]
imports: [DataColumnComponent, DataColumnListComponent, DateColumnHeaderComponent],
exports: [DataColumnComponent, DataColumnListComponent, DateColumnHeaderComponent]
})
export class DataColumnModule {}

View File

@ -17,8 +17,8 @@
/* eslint-disable id-blacklist */
import { TemplateRef } from '@angular/core';
import { DataColumnType } from '@alfresco/adf-extensions';
import { TemplateRef } from '@angular/core';
export interface DataColumn<T = unknown> {
id?: string;

View File

@ -16,10 +16,5 @@
*/
export class DataSorting {
constructor(
public key?: string,
public direction?: string,
public options?: Intl.CollatorOptions
) {
}
constructor(public key?: string, public direction?: string, public options?: Intl.CollatorOptions) {}
}

View File

@ -15,10 +15,10 @@
* limitations under the License.
*/
import { ContentChild, Input, Directive } from '@angular/core';
import { ContentChild, Directive, Input } from '@angular/core';
import { ReplaySubject } from 'rxjs';
import { AppConfigService } from '../../app-config/app-config.service';
import { DataColumnListComponent } from '../data-column/data-column-list.component';
import { AppConfigService } from '../../app-config';
import { DataColumnListComponent } from '../data-column';
import { DataColumn } from './data-column.model';
import { ObjectDataColumn } from './object-datacolumn.model';

View File

@ -15,22 +15,31 @@
* limitations under the License.
*/
import { Subject } from 'rxjs';
import { DataColumn } from './data-column.model';
import { DataRow } from './data-row.model';
import { DataSorting } from './data-sorting.model';
import { Subject } from 'rxjs';
export interface DataTableAdapter {
rowsChanged?: Subject<Array<DataRow>>;
selectedRow: DataRow;
getRows(): Array<DataRow>;
setRows(rows: Array<DataRow>): void;
getColumns(): Array<DataColumn>;
setColumns(columns: Array<DataColumn>): void;
getValue(row: DataRow, col: DataColumn, resolverFn?: (_row: DataRow, _col: DataColumn) => any): any;
getColumnType(row: DataRow, col: DataColumn): string;
getSorting(): DataSorting;
setSorting(sorting: DataSorting): void;
sort(key?: string, direction?: string): void;
}

View File

@ -15,9 +15,9 @@
* limitations under the License.
*/
import { TemplateRef } from '@angular/core';
import { DataColumnType } from '@alfresco/adf-extensions';
import { CurrencyConfig, DataColumn, DecimalConfig, DateConfig } from './data-column.model';
import { TemplateRef } from '@angular/core';
import { CurrencyConfig, DataColumn, DateConfig, DecimalConfig } from './data-column.model';
// Simple implementation of the DataColumn interface.
export class ObjectDataColumn<T = unknown> implements DataColumn<T> {

View File

@ -15,17 +15,15 @@
* limitations under the License.
*/
import { ObjectUtils } from '../../common/utils';
import { ObjectUtils } from '../../common';
import { DataRow } from './data-row.model';
// Simple implementation of the DataRow interface.
export class ObjectDataRow implements DataRow {
constructor(private obj: any, public isSelected: boolean = false) {
if (!obj) {
throw new Error('Object source not found');
}
}
getValue(key: string): any {

View File

@ -18,12 +18,11 @@
import { DataColumn } from './data-column.model';
import { DataRow } from './data-row.model';
import { DataSorting } from './data-sorting.model';
import { ObjectDataTableAdapter } from './object-datatable-adapter';
import { ObjectDataRow } from './object-datarow.model';
import { ObjectDataColumn } from './object-datacolumn.model';
import { ObjectDataRow } from './object-datarow.model';
import { ObjectDataTableAdapter } from './object-datatable-adapter';
describe('ObjectDataTableAdapter', () => {
it('should init with empty row collection', () => {
const adapter = new ObjectDataTableAdapter(null, []);
expect(adapter.getRows()).toBeDefined();
@ -46,10 +45,7 @@ describe('ObjectDataTableAdapter', () => {
});
it('should map columns without rows', () => {
const adapter = new ObjectDataTableAdapter(null, [
{} as DataColumn,
{} as DataColumn
]);
const adapter = new ObjectDataTableAdapter(null, [{} as DataColumn, {} as DataColumn]);
const columns = adapter.getColumns();
expect(columns.length).toBe(2);
@ -99,7 +95,7 @@ describe('ObjectDataTableAdapter', () => {
it('should apply new columns array', () => {
const adapter = new ObjectDataTableAdapter([], []);
const columns = [{},{}] as DataColumn[];
const columns = [{}, {}] as DataColumn[];
adapter.setColumns(columns);
expect(adapter.getColumns()).toBe(columns);
@ -116,10 +112,7 @@ describe('ObjectDataTableAdapter', () => {
});
it('should reset columns by null value', () => {
const adapter = new ObjectDataTableAdapter([], [
{} as DataColumn,
{} as DataColumn
]);
const adapter = new ObjectDataTableAdapter([], [{} as DataColumn, {} as DataColumn]);
expect(adapter.getColumns()).toBeDefined();
expect(adapter.getColumns().length).toBe(2);
@ -188,9 +181,7 @@ describe('ObjectDataTableAdapter', () => {
{ id: 2, name: 'abs' },
{ id: 1, name: 'xyz' }
],
[
new ObjectDataColumn({ key: 'id', sortable: true })
]
[new ObjectDataColumn({ key: 'id', sortable: true })]
);
const rows = adapter.getRows();
@ -199,10 +190,16 @@ describe('ObjectDataTableAdapter', () => {
});
it('should take first sortable column by default', () => {
const adapter = new ObjectDataTableAdapter([], [
{ key: 'icon' } as DataColumn,
new ObjectDataColumn({ key: 'id', sortable: true })
]);
const adapter = new ObjectDataTableAdapter(
[],
[
{ key: 'icon' } as DataColumn,
new ObjectDataColumn({
key: 'id',
sortable: true
})
]
);
expect(adapter.getSorting()).toEqual(
jasmine.objectContaining({
@ -221,10 +218,7 @@ describe('ObjectDataTableAdapter', () => {
{ id: 1, created: new Date(2016, 7, 6, 15, 7, 2) },
{ id: 2, created: new Date(2016, 7, 6, 15, 7, 1) }
],
[
{ key: 'id' } as DataColumn,
{ key: 'created' } as DataColumn
]
[{ key: 'id' } as DataColumn, { key: 'created' } as DataColumn]
);
adapter.setSorting(new DataSorting('created', 'asc', { numeric: true }));
@ -235,11 +229,7 @@ describe('ObjectDataTableAdapter', () => {
});
it('should sort by numbers', () => {
const adapter = new ObjectDataTableAdapter([
{ id: 123 },
{ id: 38 },
{ id: 50 }
],[{key: 'id'} as DataColumn]);
const adapter = new ObjectDataTableAdapter([{ id: 123 }, { id: 38 }, { id: 50 }], [{ key: 'id' } as DataColumn]);
adapter.setSorting(new DataSorting('id', 'asc', { numeric: true }));
@ -255,10 +245,7 @@ describe('ObjectDataTableAdapter', () => {
{ id: 2, name: 'abs' },
{ id: 1, name: 'xyz' }
],
[
new ObjectDataColumn({ key: 'id' }),
new ObjectDataColumn({ key: 'name' })
]
[new ObjectDataColumn({ key: 'id' }), new ObjectDataColumn({ key: 'name' })]
);
expect(adapter.getSorting()).toBeUndefined();
@ -270,9 +257,7 @@ describe('ObjectDataTableAdapter', () => {
{ id: 2, name: 'abs' },
{ id: 1, name: 'xyz' }
],
[
new ObjectDataColumn({ key: 'id', sortable: true })
]
[new ObjectDataColumn({ key: 'id', sortable: true })]
);
adapter.setSorting(new DataSorting('id', 'asc', { numeric: true }));
@ -316,7 +301,6 @@ describe('ObjectDataTableAdapter', () => {
});
describe('ObjectDataRow', () => {
it('should require object source', () => {
expect(() => new ObjectDataRow(null)).toThrowError('Object source not found');
});
@ -335,10 +319,10 @@ describe('ObjectDataRow', () => {
it('should get nested property value', () => {
const row = new ObjectDataRow({
name: {
firstName: 'John',
lastName: 'Doe'
}
name: {
firstName: 'John',
lastName: 'Doe'
}
});
expect(row.getValue('name.lastName')).toBe('Doe');
@ -370,7 +354,7 @@ describe('ObjectDataRow', () => {
});
it('should generateSchema generate a schema from data', () => {
const data = [
const data = [
{ id: 2, name: 'abs' },
{ id: 1, name: 'xyz' }
];

View File

@ -15,13 +15,13 @@
* limitations under the License.
*/
import { Subject } from 'rxjs';
import { DataColumn } from './data-column.model';
import { DataRow } from './data-row.model';
import { ObjectDataRow } from './object-datarow.model';
import { ObjectDataColumn } from './object-datacolumn.model';
import { DataSorting } from './data-sorting.model';
import { DataTableAdapter } from './datatable-adapter';
import { Subject } from 'rxjs';
import { ObjectDataColumn } from './object-datacolumn.model';
import { ObjectDataRow } from './object-datarow.model';
// Simple implementation of the DataTableAdapter interface.
export class ObjectDataTableAdapter implements DataTableAdapter {

View File

@ -15,85 +15,50 @@
* limitations under the License.
*/
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { MaterialModule } from '../material.module';
import { ContextMenuModule } from '../context-menu/context-menu.module';
import { PipeModule } from '../pipes/pipe.module';
import { DirectiveModule } from '../directives/directive.module';
import { LocalizedDatePipe } from '../pipes';
import { AmountCellComponent } from './components/amount-cell/amount-cell.component';
import { BooleanCellComponent } from './components/boolean-cell/boolean-cell.component';
import { ColumnsSelectorComponent } from './components/columns-selector/columns-selector.component';
import { DataTableCellComponent } from './components/datatable-cell/datatable-cell.component';
import { DataTableRowComponent } from './components/datatable-row/datatable-row.component';
import { DataTableComponent } from './components/datatable/datatable.component';
import { DateCellComponent } from './components/date-cell/date-cell.component';
import { ColumnsSelectorComponent } from './components/columns-selector/columns-selector.component';
import { EmptyListBodyDirective,
import {
EmptyListBodyDirective,
EmptyListComponent,
EmptyListFooterDirective,
EmptyListHeaderDirective } from './components/empty-list/empty-list.component';
EmptyListHeaderDirective
} from './components/empty-list/empty-list.component';
import { FileSizeCellComponent } from './components/filesize-cell/filesize-cell.component';
import { IconCellComponent } from './components/icon-cell/icon-cell.component';
import { JsonCellComponent } from './components/json-cell/json-cell.component';
import { LocationCellComponent } from './components/location-cell/location-cell.component';
import { LoadingContentTemplateDirective } from './directives/loading-template.directive';
import { NoContentTemplateDirective } from './directives/no-content-template.directive';
import { NoPermissionTemplateDirective } from './directives/no-permission-template.directive';
import { HeaderFilterTemplateDirective } from './directives/header-filter-template.directive';
import { NumberCellComponent } from './components/number-cell/number-cell.component';
import { DataColumnComponent, DataColumnListComponent, DateColumnHeaderComponent } from './data-column';
import { CustomEmptyContentTemplateDirective } from './directives/custom-empty-content-template.directive';
import { CustomLoadingContentTemplateDirective } from './directives/custom-loading-template.directive';
import { CustomNoPermissionTemplateDirective } from './directives/custom-no-permission-template.directive';
import { MainMenuDataTableTemplateDirective } from './directives/main-data-table-action-template.directive';
import { JsonCellComponent } from './components/json-cell/json-cell.component';
import { ClipboardModule } from '../clipboard/clipboard.module';
import { DropZoneDirective } from './directives/drop-zone.directive';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { IconModule } from '../icon/icon.module';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { DataColumnComponent, DataColumnListComponent, DateColumnHeaderComponent } from './data-column';
import { ResizableModule } from './directives/resizable/resizable.module';
import { DataColumnModule } from './data-column/data-column.module';
import { BooleanCellComponent } from './components/boolean-cell/boolean-cell.component';
import { AmountCellComponent } from './components/amount-cell/amount-cell.component';
import { NumberCellComponent } from './components/number-cell/number-cell.component';
import { LocalizedDatePipe } from '../pipes';
import { IconCellComponent } from './components/icon-cell/icon-cell.component';
import { HeaderFilterTemplateDirective } from './directives/header-filter-template.directive';
import { LoadingContentTemplateDirective } from './directives/loading-template.directive';
import { MainMenuDataTableTemplateDirective } from './directives/main-data-table-action-template.directive';
import { NoContentTemplateDirective } from './directives/no-content-template.directive';
import { NoPermissionTemplateDirective } from './directives/no-permission-template.directive';
@NgModule({
imports: [
RouterModule,
MaterialModule,
CommonModule,
TranslateModule,
ContextMenuModule,
PipeModule,
DirectiveModule,
ClipboardModule,
DragDropModule,
IconModule,
FormsModule,
ReactiveFormsModule,
ResizableModule,
DataColumnModule,
BooleanCellComponent,
AmountCellComponent,
NumberCellComponent,
LocationCellComponent,
DateCellComponent,
LocalizedDatePipe,
IconCellComponent
],
declarations: [
DataTableComponent,
EmptyListComponent,
EmptyListHeaderDirective,
EmptyListBodyDirective,
EmptyListFooterDirective,
DataTableCellComponent,
DataTableRowComponent,
DataColumnComponent,
DataColumnListComponent,
DateColumnHeaderComponent,
ColumnsSelectorComponent,
EmptyListComponent,
FileSizeCellComponent,
JsonCellComponent,
ColumnsSelectorComponent,
DropZoneDirective,
NoContentTemplateDirective,
NoPermissionTemplateDirective,
LoadingContentTemplateDirective,
@ -102,7 +67,16 @@ import { IconCellComponent } from './components/icon-cell/icon-cell.component';
CustomLoadingContentTemplateDirective,
CustomNoPermissionTemplateDirective,
MainMenuDataTableTemplateDirective,
DropZoneDirective
BooleanCellComponent,
AmountCellComponent,
NumberCellComponent,
LocationCellComponent,
DateCellComponent,
LocalizedDatePipe,
IconCellComponent,
EmptyListHeaderDirective,
EmptyListBodyDirective,
EmptyListFooterDirective
],
exports: [
DataTableComponent,

View File

@ -17,13 +17,8 @@
import { Directive } from '@angular/core';
/**
* Directive selectors without adf- prefix will be deprecated on 3.0.0.
* The empty-folder-content selector will be deprecated as it has been replace by
* adf-custom-empty-content-template.
*/
@Directive({
selector: 'adf-custom-empty-content-template, empty-folder-content'
selector: 'adf-custom-empty-content-template',
standalone: true
})
export class CustomEmptyContentTemplateDirective {}

View File

@ -18,6 +18,7 @@
import { Directive } from '@angular/core';
@Directive({
selector: 'adf-custom-loading-content-template'
selector: 'adf-custom-loading-content-template',
standalone: true
})
export class CustomLoadingContentTemplateDirective {}

View File

@ -17,12 +17,8 @@
import { Directive } from '@angular/core';
/**
* Directive selectors without adf- prefix will be deprecated on 3.0.0.
* The no-permission-content selector will be deprecated as it has been replace by
* adf-custom-no-permission-template.
*/
@Directive({
selector: 'adf-custom-no-permission-template, no-permission-content'
selector: 'adf-custom-no-permission-template',
standalone: true
})
export class CustomNoPermissionTemplateDirective {}

View File

@ -15,12 +15,13 @@
* limitations under the License.
*/
import { Directive, Input, ElementRef, NgZone, OnInit, OnDestroy } from '@angular/core';
import { DataRow } from '../data/data-row.model';
import { Directive, ElementRef, Input, NgZone, OnDestroy, OnInit } from '@angular/core';
import { DataColumn } from '../data/data-column.model';
import { DataRow } from '../data/data-row.model';
@Directive({
selector: '[adf-drop-zone]'
selector: '[adf-drop-zone]',
standalone: true
})
export class DropZoneDirective implements OnInit, OnDestroy {
private element: HTMLElement;

View File

@ -15,10 +15,10 @@
* limitations under the License.
*/
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreTestingModule } from '../../testing';
import { DataTableComponent } from '../components/datatable/datatable.component';
import { HeaderFilterTemplateDirective } from './header-filter-template.directive';
import { CoreTestingModule } from '../../testing/core.testing.module';
describe('HeaderFilterTemplateDirective', () => {
let fixture: ComponentFixture<DataTableComponent>;

View File

@ -19,15 +19,14 @@ import { AfterContentInit, ContentChild, Directive, TemplateRef } from '@angular
import { DataTableComponent } from '../components/datatable/datatable.component';
@Directive({
selector: 'adf-header-filter-template'
selector: 'adf-header-filter-template',
standalone: true
})
export class HeaderFilterTemplateDirective implements AfterContentInit {
@ContentChild(TemplateRef)
template: any;
constructor(private dataTable: DataTableComponent) {
}
constructor(private dataTable: DataTableComponent) {}
ngAfterContentInit() {
if (this.dataTable) {

View File

@ -15,10 +15,10 @@
* limitations under the License.
*/
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreTestingModule } from '../../testing';
import { DataTableComponent } from '../components/datatable/datatable.component';
import { LoadingContentTemplateDirective } from './loading-template.directive';
import { CoreTestingModule } from '../../testing/core.testing.module';
describe('LoadingContentTemplateDirective', () => {
let fixture: ComponentFixture<DataTableComponent>;

View File

@ -18,24 +18,19 @@
import { AfterContentInit, ContentChild, Directive, TemplateRef } from '@angular/core';
import { DataTableComponent } from '../components/datatable/datatable.component';
/**
* Directive selectors without adf- prefix will be deprecated on 3.0.0
*/
@Directive({
selector: 'adf-loading-content-template, loading-content-template'
selector: 'adf-loading-content-template',
standalone: true
})
export class LoadingContentTemplateDirective implements AfterContentInit {
@ContentChild(TemplateRef)
template: any;
constructor(private dataTable: DataTableComponent) {
}
constructor(private dataTable: DataTableComponent) {}
ngAfterContentInit() {
if (this.dataTable) {
this.dataTable.loadingTemplate = this.template;
}
}
}

View File

@ -15,12 +15,10 @@
* limitations under the License.
*/
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { DataTableComponent } from '../components/datatable/datatable.component';
import { MainMenuDataTableTemplateDirective } from './main-data-table-action-template.directive';
import { DataTableComponent, MainMenuDataTableTemplateDirective } from '@alfresco/adf-core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
describe('MainMenuDataTableTemplateDirective', () => {
let fixture: ComponentFixture<DataTableComponent>;
let dataTable: DataTableComponent;
let directive: MainMenuDataTableTemplateDirective;

View File

@ -19,10 +19,10 @@ import { AfterContentInit, ContentChild, Directive, TemplateRef } from '@angular
import { DataTableComponent } from '../components/datatable/datatable.component';
@Directive({
selector: 'adf-main-menu-datatable-template'
selector: 'adf-main-menu-datatable-template',
standalone: true
})
export class MainMenuDataTableTemplateDirective implements AfterContentInit {
@ContentChild(TemplateRef)
template: any;

View File

@ -15,10 +15,10 @@
* limitations under the License.
*/
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreTestingModule } from '../../testing';
import { DataTableComponent } from '../components/datatable/datatable.component';
import { NoContentTemplateDirective } from './no-content-template.directive';
import { CoreTestingModule } from '../../testing/core.testing.module';
describe('NoContentTemplateDirective', () => {
let fixture: ComponentFixture<DataTableComponent>;

View File

@ -22,15 +22,14 @@ import { DataTableComponent } from '../components/datatable/datatable.component'
* Directive selectors without adf- prefix will be deprecated on 3.0.0
*/
@Directive({
selector: 'adf-no-content-template, no-content-template'
selector: 'adf-no-content-template',
standalone: true
})
export class NoContentTemplateDirective implements AfterContentInit {
@ContentChild(TemplateRef)
template: any;
constructor(private dataTable: DataTableComponent) {
}
constructor(private dataTable: DataTableComponent) {}
ngAfterContentInit() {
if (this.dataTable) {

View File

@ -15,10 +15,10 @@
* limitations under the License.
*/
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreTestingModule } from '../../testing';
import { DataTableComponent } from '../components/datatable/datatable.component';
import { NoPermissionTemplateDirective } from './no-permission-template.directive';
import { CoreTestingModule } from '../../testing/core.testing.module';
describe('NoPermissionTemplateDirective', () => {
let fixture: ComponentFixture<DataTableComponent>;

View File

@ -22,15 +22,14 @@ import { DataTableComponent } from '../components/datatable/datatable.component'
* Directive selectors without adf- prefix will be deprecated on 3.0.0
*/
@Directive({
selector: 'adf-no-permission-template, no-permission-template'
selector: 'adf-no-permission-template',
standalone: true
})
export class NoPermissionTemplateDirective implements AfterContentInit {
@ContentChild(TemplateRef)
template: any;
constructor(private dataTable: DataTableComponent) {
}
constructor(private dataTable: DataTableComponent) {}
ngAfterContentInit() {
if (this.dataTable) {

View File

@ -15,8 +15,8 @@
* limitations under the License.
*/
import { TestBed } from '@angular/core/testing';
import { ElementRef, NgZone, Renderer2 } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { ResizableDirective } from './resizable.directive';
describe('ResizableDirective', () => {
@ -54,7 +54,7 @@ describe('ResizableDirective', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ResizableDirective],
imports: [ResizableDirective],
providers: [
{ provide: Renderer2, useValue: rendererMock },
{ provide: ElementRef, useValue: elementRefMock }
@ -103,7 +103,15 @@ describe('ResizableDirective', () => {
directive.mousedown.next({ ...mouseDownEvent, resize: true });
expect(directive.resizeStart.emit).toHaveBeenCalledWith({ rectangle: { top: 0, left: 0, bottom: 0, right: 0, width: 0 } });
expect(directive.resizeStart.emit).toHaveBeenCalledWith({
rectangle: {
top: 0,
left: 0,
bottom: 0,
right: 0,
width: 0
}
});
});
it('should unset cursor on mouseup', () => {
@ -125,7 +133,9 @@ describe('ResizableDirective', () => {
directive.mousedown.next({ ...mouseDownEvent, resize: true });
directive.mouseup.next(mouseUpEvent);
expect(directive.resizeEnd.emit).toHaveBeenCalledWith({ rectangle: { top: 0, left: 0, right: 0, width: 150, height: 0, bottom: 0, scrollTop: 0, scrollLeft: 0 } });
expect(directive.resizeEnd.emit).toHaveBeenCalledWith({
rectangle: { top: 0, left: 0, right: 0, width: 150, height: 0, bottom: 0, scrollTop: 0, scrollLeft: 0 }
});
});
it('should emit resizing on mousemove', () => {
@ -137,7 +147,15 @@ describe('ResizableDirective', () => {
directive.mousedown.next({ ...mouseDownEvent, resize: true });
directive.mousemove.next(mouseMoveEvent);
expect(directive.resizing.emit).toHaveBeenCalledWith({ rectangle: { top: 0, left: 0, bottom: 0, right: 120, width: 120 } });
expect(directive.resizing.emit).toHaveBeenCalledWith({
rectangle: {
top: 0,
left: 0,
bottom: 0,
right: 120,
width: 120
}
});
});
it('should emit resizing on mousemove considering cover padding', () => {
@ -151,6 +169,14 @@ describe('ResizableDirective', () => {
directive.mousedown.next({ ...mouseDownEvent, resize: true });
directive.mousemove.next(mouseMoveEvent);
expect(directive.resizing.emit).toHaveBeenCalledWith({ rectangle: { top: 0, left: 0, bottom: 0, right: 130, width: 130 } });
expect(directive.resizing.emit).toHaveBeenCalledWith({
rectangle: {
top: 0,
left: 0,
bottom: 0,
right: 130,
width: 130
}
});
});
});

View File

@ -15,13 +15,14 @@
* limitations under the License.
*/
import { Subject, Observable, Observer, merge } from 'rxjs';
import { BoundingRectangle, ResizeEvent, IResizeMouseEvent, ICoordinateX } from './types';
import { map, take, share, filter, pairwise, mergeMap, takeUntil } from 'rxjs/operators';
import { OnInit, Output, NgZone, OnDestroy, Directive, Renderer2, ElementRef, EventEmitter, Input } from '@angular/core';
import { Directive, ElementRef, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output, Renderer2 } from '@angular/core';
import { merge, Observable, Observer, Subject } from 'rxjs';
import { filter, map, mergeMap, pairwise, share, take, takeUntil } from 'rxjs/operators';
import { BoundingRectangle, ICoordinateX, IResizeMouseEvent, ResizeEvent } from './types';
@Directive({
selector: '[adf-resizable]',
standalone: true,
exportAs: 'adf-resizable'
})
export class ResizableDirective implements OnInit, OnDestroy {

View File

@ -20,7 +20,7 @@ import { ResizableDirective } from './resizable.directive';
import { ResizeHandleDirective } from './resize-handle.directive';
@NgModule({
declarations: [ResizableDirective, ResizeHandleDirective],
exports: [ResizableDirective, ResizeHandleDirective]
imports: [ResizableDirective, ResizeHandleDirective],
exports: [ResizableDirective, ResizeHandleDirective]
})
export class ResizableModule {}

View File

@ -15,8 +15,8 @@
* limitations under the License.
*/
import { TestBed } from '@angular/core/testing';
import { ElementRef, NgZone, Renderer2 } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { ResizeHandleDirective } from './resize-handle.directive';
describe('ResizeHandleDirective', () => {
@ -30,12 +30,14 @@ describe('ResizeHandleDirective', () => {
};
const elementRefMock = {
nativeElement: { dispatchEvent: () => { } }
nativeElement: {
dispatchEvent: () => {}
}
};
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ResizeHandleDirective],
imports: [ResizeHandleDirective],
providers: [
{ provide: Renderer2, useValue: rendererMock },
{ provide: ElementRef, useValue: elementRefMock }

View File

@ -15,12 +15,13 @@
* limitations under the License.
*/
import { Directive, ElementRef, Input, NgZone, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { Subject } from 'rxjs';
import { ResizableDirective } from './resizable.directive';
import { Input, OnInit, Directive, Renderer2, ElementRef, OnDestroy, NgZone } from '@angular/core';
@Directive({
selector: '[adf-resize-handle]'
selector: '[adf-resize-handle]',
standalone: true
})
export class ResizeHandleDirective implements OnInit, OnDestroy {
/**

View File

@ -52,6 +52,5 @@ export * from './directives/main-data-table-action-template.directive';
export * from './services/datatable.service';
export * from './datatable.module';
export * from './data-column';

View File

@ -15,35 +15,25 @@
* limitations under the License.
*/
import { Component, SimpleChange, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import {
AppConfigService,
ColumnsSelectorComponent,
CustomEmptyContentTemplateDirective,
DataColumn,
DataRowEvent,
DataTableModule,
getDataColumnMock,
ObjectDataRow,
User
} from '@alfresco/adf-core';
import { ProcessListCloudService } from '../services/process-list-cloud.service';
import { ProcessListCloudComponent } from './process-list-cloud.component';
import { fakeCustomSchema, fakeProcessCloudList, processListSchemaMock } from '../mock/process-list-service.mock';
import { of } from 'rxjs';
import { shareReplay, skip } from 'rxjs/operators';
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
import { ProcessListCloudSortingModel } from '../models/process-list-sorting.model';
import { PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN } from '../../../services/cloud-token.service';
import { ProcessListCloudPreferences } from '../models/process-cloud-preferences';
import { PROCESS_LIST_CUSTOM_VARIABLE_COLUMN } from '../../../models/data-column-custom-data';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { AppConfigService, ColumnsSelectorComponent, DataColumn, DataRowEvent, getDataColumnMock, ObjectDataRow, User } from '@alfresco/adf-core';
import { PreferenceCloudServiceInterface } from '@alfresco/adf-process-services-cloud';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { Component, SimpleChange, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
import { By } from '@angular/platform-browser';
import { of } from 'rxjs';
import { shareReplay, skip } from 'rxjs/operators';
import { PROCESS_LIST_CUSTOM_VARIABLE_COLUMN } from '../../../models/data-column-custom-data';
import { PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN } from '../../../services/cloud-token.service';
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
import { fakeCustomSchema, fakeProcessCloudList, processListSchemaMock } from '../mock/process-list-service.mock';
import { ProcessListCloudPreferences } from '../models/process-cloud-preferences';
import { ProcessListCloudSortingModel } from '../models/process-list-sorting.model';
import { ProcessListCloudService } from '../services/process-list-cloud.service';
import { ProcessListCloudComponent } from './process-list-cloud.component';
@Component({
template: ` <adf-cloud-process-list #processListCloud>
@ -636,9 +626,9 @@ describe('ProcessListCloudComponent: Creating an empty custom template - EmptyTe
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule, DataTableModule, MatProgressSpinnerModule],
imports: [ProcessServiceCloudTestingModule, MatProgressSpinnerModule],
providers: [{ provide: PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN, useValue: preferencesService }],
declarations: [EmptyTemplateComponent, ProcessListCloudComponent, CustomEmptyContentTemplateDirective]
declarations: [EmptyTemplateComponent, ProcessListCloudComponent]
});
fixtureEmpty = TestBed.createComponent(EmptyTemplateComponent);
fixtureEmpty.detectChanges();

View File

@ -650,7 +650,7 @@ describe('TaskListCloudComponent: Copy cell content directive from app.config sp
fixture.detectChanges();
const cell = fixture.debugElement.query(By.css('[data-automation-id="text_ADF_CLOUD_TASK_LIST.PROPERTIES.PRIORITY_VALUES.NONE"]'));
expect(cell.nativeElement.textContent).toEqual('ADF_CLOUD_TASK_LIST.PROPERTIES.PRIORITY_VALUES.NONE');
expect(cell.nativeElement.textContent.trim()).toEqual('ADF_CLOUD_TASK_LIST.PROPERTIES.PRIORITY_VALUES.NONE');
});
it('replacePriorityValues should return undefined when no rows defined', () => {

View File

@ -24,7 +24,6 @@ import { materialLocators } from './public-api';
const MAX_LOADING_TIME = 120000;
export class DataTableComponentPage {
rootElement: ElementFinder;
list: ElementArrayFinder;
contents: ElementArrayFinder;
@ -39,22 +38,22 @@ export class DataTableComponentPage {
noContentContainer: ElementFinder;
mainMenuButton: ElementFinder;
rows = `adf-datatable div[class*='adf-datatable-body'] adf-datatable-row[class*='adf-datatable-row']`;
rows = `adf-datatable tbody[class*='adf-datatable-body'] adf-datatable-row[class*='adf-datatable-row']`;
constructor(rootElement = $$('adf-datatable').first()) {
this.rootElement = rootElement;
this.list = this.rootElement.$$(`div[class*='adf-datatable-body'] adf-datatable-row[class*='adf-datatable-row']`);
this.list = this.rootElement.$$(`tbody[class*='adf-datatable-body'] adf-datatable-row[class*='adf-datatable-row']`);
this.contents = this.rootElement.$$('.adf-datatable-body span');
this.tableBody = this.rootElement.$$(`.adf-datatable-body`).first();
this.allColumns = this.rootElement.$$('div[data-automation-id*="auto_header_content_id"]');
this.mainMenuButton = this.rootElement.$('[data-automation-id="adf-datatable-main-menu-button"]');
this.selectedRowNumber = this.rootElement.$(`adf-datatable-row[class*='is-selected'] div[data-automation-id*='text_']`);
this.allSelectedRows = this.rootElement.$$(`adf-datatable-row[class*='is-selected']`);
this.selectAll = this.rootElement.$(`div[class*='adf-datatable-header'] ${materialLocators.Checkbox.root}`);
this.selectAll = this.rootElement.$(`thead[class*='adf-datatable-header'] ${materialLocators.Checkbox.root}`);
this.emptyList = this.rootElement.$(`adf-empty-content`);
this.emptyListTitle = this.rootElement.$(`.adf-empty-content__title`);
this.emptyListSubtitle = this.rootElement.$(`.adf-empty-content__subtitle`);
this.noContentContainer = $(`div[class*='adf-no-content-container']`);
this.noContentContainer = $(`td[class*='adf-no-content-container']`);
}
geCellElementDetail(detail: string): ElementArrayFinder {
@ -114,19 +113,23 @@ export class DataTableComponentPage {
}
async checkRowIsSelected(columnName: string, columnValue: string): Promise<void> {
const selectedRow = this.getCellElementByValue(columnName, columnValue).element(by.xpath(`ancestor::adf-datatable-row[contains(@class, 'is-selected')]`));
const selectedRow = this.getCellElementByValue(columnName, columnValue).element(
by.xpath(`ancestor::adf-datatable-row[contains(@class, 'is-selected')]`)
);
await BrowserVisibility.waitUntilElementIsVisible(selectedRow);
}
async checkRowIsNotSelected(columnName: string, columnValue: string): Promise<void> {
const selectedRow = this.getCellElementByValue(columnName, columnValue).element(by.xpath(`ancestor::adf-datatable-row[contains(@class, 'is-selected')]`));
const selectedRow = this.getCellElementByValue(columnName, columnValue).element(
by.xpath(`ancestor::adf-datatable-row[contains(@class, 'is-selected')]`)
);
await BrowserVisibility.waitUntilElementIsNotVisible(selectedRow);
}
async getColumnValueForRow(identifyingColumn: string, identifyingValue: string, columnName: string): Promise<string> {
const row = this.getRow(identifyingColumn, identifyingValue);
await BrowserVisibility.waitUntilElementIsVisible(row);
const rowColumn = row.$(`div[title="${columnName}"] span`);
const rowColumn = row.$(`td[title="${columnName}"] span`);
return BrowserActions.getText(rowColumn);
}
@ -139,7 +142,7 @@ export class DataTableComponentPage {
* @returns 'true' if the list is sorted as await expected and 'false' if it isn't
*/
async checkListIsSorted(sortOrder: string, columnTitle: string, listType: string = 'STRING'): Promise<any> {
const column = $$(`div.adf-datatable-cell[title='${columnTitle}'] span`);
const column = $$(`td.adf-datatable-cell[title='${columnTitle}'] span`);
await BrowserVisibility.waitUntilElementIsVisible(column.first());
const initialList: string[] = [];
@ -229,14 +232,14 @@ export class DataTableComponentPage {
async getAllRowsColumnValues(column: string): Promise<string[]> {
let columnValues: string[] = [];
const columnLocator = $$(`adf-datatable div[class*='adf-datatable-body'] adf-datatable-row[class*='adf-datatable-row'] div[title="${column}"] span`);
const columnLocator = $$(
`adf-datatable tbody[class*='adf-datatable-body'] adf-datatable-row[class*='adf-datatable-row'] *[title="${column}"] span`
);
await BrowserVisibility.waitUntilElementIsPresent(columnLocator.first(), 1000);
try {
await BrowserVisibility.waitUntilElementIsPresent(columnLocator.first(), 1000);
columnValues = await columnLocator
.filter(async (el) => el.isPresent())
.map(async (el) => el.getText());
columnValues = await columnLocator.filter(async (el) => el.isPresent()).map(async (el) => el.getText());
} catch (error) {
Logger.log(error);
}
@ -245,7 +248,7 @@ export class DataTableComponentPage {
}
async getRowsWithSameColumnValues(columnName: string, columnValue: string) {
const columnLocator = `div[title='${columnName}'] div[data-automation-id="text_${columnValue}"] span`;
const columnLocator = `td[title='${columnName}'] div[data-automation-id="text_${columnValue}"] span`;
await BrowserVisibility.waitUntilElementIsVisible(this.rootElement.$$(columnLocator).first());
return this.rootElement.$$(columnLocator).getText();
}
@ -273,7 +276,7 @@ export class DataTableComponentPage {
* @param titleColumn column title
*/
async sortByColumn(sortOrder: string, titleColumn: string): Promise<void> {
const locator = $(`div[data-automation-id="auto_id_${titleColumn}"]`);
const locator = $(`th[data-automation-id="auto_id_${titleColumn}"]`);
await BrowserVisibility.waitUntilElementIsVisible(locator);
const result = await BrowserActions.getAttribute(locator, 'class');
@ -326,12 +329,20 @@ export class DataTableComponentPage {
}
getRow(columnName: string, columnValue: string): ElementFinder {
return this.rootElement.all(by.xpath(`//div[starts-with(@title, '${columnName}')]//div[contains(@data-automation-id, '${columnValue}')]//ancestor::adf-datatable-row[contains(@class, 'adf-datatable-row')]`)).first();
return this.rootElement
.all(
by.xpath(
`//td[starts-with(@title, '${columnName}')]//div[contains(@data-automation-id, '${columnValue}')]//ancestor::adf-datatable-row[contains(@class, 'adf-datatable-row')]`
)
)
.first();
}
// @deprecated use Playwright instead
getRowByIndex(index: number): ElementFinder {
return this.rootElement.element(by.xpath(`//div[contains(@class,'adf-datatable-body')]//adf-datatable-row[contains(@class,'adf-datatable-row')][${index}]`));
return this.rootElement.element(
by.xpath(`//div[contains(@class,'adf-datatable-body')]//adf-datatable-row[contains(@class,'adf-datatable-row')][${index}]`)
);
}
async contentInPosition(position: number): Promise<string> {
@ -340,7 +351,7 @@ export class DataTableComponentPage {
}
getCellElementByValue(columnName: string, columnValue: string, columnPrefix = 'text_'): ElementFinder {
return this.rootElement.$$(`div[title="${columnName}"] div[data-automation-id="${columnPrefix}${columnValue}"] span`).first();
return this.rootElement.$$(`td[title="${columnName}"] div[data-automation-id="${columnPrefix}${columnValue}"] span`).first();
}
async tableIsLoaded(): Promise<void> {
@ -350,23 +361,27 @@ export class DataTableComponentPage {
async waitTillContentLoaded(): Promise<void> {
if (await this.isSpinnerPresent()) {
Logger.log('wait datatable loading spinner disappear');
await BrowserVisibility.waitUntilElementIsNotVisible(this.rootElement.element(by.tagName(materialLocators.Progress.spinner.root)), MAX_LOADING_TIME);
await BrowserVisibility.waitUntilElementIsNotVisible(
this.rootElement.element(by.tagName(materialLocators.Progress.spinner.root)),
MAX_LOADING_TIME
);
if (await this.isEmpty()) {
Logger.log('empty page');
} else {
await this.waitFirstElementPresent();
}
} else if (await this.isEmpty()) {
Logger.log('empty page');
} else {
try {
Logger.log('wait datatable loading spinner is present');
await BrowserVisibility.waitUntilElementIsVisible(this.rootElement.element(by.tagName(materialLocators.Progress.spinner.root)), 2000);
await BrowserVisibility.waitUntilElementIsNotVisible(this.rootElement.element(by.tagName(materialLocators.Progress.spinner.root)), MAX_LOADING_TIME);
} catch (error) {
}
await BrowserVisibility.waitUntilElementIsNotVisible(
this.rootElement.element(by.tagName(materialLocators.Progress.spinner.root)),
MAX_LOADING_TIME
);
} catch (error) {}
if (await this.isEmpty()) {
Logger.log('empty page');
@ -392,8 +407,7 @@ export class DataTableComponentPage {
try {
Logger.log('wait datatable loading spinner is present');
await BrowserVisibility.waitUntilElementIsVisible(element(by.tagName(materialLocators.Progress.bar.root)));
} catch (error) {
}
} catch (error) {}
if (await this.isEmpty()) {
Logger.log('empty page');
} else {
@ -404,14 +418,10 @@ export class DataTableComponentPage {
// @deprecated use Playwright instead
async isColumnDisplayed(columnTitle: string): Promise<boolean> {
const isColumnDisplayed = (await this.allColumns).some(
async column => {
const columnText = await column.getText();
return columnText === columnTitle;
}
);
return isColumnDisplayed;
return (await this.allColumns).some(async (column) => {
const columnText = await column.getText();
return columnText === columnTitle;
});
}
// @deprecated use Playwright instead
@ -424,11 +434,11 @@ export class DataTableComponentPage {
}
getCellByRowNumberAndColumnName(rowNumber: number, columnName: string): ElementFinder {
return this.list.get(rowNumber).$$(`div[title="${columnName}"] span`).first();
return this.list.get(rowNumber).$$(`td[title="${columnName}"] span`).first();
}
getCellByRowContentAndColumn(rowColumn: string, rowContent: string, columnName: string): ElementFinder {
return this.getRow(rowColumn, rowContent).$(`div[title='${columnName}']`);
return this.getRow(rowColumn, rowContent).$(`td[title='${columnName}']`);
}
async selectRowByContent(content: string): Promise<void> {
@ -447,42 +457,52 @@ export class DataTableComponentPage {
}
getCellByContent(content: string): ElementFinder {
return this.rootElement.all(by.cssContainingText(`adf-datatable-row[class*='adf-datatable-row'] div[class*='adf-datatable-cell']`, content)).first();
return this.rootElement
.all(by.cssContainingText(`adf-datatable-row[class*='adf-datatable-row'] td[class*='adf-datatable-cell']`, content))
.first();
}
async checkCellByHighlightContent(content: string): Promise<void> {
const cell = this.rootElement.element(by.cssContainingText(`adf-datatable-row[class*='adf-datatable-row'] div[class*='adf-name-location-cell-name'] span.adf-highlight`, content));
const cell = this.rootElement.element(
by.cssContainingText(
`adf-datatable-row[class*='adf-datatable-row'] div[class*='adf-name-location-cell-name'] span.adf-highlight`,
content
)
);
await BrowserVisibility.waitUntilElementIsVisible(cell);
}
async clickRowByContent(name: string): Promise<void> {
const resultElement = this.rootElement.$$(`div[data-automation-id='${name}']`).first();
const resultElement = this.rootElement.$$(`td[data-automation-id='${name}']`).first();
await BrowserActions.click(resultElement);
}
async clickRowByContentCheckbox(name: string): Promise<void> {
const resultElement = this.rootElement.$$(`div[data-automation-id='${name}']`).first().element(by.xpath(`ancestor::adf-datatable-row/label/${materialLocators.Checkbox.root}`));
const resultElement = this.rootElement
.$$(`div[data-automation-id='${name}']`)
.first()
.element(by.xpath(`ancestor::adf-datatable-row/label/${materialLocators.Checkbox.root}`));
browser.actions().mouseMove(resultElement);
await BrowserActions.click(resultElement);
}
async checkRowContentIsDisplayed(content: string): Promise<void> {
const resultElement = this.rootElement.$$(`div[data-automation-id='${content}']`).first();
const resultElement = this.rootElement.$$(`td[data-automation-id='${content}']`).first();
await BrowserVisibility.waitUntilElementIsVisible(resultElement);
}
async checkRowContentIsNotDisplayed(content: string): Promise<void> {
const resultElement = this.rootElement.$$(`div[data-automation-id='${content}']`).first();
const resultElement = this.rootElement.$$(`tr[data-automation-id='${content}']`).first();
await BrowserVisibility.waitUntilElementIsNotVisible(resultElement);
}
async checkRowContentIsDisabled(content: string): Promise<void> {
const resultElement = this.rootElement.$$(`div[data-automation-id='${content}'] div.adf-cell-value img[aria-label='Disabled']`).first();
const resultElement = this.rootElement.$$(`tr[data-automation-id='${content}'] div.adf-cell-value img[aria-label='Disabled']`).first();
await BrowserVisibility.waitUntilElementIsVisible(resultElement);
}
async doubleClickRowByContent(name: string): Promise<void> {
const resultElement = this.rootElement.$$(`div[data-automation-id='${name}']`).first();
const resultElement = this.rootElement.$$(`td[data-automation-id='${name}']`).first();
await BrowserActions.click(resultElement);
await browser.actions().sendKeys(protractor.Key.ENTER).perform();
}

View File

@ -19,7 +19,7 @@ export abstract class Column {
columnName: string;
columnType: string;
constructor(columnName: string, columnType: string ) {
constructor(columnName: string, columnType: string) {
this.columnName = columnName;
this.columnType = columnType;
}

View File

@ -23,7 +23,7 @@ import { BrowserVisibility } from '../../utils/browser-visibility';
export class DataTableItem {
columns = new Array<Column>();
rootElement: ElementFinder;
rows = `div[class*='adf-datatable-body'] adf-datatable-row[class*='adf-datatable-row']`;
rows = `tbody[class*='adf-datatable-body'] adf-datatable-row[class*='adf-datatable-row']`;
constructor(rootElement = $$('adf-datatable').first()) {
this.rootElement = rootElement;
@ -34,14 +34,16 @@ export class DataTableItem {
}
async getColumn(columnName: string): Promise<Column> {
return this.columns.find(
(column) => column.getColumnName() === columnName
);
return this.columns.find((column) => column.getColumnName() === columnName);
}
async getRow(columnName: string, columnValue: string): Promise<ElementFinder> {
console.log('getRow', '-------------------------------------------------------');
const column = await this.getColumn(columnName);
const locator = `//div[@title="${column.columnName}"]` + column.createLocator(columnValue) + `//ancestor::adf-datatable-row[contains(@class, 'adf-datatable-row')]`;
const locator =
`//td[@title="${column.columnName}"]` +
column.createLocator(columnValue) +
`//ancestor::adf-datatable-row[contains(@class, 'adf-datatable-row')]`;
return this.rootElement.element(by.xpath(locator));
}
@ -71,19 +73,26 @@ export class DataTableItem {
async getColumnValueForRow(identifyingColumnName: string, identifyingColumnValue: string, columnName: string): Promise<string> {
const row = await this.getRow(identifyingColumnName, identifyingColumnValue);
await BrowserVisibility.waitUntilElementIsVisible(row);
const rowColumn = row.$(`div[title="${columnName}"] span`);
const rowColumn = row.$(`td[title="${columnName}"] span`);
return BrowserActions.getText(rowColumn);
}
async checkRowIsSelected(columnName: string, columnValue: string): Promise<void> {
console.log('checkRowIsSelected', '-------------------------------------------------------');
const column = await this.getColumn(columnName);
const locator = `//div[@title="${column.columnName}"]` + column.createLocator(columnValue) + `//ancestor::adf-datatable-row[contains(@class, 'is-selected')]`;
const locator =
`//td[@title="${column.columnName}"]` +
column.createLocator(columnValue) +
`//ancestor::adf-datatable-row[contains(@class, 'is-selected')]`;
await BrowserVisibility.waitUntilElementIsVisible(element(by.xpath(locator)));
}
async checkRowIsNotSelected(columnName: string, columnValue: string): Promise<void> {
const column = await this.getColumn(columnName);
const locator = `//div[@title="${column.columnName}"]` + column.createLocator(columnValue) + `//ancestor::adf-datatable-row[contains(@class, 'is-selected')]`;
const locator =
`//div[@title="${column.columnName}"]` +
column.createLocator(columnValue) +
`//ancestor::adf-datatable-row[contains(@class, 'is-selected')]`;
await BrowserVisibility.waitUntilElementIsNotVisible(element(by.xpath(locator)));
}

View File

@ -58,7 +58,7 @@ export class ViewerPage {
unknownFormat = $(`adf-viewer-unknown-format .adf-viewer__unknown-format-view`);
async viewFile(fileName: string): Promise<void> {
const fileView = $$(`#document-list-container div[data-automation-id="${fileName}"]`).first();
const fileView = $$(`#document-list-container td[data-automation-id="${fileName}"]`).first();
await BrowserActions.click(fileView);
await browser.actions().sendKeys(protractor.Key.ENTER).perform();
await this.waitTillContentLoaded();
@ -245,7 +245,7 @@ export class ViewerPage {
}
async clickInfoButton(): Promise<void> {
await BrowserActions.click($('button[data-automation-id="adf-toolbar-sidebar"]'));
await BrowserActions.click(this.infoButton);
}
async clickOnTab(tabName: string): Promise<void> {