@memberjunction/ng-explorer-core 6.1.0-edge.2 → 6.1.0-edge.4

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.
@@ -0,0 +1,276 @@
1
+ /**
2
+ * @fileoverview Identity Claim Redemption Page
3
+ *
4
+ * Landing page for the links in identity-claim emails
5
+ * (`${PORTAL_BASE_URL}/claims/redeem?id=<claimId>&token=<rawToken>`). When a recipient
6
+ * clicks through, this component:
7
+ * 1. Waits for the user's session to be restored (same posture as the OAuth callback —
8
+ * no AuthGuard; the component handles the not-yet-authenticated case itself)
9
+ * 2. Extracts the claim id and optional verification token from the query params
10
+ * 3. Calls the `RedeemIdentityClaim` GraphQL mutation, which runs the server engine's full
11
+ * gate (email match subject to verification rules, or timing-safe token match, atomic CAS)
12
+ * 4. Shows the outcome and offers navigation back into the app
13
+ *
14
+ * Like the OAuth callback, this is a deliberate exception to the NavigationService-only rule:
15
+ * it is registered directly in the routing module and reads its own query params.
16
+ *
17
+ * @module IdentityClaims
18
+ */
19
+ import { Component } from '@angular/core';
20
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
21
+ import * as i0 from "@angular/core";
22
+ import * as i1 from "@angular/router";
23
+ import * as i2 from "@memberjunction/ng-shared-generic";
24
+ import * as i3 from "@memberjunction/ng-ui-components";
25
+ function ClaimRedeemComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
26
+ i0.ɵɵelementStart(0, "div", 2);
27
+ i0.ɵɵelement(1, "mj-loading", 5);
28
+ i0.ɵɵelementEnd();
29
+ } if (rf & 2) {
30
+ const ctx_r0 = i0.ɵɵnextContext();
31
+ i0.ɵɵadvance();
32
+ i0.ɵɵproperty("text", i0.ɵɵinterpolate(ctx_r0.StatusMessage));
33
+ } }
34
+ function ClaimRedeemComponent_Conditional_3_Conditional_8_Template(rf, ctx) { if (rf & 1) {
35
+ const _r3 = i0.ɵɵgetCurrentView();
36
+ i0.ɵɵelementStart(0, "button", 13);
37
+ i0.ɵɵlistener("click", function ClaimRedeemComponent_Conditional_3_Conditional_8_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onRetry()); });
38
+ i0.ɵɵelement(1, "i", 14);
39
+ i0.ɵɵtext(2, " Try Again ");
40
+ i0.ɵɵelementEnd();
41
+ } }
42
+ function ClaimRedeemComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
43
+ const _r2 = i0.ɵɵgetCurrentView();
44
+ i0.ɵɵelementStart(0, "div", 3)(1, "div", 6);
45
+ i0.ɵɵelement(2, "i", 7);
46
+ i0.ɵɵelementEnd();
47
+ i0.ɵɵelementStart(3, "h2");
48
+ i0.ɵɵtext(4);
49
+ i0.ɵɵelementEnd();
50
+ i0.ɵɵelementStart(5, "p", 8);
51
+ i0.ɵɵtext(6);
52
+ i0.ɵɵelementEnd();
53
+ i0.ɵɵelementStart(7, "div", 9);
54
+ i0.ɵɵconditionalCreate(8, ClaimRedeemComponent_Conditional_3_Conditional_8_Template, 3, 0, "button", 10);
55
+ i0.ɵɵelementStart(9, "button", 11);
56
+ i0.ɵɵlistener("click", function ClaimRedeemComponent_Conditional_3_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onGoToApp()); });
57
+ i0.ɵɵelement(10, "i", 12);
58
+ i0.ɵɵtext(11);
59
+ i0.ɵɵelementEnd()()();
60
+ } if (rf & 2) {
61
+ const ctx_r0 = i0.ɵɵnextContext();
62
+ i0.ɵɵadvance(4);
63
+ i0.ɵɵtextInterpolate(ctx_r0.NeedsSignIn ? "Sign In Required" : "Claim Not Redeemed");
64
+ i0.ɵɵadvance(2);
65
+ i0.ɵɵtextInterpolate(ctx_r0.ErrorMessage);
66
+ i0.ɵɵadvance(2);
67
+ i0.ɵɵconditional(!ctx_r0.NeedsSignIn ? 8 : -1);
68
+ i0.ɵɵadvance();
69
+ i0.ɵɵproperty("variant", ctx_r0.NeedsSignIn ? "primary" : "outline");
70
+ i0.ɵɵadvance(2);
71
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.NeedsSignIn ? "Go to Sign In" : "Open the App", " ");
72
+ } }
73
+ function ClaimRedeemComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
74
+ const _r4 = i0.ɵɵgetCurrentView();
75
+ i0.ɵɵelementStart(0, "div", 4)(1, "div", 15);
76
+ i0.ɵɵelement(2, "i", 16);
77
+ i0.ɵɵelementEnd();
78
+ i0.ɵɵelementStart(3, "h2");
79
+ i0.ɵɵtext(4, "Claim Redeemed");
80
+ i0.ɵɵelementEnd();
81
+ i0.ɵɵelementStart(5, "p");
82
+ i0.ɵɵtext(6);
83
+ i0.ɵɵelementEnd();
84
+ i0.ɵɵelementStart(7, "div", 9)(8, "button", 17);
85
+ i0.ɵɵlistener("click", function ClaimRedeemComponent_Conditional_4_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r4); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onGoToApp()); });
86
+ i0.ɵɵelement(9, "i", 18);
87
+ i0.ɵɵtext(10, " Open the App ");
88
+ i0.ɵɵelementEnd()()();
89
+ } if (rf & 2) {
90
+ const ctx_r0 = i0.ɵɵnextContext();
91
+ i0.ɵɵadvance(6);
92
+ i0.ɵɵtextInterpolate(ctx_r0.StatusMessage);
93
+ } }
94
+ /** Maximum time to wait for session restoration (30 seconds) */
95
+ const MAX_WAIT_TIME_MS = 30000;
96
+ /** Polling interval for checking provider readiness (500ms) */
97
+ const POLL_INTERVAL_MS = 500;
98
+ const REDEEM_MUTATION = `
99
+ mutation RedeemIdentityClaim($ClaimID: String!, $Token: String) {
100
+ RedeemIdentityClaim(ClaimID: $ClaimID, Token: $Token) {
101
+ Success
102
+ ErrorMessage
103
+ ClaimID
104
+ Data
105
+ }
106
+ }
107
+ `;
108
+ export class ClaimRedeemComponent extends BaseAngularComponent {
109
+ route;
110
+ router;
111
+ cdr;
112
+ /** Loading state while restoring the session / redeeming */
113
+ IsLoading = true;
114
+ /** Terminal error state */
115
+ HasError = false;
116
+ /** Error message to display */
117
+ ErrorMessage = '';
118
+ /** True when the wait for authentication timed out (user likely not signed in) */
119
+ NeedsSignIn = false;
120
+ /** Status message shown during processing */
121
+ StatusMessage = 'Restoring session...';
122
+ /** Timer for polling provider readiness */
123
+ pollTimer = null;
124
+ /** Flag to prevent double processing */
125
+ isProcessing = false;
126
+ constructor(route, router, cdr) {
127
+ super();
128
+ this.route = route;
129
+ this.router = router;
130
+ this.cdr = cdr;
131
+ }
132
+ async ngOnInit() {
133
+ await this.waitForProviderAndRedeem();
134
+ }
135
+ ngOnDestroy() {
136
+ if (this.pollTimer) {
137
+ clearInterval(this.pollTimer);
138
+ this.pollTimer = null;
139
+ }
140
+ }
141
+ /**
142
+ * Waits for the GraphQL provider to be initialized (indicating auth is complete),
143
+ * then redeems the claim from the query params.
144
+ */
145
+ async waitForProviderAndRedeem() {
146
+ const startTime = Date.now();
147
+ if (this.isProviderReady()) {
148
+ await this.safeRedeem();
149
+ return;
150
+ }
151
+ this.StatusMessage = 'Waiting for sign-in...';
152
+ this.cdr.detectChanges();
153
+ return new Promise((resolve) => {
154
+ this.pollTimer = setInterval(async () => {
155
+ const elapsed = Date.now() - startTime;
156
+ if (this.isProviderReady()) {
157
+ if (this.pollTimer) {
158
+ clearInterval(this.pollTimer);
159
+ this.pollTimer = null;
160
+ }
161
+ await this.safeRedeem();
162
+ resolve();
163
+ return;
164
+ }
165
+ if (elapsed >= MAX_WAIT_TIME_MS) {
166
+ if (this.pollTimer) {
167
+ clearInterval(this.pollTimer);
168
+ this.pollTimer = null;
169
+ }
170
+ this.NeedsSignIn = true;
171
+ this.showError('Please sign in first, then open the link from your email again — the claim will attach to your signed-in account.');
172
+ resolve();
173
+ return;
174
+ }
175
+ const secondsRemaining = Math.ceil((MAX_WAIT_TIME_MS - elapsed) / 1000);
176
+ this.StatusMessage = `Waiting for sign-in... (${secondsRemaining}s)`;
177
+ this.cdr.detectChanges();
178
+ }, POLL_INTERVAL_MS);
179
+ });
180
+ }
181
+ /** Checks if the GraphQL provider is initialized with a valid token */
182
+ isProviderReady() {
183
+ try {
184
+ const provider = this.ProviderToUse;
185
+ if (!provider) {
186
+ return false;
187
+ }
188
+ const configData = provider.ConfigData;
189
+ return Boolean(configData && configData.Token && configData.URL);
190
+ }
191
+ catch {
192
+ return false;
193
+ }
194
+ }
195
+ /** Redeems exactly once, converting any throw into the error state */
196
+ async safeRedeem() {
197
+ if (this.isProcessing) {
198
+ return;
199
+ }
200
+ this.isProcessing = true;
201
+ try {
202
+ await this.redeemClaim();
203
+ }
204
+ catch (error) {
205
+ console.error('[Claim Redeem] Error redeeming claim:', error);
206
+ this.showError(error instanceof Error ? error.message : String(error));
207
+ }
208
+ }
209
+ /** Reads the query params and calls the redemption mutation */
210
+ async redeemClaim() {
211
+ const params = this.route.snapshot.queryParams;
212
+ const claimId = params['id'];
213
+ const token = params['token'];
214
+ if (!claimId) {
215
+ this.showError('This link is missing its claim id. Please use the exact link from your email.');
216
+ return;
217
+ }
218
+ this.StatusMessage = 'Redeeming your claim...';
219
+ this.cdr.detectChanges();
220
+ const provider = this.ProviderToUse;
221
+ const result = (await provider.ExecuteGQL(REDEEM_MUTATION, {
222
+ ClaimID: claimId,
223
+ Token: token ?? null
224
+ }));
225
+ const outcome = result?.RedeemIdentityClaim;
226
+ if (outcome?.Success) {
227
+ this.IsLoading = false;
228
+ this.StatusMessage = 'Your claim has been redeemed and attached to your account.';
229
+ this.cdr.detectChanges();
230
+ }
231
+ else {
232
+ this.showError(outcome?.ErrorMessage || 'The claim could not be redeemed.');
233
+ }
234
+ }
235
+ /** Shows the terminal error state */
236
+ showError(message) {
237
+ this.IsLoading = false;
238
+ this.HasError = true;
239
+ this.ErrorMessage = message;
240
+ this.cdr.detectChanges();
241
+ }
242
+ /** Navigates into the app shell (which handles sign-in when needed) */
243
+ onGoToApp() {
244
+ this.router.navigateByUrl('/');
245
+ }
246
+ /** Retries redemption from scratch (fresh component state) */
247
+ onRetry() {
248
+ this.IsLoading = true;
249
+ this.HasError = false;
250
+ this.NeedsSignIn = false;
251
+ this.ErrorMessage = '';
252
+ this.isProcessing = false;
253
+ void this.waitForProviderAndRedeem();
254
+ }
255
+ static ɵfac = function ClaimRedeemComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ClaimRedeemComponent)(i0.ɵɵdirectiveInject(i1.ActivatedRoute), i0.ɵɵdirectiveInject(i1.Router), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
256
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ClaimRedeemComponent, selectors: [["mj-claim-redeem"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 3, consts: [[1, "claim-redeem-container"], [1, "claim-redeem-card"], [1, "claim-status", "loading"], [1, "claim-status", "error"], [1, "claim-status", "success"], [3, "text"], [1, "icon-container", "error-icon"], [1, "fa-solid", "fa-circle-exclamation"], [1, "error-message"], [1, "button-group"], ["mjButton", "", "variant", "secondary"], ["mjButton", "", 3, "click", "variant"], [1, "fa-solid", "fa-arrow-right-to-bracket"], ["mjButton", "", "variant", "secondary", 3, "click"], [1, "fa-solid", "fa-rotate-right"], [1, "icon-container", "success-icon"], [1, "fa-solid", "fa-circle-check"], ["mjButton", "", "variant", "primary", 3, "click"], [1, "fa-solid", "fa-house"]], template: function ClaimRedeemComponent_Template(rf, ctx) { if (rf & 1) {
257
+ i0.ɵɵelementStart(0, "div", 0)(1, "div", 1);
258
+ i0.ɵɵconditionalCreate(2, ClaimRedeemComponent_Conditional_2_Template, 2, 2, "div", 2);
259
+ i0.ɵɵconditionalCreate(3, ClaimRedeemComponent_Conditional_3_Template, 12, 5, "div", 3);
260
+ i0.ɵɵconditionalCreate(4, ClaimRedeemComponent_Conditional_4_Template, 11, 1, "div", 4);
261
+ i0.ɵɵelementEnd()();
262
+ } if (rf & 2) {
263
+ i0.ɵɵadvance(2);
264
+ i0.ɵɵconditional(ctx.IsLoading ? 2 : -1);
265
+ i0.ɵɵadvance();
266
+ i0.ɵɵconditional(ctx.HasError ? 3 : -1);
267
+ i0.ɵɵadvance();
268
+ i0.ɵɵconditional(!ctx.IsLoading && !ctx.HasError ? 4 : -1);
269
+ } }, dependencies: [i2.LoadingComponent, i3.MJButtonDirective], styles: [".claim-redeem-container[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n background: var(--mj-brand-primary);\n padding: 1rem;\n}\n\n.claim-redeem-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 3rem;\n border-radius: 1rem;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);\n text-align: center;\n max-width: 450px;\n width: 100%;\n}\n\n.claim-status[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.claim-status[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 1.5rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.claim-status[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n color: var(--mj-text-muted);\n line-height: 1.6;\n}\n\n.icon-container[_ngcontent-%COMP%] {\n font-size: 3rem;\n}\n\n.success-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.error-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.error-message[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.button-group[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.75rem;\n margin-top: 0.5rem;\n flex-wrap: wrap;\n justify-content: center;\n}"] });
270
+ }
271
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ClaimRedeemComponent, [{
272
+ type: Component,
273
+ args: [{ standalone: false, selector: 'mj-claim-redeem', template: "<div class=\"claim-redeem-container\">\n <div class=\"claim-redeem-card\">\n <!-- Loading State -->\n @if (IsLoading) {\n <div class=\"claim-status loading\">\n <mj-loading text=\"{{ StatusMessage }}\"></mj-loading>\n </div>\n }\n\n <!-- Error State -->\n @if (HasError) {\n <div class=\"claim-status error\">\n <div class=\"icon-container error-icon\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n </div>\n <h2>{{ NeedsSignIn ? 'Sign In Required' : 'Claim Not Redeemed' }}</h2>\n <p class=\"error-message\">{{ ErrorMessage }}</p>\n <div class=\"button-group\">\n @if (!NeedsSignIn) {\n <button mjButton variant=\"secondary\" (click)=\"onRetry()\">\n <i class=\"fa-solid fa-rotate-right\"></i>\n Try Again\n </button>\n }\n <button mjButton [variant]=\"NeedsSignIn ? 'primary' : 'outline'\" (click)=\"onGoToApp()\">\n <i class=\"fa-solid fa-arrow-right-to-bracket\"></i>\n {{ NeedsSignIn ? 'Go to Sign In' : 'Open the App' }}\n </button>\n </div>\n </div>\n }\n\n <!-- Success State -->\n @if (!IsLoading && !HasError) {\n <div class=\"claim-status success\">\n <div class=\"icon-container success-icon\">\n <i class=\"fa-solid fa-circle-check\"></i>\n </div>\n <h2>Claim Redeemed</h2>\n <p>{{ StatusMessage }}</p>\n <div class=\"button-group\">\n <button mjButton variant=\"primary\" (click)=\"onGoToApp()\">\n <i class=\"fa-solid fa-house\"></i>\n Open the App\n </button>\n </div>\n </div>\n }\n </div>\n</div>\n", styles: [".claim-redeem-container {\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n background: var(--mj-brand-primary);\n padding: 1rem;\n}\n\n.claim-redeem-card {\n background: var(--mj-bg-surface);\n padding: 3rem;\n border-radius: 1rem;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);\n text-align: center;\n max-width: 450px;\n width: 100%;\n}\n\n.claim-status {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.claim-status h2 {\n margin: 0;\n font-size: 1.5rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.claim-status p {\n margin: 0;\n color: var(--mj-text-muted);\n line-height: 1.6;\n}\n\n.icon-container {\n font-size: 3rem;\n}\n\n.success-icon {\n color: var(--mj-status-success);\n}\n\n.error-icon {\n color: var(--mj-status-error);\n}\n\n.error-message {\n color: var(--mj-text-secondary);\n}\n\n.button-group {\n display: flex;\n gap: 0.75rem;\n margin-top: 0.5rem;\n flex-wrap: wrap;\n justify-content: center;\n}\n"] }]
274
+ }], () => [{ type: i1.ActivatedRoute }, { type: i1.Router }, { type: i0.ChangeDetectorRef }], null); })();
275
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ClaimRedeemComponent, { className: "ClaimRedeemComponent", filePath: "src/lib/identity-claims/claim-redeem.component.ts", lineNumber: 56 }); })();
276
+ //# sourceMappingURL=claim-redeem.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claim-redeem.component.js","sourceRoot":"","sources":["../../../src/lib/identity-claims/claim-redeem.component.ts","../../../src/lib/identity-claims/claim-redeem.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Identity Claim Redemption Page\n *\n * Landing page for the links in identity-claim emails\n * (`${PORTAL_BASE_URL}/claims/redeem?id=<claimId>&token=<rawToken>`). When a recipient\n * clicks through, this component:\n * 1. Waits for the user's session to be restored (same posture as the OAuth callback —\n * no AuthGuard; the component handles the not-yet-authenticated case itself)\n * 2. Extracts the claim id and optional verification token from the query params\n * 3. Calls the `RedeemIdentityClaim` GraphQL mutation, which runs the server engine's full\n * gate (email match subject to verification rules, or timing-safe token match, atomic CAS)\n * 4. Shows the outcome and offers navigation back into the app\n *\n * Like the OAuth callback, this is a deliberate exception to the NavigationService-only rule:\n * it is registered directly in the routing module and reads its own query params.\n *\n * @module IdentityClaims\n */\n\nimport { Component, OnDestroy, OnInit, ChangeDetectorRef } from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { GraphQLDataProvider } from '@memberjunction/graphql-dataprovider';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\ninterface RedeemIdentityClaimResponse {\n RedeemIdentityClaim?: {\n Success: boolean;\n ErrorMessage?: string;\n ClaimID?: string;\n Data?: string;\n };\n}\n\n/** Maximum time to wait for session restoration (30 seconds) */\nconst MAX_WAIT_TIME_MS = 30000;\n/** Polling interval for checking provider readiness (500ms) */\nconst POLL_INTERVAL_MS = 500;\n\nconst REDEEM_MUTATION = `\n mutation RedeemIdentityClaim($ClaimID: String!, $Token: String) {\n RedeemIdentityClaim(ClaimID: $ClaimID, Token: $Token) {\n Success\n ErrorMessage\n ClaimID\n Data\n }\n }\n`;\n\n@Component({\n standalone: false,\n selector: 'mj-claim-redeem',\n templateUrl: './claim-redeem.component.html',\n styleUrls: ['./claim-redeem.component.css']\n})\nexport class ClaimRedeemComponent extends BaseAngularComponent implements OnInit, OnDestroy {\n /** Loading state while restoring the session / redeeming */\n public IsLoading = true;\n\n /** Terminal error state */\n public HasError = false;\n\n /** Error message to display */\n public ErrorMessage = '';\n\n /** True when the wait for authentication timed out (user likely not signed in) */\n public NeedsSignIn = false;\n\n /** Status message shown during processing */\n public StatusMessage = 'Restoring session...';\n\n /** Timer for polling provider readiness */\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n\n /** Flag to prevent double processing */\n private isProcessing = false;\n\n constructor(\n private route: ActivatedRoute,\n private router: Router,\n private cdr: ChangeDetectorRef\n ) {\n super();\n }\n\n async ngOnInit(): Promise<void> {\n await this.waitForProviderAndRedeem();\n }\n\n ngOnDestroy(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n /**\n * Waits for the GraphQL provider to be initialized (indicating auth is complete),\n * then redeems the claim from the query params.\n */\n private async waitForProviderAndRedeem(): Promise<void> {\n const startTime = Date.now();\n\n if (this.isProviderReady()) {\n await this.safeRedeem();\n return;\n }\n\n this.StatusMessage = 'Waiting for sign-in...';\n this.cdr.detectChanges();\n\n return new Promise<void>((resolve) => {\n this.pollTimer = setInterval(async () => {\n const elapsed = Date.now() - startTime;\n\n if (this.isProviderReady()) {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n await this.safeRedeem();\n resolve();\n return;\n }\n\n if (elapsed >= MAX_WAIT_TIME_MS) {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n this.NeedsSignIn = true;\n this.showError('Please sign in first, then open the link from your email again — the claim will attach to your signed-in account.');\n resolve();\n return;\n }\n\n const secondsRemaining = Math.ceil((MAX_WAIT_TIME_MS - elapsed) / 1000);\n this.StatusMessage = `Waiting for sign-in... (${secondsRemaining}s)`;\n this.cdr.detectChanges();\n }, POLL_INTERVAL_MS);\n });\n }\n\n /** Checks if the GraphQL provider is initialized with a valid token */\n private isProviderReady(): boolean {\n try {\n const provider = this.ProviderToUse as GraphQLDataProvider;\n if (!provider) {\n return false;\n }\n const configData = provider.ConfigData;\n return Boolean(configData && configData.Token && configData.URL);\n } catch {\n return false;\n }\n }\n\n /** Redeems exactly once, converting any throw into the error state */\n private async safeRedeem(): Promise<void> {\n if (this.isProcessing) {\n return;\n }\n this.isProcessing = true;\n\n try {\n await this.redeemClaim();\n } catch (error) {\n console.error('[Claim Redeem] Error redeeming claim:', error);\n this.showError(error instanceof Error ? error.message : String(error));\n }\n }\n\n /** Reads the query params and calls the redemption mutation */\n private async redeemClaim(): Promise<void> {\n const params = this.route.snapshot.queryParams;\n const claimId = params['id'] as string | undefined;\n const token = params['token'] as string | undefined;\n\n if (!claimId) {\n this.showError('This link is missing its claim id. Please use the exact link from your email.');\n return;\n }\n\n this.StatusMessage = 'Redeeming your claim...';\n this.cdr.detectChanges();\n\n const provider = this.ProviderToUse as GraphQLDataProvider;\n const result = (await provider.ExecuteGQL(REDEEM_MUTATION, {\n ClaimID: claimId,\n Token: token ?? null\n })) as RedeemIdentityClaimResponse;\n\n const outcome = result?.RedeemIdentityClaim;\n if (outcome?.Success) {\n this.IsLoading = false;\n this.StatusMessage = 'Your claim has been redeemed and attached to your account.';\n this.cdr.detectChanges();\n } else {\n this.showError(outcome?.ErrorMessage || 'The claim could not be redeemed.');\n }\n }\n\n /** Shows the terminal error state */\n private showError(message: string): void {\n this.IsLoading = false;\n this.HasError = true;\n this.ErrorMessage = message;\n this.cdr.detectChanges();\n }\n\n /** Navigates into the app shell (which handles sign-in when needed) */\n public onGoToApp(): void {\n this.router.navigateByUrl('/');\n }\n\n /** Retries redemption from scratch (fresh component state) */\n public onRetry(): void {\n this.IsLoading = true;\n this.HasError = false;\n this.NeedsSignIn = false;\n this.ErrorMessage = '';\n this.isProcessing = false;\n void this.waitForProviderAndRedeem();\n }\n}\n","<div class=\"claim-redeem-container\">\n <div class=\"claim-redeem-card\">\n <!-- Loading State -->\n @if (IsLoading) {\n <div class=\"claim-status loading\">\n <mj-loading text=\"{{ StatusMessage }}\"></mj-loading>\n </div>\n }\n\n <!-- Error State -->\n @if (HasError) {\n <div class=\"claim-status error\">\n <div class=\"icon-container error-icon\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n </div>\n <h2>{{ NeedsSignIn ? 'Sign In Required' : 'Claim Not Redeemed' }}</h2>\n <p class=\"error-message\">{{ ErrorMessage }}</p>\n <div class=\"button-group\">\n @if (!NeedsSignIn) {\n <button mjButton variant=\"secondary\" (click)=\"onRetry()\">\n <i class=\"fa-solid fa-rotate-right\"></i>\n Try Again\n </button>\n }\n <button mjButton [variant]=\"NeedsSignIn ? 'primary' : 'outline'\" (click)=\"onGoToApp()\">\n <i class=\"fa-solid fa-arrow-right-to-bracket\"></i>\n {{ NeedsSignIn ? 'Go to Sign In' : 'Open the App' }}\n </button>\n </div>\n </div>\n }\n\n <!-- Success State -->\n @if (!IsLoading && !HasError) {\n <div class=\"claim-status success\">\n <div class=\"icon-container success-icon\">\n <i class=\"fa-solid fa-circle-check\"></i>\n </div>\n <h2>Claim Redeemed</h2>\n <p>{{ StatusMessage }}</p>\n <div class=\"button-group\">\n <button mjButton variant=\"primary\" (click)=\"onGoToApp()\">\n <i class=\"fa-solid fa-house\"></i>\n Open the App\n </button>\n </div>\n </div>\n }\n </div>\n</div>\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"record-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/record-resource.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,EAAY,YAAY,EAAc,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;;AAC7F,qBAOa,oBAAqB,SAAQ,qBAAqB;IAC3D,IAAW,UAAU,IAAI,YAAY,CAEpC;WAEa,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,YAAY;IAwBrF,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IA2B3D,oBAAoB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;yCAxDtD,oBAAoB;2CAApB,oBAAoB;CAqEhC"}
1
+ {"version":3,"file":"record-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/record-resource.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,EAAY,YAAY,EAAc,iBAAiB,EAA0B,MAAM,sBAAsB,CAAC;;AACrH,qBAOa,oBAAqB,SAAQ,qBAAqB;IAC3D,IAAW,UAAU,IAAI,YAAY,CAEpC;WAEa,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,YAAY;IA4BrF,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IA2B3D,oBAAoB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;yCA5DtD,oBAAoB;2CAApB,oBAAoB;CAyEhC"}
@@ -8,7 +8,7 @@ var EntityRecordResource_1;
8
8
  import { Component } from '@angular/core';
