Browse Source

Increase search field limit. (#1296)

* Increase search field limit.

* Fix tests
pull/1299/head
Sebastian Stehle 5 months ago
committed by GitHub
parent
commit
57aa395ff6
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      backend/i18n/frontend_de.json
  2. 2
      backend/i18n/frontend_en.json
  3. 2
      backend/i18n/frontend_fr.json
  4. 2
      backend/i18n/frontend_it.json
  5. 2
      backend/i18n/frontend_nl.json
  6. 2
      backend/i18n/frontend_pt.json
  7. 2
      backend/i18n/frontend_zh.json
  8. 2
      backend/i18n/source/frontend_en.json
  9. 4
      backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/Guards/GuardSchema.cs
  10. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/Guards/GuardSchemaTests.cs
  11. 55
      frontend/src/app/framework/utils/types.spec.ts
  12. 21
      frontend/src/app/framework/utils/types.ts
  13. 2
      frontend/src/app/shared/state/schemas.forms.ts

2
backend/i18n/frontend_de.json

@ -1049,7 +1049,7 @@
"schemas.schemaNameValidationMessage": "Der Name darf nur Buchstaben, Zahlen und Bindestriche enthalten.",
"schemas.schemaTagsHint": "Tags zur Annotation Ihres Schemas für Automatisierungsprozesse.",
"schemas.searchFields": "Search Fields",
"schemas.searchFieldsHelp": "The normal search uses **full-text search** across the available data.\n\nYou can optionally define **1–3 additional search fields**. These fields are included in the search using a simple **“contains” match**, meaning results are returned when the entered text appears anywhere within those fields.",
"schemas.searchFieldsHelp": "The default search uses full-text search (indexed) across all available data. This is fast and powerful, but only matches whole words or stems, so partial terms may return no results.\n\nYou can define up to 4 additional field search fields, which use a simple contains match. This means a result is returned whenever the entered text appears anywhere within that field, making it ideal for catching partial matches the full-text search might miss.\n\nIf you need more than 4 extra fields, use a schema script to combine multiple fields into one.",
"schemas.searchFieldsHint": "The search fields",
"schemas.searchPlaceholder": "Suchen",
"schemas.showFieldFailed": "Fehler beim Anzeigen des Feldes. Bitte neu laden.",

2
backend/i18n/frontend_en.json

@ -1049,7 +1049,7 @@
"schemas.schemaNameValidationMessage": "Name can only contain letters, numbers and dashes.",
"schemas.schemaTagsHint": "Tags to annotate your schema for automation processes.",
"schemas.searchFields": "Search Fields",
"schemas.searchFieldsHelp": "The normal search uses **full-text search** across the available data.\n\nYou can optionally define **1–3 additional search fields**. These fields are included in the search using a simple **“contains” match**, meaning results are returned when the entered text appears anywhere within those fields.",
"schemas.searchFieldsHelp": "The default search uses full-text search (indexed) across all available data. This is fast and powerful, but only matches whole words or stems, so partial terms may return no results.\n\nYou can define up to 4 additional field search fields, which use a simple contains match. This means a result is returned whenever the entered text appears anywhere within that field, making it ideal for catching partial matches the full-text search might miss.\n\nIf you need more than 4 extra fields, use a schema script to combine multiple fields into one.",
"schemas.searchFieldsHint": "The search fields",
"schemas.searchPlaceholder": "Search",
"schemas.showFieldFailed": "Failed to show field. Please reload.",

2
backend/i18n/frontend_fr.json

@ -1049,7 +1049,7 @@
"schemas.schemaNameValidationMessage": "Le nom ne peut contenir que des lettres, des chiffres et des tirets.",
"schemas.schemaTagsHint": "Balises pour annoter votre schéma pour les processus d'automatisation.",
"schemas.searchFields": "Search Fields",
"schemas.searchFieldsHelp": "The normal search uses **full-text search** across the available data.\n\nYou can optionally define **1–3 additional search fields**. These fields are included in the search using a simple **“contains” match**, meaning results are returned when the entered text appears anywhere within those fields.",
"schemas.searchFieldsHelp": "The default search uses full-text search (indexed) across all available data. This is fast and powerful, but only matches whole words or stems, so partial terms may return no results.\n\nYou can define up to 4 additional field search fields, which use a simple contains match. This means a result is returned whenever the entered text appears anywhere within that field, making it ideal for catching partial matches the full-text search might miss.\n\nIf you need more than 4 extra fields, use a schema script to combine multiple fields into one.",
"schemas.searchFieldsHint": "The search fields",
"schemas.searchPlaceholder": "Recherche",
"schemas.showFieldFailed": "Impossible d'afficher le champ. Veuillez recharger.",

2
backend/i18n/frontend_it.json

@ -1049,7 +1049,7 @@
"schemas.schemaNameValidationMessage": "Il nome può contenere solo lettere, numeri e trattini.",
"schemas.schemaTagsHint": "Tag per descrivere il tuo schema per i processi automatici.",
"schemas.searchFields": "Search Fields",
"schemas.searchFieldsHelp": "The normal search uses **full-text search** across the available data.\n\nYou can optionally define **1–3 additional search fields**. These fields are included in the search using a simple **“contains” match**, meaning results are returned when the entered text appears anywhere within those fields.",
"schemas.searchFieldsHelp": "The default search uses full-text search (indexed) across all available data. This is fast and powerful, but only matches whole words or stems, so partial terms may return no results.\n\nYou can define up to 4 additional field search fields, which use a simple contains match. This means a result is returned whenever the entered text appears anywhere within that field, making it ideal for catching partial matches the full-text search might miss.\n\nIf you need more than 4 extra fields, use a schema script to combine multiple fields into one.",
"schemas.searchFieldsHint": "The search fields",
"schemas.searchPlaceholder": "Cerca negli schemi...",
"schemas.showFieldFailed": "Non è stato possibile mostrare il campo. Per favore ricarica.",

2
backend/i18n/frontend_nl.json

@ -1049,7 +1049,7 @@
"schemas.schemaNameValidationMessage": "Naam mag alleen letters, cijfers en streepjes bevatten.",
"schemas.schemaTagsHint": "Tags om uw schema voor automatiseringsprocessen te annoteren.",
"schemas.searchFields": "Search Fields",
"schemas.searchFieldsHelp": "The normal search uses **full-text search** across the available data.\n\nYou can optionally define **1–3 additional search fields**. These fields are included in the search using a simple **“contains” match**, meaning results are returned when the entered text appears anywhere within those fields.",
"schemas.searchFieldsHelp": "The default search uses full-text search (indexed) across all available data. This is fast and powerful, but only matches whole words or stems, so partial terms may return no results.\n\nYou can define up to 4 additional field search fields, which use a simple contains match. This means a result is returned whenever the entered text appears anywhere within that field, making it ideal for catching partial matches the full-text search might miss.\n\nIf you need more than 4 extra fields, use a schema script to combine multiple fields into one.",
"schemas.searchFieldsHint": "The search fields",
"schemas.searchPlaceholder": "Zoek schema's ...",
"schemas.showFieldFailed": "Kan veld niet weergeven. Laad opnieuw.",

2
backend/i18n/frontend_pt.json

@ -1049,7 +1049,7 @@
"schemas.schemaNameValidationMessage": "O nome só pode conter letras, números e traços.",
"schemas.schemaTagsHint": "Etiquetas para anotar o seu esquema para processos de automação.",
"schemas.searchFields": "Search Fields",
"schemas.searchFieldsHelp": "The normal search uses **full-text search** across the available data.\n\nYou can optionally define **1–3 additional search fields**. These fields are included in the search using a simple **“contains” match**, meaning results are returned when the entered text appears anywhere within those fields.",
"schemas.searchFieldsHelp": "The default search uses full-text search (indexed) across all available data. This is fast and powerful, but only matches whole words or stems, so partial terms may return no results.\n\nYou can define up to 4 additional field search fields, which use a simple contains match. This means a result is returned whenever the entered text appears anywhere within that field, making it ideal for catching partial matches the full-text search might miss.\n\nIf you need more than 4 extra fields, use a schema script to combine multiple fields into one.",
"schemas.searchFieldsHint": "The search fields",
"schemas.searchPlaceholder": "Pesquisar",
"schemas.showFieldFailed": "Falhou em mostrar o campo. Por favor, recarregue.",

2
backend/i18n/frontend_zh.json

@ -1049,7 +1049,7 @@
"schemas.schemaNameValidationMessage": "名称只能包含字母、数字和破折号。",
"schemas.schemaTagsHint": "用于注释自动化流程Schemas的标签。",
"schemas.searchFields": "Search Fields",
"schemas.searchFieldsHelp": "The normal search uses **full-text search** across the available data.\n\nYou can optionally define **1–3 additional search fields**. These fields are included in the search using a simple **“contains” match**, meaning results are returned when the entered text appears anywhere within those fields.",
"schemas.searchFieldsHelp": "The default search uses full-text search (indexed) across all available data. This is fast and powerful, but only matches whole words or stems, so partial terms may return no results.\n\nYou can define up to 4 additional field search fields, which use a simple contains match. This means a result is returned whenever the entered text appears anywhere within that field, making it ideal for catching partial matches the full-text search might miss.\n\nIf you need more than 4 extra fields, use a schema script to combine multiple fields into one.",
"schemas.searchFieldsHint": "The search fields",
"schemas.searchPlaceholder": "搜索Schemas...",
"schemas.showFieldFailed": "显示字段失败。请重新加载。",

2
backend/i18n/source/frontend_en.json

@ -1049,7 +1049,7 @@
"schemas.schemaNameValidationMessage": "Name can only contain letters, numbers and dashes.",
"schemas.schemaTagsHint": "Tags to annotate your schema for automation processes.",
"schemas.searchFields": "Search Fields",
"schemas.searchFieldsHelp": "The normal search uses **full-text search** across the available data.\n\nYou can optionally define **1–3 additional search fields**. These fields are included in the search using a simple **“contains” match**, meaning results are returned when the entered text appears anywhere within those fields.",
"schemas.searchFieldsHelp": "The default search uses full-text search (indexed) across all available data. This is fast and powerful, but only matches whole words or stems, so partial terms may return no results.\n\nYou can define up to 4 additional field search fields, which use a simple contains match. This means a result is returned whenever the entered text appears anywhere within that field, making it ideal for catching partial matches the full-text search might miss.\n\nIf you need more than 4 extra fields, use a schema script to combine multiple fields into one.",
"schemas.searchFieldsHint": "The search fields",
"schemas.searchPlaceholder": "Search",
"schemas.showFieldFailed": "Failed to show field. Please reload.",

4
backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/Guards/GuardSchema.cs

@ -116,9 +116,9 @@ public static class GuardSchema
Validate.It(e =>
{
if (command.Properties.SearchFields != null && command.Properties.SearchFields.Count > 3)
if (command.Properties.SearchFields != null && command.Properties.SearchFields.Count > 4)
{
e(Not.Between("Size", 1, 3), "Properties.SearchFields");
e(Not.Between("Size", 1, 4), "Properties.SearchFields");
}
});
}

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/Guards/GuardSchemaTests.cs

