@yuuvis/client-framework 3.18.0 → 3.19.0
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/fesm2022/yuuvis-client-framework-forms.mjs +4 -2
- package/fesm2022/yuuvis-client-framework-forms.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-object-preview.mjs +25 -13
- package/fesm2022/yuuvis-client-framework-object-preview.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-renderer.mjs +81 -8
- package/fesm2022/yuuvis-client-framework-renderer.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-smart-search.mjs +385 -61
- package/fesm2022/yuuvis-client-framework-smart-search.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-tile-list.mjs +2 -2
- package/fesm2022/yuuvis-client-framework-tile-list.mjs.map +1 -1
- package/package.json +5 -5
- package/smart-search/README.md +57 -7
- package/types/yuuvis-client-framework-object-preview.d.ts +14 -1
- package/types/yuuvis-client-framework-renderer.d.ts +23 -2
- package/types/yuuvis-client-framework-smart-search.d.ts +145 -19
- package/types/yuuvis-client-framework-tile-list.d.ts +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yuuvis/client-framework",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.19.0",
|
|
4
4
|
"author": "OPTIMAL SYSTEMS GmbH <npm@optimal-systems.de>",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"peerDependencies": {
|
|
@@ -8,16 +8,16 @@
|
|
|
8
8
|
"@angular/common": "^21.2.19",
|
|
9
9
|
"@angular/core": "^21.2.19",
|
|
10
10
|
"angular-gridster2": "^21.0.1",
|
|
11
|
-
"@yuuvis/client-core": "^3.
|
|
12
|
-
"@yuuvis/client-shell-core": "^3.
|
|
13
|
-
"@yuuvis/client-components": "^3.
|
|
11
|
+
"@yuuvis/client-core": "^3.19.0",
|
|
12
|
+
"@yuuvis/client-shell-core": "^3.19.0",
|
|
13
|
+
"@yuuvis/client-components": "^3.19.0",
|
|
14
14
|
"ng-dynamic-component": "^10.8.2",
|
|
15
15
|
"modern-normalize": "^3.0.1"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@angular/material": "^21.2.14",
|
|
19
19
|
"@ngrx/signals": "^21.1.0",
|
|
20
|
-
"@yuuvis/material": "^3.
|
|
20
|
+
"@yuuvis/material": "^3.19.0",
|
|
21
21
|
"@yuuvis/media-viewer": "^4.0.0",
|
|
22
22
|
"angular-split": "^20.0.0",
|
|
23
23
|
"vis-network": "^10.0.2",
|
package/smart-search/README.md
CHANGED
|
@@ -46,16 +46,66 @@ export class SearchComponent {
|
|
|
46
46
|
|
|
47
47
|
### Inputs
|
|
48
48
|
|
|
49
|
-
| Input
|
|
50
|
-
|
|
|
51
|
-
| `types`
|
|
52
|
-
| `skipProperties`
|
|
49
|
+
| Input | Type | Default | Description |
|
|
50
|
+
| -------------------------- | ---------- | ------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
51
|
+
| `types` | `string[]` | `[]` | Object-type ids that may be searched. Set at least one to enable building blocks. |
|
|
52
|
+
| `skipProperties` | `string[]` | `[]` | Field ids to hide from the field picker (e.g. internal/system properties). |
|
|
53
|
+
| `fulltextOnly` | `boolean` | `false` | Renders only the full-text bar — no condition builder. See [Full-text only](#full-text-only). |
|
|
54
|
+
| `supportDynamicConditions` | `boolean` | `false` | Enables marking conditions as *dynamic* and the form-mode toggle that swaps the builder for a fill-out form of those fields. |
|
|
53
55
|
|
|
54
56
|
### Outputs
|
|
55
57
|
|
|
56
|
-
| Output | Type | Description
|
|
57
|
-
| ------------- | -------- |
|
|
58
|
-
| `queryChange` | `string` | The current CMIS query. Emitted on every change; `''` means an empty search ("no query").
|
|
58
|
+
| Output | Type | Description |
|
|
59
|
+
| ------------- | -------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
60
|
+
| `queryChange` | `string` | The current CMIS query. Emitted on **every** change; `''` means an empty search ("no query"). |
|
|
61
|
+
| `querySubmit` | `string` | The current CMIS query, emitted when the user presses <kbd>Enter</kbd> to submit. Same `''` convention. |
|
|
62
|
+
|
|
63
|
+
### Full-text only
|
|
64
|
+
|
|
65
|
+
`fulltextOnly` reduces the component to a plain full-text search: the term box, the scope
|
|
66
|
+
select and the object-type filter stay, everything else — type blocks, the add-type row, the
|
|
67
|
+
inline condition editor and the form-mode toggle — is not rendered.
|
|
68
|
+
|
|
69
|
+
```html
|
|
70
|
+
<yuv-smart-search [types]="['document', 'invoice']" [fulltextOnly]="true" (querySubmit)="runSearch($event)" />
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`types` keeps its meaning, so the emitted query is still scoped to the allowed types:
|
|
74
|
+
|
|
75
|
+
```sql
|
|
76
|
+
-- types=['document','invoice'], full-text "acme", type filter left on "All types"
|
|
77
|
+
SELECT * FROM system:object WHERE (objectTypeId IN ('document','invoice') AND CONTAINS('acme'))
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Because the blocks are not rendered, they are not queried either: a state restored via
|
|
81
|
+
`loadState()` keeps its blocks (they come back when the flag is cleared) but only its full-text
|
|
82
|
+
unit contributes to the emitted query while the flag is set.
|
|
83
|
+
|
|
84
|
+
### Submitting with Enter
|
|
85
|
+
|
|
86
|
+
`queryChange` is a live preview — it fires on every keystroke and every edit. To run a
|
|
87
|
+
search only when the user is *done*, bind `querySubmit` instead: it behaves like an HTML
|
|
88
|
+
form, emitting when <kbd>Enter</kbd> reaches the component without an inner widget having
|
|
89
|
+
claimed the key.
|
|
90
|
+
|
|
91
|
+
Widgets that own <kbd>Enter</kbd> for their own purpose keep it, so a submit never
|
|
92
|
+
happens by surprise:
|
|
93
|
+
|
|
94
|
+
| Where <kbd>Enter</kbd> is pressed | What happens |
|
|
95
|
+
| ------------------------------------------------ | ------------------------------------------------ |
|
|
96
|
+
| Suggestion list open (type / field / operator) | Picks the highlighted suggestion |
|
|
97
|
+
| Catalog, date or other value widget with a panel | Opens the panel / picks the value |
|
|
98
|
+
| Inline editor with a condition in progress | Commits the condition — the *next* Enter submits |
|
|
99
|
+
| Add-type input with staged types | Confirms the type block |
|
|
100
|
+
| Focus on a button (remove, confirm, …) | Activates the button |
|
|
101
|
+
| Anywhere else (full-text bar, fill-out form, …) | **Submits** — `querySubmit` emits |
|
|
102
|
+
|
|
103
|
+
<kbd>Shift</kbd>+<kbd>Enter</kbd> and <kbd>Enter</kbd> inside a multi-line value never
|
|
104
|
+
submit, so long text entry keeps working.
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<yuv-smart-search [types]="types" (queryChange)="preview.set($event)" (querySubmit)="runSearch($event)" />
|
|
108
|
+
```
|
|
59
109
|
|
|
60
110
|
### Saving and restoring state
|
|
61
111
|
|
|
@@ -61,7 +61,20 @@ declare class ObjectPreviewService {
|
|
|
61
61
|
dmsObject: _angular_core.Signal<DmsObject | undefined>;
|
|
62
62
|
setDmsObject(object: DmsObject): void;
|
|
63
63
|
getDmsObject(id: string): Observable<DmsObject>;
|
|
64
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Builds the media viewer source URL for an object's content.
|
|
66
|
+
*
|
|
67
|
+
* The URL of the *current* version is keyed on the content stream (`_cs=<contentStreamId>`) when one is
|
|
68
|
+
* given. The viewers only reload when their `src` input is a *different string*: `DynamicViewerDirective`
|
|
69
|
+
* `setInput`s the same viewer instance for a same-type update, `PdfComponent` skips `#loadPDF` for a src
|
|
70
|
+
* it has already loaded and `ImageComponent` derives its cache-busting URL from `src()` alone. Without
|
|
71
|
+
* the key a content replacement that keeps the mime type kept showing the previous file (the object id,
|
|
72
|
+
* and therefore the URL, never changed). `ObjectPreviewComponent` rebuilds the details exactly when the
|
|
73
|
+
* content stream changes, so the key changes exactly then — never on metadata-only saves.
|
|
74
|
+
*
|
|
75
|
+
* Versioned URLs (`/versions/{n}/…`) address immutable content and are returned unchanged.
|
|
76
|
+
*/
|
|
77
|
+
getMediaViewerSrc(id: string, mimeType: string | undefined, version?: number, contentStreamId?: string): string;
|
|
65
78
|
getEmailViewerDetails(object: DmsObject, version?: number, MAIL_APP_ID?: string): ViewerDataEmail;
|
|
66
79
|
getEmailMetadata(object: DmsObject, MAIL_APP_ID?: string): EmailMetadata;
|
|
67
80
|
getViewerDetails(object: DmsObject, version: number | undefined): ViewerDataEmail | ViewerDataDefault | undefined;
|
|
@@ -82,6 +82,11 @@ declare class BooleanRendererComponent extends AbstractRendererComponent {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
declare class DateTimeRendererComponent extends AbstractRendererComponent<Date> {
|
|
85
|
+
/**
|
|
86
|
+
* Fields declared with `resolution: 'date'` hold a calendar day, so rendering them with the
|
|
87
|
+
* default `short` format would invent a time that is not stored anywhere.
|
|
88
|
+
*/
|
|
89
|
+
protected dateOnly: i0.Signal<boolean>;
|
|
85
90
|
static ɵfac: i0.ɵɵFactoryDeclaration<DateTimeRendererComponent, never>;
|
|
86
91
|
static ɵcmp: i0.ɵɵComponentDeclaration<DateTimeRendererComponent, "yuv-datetime-renderer", never, {}, {}, never, never, true, never>;
|
|
87
92
|
}
|
|
@@ -91,6 +96,22 @@ declare class DecimalRendererComponent extends AbstractRendererComponent<number>
|
|
|
91
96
|
static ɵcmp: i0.ɵɵComponentDeclaration<DecimalRendererComponent, "yuv-decimal-renderer", never, {}, {}, never, never, true, never>;
|
|
92
97
|
}
|
|
93
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Renders the value(s) of a dynamic catalog field (schema field carrying a `catalog` reference).
|
|
101
|
+
*
|
|
102
|
+
* Those fields store the technical entry name, so the label has to be resolved from the catalog
|
|
103
|
+
* entry's localizations — the same resolution `yuv-dynamic-catalog` does for the form element.
|
|
104
|
+
* The entries are fetched and cached by `CatalogLabelService` (once per catalog, not once per
|
|
105
|
+
* renderer instance — a summary or tile list mounts many rows of the same catalog).
|
|
106
|
+
* Values without a matching entry fall back to the technical value.
|
|
107
|
+
*/
|
|
108
|
+
declare class DynamicCatalogRendererComponent extends AbstractRendererComponent<string | string[]> {
|
|
109
|
+
#private;
|
|
110
|
+
readonly label: i0.Signal<string>;
|
|
111
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<DynamicCatalogRendererComponent, never>;
|
|
112
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<DynamicCatalogRendererComponent, "yuv-dynamic-catalog-renderer", never, {}, {}, never, never, true, never>;
|
|
113
|
+
}
|
|
114
|
+
|
|
94
115
|
declare class FileSizeRendererComponent extends AbstractRendererComponent {
|
|
95
116
|
parsedValue: i0.Signal<number>;
|
|
96
117
|
static ɵfac: i0.ɵɵFactoryDeclaration<FileSizeRendererComponent, never>;
|
|
@@ -162,7 +183,7 @@ declare class UnknownRendererComponent extends AbstractRendererComponent<any> {
|
|
|
162
183
|
static ɵcmp: i0.ɵɵComponentDeclaration<UnknownRendererComponent, "yuv-unknown-renderer", never, {}, {}, never, never, true, never>;
|
|
163
184
|
}
|
|
164
185
|
|
|
165
|
-
type RendererComponent = IntegerRendererComponent | DecimalRendererComponent | DateTimeRendererComponent | IconRendererComponent | StringRendererComponent | BooleanRendererComponent | TableRendererComponent | I18nCatalogRendererComponent;
|
|
186
|
+
type RendererComponent = IntegerRendererComponent | DecimalRendererComponent | DateTimeRendererComponent | IconRendererComponent | StringRendererComponent | BooleanRendererComponent | TableRendererComponent | I18nCatalogRendererComponent | DynamicCatalogRendererComponent;
|
|
166
187
|
type RendererDirectiveInput = ResolvedObjectConfigItem;
|
|
167
188
|
|
|
168
189
|
/**
|
|
@@ -207,5 +228,5 @@ declare class RendererDirective {
|
|
|
207
228
|
static ɵdir: i0.ɵɵDirectiveDeclaration<RendererDirective, "[yuvRenderer]", never, { "yuvRenderer": { "alias": "yuvRenderer"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
208
229
|
}
|
|
209
230
|
|
|
210
|
-
export { AbstractAuditRendererComponent, AbstractRendererComponent, AuditRendererDirective, AuditRendererService, BooleanRendererComponent, DateTimeRendererComponent, DecimalRendererComponent, DefaultAuditRendererComponent, FileSizeRendererComponent, I18nCatalogRendererComponent, IconRendererComponent, IntegerRendererComponent, OrganizationRendererComponent, RendererDirective, RendererService, StringRendererComponent, TableRendererComponent, UnknownRendererComponent };
|
|
231
|
+
export { AbstractAuditRendererComponent, AbstractRendererComponent, AuditRendererDirective, AuditRendererService, BooleanRendererComponent, DateTimeRendererComponent, DecimalRendererComponent, DefaultAuditRendererComponent, DynamicCatalogRendererComponent, FileSizeRendererComponent, I18nCatalogRendererComponent, IconRendererComponent, IntegerRendererComponent, OrganizationRendererComponent, RendererDirective, RendererService, StringRendererComponent, TableRendererComponent, UnknownRendererComponent };
|
|
211
232
|
export type { RendererComponent, RendererDirectiveInput };
|
|
@@ -116,6 +116,12 @@ interface SuggestionItem {
|
|
|
116
116
|
* Capture via {@link SmartSearchComponent.getState} and restore via
|
|
117
117
|
* {@link SmartSearchComponent.loadState}. Safe for `JSON.stringify` /
|
|
118
118
|
* `JSON.parse` roundtrips (plain data, no class instances or signals).
|
|
119
|
+
*
|
|
120
|
+
* The display labels it carries (`SearchBlockType.label`, `FieldCondition.fieldLabel` /
|
|
121
|
+
* `operatorLabel` / `conditionLabel` and `TableCondition.fieldLabel`) are a snapshot of the
|
|
122
|
+
* language the state was captured in. `loadState` re-resolves them from the live schema and the
|
|
123
|
+
* current language, so a state built by hand only needs the ids — the labels are a fallback for
|
|
124
|
+
* ids that can no longer be resolved.
|
|
119
125
|
*/
|
|
120
126
|
interface SmartSearchState {
|
|
121
127
|
blocks: SearchBlock[];
|
|
@@ -154,7 +160,10 @@ interface DynamicFormBlock {
|
|
|
154
160
|
*/
|
|
155
161
|
declare class SmartSearchEditController {
|
|
156
162
|
#private;
|
|
157
|
-
/**
|
|
163
|
+
/**
|
|
164
|
+
* The set of object type IDs the search is scoped to. Empty = unscoped: every
|
|
165
|
+
* searchable type of the schema is a candidate and nothing is restricted.
|
|
166
|
+
*/
|
|
158
167
|
allowedTypes: _angular_core.WritableSignal<string[]>;
|
|
159
168
|
/** ObjectTypeField IDs to exclude from the field-step autocomplete suggestions. */
|
|
160
169
|
skipProperties: _angular_core.WritableSignal<string[]>;
|
|
@@ -189,6 +198,12 @@ declare class SmartSearchEditController {
|
|
|
189
198
|
fulltext: _angular_core.WritableSignal<FulltextSearch>;
|
|
190
199
|
/** Whether the dynamic-conditions feature is enabled (mirrors the host `supportDynamicConditions` input). */
|
|
191
200
|
supportDynamic: _angular_core.WritableSignal<boolean>;
|
|
201
|
+
/**
|
|
202
|
+
* Whether the host renders a plain full-text search (mirrors its `fulltextOnly` input).
|
|
203
|
+
* The condition builder is hidden and {@link cmisQuery} is built from {@link fulltext}
|
|
204
|
+
* alone, so blocks a loaded state carries can't contribute invisible clauses.
|
|
205
|
+
*/
|
|
206
|
+
fulltextOnly: _angular_core.WritableSignal<boolean>;
|
|
192
207
|
/**
|
|
193
208
|
* Form mode: replace the builder with a generated form of the user-marked dynamic
|
|
194
209
|
* conditions. View state only — the template ({@link blocks}) is never mutated; the
|
|
@@ -207,6 +222,17 @@ declare class SmartSearchEditController {
|
|
|
207
222
|
/** Whether any condition is marked dynamic (gates the form-mode toggle). */
|
|
208
223
|
hasDynamicConditions: _angular_core.Signal<boolean>;
|
|
209
224
|
objectTypes: _angular_core.Signal<GenericObjectType[]>;
|
|
225
|
+
/**
|
|
226
|
+
* The types an "all types" pick resolves to. With a configured allow-list, "all types"
|
|
227
|
+
* means *any of the allowed types* — not every type of the system — so the restriction
|
|
228
|
+
* is still emitted. Without one the list is empty and "all types" restricts nothing.
|
|
229
|
+
*
|
|
230
|
+
* Resolved id-by-id against the schema (rather than from {@link objectTypes}) so an
|
|
231
|
+
* allowed id the current schema doesn't know still narrows the query instead of silently
|
|
232
|
+
* widening it; `isSot` decides whether the id lands in the primary or the secondary
|
|
233
|
+
* object-type clause.
|
|
234
|
+
*/
|
|
235
|
+
scopeTypes: _angular_core.Signal<SearchBlockType[]>;
|
|
210
236
|
/** Fields for the active top-level block, used by the field-step suggestions. */
|
|
211
237
|
activeBlockFields: _angular_core.Signal<SuggestionItem[]>;
|
|
212
238
|
/**
|
|
@@ -229,7 +255,16 @@ declare class SmartSearchEditController {
|
|
|
229
255
|
activeCtrl: _angular_core.Signal<FormControl<unknown>>;
|
|
230
256
|
/** Deep-clone the current blocks, combinator and full-text unit into a serializable {@link SmartSearchState}. */
|
|
231
257
|
getState(): SmartSearchState;
|
|
232
|
-
/**
|
|
258
|
+
/**
|
|
259
|
+
* Replace the current state with a saved one, normalizing legacy blocks and cancelling any
|
|
260
|
+
* in-progress edit.
|
|
261
|
+
*
|
|
262
|
+
* Everything a persisted state carries for display only — type, field and operator labels and
|
|
263
|
+
* the composed condition label — is re-resolved against the live schema and the *current* UI
|
|
264
|
+
* language (see {@link #resolveType} / {@link #relabelNodes}), so a query saved in one language
|
|
265
|
+
* reads in the language it is restored in. The persisted strings act as the fallback for ids the
|
|
266
|
+
* schema or the translations can no longer resolve.
|
|
267
|
+
*/
|
|
233
268
|
loadState(state: SmartSearchState): void;
|
|
234
269
|
/** Reset all search state back to its initial empty values. */
|
|
235
270
|
reset(): void;
|
|
@@ -245,9 +280,19 @@ declare class SmartSearchEditController {
|
|
|
245
280
|
exitFormMode(): void;
|
|
246
281
|
/** Toggle form mode (rebuilds the form rows on each entry). */
|
|
247
282
|
toggleFormMode(): void;
|
|
248
|
-
/**
|
|
283
|
+
/**
|
|
284
|
+
* Record a value entered in the form for a dynamic condition (drives the overlaid
|
|
285
|
+
* {@link cmisQuery}). No-op when unchanged, so re-applying a row's current value —
|
|
286
|
+
* e.g. flushing the debounced controls on submit — can't churn the query.
|
|
287
|
+
*/
|
|
249
288
|
setFormValue(condition: FieldCondition, raw: unknown): void;
|
|
250
|
-
/**
|
|
289
|
+
/**
|
|
290
|
+
* Re-apply every generated form row's current control value. The row controls are
|
|
291
|
+
* debounced, so a submit fired immediately after typing would otherwise read a stale
|
|
292
|
+
* overlay. Rows whose value already matches are skipped by {@link setFormValue}.
|
|
293
|
+
*/
|
|
294
|
+
flushFormValues(): void;
|
|
295
|
+
/** Set the full-text search term. No-op when unchanged, so re-setting it can't churn {@link cmisQuery}. */
|
|
251
296
|
setFulltextTerm(term: string): void;
|
|
252
297
|
/** Set the full-text search scope (`all` / `metadata` / `content`). */
|
|
253
298
|
setFulltextScope(scope: FulltextScope): void;
|
|
@@ -312,7 +357,10 @@ declare class SmartSearchEditController {
|
|
|
312
357
|
isConditionComplete(): boolean;
|
|
313
358
|
/** The operators available for a field's internal type, as autocomplete items. */
|
|
314
359
|
operatorsForField(field: SuggestionItem): SuggestionItem[];
|
|
315
|
-
/**
|
|
360
|
+
/**
|
|
361
|
+
* Human-readable label for an operator id: a math symbol (`=`, `≠`, …), a translated
|
|
362
|
+
* key, a translated date-preset label (`date:thisMonth` → “This month”) or the id itself.
|
|
363
|
+
*/
|
|
316
364
|
operatorLabel(operator: string): string;
|
|
317
365
|
/** Build a condition record from a date preset / boolean operator / value. */
|
|
318
366
|
buildCommitCondition(field: SuggestionItem, operatorId: string, operatorLabelText: string, value: string | string[], internalTypeOverride?: string): FieldCondition;
|
|
@@ -350,8 +398,13 @@ declare function buildNodeClause(node: ConditionNode): string;
|
|
|
350
398
|
/**
|
|
351
399
|
* Build the whole-object full-text clause: a single `CONTAINS('term')` predicate, optionally scoped
|
|
352
400
|
* to a column and AND-ed with a type restriction. Returns `''` when the term is blank.
|
|
401
|
+
*
|
|
402
|
+
* @param fulltext The full-text unit. An empty `types` list means "all types".
|
|
403
|
+
* @param scopeTypes The types the search is scoped to (the host's `types` allow-list). When
|
|
404
|
+
* the unit picks no concrete type, "all types" means *any of these* — so the restriction is
|
|
405
|
+
* still emitted. Pass an empty list for an unscoped search: then "all types" restricts nothing.
|
|
353
406
|
*/
|
|
354
|
-
declare function buildFulltextClause(fulltext: FulltextSearch): string;
|
|
407
|
+
declare function buildFulltextClause(fulltext: FulltextSearch, scopeTypes?: SearchBlockType[]): string;
|
|
355
408
|
/**
|
|
356
409
|
* Assemble the full CMIS statement from the search state. Each unit — the
|
|
357
410
|
* full-text clause plus every type block (type restriction `AND`-ed with its
|
|
@@ -361,9 +414,12 @@ declare function buildFulltextClause(fulltext: FulltextSearch): string;
|
|
|
361
414
|
* @param blocks The type blocks with their conditions.
|
|
362
415
|
* @param combinator How the top-level units combine (`AND` / `OR`).
|
|
363
416
|
* @param fulltext Optional whole-object full-text unit.
|
|
417
|
+
* @param scopeTypes The types the whole search is scoped to (the host's `types` allow-list).
|
|
418
|
+
* Applied to the full-text unit when it targets "all types"; the blocks always carry their own
|
|
419
|
+
* (already scoped) types. Empty = unscoped, i.e. "all types" restricts nothing.
|
|
364
420
|
* @returns A `SELECT * FROM system:object WHERE …` statement, or `''`.
|
|
365
421
|
*/
|
|
366
|
-
declare function buildCmisQuery(blocks: SearchBlock[], combinator: Combinator, fulltext?: FulltextSearch): string;
|
|
422
|
+
declare function buildCmisQuery(blocks: SearchBlock[], combinator: Combinator, fulltext?: FulltextSearch, scopeTypes?: SearchBlockType[]): string;
|
|
367
423
|
|
|
368
424
|
/**
|
|
369
425
|
* Visual query builder that turns guided, chip-based user input into a CMIS query.
|
|
@@ -374,15 +430,26 @@ declare function buildCmisQuery(blocks: SearchBlock[], combinator: Combinator, f
|
|
|
374
430
|
* - one or more **type blocks**, each targeting one or more object types and holding
|
|
375
431
|
* field conditions, nested groups and table-column conditions.
|
|
376
432
|
*
|
|
433
|
+
* Set {@link fulltextOnly} to drop the second part entirely and render a plain full-text
|
|
434
|
+
* search bar.
|
|
435
|
+
*
|
|
377
436
|
* Conditions are built step by step (type → field → operator → value) with an inline
|
|
378
437
|
* autocomplete editor; the value step renders the field's real metadata widget
|
|
379
438
|
* (datepicker, catalog select, organization picker, …). The resulting CMIS query is
|
|
380
439
|
* emitted through {@link queryChange} on every change and can be saved/restored as a
|
|
381
|
-
* plain-data {@link SmartSearchState} via {@link getState} / {@link loadState}.
|
|
440
|
+
* plain-data {@link SmartSearchState} via {@link getState} / {@link loadState}. A restored
|
|
441
|
+
* state is re-labelled in the current UI language (see {@link loadState}).
|
|
382
442
|
*
|
|
383
443
|
* State and mutators live in {@link SmartSearchEditController} (provided per instance);
|
|
384
444
|
* this component owns only the UI concerns (focus, autocomplete plumbing, blur handling).
|
|
385
445
|
*
|
|
446
|
+
* **Submitting.** {@link queryChange} is a live preview — it fires on every change. To run
|
|
447
|
+
* a search only when the user is done, bind {@link querySubmit}: it emits when ENTER
|
|
448
|
+
* reaches the component without an inner widget having claimed it, the way a plain HTML
|
|
449
|
+
* form submits on ENTER. Widgets that own ENTER for their own purpose keep it: the
|
|
450
|
+
* suggestion autocomplete picks an option, a catalog select picks a value, and the inline
|
|
451
|
+
* editor commits the condition it is building. Only the *next* ENTER then submits.
|
|
452
|
+
*
|
|
386
453
|
* @example
|
|
387
454
|
* ```html
|
|
388
455
|
* <!-- Restrict the picker to two object types and skip a noisy property -->
|
|
@@ -417,9 +484,14 @@ declare class SmartSearchComponent {
|
|
|
417
484
|
#private;
|
|
418
485
|
ctrl: SmartSearchEditController;
|
|
419
486
|
/**
|
|
420
|
-
* Object-type ids that may be searched
|
|
421
|
-
* full-text type filter and the type-block multi-select)
|
|
422
|
-
*
|
|
487
|
+
* Object-type ids that may be searched — the scope of the whole search. Restricts
|
|
488
|
+
* the type picker (both the full-text type filter and the type-block multi-select)
|
|
489
|
+
* to these types, and narrows the emitted query: picking *All types* in the
|
|
490
|
+
* full-text filter then means "any of these types" (`objectTypeId IN (…)`), not
|
|
491
|
+
* every type the system knows.
|
|
492
|
+
*
|
|
493
|
+
* When empty the search is unscoped — *All types* restricts nothing — and no type
|
|
494
|
+
* is offered in the picker, so only a full-text search can be built.
|
|
423
495
|
*/
|
|
424
496
|
types: _angular_core.InputSignal<string[]>;
|
|
425
497
|
/**
|
|
@@ -428,6 +500,14 @@ declare class SmartSearchComponent {
|
|
|
428
500
|
* table columns alike.
|
|
429
501
|
*/
|
|
430
502
|
skipProperties: _angular_core.InputSignal<string[]>;
|
|
503
|
+
/**
|
|
504
|
+
* Renders the component as a plain full-text search: only the full-text bar (term, scope
|
|
505
|
+
* and the object-type filter) is shown — no type blocks, no condition builder, no
|
|
506
|
+
* form-mode toggle. The emitted query is built from the full-text unit alone, so a
|
|
507
|
+
* previously {@link loadState loaded} state's blocks do not contribute while this is set.
|
|
508
|
+
* {@link types} keeps its meaning: the search stays scoped to those types.
|
|
509
|
+
*/
|
|
510
|
+
fulltextOnly: _angular_core.InputSignal<boolean>;
|
|
431
511
|
/**
|
|
432
512
|
* Enables the **dynamic conditions** feature. When `true`, each committed condition can
|
|
433
513
|
* be marked dynamic and a form-mode toggle appears that swaps the builder for a generated
|
|
@@ -442,6 +522,14 @@ declare class SmartSearchComponent {
|
|
|
442
522
|
* non-empty values.
|
|
443
523
|
*/
|
|
444
524
|
queryChange: _angular_core.OutputEmitterRef<string>;
|
|
525
|
+
/**
|
|
526
|
+
* Emits the current CMIS query when the user presses ENTER and no inner widget
|
|
527
|
+
* claimed that key — the smart-search equivalent of submitting a form. Bind this
|
|
528
|
+
* (rather than {@link queryChange}) to run the search only once the user is done
|
|
529
|
+
* building it. Like {@link queryChange}, `''` means "no query"; an empty search
|
|
530
|
+
* still submits.
|
|
531
|
+
*/
|
|
532
|
+
querySubmit: _angular_core.OutputEmitterRef<string>;
|
|
445
533
|
auto: _angular_core.Signal<MatAutocomplete>;
|
|
446
534
|
/** Trigger of the currently-focused autocomplete input — used to re-open the
|
|
447
535
|
* panel after a type pick so the multi-select stays open. */
|
|
@@ -450,6 +538,14 @@ declare class SmartSearchComponent {
|
|
|
450
538
|
fulltextTermCtrl: FormControl<string | null>;
|
|
451
539
|
/** Sentinel option value representing "no type restriction" in the type multi-select. */
|
|
452
540
|
readonly ALL_TYPES = "__all__";
|
|
541
|
+
/**
|
|
542
|
+
* Empty `matChipInputSeparatorKeyCodes` for the add-type input. The directive defaults
|
|
543
|
+
* to `[ENTER]` and then calls `preventDefault()` on *every* Enter to end a chip — but
|
|
544
|
+
* we never bind `matChipInputTokenEnd`, so that only served to hide the key from
|
|
545
|
+
* {@link onHostEnter}. A stable reference: a `[]` literal in the template would be a
|
|
546
|
+
* new array on each change-detection run.
|
|
547
|
+
*/
|
|
548
|
+
readonly NO_SEPARATOR_KEYS: number[];
|
|
453
549
|
/**
|
|
454
550
|
* Guard that prevents `onInlineBlur` from cancelling the pending condition
|
|
455
551
|
* when we programmatically open the inline editor.
|
|
@@ -523,7 +619,15 @@ declare class SmartSearchComponent {
|
|
|
523
619
|
* later restore it with {@link loadState}.
|
|
524
620
|
*/
|
|
525
621
|
getState(): SmartSearchState;
|
|
526
|
-
/**
|
|
622
|
+
/**
|
|
623
|
+
* Restore a previously {@link getState saved} search, replacing the current one.
|
|
624
|
+
*
|
|
625
|
+
* The display labels a state carries (type, field and operator labels and the chip's composed
|
|
626
|
+
* condition label) are re-resolved against the live schema and the *current* UI language, so a
|
|
627
|
+
* search saved in one language reads in the language it is restored in. Ids the schema or the
|
|
628
|
+
* translations can no longer resolve keep the label the state carried. Nothing that drives the
|
|
629
|
+
* emitted query is affected.
|
|
630
|
+
*/
|
|
527
631
|
loadState(state: SmartSearchState): void;
|
|
528
632
|
/** Clear the whole search: discard all blocks, conditions and the full-text term. */
|
|
529
633
|
clear(): void;
|
|
@@ -579,14 +683,32 @@ declare class SmartSearchComponent {
|
|
|
579
683
|
* pick, so Enter commits the staged types — even while the autocomplete panel
|
|
580
684
|
* is open. While the user is typing a filter term, Enter is left to the
|
|
581
685
|
* autocomplete so it can select the highlighted option.
|
|
686
|
+
*
|
|
687
|
+
* Unlike {@link onEnter} this deliberately lets an unusable Enter fall through:
|
|
688
|
+
* the add-type input is the resting state of an empty search, so Enter with
|
|
689
|
+
* nothing staged has to reach {@link onHostEnter} and submit.
|
|
582
690
|
*/
|
|
583
|
-
onTypeEnter(): void;
|
|
691
|
+
onTypeEnter(event: Event): void;
|
|
584
692
|
/**
|
|
585
|
-
* Enter / confirm-button handler for the
|
|
586
|
-
* condition
|
|
587
|
-
* (Enter selects the highlighted option there)
|
|
693
|
+
* Enter / confirm-button handler for the inline editor. Commits the in-progress
|
|
694
|
+
* condition once it has a field and an operator. No-op while the autocomplete
|
|
695
|
+
* panel is open (Enter selects the highlighted option there).
|
|
696
|
+
*
|
|
697
|
+
* Bound on the editor wrapper, so it covers every step — including the value
|
|
698
|
+
* step's real metadata widget — and runs after the widgets' own key handling.
|
|
699
|
+
* The `event` is optional because the confirm button calls this from a click.
|
|
588
700
|
*/
|
|
589
|
-
onEnter(): void;
|
|
701
|
+
onEnter(event?: Event): void;
|
|
702
|
+
/**
|
|
703
|
+
* Enter that bubbled all the way up to the component host without being claimed:
|
|
704
|
+
* submit the search, the way a plain HTML form does.
|
|
705
|
+
*
|
|
706
|
+
* Everything inside that owns Enter marks the event handled via `preventDefault()`
|
|
707
|
+
* — Material's autocomplete and select do, and so do {@link onEnter} /
|
|
708
|
+
* {@link onTypeEnter} — so this only sees the "nothing else wanted it" case. The
|
|
709
|
+
* remaining guards cover keys the browser itself is still acting on.
|
|
710
|
+
*/
|
|
711
|
+
onHostEnter(event: KeyboardEvent | Event): void;
|
|
590
712
|
/**
|
|
591
713
|
* Called when the inline-input wrapper loses focus.
|
|
592
714
|
* Commits the condition if complete, discards it if incomplete.
|
|
@@ -609,7 +731,11 @@ declare class SmartSearchComponent {
|
|
|
609
731
|
* condition, mirroring the blur path.
|
|
610
732
|
*/
|
|
611
733
|
onPickerClosed(): void;
|
|
612
|
-
/**
|
|
734
|
+
/**
|
|
735
|
+
* Abandon the in-progress condition edit, discarding any partial input. When an
|
|
736
|
+
* existing condition was opened for editing it is put back verbatim rather than
|
|
737
|
+
* lost — cancelling an edit means "leave it as it was", the same as the blur path.
|
|
738
|
+
*/
|
|
613
739
|
cancelPending(): void;
|
|
614
740
|
/** Jump the inline editor back to the field step so the user can re-pick the field. */
|
|
615
741
|
editField(): void;
|
|
@@ -639,7 +765,7 @@ declare class SmartSearchComponent {
|
|
|
639
765
|
*/
|
|
640
766
|
getObjectTypeField(item: SuggestionItem | null): ObjectTypeField | null;
|
|
641
767
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SmartSearchComponent, never>;
|
|
642
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SmartSearchComponent, "yuv-smart-search", never, { "types": { "alias": "types"; "required": false; "isSignal": true; }; "skipProperties": { "alias": "skipProperties"; "required": false; "isSignal": true; }; "supportDynamicConditions": { "alias": "supportDynamicConditions"; "required": false; "isSignal": true; }; }, { "queryChange": "queryChange"; }, never, never, true, never>;
|
|
768
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SmartSearchComponent, "yuv-smart-search", never, { "types": { "alias": "types"; "required": false; "isSignal": true; }; "skipProperties": { "alias": "skipProperties"; "required": false; "isSignal": true; }; "fulltextOnly": { "alias": "fulltextOnly"; "required": false; "isSignal": true; }; "supportDynamicConditions": { "alias": "supportDynamicConditions"; "required": false; "isSignal": true; }; }, { "queryChange": "queryChange"; "querySubmit": "querySubmit"; }, never, never, true, never>;
|
|
643
769
|
}
|
|
644
770
|
|
|
645
771
|
declare class YuvSmartSearchModule {
|
|
@@ -29,6 +29,11 @@ interface TileListConfigOptions {
|
|
|
29
29
|
*/
|
|
30
30
|
configTypes: VirtualObjectType[];
|
|
31
31
|
configFlavors?: ObjectFlavor[];
|
|
32
|
+
/**
|
|
33
|
+
* Property IDs that should not be offered for selection in the property
|
|
34
|
+
* slots. Added on top of the always-excluded system/base fields.
|
|
35
|
+
*/
|
|
36
|
+
excludeProperties?: string[];
|
|
32
37
|
actionContext?: ActionContext;
|
|
33
38
|
}
|
|
34
39
|
interface TileListHighlight {
|