9
9
  import { BaseResourceComponent } from '@memberjunction/ng-shared';
10
10
  import { RegisterClass } from '@memberjunction/global';
11
- import { Metadata, CompositeKey } from '@memberjunction/core';
11
+ import { Metadata, CompositeKey, IsNewEntityRecordUrlId } from '@memberjunction/core';
12
12
  import * as i0 from "@angular/core";
13
13
  import * as i1 from "../single-record/single-record.component";
14
14
  let EntityRecordResource = class EntityRecordResource extends BaseResourceComponent {
@@ -33,6 +33,9 @@ let EntityRecordResource = class EntityRecordResource extends BaseResourceCompon
33
33
  if (!e) {
34
34
  throw new Error(`Entity ${data.Configuration.Entity} not found in metadata (tried Name and DisplayName)`);
35
35
  }
36
+ if (IsNewEntityRecordUrlId(data.ResourceRecordID)) {
37
+ return new CompositeKey();
38
+ }
36
39
  let compositeKey = new CompositeKey();
37
40
  compositeKey.LoadFromURLSegment(e, data.ResourceRecordID);
38
41
  return compositeKey;
@@ -1 +1 @@
1
- {"version":3,"file":"record-resource.component.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/record-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component } from '@angular/core';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { ResourceData } from '@memberjunction/core-entities';\nimport { RegisterClass } from '@memberjunction/global';\nimport { Metadata, CompositeKey, EntityInfo, IMetadataProvider } from '@memberjunction/core';\n@RegisterClass(BaseResourceComponent, 'RecordResource')\n@Component({\n standalone: false,\n selector: 'mj-record-resource',\n styles: [`:host { display: block; height: 100%; width: 100%; }`],\n template: `<mj-single-record [PrimaryKey]=\"this.PrimaryKey\" [entityName]=\"Data.Configuration.Entity\" [newRecordValues]=\"Data.Configuration.NewRecordValues\" (loadComplete)=\"NotifyLoadComplete()\" (recordSaved)=\"ResourceRecordSaved($event)\" (recordDismissed)=\"NotifyCloseRequested()\"></mj-single-record>`\n})\nexport class EntityRecordResource extends BaseResourceComponent {\n public get PrimaryKey(): CompositeKey {\n return EntityRecordResource.GetPrimaryKey(this.Data, this.ProviderToUse);\n }\n\n public static GetPrimaryKey(data: ResourceData, provider?: IMetadataProvider): CompositeKey {\n // global-provider-ok: static helper has no component instance scope; falls back to default provider\n const md = (provider ?? Metadata.Provider) as IMetadataProvider;\n const requested = (data.Configuration.Entity ?? '').trim();\n // Prefer EntityByName (project rule: never use Entities.find for\n // single-entity lookups — case/whitespace tolerant + O(1) map). Fall\n // back to DisplayName match for callers (AI agents, hand-typed URLs,\n // external CTAs) that pass the human-readable display name instead\n // of the canonical Name (e.g. \"Users\" for \"MJ: Users\").\n let e: EntityInfo | undefined = md.EntityByName(requested);\n if (!e) {\n const lowered = requested.toLowerCase();\n e = md.Entities.find((x: EntityInfo) =>\n (x.DisplayName ?? '').trim().toLowerCase() === lowered);\n }\n if (!e){\n throw new Error(`Entity ${data.Configuration.Entity} not found in metadata (tried Name and DisplayName)`);\n }\n\n let compositeKey: CompositeKey = new CompositeKey();\n compositeKey.LoadFromURLSegment(e, data.ResourceRecordID);\n return compositeKey;\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n if (!data.Configuration.Entity) {\n return '';\n }\n\n const md = this.ProviderToUse;\n let e = md.EntityByName(data.Configuration.Entity);\n if (!e) {\n // Same DisplayName fallback as GetPrimaryKey — keeps the\n // breadcrumb/title in sync when a CTA used the display name.\n const lowered = (data.Configuration.Entity ?? '').trim().toLowerCase();\n e = md.Entities.find((x: EntityInfo) =>\n (x.DisplayName ?? '').trim().toLowerCase() === lowered);\n }\n if (!e) {\n return '';\n }\n\n const pk: CompositeKey = EntityRecordResource.GetPrimaryKey(data, this.ProviderToUse);\n if (pk.HasValue) {\n const name = await md.GetEntityRecordName(data.Configuration.Entity, pk);\n return name ? name : e.DisplayNameOrName;\n } else {\n return `New ${e.DisplayNameOrName} Record`;\n }\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n if (!data.Configuration.Entity){\n return ''\n }\n else {\n const md = this.ProviderToUse;\n const e = md.Entities.find(e => e.Name.trim().toLowerCase() === data.Configuration.Entity.trim().toLowerCase());\n if (e)\n return e?.Icon;\n else\n return '';\n }\n }\n}\n"]}
1
+ {"version":3,"file":"record-resource.component.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/record-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component } from '@angular/core';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { ResourceData } from '@memberjunction/core-entities';\nimport { RegisterClass } from '@memberjunction/global';\nimport { Metadata, CompositeKey, EntityInfo, IMetadataProvider, IsNewEntityRecordUrlId } from '@memberjunction/core';\n@RegisterClass(BaseResourceComponent, 'RecordResource')\n@Component({\n standalone: false,\n selector: 'mj-record-resource',\n styles: [`:host { display: block; height: 100%; width: 100%; }`],\n template: `<mj-single-record [PrimaryKey]=\"this.PrimaryKey\" [entityName]=\"Data.Configuration.Entity\" [newRecordValues]=\"Data.Configuration.NewRecordValues\" (loadComplete)=\"NotifyLoadComplete()\" (recordSaved)=\"ResourceRecordSaved($event)\" (recordDismissed)=\"NotifyCloseRequested()\"></mj-single-record>`\n})\nexport class EntityRecordResource extends BaseResourceComponent {\n public get PrimaryKey(): CompositeKey {\n return EntityRecordResource.GetPrimaryKey(this.Data, this.ProviderToUse);\n }\n\n public static GetPrimaryKey(data: ResourceData, provider?: IMetadataProvider): CompositeKey {\n // global-provider-ok: static helper has no component instance scope; falls back to default provider\n const md = (provider ?? Metadata.Provider) as IMetadataProvider;\n const requested = (data.Configuration.Entity ?? '').trim();\n // Prefer EntityByName (project rule: never use Entities.find for\n // single-entity lookups — case/whitespace tolerant + O(1) map). Fall\n // back to DisplayName match for callers (AI agents, hand-typed URLs,\n // external CTAs) that pass the human-readable display name instead\n // of the canonical Name (e.g. \"Users\" for \"MJ: Users\").\n let e: EntityInfo | undefined = md.EntityByName(requested);\n if (!e) {\n const lowered = requested.toLowerCase();\n e = md.Entities.find((x: EntityInfo) =>\n (x.DisplayName ?? '').trim().toLowerCase() === lowered);\n }\n if (!e){\n throw new Error(`Entity ${data.Configuration.Entity} not found in metadata (tried Name and DisplayName)`);\n }\n\n if (IsNewEntityRecordUrlId(data.ResourceRecordID)) {\n return new CompositeKey();\n }\n\n let compositeKey: CompositeKey = new CompositeKey();\n compositeKey.LoadFromURLSegment(e, data.ResourceRecordID);\n return compositeKey;\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n if (!data.Configuration.Entity) {\n return '';\n }\n\n const md = this.ProviderToUse;\n let e = md.EntityByName(data.Configuration.Entity);\n if (!e) {\n // Same DisplayName fallback as GetPrimaryKey — keeps the\n // breadcrumb/title in sync when a CTA used the display name.\n const lowered = (data.Configuration.Entity ?? '').trim().toLowerCase();\n e = md.Entities.find((x: EntityInfo) =>\n (x.DisplayName ?? '').trim().toLowerCase() === lowered);\n }\n if (!e) {\n return '';\n }\n\n const pk: CompositeKey = EntityRecordResource.GetPrimaryKey(data, this.ProviderToUse);\n if (pk.HasValue) {\n const name = await md.GetEntityRecordName(data.Configuration.Entity, pk);\n return name ? name : e.DisplayNameOrName;\n } else {\n return `New ${e.DisplayNameOrName} Record`;\n }\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n if (!data.Configuration.Entity){\n return ''\n }\n else {\n const md = this.ProviderToUse;\n const e = md.Entities.find(e => e.Name.trim().toLowerCase() === data.Configuration.Entity.trim().toLowerCase());\n if (e)\n return e?.Icon;\n else\n return '';\n }\n }\n}\n"]}
@@ -246,6 +246,13 @@ export declare class ShellComponent extends BaseAngularComponent implements OnIn
246
246
  * Creates new tabs for resources when the original tab was replaced.
