Browse Source

Tests fixed.

pull/297/head
Sebastian 8 years ago
parent
commit
24b7b8af20
  1. 37
      src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs
  2. 44
      src/Squidex/app/framework/angular/forms/forms-helper.ts
  3. 1
      src/Squidex/app/framework/declarations.ts
  4. 1
      src/Squidex/app/framework/internal.ts
  5. 40
      src/Squidex/app/framework/state.ts
  6. 42
      src/Squidex/app/framework/utils/lazy.spec.ts
  7. 24
      src/Squidex/app/framework/utils/lazy.ts
  8. 6
      src/Squidex/app/shared/services/schemas.service.spec.ts
  9. 46
      src/Squidex/app/shared/services/schemas.service.ts
  10. 10
      src/Squidex/app/shared/state/contents.forms.spec.ts
  11. 65
      src/Squidex/app/shared/state/contents.forms.ts
  12. 12
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs

37
src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs

@ -233,15 +233,20 @@ namespace Squidex.Domain.Apps.Core.ConvertContent
{
if (field is IArrayField arrayField)
{
var result = new ContentFieldData();
foreach (var partition in data)
{
if (partition.Value is JArray jArray)
{
for (var i = 0; i < jArray.Count; i++)
if (!(partition.Value is JArray jArray))
{
if (jArray[i] is JObject item)
continue;
}
var newArray = new JArray();
foreach (JObject item in jArray.OfType<JObject>())
{
var result = new JObject();
var newItem = new JObject();
foreach (var kvp in item)
{
@ -272,15 +277,17 @@ namespace Squidex.Domain.Apps.Core.ConvertContent
if (!isUnset)
{
result.Add(keyResolver(nestedField), newValue);
newItem.Add(keyResolver(nestedField), newValue);
}
}
jArray[i] = result;
}
}
newArray.Add(newItem);
}
result.Add(partition.Key, newArray);
}
return result;
}
return data;
@ -293,7 +300,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent
{
if (!(field is IArrayField))
{
ContentFieldData result = null;
var result = new ContentFieldData();
foreach (var partition in data)
{
@ -315,21 +322,13 @@ namespace Squidex.Domain.Apps.Core.ConvertContent
}
}
if (result != null || isUnset || !ReferenceEquals(newValue, partition.Value))
{
if (result == null)
{
result = new ContentFieldData();
}
if (!isUnset)
{
result.Add(partition.Key, newValue);
}
}
}
return result ?? data;
return result;
}
return data;

44
src/Squidex/app/framework/angular/forms/forms-helper.ts

@ -0,0 +1,44 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { AbstractControl, FormArray, FormGroup } from '@angular/forms';
import { Types } from '@app/framework/internal';
export const formControls = (form: AbstractControl): AbstractControl[] => {
if (Types.is(form, FormGroup)) {
return Object.values(form.controls);
} else if (Types.is(form, FormArray)) {
return form.controls;
} else {
return [];
}
};
export const fullValue = (form: AbstractControl): any => {
if (Types.is(form, FormGroup)) {
const groupValue = {};
for (let key in form.controls) {
if (form.controls.hasOwnProperty(key)) {
groupValue[key] = fullValue(form.controls[key]);
}
}
return groupValue;
} else if (Types.is(form, FormArray)) {
const arrayValue = [];
for (let child of form.controls) {
arrayValue.push(fullValue(child));
}
return arrayValue;
} else {
return form.value;
}
};

1
src/Squidex/app/framework/declarations.ts

@ -14,6 +14,7 @@ export * from './angular/forms/dropdown.component';
export * from './angular/forms/file-drop.directive';
export * from './angular/forms/focus-on-init.directive';
export * from './angular/forms/form-error.component';
export * from './angular/forms/forms-helper';
export * from './angular/forms/iframe-editor.component';
export * from './angular/forms/indeterminate-value.directive';
export * from './angular/forms/jscript-editor.component';

1
src/Squidex/app/framework/internal.ts

@ -23,6 +23,7 @@ export * from './utils/date-time';
export * from './utils/duration';
export * from './utils/error';
export * from './utils/immutable-array';
export * from './utils/lazy';
export * from './utils/math-helper';
export * from './utils/modal-view';
export * from './utils/pager';

