[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
82 changed files with 1398 additions and 1258 deletions

View File

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

View File

@@ -15,11 +15,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { BrowserActions, createApiService, LoginPage, UploadActions, UserModel, UsersActions, ViewerPage } from '@alfresco/adf-testing';
import { browser, by, element, protractor } from 'protractor'; 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 { ContentServicesPage } from '../../core/pages/content-services.page';
import { FileModel } from '../../models/ACS/file.model';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page'; import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
import { FileModel } from '../../models/ACS/file.model';
describe('Content Services Viewer', () => { describe('Content Services Viewer', () => {
const acsUser = new UserModel(); 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 () => { 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 BrowserActions.click(fileView);
await browser.actions().sendKeys(protractor.Key.ENTER).perform(); await browser.actions().sendKeys(protractor.Key.ENTER).perform();

View File

@@ -271,7 +271,7 @@ export class ContentServicesPage {
} }
async checkLockIsDisplayedForElement(name: string): Promise<void> { 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); await BrowserVisibility.waitUntilElementIsVisible(lockButton);
} }
@@ -290,7 +290,7 @@ export class ContentServicesPage {
async getAttributeValueForElement(elementName: string, propertyName: string): Promise<string> { async getAttributeValueForElement(elementName: string, propertyName: string): Promise<string> {
const elementSize = $( 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); return BrowserActions.getText(elementSize);
} }
@@ -306,7 +306,7 @@ export class ContentServicesPage {
} }
async selectFolder(folderName: string): Promise<void> { 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 BrowserVisibility.waitUntilElementIsVisible(folderSelected);
await BrowserActions.click(folderSelected); await BrowserActions.click(folderSelected);
} }

View File

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

View File

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

View File

@@ -1907,11 +1907,11 @@ describe('DocumentListComponent rendering', () => {
const rows = fixture.nativeElement.querySelectorAll('.adf-datatable-body adf-datatable-row'); const rows = fixture.nativeElement.querySelectorAll('.adf-datatable-body adf-datatable-row');
expect(rows).toBeDefined(); expect(rows).toBeDefined();
expect(rows.length).toBe(3); 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'); 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'); 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'); expect(cell3.innerText).toBe('3');
}); });
}); });

View File

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

View File

