@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
|
@@ -218,6 +218,8 @@ class Utilities {
|
|
|
218
218
|
class CommonHeaderService {
|
|
219
219
|
constructor(config) {
|
|
220
220
|
this.config = config;
|
|
221
|
+
this.SESSION_EXPIRED_KEY = 'session_expired';
|
|
222
|
+
this.LAST_ACTIVE_SESSION_KEY = 'lastActiveSessionTime';
|
|
221
223
|
this.baseUrl = '';
|
|
222
224
|
this.isSessionExpiryDialogOpen = false;
|
|
223
225
|
this._apiGatewayService = inject(ApiGatewayService);
|
|
@@ -311,6 +313,63 @@ class CommonHeaderService {
|
|
|
311
313
|
let url = `${this.baseUrl + EndPoints.API_URLS.updateLastAccessedApplication}`;
|
|
312
314
|
return this._apiGatewayService.doPost(url, reqBody);
|
|
313
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Helper to get the root domain (e.g. .profet.ai) to share cookies across subdomains/ports.
|
|
318
|
+
* If on localhost or an IP, it falls back to the hostname.
|
|
319
|
+
*/
|
|
320
|
+
getRootDomain() {
|
|
321
|
+
const hostname = window.location.hostname;
|
|
322
|
+
const parts = hostname.split('.');
|
|
323
|
+
if (parts.length > 2 && !/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(hostname)) {
|
|
324
|
+
// If we have 4+ parts (e.g. app1.local.profet.ai), we want to include the environment (local.profet.ai)
|
|
325
|
+
// to avoid sharing cookies with app1.dev.profet.ai or app1.profet.ai.
|
|
326
|
+
if (parts.length > 3) {
|
|
327
|
+
return '.' + parts.slice(-3).join('.');
|
|
328
|
+
}
|
|
329
|
+
// For standard 3 parts (app1.profet.ai), share on .profet.ai
|
|
330
|
+
return '.' + parts.slice(-2).join('.');
|
|
331
|
+
}
|
|
332
|
+
return hostname;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Generates a unique cookie name based on the environment root domain.
|
|
336
|
+
* e.g. 'lastActive' on .qa.profet.ai -> 'lastActive_qa_profet_ai'
|
|
337
|
+
* @param name Base cookie name
|
|
338
|
+
*/
|
|
339
|
+
getSuffixedCookieName(name) {
|
|
340
|
+
const rootDomain = this.getRootDomain();
|
|
341
|
+
// Replace dots with underscores to create a clean suffix
|
|
342
|
+
const suffix = rootDomain.replace(/\./g, '_');
|
|
343
|
+
return `${name}${suffix}`;
|
|
344
|
+
}
|
|
345
|
+
setCookie(name, value, days) {
|
|
346
|
+
const uniqueName = this.getSuffixedCookieName(name);
|
|
347
|
+
let expires = "";
|
|
348
|
+
if (days) {
|
|
349
|
+
const date = new Date();
|
|
350
|
+
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
|
351
|
+
expires = "; expires=" + date.toUTCString();
|
|
352
|
+
}
|
|
353
|
+
// Important: set domain to allow sharing across subdomains
|
|
354
|
+
const domain = "; domain=" + this.getRootDomain();
|
|
355
|
+
document.cookie = uniqueName + "=" + (value || "") + expires + domain + "; path=/";
|
|
356
|
+
}
|
|
357
|
+
getCookie(name) {
|
|
358
|
+
const uniqueName = this.getSuffixedCookieName(name);
|
|
359
|
+
const nameEQ = uniqueName + "=";
|
|
360
|
+
const ca = document.cookie.split(';');
|
|
361
|
+
for (let i = 0; i < ca.length; i++) {
|
|
362
|
+
let c = ca[i];
|
|
363
|
+
while (c.charAt(0) == ' ')
|
|
364
|
+
c = c.substring(1, c.length);
|
|
365
|
+
if (c.indexOf(nameEQ) == 0)
|
|
366
|
+
return c.substring(nameEQ.length, c.length);
|
|
367
|
+
}
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
deleteCookie(name) {
|
|
371
|
+
this.setCookie(name, '', -1);
|
|
372
|
+
}
|
|
314
373
|
}
|
|
315
374
|
CommonHeaderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CommonHeaderService, deps: [{ token: 'headerConfig' }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
316
375
|
CommonHeaderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CommonHeaderService, providedIn: 'root' });
|
|
@@ -445,74 +504,20 @@ class HeaderComponent {
|
|
|
445
504
|
// }
|
|
446
505
|
this.resetTimer();
|
|
447
506
|
// Clear any stale logout signal on init
|
|
448
|
-
this.setCookie(
|
|
507
|
+
this._headerSer.setCookie(this._headerSer.SESSION_EXPIRED_KEY, '', -1);
|
|
449
508
|
this.startLogoutCheck();
|
|
450
509
|
}
|
|
451
|
-
/**
|
|
452
|
-
* Helper to get the root domain (e.g. .mycom.ai) to share cookies across subdomains/ports.
|
|
453
|
-
* If on localhost or an IP, it falls back to the hostname.
|
|
454
|
-
*/
|
|
455
|
-
getRootDomain() {
|
|
456
|
-
const hostname = window.location.hostname;
|
|
457
|
-
const parts = hostname.split('.');
|
|
458
|
-
if (parts.length > 2 && !/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(hostname)) {
|
|
459
|
-
// If we have 4+ parts (e.g. app1.local.profet.ai), we want to include the environment (local.profet.ai)
|
|
460
|
-
// to avoid sharing cookies with app1.dev.profet.ai or app1.profet.ai.
|
|
461
|
-
if (parts.length > 3) {
|
|
462
|
-
return '.' + parts.slice(-3).join('.');
|
|
463
|
-
}
|
|
464
|
-
// For standard 3 parts (app1.profet.ai), share on .profet.ai
|
|
465
|
-
return '.' + parts.slice(-2).join('.');
|
|
466
|
-
}
|
|
467
|
-
return hostname;
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* Generates a unique cookie name based on the environment root domain.
|
|
471
|
-
* e.g. 'lastActive' on .qa.profet.ai -> 'lastActive_qa_profet_ai'
|
|
472
|
-
* @param name Base cookie name
|
|
473
|
-
*/
|
|
474
|
-
getSuffixedCookieName(name) {
|
|
475
|
-
const rootDomain = this.getRootDomain();
|
|
476
|
-
// Replace dots with underscores to create a clean suffix
|
|
477
|
-
const suffix = rootDomain.replace(/\./g, '_');
|
|
478
|
-
return `${name}${suffix}`;
|
|
479
|
-
}
|
|
480
|
-
setCookie(name, value, days) {
|
|
481
|
-
const uniqueName = this.getSuffixedCookieName(name);
|
|
482
|
-
let expires = "";
|
|
483
|
-
if (days) {
|
|
484
|
-
const date = new Date();
|
|
485
|
-
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
|
486
|
-
expires = "; expires=" + date.toUTCString();
|
|
487
|
-
}
|
|
488
|
-
// Important: set domain to allow sharing across subdomains
|
|
489
|
-
const domain = "; domain=" + this.getRootDomain();
|
|
490
|
-
document.cookie = uniqueName + "=" + (value || "") + expires + domain + "; path=/";
|
|
491
|
-
}
|
|
492
|
-
getCookie(name) {
|
|
493
|
-
const uniqueName = this.getSuffixedCookieName(name);
|
|
494
|
-
const nameEQ = uniqueName + "=";
|
|
495
|
-
const ca = document.cookie.split(';');
|
|
496
|
-
for (let i = 0; i < ca.length; i++) {
|
|
497
|
-
let c = ca[i];
|
|
498
|
-
while (c.charAt(0) == ' ')
|
|
499
|
-
c = c.substring(1, c.length);
|
|
500
|
-
if (c.indexOf(nameEQ) == 0)
|
|
501
|
-
return c.substring(nameEQ.length, c.length);
|
|
502
|
-
}
|
|
503
|
-
return null;
|
|
504
|
-
}
|
|
505
510
|
resetTimer(isUserActivity = true) {
|
|
506
511
|
clearTimeout(this.inactivityTimeout);
|
|
507
512
|
// Update global activity timestamp in cookie ONLY if triggered by user activity
|
|
508
513
|
if (isUserActivity) {
|
|
509
514
|
// Use a short expiry (e.g. 1 day) or sync with session length
|
|
510
|
-
this.setCookie(
|
|
515
|
+
this._headerSer.setCookie(this._headerSer.LAST_ACTIVE_SESSION_KEY, Date.now().toString(), 1);
|
|
511
516
|
}
|
|
512
517
|
// if (!this._headerSer.isSessionExpiryDialogOpen) {
|
|
513
518
|
this.inactivityTimeout = setTimeout(() => {
|
|
514
519
|
// Check global activity before logging out
|
|
515
|
-
const lastActive = this.getCookie(
|
|
520
|
+
const lastActive = this._headerSer.getCookie(this._headerSer.LAST_ACTIVE_SESSION_KEY);
|
|
516
521
|
const now = Date.now();
|
|
517
522
|
const lastActiveTime = lastActive ? parseInt(lastActive, 10) : 0;
|
|
518
523
|
const elapsed = now - lastActiveTime;
|
|
@@ -534,11 +539,11 @@ class HeaderComponent {
|
|
|
534
539
|
startLogoutCheck() {
|
|
535
540
|
// Poll for the logout signal cookie (works across ports/subdomains)
|
|
536
541
|
this.logoutCheckInterval = setInterval(() => {
|
|
537
|
-
if (this.getCookie(
|
|
542
|
+
if (this._headerSer.getCookie(this._headerSer.SESSION_EXPIRED_KEY)) {
|
|
538
543
|
// Check if tab still "active" according to the shared time
|
|
539
544
|
// If tab is active but receiving a logout signal, it implies a MANUAL logout from another tab.
|
|
540
545
|
// If tab is inactive and receiving a logout signal, it implies a TIMEOUT.
|
|
541
|
-
const lastActive = this.getCookie(
|
|
546
|
+
const lastActive = this._headerSer.getCookie(this._headerSer.LAST_ACTIVE_SESSION_KEY);
|
|
542
547
|
const now = Date.now();
|
|
543
548
|
const lastActiveTime = lastActive ? parseInt(lastActive, 10) : 0;
|
|
544
549
|
const elapsed = now - lastActiveTime;
|
|
@@ -554,15 +559,18 @@ class HeaderComponent {
|
|
|
554
559
|
// }
|
|
555
560
|
if (broadcast) {
|
|
556
561
|
// Set a cookie to signal other tabs/ports
|
|
557
|
-
this.setCookie(
|
|
562
|
+
this._headerSer.setCookie(this._headerSer.SESSION_EXPIRED_KEY, 'true', 1);
|
|
558
563
|
}
|
|
559
564
|
this.logoutEvent.emit();
|
|
560
565
|
let sessionUrl = this._headerSer.headerConfig.signOutUrl;
|
|
566
|
+
if (this._headerSer.headerConfig.enableLastUrlRedirection) {
|
|
567
|
+
const separator = sessionUrl.includes('?') ? '&' : '?';
|
|
568
|
+
sessionUrl = sessionUrl + separator + 'returnUrl=' + encodeURIComponent(window.location.href);
|
|
569
|
+
}
|
|
561
570
|
// Only add sessionExpired params if it is NOT a manual logout
|
|
562
571
|
if (!isManual) {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
sessionUrl = appUrl + separator + 'sessionExpired=true&timeout=' + this.INACTIVITY_LIMIT;
|
|
572
|
+
const separator = sessionUrl.includes('?') ? '&' : '?';
|
|
573
|
+
sessionUrl = sessionUrl + separator + 'sessionExpired=true&timeout=' + this.INACTIVITY_LIMIT;
|
|
566
574
|
}
|
|
567
575
|
signOut({ global: true, oauth: { redirectUrl: sessionUrl } })
|
|
568
576
|
.then(() => {
|
|
@@ -672,22 +680,27 @@ class HeaderComponent {
|
|
|
672
680
|
onLogoutClick() {
|
|
673
681
|
this.menuTrigger.closeMenu();
|
|
674
682
|
// Sync with other tabs
|
|
675
|
-
this.setCookie(
|
|
683
|
+
this._headerSer.setCookie(this._headerSer.SESSION_EXPIRED_KEY, 'true', 1);
|
|
676
684
|
// Clear timers
|
|
677
685
|
if (this.inactivityTimeout)
|
|
678
686
|
clearTimeout(this.inactivityTimeout);
|
|
679
687
|
if (this.logoutCheckInterval)
|
|
680
688
|
clearInterval(this.logoutCheckInterval);
|
|
681
689
|
this.logoutEvent.emit();
|
|
682
|
-
|
|
690
|
+
let sessionUrl = this._headerSer.headerConfig.signOutUrl;
|
|
691
|
+
if (this._headerSer.headerConfig.enableLastUrlRedirection) {
|
|
692
|
+
const separator = sessionUrl.includes('?') ? '&' : '?';
|
|
693
|
+
sessionUrl = sessionUrl + separator + 'returnUrl=' + encodeURIComponent(window.location.href);
|
|
694
|
+
}
|
|
695
|
+
signOut({ global: true, oauth: { redirectUrl: sessionUrl } })
|
|
683
696
|
.then((data) => {
|
|
684
|
-
window.open(
|
|
697
|
+
window.open(sessionUrl, '_self');
|
|
685
698
|
})
|
|
686
699
|
.catch((err) => {
|
|
687
700
|
console.log(err);
|
|
688
|
-
signOut({ global: true, oauth: { redirectUrl:
|
|
701
|
+
signOut({ global: true, oauth: { redirectUrl: sessionUrl } })
|
|
689
702
|
.then(() => {
|
|
690
|
-
window.open(
|
|
703
|
+
window.open(sessionUrl, '_self');
|
|
691
704
|
})
|
|
692
705
|
.catch((error) => console.log(error));
|
|
693
706
|
});
|