@masterteam/client-components 0.0.95 → 0.0.97

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/client-components",
3
- "version": "0.0.95",
3
+ "version": "0.0.97",
4
4
  "publishConfig": {
5
5
  "directory": "../../../dist/masterteam/client-components",
6
6
  "linkDirectory": true,
@@ -16,10 +16,10 @@
16
16
  "rxjs": "^7.8.2",
17
17
  "tailwindcss": "^4.2.2",
18
18
  "tailwindcss-primeui": "^0.6.1",
19
- "@masterteam/forms": "^0.0.155",
20
- "@masterteam/components": "^0.0.300",
21
- "@masterteam/dashboard-builder": "^0.0.92",
22
- "@masterteam/icons": "^0.0.17"
19
+ "@masterteam/forms": "^0.0.157",
20
+ "@masterteam/icons": "^0.0.17",
21
+ "@masterteam/components": "^0.0.302",
22
+ "@masterteam/dashboard-builder": "^0.0.92"
23
23
  },
24
24
  "dependencies": {
25
25
  "tslib": "^2.8.1"
@@ -1,7 +1,7 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { OnDestroy } from '@angular/core';
3
3
  import * as _masterteam_components_entities from '@masterteam/components/entities';
4
- import { EntityData, EntityViewType, EntityListPreviewContext } from '@masterteam/components/entities';
4
+ import { EntityRuntimeContext, EntityData, EntityViewType } from '@masterteam/components/entities';
5
5
  import { Observable } from 'rxjs';
6
6
 
7
7
  interface ClientInstancePreviewConfig {
@@ -9,6 +9,17 @@ interface ClientInstancePreviewConfig {
9
9
  instanceId: number;
10
10
  displayAreas?: string[];
11
11
  processRequestId?: number;
12
+ /**
13
+ * Owning level and level-data ids, for the renderers that fetch data of
14
+ * their own — today a module-backed `EntityList`, which renders as the real
15
+ * related-records table when this is present and as a count-and-drawer
16
+ * trigger when it is not.
17
+ *
18
+ * It has to come from the host. The response's own `context` carries the
19
+ * level id, but its `scopeId` is the *level-module* id, not the level-data
20
+ * row, and nothing else in the payload identifies that row.
21
+ */
22
+ runtimeContext?: EntityRuntimeContext;
12
23
  /**
13
24
  * Optional host projection applied after the preview response is converted
14
25
  * to renderable entities. Use it to merge or derive presentation-only
@@ -75,8 +86,22 @@ interface PreviewFetchCatalog {
75
86
  */
76
87
  nestedProperties?: Record<string, PreviewFetchPropertyMeta[]>;
77
88
  }
89
+ /**
90
+ * The resolved context of the fetched record. `scopeId` is the level-module
91
+ * id (`FetchContext.Scope.CompositeId`), **not** the level-data row — a host
92
+ * that needs that one supplies it through `runtimeContext`.
93
+ */
94
+ interface PreviewFetchContext {
95
+ kind?: string;
96
+ levelId?: number;
97
+ moduleId?: number;
98
+ templateId?: number;
99
+ scopeId?: number;
100
+ hasWorkSpace?: boolean;
101
+ }
78
102
  interface PreviewFetchRecordResponse {
79
103
  contextKey: string;
104
+ context?: PreviewFetchContext | null;
80
105
  schemas?: PreviewFetchSchema[];
81
106
  catalog?: PreviewFetchCatalog;
82
107
  record?: PreviewFetchRecord | null;
@@ -94,6 +119,7 @@ interface DisplayConfiguration {
94
119
  }
95
120
  interface PreviewResponse {
96
121
  contextKey: string;
122
+ context: PreviewFetchContext | null;
97
123
  schemas: PreviewFetchSchema[];
98
124
  catalog: PreviewFetchCatalog;
99
125
  record: PreviewFetchRecord | null;
@@ -103,6 +129,7 @@ interface PreviewResponse {
103
129
  declare class ClientInstancePreview implements OnDestroy {
104
130
  private readonly clientInstancePreviewApiService;
105
131
  private readonly transloco;
132
+ private readonly runtimeContextStore;
106
133
  private loadSub?;
107
134
  readonly config: _angular_core.InputSignal<ClientInstancePreviewConfig>;
108
135
  /** When true, suppresses the "No preview data" empty-state placeholder so the host can collapse. */
@@ -114,28 +141,9 @@ declare class ClientInstancePreview implements OnDestroy {
114
141
  * honored instead. The hard ≤280px overflow stack always applies regardless.
115
142
  */
116
143
  readonly stackOnNarrow: _angular_core.InputSignal<boolean>;
117
- /**
118
- * Level-data row the previewed record belongs to.
119
- *
120
- * Supplying it renders every `EntityList` property as the full read-only
121
- * table the form shows, instead of a count and a drawer. That table loads
122
- * itself from `Properties/{propertyId}/entitylist/table-metadata` and
123
- * `fetch/query`, which need the owning level *and* its level-data scope —
124
- * and the fetch Card payload carries neither, so the host passes this from
125
- * the route while the level is parsed from `contextKey`.
126
- *
127
- * Left null, EntityList keeps the compact renderer: without the scope the
128
- * table would draw its columns and never a row.
129
- */
130
- readonly levelDataId: _angular_core.InputSignal<string | number | null>;
131
144
  readonly loading: _angular_core.WritableSignal<boolean>;
132
145
  readonly error: _angular_core.WritableSignal<string | null>;
133
146
  readonly response: _angular_core.WritableSignal<PreviewResponse | null>;
134
- /**
135
- * Runtime scope handed to each `EntityList` entity, or null when this host
136
- * did not supply a level-data row. See {@link levelDataId}.
137
- */
138
- protected readonly entityListContext: _angular_core.Signal<EntityListPreviewContext | null>;
139
147
  readonly entities: _angular_core.Signal<EntityData[]>;
140
148
  /**
141
149
  * Name of the schema the loaded record belongs to — the level name for a
@@ -144,11 +152,21 @@ declare class ClientInstancePreview implements OnDestroy {
144
152
  * fetch resolves.
145
153
  */
146
154
  readonly schemaName: _angular_core.Signal<string | null>;
155
+ /**
156
+ * What the nested renderers fetch with.
157
+ *
158
+ * The level id is taken from the response when the host did not supply one —
159
+ * `fetch/records` resolves it anyway, so a host that already passes a
160
+ * `contextKey` should not have to repeat it. The level-data id has no such
161
+ * fallback: the response's `scopeId` is the level-module id, so a host that
162
+ * omits `runtimeContext` gets no inline table.
163
+ */
164
+ private readonly runtimeContext;
147
165
  constructor();
148
166
  load(config: ClientInstancePreviewConfig): void;
149
167
  ngOnDestroy(): void;
150
168
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ClientInstancePreview, never>;
151
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ClientInstancePreview, "mt-client-instance-preview", never, { "config": { "alias": "config"; "required": true; "isSignal": true; }; "hideEmptyState": { "alias": "hideEmptyState"; "required": false; "isSignal": true; }; "stackOnNarrow": { "alias": "stackOnNarrow"; "required": false; "isSignal": true; }; "levelDataId": { "alias": "levelDataId"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
169
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ClientInstancePreview, "mt-client-instance-preview", never, { "config": { "alias": "config"; "required": true; "isSignal": true; }; "hideEmptyState": { "alias": "hideEmptyState"; "required": false; "isSignal": true; }; "stackOnNarrow": { "alias": "stackOnNarrow"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
152
170
  }
153
171
 
154
172
  declare class ClientInstancePreviewApiService {
@@ -161,4 +179,4 @@ declare class ClientInstancePreviewApiService {
161
179
  }
162
180
 
163
181
  export { ClientInstancePreview, ClientInstancePreviewApiService };
164
- export type { ClientInstancePreviewConfig, ClientInstancePreviewEntityTransform, DisplayConfiguration, PreviewFetchCatalog, PreviewFetchPropertyMeta, PreviewFetchRecord, PreviewFetchRecordResponse, PreviewFetchSchema, PreviewFetchValueCell, PreviewResponse, Response };
182
+ export type { ClientInstancePreviewConfig, ClientInstancePreviewEntityTransform, DisplayConfiguration, PreviewFetchCatalog, PreviewFetchContext, PreviewFetchPropertyMeta, PreviewFetchRecord, PreviewFetchRecordResponse, PreviewFetchSchema, PreviewFetchValueCell, PreviewResponse, Response };
@@ -170,6 +170,9 @@ interface ClientListTableDisplayConfig {
170
170
  * The key must name a column that is actually rendered, and grouping only
171
171
  * makes sense once every row of a group is loaded — with backend paging a
172
172
  * group is split across pages and each page grows its own header.
173
+ *
174
+ * Also the board's starting grouping: table and cards share one toolbar
175
+ * state per list, seeded once by whichever view renders first.
173
176
  */
174
177
  groupBy?: string;
175
178
  }
@@ -192,15 +195,23 @@ interface ClientListFormConfiguration extends ClientListBaseConfiguration {
192
195
  /** Complete filter array forwarded unchanged to `fetch/query`. */
193
196
  filters?: ClientListFetchRequestFilter[];
194
197
  /**
195
- * `areaType: 'table'` only — fetch the rows owned by this root's
196
- * descendants instead of the rows owned by the context's own records. See
197
- * {@link ClientListFetchHierarchyScope}. Ignored for cards and informative
198
- * lists, which the backend rejects outright.
198
+ * `areaType: 'table'` and `areaType: 'cards'` — fetch the rows owned by this
199
+ * root's descendants instead of the rows owned by the context's own records.
200
+ * See {@link ClientListFetchHierarchyScope}. Ignored for informative lists,
201
+ * which the backend rejects outright.
199
202
  *
200
203
  * Rows then arrive from several owners at once: each carries its owning
201
- * record under {@link CLIENT_LIST_RECORD_SOURCE_KEY}, row actions are
202
- * addressed to that owner's context, and `state.totals` / `state.sourceGroups`
203
- * carry the pre-pagination aggregates.
204
+ * record under {@link CLIENT_LIST_RECORD_SOURCE_KEY} (a card carries it as
205
+ * {@link ClientListCard.source}), row actions are addressed to that owner's
206
+ * context, and `state.totals` / `state.sourceGroups` carry the
207
+ * pre-pagination aggregates.
208
+ *
209
+ * A cards board is still fetched as a `Table` projection — descendant scope
210
+ * is table-only on the backend — and re-dressed with the context's authored
211
+ * card layout. Two consequences: the board shows the module's table
212
+ * selection, so a property the card layout uses but the table hides cannot
213
+ * appear on it; and a write reloads the board rather than splicing, for the
214
+ * same reason a hierarchy table does.
204
215
  */
205
216
  hierarchy?: ClientListFetchHierarchyScope;
206
217
  mode?: ClientListMode;
@@ -237,7 +248,13 @@ interface ClientListFormConfiguration extends ClientListBaseConfiguration {
237
248
  table?: ClientListTableDisplayConfig;
238
249
  /**
239
250
  * Host hook to reshape built columns/rows before render — see
240
- * {@link ClientListTableTransform}. Applies to `table` area only.
251
+ * {@link ClientListTableTransform}.
252
+ *
253
+ * On `areaType: 'cards'` it runs over each card's row representation, so a
254
+ * board offers the same columns the table does — which is what lets
255
+ * `table.groupBy` name a host-derived column and still group a board. Cells
256
+ * the transform *adds* become row-only fields (grouping, filters, export);
257
+ * the card face keeps rendering its own layout and never shows them.
241
258
  */
242
259
  transformResult?: ClientListTableTransform;
243
260
  }
@@ -611,6 +628,14 @@ interface ClientListCard {
611
628
  properties: ClientListCardProperty[];
612
629
  displayProperties?: Record<string, unknown>;
613
630
  entities: EntityData[];
631
+ /**
632
+ * Descendant boards only: the record that owns this card. Null on an
633
+ * ordinary board, where the list's own context is the owner. Travels into
634
+ * the card's row representation under
635
+ * {@link CLIENT_LIST_RECORD_SOURCE_KEY}, so row actions address the owner
636
+ * rather than the aggregation context.
637
+ */
638
+ source?: ClientListFetchRecordSource | null;
614
639
  }
615
640
  type ClientListCardsPayload = ClientListFetchQueryResponse;
616
641
  interface ClientListInformativeChartLink {
@@ -646,14 +671,19 @@ interface ClientListBaseState {
646
671
  dashboardData: DashboardBuilderData | null;
647
672
  rawData: unknown | null;
648
673
  /**
649
- * Hierarchy tables only: totals over every matching row before pagination,
674
+ * Hierarchy lists only: totals over every matching row before pagination,
650
675
  * so they stay put as the user pages. Undefined for an ordinary list — the
651
676
  * backend sends none, and a page sum would not be the same number.
652
677
  */
653
678
  totals?: ClientListFetchSum[];
654
679
  /**
655
- * Hierarchy tables only: one entry per owning record, with its full matching
680
+ * Hierarchy lists only: one entry per owning record, with its full matching
656
681
  * count and subtotals plus the ids of its rows on the current page.
682
+ *
683
+ * On a board that appends pages as the user scrolls, "the current page"
684
+ * means the page fetched last while `cards` holds every page loaded so far
685
+ * — so read the counts and subtotals, which cover every matching row,
686
+ * rather than `recordIds`.
657
687
  */
658
688
  sourceGroups?: ClientListFetchSourceGroup[];
659
689
  }
@@ -787,6 +817,22 @@ declare class ClientListStateService {
787
817
  setInformativeResult(key: string, response: ClientListInformativeDashboardPayload | null, config: NormalizedClientListConfiguration): void;
788
818
  toggleExpanded(key: string): void;
789
819
  private mergeItemState;
820
+ /**
821
+ * Runs the host's `transformResult` over a board, so it offers the same
822
+ * columns the table of the same list does — the ones a host derives
823
+ * included (a descendant list's level and owning record, say). That is what
824
+ * lets a board group, filter and export by them, and what lets a
825
+ * `table.groupBy` default naming a derived column group a board at all.
826
+ *
827
+ * The card face is left alone: the card keeps rendering its own layout, and
828
+ * the derived cells ride on `displayProperties`, which only the card's row
829
+ * representation reads. Cells the transform rewrote rather than added are
830
+ * not carried over — the card already shows those fields its own way.
831
+ *
832
+ * Without a transform the board keeps its old behaviour: no `columns`, so
833
+ * the view derives them from the first card's entities.
834
+ */
835
+ private shapeCards;
790
836
  private toCards;
791
837
  private orderRecords;
792
838
  private resolvePrimarySchema;
@@ -957,11 +1003,14 @@ declare class ClientList implements OnDestroy {
957
1003
  private resolveType;
958
1004
  private resolveMode;
959
1005
  /**
960
- * Descendant scope only survives where the backend accepts it: a table, with
961
- * a usable root id. Anywhere else it is dropped rather than sent, because
962
- * the backend answers an unsupported combination with a 400 that takes the
963
- * whole list down — a cards area that happens to share a config object would
964
- * otherwise render nothing at all.
1006
+ * Descendant scope only survives where it can actually be fetched: a table
1007
+ * or a cards board, with a usable root id. An informative dashboard drops it
1008
+ * rather than sending it, because the backend answers an unsupported
1009
+ * combination with a 400 that takes the whole list down.
1010
+ *
1011
+ * A cards board does not send it as `Card` either — the backend takes
1012
+ * descendant scope on `Table` only. `ClientListApiService.getCards` fetches
1013
+ * the hierarchy table and re-dresses it as cards.
965
1014
  */
966
1015
  private resolveHierarchyScope;
967
1016
  private toNormalizedConfig;
@@ -1026,6 +1075,8 @@ declare class ClientListApiService {
1026
1075
  private readonly http;
1027
1076
  private readonly runtimeFetchBaseUrl;
1028
1077
  private readonly informativeBaseUrl;
1078
+ /** Card layouts already read back, keyed by context. See {@link getCardLayout}. */
1079
+ private readonly cardLayouts;
1029
1080
  /**
1030
1081
  * Fetches a table page. Resolves to the response **and** the `propertyKeys`
1031
1082
  * the request carried, because a write that wants its record projected the
@@ -1045,7 +1096,49 @@ declare class ClientListApiService {
1045
1096
  * having moved out of the root's subtree since it was written.
1046
1097
  */
1047
1098
  getRecord(contextKey: ClientListRuntimeContext, request: ClientListReturnRecordRequest, filters: ClientListFetchRequestFilter[]): Observable<Response<ClientListFetchQueryResponse>>;
1048
- getCards(contextKey: ClientListRuntimeContext, filters?: ClientListFetchRequestFilter[], skip?: number, take?: number): Observable<Response<ClientListCardsPayload>>;
1099
+ /**
1100
+ * Fetches a board of cards.
1101
+ *
1102
+ * Without a `hierarchy` scope this is a plain `Card` projection. With one it
1103
+ * cannot be: the backend accepts descendant scope on the **`Table`
1104
+ * projection only** and answers any other projection with a 400 that takes
1105
+ * the whole list down. So a descendant board is fetched as a hierarchy table
1106
+ * and re-dressed as cards — the rows carry the same records, their owning
1107
+ * record and the pre-pagination totals, and {@link getCardLayout} supplies
1108
+ * the card layout the board would otherwise lose.
1109
+ */
1110
+ getCards(contextKey: ClientListRuntimeContext, filters?: ClientListFetchRequestFilter[], skip?: number, take?: number, hierarchy?: ClientListFetchHierarchyScope | null): Observable<Response<ClientListCardsPayload>>;
1111
+ /**
1112
+ * The card layout authored for a context, with every property key rewritten
1113
+ * to its normalized form.
1114
+ *
1115
+ * A `Card` response names its properties by the owning context's own key
1116
+ * (`leveldatafinancial_title`), while a hierarchy response normalizes every
1117
+ * row, column and catalog entry across the child levels down to the shared
1118
+ * key (`title`). Sent through unchanged the layout would resolve against
1119
+ * nothing and every card would render empty.
1120
+ *
1121
+ * Cached per context for the life of the app: it is a second request on a
1122
+ * path that already makes one, it is pure configuration, and it is re-read
1123
+ * on the next full load anyway. A card layout edited in the control panel
1124
+ * therefore needs a reload of the app to show up on a descendant board —
1125
+ * the same page-load boundary the rest of the display configuration has.
1126
+ */
1127
+ private getCardLayout;
1128
+ private toNormalizedDisplayOrder;
1129
+ /**
1130
+ * Dresses a hierarchy table response as the card payload the board reads:
1131
+ * the same records, plus the authored card layout narrowed to the properties
1132
+ * this response actually carries. A layout entry with no property behind it
1133
+ * would render as a nameless blank slot, so it is dropped — section markers
1134
+ * excepted, since they are layout rather than data and have no property to
1135
+ * begin with.
1136
+ *
1137
+ * Leaves the response untouched when there is no usable layout: the card
1138
+ * mapper then falls back to the response's own table columns, which is a
1139
+ * plainer board but a complete one.
1140
+ */
1141
+ private withCardLayout;
1049
1142
  getInformativeDashboard(levelId: number, moduleId: number): Observable<Response<ClientListInformativeDashboardPayload>>;
1050
1143
  private queryRuntime;
1051
1144
  private resolveTablePropertyKeys;