@masterteam/work-center 0.0.60 → 0.0.62

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": "@masterteam/work-center",
3
- "version": "0.0.60",
3
+ "version": "0.0.62",
4
4
  "publishConfig": {
5
5
  "directory": "../../../dist/masterteam/work-center",
6
6
  "linkDirectory": false,
@@ -20,12 +20,12 @@
20
20
  "rxjs": "^7.8.2",
21
21
  "tailwindcss": "^4.2.2",
22
22
  "tailwindcss-primeui": "^0.6.1",
23
- "@masterteam/client-components": "^0.0.60",
24
- "@masterteam/forms": "^0.0.119",
25
- "@masterteam/components": "^0.0.231",
26
- "@masterteam/structure-builder": "^0.0.61",
23
+ "@masterteam/client-components": "^0.0.67",
27
24
  "@masterteam/discussion": "^0.0.26",
28
- "@masterteam/icons": "^0.0.17"
25
+ "@masterteam/structure-builder": "^0.0.61",
26
+ "@masterteam/forms": "^0.0.126",
27
+ "@masterteam/icons": "^0.0.17",
28
+ "@masterteam/components": "^0.0.239"
29
29
  },
30
30
  "sideEffects": false,
31
31
  "exports": {
@@ -1,5 +1,5 @@
1
1
  import * as _masterteam_components_table from '@masterteam/components/table';
2
- import { ColumnDef, TableFilters } from '@masterteam/components/table';
2
+ import { ColumnDef, TableFilters, TablePersistStateKey } from '@masterteam/components/table';
3
3
  import * as _masterteam_components_statistic_card from '@masterteam/components/statistic-card';
4
4
  import { StatisticCardData } from '@masterteam/components/statistic-card';
5
5
  import * as _masterteam_work_center from '@masterteam/work-center';
@@ -28,6 +28,22 @@ declare const WORK_CENTER_QUERY_VERSION = 1;
28
28
  declare const WORK_CENTER_MAX_PAGE_SIZE = 100;
29
29
  declare const WORK_CENTER_MAX_FILTERS = 20;
30
30
  declare const WORK_CENTER_MAX_SORT = 5;
31
+ /**
32
+ * Backend column key carrying the row's LevelData display label
33
+ * (`extra.levelDataName`). Grouping by it maps to a single backend sort on the
34
+ * same key — see `WORK_CENTER_LEVEL_GROUP_FIELD` for the grouping identity.
35
+ */
36
+ declare const WORK_CENTER_LEVEL_NAME_KEY = "levelDataName";
37
+ /**
38
+ * Synthetic per-row field holding the *identity* behind the Level Name column.
39
+ * The visible label is ambiguous (two LevelData records may share a name), so
40
+ * rows are bucketed by `context.levelDataId` instead — except rows with no
41
+ * visible label, which get an empty identity so they all collapse into the one
42
+ * shared "—" group the backend contract requires.
43
+ */
44
+ declare const WORK_CENTER_LEVEL_GROUP_FIELD = "__mtLevelGroup";
45
+ /** Rendered in place of a missing / restricted LevelData label. */
46
+ declare const WORK_CENTER_EMPTY_LABEL = "\u2014";
31
47
  interface ApiEnvelope<T> {
32
48
  endpoint: string | null;
33
49
  status: number;
@@ -102,6 +118,12 @@ interface WorkCenterRuntimeStatsItem {
102
118
  key: string;
103
119
  label: TranslatableDto;
104
120
  count: number;
121
+ /**
122
+ * Backend-owned accent color for the KPI card (typically a `#hex` status
123
+ * color). `null` means "no color configured" — the card falls back to the
124
+ * neutral theme accent. Never derive a color from `key`/`label`.
125
+ */
126
+ color?: string | null;
105
127
  }
106
128
  interface WorkCenterRuntimePagination {
107
129
  page: number;
@@ -202,6 +224,11 @@ interface WorkCenterAreaState {
202
224
  * Same `(field, op)` pair from this slice overrides a header rule.
203
225
  */
204
226
  columnFilters: WorkCenterFilterRule[];
227
+ /**
228
+ * Column key the table groups rows by. UI-only — never part of the runtime
229
+ * request; grouping is expressed to the backend as `context.sort`.
230
+ */
231
+ groupBy: string | null;
205
232
  menuItems: ClientPageMenuItem[];
206
233
  rows: Record<string, unknown>[];
207
234
  columns: ColumnDef[];
@@ -233,6 +260,8 @@ interface WorkCenterBootstrapInputs {
233
260
  levelDataId?: unknown;
234
261
  sort?: unknown;
235
262
  filters?: unknown;
263
+ /** Grouped column key, so a grouped view survives reload / deep-link. */
264
+ group?: unknown;
236
265
  }
237
266
  interface WorkCenterItemModalComponentInput {
238
267
  contextKey: WorkCenterItemContextKey;
@@ -261,7 +290,7 @@ interface WorkCenterClientFormModalOptions {
261
290
  buttonIcon?: string;
262
291
  lookups?: ClientLookup[];
263
292
  }
264
- type WorkCenterLoadReason = 'route-enter' | 'menu-change' | 'filters-change' | 'table-lazy' | 'refresh' | 'manual';
293
+ type WorkCenterLoadReason = 'route-enter' | 'menu-change' | 'filters-change' | 'group-change' | 'table-lazy' | 'refresh' | 'manual';
265
294
 
266
295
  declare class WorkCenterPage {
267
296
  private readonly facade;
@@ -283,6 +312,15 @@ declare class WorkCenterPage {
283
312
  readonly runtimeFiltersChanged: _angular_core.OutputEmitterRef<WorkCenterFilterRule[]>;
284
313
  readonly itemClicked: _angular_core.OutputEmitterRef<string>;
285
314
  readonly cardSelected: _angular_core.OutputEmitterRef<string>;
315
+ /**
316
+ * Emitted whenever the backend sort changes (including grouping, which is
317
+ * sent as a sort). Hosts should persist it — the runtime query is rebuilt
318
+ * from `bootstrapInputs`, so a sort that isn't round-tripped is dropped on
319
+ * the next navigation.
320
+ */
321
+ readonly sortChanged: _angular_core.OutputEmitterRef<WorkCenterSortRule[]>;
322
+ /** Emitted when the grouped column changes; `null` when grouping is cleared. */
323
+ readonly groupChanged: _angular_core.OutputEmitterRef<string | null>;
286
324
  protected readonly context: _angular_core.Signal<_masterteam_work_center.WorkCenterContext>;
287
325
  protected readonly headerFilters: _angular_core.Signal<WorkCenterFilterRule[]>;
288
326
  protected readonly tableFilters: _angular_core.WritableSignal<TableFilters>;
@@ -306,6 +344,14 @@ declare class WorkCenterPage {
306
344
  protected readonly totalCount: _angular_core.Signal<number>;
307
345
  protected readonly columnFilters: _angular_core.Signal<WorkCenterFilterRule[]>;
308
346
  protected readonly loading: _angular_core.Signal<boolean>;
347
+ protected readonly groupBy: _angular_core.Signal<string | null>;
348
+ /**
349
+ * Sort and grouping live in the runtime query (and the host's URL), not in
350
+ * table storage — persisting them locally would let a restored table claim a
351
+ * grouping the backend query no longer has. Stable reference: a fresh array
352
+ * per change detection would re-run the table's persistence effect.
353
+ */
354
+ protected readonly persistStateExclude: TablePersistStateKey[];
309
355
  protected readonly tableColumns: _angular_core.Signal<{
310
356
  sortable: boolean;
311
357
  key: string;
@@ -314,18 +360,28 @@ declare class WorkCenterPage {
314
360
  customCellTpl?: _angular_core.TemplateRef<any>;
315
361
  filterConfig?: _masterteam_components_table.FilterConfig;
316
362
  statusMap?: Record<string, _masterteam_components_table.TableStatusMapValue>;
363
+ groupable?: boolean;
364
+ groupKey?: string;
317
365
  readonly?: boolean;
318
366
  width?: string;
319
367
  filterOnly?: boolean;
320
368
  exportable?: boolean;
321
369
  exportValue?: (row: any) => string | number | boolean | null;
322
370
  }[]>;
371
+ /**
372
+ * Grouping is executed by the backend as a single sort, so the table's own
373
+ * sort state is driven from the query we actually sent instead of the
374
+ * table's internal memory of it.
375
+ */
376
+ protected readonly sortField: _angular_core.Signal<string>;
377
+ protected readonly sortDirection: _angular_core.Signal<"asc" | "desc" | null>;
323
378
  /**
324
379
  * Maps each status/group display label to its total count from the KPI
325
380
  * summary cards so the group header shows the real backend total rather than
326
- * the current-page row count.
381
+ * the current-page row count. Withheld for groups the backend doesn't
382
+ * aggregate — see `PAGE_LOCAL_GROUP_KEYS`.
327
383
  */
328
- protected readonly statusGroupCountMap: _angular_core.Signal<Map<string, number>>;
384
+ protected readonly groupCountMap: _angular_core.Signal<Map<string, number> | null>;
329
385
  protected readonly propertyFilterSchema: _angular_core.Signal<PropertyFilterBuilderSchema | null>;
330
386
  protected readonly showGeneralTaskCreateButton: _angular_core.Signal<boolean>;
331
387
  protected readonly generalTaskButtonLabel: _angular_core.Signal<string>;
@@ -343,14 +399,27 @@ declare class WorkCenterPage {
343
399
  * (handled by `applyColumnFiltersAndLoad`); when only paging/sort changed
344
400
  * we fall through to `applyTableLazyLoadAndLoad`.
345
401
  */
402
+ /**
403
+ * The table asks to group; the backend does the ordering. `setGroupByAndLoad`
404
+ * rewrites `context.sort` and resets paging, so the lazy event the table
405
+ * fires straight after carries the same sort and lands as a no-op.
406
+ */
407
+ onTableGroupByChange(key: string | null): void;
346
408
  onTableLazyLoad(event: any): void;
409
+ /**
410
+ * Announces the backend sort to the host only when it actually moved, so a
411
+ * host that mirrors it into the URL doesn't churn history on every page hit.
412
+ * Reads the snapshot, not the signal — this runs in the same tick as the
413
+ * dispatch that changed it.
414
+ */
415
+ private emitSortIfChanged;
347
416
  onGeneralTaskCreateClick(): void;
348
417
  onRowClick(row: Record<string, unknown>): void;
349
418
  protected readonly rowsClickable: _angular_core.Signal<boolean>;
350
419
  private getOpLabel;
351
420
  private resolveRowContextKey;
352
421
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WorkCenterPage, never>;
353
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<WorkCenterPage, "mt-work-center-page", never, { "area": { "alias": "area"; "required": false; "isSignal": true; }; "pageTitle": { "alias": "pageTitle"; "required": false; "isSignal": true; }; "menuIcon": { "alias": "menuIcon"; "required": false; "isSignal": true; }; "lookups": { "alias": "lookups"; "required": false; "isSignal": true; }; "showSidebar": { "alias": "showSidebar"; "required": false; "isSignal": true; }; "bootstrapInputs": { "alias": "bootstrapInputs"; "required": false; "isSignal": true; }; "openItemDrawer": { "alias": "openItemDrawer"; "required": false; "isSignal": true; }; "itemReadOnly": { "alias": "itemReadOnly"; "required": false; "isSignal": true; }; "openItemsInModal": { "alias": "openItemsInModal"; "required": false; "isSignal": true; }; "itemModal": { "alias": "itemModal"; "required": false; "isSignal": true; }; "generalTaskModal": { "alias": "generalTaskModal"; "required": false; "isSignal": true; }; }, { "runtimeFiltersChanged": "runtimeFiltersChanged"; "itemClicked": "itemClicked"; "cardSelected": "cardSelected"; }, never, never, true, never>;
422
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<WorkCenterPage, "mt-work-center-page", never, { "area": { "alias": "area"; "required": false; "isSignal": true; }; "pageTitle": { "alias": "pageTitle"; "required": false; "isSignal": true; }; "menuIcon": { "alias": "menuIcon"; "required": false; "isSignal": true; }; "lookups": { "alias": "lookups"; "required": false; "isSignal": true; }; "showSidebar": { "alias": "showSidebar"; "required": false; "isSignal": true; }; "bootstrapInputs": { "alias": "bootstrapInputs"; "required": false; "isSignal": true; }; "openItemDrawer": { "alias": "openItemDrawer"; "required": false; "isSignal": true; }; "itemReadOnly": { "alias": "itemReadOnly"; "required": false; "isSignal": true; }; "openItemsInModal": { "alias": "openItemsInModal"; "required": false; "isSignal": true; }; "itemModal": { "alias": "itemModal"; "required": false; "isSignal": true; }; "generalTaskModal": { "alias": "generalTaskModal"; "required": false; "isSignal": true; }; }, { "runtimeFiltersChanged": "runtimeFiltersChanged"; "itemClicked": "itemClicked"; "cardSelected": "cardSelected"; "sortChanged": "sortChanged"; "groupChanged": "groupChanged"; }, never, never, true, never>;
354
423
  }
355
424
 
356
425
  declare class WorkCenterClientFormModal {
@@ -489,6 +558,18 @@ declare class ApplyColumnFilters {
489
558
  static readonly type = "[WorkCenter] Apply Column Filters";
490
559
  constructor(area: WorkCenterArea, filters: WorkCenterFilterRule[]);
491
560
  }
561
+ /**
562
+ * Sets the grouped column. Grouping is expressed to the backend as a single
563
+ * sort on the same field, so this also rewrites `context.sort` and resets
564
+ * `page` to 1 before reloading. `groupBy: null` clears both.
565
+ */
566
+ declare class SetGroupBy {
567
+ area: WorkCenterArea;
568
+ groupBy: string | null;
569
+ dir: 'asc' | 'desc';
570
+ static readonly type = "[WorkCenter] Set Group By";
571
+ constructor(area: WorkCenterArea, groupBy: string | null, dir?: 'asc' | 'desc');
572
+ }
492
573
  /**
493
574
  * Clears both the header filter slice and the column filter slice in one
494
575
  * state update, triggering a single BE reload.
@@ -502,7 +583,7 @@ declare class ClearAllFilters {
502
583
  declare class WorkCenterFacade {
503
584
  private readonly store;
504
585
  readonly activeArea: _angular_core.Signal<WorkCenterArea>;
505
- readonly context: _angular_core.Signal<_masterteam_work_center.WorkCenterContext>;
586
+ readonly context: _angular_core.Signal<WorkCenterContext>;
506
587
  readonly menuItems: _angular_core.Signal<_masterteam_components_types_masterteam_components_client_page_menu.ClientPageMenuItem[]>;
507
588
  readonly rows: _angular_core.Signal<Record<string, unknown>[]>;
508
589
  readonly columns: _angular_core.Signal<_masterteam_components_types_masterteam_components_table.ColumnDef[]>;
@@ -511,12 +592,20 @@ declare class WorkCenterFacade {
511
592
  readonly runtimeFilterSchema: _angular_core.Signal<_masterteam_work_center.WorkCenterRuntimeFilterSchema | null>;
512
593
  readonly headerFilters: _angular_core.Signal<WorkCenterFilterRule[]>;
513
594
  readonly columnFilters: _angular_core.Signal<WorkCenterFilterRule[]>;
595
+ readonly groupBy: _angular_core.Signal<string | null>;
514
596
  readonly totalCount: _angular_core.Signal<number>;
515
597
  readonly warnings: _angular_core.Signal<_masterteam_work_center.WorkCenterRuntimeWarningDto[]>;
516
598
  private readonly loadingActive;
517
599
  private readonly errors;
518
600
  readonly loading: _angular_core.Signal<boolean>;
519
601
  readonly error: _angular_core.Signal<string | null>;
602
+ /**
603
+ * Snapshot reads for callers that must observe state *immediately* after a
604
+ * dispatch — e.g. an output handler mirroring the runtime query into the URL.
605
+ * The `select()` signals above are the right choice everywhere else.
606
+ */
607
+ snapshotContext(): WorkCenterContext;
608
+ snapshotGroupBy(): string | null;
520
609
  enterArea(area: WorkCenterArea): rxjs.Observable<void>;
521
610
  hydrateContext(area: WorkCenterArea, patch: WorkCenterHydratePatch): rxjs.Observable<void>;
522
611
  setParams(area: WorkCenterArea, inputs: WorkCenterBootstrapInputs): rxjs.Observable<void>;
@@ -534,6 +623,13 @@ declare class WorkCenterFacade {
534
623
  * and reloads with merged `headerFilters` + `columnFilters`.
535
624
  */
536
625
  applyColumnFiltersAndLoad(area: WorkCenterArea, runtimeFilters: WorkCenterFilterRule[]): rxjs.Observable<void>;
626
+ /**
627
+ * Groups the table by `groupBy` (or clears grouping with `null`). Pushes the
628
+ * grouped column down as the single backend sort, resets to page 1 and
629
+ * reloads. Safe to call from the table's `groupByChange` — the lazy event
630
+ * that follows carries the same sort and is absorbed as a no-op.
631
+ */
632
+ setGroupByAndLoad(area: WorkCenterArea, groupBy: string | null, dir?: 'asc' | 'desc'): rxjs.Observable<void>;
537
633
  /**
538
634
  * Clears both header and column filter slices in one state update,
539
635
  * triggering a single BE reload.
@@ -541,6 +637,12 @@ declare class WorkCenterFacade {
541
637
  clearAllFiltersAndLoad(area: WorkCenterArea): rxjs.Observable<void>;
542
638
  loadRuntime(area: WorkCenterArea, reason?: WorkCenterLoadReason): rxjs.Observable<void>;
543
639
  private toPositiveInt;
640
+ /**
641
+ * `mt-table` always reports its sort on a lazy event, so a `null` field is an
642
+ * explicit "no sort" and must clear `context.sort` (the BE contract asks for
643
+ * `sort: []`). Only an event with no `sortField` key at all — nothing the
644
+ * current table emits — leaves the existing sort alone.
645
+ */
544
646
  private toSortFromLazyEvent;
545
647
  private isSameSort;
546
648
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WorkCenterFacade, never>;
@@ -560,6 +662,7 @@ declare class WorkCenterState {
560
662
  static runtimeFilterSchema(snapshot: WorkCenterAreaState): WorkCenterRuntimeFilterSchema | null;
561
663
  static headerFilters(snapshot: WorkCenterAreaState): WorkCenterFilterRule[];
562
664
  static columnFilters(snapshot: WorkCenterAreaState): WorkCenterFilterRule[];
665
+ static groupBy(snapshot: WorkCenterAreaState): string | null;
563
666
  static totalCount(snapshot: WorkCenterAreaState): number;
564
667
  static warnings(snapshot: WorkCenterAreaState): _masterteam_work_center.WorkCenterRuntimeWarningDto[];
565
668
  static lookups(state: WorkCenterStateModel): _masterteam_work_center.WorkCenterLookups;
@@ -571,6 +674,12 @@ declare class WorkCenterState {
571
674
  setLookups(ctx: StateContext<WorkCenterStateModel>, action: SetLookups): void;
572
675
  applyHeaderFilters(ctx: StateContext<WorkCenterStateModel>, action: ApplyHeaderFilters): rxjs.Observable<void> | undefined;
573
676
  applyColumnFilters(ctx: StateContext<WorkCenterStateModel>, action: ApplyColumnFilters): rxjs.Observable<void> | undefined;
677
+ /**
678
+ * Grouping is a backend concern: the table only renders contiguous rows, so
679
+ * the grouped column is pushed down as the single `context.sort` entry and
680
+ * pagination restarts at page 1. Clearing the group sends `sort: []`.
681
+ */
682
+ setGroupBy(ctx: StateContext<WorkCenterStateModel>, action: SetGroupBy): rxjs.Observable<void> | undefined;
574
683
  clearAllFilters(ctx: StateContext<WorkCenterStateModel>, action: ClearAllFilters): rxjs.Observable<void> | undefined;
575
684
  private applyFilterSlice;
576
685
  loadRuntime(ctx: StateContext<WorkCenterStateModel>, action: LoadRuntime): rxjs.Observable<WorkCenterRuntimeResponseData>;
@@ -581,5 +690,5 @@ declare class WorkCenterState {
581
690
 
582
691
  declare const APP_STATES: (typeof WorkCenterState)[];
583
692
 
584
- export { APP_STATES, ApplyColumnFilters, ApplyHeaderFilters, ClearAllFilters, EnterArea, HydrateFromContext, LoadRuntime, SetLookups, SetParams, WORK_CENTER_MAX_FILTERS, WORK_CENTER_MAX_PAGE_SIZE, WORK_CENTER_MAX_SORT, WORK_CENTER_QUERY_VERSION, WorkCenterActionKey, WorkCenterClientFormModal, WorkCenterFacade, WorkCenterItemModal, WorkCenterItemModalRoute, WorkCenterPage, WorkCenterState, decodeWorkCenterRouteContextKey, encodeWorkCenterRouteContextKey };
693
+ export { APP_STATES, ApplyColumnFilters, ApplyHeaderFilters, ClearAllFilters, EnterArea, HydrateFromContext, LoadRuntime, SetGroupBy, SetLookups, SetParams, WORK_CENTER_EMPTY_LABEL, WORK_CENTER_LEVEL_GROUP_FIELD, WORK_CENTER_LEVEL_NAME_KEY, WORK_CENTER_MAX_FILTERS, WORK_CENTER_MAX_PAGE_SIZE, WORK_CENTER_MAX_SORT, WORK_CENTER_QUERY_VERSION, WorkCenterActionKey, WorkCenterClientFormModal, WorkCenterFacade, WorkCenterItemModal, WorkCenterItemModalRoute, WorkCenterPage, WorkCenterState, decodeWorkCenterRouteContextKey, encodeWorkCenterRouteContextKey };
585
694
  export type { ApiEnvelope, TranslatableDto, WorkCenterArea, WorkCenterAreaState, WorkCenterBootstrapInputs, WorkCenterClientFormModalData, WorkCenterClientFormModalOptions, WorkCenterColumnsConfig, WorkCenterContext, WorkCenterFilterOperator, WorkCenterFilterRule, WorkCenterHydratePatch, WorkCenterItemActionAfterSuccess, WorkCenterItemActionExecutionResult, WorkCenterItemActionsData, WorkCenterItemBasicInfoData, WorkCenterItemContextKey, WorkCenterItemModalComponentInput, WorkCenterItemModalOptions, WorkCenterLoadReason, WorkCenterLookups, WorkCenterPreviewLevelTarget, WorkCenterRuntimeCard, WorkCenterRuntimeFilterSchema, WorkCenterRuntimeItemAction, WorkCenterRuntimeOperatorOption, WorkCenterRuntimePagination, WorkCenterRuntimeProperty, WorkCenterRuntimeRequest, WorkCenterRuntimeResponseData, WorkCenterRuntimeSelectedCard, WorkCenterRuntimeStatsItem, WorkCenterRuntimeWarningDto, WorkCenterSortRule, WorkCenterStateModel };