@ -664,12 +664,12 @@ public class GuardSchemaTests : GivenContext, IClassFixture<TranslationsFixture>
{
Properties = new SchemaProperties()
{
SearchFields = FieldNames.Create("a", "b", "c", "d"),
SearchFields = FieldNames.Create("a", "b", "c", "d", "e"),
},
};
ValidationAssert.Throws(() => GuardSchema.CanUpdateSchema(command),
new ValidationError("Size must be between 1 and 3.", "Properties.SearchFields"));
new ValidationError("Size must be between 1 and 4.", "Properties.SearchFields"));
}
private CreateSchema CreateCommand(CreateSchema command)

55
frontend/src/app/framework/utils/types.spec.ts

@ -290,6 +290,61 @@ describe('Types', () => {
expect(result).toEqual('Hello, 1, Yes');
});
describe('Hashing', () => {
it('should hash a string', () => {
const result = Types.fnv1a('hello');
expect(result).toBe(Types.fnv1a('hello')); // deterministic
expect(typeof result).toBe('string');
});
it('should hash a number', () => {
expect(Types.fnv1a(42)).toBe(Types.fnv1a(42));
expect(Types.fnv1a(42)).not.toBe(Types.fnv1a(43));
});
it('should hash a boolean', () => {
expect(Types.fnv1a(true)).toBe(Types.fnv1a(true));
expect(Types.fnv1a(true)).not.toBe(Types.fnv1a(false));
});
it('should hash an object', () => {
expect(Types.fnv1a({ a: 1 })).toBe(Types.fnv1a({ a: 1 }));
expect(Types.fnv1a({ a: 1 })).not.toBe(Types.fnv1a({ a: 2 }));
});
it('should hash an array', () => {
expect(Types.fnv1a([1, 2, 3])).toBe(Types.fnv1a([1, 2, 3]));
expect(Types.fnv1a([1, 2, 3])).not.toBe(Types.fnv1a([1, 2, 4]));
});
it('should hash null and undefined', () => {
expect(typeof Types.fnv1a(null)).toBe('string');
expect(typeof Types.fnv1a(undefined)).toBe('string');
expect(Types.fnv1a(null)).not.toBe(Types.fnv1a(undefined));
});
it('should return a base64 encoded string with identifier', () => {
const result = Types.hashWithId('hello', 'session');
expect(() => atob(result)).not.toThrow();
expect(atob(result)).toMatch(/^session:/);
});
it('should embed the correct hash in the encoded result', () => {
const hash = Types.fnv1a('hello');
expect(atob(Types.hashWithId('hello', 'session'))).toBe(`session:${hash}`);
});
it('should produce different results for different identifiers', () => {
expect(Types.hashWithId('hello', 'a')).not.toBe(Types.hashWithId('hello', 'b'));
});
it('should produce different results for different values', () => {
expect(Types.hashWithId('hello', 'id')).not.toBe(Types.hashWithId('world', 'id'));
});
})
});
class MyClass {

21
frontend/src/app/framework/utils/types.ts

@ -97,8 +97,7 @@ export module Types {
return true;
}
// eslint-disable-next-line @typescript-eslint/no-unnecessary-boolean-literal-compare
return Types.isUndefined(value) === true || Types.isNull(value) === true;
return Types.isUndefined(value) || Types.isNull(value);
}
export function clone<T>(lhs: T): T {
@ -231,4 +230,22 @@ export module Types {
return result;
}
export function fnv1a(value: unknown): string {
const text = JSON.stringify(value) ?? String(value);
let hash = 2166136261;
for (let i = 0; i < text.length; i++) {
hash ^= text.charCodeAt(i);
hash = (hash * 16777619) >>> 0;
}
return hash.toString(16);
}
export function hashWithId(value: unknown, identifier: string): string {
const hash = fnv1a(value);
const combined = `${identifier}:${hash}`;
return btoa(combined);
}
}

2
frontend/src/app/shared/state/schemas.forms.ts

@ -422,7 +422,7 @@ export class EditSchemaForm extends Form<ExtendedFormGroup, UpdateSchemaDto, Sch
Validators.nullValidator,
),
searchFields: new UntypedFormControl([],
Validators.maxLength(3),
Validators.maxLength(4),
),
tags: new UntypedFormControl([],
Validators.nullValidator,

Loading…
Cancel
Save