@propmix/profet-common-header 3.2.0-beta.1 → 3.2.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2020/lib/common-header.interface.mjs +1 -1
- package/esm2020/lib/common-header.service.mjs +60 -1
- package/esm2020/lib/header/header.component.mjs +23 -69
- package/fesm2015/propmix-profet-common-header.mjs +81 -68
- package/fesm2015/propmix-profet-common-header.mjs.map +1 -1
- package/fesm2020/propmix-profet-common-header.mjs +81 -68
- package/fesm2020/propmix-profet-common-header.mjs.map +1 -1
- package/lib/common-header.interface.d.ts +1 -0
- package/lib/common-header.service.d.ts +16 -0
- package/lib/header/header.component.d.ts +0 -13
- package/package.json +1 -1
|
@@ -223,6 +223,8 @@ class Utilities {
|
|
|
223
223
|
class CommonHeaderService {
|
|
224
224
|
constructor(config) {
|
|
225
225
|
this.config = config;
|
|
226
|
+
this.SESSION_EXPIRED_KEY = 'session_expired';
|
|
227
|
+
this.LAST_ACTIVE_SESSION_KEY = 'lastActiveSessionTime';
|
|
226
228
|
this.baseUrl = '';
|
|
227
229
|
this.isSessionExpiryDialogOpen = false;
|
|
228
230
|
this._apiGatewayService = inject(ApiGatewayService);
|
|
@@ -318,6 +320,63 @@ class CommonHeaderService {
|
|
|
318
320
|
let url = `${this.baseUrl + EndPoints.API_URLS.updateLastAccessedApplication}`;
|
|
319
321
|
return this._apiGatewayService.doPost(url, reqBody);
|
|
320
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Helper to get the root domain (e.g. .profet.ai) to share cookies across subdomains/ports.
|
|
325
|
+
* If on localhost or an IP, it falls back to the hostname.
|
|
326
|
+
*/
|
|
327
|
+
getRootDomain() {
|
|
328
|
+
const hostname = window.location.hostname;
|
|
329
|
+
const parts = hostname.split('.');
|
|
330
|
+
if (parts.length > 2 && !/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(hostname)) {
|
|
331
|
+
// If we have 4+ parts (e.g. app1.local.profet.ai), we want to include the environment (local.profet.ai)
|
|
332
|
+
// to avoid sharing cookies with app1.dev.profet.ai or app1.profet.ai.
|
|
333
|
+
if (parts.length > 3) {
|
|
334
|
+
return '.' + parts.slice(-3).join('.');
|
|
335
|
+
}
|
|
336
|
+
// For standard 3 parts (app1.profet.ai), share on .profet.ai
|
|
337
|
+
return '.' + parts.slice(-2).join('.');
|
|
338
|
+
}
|
|
339
|
+
return hostname;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Generates a unique cookie name based on the environment root domain.
|
|
343
|
+
* e.g. 'lastActive' on .qa.profet.ai -> 'lastActive_qa_profet_ai'
|
|
344
|
+
* @param name Base cookie name
|
|
345
|
+
*/
|
|
346
|
+
getSuffixedCookieName(name) {
|
|
347
|
+
const rootDomain = this.getRootDomain();
|
|
348
|
+
// Replace dots with underscores to create a clean suffix
|
|
349
|
+
const suffix = rootDomain.replace(/\./g, '_');
|
|
350
|
+
return `${name}${suffix}`;
|
|
351
|
+
}
|
|
352
|
+
setCookie(name, value, days) {
|
|
353
|
+
const uniqueName = this.getSuffixedCookieName(name);
|
|
354
|
+
let expires = "";
|
|
355
|
+
if (days) {
|
|
356
|
+
const date = new Date();
|
|
357
|
+
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
|
358
|
+
expires = "; expires=" + date.toUTCString();
|
|
359
|
+
}
|
|
360
|
+
// Important: set domain to allow sharing across subdomains
|
|
361
|
+
const domain = "; domain=" + this.getRootDomain();
|
|
362
|
+
document.cookie = uniqueName + "=" + (value || "") + expires + domain + "; path=/";
|
|
363
|
+
}
|
|
364
|
+
getCookie(name) {
|
|
365
|
+
const uniqueName = this.getSuffixedCookieName(name);
|
|
366
|
+
const nameEQ = uniqueName + "=";
|
|
367
|
+
const ca = document.cookie.split(';');
|
|
368
|
+
for (let i = 0; i < ca.length; i++) {
|
|
369
|
+
let c = ca[i];
|
|
370
|
+
while (c.charAt(0) == ' ')
|
|
371
|
+
c = c.substring(1, c.length);
|
|
372
|
+
if (c.indexOf(nameEQ) == 0)
|
|
373
|
+
return c.substring(nameEQ.length, c.length);
|
|
374
|
+
}
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
deleteCookie(name) {
|
|
378
|
+
this.setCookie(name, '', -1);
|
|
379
|
+
}
|
|
321
380
|
}
|
|
322
381
|
CommonHeaderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CommonHeaderService, deps: [{ token: 'headerConfig' }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
323
382
|
CommonHeaderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CommonHeaderService, providedIn: 'root' });
|
|
@@ -455,75 +514,21 @@ class HeaderComponent {
|
|
|
455
514
|
// }
|
|
456
515
|
this.resetTimer();
|
|
457
516
|
// Clear any stale logout signal on init
|
|
458
|
-
this.setCookie(
|
|
517
|
+
this._headerSer.setCookie(this._headerSer.SESSION_EXPIRED_KEY, '', -1);
|
|
459
518
|
this.startLogoutCheck();
|
|
460
519
|
});
|
|
461
520
|
}
|
|
462
|
-
/**
|
|
463
|
-
* Helper to get the root domain (e.g. .mycom.ai) to share cookies across subdomains/ports.
|
|
464
|
-
* If on localhost or an IP, it falls back to the hostname.
|
|
465
|
-
*/
|
|
466
|
-
getRootDomain() {
|
|
467
|
-
const hostname = window.location.hostname;
|
|
468
|
-
const parts = hostname.split('.');
|
|
469
|
-
if (parts.length > 2 && !/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(hostname)) {
|
|
470
|
-
// If we have 4+ parts (e.g. app1.local.profet.ai), we want to include the environment (local.profet.ai)
|
|
471
|
-
// to avoid sharing cookies with app1.dev.profet.ai or app1.profet.ai.
|
|
472
|
-
if (parts.length > 3) {
|
|
473
|
-
return '.' + parts.slice(-3).join('.');
|
|
474
|
-
}
|
|
475
|
-
// For standard 3 parts (app1.profet.ai), share on .profet.ai
|
|
476
|
-
return '.' + parts.slice(-2).join('.');
|
|
477
|
-
}
|
|
478
|
-
return hostname;
|
|
479
|
-
}
|
|
480
|
-
/**
|
|
481
|
-
* Generates a unique cookie name based on the environment root domain.
|
|
482
|
-
* e.g. 'lastActive' on .qa.profet.ai -> 'lastActive_qa_profet_ai'
|
|
483
|
-
* @param name Base cookie name
|
|
484
|
-
*/
|
|
485
|
-
getSuffixedCookieName(name) {
|
|
486
|
-
const rootDomain = this.getRootDomain();
|
|
487
|
-
// Replace dots with underscores to create a clean suffix
|
|
488
|
-
const suffix = rootDomain.replace(/\./g, '_');
|
|
489
|
-
return `${name}${suffix}`;
|
|
490
|
-
}
|
|
491
|
-
setCookie(name, value, days) {
|
|
492
|
-
const uniqueName = this.getSuffixedCookieName(name);
|
|
493
|
-
let expires = "";
|
|
494
|
-
if (days) {
|
|
495
|
-
const date = new Date();
|
|
496
|
-
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
|
497
|
-
expires = "; expires=" + date.toUTCString();
|
|
498
|
-
}
|
|
499
|
-
// Important: set domain to allow sharing across subdomains
|
|
500
|
-
const domain = "; domain=" + this.getRootDomain();
|
|
501
|
-
document.cookie = uniqueName + "=" + (value || "") + expires + domain + "; path=/";
|
|
502
|
-
}
|
|
503
|
-
getCookie(name) {
|
|
504
|
-
const uniqueName = this.getSuffixedCookieName(name);
|
|
505
|
-
const nameEQ = uniqueName + "=";
|
|
506
|
-
const ca = document.cookie.split(';');
|
|
507
|
-
for (let i = 0; i < ca.length; i++) {
|
|
508
|
-
let c = ca[i];
|
|
509
|
-
while (c.charAt(0) == ' ')
|
|
510
|
-
c = c.substring(1, c.length);
|
|
511
|
-
if (c.indexOf(nameEQ) == 0)
|
|
512
|
-
return c.substring(nameEQ.length, c.length);
|
|
513
|
-
}
|
|
514
|
-
return null;
|
|
515
|
-
}
|
|
516
521
|
resetTimer(isUserActivity = true) {
|
|
517
522
|
clearTimeout(this.inactivityTimeout);
|
|
518
523
|
// Update global activity timestamp in cookie ONLY if triggered by user activity
|
|
519
524
|
if (isUserActivity) {
|
|
520
525
|
// Use a short expiry (e.g. 1 day) or sync with session length
|
|
521
|
-
this.setCookie(
|
|
526
|
+
this._headerSer.setCookie(this._headerSer.LAST_ACTIVE_SESSION_KEY, Date.now().toString(), 1);
|
|
522
527
|
}
|
|
523
528
|
// if (!this._headerSer.isSessionExpiryDialogOpen) {
|
|
524
529
|
this.inactivityTimeout = setTimeout(() => {
|
|
525
530
|
// Check global activity before logging out
|
|
526
|
-
const lastActive = this.getCookie(
|
|
531
|
+
const lastActive = this._headerSer.getCookie(this._headerSer.LAST_ACTIVE_SESSION_KEY);
|
|
527
532
|
const now = Date.now();
|
|
528
533
|
const lastActiveTime = lastActive ? parseInt(lastActive, 10) : 0;
|
|
529
534
|
const elapsed = now - lastActiveTime;
|
|
@@ -545,11 +550,11 @@ class HeaderComponent {
|
|
|
545
550
|
startLogoutCheck() {
|
|
546
551
|
// Poll for the logout signal cookie (works across ports/subdomains)
|
|
547
552
|
this.logoutCheckInterval = setInterval(() => {
|
|
548
|
-
if (this.getCookie(
|
|
553
|
+
if (this._headerSer.getCookie(this._headerSer.SESSION_EXPIRED_KEY)) {
|
|
549
554
|
// Check if tab still "active" according to the shared time
|
|
550
555
|
// If tab is active but receiving a logout signal, it implies a MANUAL logout from another tab.
|
|
551
556
|
// If tab is inactive and receiving a logout signal, it implies a TIMEOUT.
|
|
552
|
-
const lastActive = this.getCookie(
|
|
557
|
+
const lastActive = this._headerSer.getCookie(this._headerSer.LAST_ACTIVE_SESSION_KEY);
|
|
553
558
|
const now = Date.now();
|
|
554
559
|
const lastActiveTime = lastActive ? parseInt(lastActive, 10) : 0;
|
|
555
560
|
const elapsed = now - lastActiveTime;
|
|
@@ -565,15 +570,18 @@ class HeaderComponent {
|
|
|
565
570
|
// }
|
|
566
571
|
if (broadcast) {
|
|
567
572
|
// Set a cookie to signal other tabs/ports
|
|
568
|
-
this.setCookie(
|
|
573
|
+
this._headerSer.setCookie(this._headerSer.SESSION_EXPIRED_KEY, 'true', 1);
|
|
569
574
|
}
|
|
570
575
|
this.logoutEvent.emit();
|
|
571
576
|
let sessionUrl = this._headerSer.headerConfig.signOutUrl;
|
|
577
|
+
if (this._headerSer.headerConfig.enableLastUrlRedirection) {
|
|
578
|
+
const separator = sessionUrl.includes('?') ? '&' : '?';
|
|
579
|
+
sessionUrl = sessionUrl + separator + 'returnUrl=' + encodeURIComponent(window.location.href);
|
|
580
|
+
}
|
|
572
581
|
// Only add sessionExpired params if it is NOT a manual logout
|
|
573
582
|
if (!isManual) {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
sessionUrl = appUrl + separator + 'sessionExpired=true&timeout=' + this.INACTIVITY_LIMIT;
|
|
583
|
+
const separator = sessionUrl.includes('?') ? '&' : '?';
|
|
584
|
+
sessionUrl = sessionUrl + separator + 'sessionExpired=true&timeout=' + this.INACTIVITY_LIMIT;
|
|
577
585
|
}
|
|
578
586
|
signOut({ global: true, oauth: { redirectUrl: sessionUrl } })
|
|
579
587
|
.then(() => {
|
|
@@ -686,22 +694,27 @@ class HeaderComponent {
|
|
|
686
694
|
onLogoutClick() {
|
|
687
695
|
this.menuTrigger.closeMenu();
|
|
688
696
|
// Sync with other tabs
|
|
689
|
-
this.setCookie(
|
|
697
|
+
this._headerSer.setCookie(this._headerSer.SESSION_EXPIRED_KEY, 'true', 1);
|
|
690
698
|
// Clear timers
|
|
691
699
|
if (this.inactivityTimeout)
|
|
692
700
|
clearTimeout(this.inactivityTimeout);
|
|
693
701
|
if (this.logoutCheckInterval)
|
|
694
702
|
clearInterval(this.logoutCheckInterval);
|
|
695
703
|
this.logoutEvent.emit();
|
|
696
|
-
|
|
704
|
+
let sessionUrl = this._headerSer.headerConfig.signOutUrl;
|
|
705
|
+
if (this._headerSer.headerConfig.enableLastUrlRedirection) {
|
|
706
|
+
const separator = sessionUrl.includes('?') ? '&' : '?';
|
|
707
|
+
sessionUrl = sessionUrl + separator + 'returnUrl=' + encodeURIComponent(window.location.href);
|
|
708
|
+
}
|
|
709
|
+
signOut({ global: true, oauth: { redirectUrl: sessionUrl } })
|
|
697
710
|
.then((data) => {
|
|
698
|
-
window.open(
|
|
711
|
+
window.open(sessionUrl, '_self');
|
|
699
712
|
})
|
|
700
713
|
.catch((err) => {
|
|
701
714
|
console.log(err);
|
|
702
|
-
signOut({ global: true, oauth: { redirectUrl:
|
|
715
|
+
signOut({ global: true, oauth: { redirectUrl: sessionUrl } })
|
|
703
716
|
.then(() => {
|
|
704
|
-
window.open(
|
|
717
|
+
window.open(sessionUrl, '_self');
|
|
705
718
|
})
|
|
706
719
|
.catch((error) => console.log(error));
|
|
707
720
|
});
|