@masterteam/work-center 0.0.61 → 0.0.63

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.61",
3
+ "version": "0.0.63",
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.66",
24
- "@masterteam/components": "^0.0.238",
23
+ "@masterteam/client-components": "^0.0.67",
24
+ "@masterteam/components": "^0.0.240",
25
25
  "@masterteam/icons": "^0.0.17",
26
- "@masterteam/forms": "^0.0.126",
26
+ "@masterteam/structure-builder": "^0.0.61",
27
27
  "@masterteam/discussion": "^0.0.26",
28
- "@masterteam/structure-builder": "^0.0.61"
28
+ "@masterteam/forms": "^0.0.127"
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,29 @@ 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";
47
+ /**
48
+ * Bootstrap `group` value meaning "the user turned grouping off". Needed
49
+ * because an absent `group` means "not chosen yet" and falls back to the
50
+ * default grouping — without a distinct value, clearing the group would be
51
+ * undone by the next navigation.
52
+ */
53
+ declare const WORK_CENTER_GROUP_NONE = "none";
31
54
  interface ApiEnvelope<T> {
32
55
  endpoint: string | null;
33
56
  status: number;
@@ -208,6 +231,11 @@ interface WorkCenterAreaState {
208
231
  * Same `(field, op)` pair from this slice overrides a header rule.
209
232
  */
210
233
  columnFilters: WorkCenterFilterRule[];
234
+ /**
235
+ * Column key the table groups rows by. UI-only — never part of the runtime
236
+ * request; grouping is expressed to the backend as `context.sort`.
237
+ */
238
+ groupBy: string | null;
211
239
  menuItems: ClientPageMenuItem[];
212
240
  rows: Record<string, unknown>[];
213
241
  columns: ColumnDef[];
@@ -239,6 +267,8 @@ interface WorkCenterBootstrapInputs {
239
267
  levelDataId?: unknown;
240
268
  sort?: unknown;
241
269
  filters?: unknown;
270
+ /** Grouped column key, so a grouped view survives reload / deep-link. */
271
+ group?: unknown;
242
272
  }
243
273
  interface WorkCenterItemModalComponentInput {
244
274
  contextKey: WorkCenterItemContextKey;
@@ -267,7 +297,7 @@ interface WorkCenterClientFormModalOptions {
267
297
  buttonIcon?: string;
268
298
  lookups?: ClientLookup[];
269
299
  }
270
- type WorkCenterLoadReason = 'route-enter' | 'menu-change' | 'filters-change' | 'table-lazy' | 'refresh' | 'manual';
300
+ type WorkCenterLoadReason = 'route-enter' | 'menu-change' | 'filters-change' | 'group-change' | 'table-lazy' | 'refresh' | 'manual';
271
301
 
272
302
  declare class WorkCenterPage {
273
303
  private readonly facade;
@@ -289,6 +319,15 @@ declare class WorkCenterPage {
289
319
  readonly runtimeFiltersChanged: _angular_core.OutputEmitterRef<WorkCenterFilterRule[]>;
290
320
  readonly itemClicked: _angular_core.OutputEmitterRef<string>;
291
321
  readonly cardSelected: _angular_core.OutputEmitterRef<string>;
322
+ /**
323
+ * Emitted whenever the backend sort changes (including grouping, which is
324
+ * sent as a sort). Hosts should persist it — the runtime query is rebuilt
325
+ * from `bootstrapInputs`, so a sort that isn't round-tripped is dropped on
326
+ * the next navigation.
327
+ */
328
+ readonly sortChanged: _angular_core.OutputEmitterRef<WorkCenterSortRule[]>;
329
+ /** Emitted when the grouped column changes; `null` when grouping is cleared. */
330
+ readonly groupChanged: _angular_core.OutputEmitterRef<string | null>;
292
331
  protected readonly context: _angular_core.Signal<_masterteam_work_center.WorkCenterContext>;
293
332
  protected readonly headerFilters: _angular_core.Signal<WorkCenterFilterRule[]>;
294
333
  protected readonly tableFilters: _angular_core.WritableSignal<TableFilters>;
@@ -312,6 +351,14 @@ declare class WorkCenterPage {
312
351
  protected readonly totalCount: _angular_core.Signal<number>;
313
352
  protected readonly columnFilters: _angular_core.Signal<WorkCenterFilterRule[]>;
314
353
  protected readonly loading: _angular_core.Signal<boolean>;
354
+ protected readonly groupBy: _angular_core.Signal<string | null>;
355
+ /**
356
+ * Sort and grouping live in the runtime query (and the host's URL), not in
357
+ * table storage — persisting them locally would let a restored table claim a
358
+ * grouping the backend query no longer has. Stable reference: a fresh array
359
+ * per change detection would re-run the table's persistence effect.
360
+ */
361
+ protected readonly persistStateExclude: TablePersistStateKey[];
315
362
  protected readonly tableColumns: _angular_core.Signal<{
316
363
  sortable: boolean;
317
364
  key: string;
@@ -320,18 +367,29 @@ declare class WorkCenterPage {
320
367
  customCellTpl?: _angular_core.TemplateRef<any>;
321
368
  filterConfig?: _masterteam_components_table.FilterConfig;
322
369
  statusMap?: Record<string, _masterteam_components_table.TableStatusMapValue>;
370
+ groupable?: boolean;
371
+ groupKey?: string;
372
+ showGroupColumnLabel?: boolean;
323
373
  readonly?: boolean;
324
374
  width?: string;
325
375
  filterOnly?: boolean;
326
376
  exportable?: boolean;
327
377
  exportValue?: (row: any) => string | number | boolean | null;
328
378
  }[]>;
379
+ /**
380
+ * Grouping is executed by the backend as a single sort, so the table's own
381
+ * sort state is driven from the query we actually sent instead of the
382
+ * table's internal memory of it.
383
+ */
384
+ protected readonly sortField: _angular_core.Signal<string>;
385
+ protected readonly sortDirection: _angular_core.Signal<"asc" | "desc" | null>;
329
386
  /**
330
387
  * Maps each status/group display label to its total count from the KPI
331
388
  * summary cards so the group header shows the real backend total rather than
332
- * the current-page row count.
389
+ * the current-page row count. Withheld for groups the backend doesn't
390
+ * aggregate — see `PAGE_LOCAL_GROUP_KEYS`.
333
391
  */
334
- protected readonly statusGroupCountMap: _angular_core.Signal<Map<string, number>>;
392
+ protected readonly groupCountMap: _angular_core.Signal<Map<string, number> | null>;
335
393
  protected readonly propertyFilterSchema: _angular_core.Signal<PropertyFilterBuilderSchema | null>;
336
394
  protected readonly showGeneralTaskCreateButton: _angular_core.Signal<boolean>;
337
395
  protected readonly generalTaskButtonLabel: _angular_core.Signal<string>;
@@ -349,14 +407,27 @@ declare class WorkCenterPage {
349
407
  * (handled by `applyColumnFiltersAndLoad`); when only paging/sort changed
350
408
  * we fall through to `applyTableLazyLoadAndLoad`.
351
409
  */
410
+ /**
411
+ * The table asks to group; the backend does the ordering. `setGroupByAndLoad`
412
+ * rewrites `context.sort` and resets paging, so the lazy event the table
413
+ * fires straight after carries the same sort and lands as a no-op.
414
+ */
415
+ onTableGroupByChange(key: string | null): void;
352
416
  onTableLazyLoad(event: any): void;
417
+ /**
418
+ * Announces the backend sort to the host only when it actually moved, so a
419
+ * host that mirrors it into the URL doesn't churn history on every page hit.
420
+ * Reads the snapshot, not the signal — this runs in the same tick as the
421
+ * dispatch that changed it.
422
+ */
423
+ private emitSortIfChanged;
353
424
  onGeneralTaskCreateClick(): void;
354
425
  onRowClick(row: Record<string, unknown>): void;
355
426
  protected readonly rowsClickable: _angular_core.Signal<boolean>;
356
427
  private getOpLabel;
357
428
  private resolveRowContextKey;
358
429
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WorkCenterPage, never>;
359
- 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>;
430
+ 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>;
360
431
  }
361
432
 
362
433
  declare class WorkCenterClientFormModal {
@@ -495,6 +566,18 @@ declare class ApplyColumnFilters {
495
566
  static readonly type = "[WorkCenter] Apply Column Filters";
496
567
  constructor(area: WorkCenterArea, filters: WorkCenterFilterRule[]);
497
568
  }
569
+ /**
570
+ * Sets the grouped column. Grouping is expressed to the backend as a single
571
+ * sort on the same field, so this also rewrites `context.sort` and resets
572
+ * `page` to 1 before reloading. `groupBy: null` clears both.
573
+ */
574
+ declare class SetGroupBy {
575
+ area: WorkCenterArea;
576
+ groupBy: string | null;
577
+ dir: 'asc' | 'desc';
578
+ static readonly type = "[WorkCenter] Set Group By";
579
+ constructor(area: WorkCenterArea, groupBy: string | null, dir?: 'asc' | 'desc');
580
+ }
498
581
  /**
499
582
  * Clears both the header filter slice and the column filter slice in one
500
583
  * state update, triggering a single BE reload.
@@ -508,7 +591,7 @@ declare class ClearAllFilters {
508
591
  declare class WorkCenterFacade {
509
592
  private readonly store;
510
593
  readonly activeArea: _angular_core.Signal<WorkCenterArea>;
511
- readonly context: _angular_core.Signal<_masterteam_work_center.WorkCenterContext>;
594
+ readonly context: _angular_core.Signal<WorkCenterContext>;
512
595
  readonly menuItems: _angular_core.Signal<_masterteam_components_types_masterteam_components_client_page_menu.ClientPageMenuItem[]>;
513
596
  readonly rows: _angular_core.Signal<Record<string, unknown>[]>;
514
597
  readonly columns: _angular_core.Signal<_masterteam_components_types_masterteam_components_table.ColumnDef[]>;
@@ -517,12 +600,20 @@ declare class WorkCenterFacade {
517
600
  readonly runtimeFilterSchema: _angular_core.Signal<_masterteam_work_center.WorkCenterRuntimeFilterSchema | null>;
518
601
  readonly headerFilters: _angular_core.Signal<WorkCenterFilterRule[]>;
519
602
  readonly columnFilters: _angular_core.Signal<WorkCenterFilterRule[]>;
603
+ readonly groupBy: _angular_core.Signal<string | null>;
520
604
  readonly totalCount: _angular_core.Signal<number>;
521
605
  readonly warnings: _angular_core.Signal<_masterteam_work_center.WorkCenterRuntimeWarningDto[]>;
522
606
  private readonly loadingActive;
523
607
  private readonly errors;
524
608
  readonly loading: _angular_core.Signal<boolean>;
525
609
  readonly error: _angular_core.Signal<string | null>;
610
+ /**
611
+ * Snapshot reads for callers that must observe state *immediately* after a
612
+ * dispatch — e.g. an output handler mirroring the runtime query into the URL.
613
+ * The `select()` signals above are the right choice everywhere else.
614
+ */
615
+ snapshotContext(): WorkCenterContext;
616
+ snapshotGroupBy(): string | null;
526
617
  enterArea(area: WorkCenterArea): rxjs.Observable<void>;
527
618
  hydrateContext(area: WorkCenterArea, patch: WorkCenterHydratePatch): rxjs.Observable<void>;
528
619
  setParams(area: WorkCenterArea, inputs: WorkCenterBootstrapInputs): rxjs.Observable<void>;
@@ -540,6 +631,13 @@ declare class WorkCenterFacade {
540
631
  * and reloads with merged `headerFilters` + `columnFilters`.
541
632
  */
542
633
  applyColumnFiltersAndLoad(area: WorkCenterArea, runtimeFilters: WorkCenterFilterRule[]): rxjs.Observable<void>;
634
+ /**
635
+ * Groups the table by `groupBy` (or clears grouping with `null`). Pushes the
636
+ * grouped column down as the single backend sort, resets to page 1 and
637
+ * reloads. Safe to call from the table's `groupByChange` — the lazy event
638
+ * that follows carries the same sort and is absorbed as a no-op.
639
+ */
640
+ setGroupByAndLoad(area: WorkCenterArea, groupBy: string | null, dir?: 'asc' | 'desc'): rxjs.Observable<void>;
543
641
  /**
544
642
  * Clears both header and column filter slices in one state update,
545
643
  * triggering a single BE reload.
@@ -547,6 +645,12 @@ declare class WorkCenterFacade {
547
645
  clearAllFiltersAndLoad(area: WorkCenterArea): rxjs.Observable<void>;
548
646
  loadRuntime(area: WorkCenterArea, reason?: WorkCenterLoadReason): rxjs.Observable<void>;
549
647
  private toPositiveInt;
648
+ /**
649
+ * `mt-table` always reports its sort on a lazy event, so a `null` field is an
650
+ * explicit "no sort" and must clear `context.sort` (the BE contract asks for
651
+ * `sort: []`). Only an event with no `sortField` key at all — nothing the
652
+ * current table emits — leaves the existing sort alone.
653
+ */
550
654
  private toSortFromLazyEvent;
551
655
  private isSameSort;
552
656
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WorkCenterFacade, never>;
@@ -566,6 +670,7 @@ declare class WorkCenterState {
566
670
  static runtimeFilterSchema(snapshot: WorkCenterAreaState): WorkCenterRuntimeFilterSchema | null;
567
671
  static headerFilters(snapshot: WorkCenterAreaState): WorkCenterFilterRule[];
568
672
  static columnFilters(snapshot: WorkCenterAreaState): WorkCenterFilterRule[];
673
+ static groupBy(snapshot: WorkCenterAreaState): string | null;
569
674
  static totalCount(snapshot: WorkCenterAreaState): number;
570
675
  static warnings(snapshot: WorkCenterAreaState): _masterteam_work_center.WorkCenterRuntimeWarningDto[];
571
676
  static lookups(state: WorkCenterStateModel): _masterteam_work_center.WorkCenterLookups;
@@ -577,6 +682,12 @@ declare class WorkCenterState {
577
682
  setLookups(ctx: StateContext<WorkCenterStateModel>, action: SetLookups): void;
578
683
  applyHeaderFilters(ctx: StateContext<WorkCenterStateModel>, action: ApplyHeaderFilters): rxjs.Observable<void> | undefined;
579
684
  applyColumnFilters(ctx: StateContext<WorkCenterStateModel>, action: ApplyColumnFilters): rxjs.Observable<void> | undefined;
685
+ /**
686
+ * Grouping is a backend concern: the table only renders contiguous rows, so
687
+ * the grouped column is pushed down as the single `context.sort` entry and
688
+ * pagination restarts at page 1. Clearing the group sends `sort: []`.
689
+ */
690
+ setGroupBy(ctx: StateContext<WorkCenterStateModel>, action: SetGroupBy): rxjs.Observable<void> | undefined;
580
691
  clearAllFilters(ctx: StateContext<WorkCenterStateModel>, action: ClearAllFilters): rxjs.Observable<void> | undefined;
581
692
  private applyFilterSlice;
582
693
  loadRuntime(ctx: StateContext<WorkCenterStateModel>, action: LoadRuntime): rxjs.Observable<WorkCenterRuntimeResponseData>;
@@ -587,5 +698,5 @@ declare class WorkCenterState {
587
698
 
588
699
  declare const APP_STATES: (typeof WorkCenterState)[];
589
700
 
590
- 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 };
701
+ export { APP_STATES, ApplyColumnFilters, ApplyHeaderFilters, ClearAllFilters, EnterArea, HydrateFromContext, LoadRuntime, SetGroupBy, SetLookups, SetParams, WORK_CENTER_EMPTY_LABEL, WORK_CENTER_GROUP_NONE, 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 };
591
702
  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 };