Browse Source

Performance (#501)

* Performance improvements.

* Date improvements.
pull/502/head
Sebastian Stehle 6 years ago
committed by GitHub
parent
commit
ac6a49d9b1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs
  2. 19
      backend/src/Squidex.Infrastructure/Json/Newtonsoft/DateConverter.cs
  3. 5
      backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/CallsUsagePerDateDto.cs
  4. 3
      backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/StorageUsagePerDateDto.cs
  5. 1
      backend/src/Squidex/Squidex.csproj
  6. 5
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/TestData/FakeUrlGenerator.cs
  7. 1
      frontend/app-config/webpack.config.js
  8. 9
      frontend/app/features/dashboard/pages/dashboard-page.component.ts
  9. 2
      frontend/app/framework/angular/forms/editors/date-time-editor.component.scss
  10. 90
      frontend/app/framework/angular/forms/editors/date-time-editor.component.ts
  11. 2
      frontend/app/framework/angular/forms/validators.ts
  12. 7
      frontend/app/framework/angular/image-source.directive.ts
  13. 6
      frontend/app/framework/angular/pipes/date-time.pipes.spec.ts
  14. 12
      frontend/app/framework/angular/pipes/date-time.pipes.ts
  15. 23
      frontend/app/framework/utils/date-helper.spec.ts
  16. 20
      frontend/app/framework/utils/date-helper.ts
  17. 151
      frontend/app/framework/utils/date-time.spec.ts
  18. 152
      frontend/app/framework/utils/date-time.ts
  19. 18
      frontend/app/framework/utils/duration.ts
  20. 8
      frontend/app/framework/utils/string-helper.ts
  21. 6
      frontend/app/shared/components/assets/asset.component.html
  22. 19
      frontend/app/shared/components/assets/asset.component.scss
  23. 8
      frontend/app/shared/services/apps.service.spec.ts
  24. 4
      frontend/app/shared/services/apps.service.ts
  25. 8
      frontend/app/shared/services/assets.service.spec.ts
  26. 4
      frontend/app/shared/services/assets.service.ts
  27. 12
      frontend/app/shared/services/backups.service.spec.ts
  28. 8
      frontend/app/shared/services/backups.service.ts
  29. 6
      frontend/app/shared/services/comments.service.spec.ts
  30. 6
      frontend/app/shared/services/comments.service.ts
  31. 12
      frontend/app/shared/services/contents.service.spec.ts
  32. 6
      frontend/app/shared/services/contents.service.ts
  33. 4
      frontend/app/shared/services/history.service.spec.ts
  34. 2
      frontend/app/shared/services/history.service.ts
  35. 14
      frontend/app/shared/services/rules.service.spec.ts
  36. 10
      frontend/app/shared/services/rules.service.ts
  37. 16
      frontend/app/shared/services/schemas.service.spec.ts
  38. 8
      frontend/app/shared/services/schemas.service.ts
  39. 12
      frontend/app/shared/services/usages.service.spec.ts
  40. 12
      frontend/app/shared/services/usages.service.ts
  41. 8
      frontend/app/shared/state/contents.forms.spec.ts
  42. 10
      frontend/app/shared/state/contents.forms.ts
  43. 11
      frontend/package-lock.json
  44. 2
      frontend/package.json

10
backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs

@ -209,16 +209,6 @@ namespace Squidex.Domain.Apps.Core.HandleRules
return null; return null;
} }
private static string? ContentStatus(EnrichedEvent @event)
{
if (@event is EnrichedContentEvent contentEvent)
{
return contentEvent.Status.ToString();
}
return null;
}
private string? AssetContentUrl(EnrichedEvent @event) private string? AssetContentUrl(EnrichedEvent @event)
{ {
if (@event is EnrichedAssetEvent assetEvent) if (@event is EnrichedAssetEvent assetEvent)

19
backend/src/Squidex.Infrastructure/Json/Newtonsoft/DateConverter.cs

@ -0,0 +1,19 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Newtonsoft.Json.Converters;
namespace Squidex.Infrastructure.Json.Newtonsoft
{
public sealed class DateConverter : IsoDateTimeConverter
{
public DateConverter()
{
DateTimeFormat = "yyyy-MM-dd";
}
}
}

5
backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/CallsUsagePerDateDto.cs

@ -6,6 +6,8 @@
// ========================================================================== // ==========================================================================
using System; using System;
using Newtonsoft.Json;
using Squidex.Infrastructure.Json.Newtonsoft;
using Squidex.Infrastructure.UsageTracking; using Squidex.Infrastructure.UsageTracking;
namespace Squidex.Areas.Api.Controllers.Statistics.Models namespace Squidex.Areas.Api.Controllers.Statistics.Models
@ -15,6 +17,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics.Models
/// <summary> /// <summary>
/// The date when the usage was tracked. /// The date when the usage was tracked.
/// </summary> /// </summary>
[JsonConverter(typeof(DateConverter))]
public DateTime Date { get; set; } public DateTime Date { get; set; }
/// <summary> /// <summary>
@ -36,7 +39,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics.Models
{ {
var result = new CallsUsagePerDateDto var result = new CallsUsagePerDateDto
{ {
Date = stats.Date, Date = DateTime.SpecifyKind(stats.Date, DateTimeKind.Utc),
TotalBytes = stats.TotalBytes, TotalBytes = stats.TotalBytes,
TotalCalls = stats.TotalCalls, TotalCalls = stats.TotalCalls,
AverageElapsedMs = stats.AverageElapsedMs, AverageElapsedMs = stats.AverageElapsedMs,

3
backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/StorageUsagePerDateDto.cs

@ -6,7 +6,9 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Text.Json.Serialization;
using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Infrastructure.Json.Newtonsoft;
namespace Squidex.Areas.Api.Controllers.Statistics.Models namespace Squidex.Areas.Api.Controllers.Statistics.Models
{ {
@ -15,6 +17,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics.Models
/// <summary> /// <summary>
/// The date when the usage was tracked. /// The date when the usage was tracked.
/// </summary> /// </summary>
[JsonConverter(typeof(DateConverter))]
public DateTime Date { get; set; } public DateTime Date { get; set; }
/// <summary> /// <summary>

1
backend/src/Squidex/Squidex.csproj

@ -50,6 +50,7 @@
<PackageReference Include="Microsoft.Orleans.OrleansRuntime" Version="3.1.2" /> <PackageReference Include="Microsoft.Orleans.OrleansRuntime" Version="3.1.2" />
<PackageReference Include="MongoDB.Driver" Version="2.10.2" /> <PackageReference Include="MongoDB.Driver" Version="2.10.2" />
<PackageReference Include="Namotion.Reflection" Version="1.0.10" /> <PackageReference Include="Namotion.Reflection" Version="1.0.10" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NJsonSchema" Version="10.1.5" /> <PackageReference Include="NJsonSchema" Version="10.1.5" />
<PackageReference Include="NSwag.AspNetCore" Version="13.2.3" /> <PackageReference Include="NSwag.AspNetCore" Version="13.2.3" />
<PackageReference Include="OpenCover" Version="4.7.922" PrivateAssets="all" /> <PackageReference Include="OpenCover" Version="4.7.922" PrivateAssets="all" />

5
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/TestData/FakeUrlGenerator.cs

@ -51,11 +51,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.TestData
throw new NotSupportedException(); throw new NotSupportedException();
} }
public string AssetSource(Guid assetId)
{
throw new NotSupportedException();
}
public string BackupsUI(NamedId<Guid> appId) public string BackupsUI(NamedId<Guid> appId)
{ {
throw new NotSupportedException(); throw new NotSupportedException();

1
frontend/app-config/webpack.config.js

@ -169,7 +169,6 @@ module.exports = function (env) {
plugins: [ plugins: [
new webpack.ContextReplacementPlugin(/\@angular(\\|\/)core(\\|\/)fesm5/, root('./app'), {}), new webpack.ContextReplacementPlugin(/\@angular(\\|\/)core(\\|\/)fesm5/, root('./app'), {}),
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en/),
/** /**
* Puts each bundle into a file and appends the hash of the file to the path. * Puts each bundle into a file and appends the hash of the file to the path.

9
frontend/app/features/dashboard/pages/dashboard-page.component.ts

@ -135,9 +135,12 @@ export class DashboardPageComponent extends ResourceOwner implements OnInit {
this.history = dto; this.history = dto;
})); }));
const dateTo = DateTime.today().toStringFormat('yyyy-MM-dd');
const dateFrom = DateTime.today().addDays(-20).toStringFormat('yyyy-MM-dd');
this.own( this.own(
this.appsState.selectedApp.pipe( this.appsState.selectedApp.pipe(
switchMap(app => this.usagesService.getStorageUsages(app.name, DateTime.today().addDays(-20), DateTime.today()))) switchMap(app => this.usagesService.getStorageUsages(app.name, dateFrom, dateTo)))
.subscribe(dtos => { .subscribe(dtos => {
const labels = createLabels(dtos); const labels = createLabels(dtos);
@ -174,7 +177,7 @@ export class DashboardPageComponent extends ResourceOwner implements OnInit {
this.own( this.own(
this.appsState.selectedApp.pipe( this.appsState.selectedApp.pipe(
switchMap(app => this.usagesService.getCallsUsages(app.name, DateTime.today().addDays(-20), DateTime.today()))) switchMap(app => this.usagesService.getCallsUsages(app.name, dateFrom, dateTo)))
.subscribe(({ details, totalBytes, totalCalls, allowedCalls, averageElapsedMs }) => { .subscribe(({ details, totalBytes, totalCalls, allowedCalls, averageElapsedMs }) => {
const labels = createLabelsFromSet(details); const labels = createLabelsFromSet(details);
@ -234,7 +237,7 @@ function label(category: string) {
} }
function createLabels(dtos: ReadonlyArray<{ date: DateTime }>): ReadonlyArray<string> { function createLabels(dtos: ReadonlyArray<{ date: DateTime }>): ReadonlyArray<string> {
return dtos.map(d => d.date.toStringFormat('M-DD')); return dtos.map(d => d.date.toStringFormat('M-dd'));
} }
function createLabelsFromSet(dtos: { [category: string]: ReadonlyArray<{ date: DateTime }> }): ReadonlyArray<string> { function createLabelsFromSet(dtos: { [category: string]: ReadonlyArray<{ date: DateTime }> }): ReadonlyArray<string> {

2
frontend/app/framework/angular/forms/editors/date-time-editor.component.scss

@ -26,7 +26,7 @@
} }
.form-date { .form-date {
width: 7rem; width: 8.5rem;
} }
.form-date-only { .form-date-only {

90
frontend/app/framework/angular/forms/editors/date-time-editor.component.ts

@ -7,11 +7,11 @@
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
import { FormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; import { FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import moment from 'moment';
import { import {
DateHelper,
DateTime,
StatefulControlComponent, StatefulControlComponent,
Types,
UIOptions UIOptions
} from '@app/framework/internal'; } from '@app/framework/internal';
@ -38,8 +38,7 @@ const NO_EMIT = { emitEvent: false };
}) })
export class DateTimeEditorComponent extends StatefulControlComponent<{}, string | null> implements OnInit, AfterViewInit, FocusComponent { export class DateTimeEditorComponent extends StatefulControlComponent<{}, string | null> implements OnInit, AfterViewInit, FocusComponent {
private picker: any; private picker: any;
private timeValue: moment.Moment | null = null; private dateTime: DateTime | null;
private dateValue: moment.Moment | null = null;
private hideDateButtonsSettings: boolean; private hideDateButtonsSettings: boolean;
private suppressEvents = false; private suppressEvents = false;
@ -70,7 +69,7 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
} }
public get hasValue() { public get hasValue() {
return !!this.dateValue; return !!this.dateTime;
} }
constructor(changeDetector: ChangeDetectorRef, uiOptions: UIOptions) { constructor(changeDetector: ChangeDetectorRef, uiOptions: UIOptions) {
@ -81,40 +80,21 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
public ngOnInit() { public ngOnInit() {
this.own( this.own(
this.timeControl.valueChanges.subscribe(value => { this.timeControl.valueChanges.subscribe(() => {
if (!value || value.length === 0) {
this.timeValue = null;
} else {
this.timeValue = moment.utc(value, 'HH:mm:ss');
}
this.callChangeFormatted(); this.callChangeFormatted();
})); }));
this.own( this.own(
this.dateControl.valueChanges.subscribe(value => { this.dateControl.valueChanges.subscribe(() => {
if (!value || value.length === 0) {
this.dateValue = null;
} else {
this.dateValue = moment.utc(value, 'YYYY-MM-DD');
}
this.callChangeFormatted(); this.callChangeFormatted();
})); }));
} }
public writeValue(obj: any) { public writeValue(obj: any) {
if (Types.isString(obj) && obj.length > 0) { try {
const parsed = moment.parseZone(obj); this.dateTime = DateTime.parseISO(obj);
} catch (ex) {
this.dateValue = parsed; this.dateTime = null;
if (this.showTime) {
this.timeValue = parsed;
}
} else {
this.timeValue = null;
this.dateValue = null;
} }
this.updateControls(); this.updateControls();
@ -142,9 +122,9 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
if (this.suppressEvents) { if (this.suppressEvents) {
return; return;
} }
this.dateValue = this.picker.getMoment();
this.callChangeFormatted(); this.dateControl.setValue(this.picker.toString('YYYY-MM-DD'));
this.callTouched(); this.callTouched();
} }
}); });
@ -153,7 +133,7 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
} }
public writeNow() { public writeNow() {
this.writeValue(new Date().toUTCString()); this.writeValue(DateTime.now().toISOString());
this.updateControls(); this.updateControls();
this.callChangeFormatted(); this.callChangeFormatted();
@ -163,10 +143,9 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
} }
public reset() { public reset() {
this.timeControl.setValue(null, NO_EMIT); this.dateTime = null;
this.dateControl.setValue(null, NO_EMIT);
this.dateValue = null; this.updateControls();
this.callChange(null); this.callChange(null);
this.callTouched(); this.callTouched();
@ -179,22 +158,28 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
} }
private getValue(): string | null { private getValue(): string | null {
if (!this.dateValue || !this.dateValue.isValid()) { if (!this.dateControl.value) {
return null; return null;
} }
if (this.timeValue && !this.timeValue.isValid()) { let result: string | null = null;
return null;
if (this.showTime && this.timeControl.value) {
const combined = `${this.dateControl.value}T${this.timeControl.value}`;
const parsed = DateTime.tryParseISO(combined, true);
if (parsed) {
result = parsed.toISOString();
}
} }
let result = this.dateValue.format('YYYY-MM-DD'); if (!result) {
const parsed = DateTime.tryParseISO(this.dateControl.value, true);
if (this.showTime && this.timeValue) { if (parsed) {
result += 'T'; result = parsed.toISOString();
result += this.timeValue.format('HH:mm:ss'); }
result += 'Z';
} else if (this.enforceTime) {
result += 'T00:00:00Z';
} }
return result; return result;
@ -203,19 +188,18 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
private updateControls() { private updateControls() {
this.suppressEvents = true; this.suppressEvents = true;
if (this.timeValue && this.timeValue.isValid()) { if (this.dateTime && this.mode === 'DateTime') {
this.timeControl.setValue(this.timeValue.format('HH:mm:ss'), NO_EMIT); this.timeControl.setValue(this.dateTime.toStringFormatUTC('HH:mm:ss'), NO_EMIT);
} else { } else {
this.timeControl.setValue(null, NO_EMIT); this.timeControl.setValue(null, NO_EMIT);
} }
if (this.dateValue && this.dateValue.isValid() && this.picker) { if (this.dateTime && this.picker) {
const dateString = this.dateValue.format('YYYY-MM-DD'); const dateString = this.dateTime.toStringFormatUTC('yyyy-MM-dd');
const dateLocal = moment(dateString);
this.dateControl.setValue(dateString, NO_EMIT); this.picker.setDate(DateHelper.getUTCDate(this.dateTime.raw), true);
this.picker.setMoment(dateLocal); this.dateControl.setValue(dateString, NO_EMIT);
} else { } else {
this.dateControl.setValue(null, NO_EMIT); this.dateControl.setValue(null, NO_EMIT);
} }

2
frontend/app/framework/angular/forms/validators.ts

@ -66,7 +66,7 @@ export module ValidatorsEx {
if (v) { if (v) {
try { try {
DateTime.parseISO_UTC(v); DateTime.parseISO(v);
} catch (e) { } catch (e) {
return { validdatetime: false }; return { validdatetime: false };
} }

7
frontend/app/framework/angular/image-source.directive.ts

@ -8,6 +8,7 @@
import { AfterViewInit, Directive, ElementRef, Input, NgZone, OnChanges, OnDestroy, OnInit, Renderer2 } from '@angular/core'; import { AfterViewInit, Directive, ElementRef, Input, NgZone, OnChanges, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { MathHelper, ResourceOwner } from '@app/framework/internal'; import { MathHelper, ResourceOwner } from '@app/framework/internal';
import { StringHelper } from '../utils/string-helper';
const LAYOUT_CACHE: { [key: string]: { width: number, height: number } } = {}; const LAYOUT_CACHE: { [key: string]: { width: number, height: number } } = {};
@ -122,10 +123,12 @@ export class ImageSourceDirective extends ResourceOwner implements OnChanges, On
const h = Math.round(this.size.height); const h = Math.round(this.size.height);
if (w > 0 && h > 0) { if (w > 0 && h > 0) {
let source = `${this.imageSource}&width=${w}&height=${h}&mode=Pad&nofocus`; let source = this.imageSource;
source = StringHelper.appendToUrl(source, `${this.imageSource}&width=${w}&height=${h}&mode=Pad&nofocus`);
if (this.loadQuery) { if (this.loadQuery) {
source += `&q=${this.loadQuery}`; source = StringHelper.appendToUrl(source, 'q', this.loadQuery);
} }
this.renderer.setProperty(this.element.nativeElement, 'src', source); this.renderer.setProperty(this.element.nativeElement, 'src', source);

6
frontend/app/framework/angular/pipes/date-time.pipes.spec.ts

@ -20,7 +20,7 @@ import {
ShortTimePipe ShortTimePipe
} from './date-time.pipes'; } from './date-time.pipes';
const dateTime = DateTime.parse('2013-10-03T12:13:14.125', DateTime.iso8601()); const dateTime = DateTime.parseISO('2013-10-03T12:13:14.125', false);
describe('DurationPipe', () => { describe('DurationPipe', () => {
it('should format to standard duration string', () => { it('should format to standard duration string', () => {
@ -86,7 +86,7 @@ describe('DayOfWeekPipe', () => {
const pipe = new DayOfWeekPipe(); const pipe = new DayOfWeekPipe();
const actual = pipe.transform(dateTime); const actual = pipe.transform(dateTime);
const expected = 'Th'; const expected = 'Thu';
expect(actual).toBe(expected); expect(actual).toBe(expected);
}); });
@ -124,7 +124,7 @@ describe('FullDateTimePipe', () => {
const pipe = new FullDateTimePipe(); const pipe = new FullDateTimePipe();
const actual = pipe.transform(dateTime); const actual = pipe.transform(dateTime);
const expected = 'October 3, 2013 12:13 PM'; const expected = 'Oct 3, 2013, 12:13:14 PM';
expect(actual).toBe(expected); expect(actual).toBe(expected);
}); });

12
frontend/app/framework/angular/pipes/date-time.pipes.ts

@ -19,7 +19,7 @@ export class ShortDatePipe implements PipeTransform {
return fallback; return fallback;
} }
return value.toStringFormat('DD. MMM'); return value.toStringFormat('dd. MMM');
} }
} }
@ -47,7 +47,7 @@ export class DatePipe implements PipeTransform {
return fallback; return fallback;
} }
return value.toStringFormat('DD. MMM YYYY'); return value.toStringFormat('dd. LLL yyyy');
} }
} }
@ -61,7 +61,7 @@ export class MonthPipe implements PipeTransform {
return fallback; return fallback;
} }
return value.toStringFormat('MMMM'); return value.toStringFormat('LLLL');
} }
} }
@ -89,7 +89,7 @@ export class DayOfWeekPipe implements PipeTransform {
return fallback; return fallback;
} }
return value.toStringFormat('dd'); return value.toStringFormat('E');
} }
} }
@ -103,7 +103,7 @@ export class DayPipe implements PipeTransform {
return fallback; return fallback;
} }
return value.toStringFormat('DD'); return value.toStringFormat('dd');
} }
} }
@ -131,7 +131,7 @@ export class FullDateTimePipe implements PipeTransform {
return fallback; return fallback;
} }
return value.toStringFormat('LLL'); return value.toStringFormat('PPpp');
} }
} }

23
frontend/app/framework/utils/date-helper.spec.ts

@ -5,27 +5,22 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import moment from 'moment';
import { DateHelper } from './date-helper'; import { DateHelper } from './date-helper';
describe('DateHelper', () => { describe('DateHelper', () => {
it('should call config method of moment object', () => { it('should use default locale if not configured', () => {
let called: string; DateHelper.setlocale(null);
DateHelper.setMoment({
locale: (l: string) => { called = l; }
});
DateHelper.locale('en'); const locale = DateHelper.getLocale();
expect(called!).toBe('en'); expect(locale).toBe('en');
}); });
it('should use global moment if not configured', () => { it('should use configured locale', () => {
DateHelper.setMoment(null); DateHelper.setlocale('it');
DateHelper.locale('en');
const locale = DateHelper.getLocale();
expect(moment.locale()).toBe('en'); expect(locale).toBe('it');
}); });
}); });

20
frontend/app/framework/utils/date-helper.ts

@ -5,16 +5,22 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import moment from 'moment';
export module DateHelper { export module DateHelper {
let momentInstance: any; let locale: string | null;
export function setlocale(code: string | null) {
locale = code;
}
export function getLocale() {
return locale || 'en';
}
export function setMoment(value: any) { export function getUTCDate(date: Date) {
momentInstance = value; return new Date(date.getTime() + date.getTimezoneOffset() * 60 * 1000);
} }
export function locale(code: string) { export function getLocalDate (date: Date) {
(momentInstance || moment).locale(code); return new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
} }
} }

151
frontend/app/framework/utils/date-time.spec.ts

@ -13,49 +13,39 @@ describe('DateTime', () => {
const now = DateTime.now(); const now = DateTime.now();
it('should parse from iso string', () => { it('should parse from iso string', () => {
const value = DateTime.parseISO('2013-10-16T12:13:14.125'); const actual = DateTime.parseISO('2013-10-16T12:13:14.125', false);
expect(value.year).toBe(2013); expect(actual.year).toBe(2013);
expect(value.month).toBe(10); expect(actual.month).toBe(10);
expect(value.day).toBe(16); expect(actual.day).toBe(16);
expect(value.hours).toBe(12); expect(actual.hours).toBe(12);
expect(value.minutes).toBe(13); expect(actual.minutes).toBe(13);
expect(value.seconds).toBe(14); expect(actual.seconds).toBe(14);
expect(value.milliseconds).toBe(125); expect(actual.milliseconds).toBe(125);
expect(value.weekDay).toBe(3); expect(actual.weekDay).toBe(3);
expect(value.raw).not.toBeNull(); expect(actual.raw).not.toBeNull();
}); });
it('should throw when date string to parse is null', () => { it('should throw when date string to parse is null', () => {
expect(() => DateTime.parseISO('#')).toThrow(); expect(() => DateTime.parseISO(null!)).toThrow();
}); });
it('should throw when date string to parse is invalid', () => { it('should throw when date string to parse is invalid', () => {
expect(() => DateTime.parse('#', 'yyyy-MM-dd')).toThrow(); expect(() => DateTime.parseISO('#')).toThrow();
});
it('should throw when utc date string to parse is invalid', () => {
expect(() => DateTime.parseUTC('#', 'yyyy-MM-dd')).toThrow();
}); });
it('should parse Microsoft date format', () => { it('should return null when date string to try parse is null', () => {
const actual = DateTime.parseMSDate('/Date(1224043200000)/'); expect(DateTime.tryParseISO(null!)).toBeNull();
const expected = DateTime.parseISO('2008-10-15T04:00:00');
expect(actual).toEqual(expected);
}); });
it('should parse Microsoft date format with positive offset', () => { it('should return null when date string to try parse is invalid', () => {
const actual = DateTime.parseMSDate('/Date(1224043200000+2)/'); expect(DateTime.tryParseISO(null!)).toBeNull();
const expected = DateTime.parseISO('2008-10-15T06:00:00');
expect(actual).toEqual(expected);
}); });
it('should parse Microsoft date format with negative offset', () => { it('should parse date from utc date', () => {
const actual = DateTime.parseMSDate('/Date(1224043200000-2)/'); const actual = DateTime.parseISO('2013-10-16');
const expected = DateTime.parseISO('2008-10-15T02:00:00'); const expected = DateTime.parseISO('2013-10-16T00:00:00Z');
expect(actual).toEqual(expected); expect(actual).toEqual(expected);
}); });
@ -82,19 +72,47 @@ describe('DateTime', () => {
}); });
it('should print to formatted string', () => { it('should print to formatted string', () => {
const value = DateTime.parseISO('2013-10-16T12:13:14'); const value = DateTime.parseISO('2013-10-16T12:13:14', false);
const expected = '12:13'; const expected = '12:13';
expect(value.toStringFormat('HH:mm')).toEqual(expected); expect(value.toStringFormat('HH:mm')).toEqual(expected);
}); });
it('should print to formatted ISO string', () => {
const value = DateTime.parseISO('2013-10-16T12:13:14.123Z');
const expected = '12:13';
expect(value.toStringFormatUTC('HH:mm')).toEqual(expected);
});
it('should print to iso string', () => { it('should print to iso string', () => {
const value = DateTime.parseISO_UTC('2013-10-16T12:13:14'); const value = DateTime.parseISO('2013-10-16T12:13:14.123Z');
const expected = '2013-10-16T12:13:14.000Z'; const expected = '2013-10-16T12:13:14Z';
expect(value.toISOString()).toEqual(expected); expect(value.toISOString()).toEqual(expected);
}); });
it('should print to iso string with milliseconds', () => {
const value = DateTime.parseISO('2013-10-16T12:13:14.123Z');
const expected = '2013-10-16T12:13:14.123Z';
expect(value.toISOString(false)).toEqual(expected);
});
it('should print to iso date', () => {
const value = DateTime.parseISO('2013-10-16T12:13:14Z');
const expected = '2013-10-16';
expect(value.toISODate()).toEqual(expected);
});
it('should print to iso utc date', () => {
const value = DateTime.parseISO('2013-10-16T12:13:14Z');
const expected = '2013-10-16';
expect(value.toISODate()).toEqual(expected);
});
it('should print to from now string', () => { it('should print to from now string', () => {
const value = DateTime.now().addMinutes(-4); const value = DateTime.now().addMinutes(-4);
const expected = '4 minutes ago'; const expected = '4 minutes ago';
@ -102,38 +120,65 @@ describe('DateTime', () => {
expect(value.toFromNow()).toBe(expected); expect(value.toFromNow()).toBe(expected);
}); });
it('should print from format with underscore', () => { it('should calculate valid first of week', () => {
const actual = DateTime.parseISO('2013-10-16T00:00:00'); const actual = DateTime.parseISO('2013-10-16T12:13:14.125', false).firstOfWeek();
const expected = DateTime.parse('10_2013_16', 'MM_YYYY_DD'); const expected = DateTime.parseISO('2013-10-14', false);
expect(actual).toEqual(expected); expect(actual).toEqual(expected);
}); });
it('should calculate valid first of week', () => { it('should calculate valid first of month', () => {
const actual = DateTime.parseISO_UTC('2013-10-16T12:13:14.125').firstOfWeek(); const actual = DateTime.parseISO('2013-10-16T12:13:14.125', false).firstOfMonth();
const expected = DateTime.parseISO_UTC('2013-10-14T00:00:00'); const expected = DateTime.parseISO('2013-10-01', false);
expect(actual.toISOString()).toEqual(expected.toISOString());
});
it('should add years to date time', () => {
const actual = DateTime.parseISO('2013-01-01T12:12:12.100Z').addYears(2);
const expected = DateTime.parseISO('2015-01-01T12:12:12.100Z');
expect(actual).toEqual(expected); expect(actual).toEqual(expected);
}); });
it('should calculate valid first of month', () => { it('should add months to date time', () => {
const actual = DateTime.parseISO_UTC('2013-10-16T12:13:14.125').firstOfMonth(); const actual = DateTime.parseISO('2015-01-01T12:12:12.100Z').addMonths(1);
const expected = DateTime.parseISO_UTC('2013-10-01'); const expected = DateTime.parseISO('2015-02-01T12:12:12.100Z');
expect(actual.toISOString()).toEqual(expected.toISOString()); expect(actual).toEqual(expected);
});
it('should add days to date time', () => {
const actual = DateTime.parseISO('2015-02-01T12:12:12.100Z').addDays(9);
const expected = DateTime.parseISO('2015-02-10T12:12:12.100Z');
expect(actual).toEqual(expected);
});
it('should add hours to date time', () => {
const actual = DateTime.parseISO('2015-02-10T12:12:12.100Z').addHours(11);
const expected = DateTime.parseISO('2015-02-10T23:12:12.100Z');
expect(actual).toEqual(expected);
});
it('should add minutes to date time', () => {
const actual = DateTime.parseISO('2015-02-10T23:12:12.100Z').addMinutes(7);
const expected = DateTime.parseISO('2015-02-10T23:19:12.100Z');
expect(actual).toEqual(expected);
});
it('should add seconds to date time', () => {
const actual = DateTime.parseISO('2015-02-10T23:19:12.100Z').addSeconds(5);
const expected = DateTime.parseISO('2015-02-10T23:19:17.100Z');
expect(actual).toEqual(expected);
}); });
it('should add various offsets to date time', () => { it('should add milliseconds to date time', () => {
const actual = const actual = DateTime.parseISO('2015-02-10T23:19:17.100Z').addMilliseconds(125);
DateTime.parseISO_UTC('2013-05-01T12:12:12.100') const expected = DateTime.parseISO('2015-02-10T23:19:17.225Z');
.addYears(1)
.addMonths(2)
.addDays(13)
.addHours(3)
.addMinutes(10)
.addSeconds(15)
.addMilliseconds(125);
const expected = DateTime.parseISO_UTC('2014-07-16T15:22:27.225');
expect(actual).toEqual(expected); expect(actual).toEqual(expected);
}); });

152
frontend/app/framework/utils/date-time.ts

@ -5,7 +5,11 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import moment from 'moment'; import { addDays, addHours, addMilliseconds, addMinutes, addMonths, addSeconds, addYears, format, formatDistanceToNow, parse, parseISO, startOfDay, startOfMonth, startOfTomorrow, startOfWeek, startOfYesterday } from 'date-fns';
import { DateHelper } from './date-helper';
const DATE_FORMAT = 'yyyy-MM-dd';
export class DateTime { export class DateTime {
public get raw(): Date { public get raw(): Date {
@ -49,83 +53,61 @@ export class DateTime {
} }
public get date(): DateTime { public get date(): DateTime {
const clone = this.cloneDate(); return new DateTime(startOfDay(this.value));
clone.setUTCHours(0, 0, 0, 0);
return new DateTime(clone);
} }
constructor(private readonly value: Date) { constructor(private readonly value: Date) {
Object.freeze(this); Object.freeze(this);
} }
public static iso8601(): any {
return moment.ISO_8601;
}
public static now(): DateTime { public static now(): DateTime {
return new DateTime(new Date()); return new DateTime(new Date());
} }
public static today(): DateTime { public static today(): DateTime {
return DateTime.now().date; return new DateTime(startOfDay(new Date()));
} }
public static tomorrow(): DateTime { public static tomorrow(): DateTime {
return DateTime.today().addDays(1); return new DateTime(startOfTomorrow());
} }
public static yesterday(): DateTime { public static yesterday(): DateTime {
return DateTime.today().addDays(-1); return new DateTime(startOfYesterday());
} }
public static parseMSDate(value: string): DateTime { public static parseISO(value: string, assumeUtc = true): DateTime {
let off = parseInt(value.substr(19, 3), 10); const result = DateTime.tryParseISO(value, assumeUtc);
if (isNaN(off)) { if (!result) {
off = 0; throw new Error(`${value} is not a valid datetime.`);
} }
const date = new Date(parseInt(value.substr(6), 10)); return result;
const time = (date.getTime());
const offs = (date.getTimezoneOffset() + off * 60) * 60000;
date.setTime(time + offs);
return new DateTime(date);
}
public static parseISO(value: string): DateTime {
return DateTime.parse(value, DateTime.iso8601());
} }
public static parseISO_UTC(value: string): DateTime { public static tryParseISO(value: string, assumeUtc = true): DateTime | null {
return DateTime.parseUTC(value, DateTime.iso8601()); if (!value) {
} return null;
}
public static parse(value: string, format: string): DateTime { let date: Date;
const parsedMoment = moment(value, format);
if (parsedMoment.isValid()) { if (value.length === DATE_FORMAT.length) {
return new DateTime(parsedMoment.toDate()); date = parse(value, DATE_FORMAT, new Date());
} else { } else {
throw Error(`DateTime: ${value} is not a valid date time string`); date = date = parseISO(value);
} }
}
public static parseUTC(value: string, format: string): DateTime { if (isNaN(date.getTime())) {
const parsedMoment = moment.utc(value, format); return null;
}
if (parsedMoment.isValid()) { if (assumeUtc && (value.length === DATE_FORMAT.length || !value.endsWith('Z'))) {
return new DateTime(parsedMoment.toDate()); date = DateHelper.getLocalDate(date);
} else {
throw Error(`DateTime: ${value} is not a valid date time string`);
} }
}
private cloneDate(): Date { return new DateTime(date);
return new Date(this.value.getTime());
} }
public eq(v: DateTime): boolean { public eq(v: DateTime): boolean {
@ -153,86 +135,68 @@ export class DateTime {
} }
public firstOfWeek(): DateTime { public firstOfWeek(): DateTime {
const date = this.date; return new DateTime(startOfWeek(this.value, { weekStartsOn: 1 }));
return date.addDays(-date.value.getUTCDay() + 1);
} }
public firstOfMonth(): DateTime { public firstOfMonth(): DateTime {
const monthStart = new Date(Date.UTC(this.year, this.month - 1, 1)); return new DateTime(startOfMonth(this.value));
return new DateTime(monthStart);
} }
public addYears(value: number): DateTime { public addYears(value: number): DateTime {
const clone = this.cloneDate(); return new DateTime(addYears(this.value, value));
clone.setUTCFullYear(clone.getUTCFullYear() + value, clone.getUTCMonth(), clone.getUTCDay());
return new DateTime(clone);
} }
public addMonths(value: number): DateTime { public addMonths(value: number): DateTime {
const clone = this.cloneDate(); return new DateTime(addMonths(this.value, value));
clone.setUTCMonth(clone.getUTCMonth() + value, clone.getUTCDate());
return new DateTime(clone);
} }
public addDays(value: number): DateTime { public addDays(value: number): DateTime {
const clone = this.cloneDate(); return new DateTime(addDays(this.value, value));
clone.setUTCDate(clone.getUTCDate() + value);
return new DateTime(clone);
} }
public addHours(value: number): DateTime { public addHours(value: number): DateTime {
const clone = this.cloneDate(); return new DateTime(addHours(this.value, value));
clone.setTime(clone.getTime() + (value * 60 * 60 * 1000));
return new DateTime(clone);
} }
public addMinutes(value: number): DateTime { public addMinutes(value: number): DateTime {
const clone = this.cloneDate(); return new DateTime(addMinutes(this.value, value));
clone.setTime(clone.getTime() + (value * 60 * 1000));
return new DateTime(clone);
} }
public addSeconds(value: number): DateTime { public addSeconds(value: number): DateTime {
const clone = this.cloneDate(); return new DateTime(addSeconds(this.value, value));
clone.setTime(clone.getTime() + (value * 1000));
return new DateTime(clone);
} }
public addMilliseconds(value: number): DateTime { public addMilliseconds(value: number): DateTime {
const clone = this.cloneDate(); return new DateTime(addMilliseconds(this.value, value));
clone.setTime(clone.getTime() + value);
return new DateTime(clone);
} }
public toISOString(): string { public toISODateUTC(): string {
return moment(this.value).toISOString(); return format(DateHelper.getUTCDate(this.value), DATE_FORMAT);
} }
public toStringFormat(format: string): string { public toISODate(): string {
return moment(this.value).format(format); return format(this.value, DATE_FORMAT);
}
public toStringFormat(pattern: string): string {
return format(this.value, pattern);
} }
public toUTCStringFormat(format: string): string { public toStringFormatUTC(pattern: string): string {
return moment.utc(this.value).format(format); return format(DateHelper.getUTCDate(this.value), pattern);
} }
public toFromNow(): string { public toFromNow(): string {
return moment.utc(this.value).fromNow(); return formatDistanceToNow(this.value, { includeSeconds: true, addSuffix: true });
}
public toISOString(withoutMilliseconds = true): string {
let result = this.value.toISOString();
if (withoutMilliseconds) {
result = result.slice(0, 19) + 'Z';
}
return result;
} }
} }

18
frontend/app/framework/utils/duration.ts

@ -5,8 +5,6 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import moment from 'moment';
import { DateTime } from './date-time'; import { DateTime } from './date-time';
export class Duration { export class Duration {
@ -23,21 +21,29 @@ export class Duration {
} }
public toString(): string { public toString(): string {
const duration = moment.duration(this.value); let seconds = this.value / 1000;
const hours = Math.floor(seconds / 3600);
let hoursString = Math.floor(duration.asHours()).toString(); let hoursString = hours.toString();
if (hoursString.length === 1) { if (hoursString.length === 1) {
hoursString = `0${hoursString}`; hoursString = `0${hoursString}`;
} }
let minutesString = duration.minutes().toString(); seconds = seconds % 3600;
const minutes = Math.floor(seconds / 60);
let minutesString = minutes.toString();
if (minutesString.length === 1) { if (minutesString.length === 1) {
minutesString = `0${minutesString}`; minutesString = `0${minutesString}`;
} }
let secondsString = duration.seconds().toString(); seconds = seconds % 60;
let secondsString = seconds.toString();
if (secondsString.length === 1) { if (secondsString.length === 1) {
secondsString = `0${secondsString}`; secondsString = `0${secondsString}`;

8
frontend/app/framework/utils/string-helper.ts

@ -20,14 +20,18 @@ export module StringHelper {
return ''; return '';
} }
export function appendToUrl(url: string, key: string, value: any) { export function appendToUrl(url: string, key: string, value?: any) {
if (url.indexOf('?') > 0) { if (url.indexOf('?') > 0) {
url += '&'; url += '&';
} else { } else {
url += '?'; url += '?';
} }
url += `${key}=${value}`; if (value !== undefined) {
url += `${key}=${value}`;
} else {
url += key;
}
return url; return url;
} }

6
frontend/app/shared/components/assets/asset.component.html

@ -81,11 +81,7 @@
</div> </div>
</div> </div>
<div class="file-tags tags"> <div class="file-tags tags">
<sqx-tag-editor [ngModel]="asset.tags" <div class="tag" *ngFor="let tag of asset.tags">{{tag}}</div>
styleBlank="true"
styleGray="true"
readonly="true">
</sqx-tag-editor>
</div> </div>
<div class="file-info"> <div class="file-info">
{{asset.metadataText}} {{asset.metadataText}}

19
frontend/app/shared/components/assets/asset.component.scss

@ -288,6 +288,19 @@ img {
cursor: pointer; cursor: pointer;
} }
.tags { .icon-close {
min-height: 26px; font-size: .6rem;
} }
.tag {
background: $color-border;
border: 0;
border-radius: 2px;
color: $color-text;
display: inline-block;
margin-bottom: .25rem;
margin-right: 2px;
padding: 1px .5rem;
vertical-align: top;
white-space: nowrap;
}

8
frontend/app/shared/services/apps.service.spec.ts

@ -232,8 +232,8 @@ describe('AppsService', () => {
label: `my-label${id}${suffix}`, label: `my-label${id}${suffix}`,
description: `my-description${id}${suffix}`, description: `my-description${id}${suffix}`,
permissions: ['Owner'], permissions: ['Owner'],
created: `${id % 1000 + 2000}-12-12T10:10:00`, created: `${id % 1000 + 2000}-12-12T10:10:00Z`,
lastModified: `${id % 1000 + 2000}-11-11T10:10:00`, lastModified: `${id % 1000 + 2000}-11-11T10:10:00Z`,
canAccessApi: id % 2 === 0, canAccessApi: id % 2 === 0,
canAccessContent: id % 2 === 0, canAccessContent: id % 2 === 0,
planName: 'Free', planName: 'Free',
@ -257,8 +257,8 @@ export function createApp(id: number, suffix = '') {
`my-label${id}${suffix}`, `my-label${id}${suffix}`,
`my-description${id}${suffix}`, `my-description${id}${suffix}`,
['Owner'], ['Owner'],
DateTime.parseISO_UTC(`${id % 1000 + 2000}-12-12T10:10:00`), DateTime.parseISO(`${id % 1000 + 2000}-12-12T10:10:00Z`),
DateTime.parseISO_UTC(`${id % 1000 + 2000}-11-11T10:10:00`), DateTime.parseISO(`${id % 1000 + 2000}-11-11T10:10:00Z`),
id % 2 === 0, id % 2 === 0,
id % 2 === 0, id % 2 === 0,
'Free', 'Basic', 'Free', 'Basic',

4
frontend/app/shared/services/apps.service.ts

@ -229,8 +229,8 @@ function parseApp(response: any) {
response.label, response.label,
response.description, response.description,
response.permissions, response.permissions,
DateTime.parseISO_UTC(response.created), DateTime.parseISO(response.created),
DateTime.parseISO_UTC(response.lastModified), DateTime.parseISO(response.lastModified),
response.canAccessApi, response.canAccessApi,
response.canAccessContent, response.canAccessContent,
response.planName, response.planName,

8
frontend/app/shared/services/assets.service.spec.ts

@ -451,9 +451,9 @@ describe('AssetsService', () => {
return { return {
id: `id${id}`, id: `id${id}`,
created: `${id % 1000 + 2000}-12-12T10:10:00`, created: `${id % 1000 + 2000}-12-12T10:10:00Z`,
createdBy: `creator${id}`, createdBy: `creator${id}`,
lastModified: `${id % 1000 + 2000}-11-11T10:10:00`, lastModified: `${id % 1000 + 2000}-11-11T10:10:00Z`,
lastModifiedBy: `modifier${id}`, lastModifiedBy: `modifier${id}`,
fileName: `My Name${id}${suffix}.png`, fileName: `My Name${id}${suffix}.png`,
fileHash: `My Hash${id}${suffix}`, fileHash: `My Hash${id}${suffix}`,
@ -510,8 +510,8 @@ export function createAsset(id: number, tags?: ReadonlyArray<string>, suffix = '
return new AssetDto(links, meta, return new AssetDto(links, meta,
`id${id}`, `id${id}`,
DateTime.parseISO_UTC(`${id % 1000 + 2000}-12-12T10:10:00`), `creator${id}`, DateTime.parseISO(`${id % 1000 + 2000}-12-12T10:10:00Z`), `creator${id}`,
DateTime.parseISO_UTC(`${id % 1000 + 2000}-11-11T10:10:00`), `modifier${id}`, DateTime.parseISO(`${id % 1000 + 2000}-11-11T10:10:00Z`), `modifier${id}`,
`My Name${id}${suffix}.png`, `My Name${id}${suffix}.png`,
`My Hash${id}${suffix}`, `My Hash${id}${suffix}`,
'png', 'png',

4
frontend/app/shared/services/assets.service.ts

@ -418,8 +418,8 @@ export class AssetsService {
function parseAsset(response: any) { function parseAsset(response: any) {
return new AssetDto(response._links, response._meta, return new AssetDto(response._links, response._meta,
response.id, response.id,
DateTime.parseISO_UTC(response.created), response.createdBy, DateTime.parseISO(response.created), response.createdBy,
DateTime.parseISO_UTC(response.lastModified), response.lastModifiedBy, DateTime.parseISO(response.lastModified), response.lastModifiedBy,
response.fileName, response.fileName,
response.fileHash, response.fileHash,
response.fileType, response.fileType,

12
frontend/app/shared/services/backups.service.spec.ts

@ -93,8 +93,8 @@ describe('BackupsService', () => {
expect(restore!).toEqual( expect(restore!).toEqual(
new RestoreDto('http://url', new RestoreDto('http://url',
DateTime.parseISO_UTC('2017-02-03'), DateTime.parseISO('2017-02-03'),
DateTime.parseISO_UTC('2017-02-04'), DateTime.parseISO('2017-02-04'),
'Failed', 'Failed',
[ [
'log1', 'log1',
@ -194,8 +194,8 @@ describe('BackupsService', () => {
function backupResponse(id: number) { function backupResponse(id: number) {
return { return {
id: `id${id}`, id: `id${id}`,
started: `${id % 1000 + 2000}-12-12T10:10:00`, started: `${id % 1000 + 2000}-12-12T10:10:00Z`,
stopped: id % 2 === 0 ? `${id % 1000 + 2000}-11-11T10:10:00` : null, stopped: id % 2 === 0 ? `${id % 1000 + 2000}-11-11T10:10:00Z` : null,
handledEvents: id * 17, handledEvents: id * 17,
handledAssets: id * 23, handledAssets: id * 23,
status: id % 2 === 0 ? 'Success' : 'Failed', status: id % 2 === 0 ? 'Success' : 'Failed',
@ -213,8 +213,8 @@ export function createBackup(id: number) {
return new BackupDto(links, return new BackupDto(links,
`id${id}`, `id${id}`,
DateTime.parseISO_UTC(`${id % 1000 + 2000}-12-12T10:10:00`), DateTime.parseISO(`${id % 1000 + 2000}-12-12T10:10:00Z`),
id % 2 === 0 ? DateTime.parseISO_UTC(`${id % 1000 + 2000}-11-11T10:10:00`) : null, id % 2 === 0 ? DateTime.parseISO(`${id % 1000 + 2000}-11-11T10:10:00Z`) : null,
id * 17, id * 17,
id * 23, id * 23,
id % 2 === 0 ? 'Success' : 'Failed'); id % 2 === 0 ? 'Success' : 'Failed');

8
frontend/app/shared/services/backups.service.ts

@ -148,8 +148,8 @@ export class BackupsService {
function parseRestore(response: any) { function parseRestore(response: any) {
return new RestoreDto( return new RestoreDto(
response.url, response.url,
DateTime.parseISO_UTC(response.started), DateTime.parseISO(response.started),
response.stopped ? DateTime.parseISO_UTC(response.stopped) : null, response.stopped ? DateTime.parseISO(response.stopped) : null,
response.status, response.status,
response.log); response.log);
} }
@ -157,8 +157,8 @@ function parseRestore(response: any) {
function parseBackup(response: any) { function parseBackup(response: any) {
return new BackupDto(response._links, return new BackupDto(response._links,
response.id, response.id,
DateTime.parseISO_UTC(response.started), DateTime.parseISO(response.started),
response.stopped ? DateTime.parseISO_UTC(response.stopped) : null, response.stopped ? DateTime.parseISO(response.stopped) : null,
response.handledEvents, response.handledEvents,
response.handledAssets, response.handledAssets,
response.status); response.status);

6
frontend/app/shared/services/comments.service.spec.ts

@ -71,9 +71,9 @@ describe('CommentsService', () => {
expect(comments!).toEqual( expect(comments!).toEqual(
new CommentsDto( new CommentsDto(
[ [
new CommentDto('123', DateTime.parseISO_UTC('2016-10-12T10:10'), 'text1', undefined, user) new CommentDto('123', DateTime.parseISO('2016-10-12T10:10Z'), 'text1', undefined, user)
], [ ], [
new CommentDto('456', DateTime.parseISO_UTC('2017-11-12T12:12'), 'text2', undefined, user) new CommentDto('456', DateTime.parseISO('2017-11-12T12:12Z'), 'text2', undefined, user)
], [ ], [
'789' '789'
], ],
@ -104,7 +104,7 @@ describe('CommentsService', () => {
user: user user: user
}); });
expect(comment!).toEqual(new CommentDto('123', DateTime.parseISO_UTC('2016-10-12T10:10'), 'text1', undefined, user)); expect(comment!).toEqual(new CommentDto('123', DateTime.parseISO('2016-10-12T10:10Z'), 'text1', undefined, user));
})); }));
it('should make put request to replace comment content', it('should make put request to replace comment content',

6
frontend/app/shared/services/comments.service.ts

@ -69,7 +69,7 @@ export class CommentsService {
body.createdComments.map((item: any) => { body.createdComments.map((item: any) => {
return new CommentDto( return new CommentDto(
item.id, item.id,
DateTime.parseISO_UTC(item.time), DateTime.parseISO(item.time),
item.text, item.text,
item.url, item.url,
item.user); item.user);
@ -77,7 +77,7 @@ export class CommentsService {
body.updatedComments.map((item: any) => { body.updatedComments.map((item: any) => {
return new CommentDto( return new CommentDto(
item.id, item.id,
DateTime.parseISO_UTC(item.time), DateTime.parseISO(item.time),
item.text, item.text,
item.url, item.url,
item.user); item.user);
@ -98,7 +98,7 @@ export class CommentsService {
map(body => { map(body => {
const comment = new CommentDto( const comment = new CommentDto(
body.id, body.id,
DateTime.parseISO_UTC(body.time), DateTime.parseISO(body.time),
body.text, body.text,
body.url, body.url,
body.user); body.user);

12
frontend/app/shared/services/contents.service.spec.ts

@ -420,15 +420,15 @@ describe('ContentsService', () => {
statusColor: 'black', statusColor: 'black',
newStatus: `NewStatus${id}`, newStatus: `NewStatus${id}`,
newStatusColor: 'black', newStatusColor: 'black',
created: `${id % 1000 + 2000}-12-12T10:10:00`, created: `${id % 1000 + 2000}-12-12T10:10:00Z`,
createdBy: `creator${id}`, createdBy: `creator${id}`,
lastModified: `${id % 1000 + 2000}-11-11T10:10:00`, lastModified: `${id % 1000 + 2000}-11-11T10:10:00Z`,
lastModifiedBy: `modifier${id}`, lastModifiedBy: `modifier${id}`,
scheduleJob: { scheduleJob: {
status: 'Draft', status: 'Draft',
scheduledBy: `Scheduler${id}`, scheduledBy: `Scheduler${id}`,
color: 'red', color: 'red',
dueTime: `${id % 1000 + 2000}-11-11T10:10:00` dueTime: `${id % 1000 + 2000}-11-11T10:10:00Z`
}, },
data: {}, data: {},
schemaName: 'my-schema', schemaName: 'my-schema',
@ -454,9 +454,9 @@ export function createContent(id: number, suffix = '') {
'black', 'black',
`NewStatus${id}${suffix}`, `NewStatus${id}${suffix}`,
'black', 'black',
DateTime.parseISO_UTC(`${id % 1000 + 2000}-12-12T10:10:00`), `creator${id}`, DateTime.parseISO(`${id % 1000 + 2000}-12-12T10:10:00Z`), `creator${id}`,
DateTime.parseISO_UTC(`${id % 1000 + 2000}-11-11T10:10:00`), `modifier${id}`, DateTime.parseISO(`${id % 1000 + 2000}-11-11T10:10:00Z`), `modifier${id}`,
new ScheduleDto('Draft', `Scheduler${id}`, 'red', DateTime.parseISO_UTC(`${id % 1000 + 2000}-11-11T10:10:00`)), new ScheduleDto('Draft', `Scheduler${id}`, 'red', DateTime.parseISO(`${id % 1000 + 2000}-11-11T10:10:00Z`)),
{}, {},
'my-schema', 'my-schema',
'MySchema', 'MySchema',

6
frontend/app/shared/services/contents.service.ts

@ -352,8 +352,8 @@ function parseContent(response: any) {
response.statusColor, response.statusColor,
response.newStatus, response.newStatus,
response.newStatusColor, response.newStatusColor,
DateTime.parseISO_UTC(response.created), response.createdBy, DateTime.parseISO(response.created), response.createdBy,
DateTime.parseISO_UTC(response.lastModified), response.lastModifiedBy, DateTime.parseISO(response.lastModified), response.lastModifiedBy,
parseScheduleJob(response.scheduleJob), parseScheduleJob(response.scheduleJob),
response.data, response.data,
response.schemaName, response.schemaName,
@ -372,5 +372,5 @@ function parseScheduleJob(response: any) {
response.status, response.status,
response.scheduledBy, response.scheduledBy,
response.color, response.color,
DateTime.parseISO_UTC(response.dueTime)); DateTime.parseISO(response.dueTime));
} }

4
frontend/app/shared/services/history.service.spec.ts

@ -68,8 +68,8 @@ describe('HistoryService', () => {
expect(events!).toEqual( expect(events!).toEqual(
[ [
new HistoryEventDto('1', 'User1', 'Type 1', 'Message 1', DateTime.parseISO_UTC('2016-12-12T10:10'), new Version('2')), new HistoryEventDto('1', 'User1', 'Type 1', 'Message 1', DateTime.parseISO('2016-12-12T10:10Z'), new Version('2')),
new HistoryEventDto('2', 'User2', 'Type 2', 'Message 2', DateTime.parseISO_UTC('2016-12-13T10:10'), new Version('3')) new HistoryEventDto('2', 'User2', 'Type 2', 'Message 2', DateTime.parseISO('2016-12-13T10:10Z'), new Version('3'))
]); ]);
})); }));
}); });

2
frontend/app/shared/services/history.service.ts

@ -97,7 +97,7 @@ export class HistoryService {
item.actor, item.actor,
item.eventType, item.eventType,
item.message, item.message,
DateTime.parseISO_UTC(item.created), DateTime.parseISO(item.created),
new Version(item.version.toString()))); new Version(item.version.toString())));
return history; return history;

14
frontend/app/shared/services/rules.service.spec.ts

@ -357,7 +357,7 @@ describe('RulesService', () => {
function ruleEventResponse(id: number, suffix = '') { function ruleEventResponse(id: number, suffix = '') {
return { return {
id: `id${id}`, id: `id${id}`,
created: `${id % 1000 + 2000}-12-12T10:10:00`, created: `${id % 1000 + 2000}-12-12T10:10:00Z`,
eventName: `event${id}${suffix}`, eventName: `event${id}${suffix}`,
nextAttempt: `${id % 1000 + 2000}-11-11T10:10`, nextAttempt: `${id % 1000 + 2000}-11-11T10:10`,
jobResult: `Failed${id}${suffix}`, jobResult: `Failed${id}${suffix}`,
@ -381,7 +381,7 @@ describe('RulesService', () => {
name: `Name${id}${suffix}`, name: `Name${id}${suffix}`,
numSucceeded: id * 3, numSucceeded: id * 3,
numFailed: id * 4, numFailed: id * 4,
lastExecuted: `${id % 1000 + 2000}-10-10T10:10:00`, lastExecuted: `${id % 1000 + 2000}-10-10T10:10:00Z`,
isEnabled: id % 2 === 0, isEnabled: id % 2 === 0,
trigger: { trigger: {
param1: 1, param1: 1,
@ -407,8 +407,8 @@ export function createRuleEvent(id: number, suffix = '') {
}; };
return new RuleEventDto(links, `id${id}`, return new RuleEventDto(links, `id${id}`,
DateTime.parseISO_UTC(`${id % 1000 + 2000}-12-12T10:10:00`), DateTime.parseISO(`${id % 1000 + 2000}-12-12T10:10:00Z`),
DateTime.parseISO_UTC(`${id % 1000 + 2000}-11-11T10:10:00`), DateTime.parseISO(`${id % 1000 + 2000}-11-11T10:10:00Z`),
`event${id}${suffix}`, `event${id}${suffix}`,
`url${id}${suffix}`, `url${id}${suffix}`,
`dump${id}${suffix}`, `dump${id}${suffix}`,
@ -424,8 +424,8 @@ export function createRule(id: number, suffix = '') {
return new RuleDto(links, return new RuleDto(links,
`id${id}`, `id${id}`,
DateTime.parseISO_UTC(`${id % 1000 + 2000}-12-12T10:10:00`), `creator${id}`, DateTime.parseISO(`${id % 1000 + 2000}-12-12T10:10:00Z`), `creator${id}`,
DateTime.parseISO_UTC(`${id % 1000 + 2000}-11-11T10:10:00`), `modifier${id}`, DateTime.parseISO(`${id % 1000 + 2000}-11-11T10:10:00Z`), `modifier${id}`,
new Version(`${id}${suffix}`), new Version(`${id}${suffix}`),
id % 2 === 0, id % 2 === 0,
{ {
@ -443,5 +443,5 @@ export function createRule(id: number, suffix = '') {
`Name${id}${suffix}`, `Name${id}${suffix}`,
id * 3, id * 3,
id * 4, id * 4,
DateTime.parseISO_UTC(`${id % 1000 + 2000}-10-10T10:10:00`)); DateTime.parseISO(`${id % 1000 + 2000}-10-10T10:10:00Z`));
} }

10
frontend/app/shared/services/rules.service.ts

@ -357,8 +357,8 @@ export class RulesService {
const ruleEvents = new RuleEventsDto(body.total, items.map(item => const ruleEvents = new RuleEventsDto(body.total, items.map(item =>
new RuleEventDto(item._links, new RuleEventDto(item._links,
item.id, item.id,
DateTime.parseISO_UTC(item.created), DateTime.parseISO(item.created),
item.nextAttempt ? DateTime.parseISO_UTC(item.nextAttempt) : null, item.nextAttempt ? DateTime.parseISO(item.nextAttempt) : null,
item.eventName, item.eventName,
item.description, item.description,
item.lastDump, item.lastDump,
@ -399,8 +399,8 @@ export class RulesService {
function parseRule(response: any) { function parseRule(response: any) {
return new RuleDto(response._links, return new RuleDto(response._links,
response.id, response.id,
DateTime.parseISO_UTC(response.created), response.createdBy, DateTime.parseISO(response.created), response.createdBy,
DateTime.parseISO_UTC(response.lastModified), response.lastModifiedBy, DateTime.parseISO(response.lastModified), response.lastModifiedBy,
new Version(response.version.toString()), new Version(response.version.toString()),
response.isEnabled, response.isEnabled,
response.trigger, response.trigger,
@ -410,5 +410,5 @@ function parseRule(response: any) {
response.name, response.name,
response.numSucceeded, response.numSucceeded,
response.numFailed, response.numFailed,
response.lastExecuted ? DateTime.parseISO_UTC(response.lastExecuted) : undefined); response.lastExecuted ? DateTime.parseISO(response.lastExecuted) : undefined);
} }

16
frontend/app/shared/services/schemas.service.spec.ts

@ -596,9 +596,9 @@ describe('SchemasService', () => {
category: `category${id}${suffix}`, category: `category${id}${suffix}`,
isSingleton: id % 2 === 0, isSingleton: id % 2 === 0,
isPublished: id % 3 === 0, isPublished: id % 3 === 0,
created: `${id % 1000 + 2000}-12-12T10:10:00`, created: `${id % 1000 + 2000}-12-12T10:10:00Z`,
createdBy: `creator${id}`, createdBy: `creator${id}`,
lastModified: `${id % 1000 + 2000}-11-11T10:10:00`, lastModified: `${id % 1000 + 2000}-11-11T10:10:00Z`,
lastModifiedBy: `modifier${id}`, lastModifiedBy: `modifier${id}`,
properties: { properties: {
label: `label${id}${suffix}`, label: `label${id}${suffix}`,
@ -619,9 +619,9 @@ describe('SchemasService', () => {
category: `category${id}${suffix}`, category: `category${id}${suffix}`,
isSingleton: id % 2 === 0, isSingleton: id % 2 === 0,
isPublished: id % 3 === 0, isPublished: id % 3 === 0,
created: `${id % 1000 + 2000}-12-12T10:10:00`, created: `${id % 1000 + 2000}-12-12T10:10:00Z`,
createdBy: `creator${id}`, createdBy: `creator${id}`,
lastModified: `${id % 1000 + 2000}-11-11T10:10:00`, lastModified: `${id % 1000 + 2000}-11-11T10:10:00Z`,
lastModifiedBy: `modifier${id}`, lastModifiedBy: `modifier${id}`,
version: `${id}`, version: `${id}`,
properties: { properties: {
@ -808,8 +808,8 @@ export function createSchema(id: number, suffix = '') {
new SchemaPropertiesDto(`label${id}${suffix}`, `hints${id}${suffix}`, [`tags${id}${suffix}`]), new SchemaPropertiesDto(`label${id}${suffix}`, `hints${id}${suffix}`, [`tags${id}${suffix}`]),
id % 2 === 0, id % 2 === 0,
id % 3 === 0, id % 3 === 0,
DateTime.parseISO_UTC(`${id % 1000 + 2000}-12-12T10:10:00`), `creator${id}`, DateTime.parseISO(`${id % 1000 + 2000}-12-12T10:10:00Z`), `creator${id}`,
DateTime.parseISO_UTC(`${id % 1000 + 2000}-11-11T10:10:00`), `modifier${id}`, DateTime.parseISO(`${id % 1000 + 2000}-11-11T10:10:00Z`), `modifier${id}`,
new Version(`${id}${suffix}`)); new Version(`${id}${suffix}`));
} }
@ -825,8 +825,8 @@ export function createSchemaDetails(id: number, suffix = '') {
new SchemaPropertiesDto(`label${id}${suffix}`, `hints${id}${suffix}`, [`tags${id}${suffix}`]), new SchemaPropertiesDto(`label${id}${suffix}`, `hints${id}${suffix}`, [`tags${id}${suffix}`]),
id % 2 === 0, id % 2 === 0,
id % 3 === 0, id % 3 === 0,
DateTime.parseISO_UTC(`${id % 1000 + 2000}-12-12T10:10:00`), `creator${id}`, DateTime.parseISO(`${id % 1000 + 2000}-12-12T10:10:00Z`), `creator${id}`,
DateTime.parseISO_UTC(`${id % 1000 + 2000}-11-11T10:10:00`), `modifier${id}`, DateTime.parseISO(`${id % 1000 + 2000}-11-11T10:10:00Z`), `modifier${id}`,
new Version(`${id}${suffix}`), new Version(`${id}${suffix}`),
[ [
new RootFieldDto({}, 11, 'field11', createProperties('Array'), 'language', true, true, true, [ new RootFieldDto({}, 11, 'field11', createProperties('Array'), 'language', true, true, true, [

8
frontend/app/shared/services/schemas.service.ts

@ -682,8 +682,8 @@ function parseSchemas(response: any) {
new SchemaPropertiesDto(item.properties.label, item.properties.hints, item.properties.tags), new SchemaPropertiesDto(item.properties.label, item.properties.hints, item.properties.tags),
item.isSingleton, item.isSingleton,
item.isPublished, item.isPublished,
DateTime.parseISO_UTC(item.created), item.createdBy, DateTime.parseISO(item.created), item.createdBy,
DateTime.parseISO_UTC(item.lastModified), item.lastModifiedBy, DateTime.parseISO(item.lastModified), item.lastModifiedBy,
new Version(item.version.toString()))); new Version(item.version.toString())));
const _links = response._links; const _links = response._links;
@ -703,8 +703,8 @@ function parseSchemaWithDetails(response: any) {
properties, properties,
response.isSingleton, response.isSingleton,
response.isPublished, response.isPublished,
DateTime.parseISO_UTC(response.created), response.createdBy, DateTime.parseISO(response.created), response.createdBy,
DateTime.parseISO_UTC(response.lastModified), response.lastModifiedBy, DateTime.parseISO(response.lastModified), response.lastModifiedBy,
new Version(response.version.toString()), new Version(response.version.toString()),
fields, fields,
response.fieldsInLists, response.fieldsInLists,

12
frontend/app/shared/services/usages.service.spec.ts

@ -40,7 +40,7 @@ describe('UsagesService', () => {
let usages: CallsUsageDto; let usages: CallsUsageDto;
usagesService.getCallsUsages('my-app', DateTime.parseISO_UTC('2017-10-12'), DateTime.parseISO_UTC('2017-10-13')).subscribe(result => { usagesService.getCallsUsages('my-app', '2017-10-12', '2017-10-13').subscribe(result => {
usages = result; usages = result;
}); });
@ -75,8 +75,8 @@ describe('UsagesService', () => {
expect(usages!).toEqual( expect(usages!).toEqual(
new CallsUsageDto(100, 1024, 40, 12.4, { new CallsUsageDto(100, 1024, 40, 12.4, {
category1: [ category1: [
new CallsUsagePerDateDto(DateTime.parseISO_UTC('2017-10-12'), 10, 130, 12.3), new CallsUsagePerDateDto(DateTime.parseISO('2017-10-12'), 10, 130, 12.3),
new CallsUsagePerDateDto(DateTime.parseISO_UTC('2017-10-13'), 13, 170, 33.3) new CallsUsagePerDateDto(DateTime.parseISO('2017-10-13'), 13, 170, 33.3)
] ]
}) })
); );
@ -87,7 +87,7 @@ describe('UsagesService', () => {
let usages: ReadonlyArray<StorageUsagePerDateDto>; let usages: ReadonlyArray<StorageUsagePerDateDto>;
usagesService.getStorageUsages('my-app', DateTime.parseISO_UTC('2017-10-12'), DateTime.parseISO_UTC('2017-10-13')).subscribe(result => { usagesService.getStorageUsages('my-app', '2017-10-12', '2017-10-13').subscribe(result => {
usages = result; usages = result;
}); });
@ -111,8 +111,8 @@ describe('UsagesService', () => {
expect(usages!).toEqual( expect(usages!).toEqual(
[ [
new StorageUsagePerDateDto(DateTime.parseISO_UTC('2017-10-12'), 10, 130), new StorageUsagePerDateDto(DateTime.parseISO('2017-10-12'), 10, 130),
new StorageUsagePerDateDto(DateTime.parseISO_UTC('2017-10-13'), 13, 170) new StorageUsagePerDateDto(DateTime.parseISO('2017-10-13'), 13, 170)
]); ]);
})); }));

12
frontend/app/shared/services/usages.service.ts

@ -82,8 +82,8 @@ export class UsagesService {
pretifyError('Failed to load todays storage size. Please reload.')); pretifyError('Failed to load todays storage size. Please reload.'));
} }
public getCallsUsages(app: string, fromDate: DateTime, toDate: DateTime): Observable<CallsUsageDto> { public getCallsUsages(app: string, fromDate: string, toDate: string): Observable<CallsUsageDto> {
const url = this.apiUrl.buildUrl(`api/apps/${app}/usages/calls/${fromDate.toUTCStringFormat('YYYY-MM-DD')}/${toDate.toUTCStringFormat('YYYY-MM-DD')}`); const url = this.apiUrl.buildUrl(`api/apps/${app}/usages/calls/${fromDate}/${toDate}`);
return this.http.get<any>(url).pipe( return this.http.get<any>(url).pipe(
map(body => { map(body => {
@ -92,7 +92,7 @@ export class UsagesService {
for (let category of Object.keys(body.details)) { for (let category of Object.keys(body.details)) {
details[category] = body.details[category].map((item: any) => details[category] = body.details[category].map((item: any) =>
new CallsUsagePerDateDto( new CallsUsagePerDateDto(
DateTime.parseISO_UTC(item.date), DateTime.parseISO(item.date),
item.totalBytes, item.totalBytes,
item.totalCalls, item.totalCalls,
item.averageElapsedMs)); item.averageElapsedMs));
@ -111,14 +111,14 @@ export class UsagesService {
pretifyError('Failed to load calls usage. Please reload.')); pretifyError('Failed to load calls usage. Please reload.'));
} }
public getStorageUsages(app: string, fromDate: DateTime, toDate: DateTime): Observable<ReadonlyArray<StorageUsagePerDateDto>> { public getStorageUsages(app: string, fromDate: string, toDate: string): Observable<ReadonlyArray<StorageUsagePerDateDto>> {
const url = this.apiUrl.buildUrl(`api/apps/${app}/usages/storage/${fromDate.toUTCStringFormat('YYYY-MM-DD')}/${toDate.toUTCStringFormat('YYYY-MM-DD')}`); const url = this.apiUrl.buildUrl(`api/apps/${app}/usages/storage/${fromDate}/${toDate}`);
return this.http.get<any[]>(url).pipe( return this.http.get<any[]>(url).pipe(
map(body => { map(body => {
const usages = body.map(item => const usages = body.map(item =>
new StorageUsagePerDateDto( new StorageUsagePerDateDto(
DateTime.parseISO_UTC(item.date), DateTime.parseISO(item.date),
item.totalCount, item.totalCount,
item.totalSize)); item.totalSize));

8
frontend/app/shared/state/contents.forms.spec.ts

@ -248,7 +248,7 @@ describe('BooleanField', () => {
}); });
describe('DateTimeField', () => { describe('DateTimeField', () => {
const now = DateTime.parseISO_UTC('2017-10-12T16:30:10Z'); const now = DateTime.parseISO('2017-10-12T16:30:10Z');
const field = createField({ properties: createProperties('DateTime', { editor: 'DateTime', isRequired: true }) }); const field = createField({ properties: createProperties('DateTime', { editor: 'DateTime', isRequired: true }) });
it('should create validators', () => { it('should create validators', () => {
@ -263,6 +263,12 @@ describe('DateTimeField', () => {
expect(FieldFormatter.format(field, true)).toBe(true); expect(FieldFormatter.format(field, true)).toBe(true);
}); });
it('should format old format to date', () => {
const dateField = createField({ properties: createProperties('DateTime', { editor: 'Date' }) });
expect(FieldFormatter.format(dateField, '2017-12-12')).toBe('2017-12-12');
});
it('should format to date', () => { it('should format to date', () => {
const dateField = createField({ properties: createProperties('DateTime', { editor: 'Date' }) }); const dateField = createField({ properties: createProperties('DateTime', { editor: 'Date' }) });

10
frontend/app/shared/state/contents.forms.ts

@ -159,12 +159,12 @@ export class FieldFormatter implements FieldPropertiesVisitor<FieldValue> {
public visitDateTime(properties: DateTimeFieldPropertiesDto): FieldValue { public visitDateTime(properties: DateTimeFieldPropertiesDto): FieldValue {
try { try {
const parsed = DateTime.parseISO_UTC(this.value); const parsed = DateTime.parseISO(this.value);
if (properties.editor === 'Date') { if (properties.editor === 'Date') {
return parsed.toUTCStringFormat('YYYY-MM-DD'); return parsed.toStringFormatUTC('yyyy-MM-dd');
} else { } else {
return parsed.toUTCStringFormat('YYYY-MM-DD HH:mm:ss'); return parsed.toStringFormatUTC('yyyy-MM-dd HH:mm:ss');
} }
} catch (ex) { } catch (ex) {
return this.value; return this.value;
@ -388,9 +388,9 @@ export class FieldDefaultValue implements FieldPropertiesVisitor<any> {
const now = this.now || DateTime.now(); const now = this.now || DateTime.now();
if (properties.calculatedDefaultValue === 'Now') { if (properties.calculatedDefaultValue === 'Now') {
return `${now.toUTCStringFormat('YYYY-MM-DDTHH:mm:ss')}Z`; return `${now.toStringFormatUTC('yyyy-MM-dd\'T\'HH:mm:ss')}Z`;
} else if (properties.calculatedDefaultValue === 'Today') { } else if (properties.calculatedDefaultValue === 'Today') {
return `${now.toUTCStringFormat('YYYY-MM-DD')}T00:00:00Z`; return `${now.toISODate()}T00:00:00Z`;
} else { } else {
return properties.defaultValue; return properties.defaultValue;
} }

11
frontend/package-lock.json

@ -492,9 +492,9 @@
} }
}, },
"@types/jasmine": { "@types/jasmine": {
"version": "3.5.5", "version": "3.5.9",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.5.tgz", "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.9.tgz",
"integrity": "sha512-LlhwGivHkUV8ehNmaXjGGXopLm91G9ORIRcjw7Ya47jVAIGudewFZM2PdPXBvueZfRWwYzLt083wiPfKRXrSlg==", "integrity": "sha512-KNL2Fq6GRmty2j6+ZmueT/Z/dkctLNH+5DFoGHNDtcgt7yME9NZd8x2p81Yuea1Xux/qAryDd3zVLUoKpDz1TA==",
"dev": true "dev": true
}, },
"@types/jquery": { "@types/jquery": {
@ -3127,6 +3127,11 @@
"assert-plus": "^1.0.0" "assert-plus": "^1.0.0"
} }
}, },
"date-fns": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.10.0.tgz",
"integrity": "sha512-EhfEKevYGWhWlZbNeplfhIU/+N+x0iCIx7VzKlXma2EdQyznVlZhCptXUY+BegNpPW2kjdx15Rvq503YcXXrcA=="
},
"date-format": { "date-format": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",

2
frontend/package.json

@ -31,12 +31,12 @@
"bootstrap": "4.4.1", "bootstrap": "4.4.1",
"core-js": "3.6.4", "core-js": "3.6.4",
"cropperjs": "2.0.0-alpha.1", "cropperjs": "2.0.0-alpha.1",
"date-fns": "^2.10.0",
"graphiql": "0.17.5", "graphiql": "0.17.5",
"graphql": "14.6.0", "graphql": "14.6.0",
"image-focus": "^1.1.0", "image-focus": "^1.1.0",
"marked": "0.8.0", "marked": "0.8.0",
"mersenne-twister": "1.1.0", "mersenne-twister": "1.1.0",
"moment": "2.24.0",
"mousetrap": "1.6.5", "mousetrap": "1.6.5",
"ngx-color-picker": "9.0.0", "ngx-color-picker": "9.0.0",
"oidc-client": "1.10.1", "oidc-client": "1.10.1",

Loading…
Cancel
Save