task/831 Reimplement locale and date solution for all date outputs

This commit is contained in:
Martin Rojas Miguel Angel 2019-03-15 10:29:37 +01:00 committed by Holger Hagen
parent d16b4b51ab
commit cc8e47b99a
17 changed files with 117 additions and 116 deletions

View File

@ -17,7 +17,7 @@ module.exports = function (config) {
],
client: {
jasmine: {
//seed: 80185, // Specify if you need to re-run the same seed
// seed: '56124', // Specify if you need to re-run the same seed
},
clearContext: false // leave Jasmine Spec Runner output visible in browser
},

View File

@ -1,6 +1,6 @@
<div *ngIf="reportData" class="panel panel-default">
<div class="panel-heading">
<h4>{{reportData.meta.name}} ({{reportData.meta.date | date : 'dd.MM.yyyy HH:mm:ss'}})</h4>
<h4>{{reportData.meta.name}} ({{reportData.meta.date | dateTimeZone}})</h4>
</div>
<div class="panel-body">
<div class="row">
@ -13,4 +13,4 @@
</div>
<taskana-report [type]="reportType" [reportData]="reportData"></taskana-report>
</div>
</div>
</div>

View File

@ -14,14 +14,7 @@ export class RestConnectorService {
}
getTaskStatusReport(): Observable<ReportData> {
return this.httpClient.get<ReportData>(environment.taskanaRestUrl + '/v1/monitor/tasks-status-report?states=READY,CLAIMED,COMPLETED')
.pipe(map(
(response: ReportData) => {
if (response.meta.date) {
response.meta.date = TaskanaDate.applyTimeZone(response.meta.date);
}
return response;
}));
return this.httpClient.get<ReportData>(environment.taskanaRestUrl + '/v1/monitor/tasks-status-report?states=READY,CLAIMED,COMPLETED');
}
getWorkbasketStatistics(): Observable<ReportData> {

View File

@ -1,6 +1,6 @@
<div *ngIf= "reportData" class="panel panel-default">
<div class="panel-heading">
<h4>{{reportData.meta.name}} ({{reportData.meta.date | date : 'dd.MM.yyyy HH:mm:ss'}})</h4>
<h4>{{reportData.meta.name}} ({{reportData.meta.date | dateTimeZone}})</h4>
</div>
<div class="panel-body">
<div style="display: block" class =" col-xs-12 col-md-7 col-md-offset-2">

View File

@ -1,6 +1,6 @@
<div *ngIf="reportData" class="panel panel-default">
<div class="panel-heading">
<h4>{{reportData.meta.name}} ({{reportData.meta.date | date : 'dd.MM.yyyy HH:mm:ss'}})</h4>
<h4>{{reportData.meta.name}} ({{reportData.meta.date | dateTimeZone}})</h4>
</div>
<div class="panel-body">
<div class="row">

View File

@ -1,4 +1,5 @@
<div class="input-icon-wrap">
<div class="input-group">
<input type="text"
placeholder="{{placeholder}}"
class="form-control input-with-icon"
@ -7,6 +8,7 @@
(bsValueChange)="dateChange($event)"
[bsValue]="valueDate"
name="{{name}}"
id="{{id}}">
<span class="input-icon"><span class="material-icons md-24 black">date_range</span></span>
id="{{id}}"
#datePickerElement="bsDatepicker">
<span class="input-icon-addon material-icons md-24 dark-green" (click)="datePickerElement.toggle()">date_range</span>
</div>

View File

@ -1,10 +1,10 @@
.input-icon-wrap {
.input-group {
display: flex;
flex-direction: row;
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
height: 35px;
border: 1px solid #ccc;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.input-with-icon {
@ -12,7 +12,6 @@
height: 33px;
}
.input-icon span {
padding-top: 5px;
padding-right: 6px;
.input-icon-addon {
padding-top: 4px;
}

View File

@ -0,0 +1,8 @@
import { DateTimeZonePipe } from './date-time-zone.pipe';
describe('DateTimeZonePipe', () => {
it('create an instance', () => {
const pipe = new DateTimeZonePipe();
expect(pipe).toBeTruthy();
});
});

View File

@ -0,0 +1,20 @@
import {Pipe, PipeTransform} from '@angular/core';
import {TaskanaDate} from '../../util/taskana.date';
@Pipe({
name: 'dateTimeZone'
})
export class DateTimeZonePipe implements PipeTransform {
private datesMap = new Map<string, string>();
transform(value: any, args?: any): any {
let date = this.datesMap.get(value);
if (!date) {
date = TaskanaDate.getDateToDisplay(value);
this.datesMap.set(value, date);
}
return date;
}
}

View File

@ -1,48 +1,50 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AngularSvgIconModule } from 'angular-svg-icon';
import { RouterModule } from '@angular/router';
import { TreeModule } from 'angular-tree-component';
import { AlertModule, TypeaheadModule, BsDatepickerModule } from 'ngx-bootstrap';
import { AccordionModule } from 'ngx-bootstrap/accordion';
import {CommonModule} from '@angular/common';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {HttpClientModule, HTTP_INTERCEPTORS} from '@angular/common/http';
import {AngularSvgIconModule} from 'angular-svg-icon';
import {RouterModule} from '@angular/router';
import {TreeModule} from 'angular-tree-component';
import {AlertModule, TypeaheadModule, BsDatepickerModule} from 'ngx-bootstrap';
import {AccordionModule} from 'ngx-bootstrap/accordion';
/**
* Components
*/
import { GeneralMessageModalComponent } from 'app/shared/general-message-modal/general-message-modal.component';
import { SpinnerComponent } from 'app/shared/spinner/spinner.component';
import { AlertComponent } from 'app/shared/alert/alert.component';
import { MasterAndDetailComponent } from 'app/shared/master-and-detail/master-and-detail.component';
import { TaskanaTreeComponent } from 'app/shared/tree/tree.component';
import { TypeAheadComponent } from 'app/shared/type-ahead/type-ahead.component';
import { SortComponent } from './sort/sort.component';
import { RemoveConfirmationComponent } from 'app/shared/remove-confirmation/remove-confirmation.component';
import { FilterComponent } from 'app/shared/filter/filter.component';
import { IconTypeComponent } from 'app/administration/components/type-icon/icon-type.component';
import { FieldErrorDisplayComponent } from 'app/shared/field-error-display/field-error-display.component';
import { PaginationComponent } from './pagination/pagination.component';
import { NumberPickerComponent } from './number-picker/number-picker.component';
import { ProgressBarComponent } from './progress-bar/progress-bar.component';
import { DatePickerComponent } from './date-picker/date-picker.component';
import {GeneralMessageModalComponent} from 'app/shared/general-message-modal/general-message-modal.component';
import {SpinnerComponent} from 'app/shared/spinner/spinner.component';
import {AlertComponent} from 'app/shared/alert/alert.component';
import {MasterAndDetailComponent} from 'app/shared/master-and-detail/master-and-detail.component';
import {TaskanaTreeComponent} from 'app/shared/tree/tree.component';
import {TypeAheadComponent} from 'app/shared/type-ahead/type-ahead.component';
import {SortComponent} from './sort/sort.component';
import {RemoveConfirmationComponent} from 'app/shared/remove-confirmation/remove-confirmation.component';
import {FilterComponent} from 'app/shared/filter/filter.component';
import {IconTypeComponent} from 'app/administration/components/type-icon/icon-type.component';
import {FieldErrorDisplayComponent} from 'app/shared/field-error-display/field-error-display.component';
import {PaginationComponent} from './pagination/pagination.component';
import {NumberPickerComponent} from './number-picker/number-picker.component';
import {ProgressBarComponent} from './progress-bar/progress-bar.component';
import {DatePickerComponent} from './date-picker/date-picker.component';
/**
* Pipes
*/
import { MapValuesPipe } from './pipes/mapValues/map-values.pipe';
import { RemoveNoneTypePipe } from './pipes/removeNoneType/remove-none-type.pipe';
import { SelectWorkBasketPipe } from './pipes/selectedWorkbasket/seleted-workbasket.pipe';
import { SpreadNumberPipe } from './pipes/spreadNumber/spread-number';
import { OrderBy } from './pipes/orderBy/orderBy';
import { MapToIterable } from './pipes/mapToIterable/mapToIterable';
import { NumberToArray } from './pipes/numberToArray/numberToArray';
import {MapValuesPipe} from './pipes/mapValues/map-values.pipe';
import {RemoveNoneTypePipe} from './pipes/removeNoneType/remove-none-type.pipe';
import {SelectWorkBasketPipe} from './pipes/selectedWorkbasket/seleted-workbasket.pipe';
import {SpreadNumberPipe} from './pipes/spreadNumber/spread-number';
import {OrderBy} from './pipes/orderBy/orderBy';
import {MapToIterable} from './pipes/mapToIterable/mapToIterable';
import {NumberToArray} from './pipes/numberToArray/numberToArray';
import {DateTimeZonePipe} from './pipes/date-time-zone/date-time-zone.pipe';
/**
* Services
*/
import { HttpClientInterceptor } from './services/httpClientInterceptor/http-client-interceptor.service';
import { AccessIdsService } from './services/access-ids/access-ids.service';
import {HttpClientInterceptor} from './services/httpClientInterceptor/http-client-interceptor.service';
import {AccessIdsService} from './services/access-ids/access-ids.service';
const MODULES = [
CommonModule,
@ -68,6 +70,7 @@ const DECLARATIONS = [
RemoveNoneTypePipe,
SelectWorkBasketPipe,
SpreadNumberPipe,
DateTimeZonePipe,
NumberToArray,
OrderBy,
MapToIterable,

View File

@ -1,12 +1,12 @@
import { DatePipe } from '@angular/common';
export class TaskanaDate {
public static dateFormat = 'yyyy-MM-ddTHH:mm:ss.sss';
public static getDate(): string {
const dateFormat = 'yyyy-MM-ddTHH:mm:ss.sss';
const dateLocale = 'en-US';
const datePipe = new DatePipe(dateLocale);
return datePipe.transform(Date.now(), dateFormat) + 'Z';
return datePipe.transform(Date.now(), this.dateFormat) + 'Z';
}
public static convertSimpleDate(date: Date): string {
@ -20,7 +20,7 @@ export class TaskanaDate {
return this.applyTimeZone(date);
}
public static applyTimeZone(date: string): string | null {
private static applyTimeZone(date: string): string | null {
const dateFormat = 'yyyy-MM-dd HH:mm:ss';
const dateLocale = 'en-US';
const datePipe = new DatePipe(dateLocale);

View File

@ -2,12 +2,12 @@
<div class="col-md-6">
<div *ngIf="task.taskId" class="form-group">
<label for="task-modified" class="control-label">Modification date</label>
<input type="text" disabled class="form-control" id="task-modified" placeholder="Modified" [(ngModel)]="task.modified"
<input type="text" disabled class="form-control" id="task-modified" placeholder="Modified" [value]="task.modified | dateTimeZone"
name="task.modified">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-completed" class="control-label">Completion date</label>
<input type="text" disabled class="form-control" id="task-completed" placeholder="Complete date" [(ngModel)]="task.completed"
<input type="text" disabled class="form-control" id="task-completed" placeholder="Complete date" [value]="task.completed | dateTimeZone"
name="task.completed">
</div>
<div *ngIf="task.taskId" class="form-group">
@ -23,17 +23,17 @@
<div class="col-md-6">
<div *ngIf="task.taskId" class="form-group">
<label for="task-claimed" class="control-label">Claim date</label>
<input type="text" disabled class="form-control" id="task-claimed" placeholder="Claimed date" [(ngModel)]="task.claimed"
<input type="text" disabled class="form-control" id="task-claimed" placeholder="Claimed date" [value]="task.claimed | dateTimeZone"
name="task.claimed">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-planned" class="control-label">Planned date</label>
<input type="text" disabled class="form-control" id="task-planned" placeholder="Planned date" [(ngModel)]="task.planned"
<input type="text" disabled class="form-control" id="task-planned" placeholder="Planned date" [value]="task.planned | dateTimeZone"
name="task.planned">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-created" class="control-label">Creation date</label>
<input type="text" disabled class="form-control" id="task-created" placeholder="Created" [(ngModel)]="task.created"
<input type="text" disabled class="form-control" id="task-created" placeholder="Created" [value]="task.created | dateTimeZone"
name="task.created">
</div>
<div *ngIf="task.taskId" class="form-group">
@ -42,4 +42,4 @@
name="task.transferred">
</div>
</div>
</ng-container>
</ng-container>

View File

@ -131,29 +131,6 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.router.navigate(['./'], {relativeTo: this.route.parent});
}
private applyTaskDatesTimeZone(task: Task): Task {
if (task.due) {
task.due = TaskanaDate.applyTimeZone(task.due);
}
if (task.modified) {
task.modified = TaskanaDate.applyTimeZone(task.modified);
}
if (task.completed) {
task.completed = TaskanaDate.applyTimeZone(task.completed);
}
if (task.planned) {
task.planned = TaskanaDate.applyTimeZone(task.planned);
}
if (task.claimed) {
task.claimed = TaskanaDate.applyTimeZone(task.claimed);
}
if (task.created) {
task.created = TaskanaDate.applyTimeZone(task.created);
}
return task;
}
private onSave() {
this.currentId === 'new-task' ? this.createTask() : this.updateTask();
}
@ -199,8 +176,6 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.taskClone.customAttributes = this.task.customAttributes.slice(0);
this.taskClone.callbackInfo = this.task.callbackInfo.slice(0);
this.taskClone.primaryObjRef = {...this.task.primaryObjRef};
this.taskClone = this.applyTaskDatesTimeZone(this.taskClone);
}
ngOnDestroy(): void {

View File

@ -21,7 +21,7 @@
<dd data-toggle="tooltip" title="{{task.state}}">{{task.state}}</dd>
</dl>
<dl class="pull-right padding-right">
<i data-toggle="tooltip" title="{{task.due}}">Due: {{displayDate(task.due)}}</i>
<i data-toggle="tooltip" title="{{task.due}}">Due: {{task.due | dateTimeZone}}</i>
</dl>
</div>
@ -33,4 +33,4 @@
<h3 class="grey">Select a workbasket</h3>
<svg-icon class="img-responsive empty-icon workbasket-icon" src="./assets/icons/wb-empty.svg"></svg-icon>
</div>
</ng-template>
</ng-template>

View File

@ -8,6 +8,8 @@ import { Routes } from '@angular/router';
import { Component, ChangeDetectorRef } from '@angular/core';
import { WorkplaceService } from 'app/workplace/services/workplace.service';
import { SvgIconComponent, SvgIconRegistryService } from 'angular-svg-icon';
import {DateTimeZonePipe} from '../../../shared/pipes/date-time-zone/date-time-zone.pipe';
@Component({
selector: 'taskana-dummy-detail',
@ -30,7 +32,12 @@ describe('TaskListComponent', () => {
FormsModule,
RouterTestingModule.withRoutes(routes),
HttpClientModule],
declarations: [TaskListComponent, DummyDetailComponent, SvgIconComponent],
declarations: [
TaskListComponent,
DummyDetailComponent,
SvgIconComponent,
DateTimeZonePipe
],
providers: [
WorkplaceService,
ChangeDetectorRef,

View File

@ -2,20 +2,17 @@ import {
Component, OnInit, Input, ChangeDetectionStrategy, Output,
EventEmitter, SimpleChanges, OnChanges, ChangeDetectorRef
} from '@angular/core';
import { Task } from 'app/workplace/models/task';
import { TaskanaDate } from 'app/shared/util/taskana.date';
import { WorkplaceService } from 'app/workplace/services/workplace.service';
import { Router, ActivatedRoute } from '@angular/router';
import {Task} from 'app/workplace/models/task';
import {TaskanaDate} from 'app/shared/util/taskana.date';
import {WorkplaceService} from 'app/workplace/services/workplace.service';
import {Router, ActivatedRoute} from '@angular/router';
@Component({
selector: 'taskana-task-list',
templateUrl: './task-list.component.html',
styleUrls: ['./task-list.component.scss'],
// This is used to avoid angular detect changes automatically since displayDate is bein executed on every onChange.
// this cause a low performance in the screen.
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TaskListComponent implements OnInit, OnChanges {
export class TaskListComponent implements OnInit {
@Input()
tasks: Array<Task>;
@ -25,28 +22,18 @@ export class TaskListComponent implements OnInit, OnChanges {
selectedIdChange = new EventEmitter<string>();
constructor(private router: Router,
private route: ActivatedRoute,
private workplaceService: WorkplaceService,
private changeDetector: ChangeDetectorRef) { }
ngOnInit() {
private route: ActivatedRoute,
private workplaceService: WorkplaceService) {
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.tasks || changes.selectedId) {
this.changeDetector.detectChanges();
}
ngOnInit() {
}
selectTask(taskId: string) {
this.workplaceService.selectObjectReference(undefined);
this.selectedId = taskId;
this.selectedIdChange.emit(taskId);
this.router.navigate([{ outlets: { detail: `taskdetail/${this.selectedId}` } }], { relativeTo: this.route });
}
displayDate(date: string): string {
return TaskanaDate.getDateToDisplay(date);
this.router.navigate([{outlets: {detail: `taskdetail/${this.selectedId}`}}], {relativeTo: this.route});
}
}

View File

@ -88,6 +88,13 @@
}
}
.dark-green{
color: $dark-green;
& svg {
fill: $dark-green;
}
}
.grey {
color:$grey;
& svg {
@ -320,8 +327,8 @@ taskana-task-details, taskana-classification-details, taskana-access-items-manag
}
taskana-task-query {
& .panel{
&> .panel-body {
& .panel{
&> .panel-body {
height: calc(100vh - 105px);
max-height: calc(100vh - 105px);
}