@masterteam/work-center 0.0.71 → 0.0.72

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.71",
3
+ "version": "0.0.72",
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/forms": "^0.0.133",
24
- "@masterteam/components": "^0.0.253",
25
- "@masterteam/client-components": "^0.0.71",
23
+ "@masterteam/client-components": "^0.0.72",
24
+ "@masterteam/discussion": "^0.0.26",
26
25
  "@masterteam/icons": "^0.0.17",
27
- "@masterteam/structure-builder": "^0.0.62",
28
- "@masterteam/discussion": "^0.0.26"
26
+ "@masterteam/components": "^0.0.254",
27
+ "@masterteam/forms": "^0.0.130",
28
+ "@masterteam/structure-builder": "^0.0.62"
29
29
  },
30
30
  "sideEffects": false,
31
31
  "exports": {
@@ -4,7 +4,7 @@ import * as _masterteam_components_statistic_card from '@masterteam/components/s
4
4
  import { StatisticCardData } from '@masterteam/components/statistic-card';
5
5
  import * as _masterteam_work_center from '@masterteam/work-center';
6
6
  import * as _angular_core from '@angular/core';
7
- import { Type } from '@angular/core';
7
+ import { Type, InjectionToken, OnDestroy } from '@angular/core';
8
8
  import { ClientPageMenuItem } from '@masterteam/components/client-page-menu';
9
9
  import { PropertyFilterBuilderSchema, PropertyFilterBuilderRule } from '@masterteam/components/property-filter-builder';
10
10
  import { ClientLookup, ClientForm, ProcessFormSubmitResponse } from '@masterteam/forms/client-form';
@@ -12,6 +12,7 @@ import { LoadingStateShape } from '@masterteam/components';
12
12
  import { ModalRef } from '@masterteam/components/dialog';
13
13
  import { DrawerController } from '@masterteam/components/dynamic-drawer';
14
14
  import { ModalService } from '@masterteam/components/modal';
15
+ import { EntityData } from '@masterteam/components/entities';
15
16
  import * as rxjs from 'rxjs';
16
17
  import * as _masterteam_components_types_masterteam_components_statistic_card from '@masterteam/components/types/masterteam-components-statistic-card';
17
18
  import * as _masterteam_components_types_masterteam_components_table from '@masterteam/components/types/masterteam-components-table';
@@ -465,9 +466,26 @@ declare class WorkCenterClientFormModal {
465
466
  }
466
467
 
467
468
  declare class WorkCenterItemModal {
469
+ private readonly registry;
468
470
  readonly details: _angular_core.InputSignal<WorkCenterItemBasicInfoData>;
469
471
  readonly lookups: _angular_core.InputSignal<WorkCenterLookups | null>;
470
472
  readonly readOnly: _angular_core.InputSignal<boolean>;
473
+ /**
474
+ * The request's operation key, read from the item context.
475
+ *
476
+ * `LevelData.PublishSchedule` is dispatched on THIS rather than on a new
477
+ * `type` value: the request arrives under the existing `ProcessStep` /
478
+ * `ProcessRequest` types, so no published Work Center contract shifts.
479
+ */
480
+ protected readonly operationKey: _angular_core.Signal<string>;
481
+ protected readonly isSchedulePublish: _angular_core.Signal<boolean>;
482
+ /**
483
+ * A host-registered renderer for this item, if one is registered. Checked
484
+ * before the built-in chain, keyed by `operationKey:<key>` first so a host can
485
+ * specialise an existing type without replacing it wholesale.
486
+ */
487
+ protected readonly registeredComponent: _angular_core.Signal<Type<unknown> | null>;
488
+ protected readonly registeredInputs: _angular_core.Signal<Record<string, unknown>>;
471
489
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WorkCenterItemModal, never>;
472
490
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<WorkCenterItemModal, "mt-work-center-item-modal", never, { "details": { "alias": "details"; "required": true; "isSignal": true; }; "lookups": { "alias": "lookups"; "required": false; "isSignal": true; }; "readOnly": { "alias": "readOnly"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
473
491
  }
@@ -516,6 +534,285 @@ declare class WorkCenterItemModalRoute {
516
534
  declare function encodeWorkCenterRouteContextKey(contextKey: WorkCenterItemContextKey): string;
517
535
  declare function decodeWorkCenterRouteContextKey(value: WorkCenterItemContextKey | null): WorkCenterItemContextKey | null;
518
536
 
537
+ /**
538
+ * A detail component a host can register for a Work Center item, keyed by the
539
+ * item's `type` or - for operations that reuse an existing type - by
540
+ * `operationKey:<OperationKey>`.
541
+ *
542
+ * Every registered component must accept the same three inputs the built-in
543
+ * types do, so the modal can mount any of them the same way.
544
+ */
545
+ interface WorkCenterTypeComponentInputs {
546
+ details: WorkCenterItemBasicInfoData;
547
+ lookups?: unknown;
548
+ readOnly?: boolean;
549
+ }
550
+ /**
551
+ * Host-side registration for Work Center detail renderers.
552
+ *
553
+ * The built-in dispatch is a hardcoded `@if` chain, so every new request type
554
+ * has meant a package release. This token is the seam that makes the NEXT one a
555
+ * host registration instead. It is strictly additive: entries here are consulted
556
+ * before the built-in chain, so an unregistered host behaves exactly as before.
557
+ *
558
+ * Key by `operationKey:<OperationKey>` when the request arrives under an
559
+ * existing `type` - which is how `LevelData.PublishSchedule` is dispatched,
560
+ * deliberately avoiding a shift in the published `type` contract.
561
+ *
562
+ * @example
563
+ * providers: [
564
+ * {
565
+ * provide: WORK_CENTER_TYPE_COMPONENTS,
566
+ * useValue: { 'operationKey:ApproveBudget': ApproveBudgetType },
567
+ * },
568
+ * ]
569
+ */
570
+ declare const WORK_CENTER_TYPE_COMPONENTS: InjectionToken<Record<string, Type<unknown>>>;
571
+
572
+ /**
573
+ * work-center-schedule-publish.models.ts - The wire shape of the published-vs-draft
574
+ * comparison an approver acts on.
575
+ *
576
+ * Mirrors the backend's `SchedulePublishDiffDto`, which `process-form-load`
577
+ * returns as a REQUEST-level `schedulePublish` block for
578
+ * `LevelData.PublishSchedule`. It is request-level rather than hung off a form
579
+ * field because a publish submits no fields - the plan IS the payload.
580
+ *
581
+ * The same vocabulary is used by the schedule read envelope and the Review &
582
+ * Publish drawer in `@masterteam/task-schedule`, deliberately: one differ serves
583
+ * all three, so the planner who requested the publish and the approver deciding
584
+ * on it cannot be shown the same row described differently.
585
+ *
586
+ * Pure TypeScript - no Angular, no DOM.
587
+ */
588
+ /**
589
+ * `'removed'` means a row that is in the published snapshot but no longer in the
590
+ * plan. `'unchanged'` never reaches the comparison payload - the drawer shows
591
+ * what is being published, not the whole plan.
592
+ */
593
+ type SchedulePublishState = 'added' | 'changed' | 'removed' | 'unchanged';
594
+ interface SchedulePublishFieldChange {
595
+ /** Authored field key, e.g. `plannedStart`. */
596
+ field: string;
597
+ /**
598
+ * How each side should be RENDERED - Text, Date, Number, Percentage or User.
599
+ * Carried per change so a date shows as a date and a user as an avatar rather
600
+ * than as the stored string.
601
+ */
602
+ viewType?: string | null;
603
+ publishedValue?: unknown;
604
+ currentValue?: unknown;
605
+ }
606
+ interface SchedulePublishDiffRow {
607
+ scheduleItemId: number;
608
+ state: SchedulePublishState;
609
+ /** Current name, falling back to the published name for a removed row. */
610
+ name: string;
611
+ /** Module key - `Task`, `Milestone` or `Deliverable`. */
612
+ type?: string | null;
613
+ parentId?: number | null;
614
+ order?: number | null;
615
+ isSummary?: boolean | null;
616
+ /** False for a removed row. */
617
+ existsInCurrentSchedule?: boolean | null;
618
+ /** False for an added row - it has never been announced. */
619
+ existsInPublishedSchedule?: boolean | null;
620
+ /**
621
+ * Populated for `changed` only. Added and removed rows carry no per-field
622
+ * list: the whole row is the change.
623
+ */
624
+ changes?: SchedulePublishFieldChange[] | null;
625
+ }
626
+ interface SchedulePublishDiff {
627
+ levelDataId?: number | null;
628
+ /**
629
+ * False when the project has never been published, in which case `rows` is
630
+ * empty and the whole plan is implicitly unannounced. The approver is told
631
+ * something different about that than about "nothing to publish".
632
+ */
633
+ hasSnapshot?: boolean | null;
634
+ lastPublishedAtUtc?: string | null;
635
+ lastPublishedBy?: string | null;
636
+ addedCount?: number | null;
637
+ changedCount?: number | null;
638
+ removedCount?: number | null;
639
+ unpublishedChangeCount?: number | null;
640
+ rows?: SchedulePublishDiffRow[] | null;
641
+ }
642
+ /** The slice of `process-form-load` this type consumes. */
643
+ interface SchedulePublishFormLoadResponse {
644
+ schedulePublish?: SchedulePublishDiff | null;
645
+ requestId?: number | null;
646
+ /** Tolerated because several runtime endpoints wrap their payload. */
647
+ data?: SchedulePublishFormLoadResponse | null;
648
+ }
649
+
650
+ /**
651
+ * work-center-schedule-publish.rows.ts - Pure grouping, ordering, counting and
652
+ * filtering rules for the approver's published-vs-draft comparison.
653
+ *
654
+ * THE DIFF ITSELF IS SERVER-SIDE. This module never decides what changed - only
655
+ * how the answer is presented, so a 500-row plan stays scannable in a drawer.
656
+ * Split out of the component so the rules are unit-testable without a browser or
657
+ * TestBed, mirroring `work-center-process-preview.rows.ts` - this package has no
658
+ * component TestBed specs, only pure-function ones.
659
+ *
660
+ * Intentionally a twin of `@masterteam/task-schedule`'s
661
+ * `core/task-schedule-publish-diff.ts`: the planner and the approver must sort,
662
+ * group and count the same payload identically, and duplicating ~100 lines of
663
+ * pure rules is cheaper than a cross-package dependency between a schedule
664
+ * runtime and a work-center drawer.
665
+ *
666
+ * Pure TypeScript - no Angular, no DOM.
667
+ */
668
+
669
+ /**
670
+ * The order groups are presented in, and the only states a group is built for.
671
+ *
672
+ * Added first because a new row is the biggest claim a publish makes; removed
673
+ * last because it is the one an approver most needs to not miss, and a trailing
674
+ * group is where the eye stops.
675
+ */
676
+ declare const SCHEDULE_PUBLISH_GROUP_ORDER: readonly SchedulePublishState[];
677
+ interface SchedulePublishGroup {
678
+ state: SchedulePublishState;
679
+ rows: SchedulePublishDiffRow[];
680
+ /** Rows in this group BEFORE the search filter - the badge count stays honest. */
681
+ totalCount: number;
682
+ }
683
+ interface SchedulePublishSummary {
684
+ hasSnapshot: boolean;
685
+ addedCount: number;
686
+ changedCount: number;
687
+ removedCount: number;
688
+ totalCount: number;
689
+ /** True when there is genuinely nothing to publish (as opposed to never published). */
690
+ isEmpty: boolean;
691
+ }
692
+ declare function summarizeSchedulePublish(diff: SchedulePublishDiff | null | undefined): SchedulePublishSummary;
693
+ /**
694
+ * Group the comparison for display, optionally narrowed by a free-text search.
695
+ *
696
+ * Search matches a row's NAME and its changed FIELD KEYS, so "start" finds every
697
+ * row whose planned start moved even though that text appears nowhere in a name.
698
+ * Empty groups are dropped rather than rendered as empty headers.
699
+ */
700
+ declare function groupSchedulePublishRows(diff: SchedulePublishDiff | null | undefined, searchText?: string): SchedulePublishGroup[];
701
+ /**
702
+ * Plan order, falling back to the row id.
703
+ *
704
+ * Deliberately NOT alphabetical: an approver reads the comparison against the
705
+ * plan as the planner built it, and re-sorting by name would scatter a phase's
706
+ * rows across the list.
707
+ */
708
+ declare function sortSchedulePublishRows(rows: readonly SchedulePublishDiffRow[]): SchedulePublishDiffRow[];
709
+ declare function matchesSchedulePublishSearch(row: SchedulePublishDiffRow, lowerNeedle: string): boolean;
710
+ /**
711
+ * A stable per-row key for `@for` tracking.
712
+ *
713
+ * Includes the state because the SAME schedule item id can legitimately appear
714
+ * under two groups across a re-render (a row removed then re-added), and reusing
715
+ * a DOM node across that transition would carry the old group's styling.
716
+ */
717
+ declare function schedulePublishRowKey(row: SchedulePublishDiffRow): string;
718
+ /**
719
+ * Changed fields in the order the backend classified them, with blanks dropped.
720
+ * Added and removed rows have no per-field list - the whole row is the change.
721
+ */
722
+ declare function readSchedulePublishChanges(row: SchedulePublishDiffRow | null | undefined): SchedulePublishFieldChange[];
723
+ /**
724
+ * Windowing for a plan large enough to stall a drawer. Returns the first
725
+ * `limit` rows and how many were withheld, so the caller can say so out loud
726
+ * rather than silently truncating a comparison someone is approving.
727
+ */
728
+ declare function windowSchedulePublishRows(rows: readonly SchedulePublishDiffRow[], limit: number): {
729
+ rows: SchedulePublishDiffRow[];
730
+ hiddenCount: number;
731
+ };
732
+
733
+ /**
734
+ * The operation key this type renders for. Dispatch is by OPERATION KEY, not by
735
+ * a new `type` value: the request arrives under the existing `ProcessStep` /
736
+ * `ProcessRequest` types, so no published Work Center contract shifts.
737
+ */
738
+ declare const SCHEDULE_PUBLISH_OPERATION_KEY = "PublishSchedule";
739
+ /**
740
+ * The approver's view of a `LevelData.PublishSchedule` request.
741
+ *
742
+ * Exists because the closest existing zero-field action renders a title, a due
743
+ * date and three buttons: without this an approver would be asked to authorise a
744
+ * change to the plan of record while being shown less than the planner who
745
+ * requested it.
746
+ *
747
+ * The comparison is the diff FROZEN AT SUBMIT on the backend, not the live one,
748
+ * so the plan cannot move under the approver while they read it.
749
+ */
750
+ declare class WorkCenterSchedulePublishType implements OnDestroy {
751
+ private readonly http;
752
+ private readonly transloco;
753
+ private readonly destroyRef;
754
+ private loadSub?;
755
+ readonly details: _angular_core.InputSignal<WorkCenterItemBasicInfoData>;
756
+ readonly readOnly: _angular_core.InputSignal<boolean>;
757
+ protected readonly activeTab: _angular_core.WritableSignal<string>;
758
+ private readonly activeLang;
759
+ protected readonly loading: _angular_core.WritableSignal<boolean>;
760
+ protected readonly error: _angular_core.WritableSignal<string | null>;
761
+ protected readonly diff: _angular_core.WritableSignal<SchedulePublishDiff | null>;
762
+ protected readonly searchText: _angular_core.WritableSignal<string>;
763
+ protected readonly expandedRowKeys: _angular_core.WritableSignal<ReadonlySet<string>>;
764
+ protected readonly itemContext: _angular_core.Signal<Record<string, unknown> | null>;
765
+ protected readonly requestId: _angular_core.Signal<number | undefined>;
766
+ protected readonly levelId: _angular_core.Signal<number | undefined>;
767
+ protected readonly levelDataId: _angular_core.Signal<number | undefined>;
768
+ protected readonly moduleKey: _angular_core.Signal<string>;
769
+ protected readonly requestSchemaId: _angular_core.Signal<number | undefined>;
770
+ protected readonly summary: _angular_core.Signal<_masterteam_work_center.SchedulePublishSummary>;
771
+ protected readonly groups: _angular_core.Signal<SchedulePublishGroup[]>;
772
+ protected readonly hasSearch: _angular_core.Signal<boolean>;
773
+ /** True when the search hid everything, as opposed to there being nothing to publish. */
774
+ protected readonly searchFoundNothing: _angular_core.Signal<boolean>;
775
+ protected readonly resolvedRequestId: _angular_core.Signal<number>;
776
+ protected readonly canRenderPreview: _angular_core.Signal<boolean>;
777
+ protected readonly canRenderDiscussion: _angular_core.Signal<boolean>;
778
+ protected readonly tabOptions: _angular_core.Signal<{
779
+ label: string;
780
+ value: string;
781
+ icon: string;
782
+ }[]>;
783
+ constructor();
784
+ ngOnDestroy(): void;
785
+ protected onSearch(value: string): void;
786
+ protected toggleRow(row: SchedulePublishDiffRow): void;
787
+ protected isExpanded(row: SchedulePublishDiffRow): boolean;
788
+ protected rowKey(row: SchedulePublishDiffRow): string;
789
+ protected visibleRows(group: SchedulePublishGroup): SchedulePublishDiffRow[];
790
+ protected hiddenCount(group: SchedulePublishGroup): number;
791
+ protected changesFor(row: SchedulePublishDiffRow): SchedulePublishFieldChange[];
792
+ /**
793
+ * Only `changed` rows have per-field detail worth expanding. For added and
794
+ * removed rows the whole row IS the change, so an expander would open onto
795
+ * nothing.
796
+ */
797
+ protected isExpandable(row: SchedulePublishDiffRow): boolean;
798
+ protected groupBadgeClass(state: string): string;
799
+ protected groupLabel(state: string): string;
800
+ /**
801
+ * The field key as a human label, falling back to the key itself on a missing
802
+ * translation rather than rendering `workCenter.publish.field.plannedStart`.
803
+ */
804
+ protected fieldLabel(field: string): string;
805
+ /**
806
+ * One side of a field change, projected into an `EntityData` so it renders
807
+ * through its NATIVE view type - a date as a date, a user as an avatar -
808
+ * rather than as the stored string.
809
+ */
810
+ protected sideEntity(change: SchedulePublishFieldChange, side: 'published' | 'current'): EntityData;
811
+ private loadComparison;
812
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<WorkCenterSchedulePublishType, never>;
813
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<WorkCenterSchedulePublishType, "mt-work-center-schedule-publish-type", never, { "details": { "alias": "details"; "required": true; "isSignal": true; }; "readOnly": { "alias": "readOnly"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
814
+ }
815
+
519
816
  declare class EnterArea {
520
817
  area: WorkCenterArea;
521
818
  static readonly type = "[WorkCenter] Enter Area";
@@ -716,5 +1013,5 @@ declare class WorkCenterState {
716
1013
 
717
1014
  declare const APP_STATES: (typeof WorkCenterState)[];
718
1015
 
719
- export { APP_STATES, ApplyColumnFilters, ApplyHeaderFilters, ClearAllFilters, EnterArea, HydrateFromContext, LoadRuntime, SelectCard, 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 };
720
- 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 };
1016
+ export { APP_STATES, ApplyColumnFilters, ApplyHeaderFilters, ClearAllFilters, EnterArea, HydrateFromContext, LoadRuntime, SCHEDULE_PUBLISH_GROUP_ORDER, SCHEDULE_PUBLISH_OPERATION_KEY, SelectCard, 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, WORK_CENTER_TYPE_COMPONENTS, WorkCenterActionKey, WorkCenterClientFormModal, WorkCenterFacade, WorkCenterItemModal, WorkCenterItemModalRoute, WorkCenterPage, WorkCenterSchedulePublishType, WorkCenterState, decodeWorkCenterRouteContextKey, encodeWorkCenterRouteContextKey, groupSchedulePublishRows, matchesSchedulePublishSearch, readSchedulePublishChanges, schedulePublishRowKey, sortSchedulePublishRows, summarizeSchedulePublish, windowSchedulePublishRows };
1017
+ export type { ApiEnvelope, SchedulePublishDiff, SchedulePublishDiffRow, SchedulePublishFieldChange, SchedulePublishFormLoadResponse, SchedulePublishGroup, SchedulePublishState, SchedulePublishSummary, 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, WorkCenterTypeComponentInputs };