247
247
  */
248
248
  private handleMissingTabForUrl;
249
+ /**
250
+ * Recreate a record tab from a URL. `/new` is OpenNewEntityRecord — feeding
251
+ * the sentinel through OpenEntityRecord produced an empty CompositeKey and
252
+ * another forced tab, which is the loop that killed the browser.
253
+ */
254
+ private openRecordFromUrl;
255
+ private recordTabMatchesUrl;
249
256
  /**
250
257
  * Find the tab that matches a given URL
251
258
  */
@@ -1 +1 @@
1
- {"version":3,"file":"shell.component.d.ts","sourceRoot":"","sources":["../../../src/lib/shell/shell.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shell.component.d.ts","sourceRoot":"","sources":["../../../src/lib/shell/shell.component.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ import { Component, ViewChild, HostListener } from '@angular/core';
2
2
  import { NavigationEnd } from '@angular/router';
3
3
  import { combineLatest, Subject } from 'rxjs';
4
4
  import { filter, takeUntil } from 'rxjs/operators';
5
- import { LogStatus, LogError, StartupManager, CompositeKey } from '@memberjunction/core';
5
+ import { LogStatus, LogError, StartupManager, CompositeKey, EncodeNewRecordValuesForURL, IsNewEntityRecordUrlId, NEW_ENTITY_RECORD_URL_ID, NEW_RECORD_VALUES_QUERY_PARAM, RecordUrlMatchesTab, ResourceUrlsEquivalent } from '@memberjunction/core';
6
6
  import { MJEventType, MJGlobal, uuidv4, UUIDsEqual } from '@memberjunction/global';
7
7
  import { EventCodes, SharedService, SYSTEM_APP_ID, SetRecordOpenStyle, IsRecordsRegionTab, IsRecordsTabConfiguration } from '@memberjunction/ng-shared';
8
8
  import { MJNotificationService } from '@memberjunction/ng-notifications';
@@ -1292,8 +1292,11 @@ export class ShellComponent extends BaseAngularComponent {
1292
1292
  // Compare full URLs including query params to detect changes
1293
1293
  const currentUrl = this.router.url;
1294
1294
  const newUrl = resourceUrl;
1295
- // Only update if URL is different (path or query params changed)
1296
- if (currentUrl !== newUrl) {
1295
+ // Decode before compare. encodeURIComponent writes `%3A` for the
1296
+ // colon in `MJ_BizApps_Orders: Order Headers`; Angular's serializer
1297
+ // leaves `:`. A raw !== is permanently true and reloads the route
1298
+ // until the tab dies (Person → Orders → New).
1299
+ if (!ResourceUrlsEquivalent(currentUrl, newUrl)) {
1297
1300
  // Suppress ResourceResolver for this navigation - we're just syncing the URL
1298
1301
  // to reflect the current active tab, not requesting a new tab to be opened
1299
1302
  this.tabService.SuppressNextResolve();
@@ -1380,12 +1383,7 @@ export class ShellComponent extends BaseAngularComponent {
1380
1383
  if (appRecordMatch) {
1381
1384
  const entityName = decodeURIComponent(appRecordMatch[2]);
1382
1385
  const recordId = decodeURIComponent(appRecordMatch[3]);
1383
- const compositeKey = new CompositeKey();
1384
- compositeKey.SimpleLoadFromURLSegment(recordId);
1385
- // Recreating a closed tab from browser history — the user's CURRENT
1386
- // page is not where this record came from, so don't stamp it as the
1387
- // origin (recordSource 'none' = no crumb rather than a false one).
1388
- this.navigationService.OpenEntityRecord(entityName, compositeKey, { recordSource: 'none' });
1386
+ this.openRecordFromUrl(entityName, recordId, queryParams);
1389
1387
  return;
1390
1388
  }
1391
1389
  // Check for app-scoped view URL: /app/:appName/view/:viewId
@@ -1488,11 +1486,7 @@ export class ShellComponent extends BaseAngularComponent {
1488
1486
  if (legacyRecordMatch) {
1489
1487
  const entityName = decodeURIComponent(legacyRecordMatch[1]);
1490
1488
  const recordId = decodeURIComponent(legacyRecordMatch[2]);
1491
- const compositeKey = new CompositeKey();
1492
- compositeKey.SimpleLoadFromURLSegment(recordId);
1493
- // Same as the app-scoped branch above: history recreation has no
1494
- // truthful origin — suppress the crumb instead of inventing one.
1495
- this.navigationService.OpenEntityRecord(entityName, compositeKey, { recordSource: 'none' });
1489
+ this.openRecordFromUrl(entityName, recordId, queryParams);
1496
1490
  return;
1497
1491
  }
1498
1492
  // Check for legacy view URL: /resource/view/:viewId
@@ -1514,6 +1508,30 @@ export class ShellComponent extends BaseAngularComponent {
1514
1508
  this.urlBasedNavigation = false;
1515
1509
  }
1516
1510
  }
1511
+ /**
1512
+ * Recreate a record tab from a URL. `/new` is OpenNewEntityRecord — feeding
1513
+ * the sentinel through OpenEntityRecord produced an empty CompositeKey and
1514
+ * another forced tab, which is the loop that killed the browser.
1515
+ */
1516
+ openRecordFromUrl(entityName, recordId, queryParams) {
1517
+ if (IsNewEntityRecordUrlId(recordId)) {
1518
+ const nrv = queryParams.get(NEW_RECORD_VALUES_QUERY_PARAM) ?? undefined;
1519
+ this.navigationService.OpenNewEntityRecord(entityName, {
1520
+ newRecordValues: nrv,
1521
+ recordSource: 'none',
1522
+ });
1523
+ return;
1524
+ }
1525
+ const compositeKey = new CompositeKey();
1526
+ compositeKey.SimpleLoadFromURLSegment(recordId);
1527
+ this.navigationService.OpenEntityRecord(entityName, compositeKey, { recordSource: 'none' });
1528
+ }
1529
+ recordTabMatchesUrl(tab, entityName, recordId) {
1530
+ const tabConfig = tab.configuration || {};
1531
+ const tabEntity = (tabConfig['Entity'] || tabConfig['entity']);
1532
+ const tabRecordId = (tabConfig['recordId'] ?? tab.resourceRecordId);
1533
+ return RecordUrlMatchesTab(entityName, recordId, tabEntity, tabRecordId);
1534
+ }
1517
1535
  /**
1518
1536
  * Find the tab that matches a given URL
1519
1537
  */
@@ -1582,13 +1600,7 @@ export class ShellComponent extends BaseAngularComponent {
1582
1600
  if (appRecordMatch) {
1583
1601
  const entityName = decodeURIComponent(appRecordMatch[2]);
1584
1602
  const recordId = decodeURIComponent(appRecordMatch[3]);
1585
- return tabs.find(tab => {
1586
- const tabConfig = tab.configuration || {};
1587
- const tabEntity = (tabConfig['Entity'] || tabConfig['entity']);
1588
- const tabRecordId = (tabConfig['recordId'] || tab.resourceRecordId);
1589
- return tabEntity?.toLowerCase() === entityName.toLowerCase() &&
1590
- tabRecordId === recordId;
1591
- }) || null;
1603
+ return tabs.find(tab => this.recordTabMatchesUrl(tab, entityName, recordId)) || null;
1592
1604
  }
1593
1605
  // Dynamic view: /app/:appName/view/dynamic/:entityName
1594
1606
  const appDynamicViewMatch = urlPath.match(/^\/app\/([^\/]+)\/view\/dynamic\/(.+)$/);
@@ -1652,13 +1664,7 @@ export class ShellComponent extends BaseAngularComponent {
1652
1664
  if (recordMatch) {
1653
1665
  const entityName = decodeURIComponent(recordMatch[1]);
1654
1666
  const recordId = decodeURIComponent(recordMatch[2]);
1655
- return tabs.find(tab => {
1656
- const tabConfig = tab.configuration || {};
1657
- const tabEntity = (tabConfig['Entity'] || tabConfig['entity']);
1658
- const tabRecordId = (tabConfig['recordId'] || tab.resourceRecordId);
1659
- return tabEntity?.toLowerCase() === entityName.toLowerCase() &&
1660
- tabRecordId === recordId;
1661
- }) || null;
1667
+ return tabs.find(tab => this.recordTabMatchesUrl(tab, entityName, recordId)) || null;
1662
1668
  }
1663
1669
  // Check for view URL: /resource/view/:viewId
1664
1670
  const viewMatch = urlPath.match(/^\/resource\/view\/([^\/]+)$/);
@@ -1725,11 +1731,12 @@ export class ShellComponent extends BaseAngularComponent {
1725
1731
  const isAppDefault = config['isAppDefault'];
1726
1732
  const tabAppId = tab.applicationId;
1727
1733
  // Helper to append query params to a URL, preserving any existing params
1728
- const appendQP = (url) => {
1729
- if (!queryParams || Object.keys(queryParams).length === 0)
1734
+ const appendQP = (url, extra) => {
1735
+ const all = { ...(queryParams ?? {}), ...(extra ?? {}) };
1736
+ if (Object.keys(all).length === 0)
1730
1737
  return url;
1731
1738
  const separator = url.includes('?') ? '&' : '?';
1732
- const params = new URLSearchParams(queryParams);
1739
+ const params = new URLSearchParams(all);
1733
1740
  return `${url}${separator}${params.toString()}`;
1734
1741
  };
1735
1742
  // Helper function to get app path for URL
@@ -1832,13 +1839,19 @@ export class ShellComponent extends BaseAngularComponent {
1832
1839
  switch (resourceType) {
1833
1840
  case 'records':
1834
1841
  // /app/:appName/record/:entityName/:recordId
1835
- if (entityName && recordId) {
1836
- // recordId is a CompositeKey URL segment ("ID|<value>") — the '|' MUST be encoded.
1837
- // Angular's UrlSerializer percent-encodes '|' to %7C in router.url, so if we embed it raw
1838
- // here, `syncUrlWithWorkspace`'s `currentUrl !== newUrl` check is permanently true and can
1839
- // drive a re-navigation loop (with onSameUrlNavigation:'reload'). The read side already
1840
- // decodeURIComponent()s this segment, so encoding here keeps both sides consistent.
1841
- return appendQP(`/app/${encodeURIComponent(appPath)}/record/${encodeURIComponent(entityName)}/${encodeURIComponent(recordId)}`);
1842
+ // Unsaved records use the `new` sentinel so they can deeplink with NewRecordValues.
1843
+ if (entityName) {
1844
+ const isNewRecord = config['isNew'] === true || IsNewEntityRecordUrlId(recordId);
1845
+ const idSeg = isNewRecord ? NEW_ENTITY_RECORD_URL_ID : recordId;
1846
+ if (idSeg) {
1847
+ // recordId is a CompositeKey URL segment ("ID|<value>") the '|' MUST be encoded.
1848
+ // Angular's UrlSerializer percent-encodes '|' to %7C in router.url, so if we embed it raw
1849
+ // here, `syncUrlWithWorkspace`'s `currentUrl !== newUrl` check is permanently true and can
1850
+ // drive a re-navigation loop (with onSameUrlNavigation:'reload'). The read side already
1851
+ // decodeURIComponent()s this segment, so encoding here keeps both sides consistent.
1852
+ const nrv = isNewRecord ? EncodeNewRecordValuesForURL(config['NewRecordValues']) : undefined;
1853
+ return appendQP(`/app/${encodeURIComponent(appPath)}/record/${encodeURIComponent(entityName)}/${encodeURIComponent(idSeg)}`, nrv ? { [NEW_RECORD_VALUES_QUERY_PARAM]: nrv } : undefined);
1854
+ }
1842
1855
  }
1843
1856
  break;
1844
1857
  case 'user views':
@@ -1903,10 +1916,15 @@ export class ShellComponent extends BaseAngularComponent {
1903
1916
  // Fallback to legacy routes (for backward compatibility during transition)
1904
1917
  switch (resourceType) {
1905
1918
  case 'records':
1906
- if (entityName && recordId) {
1907
- // Encode the CompositeKey segment ('|' %7C) to match Angular's serialized router.url and
1908
- // the decodeURIComponent() on the read side — see the app-scoped 'records' case above.
1909
- return appendQP(`/resource/record/${encodeURIComponent(entityName)}/${encodeURIComponent(recordId)}`);
1919
+ if (entityName) {
1920
+ const isNewRecord = config['isNew'] === true || IsNewEntityRecordUrlId(recordId);
1921
+ const idSeg = isNewRecord ? NEW_ENTITY_RECORD_URL_ID : recordId;
1922
+ if (idSeg) {
1923
+ // Encode the CompositeKey segment ('|' → %7C) to match Angular's serialized router.url and
1924
+ // the decodeURIComponent() on the read side — see the app-scoped 'records' case above.
1925
+ const nrv = isNewRecord ? EncodeNewRecordValuesForURL(config['NewRecordValues']) : undefined;
1926
+ return appendQP(`/resource/record/${encodeURIComponent(entityName)}/${encodeURIComponent(idSeg)}`, nrv ? { [NEW_RECORD_VALUES_QUERY_PARAM]: nrv } : undefined);
1927
+ }
1910
1928
  }
1911
1929
  break;
1912
1930
  case 'user views':