nuxeo-development-framework 5.6.3 → 5.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/bundles/nuxeo-development-framework.umd.js +214 -174
  2. package/bundles/nuxeo-development-framework.umd.js.map +1 -1
  3. package/esm2015/lib/components/comments/components/edit-delete-modal/edit-delete-modal.component.js +1 -1
  4. package/esm2015/lib/components/dynamic-form/components/department-form/department-form.component.js +1 -1
  5. package/esm2015/lib/components/file-manger/components/create-modal/create-modal.component.js +1 -1
  6. package/esm2015/lib/components/file-manger/components/creation-type/creation-type.component.js +1 -1
  7. package/esm2015/lib/components/file-manger/components/folder-modal/folder-modal.component.js +1 -1
  8. package/esm2015/lib/components/file-manger/components/publish-dialog/publish-dialog.component.js +1 -1
  9. package/esm2015/lib/components/file-manger/components/scan-modal/scan-modal.component.js +1 -1
  10. package/esm2015/lib/components/file-manger/components/share-dialog/share-dialog.component.js +1 -1
  11. package/esm2015/lib/components/file-manger/components/template-modal/template-modal.component.js +1 -1
  12. package/esm2015/lib/components/file-manger/components/update-modal/update-modal.component.js +1 -1
  13. package/esm2015/lib/components/ndf-config-editor/components/config-editor-actions/config-editor-actions.component.js +2 -2
  14. package/esm2015/lib/components/ndf-config-editor/components/info-dialog/info-dialog.component.js +10 -4
  15. package/esm2015/lib/components/ndf-config-editor/containers/ndf-config-editor/ndf-config-editor.component.js +3 -3
  16. package/esm2015/lib/components/ndf-config-editor/models/config.js +1 -1
  17. package/esm2015/lib/components/ndf-config-editor/models/dialog-data.js +1 -1
  18. package/esm2015/lib/components/ndf-filters/components/__parts/html-dialog/html-dialog.component.js +1 -1
  19. package/esm2015/lib/components/ndf-filters/models/field-options/input-options.js +1 -1
  20. package/esm2015/lib/components/ndf-tabs/component/ndf-tabs.component.js +7 -5
  21. package/esm2015/lib/components/permissions/add-permissions-dialog/add-permissions-dialog.component.js +1 -1
  22. package/esm2015/lib/components/reports/ndf-reports/base/base-graph.report.js +3 -3
  23. package/esm2015/lib/components/reports/ndf-reports/components/_parts/custom-chart-dialog/custom-chart-dialog.component.js +1 -1
  24. package/esm2015/lib/components/reports/ndf-reports/components/_parts/graph-dialog/graph-dialog.component.js +1 -1
  25. package/esm2015/lib/components/reports/ndf-reports/components/_parts/timeline-dialog/timeline-dialog.component.js +1 -1
  26. package/esm2015/lib/components/reports/ndf-reports/containers/ndf-reports/ndf-reports.component.js +9 -2
  27. package/esm2015/lib/components/reports/ndf-reports/services/chart-manager.service.js +25 -2
  28. package/esm2015/lib/shared/components/nuxeo-dialog/confirmation/ndf-confirmation-dialog.component.js +1 -1
  29. package/esm2015/lib/shared/components/nuxeo-dialog/nuxeo.dialog.js +5 -2
  30. package/fesm2015/nuxeo-development-framework.js +197 -157
  31. package/fesm2015/nuxeo-development-framework.js.map +1 -1
  32. package/lib/components/ndf-config-editor/components/config-editor-actions/config-editor-actions.component.d.ts +2 -2
  33. package/lib/components/ndf-config-editor/components/info-dialog/info-dialog.component.d.ts +4 -3
  34. package/lib/components/ndf-config-editor/containers/ndf-config-editor/ndf-config-editor.component.d.ts +2 -2
  35. package/lib/components/ndf-config-editor/models/config.d.ts +7 -3
  36. package/lib/components/ndf-config-editor/models/dialog-data.d.ts +2 -1
  37. package/lib/components/ndf-filters/components/predicate-text-input/predicate-text-input.component.d.ts +1 -14
  38. package/lib/components/ndf-filters/models/field-options/input-options.d.ts +25 -23
  39. package/lib/components/ndf-tabs/component/ndf-tabs.component.d.ts +3 -3
  40. package/lib/components/reports/ndf-reports/containers/ndf-reports/ndf-reports.component.d.ts +1 -0
  41. package/lib/components/reports/ndf-reports/services/chart-manager.service.d.ts +1 -0
  42. package/lib/shared/components/nuxeo-dialog/nuxeo.dialog.d.ts +2 -1
  43. package/package.json +1 -1
  44. package/src/docs/ndf-filters.doc.md +1026 -0
  45. package/src/docs/ndf-reports.doc.md +4 -5
