@ieeesa-npm/groups 0.15.26 → 0.15.28

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.
@@ -272,7 +272,17 @@ export declare class TreeViewComponent implements OnInit, AfterViewInit, OnDestr
272
272
  */
273
273
  handleGroupActions(group: GroupNode): void;
274
274
  /**
275
- * Returns the filtered menu items based on groups hasChildren.
275
+ * Returns the group action menu items the current user may see for the given
276
+ * group, filtered by per-group permissions and group type. The "Manage
277
+ * Interest Form" action (SP3M-380) is gated: it renders only when the
278
+ * interest-form feature is enabled for the tenant
279
+ * (GroupsService.isInterestFormFeatureEnabled()) AND either the user holds the
280
+ * VIEW_AND_MANAGE_GROUP_INTEREST permission for that specific group (strictly
281
+ * per-group, no global fallback) OR the user is a cross-group admin holding
282
+ * MANAGE_ALL_GROUPS ("Manage All Group Details"). It is always hidden on
283
+ * admin/system group types (e.g. the System Users Group), which are not real
284
+ * committees with an interest form, and hidden entirely when the feature is
285
+ * disabled. When shown it is kept leftmost by the trailing sort.
276
286
  * @param {GroupNode} group
277
287
  * @return {Menu[]}
278
288
  * @memberof TreeViewComponent
@@ -16,6 +16,7 @@ import { GroupPermission, UserPermission } from './models/group-permissions.mode
16
16
  import { PermissionType } from './models/permission-type.model';
17
17
  import { GroupPermissionsMapService } from './services/group-permissions-map-service';
18
18
  import { LoggedInUserInfo } from './models/user.model';
19
+ import { TenantFeature } from './models/tenant-feature.model';
19
20
  import * as i0 from "@angular/core";
20
21
  /**
21
22
  * Groups component is a wrapper or container component for groups management reusable component and in this component integrates all group management functionalities and this will be entry component for managing groups when it is consumed in other applications.
@@ -76,6 +77,19 @@ export declare class GroupsComponent implements OnInit, OnDestroy {
76
77
  */
77
78
  set requiredProfileFields(value: string[] | null | undefined);
78
79
  get requiredProfileFields(): string[];
80
+ private _tenantFeatures;
81
+ /**
82
+ * Tenant feature flags supplied by the host app from its cached tenant
83
+ * configuration. Passed to GroupsService so interest-form UI (e.g. the
84
+ * "Manage Interest Form" tree action) is gated on whether the feature is
85
+ * enabled for the tenant. Optional — defaults to none (fail-closed).
86
+ *
87
+ * Implemented as a setter so EVERY input update (including a late,
88
+ * async-resolved value that arrives after ngOnInit) is propagated to the
89
+ * singleton GroupsService — not just the initial binding.
90
+ */
91
+ set tenantFeatures(value: TenantFeature[] | null | undefined);
92
+ get tenantFeatures(): TenantFeature[];
79
93
  permissionType: typeof PermissionType;
80
94
  functionType: GroupFunctionType;
81
95
  alignmentType: typeof AlignType;
@@ -256,5 +270,5 @@ export declare class GroupsComponent implements OnInit, OnDestroy {
256
270
  */
257
271
  ngOnDestroy(): void;
258
272
  static ɵfac: i0.ɵɵFactoryDeclaration<GroupsComponent, never>;
259
- static ɵcmp: i0.ɵɵComponentDeclaration<GroupsComponent, "ieeesa-groups", never, { "groupsPageInfo": { "alias": "groupsPageInfo"; "required": false; }; "applicationId": { "alias": "applicationId"; "required": false; }; "apiBaseURL": { "alias": "apiBaseURL"; "required": false; }; "userPermissions": { "alias": "userPermissions"; "required": false; }; "userInfo": { "alias": "userInfo"; "required": false; }; "requiredProfileFields": { "alias": "requiredProfileFields"; "required": false; }; }, {}, never, never, true, never>;
273
+ static ɵcmp: i0.ɵɵComponentDeclaration<GroupsComponent, "ieeesa-groups", never, { "groupsPageInfo": { "alias": "groupsPageInfo"; "required": false; }; "applicationId": { "alias": "applicationId"; "required": false; }; "apiBaseURL": { "alias": "apiBaseURL"; "required": false; }; "userPermissions": { "alias": "userPermissions"; "required": false; }; "userInfo": { "alias": "userInfo"; "required": false; }; "requiredProfileFields": { "alias": "requiredProfileFields"; "required": false; }; "tenantFeatures": { "alias": "tenantFeatures"; "required": false; }; }, {}, never, never, true, never>;
260
274
  }
@@ -0,0 +1,3 @@
1
+ export declare enum FeatureFlag {
2
+ INTEREST_FORM = "FEATURE_INTEREST_FORM"
3
+ }
@@ -13,6 +13,6 @@ export declare enum PermissionType {
13
13
  MANAGE_ALL_GROUPS = "MANAGE_ALL_GROUPS",
14
14
  VIEW_ALL_ROSTERS = "VIEW_ALL_ROSTERS",
15
15
  MANAGE_ALL_ROSTERS = "MANAGE_ALL_ROSTERS",
16
- MANAGE_CUSTOM_INTEREST_QUESTIONS = "MANAGE_CUSTOM_INTEREST_QUESTIONS",
16
+ VIEW_AND_MANAGE_GROUP_INTEREST = "VIEW_AND_MANAGE_GROUP_INTEREST",
17
17
  RESTRICT_GROUPS_AND_ROSTERS = "RESTRICT_GROUPS_AND_ROSTERS"
18
18
  }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Tenant feature flag as surfaced by the host application. Mirrors the host's