40
src/Squidex/app/framework/state.ts

@ -5,11 +5,11 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { AbstractControl, FormArray, FormGroup } from '@angular/forms';
import { AbstractControl } from '@angular/forms';
import { BehaviorSubject, Observable } from 'rxjs';
import { ErrorDto } from './utils/error';
import { Types } from './utils/types';
import { ErrorDto, Types } from '@app/framework/internal';
import { fullValue} from './angular/forms/forms-helper';
export interface FormState {
submitted: boolean;
@ -17,34 +17,6 @@ export interface FormState {
error?: string;
}
export class Lazy<T> {
private valueSet = false;
private valueField: T;
public get value(): T {
if (!this.valueSet) {
this.valueField = this.factory();
this.valueSet = true;
}
return this.valueField;
}
constructor(
private readonly factory: () => T
) {
}
}
export const formControls = (form: AbstractControl): AbstractControl[] => {
if (Types.is(form, FormGroup)) {
return Object.values(form.controls);
} else if (Types.is(form, FormArray)) {
return form.controls;
} else {
return [];
}
};
export class Form<T extends AbstractControl> {
private readonly state = new State<FormState>({ submitted: false });
@ -85,7 +57,7 @@ export class Form<T extends AbstractControl> {
this.state.next({ submitted: true });
if (this.form.valid) {
const value = this.form.value;
const value = fullValue(this.form);
this.disable();
@ -133,6 +105,10 @@ export class Model {
const clone = Object.assign(Object.create(Object.getPrototypeOf(this)), this, values);
if (Types.isFunction(clone.onCloned)) {
clone.onCloned();
}
return clone;
}
}

42
src/Squidex/app/framework/utils/lazy.spec.ts

@ -0,0 +1,42 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Lazy } from './lazy';
describe('Lazy', () => {
it('should provider value', () => {
const lazy = new Lazy(() => 1);
expect(lazy.value).toBe(1);
});
it('should call delegate once', () => {
let called = 0;
const lazy = new Lazy(() => {
called++;
return 13;
});
expect(lazy.value).toBe(13);
expect(lazy.value).toBe(13);
expect(called).toBe(1);
});
it('should call delegate once when returned undefined', () => {
let called = 0;
const lazy = new Lazy(() => {
called++;
return undefined;
});
expect(lazy.value).toBeUndefined();
expect(lazy.value).toBeUndefined();
expect(called).toBe(1);
});
});

24
src/Squidex/app/framework/utils/lazy.ts

@ -0,0 +1,24 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
export class Lazy<T> {
private valueSet = false;
private valueField: T;
public get value(): T {
if (!this.valueSet) {
this.valueField = this.factory();
this.valueSet = true;
}
return this.valueField;
}
constructor(
private readonly factory: () => T
) {
}
}

6
src/Squidex/app/shared/services/schemas.service.spec.ts

@ -158,6 +158,7 @@ describe('SchemasService', () => {
{
fieldId: 101,
name: 'field101',
isLocked: true,
isHidden: true,
isDisabled: true,
properties: {
@ -167,6 +168,7 @@ describe('SchemasService', () => {
{
fieldId: 102,
name: 'field102',
isLocked: true,
isHidden: true,
isDisabled: true,
properties: {
@ -293,8 +295,8 @@ describe('SchemasService', () => {
new Version('2'),
[
new RootFieldDto(11, 'field11', createProperties('Array'), 'language', true, true, true, [
new NestedFieldDto(101, 'field101', createProperties('String'), 11, true, true),
new NestedFieldDto(102, 'field102', createProperties('Number'), 11, true, true)
new NestedFieldDto(101, 'field101', createProperties('String'), 11, true, true, true),
new NestedFieldDto(102, 'field102', createProperties('Number'), 11, true, true, true)
]),
new RootFieldDto(12, 'field12', createProperties('Assets'), 'language', true, true, true),
new RootFieldDto(13, 'field13', createProperties('Boolean'), 'language', true, true, true),

46
src/Squidex/app/shared/services/schemas.service.ts

@ -16,7 +16,6 @@ import {
ApiUrlConfig,
DateTime,
HTTP,
Lazy,
Model,
StringHelper,
Version,
@ -26,10 +25,8 @@ import {
import { createProperties, FieldPropertiesDto } from './schemas.types';
export class SchemaDto extends Model {
private readonly displayNameValue = new Lazy((() => StringHelper.firstNonEmpty(this.properties.label, this.name)));
public get displayName() {
return this.displayNameValue.value;
return StringHelper.firstNonEmpty(this.properties.label, this.name);
}
constructor(
@ -53,8 +50,24 @@ export class SchemaDto extends Model {
}
export class SchemaDetailsDto extends SchemaDto {
private inlineEditableFieldsValue = new Lazy(() => this.listFields.filter(x => x.isInlineEditable));
private listFieldsValue = new Lazy(() => {
public listFields: RootFieldDto[];
public listFieldsEditable: RootFieldDto[];
constructor(id: string, name: string, category: string, properties: SchemaPropertiesDto, isPublished: boolean, created: DateTime, createdBy: string, lastModified: DateTime, lastModifiedBy: string, version: Version,
public readonly fields: RootFieldDto[],
public readonly scriptQuery?: string,
public readonly scriptCreate?: string,
public readonly scriptUpdate?: string,
public readonly scriptDelete?: string,
public readonly scriptChange?: string
) {
super(id, name, category, properties, isPublished, created, createdBy, lastModified, lastModifiedBy, version);
this.onCloned();
}
protected onCloned() {
if (this.fields) {
let fields = this.fields.filter(x => x.properties.isListField);
if (fields.length === 0 && this.fields.length > 0) {
@ -65,26 +78,9 @@ export class SchemaDetailsDto extends SchemaDto {
fields = [<any>{ properties: {} }];
}
return fields;
});
public get inlineEditableFields() {
return this.inlineEditableFieldsValue.value;
}
public get listFields() {
return this.listFieldsValue.value;
this.listFields = fields;
this.listFieldsEditable = fields.filter(x => x.isInlineEditable);
}
constructor(id: string, name: string, category: string, properties: SchemaPropertiesDto, isPublished: boolean, created: DateTime, createdBy: string, lastModified: DateTime, lastModifiedBy: string, version: Version,
public readonly fields: RootFieldDto[],
public readonly scriptQuery?: string,
public readonly scriptCreate?: string,
public readonly scriptUpdate?: string,
public readonly scriptDelete?: string,
public readonly scriptChange?: string
) {
super(id, name, category, properties, isPublished, created, createdBy, lastModified, lastModifiedBy, version);
}
public with(value: Partial<SchemaDetailsDto>): SchemaDetailsDto {

10
src/Squidex/app/shared/state/contents.forms.spec.ts

@ -129,7 +129,7 @@ describe('ArrayField', () => {
});
it('should format to asset count', () => {
expect(FieldFormatter.format(field, [1, 2, 3])).toBe('3 Items(s)');
expect(FieldFormatter.format(field, [1, 2, 3])).toBe('3 Item(s)');
});
it('should return zero formatting if other type', () => {
@ -250,15 +250,15 @@ describe('DateTimeField', () => {
});
it('should return calculated date when Today for DateFieldProperties', () => {
Object.assign(field.properties, { calculatedFieldDefaultValue: 'Today' });
Object.assign(field.properties, { calculatedDefaultValue: 'Today' });
expect((<any>field).properties.getFieldDefaultValue(now)).toEqual('2017-10-12');
expect(FieldDefaultValue.get(field, now)).toEqual('2017-10-12');
});
it('should return calculated date when Now for DateFieldProperties', () => {
Object.assign(field.properties, { calculatedFieldDefaultValue: 'Now' });
Object.assign(field.properties, { calculatedDefaultValue: 'Now' });
expect((<any>field).properties.getFieldDefaultValue(now)).toEqual('2017-10-12T16:30:10Z');
expect(FieldDefaultValue.get(field, now)).toEqual('2017-10-12T16:30:10Z');
});
});

65
src/Squidex/app/shared/state/contents.forms.ts

@ -43,7 +43,7 @@ export class FieldFormatter implements FieldPropertiesVisitor<string> {
}
public static format(field: FieldDto, value: any) {
if (!value) {
if (value === null || value === undefined) {
return '';
}
@ -259,8 +259,25 @@ export class FieldValidatorsFactory implements FieldPropertiesVisitor<ValidatorF
}
export class FieldDefaultValue implements FieldPropertiesVisitor<any> {
public static get(field: FieldDto) {
return field.properties.accept(new FieldDefaultValue());
constructor(
private readonly now?: DateTime
) {
}
public visitDateTime(properties: DateTimeFieldPropertiesDto): any {
const now = this.now || DateTime.now();
if (properties.calculatedDefaultValue === 'Now') {
return now.toUTCStringFormat('YYYY-MM-DDTHH:mm:ss') + 'Z';
} else if (properties.calculatedDefaultValue === 'Today') {
return now.toUTCStringFormat('YYYY-MM-DD');
} else {
return properties.defaultValue;
}
}
public static get(field: FieldDto, now?: DateTime) {
return field.properties.accept(new FieldDefaultValue(now));
}
public visitArray(properties: ArrayFieldPropertiesDto): any {
@ -275,10 +292,6 @@ export class FieldDefaultValue implements FieldPropertiesVisitor<any> {
return properties.defaultValue;
}
public visitDateTime(properties: DateTimeFieldPropertiesDto): any {
return null;
}
public visitGeolocation(properties: GeolocationFieldPropertiesDto): any {
return null;
}
@ -388,16 +401,24 @@ export class EditContentForm extends Form<FormGroup> {
const fieldValue = value ? value[field.name] || {} : {};
const addControls = (key: string, language: AppLanguageDto | null) => {
const languageValue = fieldValue[key];
const languageForm = new FormArray([]);
const partitionValue = fieldValue[key];
if (Types.isArray(languageValue)) {
for (let i = 0; i < languageValue.length; i++) {
this.addArrayItem(field, language, languageForm);
}
let partitionForm = <FormArray>fieldForm.controls[key];
if (!partitionForm) {
partitionForm = new FormArray([]);
fieldForm.setControl(key, partitionForm);
}
fieldForm.setControl(key, languageForm);
const length = Types.isArray(partitionValue) ? partitionValue.length : 0;
while (partitionForm.controls.length < length) {
this.addArrayItem(field, language, partitionForm);
}
while (partitionForm.controls.length > length) {
partitionForm.removeAt(partitionForm.length - 1);
}
};
if (field.isLocalizable) {
@ -432,19 +453,21 @@ export class EditContentForm extends Form<FormGroup> {
continue;
}
if (field.properties.fieldType === 'Array') {
if (field.isArray) {
fieldForm.enable();
for (let partitionForm of formControls(fieldForm)) {
for (let itemForm of formControls(partitionForm)) {
for (let nested of field.nested) {
const nestedForm = partitionForm.get(nested.name);
const nestedForm = itemForm.get(nested.name);
if (!nestedForm) {
continue;
}
if (nested.isDisabled) {
nestedForm.disable();
} else {
nestedForm.enable();
nestedForm.disable({ onlySelf: true });
}
}
}
}
@ -464,7 +487,7 @@ export class PatchContentForm extends Form<FormGroup> {
) {
super(new FormGroup({}));
for (let field of this.schema.inlineEditableFields) {
for (let field of this.schema.listFieldsEditable) {
const validators = FieldValidatorsFactory.createValidators(field, this.language.isOptional);
this.form.setControl(field.name, new FormControl(undefined, validators));
@ -477,7 +500,7 @@ export class PatchContentForm extends Form<FormGroup> {
if (result) {
const request = {};
for (let field of this.schema.inlineEditableFields) {
for (let field of this.schema.listFieldsEditable) {
const value = result[field.name];
if (field.isLocalizable) {

12
tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs

@ -27,18 +27,6 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent
Fields.Number(1, "field1"),
Fields.Number(2, "field2").Hide());
[Fact]
public void Should_return_same_object_for_value_conversion_if_nothing_converted()
{
var input =
new ContentFieldData()
.AddValue("iv", new JObject());
var actual = FieldConverters.ForValues()(input, stringInvariantField);
Assert.Same(input, actual);
}
[Fact]
public void Should_filter_for_value_conversion()
{

Loading…
Cancel
Save