@acorex-platform/framework-client 0.0.58 → 0.0.60

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.
Files changed (40) hide show
  1. package/fesm2022/acorex-platform-framework-client-auth.mjs +397 -93
  2. package/fesm2022/acorex-platform-framework-client-auth.mjs.map +1 -1
  3. package/fesm2022/acorex-platform-framework-client-common.mjs +33 -31
  4. package/fesm2022/acorex-platform-framework-client-common.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-framework-client-layout-components.mjs +12 -4
  6. package/fesm2022/acorex-platform-framework-client-layout-components.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-framework-client-layout-designer.mjs +2 -2
  8. package/fesm2022/acorex-platform-framework-client-layout-designer.mjs.map +1 -1
  9. package/fesm2022/{acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-jeOx-Rb8.mjs → acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-D0jDsA6M.mjs} +185 -30
  10. package/fesm2022/acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-D0jDsA6M.mjs.map +1 -0
  11. package/fesm2022/{acorex-platform-framework-client-layout-entity-attachments-page.component-B93uWhea.mjs → acorex-platform-framework-client-layout-entity-attachments-page.component-Bdvd1iYt.mjs} +2 -2
  12. package/fesm2022/{acorex-platform-framework-client-layout-entity-attachments-page.component-B93uWhea.mjs.map → acorex-platform-framework-client-layout-entity-attachments-page.component-Bdvd1iYt.mjs.map} +1 -1
  13. package/fesm2022/{acorex-platform-framework-client-layout-entity-bulk-entity.command-DITHE0f6.mjs → acorex-platform-framework-client-layout-entity-bulk-entity.command-CsTP8YHv.mjs} +2 -2
  14. package/fesm2022/{acorex-platform-framework-client-layout-entity-bulk-entity.command-DITHE0f6.mjs.map → acorex-platform-framework-client-layout-entity-bulk-entity.command-CsTP8YHv.mjs.map} +1 -1
  15. package/fesm2022/{acorex-platform-framework-client-layout-entity-gallery-page.component-f5rLdctT.mjs → acorex-platform-framework-client-layout-entity-gallery-page.component-UvMk0GbU.mjs} +2 -2
  16. package/fesm2022/{acorex-platform-framework-client-layout-entity-gallery-page.component-f5rLdctT.mjs.map → acorex-platform-framework-client-layout-entity-gallery-page.component-UvMk0GbU.mjs.map} +1 -1
  17. package/fesm2022/acorex-platform-framework-client-layout-entity.mjs +1 -1
  18. package/fesm2022/acorex-platform-framework-client-layout-widget-core.mjs +165 -28
  19. package/fesm2022/acorex-platform-framework-client-layout-widget-core.mjs.map +1 -1
  20. package/fesm2022/{acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-D9WiRo-_.mjs → acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-KrDsAa3H.mjs} +555 -121
  21. package/fesm2022/acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-KrDsAa3H.mjs.map +1 -0
  22. package/fesm2022/{acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-kwbJdTwe.mjs → acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-BDlo6nTx.mjs} +2 -2
  23. package/fesm2022/{acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-kwbJdTwe.mjs.map → acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-BDlo6nTx.mjs.map} +1 -1
  24. package/fesm2022/{acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-Bke-Wy-4.mjs → acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-By3wntCB.mjs} +2 -2
  25. package/fesm2022/{acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-Bke-Wy-4.mjs.map → acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-By3wntCB.mjs.map} +1 -1
  26. package/fesm2022/acorex-platform-framework-client-layout-widgets.mjs +1 -1
  27. package/fesm2022/acorex-platform-framework-client-themes-default.mjs +5 -5
  28. package/fesm2022/acorex-platform-framework-client-themes-default.mjs.map +1 -1
  29. package/layout/builder/README.md +10 -0
  30. package/layout/widget-core/README.md +47 -3
  31. package/layout/widgets/README.md +8 -2
  32. package/package.json +2 -2
  33. package/types/acorex-platform-framework-client-auth.d.ts +60 -1
  34. package/types/acorex-platform-framework-client-common.d.ts +3 -2
  35. package/types/acorex-platform-framework-client-layout-components.d.ts +3 -1
  36. package/types/acorex-platform-framework-client-layout-entity.d.ts +25 -1
  37. package/types/acorex-platform-framework-client-layout-widget-core.d.ts +39 -0
  38. package/types/acorex-platform-framework-client-layout-widgets.d.ts +25 -5
  39. package/fesm2022/acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-jeOx-Rb8.mjs.map +0 -1
  40. package/fesm2022/acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-D9WiRo-_.mjs.map +0 -1