@@ -15,13 +15,13 @@
* limitations under the License. * 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 { registerLocaleData } from '@angular/common';
import localePL from '@angular/common/locales/pl'; 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', () => { describe('AmountCellComponent', () => {
let component: AmountCellComponent; let component: AmountCellComponent;
@@ -58,7 +58,14 @@ describe('AmountCellComponent', () => {
}); });
it('should render currency value with custom currency code', () => { 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', () => { it('should render currency value with custom display code', () => {

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,16 +15,16 @@
* limitations under the License. * 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 { 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 { 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', () => { describe('ColumnsSelectorComponent', () => {
let fixture: ComponentFixture<ColumnsSelectorComponent>; let fixture: ComponentFixture<ColumnsSelectorComponent>;
@@ -40,8 +40,7 @@ describe('ColumnsSelectorComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [CoreTestingModule], imports: [CoreTestingModule, ColumnsSelectorComponent]
declarations: [ColumnsSelectorComponent]
}).compileComponents(); }).compileComponents();
fixture = TestBed.createComponent(ColumnsSelectorComponent); fixture = TestBed.createComponent(ColumnsSelectorComponent);

View File

@@ -15,16 +15,36 @@
* limitations under the License. * limitations under the License.
*/ */
import { NgForOf, NgIf } from '@angular/common';
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core'; 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 { MatMenuTrigger } from '@angular/material/menu';
import { TranslateModule } from '@ngx-translate/core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators'; import { debounceTime, takeUntil } from 'rxjs/operators';
import { FilterStringPipe } from '../../../pipes';
import { DataColumn } from '../../data/data-column.model'; import { DataColumn } from '../../data/data-column.model';
@Component({ @Component({
selector: 'adf-datatable-column-selector', selector: 'adf-datatable-column-selector',
standalone: true,
templateUrl: './columns-selector.component.html', templateUrl: './columns-selector.component.html',
styleUrls: ['./columns-selector.component.scss'], styleUrls: ['./columns-selector.component.scss'],
imports: [
MatButtonModule,
TranslateModule,
MatIconModule,
MatDividerModule,
ReactiveFormsModule,
MatCheckboxModule,
NgIf,
NgForOf,
FilterStringPipe
],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ColumnsSelectorComponent implements OnInit, OnDestroy { export class ColumnsSelectorComponent implements OnInit, OnDestroy {
@@ -49,23 +69,16 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
searchQuery = ''; searchQuery = '';
ngOnInit(): void { ngOnInit(): void {
this.mainMenuTrigger.menuOpened.pipe( this.mainMenuTrigger.menuOpened.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
takeUntil(this.onDestroy$) const columns = this.columns.map((column) => ({ ...column }));
).subscribe(() => {
const columns = this.columns.map(column => ({...column}));
this.columnItems = this.columnsSorting ? this.sortColumns(columns) : columns; this.columnItems = this.columnsSorting ? this.sortColumns(columns) : columns;
}); });
this.mainMenuTrigger.menuClosed.pipe( this.mainMenuTrigger.menuClosed.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
takeUntil(this.onDestroy$)
).subscribe(() => {
this.searchInputControl.setValue(''); this.searchInputControl.setValue('');
}); });
this.searchInputControl.valueChanges.pipe( this.searchInputControl.valueChanges.pipe(debounceTime(300), takeUntil(this.onDestroy$)).subscribe((searchQuery) => {
debounceTime(300),
takeUntil(this.onDestroy$)
).subscribe((searchQuery) => {
this.searchQuery = searchQuery; this.searchQuery = searchQuery;
}); });
} }
@@ -89,12 +102,16 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
} }
isCheckboxDisabled(column: DataColumn): boolean { 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[] { private sortColumns(columns: DataColumn[]): DataColumn[] {
const shownColumns = columns.filter(column => !column.isHidden); const shownColumns = columns.filter((column) => !column.isHidden);
const hiddenColumns = columns.filter(column => column.isHidden); const hiddenColumns = columns.filter((column) => column.isHidden);
return [...shownColumns, ...hiddenColumns]; 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 { 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 { 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 { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
import { DataTableService } from '../../services/datatable.service';
import { mockCarsData, mockCarsSchemaDefinition } from '../mocks/datatable.mock'; import { mockCarsData, mockCarsSchemaDefinition } from '../mocks/datatable.mock';
import { DataTableCellComponent } from './datatable-cell.component';
describe('DataTableCellComponent', () => { describe('DataTableCellComponent', () => {
let component: DataTableCellComponent; let component: DataTableCellComponent;
@@ -51,7 +51,7 @@ describe('DataTableCellComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [DataTableCellComponent], imports: [DataTableCellComponent],
providers: [DataTableService] providers: [DataTableService]
}); });

View File

@@ -15,34 +15,23 @@
* limitations under the License. * 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 { DataColumn } from '../../data/data-column.model';
import { DataRow } from '../../data/data-row.model'; import { DataRow } from '../../data/data-row.model';
import { DataTableAdapter } from '../../data/datatable-adapter'; import { DataTableAdapter } from '../../data/datatable-adapter';
import { BehaviorSubject, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { DataTableService } from '../../services/datatable.service'; import { DataTableService } from '../../services/datatable.service';
@Component({ @Component({
selector: 'adf-datatable-cell', selector: 'adf-datatable-cell',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
template: ` templateUrl: './datatable-cell.component.html',
<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>
`,
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
imports: [ClipboardModule, AsyncPipe, NgIf],
host: { class: 'adf-datatable-content-cell' } host: { class: 'adf-datatable-content-cell' }
}) })
export class DataTableCellComponent implements OnInit, OnDestroy { export class DataTableCellComponent implements OnInit, OnDestroy {

View File

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

View File

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

View File

@@ -1,406 +1,412 @@
<div <div *ngIf="data"
role="grid" role="table"
*ngIf="data" class="adf-full-width adf-datatable-list"
class="adf-full-width adf-datatable-list" [class.adf-sticky-header]="isStickyHeaderEnabled()"
[class.adf-sticky-header]="isStickyHeaderEnabled()" [class.adf-datatable--empty]="(isEmpty() && !isHeaderVisible()) || loading"
[class.adf-datatable--empty]="(isEmpty() && !isHeaderVisible()) || loading" [class.adf-datatable--empty--header-visible]="isEmpty() && isHeaderVisible()">
[class.adf-datatable--empty--header-visible]="isEmpty() && isHeaderVisible()"> <thead *ngIf="isHeaderVisible()"
<div *ngIf="isHeaderVisible()" class="adf-datatable-header" role="rowgroup" [ngClass]="{ 'adf-sr-only': !isHeaderVisible() }"> class="adf-datatable-header"
<adf-datatable-row [ngClass]="{ 'adf-sr-only': !isHeaderVisible() }">
cdkDropList <adf-datatable-row cdkDropList
cdkDropListOrientation="horizontal" cdkDropListOrientation="horizontal"
[cdkDropListSortPredicate]="filterDisabledColumns" [cdkDropListSortPredicate]="filterDisabledColumns"
data-automation-id="datatable-row-header" data-automation-id="datatable-row-header"
[disabled]="!isHeaderVisible()" [disabled]="!isHeaderVisible()"
class="adf-datatable-row" class="adf-datatable-row">
role="row">
<!-- Actions (left) --> <!-- Actions (left) -->
<div *ngIf="actions && actionsPosition === 'left'" class="adf-actions-column adf-datatable-cell-header"> <th *ngIf="actions && actionsPosition === 'left'"
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate }}</span> class="adf-actions-column adf-datatable-cell-header"
</div> [attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate">
</th>
<!-- Columns --> <!-- Columns -->
<div *ngIf="multiselect" class="adf-datatable-cell-header adf-datatable-checkbox"> <th *ngIf="multiselect"
<mat-checkbox [indeterminate]="isSelectAllIndeterminate" [checked]="isSelectAllChecked" (change)="onSelectAllClick($event)" class="adf-checkbox-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.SELECT_ALL' | translate }}</mat-checkbox> class="adf-datatable-cell-header adf-datatable-checkbox">
</div> <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 <th class="adf-datatable-cell--{{ col.type || 'text' }} {{ col.cssClass }} adf-datatable-cell-header adf-datatable-cell-data"
class="adf-datatable-cell--{{col.type || 'text'}} {{col.cssClass}} adf-datatable-cell-header adf-datatable-cell-data" *ngFor="
*ngFor=" let col of (data.getColumns() | filterOutEvery:'isHidden':true);
let col of (data.getColumns() | filterOutEvery:'isHidden':true); let columnIndex = index
let columnIndex = index let lastColumn = last"
let lastColumn = last" [attr.data-automation-id]="'auto_id_' + col.key"
[attr.data-automation-id]="'auto_id_' + col.key" [ngClass]="{
[ngClass]="{ 'adf-sortable': col.sortable,
'adf-sortable': col.sortable, 'adf-datatable__cursor--pointer': !isResizing,
'adf-datatable__cursor--pointer': !isResizing, 'adf-datatable__header--sorted-asc': isColumnSorted(col, 'asc'),
'adf-datatable__header--sorted-asc': isColumnSorted(col, 'asc'), 'adf-datatable__header--sorted-desc': isColumnSorted(col, 'desc')}"
'adf-datatable__header--sorted-desc': isColumnSorted(col, 'desc')}" [ngStyle]="(col.width) && !lastColumn && {'flex': getFlexValue(col)}"
[ngStyle]="(col.width) && !lastColumn && {'flex': getFlexValue(col)}" [attr.aria-label]="col.title | translate"
[attr.aria-label]="col.title | translate" (click)="onColumnHeaderClick(col, $event)"
(click)="onColumnHeaderClick(col, $event)" (keyup.enter)="onColumnHeaderClick(col, $event)"
(keyup.enter)="onColumnHeaderClick(col, $event)" [attr.tabindex]="isHeaderVisible() ? 0 : null"
role="columnheader" [attr.aria-sort]="col.sortable ? (getAriaSort(col) | translate) : null"
[attr.tabindex]="isHeaderVisible() ? 0 : null" cdkDrag
[attr.aria-sort]="col.sortable ? (getAriaSort(col) | translate) : null" cdkDragLockAxis="x"
cdkDrag [cdkDragPreviewClass]="'adf-drag-preview'"
cdkDragLockAxis="x" (cdkDragStarted)="isDraggingHeaderColumn = true"
(cdkDragStarted)="isDraggingHeaderColumn = true" (cdkDragDropped)="onDropHeaderColumn($event)"
(cdkDragDropped)="onDropHeaderColumn($event)" [cdkDragDisabled]="!col.draggable"
[cdkDragDisabled]="!col.draggable" (mouseenter)="hoveredHeaderColumnIndex = columnIndex"
(mouseenter)="hoveredHeaderColumnIndex = columnIndex" (mouseleave)="hoveredHeaderColumnIndex = -1"
(mouseleave)="hoveredHeaderColumnIndex = -1" adf-drop-zone
adf-drop-zone dropTarget="header" [dropColumn]="col"> dropTarget="header"
[dropColumn]="col">
<div <div adf-resizable
adf-resizable #resizableElement="adf-resizable"
#resizableElement="adf-resizable" [coverPadding]="10"
[coverPadding]="10" (resizing)="onResizing($event, columnIndex)"
(resizing)="onResizing($event, columnIndex)" (resizeStart)="resizingColumnIndex = columnIndex"
(resizeStart)="resizingColumnIndex = columnIndex" (resizeEnd)="onResizingEnd()"
(resizeEnd)="onResizingEnd()" [attr.data-automation-id]="'auto_header_content_id_' + col.key"
[attr.data-automation-id]="'auto_header_content_id_' + col.key" class="adf-datatable-cell-header-content"
class="adf-datatable-cell-header-content" [ngClass]="{ 'adf-datatable-cell-header-content--hovered':
[ngClass]="{ 'adf-datatable-cell-header-content--hovered': hoveredHeaderColumnIndex === columnIndex &&
hoveredHeaderColumnIndex === columnIndex && !isDraggingHeaderColumn &&
!isDraggingHeaderColumn && !isResizing && col.sortable}">
!isResizing && col.sortable}" <ng-container *ngIf="!col.header">
> <span *ngIf="col.title"
<ng-container *ngIf="!col.header"> [matTooltip]="col.title | translate"
<span *ngIf="col.title" matTooltip="{{col.title | translate}}" class="adf-datatable-cell-value">{{col.title | translate}}</span> class="adf-datatable-cell-value">{{ col.title | translate }}</span>
<span *ngIf="col.title && col.sortable && isDraggingHeaderColumn" class="adf-sr-only" aria-live="polite"> <span *ngIf="col.title && col.sortable && isDraggingHeaderColumn"
{{ getSortLiveAnnouncement(col) | translate: { string: col.title | translate } }} class="adf-sr-only"
</span> aria-live="polite">
{{ getSortLiveAnnouncement(col) | translate: { string: col.title | translate } }}
<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> </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 <div *ngIf="col.header" class="adf-datatable-cell-value">
*ngIf="col.draggable" <ng-template [ngTemplateOutlet]="col.header"
cdkDragHandle [ngTemplateOutletContext]="{ $implicit: col }"></ng-template>
[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>
<div
*ngIf="isResizingEnabled && col.resizable && !lastColumn" <span [class.adf-datatable__header--sorted-asc]="isColumnSorted(col, 'asc')"
[ngClass]="hoveredHeaderColumnIndex === columnIndex && !isResizing || resizingColumnIndex === columnIndex ? 'adf-datatable__resize-handle-visible' : 'adf-datatable__resize-handle-hidden'" [class.adf-datatable__header--sorted-desc]="isColumnSorted(col, 'desc')"></span>
adf-resize-handle
tabindex="0" <ng-template *ngIf="allowFiltering"
role="button" [ngTemplateOutlet]="headerFilterTemplate"
(click)="$event.stopPropagation()" [ngTemplateOutletContext]="{ $implicit: col }"></ng-template>
(keyup.enter)="$event.stopPropagation()"
class="adf-datatable__resize-handle" <span *ngIf="col.draggable"
[resizableContainer]="resizableElement"> cdkDragHandle
<div class="adf-datatable__resize-handle--divider"></div> [ngClass]="{ 'adf-datatable-cell-header-drag-icon': !isResizing }">
</div> <adf-icon *ngIf="hoveredHeaderColumnIndex === columnIndex && !isResizing"
<div class="adf-drop-header-cell-placeholder" *cdkDragPlaceholder></div> value="adf:drag_indicator"
[attr.data-automation-id]="'adf-datatable-cell-header-drag-icon-' + col.key">
</adf-icon>
</span>
</div> </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) --> <!-- Header actions (right) -->
<div <th *ngIf="(actions && actionsPosition === 'right') || (mainActionTemplate && showMainDatatableActions)"
*ngIf="(actions && actionsPosition === 'right') || class="adf-actions-column adf-datatable-actions-menu adf-datatable-cell-header adf-datatable__actions-cell">
(mainActionTemplate && showMainDatatableActions)" <ng-container *ngIf="mainActionTemplate">
class="adf-actions-column adf-datatable-actions-menu adf-datatable-cell-header adf-datatable__actions-cell" <button data-automation-id="adf-datatable-main-menu-button"
> [matTooltip]="'ADF-DATATABLE.CONTENT-ACTIONS.SELECT_COLUMNS' | translate"
<ng-container *ngIf="mainActionTemplate"> [attr.aria-label]="'ADF-DATATABLE.CONTENT-ACTIONS.SELECT_COLUMNS' | translate"
<button
data-automation-id="adf-datatable-main-menu-button"
matTooltip="{{ 'ADF-DATATABLE.CONTENT-ACTIONS.SELECT_COLUMNS' | translate }}"
mat-icon-button mat-icon-button
#mainMenuTrigger="matMenuTrigger" #mainMenuTrigger="matMenuTrigger"
(keydown.enter)="mainMenuTrigger.openMenu()" (keydown.enter)="mainMenuTrigger.openMenu()"
[matMenuTriggerFor]="mainMenu"> [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> </button>
<mat-menu #mainMenu> </mat-menu>
<ng-container </td>
[ngTemplateOutlet]="mainActionTemplate"
[ngTemplateOutletContext]="{ <td *ngIf="multiselect"
$implicit: mainMenuTrigger 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> </ng-container>
</mat-menu> </div>
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate }}</span> </div>
</ng-container> </td>
</div>
</adf-datatable-row> <!-- Row actions (right) -->
</div> <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 <ng-container *ngIf="(actions && actionsPosition === 'right')">
class="adf-datatable-body" <button mat-icon-button
[ngClass]="{ 'adf-blur-datatable-body': blurOnResize && (isDraggingHeaderColumn || isResizing) }" [matMenuTriggerFor]="menu"
role="rowgroup"> #actionsMenuTrigger="matMenuTrigger"
<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"
[ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)" [ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)"
[attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.ROW_OPTION_BUTTON' | translate"
[title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate" [title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate"
[attr.id]="'action_menu_left_' + idx" [attr.id]="'action_menu_right_' + idx"
[attr.data-automation-id]="'action_menu_' + idx"> [attr.data-automation-id]="'action_menu_' + idx"
(keydown.enter)="actionsMenuTrigger.openMenu()">
<mat-icon>more_vert</mat-icon> <mat-icon>more_vert</mat-icon>
</button> </button>
<mat-menu #menu="matMenu"> <mat-menu #menu="matMenu">
<button mat-menu-item *ngFor="let action of getRowActions(row)" <button mat-menu-item *ngFor="let action of getRowActions(row)"
[attr.data-automation-id]="action.title" [attr.data-automation-id]="action.title"
[attr.aria-label]="action.title | translate"
[disabled]="action.disabled" [disabled]="action.disabled"
(click)="onExecuteRowAction(row, action)"> (click)="onExecuteRowAction(row, action)">
<mat-icon *ngIf="action.icon">{{ action.icon }}</mat-icon> <mat-icon *ngIf="action.icon">{{ action.icon }}</mat-icon>
<span>{{ action.title | translate }}</span> <span>{{ action.title | translate }}</span>
</button> </button>
</mat-menu> </mat-menu>
</div> </ng-container>
</td>
<label *ngIf="multiselect" [for]="'select-file-' + idx" class="adf-datatable-cell adf-datatable-checkbox"> </adf-datatable-row>
<mat-checkbox <tr *ngIf="isEmpty()" class="adf-datatable-row">
[id]="'select-file-' + idx" <td class="adf-no-content-container adf-datatable-cell">
[checked]="row.isSelected" <ng-template *ngIf="noContentTemplate"
[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"
ngFor [ngForOf]="[data]" ngFor [ngForOf]="[data]"
[ngForTemplate]="noPermissionTemplate"> [ngForTemplate]="noContentTemplate">
</ng-template> </ng-template>
</div> <ng-content select="adf-empty-list"></ng-content>
</div> </td>
<div *ngIf="loading" class="adf-datatable-row"> </tr>
<div class="adf-no-content-container adf-datatable-cell"> </ng-container>
<ng-template *ngIf="loadingTemplate" <tr *ngIf="!loading && noPermission"
ngFor [ngForOf]="[data]" class="adf-datatable-row adf-no-permission__row">
[ngForTemplate]="loadingTemplate"> <td class="adf-no-permission__cell adf-no-content-container adf-datatable-cell">
</ng-template> <ng-template *ngIf="noPermissionTemplate"
</div> ngFor [ngForOf]="[data]"
</div> [ngForTemplate]="noPermissionTemplate">
</div> </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> </div>

View File

@@ -283,6 +283,11 @@ $data-table-cell-min-width-file-size: $data-table-cell-min-width-1 !default;
padding-right: 15px; padding-right: 15px;
} }
.adf-datatable-checkbox {
display: flex;
justify-content: center;
}
.adf-cell-value { .adf-cell-value {
display: flex; display: flex;
min-height: inherit; min-height: inherit;
@@ -433,13 +438,13 @@ $data-table-cell-min-width-file-size: $data-table-cell-min-width-1 !default;
} }
/* mobile phone */ /* mobile phone */
@media all and (max-width: 768px) { @media all and (width <= 768px) {
.adf-desktop-only.adf-ellipsis-cell { .adf-desktop-only.adf-ellipsis-cell {
display: none; display: none;
} }
} }
@media (max-device-width: 768px) { @media (width <= 768px) {
.adf-desktop-only.adf-ellipsis-cell { .adf-desktop-only.adf-ellipsis-cell {
display: none; display: none;
} }
@@ -495,11 +500,6 @@ $data-table-cell-min-width-file-size: $data-table-cell-min-width-1 !default;
right: -3px; right: -3px;
} }
&.adf-datatable-checkbox {
display: flex;
align-items: center;
}
.adf-datatable-cell-header-content { .adf-datatable-cell-header-content {
display: flex; display: flex;
flex-grow: 1; 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.adf-drag-preview {
&.adf-datatable-cell-header { border-radius: 6px;
border-radius: 6px; background-color: var(--theme-background-color);
background-color: var(--theme-background-color);
@include mat.elevation-transition; @include mat.elevation-transition;
@include mat.elevation(4); @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;
} }
.adf-sticky-header { .adf-sticky-header {
@@ -620,7 +606,7 @@ $data-table-cell-min-width-file-size: $data-table-cell-min-width-1 !default;
align-items: center; align-items: center;
height: inherit; height: inherit;
.adf-datatable-body[role="rowgroup"] { .adf-datatable-body[role='rowgroup'] {
.adf-datatable-row { .adf-datatable-row {
height: 100%; height: 100%;
background-color: var(--adf-theme-background-card-color); 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 { .adf-datatable-header {
max-height: 50%; max-height: 50%;
} }

View File

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

View File

@@ -15,14 +15,14 @@
* limitations under the License. * 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 { Meta, moduleMetadata, Story } from '@storybook/angular';
import { CoreStoryModule } from '../../../testing/core.story.module'; import { CoreStoryModule } from '../../../testing/core.story.module';
import { DataTableComponent } from './datatable.component';
import { DataTableModule } from '../../datatable.module'; 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 { mockPathInfos } from '../mocks/datatable.mock';
import { DataTableComponent } from './datatable.component';
export default { export default {
component: DataTableComponent, component: DataTableComponent,
@@ -150,9 +150,22 @@ export default {
cssClass: 'adf-ellipsis-cell', cssClass: 'adf-ellipsis-cell',
copyContent: true 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: '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', type: 'date',
key: 'dateCol', key: 'dateCol',
@@ -162,11 +175,43 @@ export default {
cssClass: 'adf-ellipsis-cell', cssClass: 'adf-ellipsis-cell',
dateConfig: { format: 'timeAgo' } 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: 'fileSize',
{ type: 'boolean', key: 'booleanCol', title: 'Boolean Column', draggable: true, cssClass: 'adf-ellipsis-cell' }, key: 'fileSizeCol',
{ type: 'amount', key: 'amountCol', title: 'Amount Column', draggable: true, cssClass: 'adf-ellipsis-cell' }, title: 'File Size Column',
{ type: 'number', key: 'numberCol', title: 'Number Column', draggable: true, cssClass: 'adf-ellipsis-cell' }, 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' } { type: 'json', key: 'jsonCol', title: 'JSON Column', draggable: true, cssClass: 'adf-ellipsis-cell' }
], ],
table: { table: {

View File

@@ -17,6 +17,9 @@
/* eslint-disable @angular-eslint/no-conflicting-lifecycle */ /* 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 { import {
AfterContentInit, AfterContentInit,
AfterViewInit, AfterViewInit,
@@ -39,28 +42,45 @@ import {
ViewChildren, ViewChildren,
ViewEncapsulation ViewEncapsulation
} from '@angular/core'; } from '@angular/core';
import { FocusKeyManager } from '@angular/cdk/a11y'; import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxChange } from '@angular/material/checkbox'; import { MatCheckboxChange, MatCheckboxModule } from '@angular/material/checkbox';
import { MatMenuTrigger } from '@angular/material/menu'; 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 { 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 { DataColumn } from '../../data/data-column.model';
import { DataRowEvent } from '../../data/data-row-event.model'; import { DataRowEvent } from '../../data/data-row-event.model';
import { DataRow } from '../../data/data-row.model'; import { DataRow } from '../../data/data-row.model';
import { DataSorting } from '../../data/data-sorting.model'; import { DataSorting } from '../../data/data-sorting.model';
import { DataTableAdapter } from '../../data/datatable-adapter'; 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 { ObjectDataColumn } from '../../data/object-datacolumn.model';
import { ObjectDataRow } from '../../data/object-datarow.model';
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter'; 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 { DataCellEvent } from '../data-cell.event';
import { DataRowActionEvent } from '../data-row-action.event'; import { DataRowActionEvent } from '../data-row-action.event';
import { buffer, debounceTime, filter, map, share } from 'rxjs/operators'; import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop'; import { DataTableRowComponent } from '../datatable-row/datatable-row.component';
import { MatIconRegistry } from '@angular/material/icon'; import { DateCellComponent } from '../date-cell/date-cell.component';
import { DomSanitizer } from '@angular/platform-browser'; import { FileSizeCellComponent } from '../filesize-cell/filesize-cell.component';
import { ResizeEvent } from '../../directives/resizable/types'; 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 // eslint-disable-next-line no-shadow
export enum ShowHeaderMode { export enum ShowHeaderMode {
@@ -71,9 +91,40 @@ export enum ShowHeaderMode {
@Component({ @Component({
selector: 'adf-datatable', selector: 'adf-datatable',
standalone: true,
templateUrl: './datatable.component.html', templateUrl: './datatable.component.html',
styleUrls: ['./datatable.component.scss'], styleUrls: ['./datatable.component.scss'],
encapsulation: ViewEncapsulation.None, 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' } host: { class: 'adf-datatable' }
}) })
export class DataTableComponent implements OnInit, AfterContentInit, OnChanges, DoCheck, OnDestroy, AfterViewInit { export class DataTableComponent implements OnInit, AfterContentInit, OnChanges, DoCheck, OnDestroy, AfterViewInit {

View File

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

View File

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

View File

@@ -15,12 +15,12 @@
* limitations under the License. * 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 { 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 { LocalizedDatePipe, TimeAgoPipe } from '../../../pipes';
import { DateConfig } from '../../data/data-column.model';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
@Component({ @Component({
standalone: true, standalone: true,
@@ -32,7 +32,6 @@ import { LocalizedDatePipe, TimeAgoPipe } from '../../../pipes';
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class DateCellComponent extends DataTableCellComponent implements OnInit { export class DateCellComponent extends DataTableCellComponent implements OnInit {
@Input() @Input()
dateConfig: DateConfig; dateConfig: DateConfig;

View File

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

View File

@@ -19,12 +19,27 @@ import { Component, Directive, ViewEncapsulation } from '@angular/core';
@Component({ @Component({
selector: 'adf-empty-list', selector: 'adf-empty-list',
standalone: true,
styleUrls: ['./empty-list.component.scss'], styleUrls: ['./empty-list.component.scss'],
templateUrl: './empty-list.component.html', templateUrl: './empty-list.component.html',
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class EmptyListComponent {} export class EmptyListComponent {}
@Directive({ selector: '[adf-empty-list-header]' }) export class EmptyListHeaderDirective {} @Directive({
@Directive({ selector: '[adf-empty-list-body]' }) export class EmptyListBodyDirective {} selector: '[adf-empty-list-header]',
@Directive({ selector: '[adf-empty-list-footer]' }) export class EmptyListFooterDirective {} 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. * limitations under the License.
*/ */
import { AsyncPipe, NgIf } from '@angular/common';
import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { FileSizePipe } from '../../../pipes';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component'; import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
@Component({ @Component({
selector: 'adf-filesize-cell', selector: 'adf-filesize-cell',
standalone: true,
template: ` template: `
<ng-container *ngIf="value$ | async | adfFileSize as fileSize"> <ng-container *ngIf="value$ | async | adfFileSize as fileSize">
<span [title]="tooltip">{{ fileSize }}</span> <span [title]="tooltip">{{ fileSize }}</span>
</ng-container> </ng-container>
`, `,
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
imports: [NgIf, AsyncPipe, FileSizePipe],
host: { class: 'adf-filesize-cell' } host: { class: 'adf-filesize-cell' }
}) })
export class FileSizeCellComponent extends DataTableCellComponent implements OnInit { export class FileSizeCellComponent extends DataTableCellComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
} }

View File

@@ -15,14 +15,14 @@
* limitations under the License. * 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 { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatIconHarness } from '@angular/material/icon/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', () => { describe('IconCellComponent', () => {
let component: IconCellComponent; let component: IconCellComponent;

View File

@@ -18,8 +18,8 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, ViewEncapsulation } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, ViewEncapsulation } from '@angular/core';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
@Component({ @Component({
standalone: true, 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. * 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 { 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 { 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', () => { describe('JsonCellComponent', () => {
let loader: HarnessLoader; let loader: HarnessLoader;

View File

@@ -15,25 +15,21 @@
* limitations under the License. * limitations under the License.
*/ */
import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation, Input } from '@angular/core'; import { AsyncPipe, NgIf } from '@angular/common';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component'; import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog'; 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({ @Component({
selector: 'adf-json-cell', selector: 'adf-json-cell',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
template: ` templateUrl: './json-cell.component.html',
<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>
`,
styleUrls: ['./json-cell.component.scss'], styleUrls: ['./json-cell.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
imports: [AsyncPipe, MatButtonModule, NgIf],
host: { class: 'adf-datatable-content-cell' } host: { class: 'adf-datatable-content-cell' }
}) })
export class JsonCellComponent extends DataTableCellComponent implements OnInit { export class JsonCellComponent extends DataTableCellComponent implements OnInit {

View File

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

View File

@@ -15,15 +15,15 @@
* limitations under the License. * 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 { 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({ @Component({
standalone: true,
imports: [AsyncPipe, RouterModule], imports: [AsyncPipe, RouterModule],
standalone: true,
selector: 'adf-location-cell', selector: 'adf-location-cell',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
template: ` template: `

View File

@@ -22,11 +22,12 @@ export const mockCarsData: any = [
{ {
car_id: 1, car_id: 1,
car_name: 'Fiat 126p (Process)', car_name: 'Fiat 126p (Process)',
car_price: 599.00, car_price: 599.0,
fuel_consumption: 5.25789, fuel_consumption: 5.25789,
is_available: 'false', is_available: 'false',
production_start: '1972-04-23', 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', icon: 'airport_shuttle',
wikipedia_link: 'https://en.wikipedia.org/wiki/Fiat_126' wikipedia_link: 'https://en.wikipedia.org/wiki/Fiat_126'
}, },
@@ -48,7 +49,8 @@ export const mockCarsData: any = [
fuel_consumption: 6, fuel_consumption: 6,
is_available: 'true', is_available: 'true',
production_start: '1998-06-25T12:25:20', 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', icon: 'directions_car',
wikipedia_link: 'https://en.wikipedia.org/wiki/Audi_A3' wikipedia_link: 'https://en.wikipedia.org/wiki/Audi_A3'
} }

View File

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

View File

@@ -15,13 +15,13 @@
* limitations under the License. * 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 { registerLocaleData } from '@angular/common';
import localePL from '@angular/common/locales/pl'; 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', () => { describe('NumberCellComponent', () => {
let component: NumberCellComponent; let component: NumberCellComponent;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,18 +15,18 @@
* limitations under the License. * 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 { DataColumnType } from '@alfresco/adf-extensions';
import { Component, ContentChild, Input, OnInit, TemplateRef } from '@angular/core';
import { CurrencyConfig, DateConfig, DecimalConfig } from '../data/data-column.model'; import { CurrencyConfig, DateConfig, DecimalConfig } from '../data/data-column.model';
@Component({ @Component({
selector: 'data-column', selector: 'data-column',
standalone: true,
template: '' template: ''
}) })
export class DataColumnComponent implements OnInit { export class DataColumnComponent implements OnInit {
/** Id of the Column */ /** Id of the Column */
@Input() @Input()
id: string = ''; id: string = '';
@@ -91,7 +91,7 @@ export class DataColumnComponent implements OnInit {
@Input('class') @Input('class')
cssClass: string; 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() @Input()
copyContent: boolean; copyContent: boolean;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,9 +15,9 @@
* limitations under the License. * limitations under the License.
*/ */
import { TemplateRef } from '@angular/core';
import { DataColumnType } from '@alfresco/adf-extensions'; 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. // Simple implementation of the DataColumn interface.
export class ObjectDataColumn<T = unknown> implements DataColumn<T> { export class ObjectDataColumn<T = unknown> implements DataColumn<T> {

View File

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

View File

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

View File

@@ -15,13 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { Subject } from 'rxjs';
import { DataColumn } from './data-column.model'; import { DataColumn } from './data-column.model';
import { DataRow } from './data-row.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 { DataSorting } from './data-sorting.model';
import { DataTableAdapter } from './datatable-adapter'; 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. // Simple implementation of the DataTableAdapter interface.
export class ObjectDataTableAdapter implements DataTableAdapter { export class ObjectDataTableAdapter implements DataTableAdapter {

View File

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

View File

@@ -17,13 +17,8 @@
import { Directive } from '@angular/core'; 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({ @Directive({
selector: 'adf-custom-empty-content-template, empty-folder-content' selector: 'adf-custom-empty-content-template',
standalone: true
}) })
export class CustomEmptyContentTemplateDirective {} export class CustomEmptyContentTemplateDirective {}

View File

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

View File

@@ -17,12 +17,8 @@
import { Directive } from '@angular/core'; 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({ @Directive({
selector: 'adf-custom-no-permission-template, no-permission-content' selector: 'adf-custom-no-permission-template',
standalone: true
}) })
export class CustomNoPermissionTemplateDirective {} export class CustomNoPermissionTemplateDirective {}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,10 +15,10 @@
* limitations under the License. * 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 { DataTableComponent } from '../components/datatable/datatable.component';
import { NoContentTemplateDirective } from './no-content-template.directive'; import { NoContentTemplateDirective } from './no-content-template.directive';
import { CoreTestingModule } from '../../testing/core.testing.module';
describe('NoContentTemplateDirective', () => { describe('NoContentTemplateDirective', () => {
let fixture: ComponentFixture<DataTableComponent>; 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 selectors without adf- prefix will be deprecated on 3.0.0
*/ */
@Directive({ @Directive({
selector: 'adf-no-content-template, no-content-template' selector: 'adf-no-content-template',
standalone: true
}) })
export class NoContentTemplateDirective implements AfterContentInit { export class NoContentTemplateDirective implements AfterContentInit {
@ContentChild(TemplateRef) @ContentChild(TemplateRef)
template: any; template: any;
constructor(private dataTable: DataTableComponent) { constructor(private dataTable: DataTableComponent) {}
}
ngAfterContentInit() { ngAfterContentInit() {
if (this.dataTable) { if (this.dataTable) {

View File

@@ -15,10 +15,10 @@
* limitations under the License. * 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 { DataTableComponent } from '../components/datatable/datatable.component';
import { NoPermissionTemplateDirective } from './no-permission-template.directive'; import { NoPermissionTemplateDirective } from './no-permission-template.directive';
import { CoreTestingModule } from '../../testing/core.testing.module';
describe('NoPermissionTemplateDirective', () => { describe('NoPermissionTemplateDirective', () => {
let fixture: ComponentFixture<DataTableComponent>; 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 selectors without adf- prefix will be deprecated on 3.0.0
*/ */
@Directive({ @Directive({
selector: 'adf-no-permission-template, no-permission-template' selector: 'adf-no-permission-template',
standalone: true
}) })
export class NoPermissionTemplateDirective implements AfterContentInit { export class NoPermissionTemplateDirective implements AfterContentInit {
@ContentChild(TemplateRef) @ContentChild(TemplateRef)
template: any; template: any;
constructor(private dataTable: DataTableComponent) { constructor(private dataTable: DataTableComponent) {}
}
ngAfterContentInit() { ngAfterContentInit() {
if (this.dataTable) { if (this.dataTable) {

View File

@@ -15,8 +15,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { TestBed } from '@angular/core/testing';
import { ElementRef, NgZone, Renderer2 } from '@angular/core'; import { ElementRef, NgZone, Renderer2 } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { ResizableDirective } from './resizable.directive'; import { ResizableDirective } from './resizable.directive';
describe('ResizableDirective', () => { describe('ResizableDirective', () => {
@@ -54,7 +54,7 @@ describe('ResizableDirective', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ResizableDirective], imports: [ResizableDirective],
providers: [ providers: [
{ provide: Renderer2, useValue: rendererMock }, { provide: Renderer2, useValue: rendererMock },
{ provide: ElementRef, useValue: elementRefMock } { provide: ElementRef, useValue: elementRefMock }
@@ -103,7 +103,15 @@ describe('ResizableDirective', () => {
directive.mousedown.next({ ...mouseDownEvent, resize: true }); 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', () => { it('should unset cursor on mouseup', () => {
@@ -125,7 +133,9 @@ describe('ResizableDirective', () => {
directive.mousedown.next({ ...mouseDownEvent, resize: true }); directive.mousedown.next({ ...mouseDownEvent, resize: true });
directive.mouseup.next(mouseUpEvent); 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', () => { it('should emit resizing on mousemove', () => {
@@ -137,7 +147,15 @@ describe('ResizableDirective', () => {
directive.mousedown.next({ ...mouseDownEvent, resize: true }); directive.mousedown.next({ ...mouseDownEvent, resize: true });
directive.mousemove.next(mouseMoveEvent); 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', () => { it('should emit resizing on mousemove considering cover padding', () => {
@@ -151,6 +169,14 @@ describe('ResizableDirective', () => {
directive.mousedown.next({ ...mouseDownEvent, resize: true }); directive.mousedown.next({ ...mouseDownEvent, resize: true });
directive.mousemove.next(mouseMoveEvent); 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. * limitations under the License.
*/ */
import { Subject, Observable, Observer, merge } from 'rxjs'; import { Directive, ElementRef, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output, Renderer2 } from '@angular/core';
import { BoundingRectangle, ResizeEvent, IResizeMouseEvent, ICoordinateX } from './types'; import { merge, Observable, Observer, Subject } from 'rxjs';
import { map, take, share, filter, pairwise, mergeMap, takeUntil } from 'rxjs/operators'; import { filter, map, mergeMap, pairwise, share, take, takeUntil } from 'rxjs/operators';
import { OnInit, Output, NgZone, OnDestroy, Directive, Renderer2, ElementRef, EventEmitter, Input } from '@angular/core'; import { BoundingRectangle, ICoordinateX, IResizeMouseEvent, ResizeEvent } from './types';
@Directive({ @Directive({
selector: '[adf-resizable]', selector: '[adf-resizable]',
standalone: true,
exportAs: 'adf-resizable' exportAs: 'adf-resizable'
}) })
export class ResizableDirective implements OnInit, OnDestroy { export class ResizableDirective implements OnInit, OnDestroy {

View File

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

View File

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

View File

@@ -15,12 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { Directive, ElementRef, Input, NgZone, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { ResizableDirective } from './resizable.directive'; import { ResizableDirective } from './resizable.directive';
import { Input, OnInit, Directive, Renderer2, ElementRef, OnDestroy, NgZone } from '@angular/core';
@Directive({ @Directive({
selector: '[adf-resize-handle]' selector: '[adf-resize-handle]',
standalone: true
}) })
export class ResizeHandleDirective implements OnInit, OnDestroy { 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 './services/datatable.service';
export * from './datatable.module'; export * from './datatable.module';
export * from './data-column'; export * from './data-column';

View File

@@ -15,35 +15,25 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, SimpleChange, ViewChild } from '@angular/core'; import { AppConfigService, ColumnsSelectorComponent, DataColumn, DataRowEvent, getDataColumnMock, ObjectDataRow, User } from '@alfresco/adf-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 { PreferenceCloudServiceInterface } from '@alfresco/adf-process-services-cloud'; import { PreferenceCloudServiceInterface } from '@alfresco/adf-process-services-cloud';
import { HarnessLoader } from '@angular/cdk/testing'; import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; 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 { 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({ @Component({
template: ` <adf-cloud-process-list #processListCloud> template: ` <adf-cloud-process-list #processListCloud>
@@ -636,9 +626,9 @@ describe('ProcessListCloudComponent: Creating an empty custom template - EmptyTe
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule, DataTableModule, MatProgressSpinnerModule], imports: [ProcessServiceCloudTestingModule, MatProgressSpinnerModule],
providers: [{ provide: PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN, useValue: preferencesService }], providers: [{ provide: PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN, useValue: preferencesService }],
declarations: [EmptyTemplateComponent, ProcessListCloudComponent, CustomEmptyContentTemplateDirective] declarations: [EmptyTemplateComponent, ProcessListCloudComponent]
}); });
fixtureEmpty = TestBed.createComponent(EmptyTemplateComponent); fixtureEmpty = TestBed.createComponent(EmptyTemplateComponent);
fixtureEmpty.detectChanges(); fixtureEmpty.detectChanges();

View File

@@ -650,7 +650,7 @@ describe('TaskListCloudComponent: Copy cell content directive from app.config sp
fixture.detectChanges(); fixture.detectChanges();
const cell = fixture.debugElement.query(By.css('[data-automation-id="text_ADF_CLOUD_TASK_LIST.PROPERTIES.PRIORITY_VALUES.NONE"]')); 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', () => { 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; const MAX_LOADING_TIME = 120000;
export class DataTableComponentPage { export class DataTableComponentPage {
rootElement: ElementFinder; rootElement: ElementFinder;
list: ElementArrayFinder; list: ElementArrayFinder;
contents: ElementArrayFinder; contents: ElementArrayFinder;
@@ -39,22 +38,22 @@ export class DataTableComponentPage {
noContentContainer: ElementFinder; noContentContainer: ElementFinder;
mainMenuButton: 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()) { constructor(rootElement = $$('adf-datatable').first()) {
this.rootElement = rootElement; 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.contents = this.rootElement.$$('.adf-datatable-body span');
this.tableBody = this.rootElement.$$(`.adf-datatable-body`).first(); this.tableBody = this.rootElement.$$(`.adf-datatable-body`).first();
this.allColumns = this.rootElement.$$('div[data-automation-id*="auto_header_content_id"]'); 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.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.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.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.emptyList = this.rootElement.$(`adf-empty-content`);
this.emptyListTitle = this.rootElement.$(`.adf-empty-content__title`); this.emptyListTitle = this.rootElement.$(`.adf-empty-content__title`);
this.emptyListSubtitle = this.rootElement.$(`.adf-empty-content__subtitle`); 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 { geCellElementDetail(detail: string): ElementArrayFinder {
@@ -114,19 +113,23 @@ export class DataTableComponentPage {
} }
async checkRowIsSelected(columnName: string, columnValue: string): Promise<void> { 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); await BrowserVisibility.waitUntilElementIsVisible(selectedRow);
} }
async checkRowIsNotSelected(columnName: string, columnValue: string): Promise<void> { 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); await BrowserVisibility.waitUntilElementIsNotVisible(selectedRow);
} }
async getColumnValueForRow(identifyingColumn: string, identifyingValue: string, columnName: string): Promise<string> { async getColumnValueForRow(identifyingColumn: string, identifyingValue: string, columnName: string): Promise<string> {
const row = this.getRow(identifyingColumn, identifyingValue); const row = this.getRow(identifyingColumn, identifyingValue);
await BrowserVisibility.waitUntilElementIsVisible(row); await BrowserVisibility.waitUntilElementIsVisible(row);
const rowColumn = row.$(`div[title="${columnName}"] span`); const rowColumn = row.$(`td[title="${columnName}"] span`);
return BrowserActions.getText(rowColumn); 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 * @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> { 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()); await BrowserVisibility.waitUntilElementIsVisible(column.first());
const initialList: string[] = []; const initialList: string[] = [];
@@ -229,14 +232,14 @@ export class DataTableComponentPage {
async getAllRowsColumnValues(column: string): Promise<string[]> { async getAllRowsColumnValues(column: string): Promise<string[]> {
let columnValues: 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); await BrowserVisibility.waitUntilElementIsPresent(columnLocator.first(), 1000);
try { try {
await BrowserVisibility.waitUntilElementIsPresent(columnLocator.first(), 1000); await BrowserVisibility.waitUntilElementIsPresent(columnLocator.first(), 1000);
columnValues = await columnLocator columnValues = await columnLocator.filter(async (el) => el.isPresent()).map(async (el) => el.getText());
.filter(async (el) => el.isPresent())
.map(async (el) => el.getText());
} catch (error) { } catch (error) {
Logger.log(error); Logger.log(error);
} }
@@ -245,7 +248,7 @@ export class DataTableComponentPage {
} }
async getRowsWithSameColumnValues(columnName: string, columnValue: string) { 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()); await BrowserVisibility.waitUntilElementIsVisible(this.rootElement.$$(columnLocator).first());
return this.rootElement.$$(columnLocator).getText(); return this.rootElement.$$(columnLocator).getText();
} }
@@ -273,7 +276,7 @@ export class DataTableComponentPage {
* @param titleColumn column title * @param titleColumn column title
*/ */
async sortByColumn(sortOrder: string, titleColumn: string): Promise<void> { 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); await BrowserVisibility.waitUntilElementIsVisible(locator);
const result = await BrowserActions.getAttribute(locator, 'class'); const result = await BrowserActions.getAttribute(locator, 'class');
@@ -326,12 +329,20 @@ export class DataTableComponentPage {
} }
getRow(columnName: string, columnValue: string): ElementFinder { 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 // @deprecated use Playwright instead
getRowByIndex(index: number): ElementFinder { 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> { async contentInPosition(position: number): Promise<string> {
@@ -340,7 +351,7 @@ export class DataTableComponentPage {
} }
getCellElementByValue(columnName: string, columnValue: string, columnPrefix = 'text_'): ElementFinder { 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> { async tableIsLoaded(): Promise<void> {
@@ -350,23 +361,27 @@ export class DataTableComponentPage {
async waitTillContentLoaded(): Promise<void> { async waitTillContentLoaded(): Promise<void> {
if (await this.isSpinnerPresent()) { if (await this.isSpinnerPresent()) {
Logger.log('wait datatable loading spinner disappear'); 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()) { if (await this.isEmpty()) {
Logger.log('empty page'); Logger.log('empty page');
} else { } else {
await this.waitFirstElementPresent(); await this.waitFirstElementPresent();
} }
} else if (await this.isEmpty()) { } else if (await this.isEmpty()) {
Logger.log('empty page'); Logger.log('empty page');
} else { } else {
try { try {
Logger.log('wait datatable loading spinner is present'); Logger.log('wait datatable loading spinner is present');
await BrowserVisibility.waitUntilElementIsVisible(this.rootElement.element(by.tagName(materialLocators.Progress.spinner.root)), 2000); 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); await BrowserVisibility.waitUntilElementIsNotVisible(
} catch (error) { this.rootElement.element(by.tagName(materialLocators.Progress.spinner.root)),
} MAX_LOADING_TIME
);
} catch (error) {}
if (await this.isEmpty()) { if (await this.isEmpty()) {
Logger.log('empty page'); Logger.log('empty page');
@@ -392,8 +407,7 @@ export class DataTableComponentPage {
try { try {
Logger.log('wait datatable loading spinner is present'); Logger.log('wait datatable loading spinner is present');
await BrowserVisibility.waitUntilElementIsVisible(element(by.tagName(materialLocators.Progress.bar.root))); await BrowserVisibility.waitUntilElementIsVisible(element(by.tagName(materialLocators.Progress.bar.root)));
} catch (error) { } catch (error) {}
}
if (await this.isEmpty()) { if (await this.isEmpty()) {
Logger.log('empty page'); Logger.log('empty page');
} else { } else {
@@ -404,14 +418,10 @@ export class DataTableComponentPage {
// @deprecated use Playwright instead // @deprecated use Playwright instead
async isColumnDisplayed(columnTitle: string): Promise<boolean> { async isColumnDisplayed(columnTitle: string): Promise<boolean> {
const isColumnDisplayed = (await this.allColumns).some( return (await this.allColumns).some(async (column) => {
async column => { const columnText = await column.getText();
const columnText = await column.getText(); return columnText === columnTitle;
return columnText === columnTitle; });
}
);
return isColumnDisplayed;
} }
// @deprecated use Playwright instead // @deprecated use Playwright instead
@@ -424,11 +434,11 @@ export class DataTableComponentPage {
} }
getCellByRowNumberAndColumnName(rowNumber: number, columnName: string): ElementFinder { 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 { 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> { async selectRowByContent(content: string): Promise<void> {
@@ -447,42 +457,52 @@ export class DataTableComponentPage {
} }
getCellByContent(content: string): ElementFinder { 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> { 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); await BrowserVisibility.waitUntilElementIsVisible(cell);
} }
async clickRowByContent(name: string): Promise<void> { 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); await BrowserActions.click(resultElement);
} }
async clickRowByContentCheckbox(name: string): Promise<void> { 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); browser.actions().mouseMove(resultElement);
await BrowserActions.click(resultElement); await BrowserActions.click(resultElement);
} }
async checkRowContentIsDisplayed(content: string): Promise<void> { 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); await BrowserVisibility.waitUntilElementIsVisible(resultElement);
} }
async checkRowContentIsNotDisplayed(content: string): Promise<void> { 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); await BrowserVisibility.waitUntilElementIsNotVisible(resultElement);
} }
async checkRowContentIsDisabled(content: string): Promise<void> { 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); await BrowserVisibility.waitUntilElementIsVisible(resultElement);
} }
async doubleClickRowByContent(name: string): Promise<void> { 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 BrowserActions.click(resultElement);
await browser.actions().sendKeys(protractor.Key.ENTER).perform(); await browser.actions().sendKeys(protractor.Key.ENTER).perform();
} }

View File

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

View File

@@ -23,7 +23,7 @@ import { BrowserVisibility } from '../../utils/browser-visibility';
export class DataTableItem { export class DataTableItem {
columns = new Array<Column>(); columns = new Array<Column>();
rootElement: ElementFinder; 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()) { constructor(rootElement = $$('adf-datatable').first()) {
this.rootElement = rootElement; this.rootElement = rootElement;
@@ -34,14 +34,16 @@ export class DataTableItem {
} }
async getColumn(columnName: string): Promise<Column> { async getColumn(columnName: string): Promise<Column> {
return this.columns.find( return this.columns.find((column) => column.getColumnName() === columnName);
(column) => column.getColumnName() === columnName
);
} }
async getRow(columnName: string, columnValue: string): Promise<ElementFinder> { async getRow(columnName: string, columnValue: string): Promise<ElementFinder> {
console.log('getRow', '-------------------------------------------------------');
const column = await this.getColumn(columnName); 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)); return this.rootElement.element(by.xpath(locator));
} }
@@ -71,19 +73,26 @@ export class DataTableItem {
async getColumnValueForRow(identifyingColumnName: string, identifyingColumnValue: string, columnName: string): Promise<string> { async getColumnValueForRow(identifyingColumnName: string, identifyingColumnValue: string, columnName: string): Promise<string> {
const row = await this.getRow(identifyingColumnName, identifyingColumnValue); const row = await this.getRow(identifyingColumnName, identifyingColumnValue);
await BrowserVisibility.waitUntilElementIsVisible(row); await BrowserVisibility.waitUntilElementIsVisible(row);
const rowColumn = row.$(`div[title="${columnName}"] span`); const rowColumn = row.$(`td[title="${columnName}"] span`);
return BrowserActions.getText(rowColumn); return BrowserActions.getText(rowColumn);
} }
async checkRowIsSelected(columnName: string, columnValue: string): Promise<void> { async checkRowIsSelected(columnName: string, columnValue: string): Promise<void> {
console.log('checkRowIsSelected', '-------------------------------------------------------');
const column = await this.getColumn(columnName); 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))); await BrowserVisibility.waitUntilElementIsVisible(element(by.xpath(locator)));
} }
async checkRowIsNotSelected(columnName: string, columnValue: string): Promise<void> { async checkRowIsNotSelected(columnName: string, columnValue: string): Promise<void> {
const column = await this.getColumn(columnName); 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))); 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`); unknownFormat = $(`adf-viewer-unknown-format .adf-viewer__unknown-format-view`);
async viewFile(fileName: string): Promise<void> { 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 BrowserActions.click(fileView);
await browser.actions().sendKeys(protractor.Key.ENTER).perform(); await browser.actions().sendKeys(protractor.Key.ENTER).perform();
await this.waitTillContentLoaded(); await this.waitTillContentLoaded();
@@ -245,7 +245,7 @@ export class ViewerPage {
} }
async clickInfoButton(): Promise<void> { 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> { async clickOnTab(tabName: string): Promise<void> {