diff --git a/frontend/src/app/features/content/shared/forms/array-item.component.ts b/frontend/src/app/features/content/shared/forms/array-item.component.ts
index 38b161586..afff0429d 100644
--- a/frontend/src/app/features/content/shared/forms/array-item.component.ts
+++ b/frontend/src/app/features/content/shared/forms/array-item.component.ts
@@ -140,9 +140,14 @@ export class ArrayItemComponent implements OnChanges {
function getTitle(formModel: ObjectFormBase) {
const value = formModel.form.value;
const values: string[] = [];
+
+ let valueLength = 0;
if (Types.is(formModel, ComponentForm) && formModel.schema) {
- values.push(formModel.schema.displayName);
+ const formatted = formModel.schema.displayName;
+
+ values.push(formatted);
+ valueLength += formatted.length;
}
if (Types.is(formModel.field, RootFieldDto)) {
@@ -154,6 +159,11 @@ function getTitle(formModel: ObjectFormBase) {
if (formatted) {
values.push(formatted);
+ valueLength += formatted.length;
+
+ if (valueLength > 30) {
+ break;
+ }
}
}
}
diff --git a/frontend/src/app/framework/utils/types.spec.ts b/frontend/src/app/framework/utils/types.spec.ts
index a360c53e6..e74dd3062 100644
--- a/frontend/src/app/framework/utils/types.spec.ts
+++ b/frontend/src/app/framework/utils/types.spec.ts
@@ -265,6 +265,31 @@ describe('Types', () => {
array: [4, 8],
});
});
+
+ it('Should format true', () => {
+ const result = Types.booleanToString(true);
+
+ expect(result).toEqual('Yes');
+ });
+
+ it('Should format false', () => {
+ const result = Types.booleanToString(false);
+
+ expect(result).toEqual('No');
+ });
+
+ it('Should format object', () => {
+ const input = {
+ field1: 'Hello',
+ field2: 1,
+ field3: true,
+ field4: [],
+ };
+
+ const result = Types.objectToString(input);
+
+ expect(result).toEqual('Hello, 1, Yes');
+ });
});
class MyClass {
diff --git a/frontend/src/app/framework/utils/types.ts b/frontend/src/app/framework/utils/types.ts
index f858212bf..1d12545ba 100644
--- a/frontend/src/app/framework/utils/types.ts
+++ b/frontend/src/app/framework/utils/types.ts
@@ -205,4 +205,42 @@ export module Types {
return target;
}
+
+ export function booleanToString(value: boolean) {
+ return value ? 'Yes' : 'No';
+ }
+
+ export function objectToString(value: Object, exclude?: string[], maxLength = 100) {
+ let result = '';
+
+ for (const [key, property] of Object.entries(value)) {
+ let formatted = '';
+
+ if (exclude && exclude.indexOf(key) >= 0) {
+ continue;
+ }
+
+ if (Types.isString(property)) {
+ formatted = property;
+ } else if (Types.isNumber(property)) {
+ formatted = `${property}`;
+ } else if (Types.isBoolean(property)) {
+ formatted = booleanToString(property);
+ }
+
+ if (formatted) {
+ if (result.length > 0) {
+ result += ', ';
+ }
+
+ result += formatted;
+ }
+
+ if (result.length >= maxLength) {
+ break;
+ }
+ }
+
+ return result;
+ }
}
diff --git a/frontend/src/app/shared/state/contents.forms.visitors.spec.ts b/frontend/src/app/shared/state/contents.forms.visitors.spec.ts
index 98ba1b76a..94ac72fc0 100644
--- a/frontend/src/app/shared/state/contents.forms.visitors.spec.ts
+++ b/frontend/src/app/shared/state/contents.forms.visitors.spec.ts
@@ -90,8 +90,16 @@ describe('ComponentField', () => {
expect(FieldFormatter.format(field, null)).toBe('');
});
- it('should format to constant', () => {
- expect(FieldFormatter.format(field, {})).toBe('{ Component }');
+ it('should format to constant when empty', () => {
+ expect(FieldFormatter.format(field, { schemaId: '123' })).toBe('Component');
+ });
+
+ it('should format to constant when values give', () => {
+ expect(FieldFormatter.format(field, { schemaId: '123', field1: 'Hello', field2: 1 })).toBe('Component: Hello, 1');
+ });
+
+ it('should format to constant when result is empty', () => {
+ expect(FieldFormatter.format(field, { schemaId: '123', field1: [] })).toBe('Component');
});
it('should return default value as null', () => {
@@ -240,6 +248,10 @@ describe('GeolocationField', () => {
expect(FieldFormatter.format(field, null)).toBe('');
});
+ it('should format to empty string if other type', () => {
+ expect(FieldFormatter.format(field, 'Text')).toBe('');
+ });
+
it('should format to latitude and longitude', () => {
expect(FieldFormatter.format(field, { latitude: 42, longitude: 3.14 })).toBe('3.14, 42');
});
@@ -280,6 +292,10 @@ describe('NumberField', () => {
expect(FieldFormatter.format(field, null)).toBe('');
});
+ it('should format to empty string if other type', () => {
+ expect(FieldFormatter.format(field, 'Text')).toBe('');
+ });
+
it('should format to number', () => {
expect(FieldFormatter.format(field, 42)).toEqual('42');
});
@@ -393,7 +409,7 @@ describe('StringField', () => {
it('should not format to preview image if not unsplash image', () => {
const field2 = createField({ properties: createProperties('String', { editor: 'StockPhoto' }) });
- expect(FieldFormatter.format(field2, 'https://images.com/123?x', true)).toBe('https://images.com/123?x');
+ expect(FieldFormatter.format(field2, 'https://images.com/123?x', true)).toEqual(new HtmlValue('
'));
});
it('should return default value from properties', () => {
@@ -420,12 +436,12 @@ describe('TagsField', () => {
expect(FieldFormatter.format(field, null)).toBe('');
});
- it('should format to asset count', () => {
- expect(FieldFormatter.format(field, ['hello', 'squidex', 'cms'])).toBe('hello, squidex, cms');
+ it('should format to empty string if other type', () => {
+ expect(FieldFormatter.format(field, 'Text')).toBe('');
});
- it('should return zero formatting if other type', () => {
- expect(FieldFormatter.format(field, 1)).toBe('');
+ it('should format to asset count', () => {
+ expect(FieldFormatter.format(field, ['hello', 'squidex', 'cms'])).toBe('hello, squidex, cms');
});
it('should return default value from properties', () => {
diff --git a/frontend/src/app/shared/state/contents.forms.visitors.ts b/frontend/src/app/shared/state/contents.forms.visitors.ts
index 8560d5c03..e1f462482 100644
--- a/frontend/src/app/shared/state/contents.forms.visitors.ts
+++ b/frontend/src/app/shared/state/contents.forms.visitors.ts
@@ -119,16 +119,26 @@ export class FieldFormatter implements FieldPropertiesVisitor {
return this.formatArray('Asset', 'Assets');
}
+ public visitComponents(_: ComponentsFieldPropertiesDto): string {
+ return this.formatArray('Component', 'Components');
+ }
+
+ public visitReferences(_: ReferencesFieldPropertiesDto): string {
+ return this.formatArray('Reference', 'References');
+ }
+
public visitBoolean(_: BooleanFieldPropertiesDto): string {
- return this.value ? 'Yes' : 'No';
+ return Types.booleanToString(this.value);
}
public visitComponent(_: ComponentFieldPropertiesDto): string {
- return '{ Component }';
- }
+ const inner = Types.objectToString(this.value, ['schemaId'], 100);
- public visitComponents(_: ComponentsFieldPropertiesDto): string {
- return this.formatArray('Component', 'Components');
+ if (inner.length > 0) {
+ return `Component: ${inner}`;
+ } else {
+ return 'Component';
+ }
}
public visitDateTime(properties: DateTimeFieldPropertiesDto): FieldValue {
@@ -145,15 +155,19 @@ export class FieldFormatter implements FieldPropertiesVisitor {
}
}
- public visitGeolocation(_: GeolocationFieldPropertiesDto): string {
- return `${this.value.longitude}, ${this.value.latitude}`;
- }
-
public visitJson(_: JsonFieldPropertiesDto): string {
return '';
}
+ public visitUI(_: UIFieldPropertiesDto): any {
+ return '';
+ }
+
public visitNumber(properties: NumberFieldPropertiesDto): FieldValue {
+ if (!Types.isNumber(this.value)) {
+ return '';
+ }
+
if (Types.isNumber(this.value) && properties.editor === 'Stars' && this.allowHtml) {
if (this.value <= 0 || this.value > 6) {
return new HtmlValue(`★ ${this.value}`);
@@ -167,47 +181,48 @@ export class FieldFormatter implements FieldPropertiesVisitor {
return new HtmlValue(html);
}
}
+
return `${this.value}`;
}
- public visitReferences(_: ReferencesFieldPropertiesDto): string {
- return this.formatArray('Reference', 'References');
+ public visitGeolocation(_: GeolocationFieldPropertiesDto): string {
+ if (!Types.isObject(this.value)) {
+ return '';
+ }
+
+ return `${this.value.longitude}, ${this.value.latitude}`;
}
public visitTags(_: TagsFieldPropertiesDto): string {
- if (this.value.length) {
- return this.value.join(', ');
- } else {
+ if (!Types.isArrayOfString(this.value)) {
return '';
}
+
+ return this.value.join(', ');
}
public visitString(properties: StringFieldPropertiesDto): any {
- if (properties.editor === 'StockPhoto' && this.allowHtml && this.value) {
- const src = thumbnail(this.value, undefined, 50);
+ if (!Types.isString(this.value)) {
+ return '';
+ }
- if (src) {
- return new HtmlValue(`
`);
- }
+ if (properties.editor === 'StockPhoto' && this.allowHtml && this.value) {
+ return new HtmlValue(`
`);
}
return this.value;
}
- public visitUI(_: UIFieldPropertiesDto): any {
- return '';
- }
-
private formatArray(singularName: string, pluralName: string) {
- if (Types.isArray(this.value)) {
- if (this.value.length > 1) {
- return `${this.value.length} ${pluralName}`;
- } else if (this.value.length === 1) {
- return `1 ${singularName}`;
- }
+ if (!Types.isArray(this.value)) {
+ return `0 ${pluralName}`;
}
- return `0 ${pluralName}`;
+ if (this.value.length > 1) {
+ return `${this.value.length} ${pluralName}`;
+ } else {
+ return `1 ${singularName}`;
+ }
}
}
@@ -222,7 +237,7 @@ export function thumbnail(url: string, width?: number, height?: number) {
}
}
- return undefined;
+ return url;
}
export class FieldsValidators implements FieldPropertiesVisitor> {
@@ -265,14 +280,6 @@ export class FieldsValidators implements FieldPropertiesVisitor {
- return [];
- }
-
- public visitComponent(_: ComponentFieldPropertiesDto): ReadonlyArray {
- return [];
- }
-
public visitComponents(properties: ComponentsFieldPropertiesDto): ReadonlyArray {
const validators: ValidatorFn[] = [
ValidatorsEx.betweenLength(properties.minItems, properties.maxItems),
@@ -285,18 +292,6 @@ export class FieldsValidators implements FieldPropertiesVisitor {
- return [];
- }
-
- public visitGeolocation(_: GeolocationFieldPropertiesDto): ReadonlyArray {
- return [];
- }
-
- public visitJson(_: JsonFieldPropertiesDto): ReadonlyArray {
- return [];
- }
-
public visitNumber(properties: NumberFieldPropertiesDto): ReadonlyArray {
const validators: ValidatorFn[] = [
ValidatorsEx.between(properties.minValue, properties.maxValue),
@@ -363,6 +358,26 @@ export class FieldsValidators implements FieldPropertiesVisitor {
+ return [];
+ }
+
+ public visitComponent(_: ComponentFieldPropertiesDto): ReadonlyArray {
+ return [];
+ }
+
+ public visitDateTime(_: DateTimeFieldPropertiesDto): ReadonlyArray {
+ return [];
+ }
+
+ public visitGeolocation(_: GeolocationFieldPropertiesDto): ReadonlyArray {
+ return [];
+ }
+
+ public visitJson(_: JsonFieldPropertiesDto): ReadonlyArray {
+ return [];
+ }
+
public visitUI(_: UIFieldPropertiesDto): ReadonlyArray {
return [];
}