@@ -0,0 +1,1026 @@
1
+ # Filters Panel Component Documentation (`app-filters-panel`)
2
+
3
+ ## Overview
4
+
5
+ The `app-filters-panel` component provides a comprehensive filtering interface for data tables and search results. It supports multiple field types, aggregation-based filtering, and customizable rendering options with real-time data updates and flexible configuration management.
6
+
7
+ ### Key Features
8
+
9
+ - Dynamic field rendering with multiple input types
10
+ - Aggregation-based filtering with bucket management
11
+ - Real-time query synchronization and state management
12
+ - Custom template integration for specialized components
13
+ - Internationalization support with role-based access control
14
+
15
+ ## Quick Start Guide
16
+
17
+ ### Basic Implementation
18
+
19
+ ```typescript
20
+ import { Component } from '@angular/core';
21
+ import { FieldConfigModel, AggregationResponse, FormQueryModel } from './types';
22
+
23
+ @Component({
24
+ template: `
25
+ <app-filters-panel
26
+ [aggregations]="aggregations"
27
+ [fields]="filterFields"
28
+ [activeQuery]="currentQuery"
29
+ (filterChanged)="onFilterChange($event)">
30
+ </app-filters-panel>
31
+ `
32
+ })
33
+ export class MyComponent {
34
+ aggregations: Record<string, AggregationResponse> = {
35
+ 'priority_agg': {
36
+ id: 'priority_agg',
37
+ field: 'priority',
38
+ buckets: [
39
+ { key: 'high', docCount: 25 },
40
+ { key: 'medium', docCount: 48 },
41
+ { key: 'low', docCount: 12 }
42
+ ],
43
+ properties: {}
44
+ }
45
+ };
46
+
47
+ filterFields: FieldConfigModel[] = [
48
+ {
49
+ type: 'aggregation',
50
+ config: {
51
+ label: 'FILTERS.priority',
52
+ fieldKey: 'priority',
53
+ aggregation: 'priority_agg',
54
+ sendMode: 'queryParam',
55
+ render: {
56
+ type: 'checkbox',
57
+ options: { showTotal: true }
58
+ }
59
+ }
60
+ }
61
+ ];
62
+
63
+ currentQuery: FormQueryModel = {};
64
+
65
+ onFilterChange(filters: Record<string, any>) {
66
+ console.log('Filter changed:', filters);
67
+ // Handle filter updates
68
+ }
69
+ }
70
+ ```
71
+
72
+
73
+ ---
74
+
75
+ ## Component Interface
76
+
77
+ ### Input Properties
78
+
79
+ ```typescript
80
+ @Component({
81
+ selector: 'app-filters-panel',
82
+ // ...
83
+ })
84
+ export class FiltersPanel {
85
+ @Input() aggregations: Record<string, AggregationResponse>;
86
+ @Input() fields: FieldConfigModel[];
87
+ @Input() activeQuery: FormQueryModel;
88
+ @Input() customTemplateRef: TemplateRef<any>;
89
+
90
+ @Output() filterChanged = new EventEmitter<Record<string, any>>();
91
+ }
92
+ ```
93
+
94
+ #### Property Specifications
95
+
96
+ | Property | Type | Required | Description |
97
+ | ------------------- | ------------------------------------- | -------- | ------------------------------------------------------------- |
98
+ | `aggregations` | `Record<string, AggregationResponse>` | ✅ | Collection of aggregation data indexed by aggregation ID |
99
+ | `fields` | `FieldConfigModel[]` | ✅ | Array of filter field configurations defining UI and behavior |
100
+ | `activeQuery` | `FormQueryModel` | ✅ | Current query state for synchronizing filter values |
101
+ | `customTemplateRef` | `TemplateRef<any>` | ❌ | Template reference for aggregation field custom rendering |
102
+
103
+ #### Event Emissions
104
+
105
+ |Event|Type|Description|
106
+ |---|---|---|
107
+ |`filterChanged`|`EventEmitter<Record<string, any>>`|Emitted when filter values change, containing updated filter state|
108
+
109
+ ---
110
+
111
+ ## Data Models
112
+
113
+ ### `AggregationResponse` Interface
114
+
115
+ ```typescript
116
+ export interface AggregationResponse {
117
+ 'entity-type'?: string;
118
+ id: string;
119
+ field?: string;
120
+ properties: Record<string, any>;
121
+ ranges?: any[];
122
+ selection?: any[];
123
+ type?: string;
124
+ buckets: AggregationBucket[];
125
+ extendedBuckets?: AggregationBucket[];
126
+ }
127
+ ```
128
+
129
+ #### Property Descriptions
130
+
131
+ | Property | Type | Required | Description |
132
+ | ----------------- | --------------------- | -------- | --------------------------------------------------------- |
133
+ | `entity-type` | `string` | ❌ | Entity classification for the aggregation |
134
+ | `id` | `string` | ✅ | Unique identifier |
135
+ | `field` | `string` | ❌ | Source field key used for aggregation |
136
+ | `properties` | `Record<string, any>` | ✅ | Additional metadata and configuration properties |
137
+ | `ranges` | `any[]` | ❌ | Predefined ranges for range-based aggregations |
138
+ | `selection` | `any[]` | ❌ | Currently selected values for the aggregation |
139
+ | `type` | `string` | ❌ | Aggregation type identifier |
140
+ | `buckets` | `AggregationBucket[]` | ✅ | Primary aggregation results containing filterable options |
141
+ | `extendedBuckets` | `AggregationBucket[]` | ❌ | Additional bucket data for extended functionality |
142
+
143
+ ### `AggregationBucket` Interface
144
+
145
+ ```typescript
146
+ export interface AggregationBucket {
147
+ key: string;
148
+ docCount: number;
149
+ fetchedKey?: Record<string, any>;
150
+ from?: number;
151
+ to?: number;
152
+ fromAsDate?: Record<string, any>;
153
+ toAsDate?: Record<string, any>;
154
+ }
155
+ ```
156
+
157
+ #### Property Descriptions
158
+
159
+ |Property|Type|Required|Description|
160
+ |---|---|---|---|
161
+ |`key`|`string`|✅|Unique identifier for the bucket value|
162
+ |`docCount`|`number`|✅|Number of documents matching this bucket|
163
+ |`fetchedKey`|`Record<string, any>`|❌|Additional key metadata from data source|
164
+ |`from`|`number`|❌|Range start value for numeric range buckets|
165
+ |`to`|`number`|❌|Range end value for numeric range buckets|
166
+ |`fromAsDate`|`Record<string, any>`|❌|Range start as date object for date range buckets|
167
+ |`toAsDate`|`Record<string, any>`|❌|Range end as date object for date range buckets|
168
+
169
+ ---
170
+
171
+ ## Field Configuration
172
+
173
+ ### `FieldConfigModel` Types
174
+
175
+ ```typescript
176
+ type FieldConfigModel =
177
+ | { type: 'aggregation'; config: AggregationFieldConfig; }
178
+ | { type: 'predicate'; config: PredicateFieldConfig; }
179
+ | { type: 'custom'; config: CustomFieldConfig; };
180
+ ```
181
+
182
+ ### Base Field Configuration
183
+
184
+ ```typescript
185
+ interface BaseFieldConfig {
186
+ label: TranslateKey;
187
+ fieldKey: string;
188
+ values?: unknown;
189
+ prefix?: string;
190
+ order?: number;
191
+ operator?: ComparisonOperator;
192
+ valueType: 'valueObject' | 'property';
193
+ visible?: boolean;
194
+ roles?: string[];
195
+ permission?: string;
196
+ condition?: EvaluatedString;
197
+ }
198
+ ```
199
+
200
+ #### Core Properties
201
+
202
+ | Property | Type | Required | Default | Description |
203
+ | ------------ | ------------------------------- | -------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
204
+ | `label` | `TranslateKey` | ✅ | - | Internationalization key for field display label |
205
+ | `fieldKey` | `string` | ✅ | - | Unique identifier used for data binding and query construction |
206
+ | `values` | `unknown` | ❌ | - | Static data source for field options |
207
+ | `prefix` | `string` | ❌ | - | Translation key prefix for localized option values |
208
+ | `order` | `number` | ❌ | `0` | Display order priority in filter panel |
209
+ | `operator` | `ComparisonOperator` | ❌ | - | Comparison operator for filter logic |
210
+ | `valueType` | `'valueObject'` \| `'property'` | ❌ | `valueObject` | Value interpretation method for filtering |
211
+ | `visible` | `boolean` | ❌ | `true` | Runtime visibility control |
212
+ | `roles` | `string[]` | ❌ | - | Required user roles for field access |
213
+ | `permission` | `string` | ❌ | - | Specific permission requirement |
214
+ | condition | EvaluatedString | ❌ | | **Logical expression** evaluated at runtime to determine field visibility. Supports access to other filter values or context variables (e.g., `show = filters.status === 'active'`). Use this to implement dynamic field inclusion based on filter state or external inputs |
215
+
216
+ ---
217
+
218
+ ## **Field Types**
219
+
220
+ ## 1. Aggregation Fields
221
+
222
+ ### `AggregationFieldConfig` interface
223
+
224
+ ```ts
225
+ type AggregationFieldConfig = BaseFieldConfig & {
226
+ aggregation: string;
227
+ propertyPath?: string;
228
+ bindLabel?: { ar: string; en: string };
229
+ bindValue?: string;
230
+ dataTransformer?: string;
231
+ sendMode: FieldSendModeType;
232
+ tooltip?: AggregationTooltipType;
233
+ render: CheckboxOptions | SwitchOptions | RadioOptions |
234
+ DropdownOptions | AutocompleteOptions | CustomOptions |
235
+ DateListOptions;
236
+ }
237
+ ```
238
+
239
+ ### Properties
240
+
241
+ | Property | Type | Required | Default | Description |
242
+ |----------------|----------|----------|---------|-------------|
243
+ | `aggregation` | `string` | ✅ | - | **Aggregation identifier** that must match a key in the parent component's aggregations input for data binding |
244
+ | `sendMode` | `FieldSendModeType` | ✅ | - | **Filter transmission mode** determining how selected values are sent to the backend |
245
+ | `propertyPath` | `string` | ❌ | `fieldKey` | **Alternative property path** for nested object property access when aggregation field differs from fieldKey |
246
+ | `bindLabel` | `{ ar: string; en: string }` | ❌ | - | **Localized property mappings** defining bucket properties containing Arabic and English labels |
247
+ | `bindValue` | `string` | ❌ | `'key'` | **Value extraction property** specifying which bucket property serves as the filter value |
248
+ | `dataTransformer` | `string` | ❌ | - | **Transformer function name** registered in `NdfTransformService` for custom bucket data processing |
249
+ | `tooltip` | `AggregationTooltipType` | ❌ | - | **Tooltip configuration** for displaying additional information about filter options |
250
+ | `render` | `RenderOptions` | ✅ | - | **UI rendering configuration** defining component type and display options |
251
+
252
+ ### `FieldSendModeType` Options
253
+
254
+ ```typescript
255
+ const FIELD_SEND_MODE = {
256
+ payload: 'payload',
257
+ queryParam: 'queryParam',
258
+ custom: 'custom'
259
+ } as const ;
260
+
261
+ type FieldSendModeType = (typeof FIELD_SEND_MODE)[keyof typeof FIELD_SEND_MODE]; //'queryParam' | 'payload' | 'custom'
262
+ ```
263
+
264
+ ### Properties
265
+ | Mode | Description | Use Case |
266
+ | ------------ | -------------------------------------------------- | ---------------------------------- |
267
+ | `queryParam` | Sends filter values as URL query parameters | RESTful APIs, bookmarkable filters |
268
+ | `payload` | Includes filter values in request body | Complex queries, large filter sets |
269
+ | `custom` | Delegates filter handling to custom implementation | Specialized filtering logic |
270
+
271
+
272
+ ```ts
273
+ /*
274
+ Basic Aggregation Field Setup
275
+ */
276
+ import { AggregationFieldConfig, FieldSendModeType } from './types';
277
+
278
+ // Simple checkbox aggregation field
279
+ const priorityFilter: AggregationFieldConfig = {
280
+ // Base field properties
281
+ label: 'FILTERS.priority',
282
+ fieldKey: 'priority',
283
+ valueType: 'valueObject',
284
+
285
+ // Aggregation-specific properties
286
+ aggregation: 'priority_agg',
287
+ sendMode: 'queryParam',
288
+
289
+ // Rendering configuration
290
+ render: {
291
+ type: 'checkbox',
292
+ options: {
293
+ showTotal: true,
294
+ filter: true,
295
+ collapse: true
296
+ }
297
+ }
298
+ };
299
+
300
+ /*
301
+ Advanced Configuration with Localization
302
+ */
303
+
304
+ const statusFilter: AggregationFieldConfig = {
305
+ label: 'FILTERS.documentStatus',
306
+ fieldKey: 'doc:status',
307
+ propertyPath: 'document.status',
308
+ aggregation: 'status_aggregation',
309
+
310
+ // Localized label binding
311
+ bindLabel: {
312
+ ar: 'statusAr',
313
+ en: 'statusEn'
314
+ },
315
+ bindValue: 'statusCode',
316
+
317
+ // Custom data processing
318
+ dataTransformer: 'statusTransformer',
319
+
320
+ sendMode: 'payload',
321
+
322
+ // Tooltip configuration
323
+ tooltip: {
324
+ type: 'localizeValue',
325
+ content: 'TOOLTIPS.statusFilter'
326
+ },
327
+
328
+ render: {
329
+ type: 'dropdown',
330
+ options: {
331
+ multiple: true,
332
+ showTotal: true
333
+ }
334
+ }
335
+ };
336
+
337
+ ```
338
+
339
+ ## Render Options
340
+ ### Available Render Types
341
+
342
+ The `render` property accepts one of several specialized option types:
343
+
344
+ #### `CheckboxOptions`
345
+ ```ts
346
+ type CheckboxOptions = {
347
+ type: 'checkbox';
348
+ options?: {
349
+ showTotal?: boolean; // Display document count
350
+ filter?: boolean; // Enable search within options
351
+ collapse?: boolean; // Collapsible option list
352
+ minVisibleCount?: number; // Items shown before collapse
353
+ expandedCount?: number; // Items shown when expanded
354
+ hideLabel?: boolean; // Hide field label
355
+ sort?: boolean; // Sort options alphabetically
356
+ search?: SearchConfig; // Advanced search configuration
357
+ };
358
+ };
359
+ ```
360
+
361
+
362
+ #### `SwitchOptions`
363
+ ```typescript
364
+ type SwitchOptions = {
365
+ type: 'switch';
366
+ options?: {
367
+ showTotal?: boolean; // Display document count
368
+ filter?: boolean; // Enable search within options
369
+ collapse?: boolean; // Collapsible option list
370
+ multiple?: boolean; // Allow multiple selections
371
+ hideLabel?: boolean; // Hide field label
372
+ sort?: boolean; // Sort options alphabetically
373
+ search?: SearchConfig; // Advanced search configuration
374
+ };
375
+ };
376
+ ```
377
+
378
+ #### `RadioOptions`
379
+ ```typescript
380
+ type RadioOptions = {
381
+ type: 'radio';
382
+ options?: {
383
+ showTotal?: boolean; // Display document count
384
+ hideLabel?: boolean; // Hide field label
385
+ sort?: boolean; // Sort options alphabetically
386
+ };
387
+ };
388
+ ```
389
+ #### `DropdownOptions`
390
+ ```typescript
391
+ type DropdownOptions = {
392
+ type: 'dropdown';
393
+ options?: {
394
+ showTotal?: boolean; // Display document count in options
395
+ multiple?: boolean; // Allow multiple selections
396
+ hideLabel?: boolean; // Hide field label
397
+ };
398
+ };
399
+ ```
400
+
401
+ #### `AutocompleteOptions`
402
+ ```typescript
403
+ type AutocompleteOptions = {
404
+ type: 'autocomplete';
405
+ options?: {
406
+ showTotal?: boolean; // Display document count
407
+ multiple?: boolean; // Allow multiple selections
408
+ hideLabel?: boolean; // Hide field label
409
+ minChars?: number; // Minimum characters for search
410
+ debounceTime?: number; // Search delay in milliseconds
411
+ };
412
+ };
413
+ ```
414
+
415
+ #### `DateListOptions`
416
+ ```typescript
417
+ type DateListOptions = {
418
+ type: 'dateList';
419
+ options?: {
420
+ showTotal?: boolean; // Display document count
421
+ format?: string; // Date display format
422
+ groupBy?: 'year' | 'month' | 'day'; // Date grouping
423
+ hideLabel?: boolean; // Hide field label
424
+ };
425
+ };
426
+ ```
427
+
428
+ #### `CustomOptions`
429
+ ```typescript
430
+ type CustomOptions = {
431
+ type: 'custom';
432
+ options?: Record<string, any>; // Custom component configuration
433
+ };
434
+ ```
435
+
436
+
437
+ ## Tooltip Configuration
438
+
439
+ ### `AggregationTooltipType` Interface
440
+
441
+ ```typescript
442
+ type AggregationTooltipType = {
443
+ properties: Record<string, any>;
444
+ } & (TooltipPlainText | TooltipLocalizedText | TooltipFormattedDate | TooltipTranslationKey | TooltipTranslatedDate);
445
+
446
+ type TooltipPlainText = {
447
+ type: 'text'; // Defines this variant as plain text.
448
+ separator?: string; //Optional separator used between multiple values.
449
+ };
450
+
451
+ type TooltipLocalizedText = {
452
+ type: 'localizeValue';
453
+ translateKey: string; //Key used for localization.
454
+ };
455
+
456
+ type TooltipFormattedDate = {
457
+ type: 'date';
458
+ format: string; //Date format string (e.g., `YYYY-MM-DD`).
459
+ separator?: string;
460
+ };
461
+
462
+ type TooltipTranslationKey = {
463
+ type: 'translate';
464
+ prefix: string; //Prefix to be appended to the value as a key.
465
+ separator?: string;
466
+ };
467
+
468
+ type TooltipTranslatedDate = {
469
+ type: 'translatedDate';
470
+ format: string;
471
+ translateKey: string;
472
+ };
473
+ ```
474
+
475
+ ### Example Usage
476
+
477
+ ```typescript
478
+
479
+ const fieldWithHelp: AggregationFieldConfig = {
480
+ // ... other properties
481
+ tooltip: {
482
+ type: 'localizeValue',
483
+ translateKey: 'HELP.filterUsage',
484
+ },
485
+ }
486
+
487
+ const fieldWithDateHelp: AggregationFieldConfig = {
488
+ // ... other properties
489
+ tooltip: {
490
+ type: 'date',
491
+ properties: {
492
+ from: 'from',
493
+ to: 'to',
494
+ },
495
+ },
496
+ }
497
+ ```
498
+
499
+
500
+ ## Field Search Configuration
501
+ ### `SearchConfig` Interface
502
+ The `SearchConfig` type enables dynamic search functionality within filter fields, providing configurable search endpoints with template-based query generation.
503
+
504
+ ```ts
505
+ type SearchConfig = {
506
+ /**
507
+ * Placeholder text for the search input.
508
+ */
509
+ placeholder?: string;
510
+
511
+ /**
512
+ * Query configuration for the search.
513
+ */
514
+ query: {
515
+ /**
516
+ * The field to be queried.
517
+ */
518
+ field?: string;
519
+
520
+ /**
521
+ * HTTP method to use for the query.
522
+ * Can be either 'get' or 'post'.
523
+ */
524
+ method?: 'get' | 'post';
525
+
526
+ /**
527
+ * The URL endpoint for the query.
528
+ */
529
+ url: string;
530
+
531
+ /**
532
+ * Operator to use for comparison in the query.
533
+ */
534
+ operator?: ComparisonOperator;
535
+
536
+ /**
537
+ * Template string for dynamic query generation.
538
+ * Variables enclosed in double braces will be replaced with search values.
539
+ * Example: "dc:title {{searchText}} AND status:active"
540
+ */
541
+ template?: InterpolateString;
542
+
543
+ /**
544
+ * Query parameters as key-value pairs.
545
+ */
546
+ params?: Record<string | number, string | number>;
547
+
548
+ /**
549
+ * HTTP headers as key-value pairs.
550
+ */
551
+ headers?: Record<string | number, string | number>;
552
+ };
553
+ };
554
+ ```
555
+
556
+ #### Template String Interpolation
557
+ The `template` property supports dynamic value replacement using double brace syntax `{{variableName}}`. The most common variable is `searchText`, which represents the user's input.
558
+
559
+ **Template Examples**
560
+
561
+ ```typescript
562
+ // Basic title search
563
+ "dc:title ILIKE '{{searchText}}%'"
564
+
565
+ // Complex multi-field search
566
+ "(dc:title LIKE '%{{searchText}}%' OR dc:description LIKE '%{{searchText}}%') AND ecm:currentLifeCycleState = 'active'"
567
+
568
+ // Date-based search with user input
569
+ "dc:created >= '{{startDate}}' AND dc:created <= '{{endDate}}' AND dc:title LIKE '%{{search
570
+ ```
571
+
572
+ **Basic Search with Template**
573
+ ```json
574
+ {
575
+ "search": {
576
+ "placeholder": "Search documents...",
577
+ "query": {
578
+ "url": "/api/v1/search/documents",
579
+ "method": "post",
580
+ "field": "dc:title",
581
+ "operator": "ILIKE",
582
+ "template": "'%{{searchText}}%'",
583
+ "headers": {
584
+ "Content-Type": "application/json"
585
+ }
586
+ }
587
+ }
588
+ }
589
+ ```
590
+
591
+ ## 2. Predicate Fields
592
+ ### `PredicateFieldConfig` interface
593
+ ```ts
594
+ type PredicateFieldConfig = BaseFieldConfig & {
595
+ sendMode: Exclude<FieldSendModeType, 'custom'>;
596
+ render: InputOptions | DateInputOptions;
597
+ }
598
+ ```
599
+
600
+ ## Render Options
601
+ ### Available Render Types
602
+
603
+ The `render` property accepts one of several specialized option types:
604
+
605
+ #### `InputOptions`
606
+ ```typescript
607
+ type InputOptions = {
608
+ type: 'input';
609
+ options?: {
610
+ hideLabel?: boolean
611
+ inputType?: 'text' | 'search' | 'url';
612
+ placeholder?: string;
613
+ debounceTime?: number;
614
+ mask?: InputMaskConfig;
615
+ suffix?: InputSuffixConfig;
616
+ }
617
+ };
618
+ ```
619
+
620
+ ### Properties
621
+
622
+ | Property | Type | Required | Description |
623
+ | ---------------------- | --------------------------------- | -------- | ------------------------------------------- |
624
+ | `type` | `'input'` | ✅ | Field type identifier (always `'input'`) |
625
+ | `options.hideLabel` | `boolean` | ❌ | If true, hides the field label |
626
+ | `options.inputType` | `'text'` \| `'search'` \| `'url'` | ❌ | Specifies the HTML input type |
627
+ | `options.placeholder` | `string` | ❌ | Placeholder text displayed inside the input |
628
+ | `options.debounceTime` | `number` | ❌ | Debounce time (ms) for emitting changes |
629
+
630
+ ### `InputMaskConfig` Type
631
+ ```ts
632
+ type InputMaskConfig = {
633
+ mask: string;
634
+ shownMaskExpression?: string;
635
+ dropSpecialCharacters?: boolean;
636
+ showMaskTyped?: boolean;
637
+ validation?: boolean;
638
+ allowNegativeNumbers?: boolean;
639
+ keepCharacterPositions?: boolean;
640
+ leadZero?: boolean;
641
+ hiddenInput?: boolean;
642
+ clearIfNotMatch?: boolean;
643
+ prefix?: string;
644
+ suffix?: string;
645
+ };
646
+ ```
647
+
648
+ ### Properties
649
+
650
+ |Property|Type|Required|Description|
651
+ |---|---|---|---|
652
+ |`mask`|`string`|✅|Pattern for text masking|
653
+ |`shownMaskExpression`|`string`|❌|Visible mask guide|
654
+ |`dropSpecialCharacters`|`boolean`|❌|Remove non-alphanumeric chars|
655
+ |`showMaskTyped`|`boolean`|❌|Display mask during typing|
656
+ |`validation`|`boolean`|❌|Enable input validation|
657
+ |`allowNegativeNumbers`|`boolean`|❌|Allow negative numeric values|
658
+ |`keepCharacterPositions`|`boolean`|❌|Maintain cursor position|
659
+ |`leadZero`|`boolean`|❌|Keep leading zeros|
660
+ |`hiddenInput`|`boolean`|❌|Hide raw input value|
661
+ |`clearIfNotMatch`|`boolean`|❌|Clear invalid input|
662
+ |`prefix`|`string`|❌|Fixed prefix text|
663
+ |`suffix`|`string`|❌|Fixed suffix text|
664
+
665
+ ### `InputSuffixConfig` Type
666
+
667
+ ```ts
668
+ type InputSuffixConfig = {
669
+ text?: string;
670
+ dropdown?: {
671
+ selectedValue?: string;
672
+ items: KeyValue<TranslateKey, string>[];
673
+ };
674
+ tooltip?: string;
675
+ dialog?: HtmlDialogConfig;
676
+ };
677
+ ```
678
+
679
+ ### Properties
680
+
681
+ | Property | Type | Required | Description |
682
+ | ------------------ | ---------------------------------------------------------------------- | -------- | ---------------------------------- |
683
+ | `text` | `string` | ❌ | Static text displayed as suffix |
684
+ | `dropdown` | `{ selectedValue?: string; items: KeyValue<TranslateKey, string>[]; }` | ❌ | Adds a dropdown menu to the suffix |
685
+ | └─ `selectedValue` | `string` | ❌ | Currently selected value |
686
+ | └─ `items` | `KeyValue<TranslateKey, string>[]` | ✅ | Dropdown list items |
687
+ | `tooltip` | `string` | ❌ | Tooltip displayed on hover |
688
+ | `dialog` | `HtmlDialogConfig` | ❌ | Configuration for a modal dialog |
689
+
690
+ ### `HtmlDialogConfig` Interface
691
+ ```ts
692
+ export type HtmlDialogConfig = {
693
+ content: string[];
694
+ title?: string;
695
+ options?: Partial<MatDialogConfig>;
696
+ };
697
+ ```
698
+
699
+ ### Properties
700
+
701
+ | Property | Type | Required | Description |
702
+ | --------- | -------------------------- | -------- | ------------------------------------------------------------ |
703
+ | `content` | `string[]` | ✅ | ##translate keys## or content lines to display in the dialog |
704
+ | `title` | `string` | ❌ | Dialog title text |
705
+ | `options` | `Partial<MatDialogConfig>` | ❌ | Angular Material dialog configuration overrides |
706
+ ### Example Usage
707
+
708
+ ```json
709
+ {
710
+ "type": "predicate",
711
+ "config": {
712
+ "label": "FILTERS.searchTerm",
713
+ "fieldKey": "searchQuery",
714
+ "sendMode": "payload",
715
+ "render": {
716
+ "type": "input",
717
+ "options": {
718
+ "placeholder": "Enter your query...",
719
+ "debounceTime": 400,
720
+ "inputType": "text",
721
+ "mask": {
722
+ "mask": "000-000",
723
+ "dropSpecialCharacters": true
724
+ },
725
+ "suffix": {
726
+ "text": "?",
727
+ "tooltip": "Search by reference number"
728
+ }
729
+ }
730
+ }
731
+ }
732
+ }
733
+
734
+ ```
735
+
736
+
737
+ ## 2. Custom Fields
738
+ ### `CustomFieldConfig` interface
739
+ ```ts
740
+ type CustomFieldConfig = BaseFieldConfig & {
741
+ sendMode: Exclude<FieldSendModeType, 'custom'>;
742
+ render: ActiveUserSwitcherOptions | AggregationGroupOptions;
743
+ }
744
+ ```
745
+
746
+ ## Render Options
747
+ ### Available Render Types
748
+
749
+ The `render` property accepts one of `ActiveUserSwitcherOptions` and `AggregationGroupOptions` :
750
+
751
+ ### `ActiveUserSwitcherOptions` Type
752
+
753
+ ```ts
754
+ type ActiveUserSwitcherOptions = {
755
+ type: 'activeUser';
756
+ options?: HideLabel & {
757
+ bindValue?: string;
758
+ text?: string;
759
+ }
760
+ };
761
+ ```
762
+ ### Properties
763
+ | Property | Type | Required | Description |
764
+ | ------------------- | -------------- | -------- | ------------------------------------------- |
765
+ | `type` | `'activeUser'` | ✅ | Identifier for active user switch rendering |
766
+ | `options.bindValue` | `string` | ❌ | Key to bind user value (e.g., user ID) |
767
+ | `options.text` | `string` | ❌ | translated key |
768
+ | `options.hideLabel` | `boolean` | ❌ | If true, hides the label in the UI |
769
+
770
+ ### `AggregationGroupOptions` Type
771
+
772
+ Enables rendering of a grouped set of aggregation-based filters as a single field. Each item behaves like a standard aggregation input field.
773
+ ```ts
774
+ export type AggregationGroupOptions = {
775
+ type: 'aggregationGroup';
776
+ options?: {
777
+ aggregations: AggregationGroupItem[];
778
+ };
779
+ };
780
+
781
+ /*
782
+ `AggregationGroupItem` Type
783
+ */
784
+
785
+ interface AggregationGroupItem
786
+ extends Omit<AggregationFieldConfig, 'render' | 'valueType' | 'sendMode'> {
787
+ render: CheckboxOptions | SwitchOptions | RadioOptions | DropdownOptions;
788
+ }
789
+
790
+ ```
791
+
792
+ ### Properties
793
+ |Property|Type|Required|Description|
794
+ |---|---|---|---|
795
+ |`type`|`'aggregationGroup'`|✅|Field type identifier|
796
+ |`options.aggregations`|`AggregationGroupItem[]`|✅|List of aggregation-based fields rendered as a group|
797
+ |└─ `render`|`CheckboxOptions` \| `SwitchOptions` \| `RadioOptions` \| `DropdownOptions`|✅|Rendering configuration for each sub-field|
798
+
799
+ ### Example Usage
800
+
801
+ ```json
802
+ {
803
+ "type": "custom",
804
+ "config": {
805
+ "label": "",
806
+ "fieldKey": "gdoc:categoryHierarchyCode",
807
+ "sendMode": "payload",
808
+ "valueType": "valueObject",
809
+ "render": {
810
+ "type": "aggregationGroup",
811
+ "options": {
812
+ "aggregations": [
813
+ {
814
+ "label": "rmAdvancedSearch.gdocCategoryHierarchyCode",
815
+ "aggregation": "generaldocument_categoryHierarchyCode_agg",
816
+ "fieldKey": "categoryHierarchyCode",
817
+ "dataTransformer": "subject",
818
+ "order": 0,
819
+ "render": {
820
+ "type": "checkbox",
821
+ "options": {
822
+ "showTotal": true
823
+ }
824
+ }
825
+ },
826
+ {
827
+ "label": "rmAdvancedSearch.gdocCategoryHierarchyCode1",
828
+ "aggregation": "generaldocument_categoryHierarchyCode_1_agg",
829
+ "fieldKey": "categoryHierarchyCode_1_agg",
830
+ "order": 0,
831
+ "dataTransformer": "subject",
832
+ "render": {
833
+ "type": "checkbox",
834
+ "options": {
835
+ "showTotal": true,
836
+ "collapse": true
837
+ }
838
+ }
839
+ }
840
+ ]
841
+ }
842
+ }
843
+ }
844
+ }
845
+
846
+ ```
847
+
848
+
849
+ ---
850
+ # Utilities & Advanced Features
851
+ ## Query Encoding & Decoding
852
+
853
+ The `FilterQueryService` provides utility methods to **serialize and deserialize filter states** between object-based formats and compact, URL-safe strings. This enables sharing and persisting filter configurations via query parameters or external storage.
854
+
855
+ It uses a **short key mapping system** to reduce payload size, especially for deeply nested predicate filters.
856
+
857
+ > **Note:** Before encoding or decoding custom filters, you must call `registerKeys()` in your `CoreModule` || 'AppModule' to define how long property names map to short ones. This is essential for consistency between encoded and decoded queries.
858
+
859
+ ### Service: `FilterQueryService`
860
+
861
+ ```ts
862
+ @Injectable({ providedIn: 'root' })
863
+ export class FilterQueryService {
864
+ // Registers a set of key mappings
865
+ registerKeys(keys: Record<string, string>): void;
866
+
867
+ // Registers a single key mapping
868
+ registerKey(longKey: string, shortKey: string): void;
869
+
870
+ // Encodes a query object into a URL-safe string
871
+ encodeQuery(query: Record<string, any>): string;
872
+
873
+ // Decodes an encoded query string back into its original object structure
874
+ decodeQuery(encodedQuery: string): Record<string, any> | null;
875
+ }
876
+ ```
877
+
878
+
879
+ ### Example: Registering Field Keys
880
+
881
+ ```ts
882
+ //file : core.module.ts
883
+ this.filterQueryService.registerKeys({
884
+ 'ecm:primaryType': 'EPT',
885
+ 'requestcase:requestNumber': 'RRN',
886
+ 'ecm:currentLifeCycleState': 'ECL',
887
+ 'dublincore_created_agg': 'DCA',
888
+ 'requestcase_dueDate_agg': 'RDA',
889
+ 'requestcase_dueDate_1_agg': 'RD1'
890
+ });
891
+ ```
892
+
893
+ This ensures that a query like:
894
+ ```ts
895
+ {
896
+ 'ecm:primaryType': ['Case'],
897
+ 'requestcase:requestNumber': {
898
+ value: '12345',
899
+ operator: 'EQUALS'
900
+ }
901
+ }
902
+ ```
903
+ …is encoded as:
904
+ ```json
905
+ {
906
+ "EPT": ["Case"],
907
+ "RRN": { "v": "12345", "o": "EQUALS" }
908
+ }
909
+ ```
910
+ …and will decode back into the original format using the same mappings.
911
+
912
+ ### Encoding Example
913
+ ```ts
914
+ const filters = {
915
+ 'ecm:primaryType': ['Case'],
916
+ 'requestcase:requestNumber': {
917
+ value: '12345',
918
+ operator: 'EQUALS'
919
+ }
920
+ };
921
+
922
+ const encoded = this.filterQueryService.encodeQuery(filters);
923
+ // Output: "%7BEPT%3A%5B%22Case%22%5D%2CRRN%3A%7Bv%3A%2212345%22%2Co%3A%22EQUALS%22%7D%7D"
924
+ ```
925
+
926
+ ### Decoding Example
927
+ ```ts
928
+ const encoded = '%7BEPT%3A%5B%22Case%22%5D%2CRRN%3A%7Bv%3A%2212345%22%2Co%3A%22EQUALS%22%7D%7D';
929
+ const decoded = this.filterQueryService.decodeQuery(encoded);
930
+ // Output:
931
+ {
932
+ 'ecm:primaryType': ['Case'],
933
+ 'requestcase:requestNumber': {
934
+ value: '12345',
935
+ operator: 'EQUALS'
936
+ }
937
+ }
938
+ ```
939
+
940
+ ### Best Practices
941
+ 1. **Register all custom keys** during application initialization
942
+ 2. **Pre-process special characters** in values
943
+ 3. **Maintain mapping consistency** across environments
944
+ 4. **Test round-trip encoding** for complex queries
945
+ 5. **Handle null returns** in decoding operations
946
+
947
+ ```ts
948
+ // Safe decoding pattern
949
+ const decoded = this.filterQueryService.decodeQuery(params) || {};
950
+ ```
951
+
952
+
953
+ ## Evaluator Sandbox
954
+
955
+ The `condition` parameter allows developers to define dynamic logical expressions that determine visibility, execution, or behavior within applications—without compromising security. These expressions are evaluated within a tightly controlled sandbox to prevent access to unsafe or unintended resources.
956
+ ### Current Secure Context Implementation
957
+
958
+ The Evaluator function Structure with Conditional Execution
959
+ ```ts
960
+ (function anonymous(aggregations, language, user, values, sandbox) {
961
+ // Securely exposed globals
962
+ const console = sandbox.console;
963
+ const Math = sandbox.Math;
964
+ const Date = sandbox.Date;
965
+ const Number = sandbox.Number;
966
+ const String = sandbox.String;
967
+ const Boolean = sandbox.Boolean;
968
+ const Array = sandbox.Array;
969
+ const Object = sandbox.Object;
970
+ const JSON = sandbox.JSON;
971
+ const window = sandbox.window;
972
+ const self = sandbox.self;
973
+ const globalThis = sandbox.globalThis;
974
+ const _ = sandbox._; // Lodash
975
+ var show;
976
+ // your conditional logic here
977
+ // Example:
978
+ // show = user.role === 'admin' && values.status === 'active'; console.log('Access granted');
979
+ return show
980
+ }
981
+ )
982
+
983
+ ```
984
+
985
+ >**Note:**
986
+ - **`show` is always the expected return variable** — the condition must assign to it.
987
+ - **Function parameters are dynamic in most cases**, **but in the context of a field config**, the function signature is **fixed**.
988
+ ### Writing a Condition
989
+ ```json
990
+ {
991
+ "condition": "show = user.role === 'admin' && values.status === 'active'; console.log('Access granted');"
992
+ }
993
+ ```
994
+
995
+
996
+
997
+ ## Troubleshooting
998
+
999
+ ### Common Issues
1000
+
1001
+ #### 1. Transformer Not Found
1002
+
1003
+ **Error**: `No transformer defined for type 'subject'` **Solution**: Register the transformer using the appropriate service method:
1004
+
1005
+ ```typescript
1006
+
1007
+ ndfTransformService.register('subject', (keys) => {});
1008
+
1009
+ ```
1010
+
1011
+ #### 2. Query not encoding
1012
+
1013
+ **Error**: `Query key mapping not found for 'SOME KEY'.` **Solution**: Register the key in `FilterQueryService` before using:
1014
+
1015
+ ```typescript
1016
+ FilterQueryService.registerKey('long Key', 'short Key');
1017
+ ```
1018
+
1019
+ #### 3. Field Condition not applied
1020
+
1021
+ **Error**: `condition not working or drop a warrnig message` **Solution**: Check and the evaluated string and make sure append value to declared variable 'show' :
1022
+
1023
+ ```ts
1024
+ //example
1025
+ show = values && values['any']?.includes('some');
1026
+ ```