3
+ * `TenantFeature` shape (shared.state.ts); the groups reusable library cannot
4
+ * import the host state, so the shape is duplicated locally.
5
+ */
6
+ export interface TenantFeature {
7
+ featureId: string;
8
+ featureName?: string;
9
+ isDeleted?: boolean;
10
+ /**
11
+ * The application (tenant) this feature flag belongs to. Present in the
12
+ * host's cached payload; used to scope the origin-wide TENANT_FEATURES cache
13
+ * to the active application so another app's flags cannot bleed through.
14
+ */
15
+ appId?: string;
16
+ }
@@ -22,6 +22,7 @@ import { CheckboxOption, SelectOption } from '@ieeesa-npm/models';
22
22
  import { FormControlStatus } from '@angular/forms';
23
23
  import { GroupPermission, UserPermission } from '../models/group-permissions.model';
24
24
  import { PermissionType } from '../models/permission-type.model';
25
+ import { TenantFeature } from '../models/tenant-feature.model';
25
26
  import { UserPermissionsService } from './user-permissions.service';
26
27
  import { GroupPermissionsMapService } from './group-permissions-map-service';
27
28
  import { ParentGroupsInfo } from '../models/parent-groups-info.model';
@@ -116,6 +117,12 @@ export declare class GroupsService {
116
117
  * list and the sample file. Empty when the tenant has none configured.
117
118
  */
118
119
  requiredProfileFields: string[];
120
+ /**
121
+ * Tenant feature flags supplied by the host app. Used by
122
+ * {@link isInterestFormFeatureEnabled} to gate interest-form UI. Empty when
123
+ * the host has not provided any features (fail-closed).
124
+ */
125
+ tenantFeatures: TenantFeature[];
119
126
  selectedGroupInfo: GroupInfo | undefined;
120
127
  groupFunctionType: GroupFunctionType;
121
128
  selectedGroupParentInfo: GroupInfo | undefined;
@@ -138,6 +145,33 @@ export declare class GroupsService {
138
145
  * @memberof GroupsService
139
146
  */
140
147
  setRequiredProfileFields(requiredProfileFields: string[]): void;
148
+ /**
149
+ * Stores the tenant feature flags provided by the host app. Consumed by
150
+ * {@link isInterestFormFeatureEnabled} to gate interest-form UI.
151
+ * @param {TenantFeature[]} tenantFeatures - Tenant feature flags.
152
+ * @memberof GroupsService
153
+ */
154
+ setTenantFeatures(tenantFeatures: TenantFeature[]): void;
155
+ /**
156
+ * Returns the tenant feature flags (never null).
157
+ *
158
+ * Reads the local storage cache the hosting application writes at login (key
159
+ * `TENANT_FEATURES`, a bare `TenantFeature[]`) as the source of truth, so the
160
+ * interest-form gate reflects the tenant configuration regardless of the
161
+ * @Input/resolver timing.
162
+ *
163
+ * The cache is only trusted when it is well-formed for the active
164
+ * application: it must be an array and its entries must belong to the current
165
+ * user's `appId`. The `TENANT_FEATURES` key is origin-wide, so a cache written
166
+ * by another application on the same origin could otherwise flip the
167
+ * interest-form gate with a different tenant's flags. When the cache is
168
+ * missing, malformed, or scoped to another app, it falls back to the in-memory
169
+ * value set via {@link setTenantFeatures} (the host @Input), then to an empty
170
+ * list.
171
+ * @return {TenantFeature[]}
172
+ * @memberof GroupsService
173
+ */
174
+ getTenantFeatures(): TenantFeature[];
141
175
  /**
142
176
  * Returns the tenant-level required profile fields (never null).
143
177
  *
@@ -424,6 +458,17 @@ export declare class GroupsService {
424
458
  * @memberof GroupsService
425
459
  */
426
460
  validateAccess(permissionType: PermissionType, permissions?: UserPermission[] | null): boolean;
461
+ /**
462
+ * SP3M-380: Returns true when the interest-form feature
463
+ * (`FEATURE_INTEREST_FORM`) is enabled for the current tenant. A single
464
+ * boolean capability check the UI gates on. Reads the tenant features from
465
+ * {@link getTenantFeatures} (local storage cache first, then the host
466
+ * @Input). Fail-closed: an empty/undefined feature list, or a feature marked
467
+ * deleted, yields false.
468
+ * @return {boolean}
469
+ * @memberof GroupsService
470
+ */
471
+ isInterestFormFeatureEnabled(): boolean;
427
472
  /**
428
473
  * Store the loaded group types.
429
474
  * @param {GroupTypeConfiguration[]} groupTypes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ieeesa-npm/groups",
3
- "version": "0.15.26",
3
+ "version": "0.15.28",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^16.1.0",
6
6
  "@angular/core": "^16.1.0"
package/public-api.d.ts CHANGED
@@ -34,6 +34,7 @@ export * from './lib/models/table-column-schema-user-group.model';
34
34
  export * from './lib/models/parent-groups-info.model';
35
35
  export * from './lib/models/reciprocal-credit.model';
36
36
  export * from './lib/models/required-profile-fields.model';
37
+ export * from './lib/models/tenant-feature.model';
37
38
  export * from './lib/services/groups.service';
38
39
  export * from './lib/services/roster-export.service';
39
40
  export * from './lib/services/roster-import-api.service';