@yuuvis/client-framework 3.2.2 → 3.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuuvis/client-framework",
3
- "version": "3.2.2",
3
+ "version": "3.4.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.9",
9
9
  "@angular/core": "^21.2.9",
10
10
  "angular-gridster2": "^21.0.1",
11
- "@yuuvis/client-core": "^3.2.2",
12
- "@yuuvis/client-shell-core": "^3.2.2",
13
- "@yuuvis/client-components": "^3.2.2",
11
+ "@yuuvis/client-core": "^3.4.0",
12
+ "@yuuvis/client-shell-core": "^3.4.0",
13
+ "@yuuvis/client-components": "^3.4.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.7",
19
19
  "@ngrx/signals": "^21.1.0",
20
- "@yuuvis/material": "^3.2.2",
20
+ "@yuuvis/material": "^3.4.0",
21
21
  "@yuuvis/media-viewer": "^3.0.1",
22
22
  "angular-split": "^20.0.0",
23
23
  "vis-network": "^10.0.2",
@@ -1,7 +1,7 @@
1
1
  import * as _angular_forms from '@angular/forms';
2
2
  import { ControlValueAccessor, FormControl, Validator, FormGroup, ValidationErrors, AbstractControl } from '@angular/forms';
3
3
  import * as _angular_core from '@angular/core';
4
- import { OnInit, OnDestroy, ElementRef, AfterViewInit } from '@angular/core';
4
+ import { OnInit, OnDestroy, ElementRef, WritableSignal, AfterViewInit } from '@angular/core';
5
5
  import { AbstractMatFormField } from '@yuuvis/client-framework/common';
6
6
  import { TranslateService, Situation, ObjectFormControl, RangeValue, Operator, LocaleNumberPipe, FileSizePipe, OrganizationSetEntry, DateRange, FilesizeRange, FormattedMailTo } from '@yuuvis/client-core';
7
7
  import { MetadataFormFieldContext } from '@yuuvis/client-framework/metadata-form';
@@ -11,7 +11,6 @@ import { MatChipInputEvent, MatChipEditedEvent } from '@angular/material/chips';
11
11
 