@@ -1220,6 +1220,16 @@ export class SignatureComponent {
1220
1220
 
1221
1221
  ---
1222
1222
 
1223
+ ## Repeater widgets (row isolation)
1224
+
1225
+ Sibling rows share leaf names (`applicationId`, `roleIds`). Do not bind triggers to `events.context('*applicationId')` or a bare `applicationId` — that clears **every** row.
1226
+
1227
+ - This row only: `events.context('>field')`.
1228
+ - Duplicate keys: merge on submit (union), not unique dropdowns with `filter` `not-in`.
1229
+ - Details: `libs/framework/client/layout/widget-core/README.md`.
1230
+
1231
+ ---
1232
+
1223
1233
  ## Best Practices
1224
1234
 
1225
1235
  ### 1. Use Descriptive Names
@@ -1,4 +1,48 @@
1
- # @acorex-platform/framework-client/layout
1
+ # Widget renderer — repeater context isolation
2
2
 
3
- Secondary entry point of `@acorex-platform/framework-client/platform`. It can be used by importing from `@acorex-platform/framework-client/layout`.
4
-
3
+ Package: `@acorex-platform/framework-client/layout/widget-core`.
4
+
5
+ Renderer: `src/lib/widget-renderer.directive.ts`.
6
+
7
+ Do not “simplify” path matching so that two repeater rows share the same leaf field name. That regression already shipped twice on TM Tenant Users Invite (`applicationRoleRows`).
8
+
9
+ ## What went wrong
10
+
11
+ Indexed store paths look like:
12
+
13
+ - `applicationRoleRows[0].applicationId`
14
+ - `applicationRoleRows[1].applicationId`
15
+
16
+ Last-segment matching (`applicationId`) treats those as the same change. Effects:
17
+
18
+ - `events.context('>applicationId')` + `widget.setValue([])` on Roles runs on **every** row.
19
+ - `events.context('*applicationId')` does the same by design — never use `*` for row-local reset.
20
+
21
+ Unresolved `>` (empty `parentPath`) becomes the bare field `applicationId`. That must **not** suffix-match every `*.applicationId`.
22
+
23
+ ## Required matching rules
24
+
25
+ | Listener | Match |
26
+ |----------|--------|
27
+ | `events.context('>field')` | Exact resolved path for **this** widget row only |
28
+ | `events.context('rows')` | The array and every `rows[n]…` child (list-wide refresh) |
29
+ | Different `rows[i]` vs `rows[j]` | **Never** match via shared suffix |
30
+
31
+ `repeaterRowIndexConflicts` must stay in front of suffix matching in `contextStorePathDependsOnChangedPath`. `getEventScope` / `hasTriggerDependency` must keep the exact-match branch for `>` — do not OR `>` with suffix matching.
32
+
33
+ ## Duplicate keys in a repeater
34
+
35
+ Prefer **merge on submit** (union of child values for the same key). TM Tenant Users Invite does this via `normalizeInviteApplicationRoleAssignments` — the same application may appear on two rows; persist one grant with all picked roles.
36
+
37
+ Do **not** unique the dropdown with widget `filter` `not-in` / `nin`. Empty `not-in` is treated as a pending cascade and disables the select (empty list + not-allowed cursor). If a different screen truly needs unique options, use `excludeIds` (keep the current widget value in `excludeOptionRows`), never `not-in`.
38
+
39
+ ## Layout recipe — row-local Roles reset
40
+
41
+ ```typescript
42
+ triggers: [{
43
+ event: "{{ events.context('>applicationId') }}",
44
+ action: '{{ widget.setValue([]); widget.refresh(); }}',
45
+ }]
46
+ ```
47
+
48
+ Reference: `libs/modules/security-management/client/src/lib/commands/invite-user.command.ts` (`buildApplicationRoleRepeaterChildren`).
@@ -1,3 +1,9 @@
1
- # @acorex-platform/framework-client/layout/widgets
1
+ # Layout widgets
2
2
 
3
- Secondary entry point of `@acorex-platform/framework-client/platform`. It can be used by importing from `@acorex-platform/framework-client/layout/widgets`.
3
+ Package: `@acorex-platform/framework-client/layout/widgets`.
4
+
5
+ Select / combo (`select-box-widget-edit.component.ts`):
6
+
7
+ - Cascade parent empty → `hasPendingCascadeFilter` disables the control. Operators `not-in` / `nin` are **not** cascade.
8
+ - Repeater duplicate keys: merge on submit (see TM invite `normalizeInviteApplicationRoleAssignments`). Do not unique options with `filter` `not-in`.
9
+ - Repeater path matching: `libs/framework/client/layout/widget-core/README.md`.
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@acorex-platform/framework-client",
3
- "version": "0.0.58",
3
+ "version": "0.0.60",
4
4
  "peerDependencies": {
5
- "@acorex-platform/framework-shared": "0.0.58",
5
+ "@acorex-platform/framework-shared": "0.0.60",
6
6
  "@acorex/cdk": "^21.0.0 || ^22.0.0 || ^22.0.0-next.0 || ^22.1.0-next.0 || ^22.2.0-next.0 || ^22.2.0-next.0",
7
7
  "@acorex/charts": "^21.0.0 || ^22.0.0 || ^22.0.0-next.0 || ^22.1.0-next.0 || ^22.2.0-next.0 || ^22.2.0-next.0",
8
8
  "@acorex/components": "^21.0.0 || ^22.0.0 || ^22.0.0-next.0 || ^22.1.0-next.0 || ^22.2.0-next.0 || ^22.2.0-next.0",
@@ -351,7 +351,13 @@ declare class AXPSessionService {
351
351
  /** In-memory catalog caches — shared by guards and chooser UI (one List* per bind). */
352
352
  private tenantsListCache;
353
353
  private applicationsListCache;
354
+ /** Bumps when catalogs must re-fetch (e.g. after tenant-request approve). */
355
+ private readonly catalogEpoch$;
354
356
  private signoutInFlight;
357
+ /** Coalesces soft-restore → Authorized promotion after connectivity recovers. */
358
+ private accessPolicyRetryInFlight;
359
+ private softRestoreOnlineRecoveryAttached;
360
+ private softRestoreOnlineRecoveryHandler;
355
361
  private status;
356
362
  readonly status$: Observable<AXPSessionStatus>;
357
363
  private isLoading;
@@ -391,6 +397,28 @@ declare class AXPSessionService {
391
397
  /** Waits for session restore to finish, then emits whether the session is fully authorized. */
392
398
  readonly isAuthorizedWithLoading$: Observable<boolean>;
393
399
  restoreSession(): Promise<void>;
400
+ /**
401
+ * Trust persisted AXP_SESSION after a non-definitive restore refresh failure.
402
+ * Keeps identity; promotes to Authorized only when access policy load succeeds.
403
+ */
404
+ private softRestoreFromStoredSession;
405
+ /**
406
+ * Soft-restore policy load: success = both loaders completed without throw
407
+ * (empty permission/feature lists still count as a successful load).
408
+ */
409
+ private tryLoadAccessPolicyForSoftRestore;
410
+ /**
411
+ * Retries access-policy load after a soft restore that stayed Authenticated.
412
+ * On success with complete workspace, promotes to Authorized (no logout on failure).
413
+ * Coalesces concurrent callers (refresh / online / successful API).
414
+ */
415
+ retryAccessPolicyAuthorization(): Promise<boolean>;
416
+ /**
417
+ * Bounded recovery after soft-restore Authenticated: browser `online` once per arm.
418
+ * Successful token refresh also retries (see {@link refreshToken}).
419
+ */
420
+ private armSoftRestorePolicyRecovery;
421
+ private disarmSoftRestorePolicyRecovery;
394
422
  signin(credentials: AXPBaseCredentials): Promise<void>;
395
423
  register(credentials: AXPBaseCredentials): Promise<void>;
396
424
  private applySignInResult;
@@ -428,6 +456,11 @@ declare class AXPSessionService {
428
456
  /** Shared ListApplications — used by guards and {@link applications$}. */
429
457
  getApplicationsList(): Promise<AXPApplication[]>;
430
458
  private clearCatalogCaches;
459
+ /**
460
+ * Drops ListTenants / ListApplications caches and re-emits {@link tenants$}.
461
+ * Call after membership/tenant availability changes (e.g. approve tenant request).
462
+ */
463
+ invalidateCatalogCaches(): void;
431
464
  signInComplete(): Promise<void>;
432
465
  /** Tenant + application must be bound before menu, permissions, and features are fully valid. */
433
466
  private hasCompleteSessionContext;
@@ -715,6 +748,32 @@ declare function storeSessionLimitPendingTenant(tenant: AXPSessionLimitPendingTe
715
748
  declare function readSessionLimitPendingTenant(): AXPSessionLimitPendingTenant | null;
716
749
  declare function clearSessionLimitPendingTenant(): void;
717
750
 
751
+ /**
752
+ * Stable server codes for definitive refresh/session death (prefer over message text).
753
+ * Keep in sync with `AUTH_REFRESH_ERROR_CODES` / `SESSION_MEMBERSHIP_DENIED` on the server.
754
+ */
755
+ declare const DEFINITIVE_AUTH_REFRESH_CODES: readonly ["REFRESH_MISSING", "REFRESH_EXPIRED", "REFRESH_REVOKED", "REFRESH_REUSE", "SESSION_REVOKED", "USER_NOT_FOUND", "SESSION_MEMBERSHIP_DENIED"];
756
+ /**
757
+ * True only when refresh failed because the refresh cookie / session family is dead.
758
+ * Network / 5xx / Redis unavailable / empty transient results → false.
759
+ */
760
+ declare function isDefinitiveAuthRefreshFailure(error: unknown): boolean;
761
+
762
+ /**
763
+ * After soft restore: keep identity without promoting to Authorized when
764
+ * access policy could not be loaded (transient API/refresh failure).
765
+ */
766
+ declare function resolveStatusAfterSoftRestore(options: {
767
+ hasUser: boolean;
768
+ hasCompleteWorkspace: boolean;
769
+ policyLoadSucceeded: boolean;
770
+ }): AXPSessionStatus;
771
+ /**
772
+ * Soft-restore left the session Authenticated (policy unavailable).
773
+ * Retry access-policy load after connectivity / successful token refresh recovers.
774
+ */
775
+ declare function shouldRetryAccessPolicyAuthorization(status: AXPSessionStatus): boolean;
776
+
718
777
  /**
719
778
  * Best-effort plain string for thrown {@link Error} messages from command results (no i18n lookup).
720
779
  */
@@ -1059,5 +1118,5 @@ declare class AXPSignInMethodRegistry {
1059
1118
  static ɵprov: i0.ɵɵInjectableDeclaration<AXPSignInMethodRegistry>;
1060
1119
  }
1061
1120
 
1062
- export { AUTH_SESSION_TRACE_NS, AUTH_SESSION_TRACE_TITLE, AXPAuthGuard, AXPAuthModule, AXPAuthStrategy, AXPAuthStrategyRegistryService, AXPFeatureDirective, AXPFeatureEvaluatorScopeProvider, AXPFeatureGuard, AXPLoginChallengeComponentBase, AXPLoginChallengeProvider, AXPPermissionDefinitionBuilder, AXPPermissionDefinitionGroupBuilder, AXPPermissionDefinitionProviderContext, AXPPermissionDefinitionService, AXPPermissionDirective, AXPPermissionEvaluatorScopeProvider, AXPPermissionGuard, AXPPlatformAuthRuntimeService, AXPSessionContext, AXPSessionService, AXPSessionStatus, AXPSignInMethod, AXPSignInMethodRegistry, AXPUnauthenticatedError, AXPUnauthorizedError, AXPUserProfileIdentityService, AXP_ACCESS_POLICY_CACHE_PORT, AXP_APPLICATION_LOADER, AXP_DEFAULT_PLATFORM_OAUTH_CLIENT_ID, AXP_DEFAULT_PLATFORM_OAUTH_SCOPE, AXP_FEATURE_CHECKER, AXP_FEATURE_LOADER, AXP_LOGIN_CHALLENGE_PROVIDER, AXP_OAUTH_PKCE_VERIFIER_KEY, AXP_PERMISSION_CHECKER, AXP_PERMISSION_DEFINITION_PROVIDER, AXP_PERMISSION_LOADER, AXP_PERMISSION_MODULES_RESOLVER, AXP_PLATFORM_OAUTH_CSRF_COOKIE, AXP_TENANT_LOADER, AXP_USER_AVATAR_CACHE_PORT, JwtUtil, MAX_ACTIVE_DEVICE_SESSIONS_CODE, PkceUtil, TimeUtil, asAuthListProvidersResponse, clearOAuthPendingStrategy, clearSessionLimitPendingTenant, commandMessageTextForError, exchangePlatformOAuthAuthorizationCode, fetchPlatformOAuthDiscoveryDocument, findIdentityProvider, getOAuthPendingStrategy, hasLegacyOAuthPkceVerifier, hasOAuthPendingFlow, initPlatformOAuthAuthorization, isMaxActiveDeviceSessionsError, isOAuthRedirectInFlight, platformOAuthSessionUpdateParams, readPlatformOAuthCsrfToken, readSessionLimitPendingTenant, resolvePlatformOAuthAuthorizeEndpoint, resolvePlatformOAuthClientConfig, resolvePlatformOAuthIssuer, resolvePlatformOAuthRedirectUri, resolvePlatformOAuthTokenEndpoint, setOAuthPendingStrategy, shouldPlatformOAuthBindSession, storeSessionLimitPendingTenant, toPlatformOAuthSignInResult, traceAuthAccessPolicy, traceAuthCatalog, traceAuthGuard, traceAuthLifecycle, traceAuthLifecycleError, traceAuthRestore, traceAuthWorkspace, warnAuthAccessPolicy, warnAuthLifecycle, warnAuthWorkspace };
1121
+ export { AUTH_SESSION_TRACE_NS, AUTH_SESSION_TRACE_TITLE, AXPAuthGuard, AXPAuthModule, AXPAuthStrategy, AXPAuthStrategyRegistryService, AXPFeatureDirective, AXPFeatureEvaluatorScopeProvider, AXPFeatureGuard, AXPLoginChallengeComponentBase, AXPLoginChallengeProvider, AXPPermissionDefinitionBuilder, AXPPermissionDefinitionGroupBuilder, AXPPermissionDefinitionProviderContext, AXPPermissionDefinitionService, AXPPermissionDirective, AXPPermissionEvaluatorScopeProvider, AXPPermissionGuard, AXPPlatformAuthRuntimeService, AXPSessionContext, AXPSessionService, AXPSessionStatus, AXPSignInMethod, AXPSignInMethodRegistry, AXPUnauthenticatedError, AXPUnauthorizedError, AXPUserProfileIdentityService, AXP_ACCESS_POLICY_CACHE_PORT, AXP_APPLICATION_LOADER, AXP_DEFAULT_PLATFORM_OAUTH_CLIENT_ID, AXP_DEFAULT_PLATFORM_OAUTH_SCOPE, AXP_FEATURE_CHECKER, AXP_FEATURE_LOADER, AXP_LOGIN_CHALLENGE_PROVIDER, AXP_OAUTH_PKCE_VERIFIER_KEY, AXP_PERMISSION_CHECKER, AXP_PERMISSION_DEFINITION_PROVIDER, AXP_PERMISSION_LOADER, AXP_PERMISSION_MODULES_RESOLVER, AXP_PLATFORM_OAUTH_CSRF_COOKIE, AXP_TENANT_LOADER, AXP_USER_AVATAR_CACHE_PORT, DEFINITIVE_AUTH_REFRESH_CODES, JwtUtil, MAX_ACTIVE_DEVICE_SESSIONS_CODE, PkceUtil, TimeUtil, asAuthListProvidersResponse, clearOAuthPendingStrategy, clearSessionLimitPendingTenant, commandMessageTextForError, exchangePlatformOAuthAuthorizationCode, fetchPlatformOAuthDiscoveryDocument, findIdentityProvider, getOAuthPendingStrategy, hasLegacyOAuthPkceVerifier, hasOAuthPendingFlow, initPlatformOAuthAuthorization, isDefinitiveAuthRefreshFailure, isMaxActiveDeviceSessionsError, isOAuthRedirectInFlight, platformOAuthSessionUpdateParams, readPlatformOAuthCsrfToken, readSessionLimitPendingTenant, resolvePlatformOAuthAuthorizeEndpoint, resolvePlatformOAuthClientConfig, resolvePlatformOAuthIssuer, resolvePlatformOAuthRedirectUri, resolvePlatformOAuthTokenEndpoint, resolveStatusAfterSoftRestore, setOAuthPendingStrategy, shouldPlatformOAuthBindSession, shouldRetryAccessPolicyAuthorization, storeSessionLimitPendingTenant, toPlatformOAuthSignInResult, traceAuthAccessPolicy, traceAuthCatalog, traceAuthGuard, traceAuthLifecycle, traceAuthLifecycleError, traceAuthRestore, traceAuthWorkspace, warnAuthAccessPolicy, warnAuthLifecycle, warnAuthWorkspace };
1063
1122
  export type { AXPAccessPolicyCachePort, AXPApplication, AXPApplicationLoader, AXPAuthIdentityProvider, AXPAuthListProvidersResponse, AXPAuthLocalSignInMethod, AXPAuthModuleConfigs, AXPBaseCredentials, AXPChallengeCheckResult, AXPChallengeContentType, AXPEdition, AXPFeature, AXPFeatureChecker, AXPFeatureLoader, AXPLoginChallengeData, AXPPermission, AXPPermissionAddOptions, AXPPermissionChecker, AXPPermissionDefinition, AXPPermissionDefinitionProvider, AXPPermissionGroupAddOptions, AXPPermissionGroupDefinition, AXPPermissionLoader, AXPPermissionModulesResolver, AXPPlatformOAuthClientConfig, AXPPlatformOAuthDiscoveryDocument, AXPSessionData, AXPSessionLimitPendingTenant, AXPSignInMethodDescriptor, AXPSignInMethodProtocol, AXPSignInMethodStartResult, AXPSignInMethodStep, AXPSignInMethodStepKind, AXPSignInResult, AXPTenant, AXPTenantLoader, AXPTokenResult, AXPUser, AXPUserAvatarCachePort, PlatformAuthOwnDeviceSessionDto, PlatformAuthTokenResponseDto, PlatformAuthUpdateSessionInput };
@@ -820,15 +820,17 @@ declare class AXPKeyboardShortcutsHelpComponent {
820
820
 
821
821
  declare class AXPKeyboardShortcutsHelpService {
822
822
  private readonly popupService;
823
- private readonly dialogOpener;
824
823
  private readonly translationService;
825
824
  private readonly shortcutRegistry;
826
825
  private readonly document;
826
+ /** In-flight help popup session (open until the popup closes). */
827
+ private activeShow;
827
828
  constructor();
828
829
  /**
829
830
  * Opens the keyboard shortcuts help popup, or no-ops when it is already open.
830
831
  */
831
832
  show(): Promise<void>;
833
+ private openHelpPopup;
832
834
  static ɵfac: i0.ɵɵFactoryDeclaration<AXPKeyboardShortcutsHelpService, never>;
833
835
  static ɵprov: i0.ɵɵInjectableDeclaration<AXPKeyboardShortcutsHelpService>;
834
836
  }
@@ -4152,7 +4154,6 @@ declare function downloadGraphicFromElement(container: HTMLElement, options: AXP
4152
4154
 
4153
4155
  declare class AXPExportService {
4154
4156
  popupService: AXPopupService;
4155
- private readonly dialogOpener;
4156
4157
  generateBlobFromElement(element: HTMLElement, blobOptions?: AXPDomToImageOptions): Promise<Blob>;
4157
4158
  download(blob: Blob, filename: string): void;
4158
4159
  static ɵfac: i0.ɵɵFactoryDeclaration<AXPExportService, never>;
@@ -2990,6 +2990,8 @@ declare class AXPRepeaterRowsLayoutComponent {
2990
2990
  disabled: _angular_core.InputSignal<boolean>;
2991
2991
  hasControls: _angular_core.InputSignal<boolean>;
2992
2992
  allowReorder: _angular_core.InputSignal<boolean>;
2993
+ /** Opt-in: put Add next to last-row Remove. Default keeps footer Add Item for other repeaters. */
2994
+ inlineAddControl: _angular_core.InputSignal<boolean>;
2993
2995
  rowTemplate: _angular_core.InputSignal<TemplateRef<{
2994
2996
  index: number;
2995
2997
  }>>;
@@ -3007,7 +3009,7 @@ declare class AXPRepeaterRowsLayoutComponent {
3007
3009
  protected onAddClick(): void;
3008
3010
  protected onRemoveClick(index: number): void;
3009
3011
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXPRepeaterRowsLayoutComponent, never>;
3010
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXPRepeaterRowsLayoutComponent, "axp-repeater-rows-layout", never, { "count": { "alias": "count"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "hasControls": { "alias": "hasControls"; "required": false; "isSignal": true; }; "allowReorder": { "alias": "allowReorder"; "required": false; "isSignal": true; }; "rowTemplate": { "alias": "rowTemplate"; "required": true; "isSignal": true; }; "addItemLabelKey": { "alias": "addItemLabelKey"; "required": false; "isSignal": true; }; "emptyTitleKey": { "alias": "emptyTitleKey"; "required": false; "isSignal": true; }; "emptyDescriptionKey": { "alias": "emptyDescriptionKey"; "required": false; "isSignal": true; }; "addFirstItemLabelKey": { "alias": "addFirstItemLabelKey"; "required": false; "isSignal": true; }; }, { "addClick": "addClick"; "removeClick": "removeClick"; "drop": "drop"; }, never, never, true, never>;
3012
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXPRepeaterRowsLayoutComponent, "axp-repeater-rows-layout", never, { "count": { "alias": "count"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "hasControls": { "alias": "hasControls"; "required": false; "isSignal": true; }; "allowReorder": { "alias": "allowReorder"; "required": false; "isSignal": true; }; "inlineAddControl": { "alias": "inlineAddControl"; "required": false; "isSignal": true; }; "rowTemplate": { "alias": "rowTemplate"; "required": true; "isSignal": true; }; "addItemLabelKey": { "alias": "addItemLabelKey"; "required": false; "isSignal": true; }; "emptyTitleKey": { "alias": "emptyTitleKey"; "required": false; "isSignal": true; }; "emptyDescriptionKey": { "alias": "emptyDescriptionKey"; "required": false; "isSignal": true; }; "addFirstItemLabelKey": { "alias": "addFirstItemLabelKey"; "required": false; "isSignal": true; }; }, { "addClick": "addClick"; "removeClick": "removeClick"; "drop": "drop"; }, never, never, true, never>;
3011
3013
  }
3012
3014
 
3013
3015
  /** Scheduler appointment with optional provider tag for context menu routing. */
@@ -1633,6 +1633,11 @@ declare class AXPEntityMasterListViewModel {
1633
1633
  title: string;
1634
1634
  } | null>;
1635
1635
  parentKey: _angular_core.Signal<string | undefined>;
1636
+ /**
1637
+ * Tree column only while the list is unfiltered roots.
1638
+ * An active filter returns a flat page; keeping parentField would drop child rows and page by the flat total.
1639
+ */
1640
+ gridParentField: _angular_core.Signal<string | undefined>;
1636
1641
  hasSelectedItems: _angular_core.Signal<boolean>;
1637
1642
  clearSelection(): void;
1638
1643
  /**
@@ -1649,6 +1654,7 @@ declare class AXPEntityMasterListViewModel {
1649
1654
  */
1650
1655
  categoryListFilters: _angular_core.WritableSignal<AXPFilterQuery[]>;
1651
1656
  setCategoryListFilters(filters: AXPFilterQuery[]): void;
1657
+ private hasActiveListFilter;
1652
1658
  title: _angular_core.Signal<string>;
1653
1659
  description: _angular_core.Signal<string | null>;
1654
1660
  filterDefinitions: _angular_core.WritableSignal<AXPEntityListFilterDefinition[]>;
@@ -2553,7 +2559,8 @@ interface AXPEntityDeletePerformInput {
2553
2559
  meta?: unknown;
2554
2560
  }
2555
2561
  /**
2556
- * Deletes one or more entity records via the server filter-only bulk command API.
2562
+ * Deletes one or more entity records.
2563
+ * A custom `commands.delete.execute` runs once per id. The crud default stays on the bulk API.
2557
2564
  */
2558
2565
  declare class AXPEntityDeletePerformService {
2559
2566
  private readonly entityRegistry;
@@ -3886,6 +3893,23 @@ declare class AXPEntityListToolbarService {
3886
3893
  * Includes host properties and merge-detail related fields with sort enabled.
3887
3894
  */
3888
3895
  private createSortDefinitions;
3896
+ /**
3897
+ * Related lists pass `includeColumns` / `relatedTableColumns` so the grid only shows chosen columns.
3898
+ * Filters and sorts must use that same set. An empty include means the full entity list (master lists).
3899
+ */
3900
+ private resolveColumnScope;
3901
+ private scopeFiltersToColumns;
3902
+ private scopeSortsToColumns;
3903
+ private scopeSortPresetsToColumns;
3904
+ private hasColumnScope;
3905
+ private filterMatchKeys;
3906
+ private isFieldInColumnScope;
3907
+ /**
3908
+ * Exact name, or a column that is a display path of the filter property
3909
+ * (`person.displayName` covers filter field `person`). Nested filters such as
3910
+ * `person.firstName` stay hidden unless that path is itself a listed column.
3911
+ */
3912
+ private fieldMatchesColumn;
3889
3913
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXPEntityListToolbarService, never>;
3890
3914
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXPEntityListToolbarService>;
3891
3915
  }
@@ -229,6 +229,12 @@ declare abstract class AXPValueWidgetComponent<T = any | null, TOptions extends
229
229
  /** Applies schema default without marking the form as user-edited. */
230
230
  protected applyDefaultValue(value: T | null | undefined): void;
231
231
  setValue(value: T | null | undefined): void;
232
+ /**
233
+ * Repeater clones pass the row index onto every descendant. Attach that index
234
+ * to the ancestor array path (`rows[0].field`), not after the leaf (`rows.field.[0]`).
235
+ * Lodash paths need `rows[0].field` — a dotted `.[0].` segment is a literal key.
236
+ */
237
+ private joinIndexedWidgetPath;
232
238
  protected detectFullPath(): void;
233
239
  protected handleValueChanged(e: AXValueChangedEvent<T>): void;
234
240
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXPValueWidgetComponent<any, any>, never>;
@@ -243,6 +249,8 @@ declare abstract class AXPDataListWidgetComponent extends AXPValueWidgetComponen
243
249
  protected valueField: _angular_core.Signal<string>;
244
250
  protected textTemplate: _angular_core.Signal<string | undefined>;
245
251
  protected dataSource: _angular_core.WritableSignal<AXDataSource<any>>;
252
+ /** AXDataSource instance from options that the isolated widget copy was built from. */
253
+ private boundRemoteDataSource;
246
254
  /** Query key from options, when options.dataSource is a string or `{ id }` object. */
247
255
  protected queryDataSourceName: _angular_core.Signal<string | null>;
248
256
  selectedItems: _angular_core.WritableSignal<any[]>;
@@ -911,15 +919,35 @@ declare class AXPWidgetRendererDirective {
911
919
  /**
912
920
  * True when a context store path used in an expression (`context.eval`, `context.options`) is
913
921
  * affected by `changedPath`.
922
+ *
923
+ * Do not drop `repeaterRowIndexConflicts` or re-enable last-segment matching across rows.
924
+ * `applicationRoleRows[0].applicationId` and `applicationRoleRows[1].applicationId` share the
925
+ * suffix `applicationId`; treating that as a match clears sibling repeater fields (roles).
926
+ * Canonical: `libs/framework/client/layout/widget-core/README.md` (repeater context isolation).
914
927
  */
915
928
  private contextStorePathDependsOnChangedPath;
929
+ /**
930
+ * Different indexed rows of the same array must not share context events.
931
+ * `rows[0].applicationId` must not match `rows[1].applicationId` via suffix (`applicationId`).
932
+ * Bare `rows` (no `[n]`) still matches every indexed child so list-wide expressions can refresh.
933
+ * Do not remove this gate or “simplify” it back to suffix-only matching.
934
+ */
935
+ private repeaterRowIndexConflicts;
916
936
  /**
917
937
  * Whether an expression template string reads context store paths affected by `changedPath`.
938
+ *
939
+ * Unresolved `>field` (parentPath empty) is `field` only — never suffix-match every `*.field`.
940
+ * Do not fold `>` back into generic suffix matching.
918
941
  */
919
942
  private expressionTextDependsOnContextPath;
920
943
  private hasExpressionDependency;
921
944
  private isPathAlias;
922
945
  private getExpressionValueFromNode;
946
+ /**
947
+ * `events.context('>field')` is this row only (exact resolved path).
948
+ * Do not use `*field` / suffix matching for row-local reset triggers — that fires on every
949
+ * repeater row that has a field of the same name.
950
+ */
923
951
  private hasTriggerDependency;
924
952
  private hasVisibilityDependency;
925
953
  ngOnChanges(changes: SimpleChanges): void;
@@ -934,8 +962,19 @@ declare class AXPWidgetRendererDirective {
934
962
  private show;
935
963
  private hide;
936
964
  private evaluateExpression;
965
+ /**
966
+ * Repeater-relative paths (`>applicationId`) resolve against this widget's parent
967
+ * row (`applicationRoleRows[0].applicationId`), not every field with the same name.
968
+ * When `parentPath` is empty the result is the bare field — callers must not treat that
969
+ * as “any `*.applicationId`”.
970
+ */
971
+ private resolveRowRelativeContextPath;
937
972
  private buildExpressionScope;
938
973
  private getContextScope;
974
+ /**
975
+ * `events.context('>…')` is exact row path only. Do not OR it with
976
+ * `contextStorePathDependsOnChangedPath` — that suffix-matches sibling rows.
977
+ */
939
978
  private getEventScope;
940
979
  private getWidgetScope;
941
980
  private getFunctionScope;
@@ -1616,16 +1616,25 @@ interface AXPRichTextWidgetOptions {
1616
1616
  column: AXPRichTextWidgetColumnOptions;
1617
1617
  }
1618
1618
 
1619
- declare class AXPSelectBoxWidgetColumnComponent extends AXPColumnWidgetComponent<any> {
1619
+ declare class AXPSelectBoxWidgetColumnComponent extends AXPColumnWidgetComponent<unknown> implements OnInit {
1620
+ private readonly queryService;
1621
+ private readonly localStore;
1622
+ private readonly destroyRef;
1623
+ private readonly activeTextField;
1624
+ private readonly activeValueField;
1620
1625
  protected textField: _angular_core.Signal<string>;
1621
1626
  protected valueField: _angular_core.Signal<string>;
1622
1627
  protected cssClassField: _angular_core.Signal<string | undefined>;
1623
1628
  protected badgeClass: _angular_core.Signal<string | undefined>;
1624
- protected dataSource: _angular_core.Signal<unknown[]>;
1629
+ private readonly displayRows;
1630
+ private destroyed;
1625
1631
  protected internalValue: _angular_core.Signal<Record<string, unknown>[]>;
1632
+ ngOnInit(): void;
1626
1633
  protected resolveBadgeClasses(item: unknown): string;
1627
1634
  protected getItemLabel(item: unknown): string | Record<string, string>;
1628
- private extractItem;
1635
+ private loadRows;
1636
+ private resolveSlots;
1637
+ private readLocalItems;
1629
1638
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXPSelectBoxWidgetColumnComponent, never>;
1630
1639
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXPSelectBoxWidgetColumnComponent, "axp-select-box-widget-column", never, { "rawValue": { "alias": "rawValue"; "required": false; }; "rowData": { "alias": "rowData"; "required": false; }; }, {}, never, never, true, never>;
1631
1640
  }
@@ -1674,6 +1683,8 @@ declare class AXPSelectBoxWidgetEditComponent extends AXPDataListWidgetComponent
1674
1683
  /**
1675
1684
  * True when a cascade/parent filter is configured but required values are still empty
1676
1685
  * (e.g. state select before country is chosen).
1686
+ * `not-in` / `nin` are not cascade — treating them as pending disables the control
1687
+ * (not-allowed cursor, empty list). Hide already-picked options with `excludeIds`, not `filter`.
1677
1688
  */
1678
1689
  protected hasPendingCascadeFilter: _angular_core.Signal<boolean>;
1679
1690
  /** Only swap datasource when cascade parent is missing. */
@@ -1721,6 +1732,12 @@ declare class AXPSelectBoxWidgetEditComponent extends AXPDataListWidgetComponent
1721
1732
  */
1722
1733
  private syncExposePathsToSavedBaseline;
1723
1734
  private remapComboItems;
1735
+ /**
1736
+ * Drop ids in `excludeIds` except this widget's current value so the selected item stays visible.
1737
+ * Do not filter out the current row's own id — the dropdown would go empty after pick.
1738
+ */
1739
+ private excludeOptionRows;
1740
+ private applyArrayWidgetFilter;
1724
1741
  /**
1725
1742
  * Patches lookup `load` so widget/cascade filters are AND-ed with lookup search,
1726
1743
  * and so a pending cascade parent returns an empty page.
@@ -4314,6 +4331,7 @@ declare class AXPRepeaterWidgetEditComponent extends AXPValueWidgetComponent<any
4314
4331
  protected disabled: _angular_core.Signal<boolean>;
4315
4332
  protected hasControls: _angular_core.Signal<boolean>;
4316
4333
  protected allowReorder: _angular_core.Signal<boolean>;
4334
+ protected inlineAddControl: _angular_core.Signal<boolean>;
4317
4335
  protected rows: _angular_core.Signal<any[]>;
4318
4336
  onDrop(e: AXDropListDroppedEvent): void;
4319
4337
  protected handleAddItemClick(): void;
@@ -4350,6 +4368,8 @@ interface AXPRepeaterWidgetEditOptions {
4350
4368
  disabled?: boolean;
4351
4369
  hasControls?: boolean;
4352
4370
  allowReorder?: boolean;
4371
+ /** When true, Add sits on the last row (opt-in). Default keeps footer Add Item. */
4372
+ inlineAddControl?: boolean;
4353
4373
  /** Cloned into each new row. Missing `id` values are generated. */
4354
4374
  defaultItem?: Record<string, unknown>;
4355
4375
  }
@@ -5274,9 +5294,9 @@ declare class AXPFlexOptionsWidgetEditComponent extends AXPValueWidgetComponent<
5274
5294
  protected flexDirectionIsColumn: _angular_core.Signal<boolean | undefined>;
5275
5295
  protected flexDirectionIsReverse: _angular_core.Signal<boolean | undefined>;
5276
5296
  protected flexDirectionWithoutReverse: _angular_core.Signal<string | undefined>;
5277
- protected gapMode: _angular_core.WritableSignal<"single" | "both">;
5297
+ protected gapMode: _angular_core.WritableSignal<"both" | "single">;
5278
5298
  protected gapUnit: _angular_core.WritableSignal<string>;
5279
- protected gap: _angular_core.WritableSignal<Record<"x" | "y" | "both", number>>;
5299
+ protected gap: _angular_core.WritableSignal<Record<"both" | "x" | "y", number>>;
5280
5300
  protected lastGap: _angular_core.WritableSignal<number>;
5281
5301
  protected selectedJustify: _angular_core.WritableSignal<AXPFlexBoxOption>;
5282
5302
  protected selectedAlign: _angular_core.WritableSignal<AXPFlexBoxOption>;