From b6eb98df7d1b947eeebc78c64d3f71f4f6d65bcf Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 20 Feb 2020 14:40:33 +0100 Subject: [PATCH] Better handle of empty strings. --- .../angular/forms/forms-helper.spec.ts | 3 +- .../framework/angular/forms/forms-helper.ts | 4 +- .../angular/forms/string-form-control.spec.ts | 26 ++ .../angular/forms/string-form-control.ts | 39 +++ frontend/app/framework/declarations.ts | 1 + frontend/app/framework/utils/pager.spec.ts | 2 + frontend/app/framework/utils/types.spec.ts | 20 ++ frontend/app/framework/utils/types.ts | 16 +- .../forms/references-dropdown.component.ts | 28 ++- frontend/app/shared/state/contents.forms.ts | 22 +- .../app/shared/state/table-fields.spec.ts | 6 +- frontend/package-lock.json | 224 +++++++++--------- frontend/package.json | 50 ++-- 13 files changed, 280 insertions(+), 161 deletions(-) create mode 100644 frontend/app/framework/angular/forms/string-form-control.spec.ts create mode 100644 frontend/app/framework/angular/forms/string-form-control.ts diff --git a/frontend/app/framework/angular/forms/forms-helper.spec.ts b/frontend/app/framework/angular/forms/forms-helper.spec.ts index 4af03773a..44d827cd8 100644 --- a/frontend/app/framework/angular/forms/forms-helper.spec.ts +++ b/frontend/app/framework/angular/forms/forms-helper.spec.ts @@ -26,7 +26,7 @@ describe('FormHelpers', () => { expect(values).toEqual(['1', '2', '3']); }); - it('should not trigger on disable', () => { + it('should also trigger on disable', () => { const form = new FormControl('1', Validators.required); const values: any[] = []; @@ -39,6 +39,7 @@ describe('FormHelpers', () => { form.enable(); form.setValue('3'); form.disable(); + form.setValue('4'); expect(values).toEqual(['1', '2', '3']); }); diff --git a/frontend/app/framework/angular/forms/forms-helper.ts b/frontend/app/framework/angular/forms/forms-helper.ts index eb6033fcb..e3953a948 100644 --- a/frontend/app/framework/angular/forms/forms-helper.ts +++ b/frontend/app/framework/angular/forms/forms-helper.ts @@ -7,7 +7,7 @@ import { AbstractControl, FormArray, FormGroup } from '@angular/forms'; import { Observable } from 'rxjs'; -import { distinctUntilChanged, filter, map, startWith } from 'rxjs/operators'; +import { distinctUntilChanged, map, startWith } from 'rxjs/operators'; import { Types } from './../../utils/types'; @@ -30,7 +30,7 @@ export function invalid$(form: AbstractControl): Observable { } export function value$(form: AbstractControl): Observable { - return form.valueChanges.pipe(startWith(form.value), filter(_ => form.enabled), distinctUntilChanged()); + return form.valueChanges.pipe(startWith(form.value), distinctUntilChanged()); } export function hasValue$(form: AbstractControl): Observable { diff --git a/frontend/app/framework/angular/forms/string-form-control.spec.ts b/frontend/app/framework/angular/forms/string-form-control.spec.ts new file mode 100644 index 000000000..de38a3436 --- /dev/null +++ b/frontend/app/framework/angular/forms/string-form-control.spec.ts @@ -0,0 +1,26 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { StringFormControl } from './string-form-control'; + +describe('StringFormControl', () => { + it('should convert empty string to undefined', () => { + const formControl = new StringFormControl(); + + formControl.setValue(''); + + expect(formControl.value).toBeUndefined(); + }); + + it('should convert empty string to undefined when patching', () => { + const formControl = new StringFormControl(); + + formControl.patchValue(''); + + expect(formControl.value).toBeUndefined(); + }); +}); \ No newline at end of file diff --git a/frontend/app/framework/angular/forms/string-form-control.ts b/frontend/app/framework/angular/forms/string-form-control.ts new file mode 100644 index 000000000..e867cc913 --- /dev/null +++ b/frontend/app/framework/angular/forms/string-form-control.ts @@ -0,0 +1,39 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +// tslint:disable: readonly-array + +import { AbstractControlOptions, AsyncValidatorFn, FormControl, ValidatorFn } from '@angular/forms'; + +type ValueOptions = { + onlySelf?: boolean; + emitEvent?: boolean; + emitModelToViewChange?: boolean; + emitViewToModelChange?: boolean; +}; + +export class StringFormControl extends FormControl { + constructor(formState?: any, validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null) { + super(formState, validatorOrOpts, asyncValidator); + } + + public setValue(value: any, options?: ValueOptions) { + if (value === '') { + value = undefined; + } + + super.setValue(value, options); + } + + public patchValue(value: any, options?: ValueOptions) { + if (value === '') { + value = undefined; + } + + super.patchValue(value, options); + } +} \ No newline at end of file diff --git a/frontend/app/framework/declarations.ts b/frontend/app/framework/declarations.ts index c8c825b34..7c64e1a7b 100644 --- a/frontend/app/framework/declarations.ts +++ b/frontend/app/framework/declarations.ts @@ -29,6 +29,7 @@ export * from './angular/forms/form-hint.component'; export * from './angular/forms/forms-helper'; export * from './angular/forms/indeterminate-value.directive'; export * from './angular/forms/progress-bar.component'; +export * from './angular/forms/string-form-control'; export * from './angular/forms/transform-input.directive'; export * from './angular/forms/validators'; diff --git a/frontend/app/framework/utils/pager.spec.ts b/frontend/app/framework/utils/pager.spec.ts index ae4d43834..2d73c868a 100644 --- a/frontend/app/framework/utils/pager.spec.ts +++ b/frontend/app/framework/utils/pager.spec.ts @@ -235,5 +235,7 @@ describe('Pager', () => { pager.saveTo('my', localStore.object); localStore.verify(x => x.setInt('my.pageSize', 25), Times.once()); + + expect().nothing(); }); }); \ No newline at end of file diff --git a/frontend/app/framework/utils/types.spec.ts b/frontend/app/framework/utils/types.spec.ts index fdd2edf34..c1ccdddde 100644 --- a/frontend/app/framework/utils/types.spec.ts +++ b/frontend/app/framework/utils/types.spec.ts @@ -173,6 +173,26 @@ describe('Types', () => { expect(Types.equals({ a: [1, 2] }, { a: [1, 2] })).toBeTruthy(); }); + const FalsyValues = [false, null, 0]; + + it('should compare empty string with undefined', () => { + expect(Types.equals('', undefined, true)).toBeTruthy(); + expect(Types.equals('', undefined, false)).toBeFalsy(); + + expect(Types.equals(undefined, '', true)).toBeTruthy(); + expect(Types.equals(undefined, '', false)).toBeFalsy(); + }); + + FalsyValues.forEach(x => { + it(`should compare empty string with {x}`, () => { + expect(Types.equals('', x, true)).toBeFalsy(); + expect(Types.equals('', x, false)).toBeFalsy(); + + expect(Types.equals(x, '', true)).toBeFalsy(); + expect(Types.equals(x, '', false)).toBeFalsy(); + }); + }); + it('should clone array', () => { const source = [1, 2, 3]; const result = Types.clone(source); diff --git a/frontend/app/framework/utils/types.ts b/frontend/app/framework/utils/types.ts index 5c40b4e35..5d9d936d9 100644 --- a/frontend/app/framework/utils/types.ts +++ b/frontend/app/framework/utils/types.ts @@ -126,11 +126,21 @@ export module Types { return lhs; } - export function equals(lhs: any, rhs: any) { + export function equals(lhs: any, rhs: any, lazyString = false) { if (lhs === rhs || (lhs !== lhs && rhs !== rhs)) { return true; } + if (lazyString) { + const result = + (lhs === '' && Types.isUndefined(rhs) || + (rhs === '' && Types.isUndefined(lhs))); + + if (result) { + return true; + } + } + if (!lhs || !rhs) { return false; } @@ -141,7 +151,7 @@ export module Types { } for (let i = 0; i < lhs.length; i++) { - if (!equals(lhs[i], rhs[i])) { + if (!equals(lhs[i], rhs[i], lazyString)) { return false; } } @@ -154,7 +164,7 @@ export module Types { for (let key in lhs) { if (lhs.hasOwnProperty(key)) { - if (!equals(lhs[key], rhs[key])) { + if (!equals(lhs[key], rhs[key], lazyString)) { return false; } } diff --git a/frontend/app/shared/components/forms/references-dropdown.component.ts b/frontend/app/shared/components/forms/references-dropdown.component.ts index 524bc216d..9265f681b 100644 --- a/frontend/app/shared/components/forms/references-dropdown.component.ts +++ b/frontend/app/shared/components/forms/references-dropdown.component.ts @@ -86,21 +86,23 @@ export class ReferencesDropdownComponent extends StatefulControlComponent { - if (value && value.id) { - this.callTouched(); - - if (this.mode === 'Single') { - this.callChange(value.id); + if (this.selectionControl.enabled) { + if (value && value.id) { + this.callTouched(); + + if (this.mode === 'Single') { + this.callChange(value.id); + } else { + this.callChange([value.id]); + } } else { - this.callChange([value.id]); - } - } else { - this.callTouched(); + this.callTouched(); - if (this.mode === 'Single') { - this.callChange(null); - } else { - this.callChange([]); + if (this.mode === 'Single') { + this.callChange(null); + } else { + this.callChange([]); + } } } })); diff --git a/frontend/app/shared/state/contents.forms.ts b/frontend/app/shared/state/contents.forms.ts index df5f2768f..e668e109f 100644 --- a/frontend/app/shared/state/contents.forms.ts +++ b/frontend/app/shared/state/contents.forms.ts @@ -7,13 +7,14 @@ // tslint:disable:prefer-for-of -import { FormArray, FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'; +import { FormArray, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; import { BehaviorSubject } from 'rxjs'; import { DateTime, Form, formControls, + StringFormControl, Types, ValidatorsEx, value$ @@ -483,11 +484,12 @@ export class EditContentForm extends Form { for (const { key, isOptional } of this.partitions.getAll(field)) { const fieldValidators = FieldsValidators.create(field, isOptional); - if (field.isArray) { - fieldForm.setControl(key, new FormArray([], fieldValidators)); - } else { - fieldForm.setControl(key, new FormControl(fieldDefault, fieldValidators)); - } + const control = + field.isArray ? + new FormArray([], fieldValidators) : + new StringFormControl(fieldDefault, fieldValidators); + + fieldForm.setControl(key, control); } this.form.setControl(field.name, fieldForm); @@ -501,13 +503,13 @@ export class EditContentForm extends Form { public hasChanged() { const currentValue = this.form.getRawValue(); - return !Types.equals(this.initialData, currentValue); + return !Types.equals(this.initialData, currentValue, true); } public hasChanges(changes: any) { const currentValue = this.form.getRawValue(); - return !Types.equals(changes, currentValue); + return !Types.equals(changes, currentValue, true); } public arrayItemRemove(field: RootFieldDto, language: AppLanguageDto, index: number) { @@ -546,7 +548,7 @@ export class EditContentForm extends Form { } const nestedValidators = FieldsValidators.create(nestedField, partition.isOptional); - const nestedForm = new FormControl(value, nestedValidators); + const nestedForm = new StringFormControl(value, nestedValidators); if (nestedField.isDisabled) { nestedForm.disable(NO_EMIT); @@ -673,7 +675,7 @@ export class PatchContentForm extends Form { for (const field of this.editableFields) { const validators = FieldsValidators.create(field, this.language.isOptional); - this.form.setControl(field.name, new FormControl(undefined, validators)); + this.form.setControl(field.name, new StringFormControl(undefined, validators)); } } diff --git a/frontend/app/shared/state/table-fields.spec.ts b/frontend/app/shared/state/table-fields.spec.ts index 544948124..3e9c9204c 100644 --- a/frontend/app/shared/state/table-fields.spec.ts +++ b/frontend/app/shared/state/table-fields.spec.ts @@ -20,7 +20,7 @@ import { UIState } from '@app/shared/internal'; -describe('TableFielsd', () => { +describe('TableFields', () => { let uiState: IMock; const schema = @@ -82,6 +82,8 @@ describe('TableFielsd', () => { tableFields.updateFields(test.fields, true); uiState.verify(x => x.removeUser('schemas.my-schema.view'), Times.once()); + + expect().nothing(); }); }); @@ -119,5 +121,7 @@ describe('TableFielsd', () => { tableFields.updateFields(config, true); uiState.verify(x => x.set('schemas.my-schema.view', [MetaFields.version], true), Times.once()); + + expect().nothing(); }); }); \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index bec56c874..e4955a09c 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@angular-devkit/build-optimizer": { - "version": "0.900.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.900.1.tgz", - "integrity": "sha512-EnIU+ogiJrUPf8+fuPE5xQ+j/qUZDZ/SmLs8XAOmvoOBpZ0vPNedrHBHCxmV+ACbCxHGmIKQ/ZL29XUYVasteg==", + "version": "0.900.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.900.3.tgz", + "integrity": "sha512-VLAWtAXpOzOoYUJrN6sT90UdIdvrVIipkzGz7nfI1kscDvxUFwVZnsNNHtFinaY2SfZAunHhYQOA/B9FJ8WPdQ==", "dev": true, "requires": { "loader-utils": "1.2.3", @@ -76,9 +76,9 @@ } }, "@angular-devkit/core": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-9.0.1.tgz", - "integrity": "sha512-HboJI/x+SJD9clSOAMjHRv0eXAGRAdEaqJGmjDfdFMP2wznfsBiC6cgcHC17oM4jRWFhmWMR8Omc7CjLZJawJg==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-9.0.3.tgz", + "integrity": "sha512-3+abmv9K9d+BVgUAolYgoOqlGAA2Jb1pWo2biapSDG6KjUZHUCJdnsKigLtLorCdv0SrjTp56FFplkcqKsFQgA==", "dev": true, "requires": { "ajv": "6.10.2", @@ -148,33 +148,33 @@ } }, "@angular/animations": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-9.0.0.tgz", - "integrity": "sha512-jB8+SC3vMztW5zt5UYVmtVwqIWE33UyEjbP5JPba3I3bLRK5E059LcJmN1rSdJHItgIAdG9Y1I0WJ6aiSFyp4Q==" + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-9.0.2.tgz", + "integrity": "sha512-vj4N8nSLytQI45TtGy2tJb0Yc7uqlyap+qhghc+jdyG41w18KQUnIneEWKOfHWnp8VJEfzgzaY7zr/1QPlxWgA==" }, "@angular/cdk": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-9.0.0.tgz", - "integrity": "sha512-2kYpyYbewIB6fubSIDMvSprJLNplRZoL/AtXW3od4dLyRxtzX+7iWTAtzUG/dhq8CKev0lpd1HENh5lLR/Lhjw==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-9.0.1.tgz", + "integrity": "sha512-slhYG9lOX7JoxcULdfIvXspkDRjYTBG8PH6B2Slxi8CpV42x0t+yQnBQxp/U3ud1m1BWVrlxwKZywaPFe1tSeA==", "requires": { "parse5": "^5.0.0" } }, "@angular/common": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-9.0.0.tgz", - "integrity": "sha512-ZMmEClGtUNJwV5CBlqcSHPIsNyz6WU/GvKWFzJ5VZc68oeg1e7lqfNMNIC47TjyolNJ7VSpNlyrKjzfdBlmqVw==" + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-9.0.2.tgz", + "integrity": "sha512-KYOov8fg5WX/bAMkemlcAZxqiq/6ga1BoxjaiZXBj07KDq8i5Nwcm6RmNkeDByCuXd2UHVm1w5t897wEUi6fnw==" }, "@angular/compiler": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz", - "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.2.tgz", + "integrity": "sha512-IWlKn5v3y7k1Z2K2wfNNzbn9xgA4fFlWyPe9QpdS8iy6/bPe5GfKhHbMYIza5eIhPXDN93zdEptiAIXGP3kLBQ==", "dev": true }, "@angular/compiler-cli": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-9.0.0.tgz", - "integrity": "sha512-6L3swd3Z2ceAapmioml6z7yu3bYC2aVm3/rgK7eCoZtPcevuvTpGnXcFSVvNgByV51GntgInThPbMx0xY23Rvw==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-9.0.2.tgz", + "integrity": "sha512-2AAZr1jX72OG9k1viVShiDGAwV9PZEcoDt80PXkUjLTUwWxicuSBKYauph47PzK/qzqWhdbvMbh8wCWHSLq0Qg==", "dev": true, "requires": { "canonical-path": "1.0.0", @@ -199,38 +199,38 @@ } }, "@angular/core": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz", - "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==" + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.2.tgz", + "integrity": "sha512-ccVPR6RZo2s9O9phO0TJ60QZ0WA7qfUMzo0xnpBW0XGcbTzLEn9upvs+0PX64f9UpnHz/MQo0wsqYvTLuoz7Yw==" }, "@angular/forms": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-9.0.0.tgz", - "integrity": "sha512-SIYJc0Rgaihow1t+iiwSFGEvvRgssgUuxwIYbMfCp1Sx513K+JX9nVFXqU+dcGj/eF1u5wwYwbvlVyuMQLzmXg==" + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-9.0.2.tgz", + "integrity": "sha512-qXEth7yeCd+5i6QyvllXnh/Rkzh16raFX5nfI7mgKHjWMik15Ua8wkVhDX9b5gizWeEyZtZcMGsTbbOQy0Ft3Q==" }, "@angular/platform-browser": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.0.0.tgz", - "integrity": "sha512-2PR/o57HjZvKEnAF8ODeqxmeC90oth9dLTMrJNoI5MET0IeErKeI/9Sl5cLQuXC+lSVN5rOMCvDb74VWSno5yw==" + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.0.2.tgz", + "integrity": "sha512-RMivdtJtspYLH/96AzLwLj3v0O9ck0sL6R1uh5JacfBkmedqJzmLn+AOxTdjaGdIpFtw9tisT+0Aw/nkG14vlA==" }, "@angular/platform-browser-dynamic": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.0.0.tgz", - "integrity": "sha512-F1kbEpmDottTemRPEOAz2Te5ABVJ7wypfzBllxqXbdxPHvYLfL8db2dXyiGqABQ3ZFHPLNilrkUTy0sbuuU4OA==" + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.0.2.tgz", + "integrity": "sha512-RJa+Y83hIFcf7pFcbbaCi7M5Y9nUUcQVuazWbQtiUe+BY5pikyug4RsF2B10pctcxb6LFLElfmkvatmmwEQ9aQ==" }, "@angular/platform-server": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-9.0.0.tgz", - "integrity": "sha512-wIHZdv7WCtuZ6pgj1n/H2V7KbUxUBfrb1PJzVnCWzpMQDIf+jrMxLlB2irpYb/HHh4tOem6dHX5JV45A2sJ5/w==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-9.0.2.tgz", + "integrity": "sha512-GXpEKMACf648vEGt5n/5XXHWd5Tf5D/x4sjbPCasgZ4uIrtSy3SDrJrQl8rxvFQkv804eBnC5CH9ckEFj8g9QQ==", "requires": { "domino": "^2.1.2", "xhr2": "^0.1.4" } }, "@angular/router": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.0.0.tgz", - "integrity": "sha512-yyOcStpgN5t8wGRNO85mo0jplXkntP+v2tmSxNx45pahqmofSFm+QCEFa2zHQuMr7NoiGERhd0Tae7NDCCjtjA==" + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.0.2.tgz", + "integrity": "sha512-jDKq9K0pOgaMtocg7VCfIQX8jTyBSb+0hjOcj6kXQVCcmnxeBzGPRX2THQyFkyzG8owTBZlHIrJA3H2thDU2LQ==" }, "@babel/code-frame": { "version": "7.8.3", @@ -408,12 +408,12 @@ "dev": true }, "@ngtools/webpack": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-9.0.1.tgz", - "integrity": "sha512-SG1MDVSC7pIuaX1QYTh94k/YJa6w2OR2RNbghkDXToDzDv6bKnTQYoJPyXk+gwfDTVD4V5z2dKSNbxFzWleFpg==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-9.0.3.tgz", + "integrity": "sha512-pMIXfq1IJLbvwmkPonGs7nrpuBCXrlZTf9A4OYsMBZcfU8JMn0pRdx7G2+bC9Q/f+uSw2uvPSv76xJXLBOntmA==", "dev": true, "requires": { - "@angular-devkit/core": "9.0.1", + "@angular-devkit/core": "9.0.3", "enhanced-resolve": "4.1.1", "rxjs": "6.5.3", "webpack-sources": "1.4.3" @@ -462,9 +462,9 @@ } }, "@types/core-js": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@types/core-js/-/core-js-2.5.2.tgz", - "integrity": "sha512-+NPqjXgyA02xTHKJDeDca9u8Zr42ts6jhdND4C3PrPeQ35RJa0dmfAedXW7a9K4N1QcBbuWI1nSfGK4r1eVFCQ==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@types/core-js/-/core-js-2.5.3.tgz", + "integrity": "sha512-F9RHpjuPSit4dCCRXgi7XcqA01DAjy9QY+v9yICoxXsjXD9cgQpyZyL2eSZnTkBGXGaQnea8waZOZTogLDB+rA==", "dev": true }, "@types/events": { @@ -485,9 +485,9 @@ } }, "@types/jasmine": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.3.tgz", - "integrity": "sha512-LRJ21f/BO4QNZ3YDaMP0OEurOfE77x8mi8MfEnUsei5IKfmZL0GKl7juhABMdUIJHhVS9OCLotKHfsFNAuJ+DA==", + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.5.tgz", + "integrity": "sha512-LlhwGivHkUV8ehNmaXjGGXopLm91G9ORIRcjw7Ya47jVAIGudewFZM2PdPXBvueZfRWwYzLt083wiPfKRXrSlg==", "dev": true }, "@types/json5": { @@ -521,9 +521,9 @@ "dev": true }, "@types/node": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.0.tgz", - "integrity": "sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ==", + "version": "13.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.4.tgz", + "integrity": "sha512-oVeL12C6gQS/GAExndigSaLxTrKpQPxewx9bOcwfvJiJge4rr7wNaph4J+ns5hrmIV2as5qxqN8YKthn9qh0jw==", "dev": true }, "@types/prop-types": { @@ -539,9 +539,9 @@ "dev": true }, "@types/react": { - "version": "16.9.19", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.19.tgz", - "integrity": "sha512-LJV97//H+zqKWMms0kvxaKYJDG05U2TtQB3chRLF8MPNs+MQh/H1aGlyDUxjaHvu08EAGerdX2z4LTBc7ns77A==", + "version": "16.9.21", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.21.tgz", + "integrity": "sha512-xpmenCMeBwJRct8vmIfczlgdOXWIWASoOM857kxKfHlVQvDltRh7IFRVfGws79iO2jkNPXOeWREyKoClzhBaQA==", "dev": true, "requires": { "@types/prop-types": "*", @@ -1735,14 +1735,14 @@ } }, "browserslist": { - "version": "4.8.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.6.tgz", - "integrity": "sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg==", + "version": "4.8.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.7.tgz", + "integrity": "sha512-gFOnZNYBHrEyUML0xr5NJ6edFaaKbTFX9S9kQHlYfCP0Rit/boRIz4G+Avq6/4haEKJXdGGUnoolx+5MWW2BoA==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001023", - "electron-to-chromium": "^1.3.341", - "node-releases": "^1.1.47" + "caniuse-lite": "^1.0.30001027", + "electron-to-chromium": "^1.3.349", + "node-releases": "^1.1.49" } }, "buffer": { @@ -1988,9 +1988,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001025", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001025.tgz", - "integrity": "sha512-SKyFdHYfXUZf5V85+PJgLYyit27q4wgvZuf8QTOk1osbypcROihMBlx9GRar2/pIcKH2r4OehdlBr9x6PXetAQ==", + "version": "1.0.30001028", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001028.tgz", + "integrity": "sha512-Vnrq+XMSHpT7E+LWoIYhs3Sne8h9lx9YJV3acH3THNCwU/9zV93/ta4xVfzTtnqd3rvnuVpVjE3DFqf56tr3aQ==", "dev": true }, "canonical-path": { @@ -2065,9 +2065,9 @@ } }, "chownr": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", - "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true }, "chrome-trace-event": { @@ -3045,9 +3045,9 @@ } }, "csstype": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.8.tgz", - "integrity": "sha512-msVS9qTuMT5zwAGCVm4mxfrZ18BNc6Csd0oJAtiFMZ1FAx1CCvy2+5MDmYoix63LM/6NDbNtodCiGYGmFgO0dA==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.9.tgz", + "integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==", "dev": true }, "currently-unhandled": { @@ -3536,9 +3536,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.345", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.345.tgz", - "integrity": "sha512-f8nx53+Z9Y+SPWGg3YdHrbYYfIJAtbUjpFfW4X1RwTZ94iUG7geg9tV8HqzAXX7XTNgyWgAFvce4yce8ZKxKmg==", + "version": "1.3.355", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.355.tgz", + "integrity": "sha512-zKO/wS+2ChI/jz9WAo647xSW8t2RmgRLFdbUb/77cORkUTargO+SCj4ctTHjBn2VeNFrsLgDT7IuDVrd3F8mLQ==", "dev": true }, "elliptic": { @@ -4285,12 +4285,12 @@ } }, "file-loader": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-5.0.2.tgz", - "integrity": "sha512-QMiQ+WBkGLejKe81HU8SZ9PovsU/5uaLo0JdTCEXOYv7i7jfAjHZi1tcwp9tSASJPOmmHZtbdCervFmXMH/Dcg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-5.1.0.tgz", + "integrity": "sha512-u/VkLGskw3Ue59nyOwUwXI/6nuBCo7KBkniB/l7ICwr/7cPNGsL1WCXUp3GB0qgOOKU1TiP49bv4DZF/LJqprg==", "dev": true, "requires": { - "loader-utils": "^1.2.3", + "loader-utils": "^1.4.0", "schema-utils": "^2.5.0" }, "dependencies": { @@ -4318,6 +4318,12 @@ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, "fast-deep-equal": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", @@ -4340,13 +4346,13 @@ } }, "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", "dev": true, "requires": { "big.js": "^5.2.2", - "emojis-list": "^2.0.0", + "emojis-list": "^3.0.0", "json5": "^1.0.1" } }, @@ -4430,9 +4436,9 @@ }, "dependencies": { "make-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", - "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz", + "integrity": "sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w==", "dev": true, "requires": { "semver": "^6.0.0" @@ -6788,9 +6794,9 @@ } }, "karma-jasmine": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-3.1.0.tgz", - "integrity": "sha512-IVGbC8gap5x5NNCEOsAE77ic8rZtHDt6wmO0fFC5yT5FeB8qKnGTeud2mtKyQ41xl7vZkZ7ZxKr4wMGR6tWN+A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-3.1.1.tgz", + "integrity": "sha512-pxBmv5K7IkBRLsFSTOpgiK/HzicQT3mfFF+oHAC7nxMfYKhaYFgxOa5qjnHW4sL5rUnmdkSajoudOnnOdPyW4Q==", "dev": true, "requires": { "jasmine-core": "^3.5.0" @@ -7752,9 +7758,9 @@ } }, "node-releases": { - "version": "1.1.48", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.48.tgz", - "integrity": "sha512-Hr8BbmUl1ujAST0K0snItzEA5zkJTQup8VNTKNfT6Zw8vTJkIiagUPNfxHmgDOyfFYNfKAul40sD0UEYTvwebw==", + "version": "1.1.49", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.49.tgz", + "integrity": "sha512-xH8t0LS0disN0mtRCh+eByxFPie+msJUBL/lJDBuap53QGiYPa9joh83K4pCZgWJ+2L4b9h88vCVdXQ60NO2bg==", "dev": true, "requires": { "semver": "^6.3.0" @@ -10444,9 +10450,9 @@ "dev": true }, "rimraf": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.1.tgz", - "integrity": "sha512-IQ4ikL8SjBiEDZfk+DFVwqRK8md24RWMEJkdSlgNLkyyAImcjf8SWvU1qFMDOb4igBClbTQ/ugPqXcRwdFTxZw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" @@ -12125,9 +12131,9 @@ } }, "terser-webpack-plugin": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.4.tgz", - "integrity": "sha512-Nv96Nws2R2nrFOpbzF6IxRDpIkkIfmhvOws+IqMvYdFLO7o6wAILWFKONFgaYy8+T4LVz77DQW0f7wOeDEAjrg==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.5.tgz", + "integrity": "sha512-WlWksUoq+E4+JlJ+h+U+QUzXpcsMSSNXkDy9lBVkSqDn1w23Gg29L/ary9GeJVYCGiNJJX7LnVc4bwL1N3/g1w==", "dev": true, "requires": { "cacache": "^13.0.1", @@ -13651,9 +13657,9 @@ } }, "webpack": { - "version": "4.41.5", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.5.tgz", - "integrity": "sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw==", + "version": "4.41.6", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.6.tgz", + "integrity": "sha512-yxXfV0Zv9WMGRD+QexkZzmGIh54bsvEs+9aRWxnN8erLWEOehAKUTeNBoUbA6HPEZPlRo7KDi2ZcNveoZgK9MA==", "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", @@ -13763,6 +13769,12 @@ "y18n": "^4.0.0" } }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, "fast-deep-equal": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", @@ -13859,13 +13871,13 @@ } }, "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", "dev": true, "requires": { "big.js": "^5.2.2", - "emojis-list": "^2.0.0", + "emojis-list": "^3.0.0", "json5": "^1.0.1" } }, @@ -14037,9 +14049,9 @@ } }, "webpack-cli": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.10.tgz", - "integrity": "sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.11.tgz", + "integrity": "sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g==", "dev": true, "requires": { "chalk": "2.4.2", diff --git a/frontend/package.json b/frontend/package.json index 9dfbc0016..c111c0f94 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,15 +16,15 @@ "postinstall": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points" }, "dependencies": { - "@angular/animations": "9.0.0", - "@angular/cdk": "9.0.0", - "@angular/common": "9.0.0", - "@angular/core": "9.0.0", - "@angular/forms": "9.0.0", - "@angular/platform-browser": "9.0.0", - "@angular/platform-browser-dynamic": "9.0.0", - "@angular/platform-server": "9.0.0", - "@angular/router": "9.0.0", + "@angular/animations": "9.0.2", + "@angular/cdk": "9.0.1", + "@angular/common": "9.0.2", + "@angular/core": "9.0.2", + "@angular/forms": "9.0.2", + "@angular/platform-browser": "9.0.2", + "@angular/platform-browser-dynamic": "9.0.2", + "@angular/platform-server": "9.0.2", + "@angular/router": "9.0.2", "angular-mentions": "^1.1.3", "angular2-chartjs": "0.5.1", "babel-polyfill": "6.26.0", @@ -50,26 +50,26 @@ "zone.js": "0.10.2" }, "devDependencies": { - "@angular-devkit/build-optimizer": "^0.900.1", - "@angular/compiler": "9.0.0", - "@angular/compiler-cli": "9.0.0", - "@ngtools/webpack": "9.0.1", - "@types/core-js": "2.5.2", - "@types/jasmine": "3.5.3", + "@angular-devkit/build-optimizer": "^0.900.3", + "@angular/compiler": "9.0.2", + "@angular/compiler-cli": "9.0.2", + "@ngtools/webpack": "9.0.3", + "@types/core-js": "2.5.3", + "@types/jasmine": "3.5.5", "@types/marked": "0.7.2", "@types/mersenne-twister": "1.1.2", "@types/mousetrap": "1.6", - "@types/node": "13.7.0", - "@types/react": "16.9.19", + "@types/node": "13.7.4", + "@types/react": "16.9.21", "@types/react-dom": "16.9.5", - "browserslist": "4.8.6", - "caniuse-lite": "1.0.30001025", + "browserslist": "4.8.7", + "caniuse-lite": "1.0.30001028", "circular-dependency-plugin": "5.2.0", "codelyzer": "5.2.1", "css-loader": "3.4.2", "cssnano": "^4.1.10", "entities": "^2.0.0", - "file-loader": "5.0.2", + "file-loader": "5.1.0", "html-loader": "0.5.5", "html-webpack-plugin": "3.2.0", "ignore-loader": "0.1.2", @@ -80,7 +80,7 @@ "karma-cli": "2.0.0", "karma-coverage-istanbul-reporter": "2.1.1", "karma-htmlfile-reporter": "0.3.8", - "karma-jasmine": "3.1.0", + "karma-jasmine": "3.1.1", "karma-jasmine-html-reporter": "1.5.2", "karma-mocha-reporter": "2.2.5", "karma-sourcemap-loader": "0.3.7", @@ -93,14 +93,14 @@ "postcss-preset-env": "^6.7.0", "raw-loader": "4.0.0", "resize-observer-polyfill": "^1.5.1", - "rimraf": "3.0.1", + "rimraf": "3.0.2", "rxjs-tslint": "0.1.7", "sass-lint": "^1.13.1", "sass-lint-webpack": "^1.0.2", "sass-loader": "8.0.2", "style-loader": "1.1.3", "sugarss": "^2.0.0", - "terser-webpack-plugin": "2.3.4", + "terser-webpack-plugin": "2.3.5", "ts-loader": "6.2.1", "tsconfig-paths-webpack-plugin": "3.2.0", "tslint": "6.0.0", @@ -109,9 +109,9 @@ "typemoq": "2.1.0", "typescript": "3.7.5", "underscore": "1.9.2", - "webpack": "4.41.5", + "webpack": "4.41.6", "webpack-bundle-analyzer": "^3.6.0", - "webpack-cli": "3.3.10", + "webpack-cli": "3.3.11", "webpack-dev-server": "3.10.3" } }