12
12
  declare class CatalogComponent extends AbstractMatFormField<string | string[]> implements ControlValueAccessor, OnInit, OnDestroy {
13
13
  #private;
14
- private readonly translate;
15
14
  readonly: _angular_core.InputSignal<boolean>;
16
15
  multiple: _angular_core.InputSignal<boolean>;
17
16
  _options: _angular_core.WritableSignal<{
@@ -24,15 +23,17 @@ declare class CatalogComponent extends AbstractMatFormField<string | string[]> i
24
23
  */
25
24
  classifications: _angular_core.InputSignal<string[]>;
26
25
  /**
27
- * Possibles values are `EDIT` (default),`SEARCH`,`CREATE`. In search situation validation of the form element will be turned off, so you are able to enter search terms that do not meet the elements validators.
26
+ * Possibles values are `EDIT` (default),`SEARCH`,`CREATE`. In search situation validation
27
+ * of the form element will be turned off, so you are able to enter search terms that do not
28
+ * meet the elements validators.
28
29
  */
29
30
  situation: _angular_core.InputSignal<string | undefined>;
30
31
  ngControl: _angular_forms.NgControl | null;
31
- readonly fc: FormControl<string | string[] | null | undefined>;
32
+ readonly formCtrl: FormControl<string | string[] | null | undefined>;
32
33
  propagateChange: (_: any) => void;
33
34
  writeValue(value: string | string[]): void;
34
35
  registerOnChange(fn: any): void;
35
- registerOnTouched(fn: any): void;
36
+ registerOnTouched(): void;
36
37
  setDisabledState?(isDisabled: boolean): void;
37
38
  ngOnInit(): void;
38
39
  ngOnDestroy(): void;
@@ -123,7 +124,7 @@ declare class DatetimeRangeComponent extends AbstractMatFormField<RangeValue<Dat
123
124
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DatetimeRangeComponent, "yuv-datetime-range", never, { "withTimeInput": { "alias": "withTime"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "operator": { "alias": "operator"; "required": false; "isSignal": true; }; "situation": { "alias": "situation"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
124
125
  }
125
126
 
126
- declare class DatetimeComponent extends AbstractMatFormField<Date | null> implements ControlValueAccessor, OnInit {
127
+ declare class DatetimeComponent extends AbstractMatFormField<Date | string | null> implements ControlValueAccessor, OnInit {
127
128
  #private;
128
129
  private translate;
129
130
  pickerCmp: _angular_core.Signal<DatepickerComponent>;
@@ -150,7 +151,7 @@ declare class DatetimeComponent extends AbstractMatFormField<Date | null> implem
150
151
  withTime: _angular_core.InputSignal<boolean>;
151
152
  openCalendar(): void;
152
153
  propagateChange: (_: any) => void;
153
- writeValue(value: any): void;
154
+ writeValue(value: string | Date): void;
154
155
  registerOnChange(fn: () => void): void;
155
156
  registerOnTouched(): void;
156
157
  setDisabledState?(isDisabled: boolean): void;
@@ -160,15 +161,24 @@ declare class DatetimeComponent extends AbstractMatFormField<Date | null> implem
160
161
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DatetimeComponent, "yuv-datetime", never, { "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "onlyFutureDates": { "alias": "onlyFutureDates"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "calendar": { "alias": "calendar"; "required": false; "isSignal": true; }; "withTime": { "alias": "withTime"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
161
162
  }
162
163
 
164
+ interface DynamicCatalogOption {
165
+ value: string;
166
+ label: string;
167
+ disabled: boolean;
168
+ invalid?: boolean;
169
+ }
170
+ interface SelectedDisplay {
171
+ value: string;
172
+ label: string;
173
+ invalid: boolean;
174
+ }
163
175
  declare class DynamicCatalogComponent extends AbstractMatFormField<string | string[]> implements ControlValueAccessor, OnInit, OnDestroy {
164
176
  #private;
165
177
  catalog: _angular_core.InputSignal<string>;
166
178
  readonly: _angular_core.InputSignal<boolean>;
167
179
  multiple: _angular_core.InputSignal<boolean>;
168
- options: _angular_core.WritableSignal<{
169
- value: string;
170
- label: string;
171
- }[] | undefined>;
180
+ options: WritableSignal<DynamicCatalogOption[]>;
181
+ selectedDisplay: _angular_core.Signal<SelectedDisplay[]>;
172
182
  /**
173
183
  * Possibles values are `EDIT` (default),`SEARCH`,`CREATE`. In search situation
174
184
  * validation of the form element will be turned off, so you are able to enter
@@ -1,10 +1,8 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { WritableSignal } from '@angular/core';
3
- import * as _yuuvis_client_core from '@yuuvis/client-core';
4
- import { DmsObject } from '@yuuvis/client-core';
5
- import * as _yuuvis_media_viewer from '@yuuvis/media-viewer';
3
+ import { DmsObject, YuvUser } from '@yuuvis/client-core';
6
4
  import { Metadata, EmailMetadata } from '@yuuvis/media-viewer';
7
- import * as rxjs from 'rxjs';
5
+ import { Observable } from 'rxjs';
8
6
 
9
7
  interface ViewerDetails {
10
8
  id: string;
@@ -26,17 +24,34 @@ declare class ObjectPreviewComponent {
26
24
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ObjectPreviewComponent, "yuv-object-preview", never, { "objectId": { "alias": "objectId"; "required": false; "isSignal": true; }; "dmsObjectInput": { "alias": "dmsObject"; "required": false; "isSignal": true; }; "version": { "alias": "version"; "required": false; "isSignal": true; }; "metadata": { "alias": "metadata"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
27
25
  }
28
26
 
27
+ interface BaseViewerData {
28
+ mediaViewerSrc: string;
29
+ id: string;
30
+ mimeType: string | undefined;
31
+ }
32
+ type ViewerDataEmail = BaseViewerData & {
33
+ metadata: EmailMetadata;
34
+ };
35
+ type ViewerDataDefault = BaseViewerData & {
36
+ metadata: {
37
+ type: Uppercase<string> | undefined;
38
+ name: string;
39
+ dmsObject: Record<string, unknown>;
40
+ id: string;
41
+ editable: boolean;
42
+ user: YuvUser;
43
+ theme: string;
44
+ version: number | undefined;
45
+ sendEvent: boolean;
46
+ };
47
+ };
48
+
29
49
  declare class ObjectEmailPreviewComponent {
30
50
  #private;
31
51
  objectId: _angular_core.InputSignal<string | undefined>;
32
52
  dmsObjectInput: _angular_core.InputSignal<DmsObject | undefined>;
33
53
  dmsObject: _angular_core.Signal<DmsObject | undefined>;
34
- viewerDetails: _angular_core.Signal<{
35
- mediaViewerSrc: string;
36
- id: string;
37
- mimeType: string | undefined;
38
- metadata: _yuuvis_media_viewer.EmailMetadata;
39
- } | undefined>;
54
+ viewerDetails: _angular_core.Signal<ViewerDataEmail | undefined>;
40
55
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ObjectEmailPreviewComponent, never>;
41
56
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ObjectEmailPreviewComponent, "yuv-object-email-preview", never, { "objectId": { "alias": "objectId"; "required": false; "isSignal": true; }; "dmsObjectInput": { "alias": "dmsObject"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
42
57
  }
@@ -45,36 +60,11 @@ declare class ObjectPreviewService {
45
60
  #private;
46
61
  dmsObject: _angular_core.Signal<DmsObject | undefined>;
47
62
  setDmsObject(object: DmsObject): void;
48
- getDmsObject(id: string): rxjs.Observable<DmsObject>;
63
+ getDmsObject(id: string): Observable<DmsObject>;
49
64
  getMediaViewerSrc(id: string, mimeType: string | undefined, version?: number): string;
50
- getViewerDetails(object: DmsObject, version: number | undefined): {
51
- mediaViewerSrc: string;
52
- id: string;
53
- mimeType: string | undefined;
54
- metadata: EmailMetadata;
55
- } | {
56
- mediaViewerSrc: string;
57
- id: string;
58
- mimeType: string | undefined;
59
- metadata: {
60
- type: Uppercase<string> | undefined;
61
- name: string;
62
- dmsObject: Record<string, unknown>;
63
- id: string;
64
- editable: boolean;
65
- user: _yuuvis_client_core.YuvUser;
66
- theme: string;
67
- version: number | undefined;
68
- sendEvent: boolean;
69
- };
70
- } | undefined;
71
- getEmailViewerDetails(object: DmsObject, MAIL_APP_ID?: string): {
72
- mediaViewerSrc: string;
73
- id: string;
74
- mimeType: string | undefined;
75
- metadata: EmailMetadata;
76
- };
65
+ getEmailViewerDetails(object: DmsObject, MAIL_APP_ID?: string): ViewerDataEmail;
77
66
  getEmailMetadata(object: DmsObject, MAIL_APP_ID?: string): EmailMetadata;
67
+ getViewerDetails(object: DmsObject, version: number | undefined): ViewerDataEmail | ViewerDataDefault | undefined;
78
68
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ObjectPreviewService, never>;
79
69
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<ObjectPreviewService>;
80
70
  }
@@ -217,9 +217,11 @@ declare class QueryListComponent<T = any> {
217
217
  * exceeds this value, pagination controls are shown and the user can navigate between
218
218
  * pages via `changePage()` / `goToPage()`.
219
219
  *
220
- * @default SearchService.DEFAULT_QUERY_SIZE
220
+ * Resolution order (see `effectivePageSize`): explicit `pageSize` input takes precedence,
221
+ * otherwise `(query as SearchQuery).size` is used if set, otherwise
222
+ * `SearchService.DEFAULT_QUERY_SIZE` is used.
221
223
  */
222
- pageSize: _angular_core.InputSignal<number>;
224
+ pageSize: _angular_core.InputSignal<number | undefined>;
223
225
  /**
224
226
  * Enables mouse drag-to-select on list items.
225
227
  *
@@ -274,6 +276,21 @@ declare class QueryListComponent<T = any> {
274
276
  * (e.g. to show a visual indicator or adjust layout) without accessing internal state.
275
277
  */
276
278
  dropInSize: _angular_core.Signal<number>;
279
+ /**
280
+ * Resolved page size used by both the `mat-paginator` and every server request.
281
+ *
282
+ * Falls back through three sources, in order:
283
+ * 1. The explicit `pageSize` input, when the consumer has provided one.
284
+ * 2. `(query as SearchQuery).size`, when the query is a `SearchQuery` object that
285
+ * already declares its own page size — keeps server response and paginator in
286
+ * sync when the consumer only configures the query.
287
+ * 3. `SearchService.DEFAULT_QUERY_SIZE` as the final default.
288
+ *
289
+ * Used internally to avoid the bug where `mat-paginator` and the server pageination
290
+ * use different page sizes (paginator showing e.g. "1-25 of 43" while `getPage()`
291
+ * asks the server for skip=50 — landing on an empty page).
292
+ */
293
+ effectivePageSize: _angular_core.Signal<number>;
277
294
  /**
278
295
  * The final list of items rendered by the template.
279
296
  *
@@ -399,6 +416,33 @@ declare class QueryListComponent<T = any> {
399
416
  * Defaults to `true` so the newly dropped items are immediately visible.
400
417
  */
401
418
  dropItems(items: T[], scrollTo?: boolean): void;
419
+ /**
420
+ * Surgically removes specific items from the drop-in set by their stable IDs.
421
+ *
422
+ * Filters `#dropInItems` to drop any entry whose `idProperty` value is in `ids`,
423
+ * leaving the remaining drop-ins (and the rest of the result list) untouched.
424
+ * The structural shift is handled by the rendering pipeline — `resultItems`
425
+ * recomputes automatically, and the leading `drop-in` class follows the new
426
+ * (smaller) `dropInSize()`.
427
+ *
428
+ * This method intentionally does **not** mutate the inner list's selection
429
+ * state. The caller (typically `TileListComponent.removeDropItems`) is in a
430
+ * better position to decide whether to clear, shift, or preserve selection,
431
+ * because it tracks selection at a higher level by stable object identity.
432
+ *
433
+ * Requires `idProperty` to be set — without it items cannot be identified
434
+ * and the call is a no-op (returns 0).
435
+ *
436
+ * **Typical use case:** an upstream deletion (e.g. `DmsService.deleteDmsObject`)
437
+ * removed an object that is currently rendered as a drop-in. Without removing
438
+ * it from `#dropInItems`, the deleted tile would remain visible after `refresh()`
439
+ * because the framework treats drop-ins as authoritative and prepends them to
440
+ * every refreshed result set.
441
+ *
442
+ * @param ids Array of ID values (as resolved via `idProperty`) to remove.
443
+ * @returns Number of items that were actually removed from the drop-in set.
444
+ */
445
+ removeDropItems(ids: string[]): number;
402
446
  /**
403
447
  * Programmatically replaces the entire selection with the given indices.
404
448
  *
@@ -154,9 +154,11 @@ declare class TileListComponent implements OnInit {
154
154
  * this value, pagination controls appear. Reducing this number improves initial load
155
155
  * time; increasing it reduces the need for pagination.
156
156
  *
157
- * @default SearchService.DEFAULT_QUERY_SIZE
157
+ * When omitted, the inner `QueryListComponent` falls back to `(query as SearchQuery).size`
158
+ * if set, otherwise to `SearchService.DEFAULT_QUERY_SIZE` — keeping the paginator and
159
+ * the server in sync without requiring the consumer to set this input explicitly.
158
160
  */
159
- pageSize: _angular_core.InputSignal<number>;
161
+ pageSize: _angular_core.InputSignal<number | undefined>;
160
162
  /**
161
163
  * Enables multi-selection mode.
162
164
  *
@@ -563,6 +565,33 @@ declare class TileListComponent implements OnInit {
563
565
  * @param objects `DmsObject` instances to prepend to the visible list.
564
566
  */
565
567
  dropItems(objects: DmsObject[]): void;
568
+ /**
569
+ * Surgically removes tiles matching the given IDs from the rendered list.
570
+ *
571
+ * Use this when an upstream deletion (e.g. `DmsService.deleteDmsObject`) removes
572
+ * an object that is currently rendered. Without this call, drop-in tiles would
573
+ * remain visible after `refresh()` because `onQueryResult` reconstructs them by
574
+ * slicing the leading `dropInSize()` items from the `items` signal — the deleted
575
+ * tile would survive as a stale leader.
576
+ *
577
+ * The method is also invoked automatically by an internal `DMS_OBJECT_DELETED`
578
+ * subscription, so consumers that delete via `DmsService` get correct behavior
579
+ * without any extra wiring. Calling it directly is only needed for deletions
580
+ * that do not flow through the standard event service.
581
+ *
582
+ * Internally:
583
+ * 1. Locates positions of matching tiles in the `items` signal.
584
+ * 2. Removes them from `items` (the parent-visible view model).
585
+ * 3. Filters `_selection` to drop indices on removed tiles, then shifts the
586
+ * remaining indices back by the count of removed positions that preceded
587
+ * each surviving entry so selection stays attached to the same logical items.
588
+ * 4. Clears `_lastSelection` if it pointed to a removed tile, else shifts it.
589
+ * 5. Delegates to `QueryListComponent.removeDropItems` to filter the inner
590
+ * drop-in set so `resultItems` recomputes with the correct leading slice.
591
+ *
592
+ * @param ids Object IDs to remove.
593
+ */
594
+ removeDropItems(ids: string[]): void;
566
595
  /**
567
596
  * Toggles an `ObjectFlavor` on or off and re-maps the current result set.
568
597
  *