mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-06-23 18:05:09 +00:00
[AAE-16965] Improve data table date column (#9038)
* [AAE-16965] Improve Date data table column type * [AAE-16965] Date unit tests * update docs * cleanup cells after implement inject * bring back removed constructors * remove empty constructors * replace constructor token injection by inject function * [AAE-16965] Use other variable for template * implement suggestions * update demo shell module * fix unit test * fix timeAgo problem * add some more unit tests * fake change in extensions * [AAE-16965] fix for backward compatibility
This commit is contained in:
parent
85ddcdf22c
commit
9278d9296f
@ -19,7 +19,7 @@ import { NgModule } from '@angular/core';
|
||||
import { TaskListDemoComponent } from './task-list-demo.component';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CoreModule } from '@alfresco/adf-core';
|
||||
import { CoreModule, LocalizedDatePipe } from '@alfresco/adf-core';
|
||||
import { ProcessModule } from '@alfresco/adf-process-services';
|
||||
|
||||
const routes: Routes = [
|
||||
@ -38,7 +38,8 @@ const routes: Routes = [
|
||||
CommonModule,
|
||||
RouterModule.forChild(routes),
|
||||
CoreModule,
|
||||
ProcessModule.forChild()
|
||||
ProcessModule.forChild(),
|
||||
LocalizedDatePipe
|
||||
],
|
||||
declarations: [TaskListDemoComponent]
|
||||
})
|
||||
|
@ -63,6 +63,7 @@ Defines column properties for DataTable, Tasklist, Document List and other compo
|
||||
| order | `number` | | Sets position of column. |
|
||||
| currencyConfig | `CurrencyConfig` | [Default currency config](#default-currency-config) | Currency configuration to customize the formatting and display of currency values within the component. |
|
||||
| decimalConfig | `DecimalConfig` | [Default decimal config](#default-decimal-config) | Decimal configuration to customize the formatting and display of decimal values within the component. |
|
||||
| dateConfig | `DateConfig` | [Default date config](#default-date-config) | Date configuration to customize the formatting and localization of date values within the component. |
|
||||
|
||||
## Properties configuration
|
||||
|
||||
@ -72,6 +73,7 @@ The `type` input allows us to specify the type of hosted values for a given colu
|
||||
|
||||
- `text` - The given values are represented as a strings (default option).
|
||||
- `boolean` - The column expects true / false (boolean values) and in addition accepts two strings - 'false' and 'true'. Other values are not recognized by the column, and the cell remains empty.
|
||||
- `date` - This column is responsible for displaying dates. It expects date represented by a string, number or Date object. This type comes with [`dateConfig`](#default-date-config),
|
||||
- `amount` - This column is responsible for displaying currencies. It expects numerals represented by a string or a number. This type comes with [`currencyConfig`](#default-currency-config),
|
||||
- `number` - This column is responsible for displaying numbers (integers and decimals). It expects numerals represented by a string or a number. This type comes with [`decimalConfig`](#default-decimal-config)
|
||||
- `location` - This column displays a clickable location link pointing to the parent path of the node. **Note:** This type is strongly related to the document list component ([document-list.component.md](../../content-services/components/document-list.component.md)).
|
||||
@ -120,6 +122,28 @@ These properties offer flexibility in customizing how decimal values are present
|
||||
|
||||
For more details on the possible use cases of the above properties, see the [official Angular documents](https://angular.io/api/common/DecimalPipe).
|
||||
|
||||
### `dateConfig` Input
|
||||
|
||||
The `dateConfig` input allows you to configure date formatting and localization for a component. It accepts an object of type `DateConfig` with optional properties for specifying the format of displayed date, tooltip and locale.
|
||||
|
||||
#### Properties
|
||||
|
||||
- `format` (optional): A string specifying the date format ([pre-defined formats](https://angular.io/api/common/DatePipe#pre-defined-format-options)).
|
||||
- `tooltipFormat` (optional): A string specifying the date format for tooltips.
|
||||
- `locale` (optional): A string indicating the locale or region-specific formatting to use for the currency.
|
||||
|
||||
#### Default date config
|
||||
|
||||
By default, the `dateConfig` object is not required. If not provided, the component will use the following default values:
|
||||
|
||||
- `format`: "medium"
|
||||
- `tooltipFormat`: "medium"
|
||||
- `locale`: undefined
|
||||
|
||||
These properties offer flexibility in customizing how date values are presented within the component.
|
||||
|
||||
For more details on the possible use cases of the above properties, see the [official Angular documents](https://angular.io/api/common/DatePipe).
|
||||
|
||||
## Details
|
||||
|
||||
### Conditional visibility
|
||||
|
@ -20,13 +20,11 @@ import {
|
||||
Component,
|
||||
ViewEncapsulation,
|
||||
Input,
|
||||
Optional,
|
||||
OnInit,
|
||||
DEFAULT_CURRENCY_CODE,
|
||||
Inject
|
||||
inject
|
||||
} from '@angular/core';
|
||||
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
|
||||
import { DataTableService } from '../../services/datatable.service';
|
||||
import { CurrencyConfig } from '../../data/data-column.model';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@ -44,6 +42,8 @@ export class AmountCellComponent extends DataTableCellComponent implements OnIni
|
||||
@Input()
|
||||
currencyConfig: CurrencyConfig;
|
||||
|
||||
private readonly defaultCurrencyCode: string = inject(DEFAULT_CURRENCY_CODE);
|
||||
|
||||
readonly defaultCurrencyConfig: CurrencyConfig = {
|
||||
code: this.defaultCurrencyCode,
|
||||
display: 'symbol',
|
||||
@ -51,16 +51,7 @@ export class AmountCellComponent extends DataTableCellComponent implements OnIni
|
||||
locale: undefined
|
||||
};
|
||||
|
||||
constructor(
|
||||
@Optional() dataTableService: DataTableService,
|
||||
@Inject(DEFAULT_CURRENCY_CODE) private readonly defaultCurrencyCode: string
|
||||
) {
|
||||
super(dataTableService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.column?.key && this.row && this.data) {
|
||||
this.value$.next(this.data.getValue(this.row, this.column, this.resolverFn));
|
||||
}
|
||||
super.ngOnInit();
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ChangeDetectionStrategy, Component, OnInit, Optional, ViewEncapsulation } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { DataTableService } from '../../services/datatable.service';
|
||||
import { BooleanPipe } from '../../../pipes/boolean.pipe';
|
||||
|
||||
@Component({
|
||||
@ -37,13 +36,8 @@ import { BooleanPipe } from '../../../pipes/boolean.pipe';
|
||||
host: { class: 'adf-datatable-content-cell' }
|
||||
})
|
||||
export class BooleanCellComponent extends DataTableCellComponent implements OnInit {
|
||||
constructor(@Optional() dataTableService: DataTableService) {
|
||||
super(dataTableService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.column?.key && this.row && this.data) {
|
||||
this.value$.next(this.data.getValue(this.row, this.column, this.resolverFn));
|
||||
}
|
||||
super.ngOnInit();
|
||||
}
|
||||
}
|
||||
|
@ -15,58 +15,86 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { UserPreferencesService } from '../../../common/services/user-preferences.service';
|
||||
import { AppConfigService } from '../../../app-config';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CoreTestingModule } from '../../../testing';
|
||||
import { DateCellComponent } from '../date-cell/date-cell.component';
|
||||
import { DataTableCellComponent } from './datatable-cell.component';
|
||||
import { DataRow } from '../../data/data-row.model';
|
||||
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
||||
import { DataTableService } from '../../services/datatable.service';
|
||||
import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
|
||||
import { mockCarsData, mockCarsSchemaDefinition } from '../mocks/datatable.mock';
|
||||
|
||||
describe('DateCellComponent', () => {
|
||||
let appConfigService: AppConfigService;
|
||||
let userPreferencesService: UserPreferencesService;
|
||||
let fixture: ComponentFixture<DateCellComponent>;
|
||||
let component: DateCellComponent;
|
||||
let getLocaleSpy: jasmine.Spy;
|
||||
describe('DataTableCellComponent', () => {
|
||||
let component: DataTableCellComponent;
|
||||
let fixture: ComponentFixture<DataTableCellComponent>;
|
||||
let dataTableService: DataTableService;
|
||||
|
||||
const renderTextCell = (value: string, tooltip: string) => {
|
||||
component.value$ = new BehaviorSubject<string>(value);
|
||||
component.tooltip = tooltip;
|
||||
|
||||
fixture.detectChanges();
|
||||
};
|
||||
|
||||
const checkDisplayedText = (expectedText: string) => {
|
||||
const displayedText = fixture.nativeElement.querySelector('span').textContent.trim();
|
||||
|
||||
expect(displayedText).toBeTruthy();
|
||||
expect(displayedText).toBe(expectedText);
|
||||
};
|
||||
|
||||
const checkDisplayedTooltip = (expectedTooltip: string) => {
|
||||
const displayedTooltip = fixture.nativeElement.querySelector('span').title;
|
||||
|
||||
expect(displayedTooltip).toBeTruthy();
|
||||
expect(displayedTooltip).toBe(expectedTooltip);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreTestingModule
|
||||
],
|
||||
declarations: [DateCellComponent]
|
||||
declarations: [DataTableCellComponent],
|
||||
providers: [DataTableService]
|
||||
});
|
||||
appConfigService = TestBed.inject(AppConfigService);
|
||||
userPreferencesService = TestBed.inject(UserPreferencesService);
|
||||
|
||||
getLocaleSpy = spyOn(userPreferencesService, 'select').and.callThrough();
|
||||
appConfigService.config = {
|
||||
dateValues: {
|
||||
defaultDateFormat: 'mediumDate',
|
||||
defaultTooltipDateFormat: 'medium'
|
||||
}
|
||||
};
|
||||
fixture = TestBed.createComponent(DateCellComponent);
|
||||
fixture = TestBed.createComponent(DataTableCellComponent);
|
||||
component = fixture.componentInstance;
|
||||
dataTableService = TestBed.inject(DataTableService);
|
||||
});
|
||||
|
||||
it('should read locale from user preferences service', () => {
|
||||
expect(getLocaleSpy).toHaveBeenCalledWith('locale');
|
||||
expect(component.currentLocale).toEqual('en');
|
||||
it('should display text and tooltip', () => {
|
||||
const row: DataRow = {
|
||||
id: '1',
|
||||
isSelected: false,
|
||||
hasValue: () => true,
|
||||
getValue: () => 'hello world',
|
||||
obj: 'Initial Value',
|
||||
cache: []
|
||||
};
|
||||
|
||||
component.row = row;
|
||||
|
||||
renderTextCell('hello world', 'hello world tooltip');
|
||||
|
||||
checkDisplayedText('hello world');
|
||||
checkDisplayedTooltip('hello world tooltip');
|
||||
});
|
||||
|
||||
it('should read date format values from app config service', () => {
|
||||
expect(component.format).toEqual('mediumDate');
|
||||
expect(component.tooltipDateFormat).toEqual('medium');
|
||||
});
|
||||
it('should update row obj value on data changes', () => {
|
||||
const row: DataRow = {
|
||||
id: '1',
|
||||
isSelected: false,
|
||||
hasValue: () => true,
|
||||
getValue: () => 'hello world',
|
||||
obj: 'Initial Value',
|
||||
cache: []
|
||||
};
|
||||
|
||||
component.data = new ObjectDataTableAdapter(mockCarsData, mockCarsSchemaDefinition);
|
||||
component.column = { key: 'car_name', type: 'text' };
|
||||
component.row = row;
|
||||
|
||||
it('should date values be formatted based on the formats defined in the app config', () => {
|
||||
component.value$.next('2022-07-14T11:50:45.973+0000');
|
||||
component.tooltip = '2022-07-14T11:50:45.973+0000';
|
||||
fixture.detectChanges();
|
||||
const dateCellValue = fixture.nativeElement.querySelector('.adf-datatable-cell-value');
|
||||
const tooltipValue = dateCellValue.attributes['title'].value;
|
||||
dataTableService.rowUpdate.next({ id: '1', obj: 'New Value' });
|
||||
|
||||
expect(dateCellValue.textContent.trim()).toEqual('Jul 14, 2022');
|
||||
expect(tooltipValue).toEqual('Jul 14, 2022, 11:50:45 AM');
|
||||
expect(component.row.obj).toBe('New Value');
|
||||
});
|
||||
});
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation, OnDestroy, Optional } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation, OnDestroy, inject } from '@angular/core';
|
||||
import { DataColumn } from '../../data/data-column.model';
|
||||
import { DataRow } from '../../data/data-row.model';
|
||||
import { DataTableAdapter } from '../../data/datatable-adapter';
|
||||
@ -58,8 +58,6 @@ export class DataTableCellComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
row: DataRow;
|
||||
|
||||
value$ = new BehaviorSubject<any>('');
|
||||
|
||||
/** Enables/disables a Clipboard directive to allow copying of the cell's content. */
|
||||
@Input()
|
||||
copyContent: boolean;
|
||||
@ -73,8 +71,9 @@ export class DataTableCellComponent implements OnInit, OnDestroy {
|
||||
resolverFn: (row: DataRow, col: DataColumn) => any = null;
|
||||
|
||||
protected onDestroy$ = new Subject<boolean>();
|
||||
protected dataTableService = inject(DataTableService, { optional: true });
|
||||
|
||||
constructor(@Optional() protected dataTableService: DataTableService) {}
|
||||
value$ = new BehaviorSubject<any>('');
|
||||
|
||||
ngOnInit() {
|
||||
this.updateValue();
|
||||
@ -97,6 +96,7 @@ export class DataTableCellComponent implements OnInit, OnDestroy {
|
||||
if (!this.dataTableService || !this.row.obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dataTableService.rowUpdate.pipe(takeUntil(this.onDestroy$)).subscribe((data) => {
|
||||
if (data?.id === this.row?.id && data.obj) {
|
||||
this.row.obj = data.obj;
|
||||
|
@ -253,7 +253,8 @@
|
||||
[column]="col"
|
||||
[row]="row"
|
||||
[resolverFn]="resolverFn"
|
||||
[tooltip]="getCellTooltip(row, col)">
|
||||
[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"
|
||||
|
@ -1229,6 +1229,17 @@ describe('DataTable', () => {
|
||||
expect(rows[1].getValue('fuel_consumption')).toBe(6);
|
||||
expect(rows[2].getValue('fuel_consumption')).toBe(4.9);
|
||||
});
|
||||
|
||||
it('should be able to display column of type date', () => {
|
||||
dataTable.data = new ObjectDataTableAdapter(mockCarsData, mockCarsSchemaDefinition);
|
||||
|
||||
fixture.detectChanges();
|
||||
const rows = dataTable.data.getRows();
|
||||
|
||||
expect(rows[0].getValue('production_start')).toBe('1972-04-23');
|
||||
expect(rows[1].getValue('production_start')).toBe('1998-06-25T12:25:20');
|
||||
expect(rows[2].getValue('production_start')).toBe('2004-02-10T12:25:43.511Z');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accesibility', () => {
|
||||
|
@ -0,0 +1,15 @@
|
||||
<ng-container *ngIf="value$ | async as date">
|
||||
<span
|
||||
[title]="tooltip | adfLocalizedDate: config.tooltipFormat: config.locale"
|
||||
class="adf-datatable-cell-value"
|
||||
*ngIf="format === 'timeAgo'; else standard_date">
|
||||
{{ date | adfTimeAgo: config.locale }}
|
||||
</span>
|
||||
<ng-template #standard_date>
|
||||
<span
|
||||
class="adf-datatable-cell-value"
|
||||
[title]="tooltip | adfLocalizedDate: config.tooltipFormat: config.locale">
|
||||
{{ date | adfLocalizedDate: format: config.locale }}
|
||||
</span>
|
||||
</ng-template>
|
||||
</ng-container>
|
@ -0,0 +1,235 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { DateCellComponent } from './date-cell.component';
|
||||
import { DataColumn, DateConfig } from '../../data/data-column.model';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { AppConfigService } from '../../../app-config';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { LOCALE_ID } from '@angular/core';
|
||||
import { registerLocaleData } from '@angular/common';
|
||||
import localePL from '@angular/common/locales/pl';
|
||||
|
||||
let component: DateCellComponent;
|
||||
let appConfigService: AppConfigService;
|
||||
let fixture: ComponentFixture<DateCellComponent>;
|
||||
|
||||
const mockDate = new Date('2023-10-25');
|
||||
const mockTooltip = mockDate.toISOString();
|
||||
const mockColumn: DataColumn = {
|
||||
key: 'mock-date',
|
||||
type: 'date',
|
||||
format: 'full'
|
||||
};
|
||||
|
||||
const renderDateCell = (dateConfig: DateConfig, value: number | string | Date, tooltip: string) => {
|
||||
component.value$ = new BehaviorSubject<number | string | Date>(value);
|
||||
component.dateConfig = dateConfig;
|
||||
component.tooltip = tooltip;
|
||||
|
||||
fixture.detectChanges();
|
||||
};
|
||||
|
||||
const checkDisplayedDate = (expectedDate: string) => {
|
||||
const displayedDate = fixture.nativeElement.querySelector('span').textContent.trim();
|
||||
|
||||
expect(displayedDate).toBeTruthy();
|
||||
expect(displayedDate).toBe(expectedDate);
|
||||
};
|
||||
|
||||
const checkDisplayedTooltip = (expectedTooltip: string) => {
|
||||
const displayedTooltip = fixture.nativeElement.querySelector('span').title;
|
||||
|
||||
expect(displayedTooltip).toBeTruthy();
|
||||
expect(displayedTooltip).toBe(expectedTooltip);
|
||||
};
|
||||
|
||||
const configureTestingModule = (providers: any[]) => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
DateCellComponent,
|
||||
HttpClientTestingModule,
|
||||
TranslateModule.forRoot()
|
||||
],
|
||||
providers
|
||||
});
|
||||
fixture = TestBed.createComponent(DateCellComponent);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
appConfigService = TestBed.inject(AppConfigService);
|
||||
|
||||
appConfigService.config = {
|
||||
dateValues: {
|
||||
defaultDateFormat: 'mediumDate',
|
||||
defaultTooltipDateFormat: 'long',
|
||||
defaultLocale: 'en-US'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
describe('DateCellComponent', () => {
|
||||
beforeEach(() => {
|
||||
configureTestingModule([]);
|
||||
});
|
||||
|
||||
it('should set default date config', () => {
|
||||
expect(component.defaultDateConfig.format).toBe('medium');
|
||||
expect(component.defaultDateConfig.tooltipFormat).toBe('medium');
|
||||
expect(component.defaultDateConfig.locale).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should display date and tooltip with provided config', () => {
|
||||
const mockDateConfig: DateConfig = {
|
||||
format: 'short',
|
||||
tooltipFormat: 'shortDate'
|
||||
};
|
||||
|
||||
const expectedDate = '10/25/23, 12:00 AM';
|
||||
const expectedTooltip = '10/25/23';
|
||||
|
||||
renderDateCell(mockDateConfig, mockDate, mockTooltip);
|
||||
checkDisplayedDate(expectedDate);
|
||||
checkDisplayedTooltip(expectedTooltip);
|
||||
});
|
||||
|
||||
it('should display date and tooltip with based on appConfig values if dateConfig is NOT provided', () => {
|
||||
const mockDateConfig: DateConfig = {};
|
||||
|
||||
const expectedDate = 'Oct 25, 2023';
|
||||
const expectedTooltip = 'October 25, 2023 at 12:00:00 AM GMT+0';
|
||||
|
||||
renderDateCell(mockDateConfig, mockDate, mockTooltip);
|
||||
checkDisplayedDate(expectedDate);
|
||||
checkDisplayedTooltip(expectedTooltip);
|
||||
|
||||
expect(component.config.format).toEqual('mediumDate');
|
||||
expect(component.config.tooltipFormat).toEqual('long');
|
||||
expect(component.config.locale).toEqual('en-US');
|
||||
});
|
||||
|
||||
it('should display date and tooltip with defaules values if NO dateConfig or appConfig is provided', () => {
|
||||
appConfigService.config = {
|
||||
dateValues: {}
|
||||
};
|
||||
const mockDateConfig: DateConfig = {};
|
||||
|
||||
const expectedDate = 'Oct 25, 2023, 12:00:00 AM';
|
||||
const expectedTooltip = expectedDate;
|
||||
|
||||
renderDateCell(mockDateConfig, mockDate, mockTooltip);
|
||||
checkDisplayedDate(expectedDate);
|
||||
checkDisplayedTooltip(expectedTooltip);
|
||||
});
|
||||
|
||||
it('should display date with timeAgo format', () => {
|
||||
const mockDateConfig: DateConfig = {
|
||||
format: 'timeAgo'
|
||||
};
|
||||
const today = new Date();
|
||||
const yesterday = new Date(today);
|
||||
yesterday.setDate(today.getDate() - 1);
|
||||
|
||||
const expectedDate = '1 day ago';
|
||||
|
||||
renderDateCell(mockDateConfig, yesterday, mockTooltip);
|
||||
checkDisplayedDate(expectedDate);
|
||||
});
|
||||
|
||||
it('should display date with timeAgo format if NO dateConfig and column format provided', () => {
|
||||
component.column = { ...mockColumn, format: 'timeAgo' };
|
||||
const mockDateConfig = undefined as any;
|
||||
const today = new Date();
|
||||
const yesterday = new Date(today);
|
||||
yesterday.setDate(today.getDate() - 1);
|
||||
|
||||
const expectedDate = '1 day ago';
|
||||
renderDateCell(mockDateConfig, yesterday, mockTooltip);
|
||||
checkDisplayedDate(expectedDate);
|
||||
});
|
||||
|
||||
it('should display date with column format if dateConfig format is not provided', () => {
|
||||
component.column = mockColumn;
|
||||
const mockDateConfig: DateConfig = {
|
||||
tooltipFormat: 'short'
|
||||
};
|
||||
|
||||
const expectedDate = 'Wednesday, October 25, 2023 at 12:00:00 AM GMT+00:00';
|
||||
|
||||
renderDateCell(mockDateConfig, mockDate, mockTooltip);
|
||||
checkDisplayedDate(expectedDate);
|
||||
});
|
||||
|
||||
it('should display date and override dateConfig by column format if is provided', () => {
|
||||
component.column = mockColumn;
|
||||
const mockDateConfig: DateConfig = {
|
||||
format: 'short'
|
||||
};
|
||||
|
||||
const expectedDate = 'Wednesday, October 25, 2023 at 12:00:00 AM GMT+00:00';
|
||||
|
||||
renderDateCell(mockDateConfig, mockDate, mockTooltip);
|
||||
checkDisplayedDate(expectedDate);
|
||||
});
|
||||
|
||||
it('should display date based on string', () => {
|
||||
const mockDateConfig: DateConfig = {
|
||||
format: 'short',
|
||||
tooltipFormat: 'short'
|
||||
};
|
||||
const mockStringDate = 'Oct 25, 2023';
|
||||
|
||||
const expectedDate = '10/25/23, 12:00 AM';
|
||||
|
||||
renderDateCell(mockDateConfig, mockStringDate, mockTooltip);
|
||||
checkDisplayedDate(expectedDate);
|
||||
});
|
||||
|
||||
it('should display date based on timestamp', () => {
|
||||
const mockDateConfig: DateConfig = {
|
||||
format: 'short',
|
||||
tooltipFormat: 'short'
|
||||
};
|
||||
const mockTimestamp = Date.parse('Oct 25, 2023');
|
||||
|
||||
const expectedDate = '10/25/23, 12:00 AM';
|
||||
|
||||
renderDateCell(mockDateConfig, mockTimestamp, mockTooltip);
|
||||
checkDisplayedDate(expectedDate);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DateCellComponent locale', () => {
|
||||
it('should display date and tooltip with custom locale', () => {
|
||||
configureTestingModule([{ provide: LOCALE_ID, useValue: 'pl-PL' }]);
|
||||
registerLocaleData(localePL);
|
||||
|
||||
const mockDateConfig: DateConfig = {
|
||||
format: 'short',
|
||||
tooltipFormat: 'medium',
|
||||
locale: 'pl-PL'
|
||||
};
|
||||
|
||||
const expectedDate = '25.10.2023, 00:00';
|
||||
const expectedTooltip = '25 paź 2023, 00:00:00';
|
||||
|
||||
renderDateCell(mockDateConfig, mockDate, mockTooltip);
|
||||
checkDisplayedDate(expectedDate);
|
||||
checkDisplayedTooltip(expectedTooltip);
|
||||
});
|
||||
});
|
@ -15,67 +15,52 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Optional, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, Input, OnInit, ViewEncapsulation, inject } from '@angular/core';
|
||||
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
|
||||
import {
|
||||
UserPreferencesService,
|
||||
UserPreferenceValues
|
||||
} from '../../../common/services/user-preferences.service';
|
||||
import { AppConfigService } from '../../../app-config/app-config.service';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { DataTableService } from '../../services/datatable.service';
|
||||
import { DateConfig } from '../../data/data-column.model';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { LocalizedDatePipe, TimeAgoPipe } from '../../../pipes';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [CommonModule, LocalizedDatePipe, TimeAgoPipe],
|
||||
selector: 'adf-date-cell',
|
||||
template: `
|
||||
<ng-container>
|
||||
<span
|
||||
title="{{ tooltip | adfLocalizedDate: 'medium' }}"
|
||||
class="adf-datatable-cell-value"
|
||||
*ngIf="format === 'timeAgo'; else standard_date">
|
||||
{{ value$ | async | adfTimeAgo: currentLocale }}
|
||||
</span>
|
||||
</ng-container>
|
||||
<ng-template #standard_date>
|
||||
<span
|
||||
class="adf-datatable-cell-value"
|
||||
title="{{ tooltip | adfLocalizedDate: tooltipDateFormat }}">
|
||||
{{ value$ | async | adfLocalizedDate: format }}
|
||||
</span>
|
||||
</ng-template>
|
||||
`,
|
||||
templateUrl: './date-cell.component.html',
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'adf-date-cell adf-datatable-content-cell' }
|
||||
host: { class: 'adf-datatable-content-cell' }
|
||||
})
|
||||
export class DateCellComponent extends DataTableCellComponent {
|
||||
export class DateCellComponent extends DataTableCellComponent implements OnInit {
|
||||
|
||||
static DATE_FORMAT = 'medium';
|
||||
@Input()
|
||||
dateConfig: DateConfig;
|
||||
|
||||
currentLocale: string;
|
||||
dateFormat: string;
|
||||
tooltipDateFormat: string;
|
||||
config: DateConfig = {};
|
||||
|
||||
private readonly appConfig: AppConfigService = inject(AppConfigService);
|
||||
|
||||
readonly defaultDateConfig: DateConfig = {
|
||||
format: 'medium',
|
||||
tooltipFormat: 'medium',
|
||||
locale: undefined
|
||||
};
|
||||
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
this.setConfig();
|
||||
}
|
||||
|
||||
get format(): string {
|
||||
if (this.column) {
|
||||
return this.column.format || this.dateFormat;
|
||||
}
|
||||
return this.dateFormat;
|
||||
return this.column?.format ?? this.config.format;
|
||||
}
|
||||
|
||||
constructor(
|
||||
userPreferenceService: UserPreferencesService,
|
||||
@Optional() dataTableService: DataTableService,
|
||||
appConfig: AppConfigService
|
||||
) {
|
||||
super(dataTableService);
|
||||
private setConfig(): void {
|
||||
this.config.format = this.dateConfig?.format || this.getAppConfigPropertyValue('dateValues.defaultDateFormat', this.defaultDateConfig.format);
|
||||
this.config.tooltipFormat = this.dateConfig?.tooltipFormat || this.getAppConfigPropertyValue('dateValues.defaultTooltipDateFormat', this.defaultDateConfig.tooltipFormat);
|
||||
this.config.locale = this.dateConfig?.locale || this.getAppConfigPropertyValue('dateValues.defaultLocale', this.defaultDateConfig.locale);
|
||||
}
|
||||
|
||||
this.dateFormat = appConfig.get('dateValues.defaultDateFormat', DateCellComponent.DATE_FORMAT);
|
||||
this.tooltipDateFormat = appConfig.get('dateValues.defaultTooltipDateFormat', DateCellComponent.DATE_FORMAT);
|
||||
if (userPreferenceService) {
|
||||
userPreferenceService
|
||||
.select(UserPreferenceValues.Locale)
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(locale => this.currentLocale = locale);
|
||||
}
|
||||
private getAppConfigPropertyValue(key: string, defaultValue: string): string {
|
||||
return this.appConfig.get(key, defaultValue);
|
||||
}
|
||||
}
|
||||
|
@ -15,25 +15,22 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Optional, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
|
||||
import { DataTableService } from '../../services/datatable.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-filesize-cell',
|
||||
template: `
|
||||
<ng-container *ngIf="(value$ | async | adfFileSize) as fileSize">
|
||||
<span
|
||||
[title]="tooltip"
|
||||
>{{ fileSize }}</span
|
||||
>
|
||||
<span [title]="tooltip">{{ fileSize }}</span>
|
||||
</ng-container>
|
||||
`,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'adf-filesize-cell' }
|
||||
})
|
||||
export class FileSizeCellComponent extends DataTableCellComponent {
|
||||
constructor(@Optional() dataTableService: DataTableService) {
|
||||
super(dataTableService);
|
||||
export class FileSizeCellComponent extends DataTableCellComponent implements OnInit {
|
||||
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation, Input, Optional } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation, Input } from '@angular/core';
|
||||
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { EditJsonDialogComponent, EditJsonDialogSettings } from '../../../dialogs/edit-json/edit-json.dialog';
|
||||
import { DataTableService } from '../../services/datatable.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-json-cell',
|
||||
@ -42,14 +41,12 @@ export class JsonCellComponent extends DataTableCellComponent implements OnInit
|
||||
@Input()
|
||||
editable: boolean = false;
|
||||
|
||||
constructor(private dialog: MatDialog, @Optional() dataTableService: DataTableService) {
|
||||
super(dataTableService);
|
||||
constructor(private dialog: MatDialog) {
|
||||
super();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.column?.key && this.row && this.data) {
|
||||
this.value$.next(this.data.getValue(this.row, this.column, this.resolverFn));
|
||||
}
|
||||
super.ngOnInit();
|
||||
}
|
||||
|
||||
view() {
|
||||
|
@ -15,9 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit, Optional, ViewEncapsulation } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
|
||||
import { DataTableService } from '../../services/datatable.service';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { PathInfo } from '@alfresco/js-api';
|
||||
@ -41,10 +40,6 @@ export class LocationCellComponent extends DataTableCellComponent implements OnI
|
||||
@Input()
|
||||
link: any[];
|
||||
|
||||
constructor(@Optional() dataTableService: DataTableService) {
|
||||
super(dataTableService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.ngOnInit();
|
||||
}
|
||||
|
@ -20,11 +20,9 @@ import {
|
||||
Component,
|
||||
ViewEncapsulation,
|
||||
Input,
|
||||
Optional,
|
||||
OnInit
|
||||
} from '@angular/core';
|
||||
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
|
||||
import { DataTableService } from '../../services/datatable.service';
|
||||
import { DecimalConfig } from '../../data/data-column.model';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@ -47,13 +45,7 @@ export class NumberCellComponent extends DataTableCellComponent implements OnIni
|
||||
locale: undefined
|
||||
};
|
||||
|
||||
constructor(@Optional() dataTableService: DataTableService) {
|
||||
super(dataTableService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.column?.key && this.row && this.data) {
|
||||
this.value$.next(this.data.getValue(this.row, this.column, this.resolverFn));
|
||||
}
|
||||
super.ngOnInit();
|
||||
}
|
||||
}
|
||||
|
@ -43,12 +43,23 @@ export interface DataColumn<T = unknown> {
|
||||
order?: number;
|
||||
currencyConfig?: CurrencyConfig;
|
||||
decimalConfig?: DecimalConfig;
|
||||
dateConfig?: DateConfig;
|
||||
}
|
||||
export interface DecimalConfig {
|
||||
digitsInfo?: string;
|
||||
|
||||
export interface LocaleConfig {
|
||||
locale?: string;
|
||||
}
|
||||
|
||||
export interface DecimalConfig extends LocaleConfig {
|
||||
digitsInfo?: string;
|
||||
}
|
||||
|
||||
export interface CurrencyConfig extends DecimalConfig {
|
||||
code?: string;
|
||||
display?: string;
|
||||
}
|
||||
|
||||
export interface DateConfig extends LocaleConfig {
|
||||
format?: string;
|
||||
tooltipFormat?: string;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
import { TemplateRef } from '@angular/core';
|
||||
import { DataColumnType } from '@alfresco/adf-extensions';
|
||||
import { CurrencyConfig, DataColumn, DecimalConfig } from './data-column.model';
|
||||
import { CurrencyConfig, DataColumn, DecimalConfig, DateConfig } from './data-column.model';
|
||||
|
||||
// Simple implementation of the DataColumn interface.
|
||||
export class ObjectDataColumn<T = unknown> implements DataColumn<T> {
|
||||
@ -41,6 +41,7 @@ export class ObjectDataColumn<T = unknown> implements DataColumn<T> {
|
||||
order?: number;
|
||||
currencyConfig?: CurrencyConfig;
|
||||
decimalConfig?: DecimalConfig;
|
||||
dateConfig?: DateConfig;
|
||||
|
||||
constructor(input: any) {
|
||||
this.id = input.id ?? '';
|
||||
@ -63,5 +64,6 @@ export class ObjectDataColumn<T = unknown> implements DataColumn<T> {
|
||||
this.order = input.order;
|
||||
this.currencyConfig = input.currencyConfig;
|
||||
this.decimalConfig = input.decimalConfig;
|
||||
this.dateConfig = input.dateConfig;
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ 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';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -76,7 +77,9 @@ import { NumberCellComponent } from './components/number-cell/number-cell.compon
|
||||
BooleanCellComponent,
|
||||
AmountCellComponent,
|
||||
NumberCellComponent,
|
||||
LocationCellComponent
|
||||
LocationCellComponent,
|
||||
DateCellComponent,
|
||||
LocalizedDatePipe
|
||||
],
|
||||
declarations: [
|
||||
DataTableComponent,
|
||||
@ -86,7 +89,6 @@ import { NumberCellComponent } from './components/number-cell/number-cell.compon
|
||||
EmptyListFooterDirective,
|
||||
DataTableCellComponent,
|
||||
DataTableRowComponent,
|
||||
DateCellComponent,
|
||||
FileSizeCellComponent,
|
||||
JsonCellComponent,
|
||||
ColumnsSelectorComponent,
|
||||
@ -108,7 +110,6 @@ import { NumberCellComponent } from './components/number-cell/number-cell.compon
|
||||
EmptyListFooterDirective,
|
||||
DataTableCellComponent,
|
||||
DataTableRowComponent,
|
||||
DateCellComponent,
|
||||
ColumnsSelectorComponent,
|
||||
FileSizeCellComponent,
|
||||
JsonCellComponent,
|
||||
|
@ -23,6 +23,7 @@ import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Pipe({
|
||||
standalone: true,
|
||||
name: 'adfLocalizedDate',
|
||||
pure: false
|
||||
})
|
||||
|
@ -40,19 +40,19 @@ import { DateTimePipe } from './date-time.pipe';
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
TranslateModule
|
||||
TranslateModule,
|
||||
LocalizedDatePipe,
|
||||
TimeAgoPipe
|
||||
],
|
||||
declarations: [
|
||||
FileSizePipe,
|
||||
HighlightPipe,
|
||||
TimeAgoPipe,
|
||||
MimeTypeIconPipe,
|
||||
InitialUsernamePipe,
|
||||
FullNamePipe,
|
||||
FormatSpacePipe,
|
||||
FileTypePipe,
|
||||
MultiValuePipe,
|
||||
LocalizedDatePipe,
|
||||
DecimalNumberPipe,
|
||||
LocalizedRolePipe,
|
||||
MomentDatePipe,
|
||||
@ -70,14 +70,14 @@ import { DateTimePipe } from './date-time.pipe';
|
||||
FormatSpacePipe,
|
||||
FileTypePipe,
|
||||
MultiValuePipe,
|
||||
LocalizedDatePipe,
|
||||
DecimalNumberPipe,
|
||||
LocalizedRolePipe,
|
||||
MomentDatePipe,
|
||||
MomentDateTimePipe,
|
||||
DateTimePipe,
|
||||
FilterStringPipe,
|
||||
FilterOutArrayObjectsByPropPipe
|
||||
FilterOutArrayObjectsByPropPipe,
|
||||
LocalizedDatePipe
|
||||
],
|
||||
exports: [
|
||||
FileSizePipe,
|
||||
@ -89,7 +89,6 @@ import { DateTimePipe } from './date-time.pipe';
|
||||
FormatSpacePipe,
|
||||
FileTypePipe,
|
||||
MultiValuePipe,
|
||||
LocalizedDatePipe,
|
||||
DecimalNumberPipe,
|
||||
LocalizedRolePipe,
|
||||
MomentDatePipe,
|
||||
|
@ -25,6 +25,7 @@ import { differenceInDays, formatDistance } from 'date-fns';
|
||||
import * as Locales from 'date-fns/locale';
|
||||
|
||||
@Pipe({
|
||||
standalone: true,
|
||||
name: 'adfTimeAgo'
|
||||
})
|
||||
export class TimeAgoPipe implements PipeTransform, OnDestroy {
|
||||
|
@ -35,18 +35,18 @@ export interface DataColumnTypes {
|
||||
export type DataColumnType = keyof DataColumnTypes;
|
||||
|
||||
export interface DocumentListPresetRef extends ExtensionElement {
|
||||
key: string;
|
||||
type: DataColumnType;
|
||||
title?: string;
|
||||
format?: string;
|
||||
class?: string;
|
||||
sortable: boolean;
|
||||
template: string;
|
||||
desktopOnly: boolean;
|
||||
sortingKey: string;
|
||||
isHidden?: boolean;
|
||||
rules?: {
|
||||
[key: string]: string;
|
||||
visible?: string;
|
||||
};
|
||||
key: string;
|
||||
type: DataColumnType;
|
||||
title?: string;
|
||||
format?: string;
|
||||
class?: string;
|
||||
sortable: boolean;
|
||||
template: string;
|
||||
desktopOnly: boolean;
|
||||
sortingKey: string;
|
||||
isHidden?: boolean;
|
||||
rules?: {
|
||||
[key: string]: string;
|
||||
visible?: string;
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user