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.
- package/bundles/nuxeo-development-framework.umd.js +214 -174
- package/bundles/nuxeo-development-framework.umd.js.map +1 -1
- package/esm2015/lib/components/comments/components/edit-delete-modal/edit-delete-modal.component.js +1 -1
- package/esm2015/lib/components/dynamic-form/components/department-form/department-form.component.js +1 -1
- package/esm2015/lib/components/file-manger/components/create-modal/create-modal.component.js +1 -1
- package/esm2015/lib/components/file-manger/components/creation-type/creation-type.component.js +1 -1
- package/esm2015/lib/components/file-manger/components/folder-modal/folder-modal.component.js +1 -1
- package/esm2015/lib/components/file-manger/components/publish-dialog/publish-dialog.component.js +1 -1
- package/esm2015/lib/components/file-manger/components/scan-modal/scan-modal.component.js +1 -1
- package/esm2015/lib/components/file-manger/components/share-dialog/share-dialog.component.js +1 -1
- package/esm2015/lib/components/file-manger/components/template-modal/template-modal.component.js +1 -1
- package/esm2015/lib/components/file-manger/components/update-modal/update-modal.component.js +1 -1
- package/esm2015/lib/components/ndf-config-editor/components/config-editor-actions/config-editor-actions.component.js +2 -2
- package/esm2015/lib/components/ndf-config-editor/components/info-dialog/info-dialog.component.js +10 -4
- package/esm2015/lib/components/ndf-config-editor/containers/ndf-config-editor/ndf-config-editor.component.js +3 -3
- package/esm2015/lib/components/ndf-config-editor/models/config.js +1 -1
- package/esm2015/lib/components/ndf-config-editor/models/dialog-data.js +1 -1
- package/esm2015/lib/components/ndf-filters/components/__parts/html-dialog/html-dialog.component.js +1 -1
- package/esm2015/lib/components/ndf-filters/models/field-options/input-options.js +1 -1
- package/esm2015/lib/components/ndf-tabs/component/ndf-tabs.component.js +7 -5
- package/esm2015/lib/components/permissions/add-permissions-dialog/add-permissions-dialog.component.js +1 -1
- package/esm2015/lib/components/reports/ndf-reports/base/base-graph.report.js +3 -3
- package/esm2015/lib/components/reports/ndf-reports/components/_parts/custom-chart-dialog/custom-chart-dialog.component.js +1 -1
- package/esm2015/lib/components/reports/ndf-reports/components/_parts/graph-dialog/graph-dialog.component.js +1 -1
- package/esm2015/lib/components/reports/ndf-reports/components/_parts/timeline-dialog/timeline-dialog.component.js +1 -1
- package/esm2015/lib/components/reports/ndf-reports/containers/ndf-reports/ndf-reports.component.js +9 -2
- package/esm2015/lib/components/reports/ndf-reports/services/chart-manager.service.js +25 -2
- package/esm2015/lib/shared/components/nuxeo-dialog/confirmation/ndf-confirmation-dialog.component.js +1 -1
- package/esm2015/lib/shared/components/nuxeo-dialog/nuxeo.dialog.js +5 -2
- package/fesm2015/nuxeo-development-framework.js +197 -157
- package/fesm2015/nuxeo-development-framework.js.map +1 -1
- package/lib/components/ndf-config-editor/components/config-editor-actions/config-editor-actions.component.d.ts +2 -2
- package/lib/components/ndf-config-editor/components/info-dialog/info-dialog.component.d.ts +4 -3
- package/lib/components/ndf-config-editor/containers/ndf-config-editor/ndf-config-editor.component.d.ts +2 -2
- package/lib/components/ndf-config-editor/models/config.d.ts +7 -3
- package/lib/components/ndf-config-editor/models/dialog-data.d.ts +2 -1
- package/lib/components/ndf-filters/components/predicate-text-input/predicate-text-input.component.d.ts +1 -14
- package/lib/components/ndf-filters/models/field-options/input-options.d.ts +25 -23
- package/lib/components/ndf-tabs/component/ndf-tabs.component.d.ts +3 -3
- package/lib/components/reports/ndf-reports/containers/ndf-reports/ndf-reports.component.d.ts +1 -0
- package/lib/components/reports/ndf-reports/services/chart-manager.service.d.ts +1 -0
- package/lib/shared/components/nuxeo-dialog/nuxeo.dialog.d.ts +2 -1
- package/package.json +1 -1
- package/src/docs/ndf-filters.doc.md +1026 -0
- 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
|
+
```
|