@masterteam/work-center 0.0.63 → 0.0.65

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.
@@ -168,6 +168,22 @@ class ApplyColumnFilters {
168
168
  this.filters = filters;
169
169
  }
170
170
  }
171
+ /**
172
+ * Switches the selected card and drops everything that was scoped to the
173
+ * previous one: advanced filters, in-table column filters, grouping and the
174
+ * sort that grouping implied. Each card brings its own columns and filter
175
+ * schema, so carrying those over would filter on fields the new card doesn't
176
+ * have and group by a column it doesn't show.
177
+ */
178
+ class SelectCard {
179
+ area;
180
+ selectedCardKey;
181
+ static type = '[WorkCenter] Select Card';
182
+ constructor(area, selectedCardKey) {
183
+ this.area = area;
184
+ this.selectedCardKey = selectedCardKey;
185
+ }
186
+ }
171
187
  /**
172
188
  * Sets the grouped column. Grouping is expressed to the backend as a single
173
189
  * sort on the same field, so this also rewrites `context.sort` and resets
@@ -315,11 +331,10 @@ function parseSortInput(value) {
315
331
  /**
316
332
  * Resolves the grouped column key from bootstrap inputs.
317
333
  *
318
- * A missing `group` means "not chosen yet" and keeps whatever state already
319
- * has which starts at the area default, so a first visit lands grouped.
320
- * `WORK_CENTER_GROUP_NONE` is the only way to express "the user turned it
321
- * off"; a bare `null` can't, because it is also what a host passes for an
322
- * absent query param.
334
+ * A missing `group` keeps whatever state already has, so an unrelated
335
+ * navigation doesn't drop the user's grouping. `WORK_CENTER_GROUP_NONE` is the
336
+ * only way to express "turn it off" — a bare `null` can't, because it is also
337
+ * what a host passes for an absent query param.
323
338
  */
