Merge pull request #2715 from JaySoni1/WEB-185-made-on-date-and-checked-on-date-should-show-full-datetime-with-timezone-information-or-explicitly-convert-the-epoch-time-to-utc

WEB-185-made-on-date-and-checked-on-date-should-show-full-datetime-with-timezone-information-or-explicitly-convert-the-epoch-time-to-utc
This commit is contained in:
Gopi Kishan
2025-10-23 16:58:20 +05:30
committed by GitHub
6 changed files with 196 additions and 68 deletions
+25 -18
View File
@@ -1,25 +1,32 @@
import { Pipe, PipeTransform } from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
import { SettingsService } from 'app/settings/settings.service'; import moment, { Moment } from 'moment';
import moment from 'moment';
@Pipe({ name: 'datetimeFormat' }) @Pipe({ name: 'datetimeFormat', standalone: true })
export class DatetimeFormatPipe implements PipeTransform { export class DatetimeFormatPipe implements PipeTransform {
constructor(private settingsService: SettingsService) {} transform(value: unknown, datetimeFormat?: string): string {
if (value == null || value === '') return '';
transform(value: any, datetimeFormat?: string): any { let dateVal: Moment;
const defaultDateFormat = this.settingsService.dateFormat.replace('dd', 'DD'); if (Array.isArray(value)) {
if (typeof value === 'undefined') { const [
return ''; y,
} m,
let dateVal; d,
if (value instanceof Array) { hh,
dateVal = moment(value.join('-'), 'YYYY-MM-DD HH:mm:ss'); mm,
ss
] = value as number[];
if (hh != null) {
dateVal = moment({ year: y, month: (m ?? 1) - 1, date: d, hour: hh, minute: mm ?? 0, second: ss ?? 0 });
} else {
dateVal = moment({ year: y, month: (m ?? 1) - 1, date: d });
}
} else if (typeof value === 'number' && value < 1e12) {
// epoch seconds
dateVal = moment.unix(value);
} else { } else {
dateVal = moment(value); dateVal = moment(value as any);
} }
if (datetimeFormat == null) { const fmt = datetimeFormat ?? 'YYYY-MM-DDTHH:mm:ssZ';
return dateVal.format(defaultDateFormat + ' HH:mm:ss'); return dateVal.format(fmt);
}
return dateVal.format(datetimeFormat);
} }
} }
@@ -5,7 +5,7 @@
</button> </button>
</div> </div>
<div class="container layout-row-wrap gap-2px responsive-column"> <div class="container layout-row-wrap gap-8px responsive-column">
<mat-form-field class="flex-48"> <mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Resource ID' | translate }}</mat-label> <mat-label>{{ 'labels.inputs.Resource ID' | translate }}</mat-label>
<input matInput [formControl]="resourceId" /> <input matInput [formControl]="resourceId" />
@@ -43,45 +43,89 @@
<input matInput [formControl]="checker" [matAutocomplete]="checkerAutocomplete" /> <input matInput [formControl]="checker" [matAutocomplete]="checkerAutocomplete" />
</mat-form-field> </mat-form-field>
<mat-form-field class="flex-48" (click)="fromDatePicker.open()"> <div class="flex-48 layout-row-wrap gap-8px">
<mat-label>{{ 'labels.inputs.Maker From Date' | translate }}</mat-label> <mat-form-field class="flex-60" (click)="fromDatePicker.open()">
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="fromDatePicker" [formControl]="fromDate" /> <mat-label>{{ 'labels.inputs.Maker From Date' | translate }}</mat-label>
<mat-datepicker-toggle matSuffix [for]="fromDatePicker"></mat-datepicker-toggle> <input
<mat-datepicker #fromDatePicker></mat-datepicker> matInput
</mat-form-field> [min]="minDate"
[max]="maxDate"
[matDatepicker]="fromDatePicker"
[formControl]="fromDate"
placeholder="YYYY-MM-DD"
/>
<mat-datepicker-toggle matSuffix [for]="fromDatePicker"></mat-datepicker-toggle>
<mat-datepicker #fromDatePicker></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-48" (click)="toDatePicker.open()"> <mat-form-field class="flex-38">
<mat-label>{{ 'labels.inputs.Maker To Date' | translate }}</mat-label> <mat-label>{{ 'labels.inputs.Time' | translate }}</mat-label>
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="toDatePicker" [formControl]="toDate" /> <input matInput type="time" step="1" [formControl]="fromTime" placeholder="HH:MM:SS" class="time-input" />
<mat-datepicker-toggle matSuffix [for]="toDatePicker"></mat-datepicker-toggle> </mat-form-field>
<mat-datepicker #toDatePicker></mat-datepicker> </div>
</mat-form-field>
<mat-form-field class="flex-48" (click)="checkedFromDatePicker.open()"> <div class="flex-48 layout-row-wrap gap-8px">
<mat-label>{{ 'labels.inputs.Checker From Date' | translate }}</mat-label> <mat-form-field class="flex-60" (click)="toDatePicker.open()">
<input <mat-label>{{ 'labels.inputs.Maker To Date' | translate }}</mat-label>
matInput <input
[min]="minDate" matInput
[max]="maxDate" [min]="minDate"
[matDatepicker]="checkedFromDatePicker" [max]="maxDate"
[formControl]="checkedFromDate" [matDatepicker]="toDatePicker"
/> [formControl]="toDate"
<mat-datepicker-toggle matSuffix [for]="checkedFromDatePicker"></mat-datepicker-toggle> placeholder="YYYY-MM-DD"
<mat-datepicker #checkedFromDatePicker></mat-datepicker> />
</mat-form-field> <mat-datepicker-toggle matSuffix [for]="toDatePicker"></mat-datepicker-toggle>
<mat-datepicker #toDatePicker></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-48" (click)="checkedToDatePicker.open()"> <mat-form-field class="flex-38">
<mat-label>{{ 'labels.inputs.Checked To Date' | translate }}</mat-label> <mat-label>{{ 'labels.inputs.Time' | translate }}</mat-label>
<input <input matInput type="time" step="1" [formControl]="toTime" placeholder="HH:MM:SS" class="time-input" />
matInput </mat-form-field>
[min]="minDate" </div>
[max]="maxDate"
[matDatepicker]="checkedToDatePicker" <div class="flex-48 layout-row-wrap gap-8px">
[formControl]="checkedToDate" <mat-form-field class="flex-60" (click)="checkedFromDatePicker.open()">
/> <mat-label>{{ 'labels.inputs.Checker From Date' | translate }}</mat-label>
<mat-datepicker-toggle matSuffix [for]="checkedToDatePicker"></mat-datepicker-toggle> <input
<mat-datepicker #checkedToDatePicker></mat-datepicker> matInput
</mat-form-field> [min]="minDate"
[max]="maxDate"
[matDatepicker]="checkedFromDatePicker"
[formControl]="checkedFromDate"
placeholder="YYYY-MM-DD"
/>
<mat-datepicker-toggle matSuffix [for]="checkedFromDatePicker"></mat-datepicker-toggle>
<mat-datepicker #checkedFromDatePicker></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-38">
<mat-label>{{ 'labels.inputs.Time' | translate }}</mat-label>
<input matInput type="time" step="1" [formControl]="checkedFromTime" placeholder="HH:MM:SS" class="time-input" />
</mat-form-field>
</div>
<div class="flex-48 layout-row-wrap gap-8px">
<mat-form-field class="flex-60" (click)="checkedToDatePicker.open()">
<mat-label>{{ 'labels.inputs.Checked To Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="checkedToDatePicker"
[formControl]="checkedToDate"
placeholder="YYYY-MM-DD"
/>
<mat-datepicker-toggle matSuffix [for]="checkedToDatePicker"></mat-datepicker-toggle>
<mat-datepicker #checkedToDatePicker></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-38">
<mat-label>{{ 'labels.inputs.Time' | translate }}</mat-label>
<input matInput type="time" step="1" [formControl]="checkedToTime" placeholder="HH:MM:SS" class="time-input" />
</mat-form-field>
</div>
</div> </div>
<!-- Autocomplete data --> <!-- Autocomplete data -->
@@ -151,7 +195,7 @@
<ng-container matColumnDef="madeOnDate"> <ng-container matColumnDef="madeOnDate">
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Made Date' | translate }}</th> <th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Made Date' | translate }}</th>
<td mat-cell *matCellDef="let auditTrail">{{ auditTrail.madeOnDate | dateFormat }}</td> <td mat-cell *matCellDef="let auditTrail">{{ auditTrail.madeOnDate | datetimeFormat }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="checker"> <ng-container matColumnDef="checker">
@@ -161,7 +205,7 @@
<ng-container matColumnDef="checkedOnDate"> <ng-container matColumnDef="checkedOnDate">
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Checked Date' | translate }}</th> <th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Checked Date' | translate }}</th>
<td mat-cell *matCellDef="let auditTrail">{{ auditTrail.checkedOnDate | dateFormat }}</td> <td mat-cell *matCellDef="let auditTrail">{{ auditTrail.checkedOnDate | datetimeFormat }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="clientIp"> <ng-container matColumnDef="clientIp">
@@ -5,3 +5,14 @@ table {
cursor: pointer; cursor: pointer;
} }
} }
.flex-38 {
.time-input {
font-size: 14px;
width: 100%;
}
}
.gap-8px {
gap: 8px;
}
@@ -32,7 +32,7 @@ import {
MatRowDef, MatRowDef,
MatRow MatRow
} from '@angular/material/table'; } from '@angular/material/table';
import { DateFormatPipe } from '../../pipes/date-format.pipe'; import { DatetimeFormatPipe } from '../../pipes/datetime-format.pipe';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/** /**
@@ -62,7 +62,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
MatRow, MatRow,
MatPaginator, MatPaginator,
AsyncPipe, AsyncPipe,
DateFormatPipe DatetimeFormatPipe
] ]
}) })
export class AuditTrailsComponent implements OnInit, AfterViewInit { export class AuditTrailsComponent implements OnInit, AfterViewInit {
@@ -153,8 +153,12 @@ export class AuditTrailsComponent implements OnInit, AfterViewInit {
user = new UntypedFormControl(''); user = new UntypedFormControl('');
/** From date form control. */ /** From date form control. */
fromDate = new UntypedFormControl(); fromDate = new UntypedFormControl();
/** From time form control. */
fromTime = new UntypedFormControl();
/** Checked from date form control. */ /** Checked from date form control. */
checkedFromDate = new UntypedFormControl(); checkedFromDate = new UntypedFormControl();
/** Checked from time form control. */
checkedFromTime = new UntypedFormControl();
/** Processing result form control. */ /** Processing result form control. */
processingResult = new UntypedFormControl(); processingResult = new UntypedFormControl();
/** Action name form control. */ /** Action name form control. */
@@ -163,8 +167,12 @@ export class AuditTrailsComponent implements OnInit, AfterViewInit {
resourceId = new UntypedFormControl(''); resourceId = new UntypedFormControl('');
/** To date form control. */ /** To date form control. */
toDate = new UntypedFormControl(); toDate = new UntypedFormControl();
/** To time form control. */
toTime = new UntypedFormControl();
/** Checked to date form control. */ /** Checked to date form control. */
checkedToDate = new UntypedFormControl(); checkedToDate = new UntypedFormControl();
/** Checked to time form control. */
checkedToTime = new UntypedFormControl();
/** Entity name form control. */ /** Entity name form control. */
entityName = new UntypedFormControl(); entityName = new UntypedFormControl();
/** Checker form control. */ /** Checker form control. */
@@ -230,7 +238,17 @@ export class AuditTrailsComponent implements OnInit, AfterViewInit {
debounceTime(500), debounceTime(500),
distinctUntilChanged(), distinctUntilChanged(),
tap((filterValue) => { tap((filterValue) => {
this.applyFilter(this.getDate(filterValue), 'makerDateTimeFrom'); this.applyFilter(this.getDateTime(filterValue, this.fromTime.value), 'makerDateTimeFrom');
})
)
.subscribe();
this.fromTime.valueChanges
.pipe(
debounceTime(500),
distinctUntilChanged(),
tap((timeValue) => {
this.applyFilter(this.getDateTime(this.fromDate.value, timeValue), 'makerDateTimeFrom');
}) })
) )
.subscribe(); .subscribe();
@@ -240,7 +258,17 @@ export class AuditTrailsComponent implements OnInit, AfterViewInit {
debounceTime(500), debounceTime(500),
distinctUntilChanged(), distinctUntilChanged(),
tap((filterValue) => { tap((filterValue) => {
this.applyFilter(this.getDate(filterValue), 'makerDateTimeTo'); this.applyFilter(this.getDateTime(filterValue, this.toTime.value), 'makerDateTimeTo');
})
)
.subscribe();
this.toTime.valueChanges
.pipe(
debounceTime(500),
distinctUntilChanged(),
tap((timeValue) => {
this.applyFilter(this.getDateTime(this.toDate.value, timeValue), 'makerDateTimeTo');
}) })
) )
.subscribe(); .subscribe();
@@ -250,7 +278,17 @@ export class AuditTrailsComponent implements OnInit, AfterViewInit {
debounceTime(500), debounceTime(500),
distinctUntilChanged(), distinctUntilChanged(),
tap((filterValue) => { tap((filterValue) => {
this.applyFilter(this.getDate(filterValue), 'checkerDateTimeFrom'); this.applyFilter(this.getDateTime(filterValue, this.checkedFromTime.value), 'checkerDateTimeFrom');
})
)
.subscribe();
this.checkedFromTime.valueChanges
.pipe(
debounceTime(500),
distinctUntilChanged(),
tap((timeValue) => {
this.applyFilter(this.getDateTime(this.checkedFromDate.value, timeValue), 'checkerDateTimeFrom');
}) })
) )
.subscribe(); .subscribe();
@@ -260,7 +298,17 @@ export class AuditTrailsComponent implements OnInit, AfterViewInit {
debounceTime(500), debounceTime(500),
distinctUntilChanged(), distinctUntilChanged(),
tap((filterValue) => { tap((filterValue) => {
this.applyFilter(this.getDate(filterValue), 'checkerDateTimeTo'); this.applyFilter(this.getDateTime(filterValue, this.checkedToTime.value), 'checkerDateTimeTo');
})
)
.subscribe();
this.checkedToTime.valueChanges
.pipe(
debounceTime(500),
distinctUntilChanged(),
tap((timeValue) => {
this.applyFilter(this.getDateTime(this.checkedToDate.value, timeValue), 'checkerDateTimeTo');
}) })
) )
.subscribe(); .subscribe();
@@ -502,8 +550,9 @@ export class AuditTrailsComponent implements OnInit, AfterViewInit {
let csv = response.pageItems.map((row: any) => let csv = response.pageItems.map((row: any) =>
headerCode.map((fieldName) => headerCode.map((fieldName) =>
(fieldName === 'madeOnDate' || fieldName === 'checkedOnDate') && (fieldName === 'madeOnDate' || fieldName === 'checkedOnDate') &&
JSON.stringify(row[fieldName], replacer) !== '""' row[fieldName] != null &&
? this.dateUtils.formatDate(JSON.stringify(row[fieldName], replacer), dateFormat) row[fieldName] !== ''
? JSON.stringify(this.dateUtils.formatDate(row[fieldName], 'YYYY-MM-DDTHH:mm:ssZ'))
: JSON.stringify(row[fieldName], replacer) : JSON.stringify(row[fieldName], replacer)
) )
); );
@@ -530,4 +579,21 @@ export class AuditTrailsComponent implements OnInit, AfterViewInit {
const dateFormat = this.settingsService.dateFormat; const dateFormat = this.settingsService.dateFormat;
return this.dateUtils.formatDate(timestamp, dateFormat); return this.dateUtils.formatDate(timestamp, dateFormat);
} }
private getDateTime(date: Date, timeStr: string): string {
if (!date) {
return '';
}
const result = new Date(date);
if (timeStr) {
const [
hours,
minutes,
seconds
] = timeStr.split(':').map(Number);
result.setHours(hours || 0);
result.setMinutes(minutes || 0);
result.setSeconds(seconds || 0);
}
return this.dateUtils.formatDate(result, 'YYYY-MM-DDTHH:mm:ssZ');
}
} }
@@ -57,7 +57,7 @@
</div> </div>
<div class="flex-50"> <div class="flex-50">
{{ auditTrailData.madeOnDate | dateFormat }} {{ auditTrailData.madeOnDate | datetimeFormat }}
</div> </div>
<div class="flex-50 mat-body-strong" *ngIf="auditTrailData.officeName"> <div class="flex-50 mat-body-strong" *ngIf="auditTrailData.officeName">
@@ -16,7 +16,7 @@ import {
MatRowDef, MatRowDef,
MatRow MatRow
} from '@angular/material/table'; } from '@angular/material/table';
import { DateFormatPipe } from '../../../pipes/date-format.pipe'; import { DatetimeFormatPipe } from '../../../pipes/datetime-format.pipe';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/** /**
@@ -40,7 +40,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
MatHeaderRow, MatHeaderRow,
MatRowDef, MatRowDef,
MatRow, MatRow,
DateFormatPipe DatetimeFormatPipe
] ]
}) })
export class ViewAuditComponent implements OnInit { export class ViewAuditComponent implements OnInit {