324
339
  function resolveGroupByFromInputs(current, group) {
325
340
  if (!hasParamValue(group) || typeof group !== 'string') {
@@ -331,6 +346,14 @@ function resolveGroupByFromInputs(current, group) {
331
346
  }
332
347
  return parsed;
333
348
  }
349
+ /**
350
+ * The card these inputs resolve to — the same rule `buildContextFromInputs`
351
+ * applies, exposed so callers can detect a card switch before building the
352
+ * context (what survives the switch depends on it).
353
+ */
354
+ function resolveSelectedCardKeyFromInputs(currentContext, inputs = {}) {
355
+ return toSelectedCardKey(inputs.card) ?? currentContext.selectedCardKey;
356
+ }
334
357
  function parseFiltersInput(value) {
335
358
  const parsed = parseJson(value);
336
359
  return Array.isArray(parsed)
@@ -462,13 +485,7 @@ function buildColumnsFromProperties(properties) {
462
485
  */
463
486
  function withLevelNameGrouping(key) {
464
487
  return key === WORK_CENTER_LEVEL_NAME_KEY
465
- ? {
466
- groupable: true,
467
- groupKey: WORK_CENTER_LEVEL_GROUP_FIELD,
468
- // A level name names itself — "Level Name · Project Gamma" would just
469
- // repeat the column header down every group.
470
- showGroupColumnLabel: false,
471
- }
488
+ ? { groupable: true, groupKey: WORK_CENTER_LEVEL_GROUP_FIELD }
472
489
  : {};
473
490
  }
474
491
  function buildColumns(columnsConfig) {
@@ -564,15 +581,6 @@ function buildKpis(stats, fallbackIcon) {
564
581
  color: stat.color?.trim() || KPI_COLORS[index % KPI_COLORS.length],
565
582
  }));
566
583
  }
567
- /**
568
- * Level Name grouping is the default view of the personal work areas — those
569
- * rows come from all over the hierarchy, so "which project is this?" is the
570
- * first question a user has. Workspace is already scoped to one record, so
571
- * grouping it by that record would produce a single group.
572
- */
573
- function defaultGroupBy(area) {
574
- return area === 'Workspace' ? null : WORK_CENTER_LEVEL_NAME_KEY;
575
- }
576
584
  /** The backend sort that renders a grouped column as contiguous rows. */
577
585
  function sortForGroup(groupBy) {
578
586
  return groupBy ? [{ field: groupBy, dir: 'asc' }] : [];
@@ -585,7 +593,7 @@ function createDefaultContext(area) {
585
593
  selectedCardKey: null,
586
594
  page: 1,
587
595
  pageSize: WORK_CENTER_LOCAL_FETCH_SIZE,
588
- sort: sortForGroup(defaultGroupBy(area)),
596
+ sort: [],
589
597
  runtimeFilters: [],
590
598
  includeStats: true,
591
599
  };
@@ -595,7 +603,7 @@ function createDefaultAreaState(area) {
595
603
  context: createDefaultContext(area),
596
604
  headerFilters: [],
597
605
  columnFilters: [],
598
- groupBy: defaultGroupBy(area),
606
+ groupBy: null,
599
607
  menuItems: [],
600
608
  rows: [],
601
609
  columns: [],
@@ -844,10 +852,19 @@ let WorkCenterState = class WorkCenterState {
844
852
  setParams(ctx, action) {
845
853
  const state = ctx.getState();
846
854
  const current = state.byArea[action.area];
855
+ // A card switch invalidates everything scoped to the previous card. The
856
+ // host usually drops those query params too, but a stale URL must not be
857
+ // able to re-apply a filter on a field the new card doesn't have.
858
+ const cardChanged = resolveSelectedCardKeyFromInputs(current.context, action.inputs) !==
859
+ current.context.selectedCardKey;
847
860
  // Resolve grouping first: with no explicit `sort` input it is what defines
848
- // the backend sort, so the default grouping reaches the first request.
849
- const nextGroupBy = resolveGroupByFromInputs(current.groupBy, action.inputs?.group);
850
- const nextContext = buildContextFromInputs(current.context, action.area, action.inputs, nextGroupBy);
861
+ // the backend sort.
862
+ const nextGroupBy = resolveGroupByFromInputs(cardChanged ? null : current.groupBy, action.inputs?.group);
863
+ const builtContext = buildContextFromInputs(current.context, action.area, action.inputs, nextGroupBy);
864
+ const filtersFromInputs = action.inputs?.filters !== undefined;
865
+ const nextContext = cardChanged && !filtersFromInputs
866
+ ? { ...builtContext, runtimeFilters: [] }
867
+ : builtContext;
851
868
  const areaChanged = state.activeArea !== action.area;
852
869
  const contextChanged = !isSameContext(current.context, nextContext);
853
870
  const groupChanged = nextGroupBy !== current.groupBy;
@@ -857,11 +874,12 @@ let WorkCenterState = class WorkCenterState {
857
874
  // URL-derived filters land on the header slice. Anything previously
858
875
  // applied via the in-table column filters is dropped so the BE payload
859
876
  // matches what the user sees on the page header.
860
- const filtersFromInputs = action.inputs?.filters !== undefined;
861
877
  const nextHeaderFilters = filtersFromInputs
862
878
  ? nextContext.runtimeFilters
863
- : current.headerFilters;
864
- const nextColumnFilters = filtersFromInputs ? [] : current.columnFilters;
879
+ : cardChanged
880
+ ? []
881
+ : current.headerFilters;
882
+ const nextColumnFilters = filtersFromInputs || cardChanged ? [] : current.columnFilters;
865
883
  ctx.patchState({
866
884
  activeArea: action.area,
867
885
  byArea: {
@@ -898,6 +916,33 @@ let WorkCenterState = class WorkCenterState {
898
916
  columnFilters: action.filters,
899
917
  });
900
918
  }
919
+ selectCard(ctx, action) {
920
+ const state = ctx.getState();
921
+ const current = state.byArea[action.area];
922
+ if (current.context.selectedCardKey === action.selectedCardKey) {
923
+ return;
924
+ }
925
+ ctx.patchState({
926
+ activeArea: action.area,
927
+ byArea: {
928
+ ...state.byArea,
929
+ [action.area]: {
930
+ ...current,
931
+ headerFilters: [],
932
+ columnFilters: [],
933
+ groupBy: null,
934
+ context: {
935
+ ...current.context,
936
+ selectedCardKey: action.selectedCardKey,
937
+ runtimeFilters: [],
938
+ sort: [],
939
+ page: 1,
940
+ },
941
+ },
942
+ },
943
+ });
944
+ return ctx.dispatch(new LoadRuntime(action.area, 'menu-change'));
945
+ }
901
946
  /**
902
947
  * Grouping is a backend concern: the table only renders contiguous rows, so
903
948
  * the grouped column is pushed down as the single `context.sort` entry and
@@ -1036,6 +1081,9 @@ __decorate([
1036
1081
  __decorate([
1037
1082
  Action(ApplyColumnFilters)
1038
1083
  ], WorkCenterState.prototype, "applyColumnFilters", null);
1084
+ __decorate([
1085
+ Action(SelectCard)
1086
+ ], WorkCenterState.prototype, "selectCard", null);
1039
1087
  __decorate([
1040
1088
  Action(SetGroupBy)
1041
1089
  ], WorkCenterState.prototype, "setGroupBy", null);
@@ -1104,7 +1152,7 @@ WorkCenterState = __decorate([
1104
1152
  ], WorkCenterState);
1105
1153
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterState, decorators: [{
1106
1154
  type: Injectable
1107
- }], propDecorators: { enterArea: [], hydrateFromContext: [], setParams: [], setLookups: [], applyHeaderFilters: [], applyColumnFilters: [], setGroupBy: [], clearAllFilters: [], loadRuntime: [] } });
1155
+ }], propDecorators: { enterArea: [], hydrateFromContext: [], setParams: [], setLookups: [], applyHeaderFilters: [], applyColumnFilters: [], selectCard: [], setGroupBy: [], clearAllFilters: [], loadRuntime: [] } });
1108
1156
 
1109
1157
  class WorkCenterFacade {
1110
1158
  store = inject(Store);
@@ -1148,11 +1196,12 @@ class WorkCenterFacade {
1148
1196
  setLookups(lookups) {
1149
1197
  return this.store.dispatch(new SetLookups(lookups));
1150
1198
  }
1199
+ /**
1200
+ * Switches card and drops the previous card's filters, grouping and sort —
1201
+ * each card has its own columns and filter schema.
1202
+ */
1151
1203
  selectCardAndLoad(area, selectedCardKey) {
1152
- return this.store.dispatch([
1153
- new HydrateFromContext(area, { selectedCardKey, page: 1 }),
1154
- new LoadRuntime(area, 'menu-change'),
1155
- ]);
1204
+ return this.store.dispatch(new SelectCard(area, selectedCardKey));
1156
1205
  }
1157
1206
  applyTableLazyLoadAndLoad(area, event) {
1158
1207
  const context = this.store.selectSnapshot(WorkCenterState.context);
@@ -1432,6 +1481,15 @@ class WorkCenterEscalationInstanceType {
1432
1481
  : isFinal
1433
1482
  ? this.transloco.translate('workCenter.preview.final')
1434
1483
  : null,
1484
+ // Semantic color for the badge — every step state renders with the
1485
+ // same pill and is told apart by color alone.
1486
+ badgeTone: isClosed
1487
+ ? 'closed'
1488
+ : isInitial
1489
+ ? 'initial'
1490
+ : isFinal
1491
+ ? 'final'
1492
+ : 'accent',
1435
1493
  style: 'detail',
1436
1494
  current: currentIds.has(String(step.id)),
1437
1495
  };
@@ -1444,6 +1502,7 @@ class WorkCenterEscalationInstanceType {
1444
1502
  color: 'color',
1445
1503
  subtitle: 'subtitle',
1446
1504
  badge: 'badge',
1505
+ badgeTone: 'badgeTone',
1447
1506
  status: 'status',
1448
1507
  style: 'style',
1449
1508
  current: 'current',
@@ -1820,6 +1879,9 @@ class WorkCenterProcessPreview {
1820
1879
  : isFinal
1821
1880
  ? this.transloco.translate('workCenter.preview.final')
1822
1881
  : null,
1882
+ // Semantic color for the badge — every step state renders with the
1883
+ // same pill and is told apart by color alone.
1884
+ badgeTone: step.isInitial ? 'initial' : isFinal ? 'final' : 'accent',
1823
1885
  status: step.status ?? null,
1824
1886
  style: isAppAction || isApprovalCommit ? 'icon' : 'detail',
1825
1887
  current: currentStepIds.has(String(step.id)),
@@ -1840,6 +1902,7 @@ class WorkCenterProcessPreview {
1840
1902
  color: 'color',
1841
1903
  subtitle: 'subtitle',
1842
1904
  badge: 'badge',
1905
+ badgeTone: 'badgeTone',
1843
1906
  status: 'status',
1844
1907
  style: 'style',
1845
1908
  current: 'current',
@@ -3074,8 +3137,13 @@ class WorkCenterPage {
3074
3137
  if (item.key === this.context().selectedCardKey) {
3075
3138
  return;
3076
3139
  }
3140
+ // The store drops the previous card's filters and grouping; the table's
3141
+ // own filter chips live here, so they have to be cleared alongside.
3142
+ this.tableFilters.set({});
3077
3143
  this.facade.selectCardAndLoad(this.area(), item.key);
3078
3144
  this.cardSelected.emit(item.key);
3145
+ this.groupChanged.emit(null);
3146
+ this.sortChanged.emit([]);
3079
3147
  }
3080
3148
  onRuntimeFiltersApplied(filters) {
3081
3149
  const mappedFilters = filters.map((filter) => ({
@@ -3251,5 +3319,5 @@ const APP_STATES = [WorkCenterState];
3251
3319
  * Generated bundle index. Do not edit.
3252
3320
  */
3253
3321
 
3254
- 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 };
3322
+ 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 };
3255
3323
  //# sourceMappingURL=masterteam-work-center.mjs.map