aril 1.2.18 → 2.0.1-dev.0
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/boot/bridge/src/mfe-bridge.d.ts +42 -2
- package/boot/config/apps/index.d.ts +7 -1
- package/boot/config/apps/src/custom-reuse-outlet.component.d.ts +37 -0
- package/boot/config/apps/src/custom-route-reuse-strategy.class.d.ts +156 -0
- package/boot/config/apps/src/nav-link-context-menu.service.d.ts +33 -0
- package/boot/config/apps/src/nav-link.directive.d.ts +29 -0
- package/boot/config/apps/src/nav.service.d.ts +198 -0
- package/boot/config/apps/src/route-close.service.d.ts +9 -0
- package/boot/config/apps/src/safe-navigate.d.ts +17 -0
- package/boot/config/apps/src/tab-aware-url-serializer.d.ts +22 -0
- package/boot/config/plugins/src/getNgZone.d.ts +9 -1
- package/boot/mfe/src/app.component.d.ts +15 -4
- package/boot/mfe/src/isolated-location-strategy.d.ts +57 -0
- package/esm2022/boot/bridge/src/mfe-bridge.mjs +36 -5
- package/esm2022/boot/config/api/src/api.service.mjs +12 -3
- package/esm2022/boot/config/apps/index.mjs +8 -2
- package/esm2022/boot/config/apps/src/apps.service.mjs +14 -6
- package/esm2022/boot/config/apps/src/custom-reuse-outlet.component.mjs +207 -0
- package/esm2022/boot/config/apps/src/custom-route-reuse-strategy.class.mjs +540 -0
- package/esm2022/boot/config/apps/src/nav-link-context-menu.service.mjs +105 -0
- package/esm2022/boot/config/apps/src/nav-link.directive.mjs +45 -0
- package/esm2022/boot/config/apps/src/nav.service.mjs +675 -0
- package/esm2022/boot/config/apps/src/route-close.service.mjs +19 -0
- package/esm2022/boot/config/apps/src/safe-navigate.mjs +50 -0
- package/esm2022/boot/config/apps/src/tab-aware-url-serializer.mjs +50 -0
- package/esm2022/boot/config/plugins/src/getNgZone.mjs +13 -5
- package/esm2022/boot/host/src/app.component.mjs +1 -2
- package/esm2022/boot/host/src/bootstrap.mjs +22 -7
- package/esm2022/boot/mfe/src/app.component.mjs +143 -39
- package/esm2022/boot/mfe/src/bootstrap.mjs +197 -20
- package/esm2022/boot/mfe/src/isolated-location-strategy.mjs +142 -0
- package/esm2022/keycloak/src/auth.interceptor.mjs +17 -2
- package/esm2022/provider/src/prodiveHost.mjs +3 -5
- package/esm2022/provider/src/prodiveHostRouter.mjs +88 -9
- package/esm2022/theme/layout/app/expandableMenu/expandable-menu.component.mjs +81 -19
- package/esm2022/theme/layout/app/favorite-pages/favorite-pages-sidebar.component.mjs +6 -4
- package/esm2022/theme/layout/app/general-search/general-search.component.mjs +4 -4
- package/esm2022/theme/layout/app/history/history-sidebar.component.mjs +6 -4
- package/esm2022/theme/layout/app/layout/app.layout.component.mjs +422 -20
- package/esm2022/theme/layout/app/layout/mfe.layout.component.mjs +24 -35
- package/esm2022/theme/layout/app/site-map/site-map-sidebar.component.mjs +6 -4
- package/esm2022/theme/layout/app/static-sidebar/static-sidebar.component.mjs +85 -27
- package/esm2022/theme/layout/app/topbar/app.topbar.component.mjs +3 -3
- package/esm2022/theme/layout/service/breadcrumb-publisher.service.mjs +86 -0
- package/esm2022/theme/layout/service/tab-session.service.mjs +126 -0
- package/esm2022/ui-business/ref-value/src/ref-value.component.mjs +15 -7
- package/esm2022/util/sync-active-tab-route/src/sync-active-tab-route.directive.mjs +29 -9
- package/fesm2022/aril-app.component-s14ruALV.mjs +183 -0
- package/fesm2022/aril-app.component-s14ruALV.mjs.map +1 -0
- package/fesm2022/aril-boot-bridge.mjs +35 -4
- package/fesm2022/aril-boot-bridge.mjs.map +1 -1
- package/fesm2022/aril-boot-config-api.mjs +11 -2
- package/fesm2022/aril-boot-config-api.mjs.map +1 -1
- package/fesm2022/aril-boot-config-apps.mjs +1678 -10
- package/fesm2022/aril-boot-config-apps.mjs.map +1 -1
- package/fesm2022/aril-boot-config-plugins.mjs +12 -4
- package/fesm2022/aril-boot-config-plugins.mjs.map +1 -1
- package/fesm2022/aril-boot-host.mjs +21 -7
- package/fesm2022/aril-boot-host.mjs.map +1 -1
- package/fesm2022/aril-boot-mfe-app.component-a34GeuUv.mjs +183 -0
- package/fesm2022/aril-boot-mfe-app.component-a34GeuUv.mjs.map +1 -0
- package/fesm2022/aril-boot-mfe-aril-boot-mfe-KFO_X7yR.mjs +631 -0
- package/fesm2022/aril-boot-mfe-aril-boot-mfe-KFO_X7yR.mjs.map +1 -0
- package/fesm2022/aril-boot-mfe.mjs +5 -3
- package/fesm2022/aril-boot-mfe.mjs.map +1 -1
- package/fesm2022/aril-keycloak.mjs +16 -1
- package/fesm2022/aril-keycloak.mjs.map +1 -1
- package/fesm2022/aril-provider.mjs +90 -12
- package/fesm2022/aril-provider.mjs.map +1 -1
- package/fesm2022/aril-theme-layout.mjs +2630 -2017
- package/fesm2022/aril-theme-layout.mjs.map +1 -1
- package/fesm2022/aril-ui-business-ref-value.mjs +14 -6
- package/fesm2022/aril-ui-business-ref-value.mjs.map +1 -1
- package/fesm2022/aril-util-sync-active-tab-route.mjs +28 -8
- package/fesm2022/aril-util-sync-active-tab-route.mjs.map +1 -1
- package/fesm2022/aril.mjs +354 -25
- package/fesm2022/aril.mjs.map +1 -1
- package/keycloak/src/auth.interceptor.d.ts +7 -0
- package/package.json +216 -216
- package/provider/src/prodiveHost.d.ts +1 -0
- package/theme/layout/app/expandableMenu/expandable-menu.component.d.ts +21 -4
- package/theme/layout/app/expandableMenu/expandable-menu.component.html +19 -5
- package/theme/layout/app/expandableMenu/expandable-menu.component.ts +69 -9
- package/theme/layout/app/favorite-pages/favorite-pages-sidebar.component.html +1 -0
- package/theme/layout/app/favorite-pages/favorite-pages-sidebar.component.ts +3 -1
- package/theme/layout/app/general-search/general-search.component.html +2 -1
- package/theme/layout/app/general-search/general-search.component.ts +2 -2
- package/theme/layout/app/history/history-sidebar.component.html +3 -1
- package/theme/layout/app/history/history-sidebar.component.ts +3 -1
- package/theme/layout/app/layout/app.layout.component.d.ts +105 -5
- package/theme/layout/app/layout/app.layout.component.html +102 -1
- package/theme/layout/app/layout/app.layout.component.scss +372 -0
- package/theme/layout/app/layout/app.layout.component.ts +452 -13
- package/theme/layout/app/layout/mfe.layout.component.d.ts +7 -5
- package/theme/layout/app/layout/mfe.layout.component.ts +13 -39
- package/theme/layout/app/site-map/site-map-sidebar.component.html +1 -0
- package/theme/layout/app/site-map/site-map-sidebar.component.ts +3 -1
- package/theme/layout/app/static-sidebar/static-sidebar.component.d.ts +26 -5
- package/theme/layout/app/static-sidebar/static-sidebar.component.html +11 -5
- package/theme/layout/app/static-sidebar/static-sidebar.component.ts +68 -13
- package/theme/layout/app/topbar/app.topbar.component.html +0 -1
- package/theme/layout/app/topbar/app.topbar.component.scss +1 -1
- package/theme/layout/service/breadcrumb-publisher.service.d.ts +24 -0
- package/theme/layout/service/breadcrumb-publisher.service.ts +95 -0
- package/theme/layout/service/tab-session.service.d.ts +52 -0
- package/theme/layout/service/tab-session.service.ts +138 -0
- package/theme/styles/layout/_breadcrumb.scss +95 -0
- package/theme/styles/layout/_content.scss +2 -2
- package/ui-business/ref-value/src/ref-value.component.d.ts +4 -2
- package/util/sync-active-tab-route/src/sync-active-tab-route.directive.d.ts +15 -2
- package/boot/config/apps/src/reuse-strategy.d.ts +0 -4
- package/esm2022/boot/config/apps/src/reuse-strategy.mjs +0 -9
- package/esm2022/theme/layout/app/breadcrumb/app.breadcrumb.component.mjs +0 -107
- package/fesm2022/aril-app.component-wxP3y8dg.mjs +0 -81
- package/fesm2022/aril-app.component-wxP3y8dg.mjs.map +0 -1
- package/fesm2022/aril-boot-mfe-app.component-7IjAmjz0.mjs +0 -80
- package/fesm2022/aril-boot-mfe-app.component-7IjAmjz0.mjs.map +0 -1
- package/fesm2022/aril-boot-mfe-aril-boot-mfe-KXDpUyv7.mjs +0 -315
- package/fesm2022/aril-boot-mfe-aril-boot-mfe-KXDpUyv7.mjs.map +0 -1
- package/theme/layout/app/breadcrumb/app.breadcrumb.component.d.ts +0 -25
- package/theme/layout/app/breadcrumb/app.breadcrumb.component.html +0 -8
- package/theme/layout/app/breadcrumb/app.breadcrumb.component.ts +0 -127
|
@@ -1,35 +1,55 @@
|
|
|
1
1
|
import { Directive, HostListener } from '@angular/core';
|
|
2
2
|
import { Subscription } from 'rxjs';
|
|
3
|
+
import { bridge } from 'aril/boot/bridge';
|
|
3
4
|
import * as i0 from "@angular/core";
|
|
4
5
|
import * as i1 from "@angular/router";
|
|
5
6
|
import * as i2 from "primeng/tabview";
|
|
6
7
|
import * as i3 from "@angular/common";
|
|
7
8
|
export class SyncActiveTabRouteDirective {
|
|
8
|
-
constructor(router, tabView, location) {
|
|
9
|
+
constructor(router, tabView, location, urlSerializer) {
|
|
9
10
|
this.router = router;
|
|
10
11
|
this.tabView = tabView;
|
|
11
12
|
this.location = location;
|
|
13
|
+
this.urlSerializer = urlSerializer;
|
|
12
14
|
this.subscription = new Subscription();
|
|
15
|
+
/**
|
|
16
|
+
* Host (shell) modunda MFE Router `IsolatedLocationStrategy` kullanır — browser hash'ına
|
|
17
|
+
* YAZMAZ (tab izolasyonu, bkz. `isolated-location-strategy.ts`). Bu yüzden `?activeTab`
|
|
18
|
+
* adres çubuğunda görünsün/okunsun diye HOST Router + HOST Location'a köprüleriz.
|
|
19
|
+
* Standalone MFE modunda (`bridge.hostRouter` null) eski davranış korunur: enjekte edilen
|
|
20
|
+
* child Router + child Location (gerçek `LocationStrategy` adres çubuğuna yazar).
|
|
21
|
+
*
|
|
22
|
+
* `replaceState` (navigate DEĞİL) kullanılır: NavigationEnd fire ETMEZ → app.component'in
|
|
23
|
+
* host-NavigationEnd handler'ı tetiklenmez → MFE yeniden navigate olmaz (döngü yok).
|
|
24
|
+
*/
|
|
25
|
+
this.hostRouter = bridge.hostRouter;
|
|
26
|
+
this.effectiveRouter = this.hostRouter ?? this.router;
|
|
13
27
|
}
|
|
14
28
|
ngOnInit() {
|
|
15
|
-
this.subscription.add(this.
|
|
29
|
+
this.subscription.add(this.effectiveRouter.routerState.root.queryParamMap.subscribe((params) => {
|
|
16
30
|
if (params.has('activeTab')) {
|
|
17
31
|
this.tabView.activeIndex = Number(params.get('activeTab'));
|
|
18
32
|
}
|
|
19
33
|
}));
|
|
20
34
|
}
|
|
21
35
|
onTabChange(e) {
|
|
22
|
-
|
|
23
|
-
|
|
36
|
+
// `UrlTree.toString()` built-in `DefaultUrlSerializer` kullanır → `_tab` adres çubuğunda
|
|
37
|
+
// görünür kalırdı. Router'a kayıtlı `UrlSerializer` (child injector'da
|
|
38
|
+
// `TabAwareUrlSerializer`) ile serialize edip `_tab`'ı gizliyoruz; `activeTab` korunur.
|
|
39
|
+
const url = this.urlSerializer.serialize(this.effectiveRouter.createUrlTree([], {
|
|
24
40
|
queryParams: { activeTab: e },
|
|
25
41
|
queryParamsHandling: 'merge'
|
|
26
|
-
})
|
|
27
|
-
|
|
42
|
+
}));
|
|
43
|
+
const location = this.hostRouter ? bridge.hostLocation : this.location;
|
|
44
|
+
// `history.state` (içindeki `_tab`) KORUNMALI: `Location.replaceState(path, query, state)`
|
|
45
|
+
// default `state=null` — 3. argüman verilmezse `_tab` silinir ve tab tespiti
|
|
46
|
+
// (`nav.service`/`app.component` `history.state._tab` okur) bozulur.
|
|
47
|
+
location?.replaceState(url, '', window.history.state);
|
|
28
48
|
}
|
|
29
49
|
ngOnDestroy() {
|
|
30
50
|
this.subscription.unsubscribe();
|
|
31
51
|
}
|
|
32
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: SyncActiveTabRouteDirective, deps: [{ token: i1.Router }, { token: i2.TabView }, { token: i3.Location }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
52
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: SyncActiveTabRouteDirective, deps: [{ token: i1.Router }, { token: i2.TabView }, { token: i3.Location }, { token: i1.UrlSerializer }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
33
53
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.1.2", type: SyncActiveTabRouteDirective, isStandalone: true, selector: "[syncActiveTabRoute]", host: { listeners: { "activeIndexChange": "onTabChange($event)" } }, ngImport: i0 }); }
|
|
34
54
|
}
|
|
35
55
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: SyncActiveTabRouteDirective, decorators: [{
|
|
@@ -38,8 +58,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
|
|
|
38
58
|
selector: '[syncActiveTabRoute]',
|
|
39
59
|
standalone: true
|
|
40
60
|
}]
|
|
41
|
-
}], ctorParameters: () => [{ type: i1.Router }, { type: i2.TabView }, { type: i3.Location }], propDecorators: { onTabChange: [{
|
|
61
|
+
}], ctorParameters: () => [{ type: i1.Router }, { type: i2.TabView }, { type: i3.Location }, { type: i1.UrlSerializer }], propDecorators: { onTabChange: [{
|
|
42
62
|
type: HostListener,
|
|
43
63
|
args: ['activeIndexChange', ['$event']]
|
|
44
64
|
}] } });
|
|
45
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
65
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1hY3RpdmUtdGFiLXJvdXRlLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FyaWwvdXRpbC9zeW5jLWFjdGl2ZS10YWItcm91dGUvc3JjL3N5bmMtYWN0aXZlLXRhYi1yb3V0ZS5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQXFCLE1BQU0sZUFBZSxDQUFDO0FBSzNFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFcEMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGtCQUFrQixDQUFDOzs7OztBQU0xQyxNQUFNLE9BQU8sMkJBQTJCO0lBZ0J2QyxZQUNrQixNQUFjLEVBQ2QsT0FBZ0IsRUFDaEIsUUFBa0IsRUFDbEIsYUFBNEI7UUFINUIsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQUNkLFlBQU8sR0FBUCxPQUFPLENBQVM7UUFDaEIsYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQUNsQixrQkFBYSxHQUFiLGFBQWEsQ0FBZTtRQW5CN0IsaUJBQVksR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBRW5EOzs7Ozs7Ozs7V0FTRztRQUNjLGVBQVUsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDO1FBUy9DLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDLFVBQVUsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDO0lBQ3ZELENBQUM7SUFFRCxRQUFRO1FBQ1AsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQ3BCLElBQUksQ0FBQyxlQUFlLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUU7WUFDeEUsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7Z0JBQzdCLElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7WUFDNUQsQ0FBQztRQUNGLENBQUMsQ0FBQyxDQUNGLENBQUM7SUFDSCxDQUFDO0lBR0QsV0FBVyxDQUFDLENBQVM7UUFDcEIseUZBQXlGO1FBQ3pGLHVFQUF1RTtRQUN2RSx3RkFBd0Y7UUFDeEYsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQ3ZDLElBQUksQ0FBQyxlQUFlLENBQUMsYUFBYSxDQUFDLEVBQUUsRUFBRTtZQUN0QyxXQUFXLEVBQUUsRUFBRSxTQUFTLEVBQUUsQ0FBQyxFQUFFO1lBQzdCLG1CQUFtQixFQUFFLE9BQU87U0FDNUIsQ0FBQyxDQUNGLENBQUM7UUFFRixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO1FBQ3ZFLDJGQUEyRjtRQUMzRiw2RUFBNkU7UUFDN0UscUVBQXFFO1FBQ3JFLFFBQVEsRUFBRSxZQUFZLENBQUMsR0FBRyxFQUFFLEVBQUUsRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3ZELENBQUM7SUFFRCxXQUFXO1FBQ1YsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNqQyxDQUFDOzhHQXhEVywyQkFBMkI7a0dBQTNCLDJCQUEyQjs7MkZBQTNCLDJCQUEyQjtrQkFKdkMsU0FBUzttQkFBQztvQkFDVixRQUFRLEVBQUUsc0JBQXNCO29CQUNoQyxVQUFVLEVBQUUsSUFBSTtpQkFDaEI7b0pBcUNBLFdBQVc7c0JBRFYsWUFBWTt1QkFBQyxtQkFBbUIsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IExvY2F0aW9uIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuaW1wb3J0IHsgRGlyZWN0aXZlLCBIb3N0TGlzdGVuZXIsIE9uRGVzdHJveSwgT25Jbml0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IFJvdXRlciwgVXJsU2VyaWFsaXplciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XHJcblxyXG5pbXBvcnQgeyBUYWJWaWV3IH0gZnJvbSAncHJpbWVuZy90YWJ2aWV3JztcclxuXHJcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xyXG5cclxuaW1wb3J0IHsgYnJpZGdlIH0gZnJvbSAnYXJpbC9ib290L2JyaWRnZSc7XHJcblxyXG5ARGlyZWN0aXZlKHtcclxuXHRzZWxlY3RvcjogJ1tzeW5jQWN0aXZlVGFiUm91dGVdJyxcclxuXHRzdGFuZGFsb25lOiB0cnVlXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBTeW5jQWN0aXZlVGFiUm91dGVEaXJlY3RpdmUgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XHJcblx0cHJpdmF0ZSByZWFkb25seSBzdWJzY3JpcHRpb24gPSBuZXcgU3Vic2NyaXB0aW9uKCk7XHJcblxyXG5cdC8qKlxyXG5cdCAqIEhvc3QgKHNoZWxsKSBtb2R1bmRhIE1GRSBSb3V0ZXIgYElzb2xhdGVkTG9jYXRpb25TdHJhdGVneWAga3VsbGFuxLFyIOKAlCBicm93c2VyIGhhc2gnxLFuYVxyXG5cdCAqIFlBWk1BWiAodGFiIGl6b2xhc3lvbnUsIGJrei4gYGlzb2xhdGVkLWxvY2F0aW9uLXN0cmF0ZWd5LnRzYCkuIEJ1IHnDvHpkZW4gYD9hY3RpdmVUYWJgXHJcblx0ICogYWRyZXMgw6d1YnXEn3VuZGEgZ8O2csO8bnPDvG4vb2t1bnN1biBkaXllIEhPU1QgUm91dGVyICsgSE9TVCBMb2NhdGlvbidhIGvDtnByw7xsZXJpei5cclxuXHQgKiBTdGFuZGFsb25lIE1GRSBtb2R1bmRhIChgYnJpZGdlLmhvc3RSb3V0ZXJgIG51bGwpIGVza2kgZGF2cmFuxLHFnyBrb3J1bnVyOiBlbmpla3RlIGVkaWxlblxyXG5cdCAqIGNoaWxkIFJvdXRlciArIGNoaWxkIExvY2F0aW9uIChnZXLDp2VrIGBMb2NhdGlvblN0cmF0ZWd5YCBhZHJlcyDDp3VidcSfdW5hIHlhemFyKS5cclxuXHQgKlxyXG5cdCAqIGByZXBsYWNlU3RhdGVgIChuYXZpZ2F0ZSBERcSexLBMKSBrdWxsYW7EsWzEsXI6IE5hdmlnYXRpb25FbmQgZmlyZSBFVE1FWiDihpIgYXBwLmNvbXBvbmVudCdpblxyXG5cdCAqIGhvc3QtTmF2aWdhdGlvbkVuZCBoYW5kbGVyJ8SxIHRldGlrbGVubWV6IOKGkiBNRkUgeWVuaWRlbiBuYXZpZ2F0ZSBvbG1heiAoZMO2bmfDvCB5b2spLlxyXG5cdCAqL1xyXG5cdHByaXZhdGUgcmVhZG9ubHkgaG9zdFJvdXRlciA9IGJyaWRnZS5ob3N0Um91dGVyO1xyXG5cdHByaXZhdGUgcmVhZG9ubHkgZWZmZWN0aXZlUm91dGVyOiBSb3V0ZXI7XHJcblxyXG5cdGNvbnN0cnVjdG9yKFxyXG5cdFx0cHJpdmF0ZSByZWFkb25seSByb3V0ZXI6IFJvdXRlcixcclxuXHRcdHByaXZhdGUgcmVhZG9ubHkgdGFiVmlldzogVGFiVmlldyxcclxuXHRcdHByaXZhdGUgcmVhZG9ubHkgbG9jYXRpb246IExvY2F0aW9uLFxyXG5cdFx0cHJpdmF0ZSByZWFkb25seSB1cmxTZXJpYWxpemVyOiBVcmxTZXJpYWxpemVyXHJcblx0KSB7XHJcblx0XHR0aGlzLmVmZmVjdGl2ZVJvdXRlciA9IHRoaXMuaG9zdFJvdXRlciA/PyB0aGlzLnJvdXRlcjtcclxuXHR9XHJcblxyXG5cdG5nT25Jbml0KCkge1xyXG5cdFx0dGhpcy5zdWJzY3JpcHRpb24uYWRkKFxyXG5cdFx0XHR0aGlzLmVmZmVjdGl2ZVJvdXRlci5yb3V0ZXJTdGF0ZS5yb290LnF1ZXJ5UGFyYW1NYXAuc3Vic2NyaWJlKChwYXJhbXMpID0+IHtcclxuXHRcdFx0XHRpZiAocGFyYW1zLmhhcygnYWN0aXZlVGFiJykpIHtcclxuXHRcdFx0XHRcdHRoaXMudGFiVmlldy5hY3RpdmVJbmRleCA9IE51bWJlcihwYXJhbXMuZ2V0KCdhY3RpdmVUYWInKSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9KVxyXG5cdFx0KTtcclxuXHR9XHJcblxyXG5cdEBIb3N0TGlzdGVuZXIoJ2FjdGl2ZUluZGV4Q2hhbmdlJywgWyckZXZlbnQnXSlcclxuXHRvblRhYkNoYW5nZShlOiBudW1iZXIpIHtcclxuXHRcdC8vIGBVcmxUcmVlLnRvU3RyaW5nKClgIGJ1aWx0LWluIGBEZWZhdWx0VXJsU2VyaWFsaXplcmAga3VsbGFuxLFyIOKGkiBgX3RhYmAgYWRyZXMgw6d1YnXEn3VuZGFcclxuXHRcdC8vIGfDtnLDvG7DvHIga2FsxLFyZMSxLiBSb3V0ZXInYSBrYXnEsXRsxLEgYFVybFNlcmlhbGl6ZXJgIChjaGlsZCBpbmplY3RvcidkYVxyXG5cdFx0Ly8gYFRhYkF3YXJlVXJsU2VyaWFsaXplcmApIGlsZSBzZXJpYWxpemUgZWRpcCBgX3RhYmAnxLEgZ2l6bGl5b3J1ejsgYGFjdGl2ZVRhYmAga29ydW51ci5cclxuXHRcdGNvbnN0IHVybCA9IHRoaXMudXJsU2VyaWFsaXplci5zZXJpYWxpemUoXHJcblx0XHRcdHRoaXMuZWZmZWN0aXZlUm91dGVyLmNyZWF0ZVVybFRyZWUoW10sIHtcclxuXHRcdFx0XHRxdWVyeVBhcmFtczogeyBhY3RpdmVUYWI6IGUgfSxcclxuXHRcdFx0XHRxdWVyeVBhcmFtc0hhbmRsaW5nOiAnbWVyZ2UnXHJcblx0XHRcdH0pXHJcblx0XHQpO1xyXG5cclxuXHRcdGNvbnN0IGxvY2F0aW9uID0gdGhpcy5ob3N0Um91dGVyID8gYnJpZGdlLmhvc3RMb2NhdGlvbiA6IHRoaXMubG9jYXRpb247XHJcblx0XHQvLyBgaGlzdG9yeS5zdGF0ZWAgKGnDp2luZGVraSBgX3RhYmApIEtPUlVOTUFMSTogYExvY2F0aW9uLnJlcGxhY2VTdGF0ZShwYXRoLCBxdWVyeSwgc3RhdGUpYFxyXG5cdFx0Ly8gZGVmYXVsdCBgc3RhdGU9bnVsbGAg4oCUIDMuIGFyZ8O8bWFuIHZlcmlsbWV6c2UgYF90YWJgIHNpbGluaXIgdmUgdGFiIHRlc3BpdGlcclxuXHRcdC8vIChgbmF2LnNlcnZpY2VgL2BhcHAuY29tcG9uZW50YCBgaGlzdG9yeS5zdGF0ZS5fdGFiYCBva3VyKSBib3p1bHVyLlxyXG5cdFx0bG9jYXRpb24/LnJlcGxhY2VTdGF0ZSh1cmwsICcnLCB3aW5kb3cuaGlzdG9yeS5zdGF0ZSk7XHJcblx0fVxyXG5cclxuXHRuZ09uRGVzdHJveSgpIHtcclxuXHRcdHRoaXMuc3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XHJcblx0fVxyXG59XHJcbiJdfQ==
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { LocationStrategy } from '@angular/common';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { inject, ElementRef, effect, Component } from '@angular/core';
|
|
4
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
5
|
+
import * as i1 from '@angular/router';
|
|
6
|
+
import { EventType } from '@angular/router';
|
|
7
|
+
import { ModuleFederationToolsModule } from '@angular-architects/module-federation-tools';
|
|
8
|
+
import { safeNavigate } from 'aril/boot/config/apps';
|
|
9
|
+
import { LanguageCode, TR_TRANSLATIONS } from 'aril/boot/config/translate';
|
|
10
|
+
import { BreadcrumbService, MFELayoutComponent } from 'aril/theme/layout';
|
|
11
|
+
import { a as appName } from './aril.mjs';
|
|
12
|
+
import * as i2 from '@ngneat/transloco';
|
|
13
|
+
import * as i3 from 'primeng/api';
|
|
14
|
+
import * as i3$1 from 'aril/boot/bridge';
|
|
15
|
+
import '@angular/common/http';
|
|
16
|
+
import '@angular/platform-browser';
|
|
17
|
+
import 'keycloak-angular';
|
|
18
|
+
import 'aril/boot/base';
|
|
19
|
+
import 'aril/boot/config/api';
|
|
20
|
+
import 'aril/boot/config/plugins';
|
|
21
|
+
import 'aril/i18n';
|
|
22
|
+
import 'aril/util/pub-sub';
|
|
23
|
+
import 'ngx-monaco-editor-v2';
|
|
24
|
+
import 'aril/provider';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Tab izolasyonlu MFE app root.
|
|
28
|
+
*
|
|
29
|
+
* Her `<app-${appName}>` custom element instance'ı kendi `createApplication`'ını yarattığı için
|
|
30
|
+
* (bkz. `bootstrap.ts` `MFEAppElement`), `AppComponent` constructor'ı her tab için **bağımsız**
|
|
31
|
+
* çalışır — paylaşılan Injector/Router yok. Bu yüzden host Router subscription'ı her tab için
|
|
32
|
+
* ayrı kurulur ama "tab-id filter" ile **sadece o tab'a ait** `NavigationEnd`'leri MFE Router'a
|
|
33
|
+
* iletir; diğer tab'lerin navigation'ları ignore edilir.
|
|
34
|
+
*
|
|
35
|
+
* Tab kimliği `<app-${appName}>` element'inde `aril-tab-id` attribute olarak yazılır
|
|
36
|
+
* (`ArilWebComponentWrapper` route.queryParams._tab'ten okuyup set eder). Filter karşılaştırması:
|
|
37
|
+
* `window.history.state._tab === tabId` — `navigateToTab` `extras.state._tab` ile yazıyor.
|
|
38
|
+
*/
|
|
39
|
+
class AppComponent {
|
|
40
|
+
constructor(router, translocoService, primeNgConfig, bridgeSvc) {
|
|
41
|
+
this.router = router;
|
|
42
|
+
this.translocoService = translocoService;
|
|
43
|
+
this.primeNgConfig = primeNgConfig;
|
|
44
|
+
this.bridgeSvc = bridgeSvc;
|
|
45
|
+
this.elementRef = inject(ElementRef);
|
|
46
|
+
// Bu tab'ın kimliği — wrapper component `aril-tab-id` attribute olarak yazıyor.
|
|
47
|
+
// İlk yükleme cycle'ında URL'de henüz `_tab` yok; NavService `firstCheckForRoute`
|
|
48
|
+
// sonradan `replaceUrl` ile ekliyor. Wrapper queryParams.subscribe ile attribute'u
|
|
49
|
+
// güncelliyor — bu yüzden constructor'da değil, her NavigationEnd'de fresh okuyoruz.
|
|
50
|
+
const readMyTabId = () => this.elementRef.nativeElement.getAttribute('aril-tab-id') ?? '';
|
|
51
|
+
const initialTabId = readMyTabId();
|
|
52
|
+
const locStrategy = inject(LocationStrategy);
|
|
53
|
+
const sameRouter = this.router === this.bridgeSvc.hostRouter;
|
|
54
|
+
console.log(`[MFE:${appName}] host modu — tab="${initialTabId || '(pending)'}" ` +
|
|
55
|
+
`LocationStrategy=${locStrategy.constructor.name} ` +
|
|
56
|
+
`router===hostRouter? ${sameRouter}`);
|
|
57
|
+
const initial = this.bridgeSvc.hostRouter.url;
|
|
58
|
+
console.log(`[MFE:${appName}] initial sync:`, initial);
|
|
59
|
+
safeNavigate(this.router, initial);
|
|
60
|
+
// MFE içi `routerLink`/`router.navigate` host Router'a yansımıyor (IsolatedLocationStrategy
|
|
61
|
+
// browser hash'ı değiştirmiyor) — NavService tab navLink'ini güncelleyemiyor.
|
|
62
|
+
// MFE NavigationEnd'i `bridge.activeMFEUrl`'a (kaynak tabId ile) yazarız;
|
|
63
|
+
// AppLayoutComponent effect → `syncActiveTabNavLinkForTab(tabId, url)` ile sadece
|
|
64
|
+
// kaynak tab'ın navLink'i güncellenir → cross-tab kontaminasyonu yok.
|
|
65
|
+
// Tab title resolve — kaynak öncelik sırası (en spesifik → en geniş):
|
|
66
|
+
// 1. `route.title` (ÖNERİLEN — Angular Router 16+ standardı, sayfa <title>'ını da set eder)
|
|
67
|
+
// 2. `data.tabName` (ÖNERİLEN — tab adı sayfa <title>'ından farklı olmalıysa)
|
|
68
|
+
// 3. `data.title` (DEPRECATED — geriye uyumluluk için var; yeni route'larda kullanmayın,
|
|
69
|
+
// `route.title` ile aynı semantiği taşıyor ama Angular contract dışı kalıyor)
|
|
70
|
+
// 4. `data.breadcrumb` — mevcut breadcrumb template'i fallback olarak kullanılır
|
|
71
|
+
// (single-brace `{key}` placeholder, literal string, i18n YOK)
|
|
72
|
+
//
|
|
73
|
+
// i18n key'lerinde `{{placeholder}}` Transloco interpolation'ı `BreadcrumbService.keyValues`
|
|
74
|
+
// ile doldurulur. Component cevap geldiğinde `breadcrumbService.set('GatewayMaterialSerialNumber',
|
|
75
|
+
// '12345')` her iki path'i de besler — effect ile re-compute, dinamik tab adı
|
|
76
|
+
// ("12345 - Modem Detay").
|
|
77
|
+
const breadcrumbService = inject(BreadcrumbService);
|
|
78
|
+
const computeTabTitle = () => {
|
|
79
|
+
let route = this.router.routerState.snapshot.root;
|
|
80
|
+
while (route.firstChild)
|
|
81
|
+
route = route.firstChild;
|
|
82
|
+
const params = breadcrumbService.keyValues();
|
|
83
|
+
const i18nKey = route.title ??
|
|
84
|
+
route.data?.['title'] ??
|
|
85
|
+
route.data?.['tabName'];
|
|
86
|
+
if (i18nKey) {
|
|
87
|
+
const translated = this.translocoService.translate(i18nKey, params);
|
|
88
|
+
return translated || i18nKey;
|
|
89
|
+
}
|
|
90
|
+
const breadcrumb = route.data?.['breadcrumb'];
|
|
91
|
+
if (breadcrumb) {
|
|
92
|
+
return breadcrumb.replace(/\{([^}]+)\}/g, (_, key) => params[key] ?? '...');
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
};
|
|
96
|
+
let lastUrl;
|
|
97
|
+
let lastTabIdForTitle;
|
|
98
|
+
this.router.events.pipe(takeUntilDestroyed()).subscribe((event) => {
|
|
99
|
+
if (event.type === EventType.NavigationEnd) {
|
|
100
|
+
const url = event.urlAfterRedirects ?? event.url;
|
|
101
|
+
const myTabId = readMyTabId();
|
|
102
|
+
if (!myTabId)
|
|
103
|
+
return;
|
|
104
|
+
lastUrl = url;
|
|
105
|
+
lastTabIdForTitle = myTabId;
|
|
106
|
+
const title = computeTabTitle();
|
|
107
|
+
const prev = this.bridgeSvc.activeMFEUrl();
|
|
108
|
+
if (prev?.tabId === myTabId && prev?.url === url && prev?.title === title)
|
|
109
|
+
return;
|
|
110
|
+
this.bridgeSvc.activeMFEUrl.set({ tabId: myTabId, url, title });
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
// Component cevap gelince `breadcrumbService.set('meterNo', '12345')` keyValues'ı
|
|
114
|
+
// günceller; effect ile yakalayıp tab title'ı yeniden hesaplarız → "12345 - Sayaç
|
|
115
|
+
// Detayı" gibi dinamik sonuçlar tab adına yansır.
|
|
116
|
+
effect(() => {
|
|
117
|
+
breadcrumbService.keyValues();
|
|
118
|
+
if (!lastUrl || !lastTabIdForTitle)
|
|
119
|
+
return;
|
|
120
|
+
const title = computeTabTitle();
|
|
121
|
+
const prev = this.bridgeSvc.activeMFEUrl();
|
|
122
|
+
if (prev?.tabId === lastTabIdForTitle && prev?.url === lastUrl && prev?.title === title) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
this.bridgeSvc.activeMFEUrl.set({ tabId: lastTabIdForTitle, url: lastUrl, title });
|
|
126
|
+
}, { allowSignalWrites: true });
|
|
127
|
+
const mfePrefix = `/${appName}`;
|
|
128
|
+
this.bridgeSvc.hostRouter.events.pipe(takeUntilDestroyed()).subscribe((event) => {
|
|
129
|
+
if (event.type === EventType.NavigationEnd) {
|
|
130
|
+
const target = event.urlAfterRedirects ?? event.url;
|
|
131
|
+
if (target !== mfePrefix && !target.startsWith(`${mfePrefix}/`))
|
|
132
|
+
return;
|
|
133
|
+
// **Tab izolasyonu filter**: navigation'ın hedef tab'ı bu instance mı?
|
|
134
|
+
// `IsolatedLocationStrategy` sayesinde host'a sadece tab tıklamaları
|
|
135
|
+
// (`tabState({_tab})` ile) gelir — `history.state._tab` her zaman dolu.
|
|
136
|
+
const myTabId = readMyTabId();
|
|
137
|
+
if (myTabId) {
|
|
138
|
+
const navTabId = window.history.state?.['_tab'];
|
|
139
|
+
if (navTabId !== myTabId)
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
// `lastNavigated`/`router.url===target` early-return YOK: izole Router'da (her tab
|
|
143
|
+
// kendi Router'ı) bir tab'a geri dönüldüğünde MFE Router zaten hedef URL'dedir;
|
|
144
|
+
// navigate atlanırsa NavigationEnd fire etmez → `BreadcrumbPublisherService` yeniden
|
|
145
|
+
// yayın yapmaz ve app.layout tab geçişinde breadcrumb'ı `set([])` ile temizlediği için
|
|
146
|
+
// breadcrumb boş kalır. `onSameUrlNavigation:'reload'` aynı URL'e navigate'i
|
|
147
|
+
// NavigationEnd ile garanti eder → breadcrumb + tab navLink yeniden yayınlanır.
|
|
148
|
+
console.log(`[MFE:${appName}] tab="${myTabId || '(pending)'}" host NavigationEnd → navigate:`, target);
|
|
149
|
+
safeNavigate(this.router, target);
|
|
150
|
+
}
|
|
151
|
+
else if (event.type === EventType.NavigationCancel) {
|
|
152
|
+
console.warn(`[MFE:${appName}] host NavigationCancel:`, event.url, 'reason:', event.reason);
|
|
153
|
+
}
|
|
154
|
+
else if (event.type === EventType.NavigationError) {
|
|
155
|
+
console.error(`[MFE:${appName}] host NavigationError:`, event.url, 'err:', event.error);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
this.bridgeSvc.activeMF.set(appName);
|
|
159
|
+
const lang = localStorage.getItem('lang') ?? LanguageCode.TR;
|
|
160
|
+
this.translocoService.setActiveLang(lang);
|
|
161
|
+
this.setLocale(lang);
|
|
162
|
+
}
|
|
163
|
+
setLocale(lang) {
|
|
164
|
+
if (!lang?.length)
|
|
165
|
+
return;
|
|
166
|
+
if (lang === LanguageCode.TR) {
|
|
167
|
+
this.primeNgConfig.setTranslation(TR_TRANSLATIONS);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AppComponent, deps: [{ token: i1.Router }, { token: i2.TranslocoService }, { token: i3.PrimeNGConfig }, { token: i3$1.MfeBridge }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
171
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: AppComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: `<mfe-layout></mfe-layout>`, isInline: true, dependencies: [{ kind: "ngmodule", type: ModuleFederationToolsModule }, { kind: "component", type: MFELayoutComponent, selector: "mfe-layout" }] }); }
|
|
172
|
+
}
|
|
173
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AppComponent, decorators: [{
|
|
174
|
+
type: Component,
|
|
175
|
+
args: [{
|
|
176
|
+
standalone: true,
|
|
177
|
+
template: `<mfe-layout></mfe-layout>`,
|
|
178
|
+
imports: [ModuleFederationToolsModule, MFELayoutComponent]
|
|
179
|
+
}]
|
|
180
|
+
}], ctorParameters: () => [{ type: i1.Router }, { type: i2.TranslocoService }, { type: i3.PrimeNGConfig }, { type: i3$1.MfeBridge }] });
|
|
181
|
+
|
|
182
|
+
export { AppComponent };
|
|
183
|
+
//# sourceMappingURL=aril-app.component-s14ruALV.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aril-app.component-s14ruALV.mjs","sources":["../../projects/aril/boot/mfe/src/app.component.ts"],"sourcesContent":["import { LocationStrategy } from '@angular/common';\r\nimport { Component, ElementRef, effect, inject } from '@angular/core';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { EventType, Router, type Event as RouterEvent } from '@angular/router';\r\n\r\nimport { PrimeNGConfig } from 'primeng/api';\r\n\r\nimport { ModuleFederationToolsModule } from '@angular-architects/module-federation-tools';\r\nimport { TranslocoService } from '@ngneat/transloco';\r\n\r\nimport { MfeBridge } from 'aril/boot/bridge';\r\nimport { safeNavigate } from 'aril/boot/config/apps';\r\nimport { LanguageCode, TR_TRANSLATIONS } from 'aril/boot/config/translate';\r\nimport { BreadcrumbService, MFELayoutComponent } from 'aril/theme/layout';\r\n\r\nimport { appName } from './bootstrap';\r\n\r\n/**\r\n * Tab izolasyonlu MFE app root.\r\n *\r\n * Her `<app-${appName}>` custom element instance'ı kendi `createApplication`'ını yarattığı için\r\n * (bkz. `bootstrap.ts` `MFEAppElement`), `AppComponent` constructor'ı her tab için **bağımsız**\r\n * çalışır — paylaşılan Injector/Router yok. Bu yüzden host Router subscription'ı her tab için\r\n * ayrı kurulur ama \"tab-id filter\" ile **sadece o tab'a ait** `NavigationEnd`'leri MFE Router'a\r\n * iletir; diğer tab'lerin navigation'ları ignore edilir.\r\n *\r\n * Tab kimliği `<app-${appName}>` element'inde `aril-tab-id` attribute olarak yazılır\r\n * (`ArilWebComponentWrapper` route.queryParams._tab'ten okuyup set eder). Filter karşılaştırması:\r\n * `window.history.state._tab === tabId` — `navigateToTab` `extras.state._tab` ile yazıyor.\r\n */\r\n@Component({\r\n\tstandalone: true,\r\n\ttemplate: `<mfe-layout></mfe-layout>`,\r\n\timports: [ModuleFederationToolsModule, MFELayoutComponent]\r\n})\r\nexport class AppComponent {\r\n\tprivate readonly elementRef = inject(ElementRef);\r\n\r\n\tconstructor(\r\n\t\tprivate readonly router: Router,\r\n\t\tprivate readonly translocoService: TranslocoService,\r\n\t\tprivate readonly primeNgConfig: PrimeNGConfig,\r\n\t\tprivate readonly bridgeSvc: MfeBridge\r\n\t) {\r\n\t\t// Bu tab'ın kimliği — wrapper component `aril-tab-id` attribute olarak yazıyor.\r\n\t\t// İlk yükleme cycle'ında URL'de henüz `_tab` yok; NavService `firstCheckForRoute`\r\n\t\t// sonradan `replaceUrl` ile ekliyor. Wrapper queryParams.subscribe ile attribute'u\r\n\t\t// güncelliyor — bu yüzden constructor'da değil, her NavigationEnd'de fresh okuyoruz.\r\n\t\tconst readMyTabId = (): string => (this.elementRef.nativeElement as HTMLElement).getAttribute('aril-tab-id') ?? '';\r\n\r\n\t\tconst initialTabId = readMyTabId();\r\n\t\tconst locStrategy = inject(LocationStrategy);\r\n\t\tconst sameRouter = this.router === this.bridgeSvc.hostRouter;\r\n\t\tconsole.log(\r\n\t\t\t`[MFE:${appName}] host modu — tab=\"${initialTabId || '(pending)'}\" ` +\r\n\t\t\t\t`LocationStrategy=${locStrategy.constructor.name} ` +\r\n\t\t\t\t`router===hostRouter? ${sameRouter}`\r\n\t\t);\r\n\t\tconst initial = this.bridgeSvc.hostRouter!.url;\r\n\t\tconsole.log(`[MFE:${appName}] initial sync:`, initial);\r\n\t\tsafeNavigate(this.router, initial);\r\n\r\n\t\t// MFE içi `routerLink`/`router.navigate` host Router'a yansımıyor (IsolatedLocationStrategy\r\n\t\t// browser hash'ı değiştirmiyor) — NavService tab navLink'ini güncelleyemiyor.\r\n\t\t// MFE NavigationEnd'i `bridge.activeMFEUrl`'a (kaynak tabId ile) yazarız;\r\n\t\t// AppLayoutComponent effect → `syncActiveTabNavLinkForTab(tabId, url)` ile sadece\r\n\t\t// kaynak tab'ın navLink'i güncellenir → cross-tab kontaminasyonu yok.\r\n\t\t// Tab title resolve — kaynak öncelik sırası (en spesifik → en geniş):\r\n\t\t// 1. `route.title` (ÖNERİLEN — Angular Router 16+ standardı, sayfa <title>'ını da set eder)\r\n\t\t// 2. `data.tabName` (ÖNERİLEN — tab adı sayfa <title>'ından farklı olmalıysa)\r\n\t\t// 3. `data.title` (DEPRECATED — geriye uyumluluk için var; yeni route'larda kullanmayın,\r\n\t\t// `route.title` ile aynı semantiği taşıyor ama Angular contract dışı kalıyor)\r\n\t\t// 4. `data.breadcrumb` — mevcut breadcrumb template'i fallback olarak kullanılır\r\n\t\t// (single-brace `{key}` placeholder, literal string, i18n YOK)\r\n\t\t//\r\n\t\t// i18n key'lerinde `{{placeholder}}` Transloco interpolation'ı `BreadcrumbService.keyValues`\r\n\t\t// ile doldurulur. Component cevap geldiğinde `breadcrumbService.set('GatewayMaterialSerialNumber',\r\n\t\t// '12345')` her iki path'i de besler — effect ile re-compute, dinamik tab adı\r\n\t\t// (\"12345 - Modem Detay\").\r\n\t\tconst breadcrumbService = inject(BreadcrumbService);\r\n\t\tconst computeTabTitle = (): string | undefined => {\r\n\t\t\tlet route = this.router.routerState.snapshot.root;\r\n\t\t\twhile (route.firstChild) route = route.firstChild;\r\n\t\t\tconst params = breadcrumbService.keyValues();\r\n\r\n\t\t\tconst i18nKey =\r\n\t\t\t\t(route.title as string | undefined) ??\r\n\t\t\t\t(route.data?.['title'] as string | undefined) ??\r\n\t\t\t\t(route.data?.['tabName'] as string | undefined);\r\n\t\t\tif (i18nKey) {\r\n\t\t\t\tconst translated = this.translocoService.translate(i18nKey, params);\r\n\t\t\t\treturn translated || i18nKey;\r\n\t\t\t}\r\n\r\n\t\t\tconst breadcrumb = route.data?.['breadcrumb'] as string | undefined;\r\n\t\t\tif (breadcrumb) {\r\n\t\t\t\treturn breadcrumb.replace(/\\{([^}]+)\\}/g, (_, key: string) => params[key] ?? '...');\r\n\t\t\t}\r\n\r\n\t\t\treturn undefined;\r\n\t\t};\r\n\r\n\t\tlet lastUrl: string | undefined;\r\n\t\tlet lastTabIdForTitle: string | undefined;\r\n\r\n\t\tthis.router.events.pipe(takeUntilDestroyed()).subscribe((event: RouterEvent) => {\r\n\t\t\tif (event.type === EventType.NavigationEnd) {\r\n\t\t\t\tconst url = event.urlAfterRedirects ?? event.url;\r\n\t\t\t\tconst myTabId = readMyTabId();\r\n\t\t\t\tif (!myTabId) return;\r\n\t\t\t\tlastUrl = url;\r\n\t\t\t\tlastTabIdForTitle = myTabId;\r\n\t\t\t\tconst title = computeTabTitle();\r\n\t\t\t\tconst prev = this.bridgeSvc.activeMFEUrl();\r\n\t\t\t\tif (prev?.tabId === myTabId && prev?.url === url && prev?.title === title) return;\r\n\t\t\t\tthis.bridgeSvc.activeMFEUrl.set({ tabId: myTabId, url, title });\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// Component cevap gelince `breadcrumbService.set('meterNo', '12345')` keyValues'ı\r\n\t\t// günceller; effect ile yakalayıp tab title'ı yeniden hesaplarız → \"12345 - Sayaç\r\n\t\t// Detayı\" gibi dinamik sonuçlar tab adına yansır.\r\n\t\teffect(\r\n\t\t\t() => {\r\n\t\t\t\tbreadcrumbService.keyValues();\r\n\t\t\t\tif (!lastUrl || !lastTabIdForTitle) return;\r\n\t\t\t\tconst title = computeTabTitle();\r\n\t\t\t\tconst prev = this.bridgeSvc.activeMFEUrl();\r\n\t\t\t\tif (prev?.tabId === lastTabIdForTitle && prev?.url === lastUrl && prev?.title === title) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tthis.bridgeSvc.activeMFEUrl.set({ tabId: lastTabIdForTitle, url: lastUrl, title });\r\n\t\t\t},\r\n\t\t\t{ allowSignalWrites: true }\r\n\t\t);\r\n\r\n\t\tconst mfePrefix = `/${appName}`;\r\n\r\n\t\tthis.bridgeSvc.hostRouter!.events.pipe(takeUntilDestroyed()).subscribe((event: RouterEvent) => {\r\n\t\t\tif (event.type === EventType.NavigationEnd) {\r\n\t\t\t\tconst target = event.urlAfterRedirects ?? event.url;\r\n\t\t\t\tif (target !== mfePrefix && !target.startsWith(`${mfePrefix}/`)) return;\r\n\t\t\t\t// **Tab izolasyonu filter**: navigation'ın hedef tab'ı bu instance mı?\r\n\t\t\t\t// `IsolatedLocationStrategy` sayesinde host'a sadece tab tıklamaları\r\n\t\t\t\t// (`tabState({_tab})` ile) gelir — `history.state._tab` her zaman dolu.\r\n\t\t\t\tconst myTabId = readMyTabId();\r\n\t\t\t\tif (myTabId) {\r\n\t\t\t\t\tconst navTabId = (window.history.state as Record<string, unknown> | null)?.['_tab'];\r\n\t\t\t\t\tif (navTabId !== myTabId) return;\r\n\t\t\t\t}\r\n\t\t\t\t// `lastNavigated`/`router.url===target` early-return YOK: izole Router'da (her tab\r\n\t\t\t\t// kendi Router'ı) bir tab'a geri dönüldüğünde MFE Router zaten hedef URL'dedir;\r\n\t\t\t\t// navigate atlanırsa NavigationEnd fire etmez → `BreadcrumbPublisherService` yeniden\r\n\t\t\t\t// yayın yapmaz ve app.layout tab geçişinde breadcrumb'ı `set([])` ile temizlediği için\r\n\t\t\t\t// breadcrumb boş kalır. `onSameUrlNavigation:'reload'` aynı URL'e navigate'i\r\n\t\t\t\t// NavigationEnd ile garanti eder → breadcrumb + tab navLink yeniden yayınlanır.\r\n\t\t\t\tconsole.log(`[MFE:${appName}] tab=\"${myTabId || '(pending)'}\" host NavigationEnd → navigate:`, target);\r\n\t\t\t\tsafeNavigate(this.router, target);\r\n\t\t\t} else if (event.type === EventType.NavigationCancel) {\r\n\t\t\t\tconsole.warn(`[MFE:${appName}] host NavigationCancel:`, event.url, 'reason:', event.reason);\r\n\t\t\t} else if (event.type === EventType.NavigationError) {\r\n\t\t\t\tconsole.error(`[MFE:${appName}] host NavigationError:`, event.url, 'err:', event.error);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.bridgeSvc.activeMF.set(appName);\r\n\t\tconst lang: LanguageCode = (localStorage.getItem('lang') as LanguageCode) ?? LanguageCode.TR;\r\n\r\n\t\tthis.translocoService.setActiveLang(lang);\r\n\r\n\t\tthis.setLocale(lang);\r\n\t}\r\n\r\n\tsetLocale(lang: LanguageCode) {\r\n\t\tif (!lang?.length) return;\r\n\r\n\t\tif (lang === LanguageCode.TR) {\r\n\t\t\tthis.primeNgConfig.setTranslation(TR_TRANSLATIONS);\r\n\t\t}\r\n\t}\r\n}\r\n"],"names":["i4"],"mappings":"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"}
|
|
@@ -4,13 +4,47 @@ class MfeBridge {
|
|
|
4
4
|
constructor() {
|
|
5
5
|
this.activeHost = signal(null);
|
|
6
6
|
this.activeMF = signal(null);
|
|
7
|
-
this.isHostMode = signal(false);
|
|
8
7
|
this.hostMenuItems = signal([]);
|
|
9
8
|
this.pluginJson = signal({});
|
|
10
9
|
this.routeConfigs = signal(null);
|
|
11
10
|
this.pageTitle = signal('');
|
|
11
|
+
this.breadcrumbs = signal([]);
|
|
12
|
+
/**
|
|
13
|
+
* Bir MFE Router'ında olan son `NavigationEnd`'in URL'i ve **hangi tab'a ait olduğu**.
|
|
14
|
+
* MFE içi sayfa içi navigation'lar host Router'a yansımayabiliyor → `NavService` tab
|
|
15
|
+
* navLink'ini güncellemek için bu signal'ı izler.
|
|
16
|
+
*
|
|
17
|
+
* **Neden tabId taşıyor**: Birden fazla tab'ın MFE Router'ı async event tetikleyebilir
|
|
18
|
+
* (örn. hidden container'daki tab2 `?activeTab=1` replaceState yaparken). `activeTabId`'ye
|
|
19
|
+
* bakarak update yaparsak yanlış tab'ı kontamine ederiz. Mesajda kaynak tabId'yi taşıyıp
|
|
20
|
+
* `NavService.syncActiveTabNavLinkForTab(tabId, url)` ile spesifik tab'ı update ederiz.
|
|
21
|
+
*
|
|
22
|
+
* **Custom `equal`**: AppComponent her MFE NavigationEnd'de `set({tabId, url})` çağırır;
|
|
23
|
+
* yeni object reference olduğu için default reference-equality re-emit eder. Bu durumda
|
|
24
|
+
* aynı tab+url ile sürekli effect tetiklenir → tab navLink'i kullanıcının anasayfaya
|
|
25
|
+
* geçtiği gibi (host route'lar MFE NavigationEnd tetiklemez ama signal eski değerinde
|
|
26
|
+
* kalır) state değişikliklerini geri alır. Value-equality ile yalnızca gerçek URL
|
|
27
|
+
* değişikliklerinde tetiklensin.
|
|
28
|
+
*/
|
|
29
|
+
this.activeMFEUrl = signal(null, {
|
|
30
|
+
equal: (a, b) => a?.tabId === b?.tabId && a?.url === b?.url && a?.title === b?.title
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Aktif tab'ın `tabId`'si — `NavService` tab değişimlerinde günceller.
|
|
34
|
+
* Plugin Router proxy'leri (`provideHostRouter`) bu signal'ı okuyup `navigate`/`navigateByUrl`
|
|
35
|
+
* çağrılarına `extras.state._tab` enjekte eder → plugin'lerin yaptığı tüm host
|
|
36
|
+
* navigation'ları otomatik tab-aware olur, Strategy doğru tab handle'ını korur.
|
|
37
|
+
*/
|
|
38
|
+
this.activeTabId = signal('');
|
|
12
39
|
this.hostNgZone = null;
|
|
13
40
|
this.hostRouter = null;
|
|
41
|
+
/**
|
|
42
|
+
* Host (shell) `Location` servisi. Host modda MFE/plugin child injector'larından
|
|
43
|
+
* erişilemez (child Location izole `IsolatedLocationStrategy`'ye bağlı); browser
|
|
44
|
+
* adres çubuğuna `replaceState` ile yazmak isteyen directive'ler (örn. `?activeTab`
|
|
45
|
+
* senkronizasyonu) bunu kullanır. `hostRouter` ile aynı pattern.
|
|
46
|
+
*/
|
|
47
|
+
this.hostLocation = null;
|
|
14
48
|
this.mirrored = false;
|
|
15
49
|
}
|
|
16
50
|
mirrorToWindow() {
|
|
@@ -26,9 +60,6 @@ class MfeBridge {
|
|
|
26
60
|
effect(() => {
|
|
27
61
|
w.activeMF = this.activeMF() ?? undefined;
|
|
28
62
|
});
|
|
29
|
-
effect(() => {
|
|
30
|
-
w.isHostMode = this.isHostMode();
|
|
31
|
-
});
|
|
32
63
|
effect(() => {
|
|
33
64
|
w.pluginJson = this.pluginJson();
|
|
34
65
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aril-boot-bridge.mjs","sources":["../../projects/aril/boot/bridge/src/mfe-bridge.ts","../../projects/aril/boot/bridge/src/provide-mfe-bridge.ts","../../projects/aril/boot/bridge/aril-boot-bridge.ts"],"sourcesContent":["import { NgZone, Signal, effect, signal } from '@angular/core';\r\nimport type { Router } from '@angular/router';\r\n\r\nimport type { Apps, PluginMenuItem } from 'aril/boot/config/apps';\r\n\r\nexport interface RouteConfig {\r\n\tpath: string;\r\n\tcontent: string;\r\n\tversion: number;\r\n}\r\n\r\nexport interface
|
|
1
|
+
{"version":3,"file":"aril-boot-bridge.mjs","sources":["../../projects/aril/boot/bridge/src/mfe-bridge.ts","../../projects/aril/boot/bridge/src/provide-mfe-bridge.ts","../../projects/aril/boot/bridge/aril-boot-bridge.ts"],"sourcesContent":["import type { Location } from '@angular/common';\r\nimport { NgZone, Signal, effect, signal } from '@angular/core';\r\nimport type { Router } from '@angular/router';\r\n\r\nimport type { Apps, PluginMenuItem } from 'aril/boot/config/apps';\r\n\r\nexport interface RouteConfig {\r\n\tpath: string;\r\n\tcontent: string;\r\n\tversion: number;\r\n}\r\n\r\nexport interface Breadcrumb {\r\n\tlabel: string;\r\n\turl?: string;\r\n}\r\n\r\nexport interface LegacyWindowSlots {\r\n\tactiveHost?: Apps;\r\n\tactiveMF?: Apps;\r\n\thostMenuItems?: Signal<PluginMenuItem[]>;\r\n\tpluginJson?: Record<string, unknown>;\r\n\trouteConfigs?: RouteConfig[];\r\n\tngZone?: NgZone;\r\n\thostRouter?: Router;\r\n\t__ARIL_PAGE_TITLE__?: Signal<string>;\r\n}\r\n\r\nexport class MfeBridge {\r\n\treadonly activeHost = signal<Apps | null>(null);\r\n\treadonly activeMF = signal<Apps | null>(null);\r\n\treadonly hostMenuItems = signal<PluginMenuItem[]>([]);\r\n\treadonly pluginJson = signal<Record<string, unknown>>({});\r\n\treadonly routeConfigs = signal<RouteConfig[] | null>(null);\r\n\treadonly pageTitle = signal<string>('');\r\n\treadonly breadcrumbs = signal<Breadcrumb[]>([]);\r\n\t/**\r\n\t * Bir MFE Router'ında olan son `NavigationEnd`'in URL'i ve **hangi tab'a ait olduğu**.\r\n\t * MFE içi sayfa içi navigation'lar host Router'a yansımayabiliyor → `NavService` tab\r\n\t * navLink'ini güncellemek için bu signal'ı izler.\r\n\t *\r\n\t * **Neden tabId taşıyor**: Birden fazla tab'ın MFE Router'ı async event tetikleyebilir\r\n\t * (örn. hidden container'daki tab2 `?activeTab=1` replaceState yaparken). `activeTabId`'ye\r\n\t * bakarak update yaparsak yanlış tab'ı kontamine ederiz. Mesajda kaynak tabId'yi taşıyıp\r\n\t * `NavService.syncActiveTabNavLinkForTab(tabId, url)` ile spesifik tab'ı update ederiz.\r\n\t *\r\n\t * **Custom `equal`**: AppComponent her MFE NavigationEnd'de `set({tabId, url})` çağırır;\r\n\t * yeni object reference olduğu için default reference-equality re-emit eder. Bu durumda\r\n\t * aynı tab+url ile sürekli effect tetiklenir → tab navLink'i kullanıcının anasayfaya\r\n\t * geçtiği gibi (host route'lar MFE NavigationEnd tetiklemez ama signal eski değerinde\r\n\t * kalır) state değişikliklerini geri alır. Value-equality ile yalnızca gerçek URL\r\n\t * değişikliklerinde tetiklensin.\r\n\t */\r\n\treadonly activeMFEUrl = signal<{ tabId: string; url: string; title?: string } | null>(null, {\r\n\t\tequal: (a, b) => a?.tabId === b?.tabId && a?.url === b?.url && a?.title === b?.title\r\n\t});\r\n\r\n\t/**\r\n\t * Aktif tab'ın `tabId`'si — `NavService` tab değişimlerinde günceller.\r\n\t * Plugin Router proxy'leri (`provideHostRouter`) bu signal'ı okuyup `navigate`/`navigateByUrl`\r\n\t * çağrılarına `extras.state._tab` enjekte eder → plugin'lerin yaptığı tüm host\r\n\t * navigation'ları otomatik tab-aware olur, Strategy doğru tab handle'ını korur.\r\n\t */\r\n\treadonly activeTabId = signal<string>('');\r\n\r\n\thostNgZone: NgZone | null = null;\r\n\thostRouter: Router | null = null;\r\n\t/**\r\n\t * Host (shell) `Location` servisi. Host modda MFE/plugin child injector'larından\r\n\t * erişilemez (child Location izole `IsolatedLocationStrategy`'ye bağlı); browser\r\n\t * adres çubuğuna `replaceState` ile yazmak isteyen directive'ler (örn. `?activeTab`\r\n\t * senkronizasyonu) bunu kullanır. `hostRouter` ile aynı pattern.\r\n\t */\r\n\thostLocation: Location | null = null;\r\n\r\n\tprivate mirrored = false;\r\n\r\n\tmirrorToWindow(): void {\r\n\t\tif (this.mirrored || typeof window === 'undefined') return;\r\n\t\tthis.mirrored = true;\r\n\r\n\t\tconst w = window as Window & LegacyWindowSlots;\r\n\r\n\t\tw.hostMenuItems = this.hostMenuItems;\r\n\t\tw.__ARIL_PAGE_TITLE__ = this.pageTitle;\r\n\r\n\t\teffect(() => {\r\n\t\t\tw.activeHost = this.activeHost() ?? undefined;\r\n\t\t});\r\n\t\teffect(() => {\r\n\t\t\tw.activeMF = this.activeMF() ?? undefined;\r\n\t\t});\r\n\t\teffect(() => {\r\n\t\t\tw.pluginJson = this.pluginJson();\r\n\t\t});\r\n\t\teffect(() => {\r\n\t\t\tw.routeConfigs = this.routeConfigs() ?? undefined;\r\n\t\t});\r\n\r\n\t\tObject.defineProperty(w, 'ngZone', {\r\n\t\t\tconfigurable: true,\r\n\t\t\tget: () => this.hostNgZone\r\n\t\t});\r\n\t\tObject.defineProperty(w, 'hostRouter', {\r\n\t\t\tconfigurable: true,\r\n\t\t\tget: () => this.hostRouter\r\n\t\t});\r\n\t}\r\n}\r\n\r\n// Module Federation shared config olmadığı durumlar için globalThis slot\r\n// üzerinden tek instance garantisi. Host ve her remote MFE ayrı bundle olsa\r\n// bile aynı JS realm'inde aynı instance'ı okur — eski globalThis sözleşmesinin\r\n// yaptığı görevi tek bir tipli slotta birleştirir.\r\nconst BRIDGE_SLOT = '__arilMfeBridge__';\r\ntype BridgeSlotHost = { [BRIDGE_SLOT]?: MfeBridge };\r\nexport const bridge: MfeBridge = (() => {\r\n\tconst g = globalThis as unknown as BridgeSlotHost;\r\n\tif (!g[BRIDGE_SLOT]) {\r\n\t\tg[BRIDGE_SLOT] = new MfeBridge();\r\n\t}\r\n\treturn g[BRIDGE_SLOT]!;\r\n})();\r\n","import { makeEnvironmentProviders } from '@angular/core';\r\n\r\nimport { MfeBridge, bridge } from './mfe-bridge';\r\n\r\nexport function provideMfeBridge() {\r\n\treturn makeEnvironmentProviders([{ provide: MfeBridge, useValue: bridge }]);\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;MA4Ba,SAAS,CAAA;AAAtB,IAAA,WAAA,GAAA;AACU,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAc,IAAI,CAAC,CAAC;AACvC,QAAA,IAAA,CAAA,QAAQ,GAAG,MAAM,CAAc,IAAI,CAAC,CAAC;AACrC,QAAA,IAAA,CAAA,aAAa,GAAG,MAAM,CAAmB,EAAE,CAAC,CAAC;AAC7C,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAA0B,EAAE,CAAC,CAAC;AACjD,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAuB,IAAI,CAAC,CAAC;AAClD,QAAA,IAAA,CAAA,SAAS,GAAG,MAAM,CAAS,EAAE,CAAC,CAAC;AAC/B,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAe,EAAE,CAAC,CAAC;AAChD;;;;;;;;;;;;;;;;AAgBG;AACM,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAwD,IAAI,EAAE;AAC3F,YAAA,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,KAAK;AACpF,SAAA,CAAC,CAAC;AAEH;;;;;AAKG;AACM,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAS,EAAE,CAAC,CAAC;QAE1C,IAAU,CAAA,UAAA,GAAkB,IAAI,CAAC;QACjC,IAAU,CAAA,UAAA,GAAkB,IAAI,CAAC;AACjC;;;;;AAKG;QACH,IAAY,CAAA,YAAA,GAAoB,IAAI,CAAC;QAE7B,IAAQ,CAAA,QAAA,GAAG,KAAK,CAAC;KAiCzB;IA/BA,cAAc,GAAA;AACb,QAAA,IAAI,IAAI,CAAC,QAAQ,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO;AAC3D,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,MAAM,CAAC,GAAG,MAAoC,CAAC;AAE/C,QAAA,CAAC,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;AACrC,QAAA,CAAC,CAAC,mBAAmB,GAAG,IAAI,CAAC,SAAS,CAAC;QAEvC,MAAM,CAAC,MAAK;YACX,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,IAAI,SAAS,CAAC;AAC/C,SAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAK;YACX,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,SAAS,CAAC;AAC3C,SAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAK;AACX,YAAA,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;AAClC,SAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAK;YACX,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,SAAS,CAAC;AACnD,SAAC,CAAC,CAAC;AAEH,QAAA,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE;AAClC,YAAA,YAAY,EAAE,IAAI;AAClB,YAAA,GAAG,EAAE,MAAM,IAAI,CAAC,UAAU;AAC1B,SAAA,CAAC,CAAC;AACH,QAAA,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,YAAY,EAAE;AACtC,YAAA,YAAY,EAAE,IAAI;AAClB,YAAA,GAAG,EAAE,MAAM,IAAI,CAAC,UAAU;AAC1B,SAAA,CAAC,CAAC;KACH;AACD,CAAA;AAED;AACA;AACA;AACA;AACA,MAAM,WAAW,GAAG,mBAAmB,CAAC;AAE3B,MAAA,MAAM,GAAc,CAAC,MAAK;IACtC,MAAM,CAAC,GAAG,UAAuC,CAAC;AAClD,IAAA,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE;AACpB,QAAA,CAAC,CAAC,WAAW,CAAC,GAAG,IAAI,SAAS,EAAE,CAAC;KACjC;AACD,IAAA,OAAO,CAAC,CAAC,WAAW,CAAE,CAAC;AACxB,CAAC;;SCtHe,gBAAgB,GAAA;AAC/B,IAAA,OAAO,wBAAwB,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;AAC7E;;ACNA;;AAEG;;;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isDevMode } from '@angular/core';
|
|
2
2
|
import { KeycloakEventType } from 'keycloak-angular';
|
|
3
|
-
import { switchMap, from, finalize, takeUntil, fromEvent,
|
|
3
|
+
import { switchMap, from, finalize, takeUntil, fromEvent, catchError, EMPTY, tap, firstValueFrom } from 'rxjs';
|
|
4
4
|
import { bridge } from 'aril/boot/bridge';
|
|
5
5
|
import { Apps } from 'aril/boot/config/apps';
|
|
6
6
|
|
|
@@ -65,7 +65,16 @@ const loadApiConfigs = (httpClient, keycloak, appName, microAppService) => () =>
|
|
|
65
65
|
dispatchEvent(new CustomEvent(`${app}:update-keycloak`, { detail: keycloak }));
|
|
66
66
|
}
|
|
67
67
|
});
|
|
68
|
-
}))
|
|
68
|
+
})),
|
|
69
|
+
// Browser arka plandayken refresh edilince token endpoint 400 (invalid_grant /
|
|
70
|
+
// süresi dolmuş refresh token / silent-SSO timeout) dönüp `keycloak.init()` reject
|
|
71
|
+
// olabiliyor. Yakalanmazsa "ERROR undefined" + auth'suz bozuk açılış oluyordu.
|
|
72
|
+
// Hatayı yakalayıp temiz yeniden login'e yönlendir (Keycloak login → mevcut URL'e döner).
|
|
73
|
+
catchError((err) => {
|
|
74
|
+
console.error("Keycloak init başarısız — yeniden login'e yönlendiriliyor:", err);
|
|
75
|
+
void keycloak.login();
|
|
76
|
+
return EMPTY;
|
|
77
|
+
}));
|
|
69
78
|
}), switchMap(() => microAppService?.init(httpClient, API_CONFIGS.api).pipe(tap((result) => {
|
|
70
79
|
bridge.hostMenuItems.set(result.menuItems);
|
|
71
80
|
bridge.pluginJson.set(result.plugins);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aril-boot-config-api.mjs","sources":["../../projects/aril/boot/config/api/src/interfaces.ts","../../projects/aril/boot/config/api/src/api.service.ts","../../projects/aril/boot/config/api/aril-boot-config-api.ts"],"sourcesContent":["import { Apps } from 'aril/boot/config/apps';\r\n\r\nexport enum AppsRoutes {\r\n\tMNG_BASE_URL = 'mngBaseUrl',\r\n}\r\n\r\nexport interface KeycloakConfig {\r\n\turl: string;\r\n\trealm: string;\r\n\tclientId: string;\r\n}\r\n\r\nexport class ApiConfigsFactory {\r\n\tapi: string = '';\r\n\tfromMail: string = '';\r\n\tmwApi: string = '';\r\n\taiApi: string = '';\r\n\tstatusApi: string = '';\r\n\tenvironment: string = '';\r\n\tkeycloak!: Keycloak.KeycloakConfig;\r\n\troutes: Record<AppsRoutes, string> = {\r\n\t\tmngBaseUrl: '',\r\n\t};\r\n\tprefixMap: Record<Apps, string> = {\r\n\t\t[Apps.THOR]: '',\r\n\t\t[Apps.CRM]: '',\r\n\t\t[Apps.WDM]: '',\r\n\t\t[Apps.BILLING]: '',\r\n\t\t[Apps.PAYMENT]: '',\r\n\t\t[Apps.YEAP]: '',\r\n\t\t[Apps.MW]: '',\r\n\t\t[Apps.LENA]: '',\r\n\t\t[Apps.HES]: '',\r\n\t\t[Apps.CTS]: '',\r\n\t\t[Apps.SIS]: '',\r\n\t\t[Apps.MNG]: '',\r\n\t\t[Apps.STATE_MACHINE]: '',\r\n\t\t[Apps.MDM]:'',\r\n\t\t[Apps.REPORT]: '',\r\n\t\t[Apps.LGC]: '',\r\n\t\t[Apps.DMS]: ''\r\n\t};\r\n\tgetExternalAppEndpoint(appName: Apps): string {\r\n\t\tconst prefix = this.prefixMap[appName] || this.prefixMap[Apps.MNG];\r\n\t\treturn `${new URL(this.api).origin}/${prefix}`;\r\n\t}\r\n}\r\n","import { HttpClient } from '@angular/common/http';\r\nimport { isDevMode } from '@angular/core';\r\n\r\nimport { KeycloakEventType, KeycloakService } from 'keycloak-angular';\r\nimport { EMPTY, finalize, firstValueFrom, from, fromEvent, switchMap, takeUntil, tap } from 'rxjs';\r\n\r\nimport { RouteConfig, bridge } from 'aril/boot/bridge';\r\nimport { Apps, MicroAppService } from 'aril/boot/config/apps';\r\n\r\nimport { ApiConfigsFactory } from './interfaces';\r\n\r\nexport const API_CONFIGS = new ApiConfigsFactory();\r\n\r\nexport const loadApiConfigs =\r\n\t(httpClient: HttpClient, keycloak: KeycloakService, appName: string, microAppService?: MicroAppService) => () =>\r\n\t\tnew Promise<void>((resolve) =>\r\n\t\t\thttpClient\r\n\t\t\t\t.get<ApiConfigsFactory>(isDevMode() ? './assets/local-configs/api.local.json' : './api.json')\r\n\t\t\t\t.pipe(\r\n\t\t\t\t\tswitchMap((configs) => {\r\n\t\t\t\t\t\tbridge.hostMenuItems.set([]);\r\n\t\t\t\t\t\tbridge.pluginJson.set({});\r\n\r\n\t\t\t\t\t\tObject.assign(API_CONFIGS, { ...configs });\r\n\r\n\t\t\t\t\t\treturn from(\r\n\t\t\t\t\t\t\tkeycloak.init({\r\n\t\t\t\t\t\t\t\tconfig: API_CONFIGS.keycloak,\r\n\t\t\t\t\t\t\t\tloadUserProfileAtStartUp: true,\r\n\t\t\t\t\t\t\t\tinitOptions: { onLoad: 'login-required', checkLoginIframe: false },\r\n\t\t\t\t\t\t\t\tbearerExcludedUrls: ['/assets']\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t).pipe(\r\n\t\t\t\t\t\t\tfinalize(() =>\r\n\t\t\t\t\t\t\t\taddEventListener('module-ready', (event) => {\r\n\t\t\t\t\t\t\t\t\tconst app = (event as CustomEvent).detail;\r\n\t\t\t\t\t\t\t\t\tdispatchEvent(new CustomEvent(`${app}:init-keycloak`, { detail: keycloak }));\r\n\r\n\t\t\t\t\t\t\t\t\tkeycloak.keycloakEvents$.pipe(takeUntil(fromEvent(window, 'beforeunload'))).subscribe((e) => {\r\n\t\t\t\t\t\t\t\t\t\tif (e.type === KeycloakEventType.OnAuthRefreshSuccess) {\r\n\t\t\t\t\t\t\t\t\t\t\tdispatchEvent(new CustomEvent(`${app}:update-keycloak`, { detail: keycloak }));\r\n\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t\t)\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t}),\r\n\t\t\t\t\tswitchMap(\r\n\t\t\t\t\t\t() =>\r\n\t\t\t\t\t\t\tmicroAppService?.init(httpClient, API_CONFIGS.api).pipe(\r\n\t\t\t\t\t\t\t\ttap((result) => {\r\n\t\t\t\t\t\t\t\t\tbridge.hostMenuItems.set(result.menuItems);\r\n\t\t\t\t\t\t\t\t\tbridge.pluginJson.set(result.plugins);\r\n\t\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t\t) ?? EMPTY\r\n\t\t\t\t\t)\r\n\t\t\t\t)\r\n\t\t\t\t.subscribe()\r\n\t\t\t\t.add(resolve)\r\n\t\t);\r\n\r\n/**\r\n * only works when isHostMode is true\r\n * micro-app access its own api.json file when opened in host\r\n */\r\nexport function setApiConfigOnMFEMode(\r\n\thttpClient: HttpClient,\r\n\tkeycloak: KeycloakService,\r\n\tappName: Apps\r\n): () => Promise<any> {\r\n\treturn () => {\r\n\t\tconst observable$ = httpClient\r\n\t\t\t.get<ApiConfigsFactory>(isDevMode() ? './assets/local-configs/api.local.json' : './api.json')\r\n\t\t\t.pipe(\r\n\t\t\t\ttap((configs) => {\r\n\t\t\t\t\tObject.assign(API_CONFIGS, { ...configs });\r\n\t\t\t\t\tif (appName !== Apps.THOR && appName !== Apps.YEAP) {\r\n\t\t\t\t\t\tAPI_CONFIGS.api = API_CONFIGS.getExternalAppEndpoint(appName);\r\n\t\t\t\t\t}\r\n\t\t\t\t})\r\n\t\t\t);\r\n\r\n\t\treturn firstValueFrom(observable$);\r\n\t};\r\n}\r\n\r\nexport const loadInitData = (httpClient: HttpClient) => () =>\r\n\tnew Promise<void>((resolve, _reject) => {\r\n\t\tconst endpoint = API_CONFIGS.api + '/ui-route-content-configs/all';\r\n\t\thttpClient.get<RouteConfig[]>(endpoint).subscribe({\r\n\t\t\tnext: (data) => {\r\n\t\t\t\tbridge.routeConfigs.set(data);\r\n\t\t\t\tresolve();\r\n\t\t\t},\r\n\t\t\terror: (err) => {\r\n\t\t\t\tconsole.error(`Failed to load init data from ${endpoint}:`, err);\r\n\t\t\t\tresolve();\r\n\t\t\t}\r\n\t\t});\r\n\t});\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;AAEA,IAAY,UAEX,CAAA;AAFD,CAAA,UAAY,UAAU,EAAA;AACrB,IAAA,UAAA,CAAA,cAAA,CAAA,GAAA,YAA2B,CAAA;AAC5B,CAAC,EAFW,UAAU,KAAV,UAAU,GAErB,EAAA,CAAA,CAAA,CAAA;MAQY,iBAAiB,CAAA;AAA9B,IAAA,WAAA,GAAA;QACC,IAAG,CAAA,GAAA,GAAW,EAAE,CAAC;QACjB,IAAQ,CAAA,QAAA,GAAW,EAAE,CAAC;QACtB,IAAK,CAAA,KAAA,GAAW,EAAE,CAAC;QACnB,IAAK,CAAA,KAAA,GAAW,EAAE,CAAC;QACnB,IAAS,CAAA,SAAA,GAAW,EAAE,CAAC;QACvB,IAAW,CAAA,WAAA,GAAW,EAAE,CAAC;AAEzB,QAAA,IAAA,CAAA,MAAM,GAA+B;AACpC,YAAA,UAAU,EAAE,EAAE;SACd,CAAC;AACF,QAAA,IAAA,CAAA,SAAS,GAAyB;AACjC,YAAA,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE;AACf,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,OAAO,GAAG,EAAE;AAClB,YAAA,CAAC,IAAI,CAAC,OAAO,GAAG,EAAE;AAClB,YAAA,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE;AACf,YAAA,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE;AACb,YAAA,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE;AACf,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,aAAa,GAAG,EAAE;AACxB,YAAA,CAAC,IAAI,CAAC,GAAG,GAAE,EAAE;AACb,YAAA,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE;AACjB,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;SACd,CAAC;KAKF;AAJA,IAAA,sBAAsB,CAAC,OAAa,EAAA;AACnC,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACnE,QAAA,OAAO,CAAG,EAAA,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAI,CAAA,EAAA,MAAM,EAAE,CAAC;KAC/C;AACD;;ACnCY,MAAA,WAAW,GAAG,IAAI,iBAAiB,GAAG;AAEtC,MAAA,cAAc,GAC1B,CAAC,UAAsB,EAAE,QAAyB,EAAE,OAAe,EAAE,eAAiC,KAAK,MAC1G,IAAI,OAAO,CAAO,CAAC,OAAO,KACzB,UAAU;KACR,GAAG,CAAoB,SAAS,EAAE,GAAG,uCAAuC,GAAG,YAAY,CAAC;AAC5F,KAAA,IAAI,CACJ,SAAS,CAAC,CAAC,OAAO,KAAI;AACrB,IAAA,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAC7B,IAAA,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAE1B,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAE3C,IAAA,OAAO,IAAI,CACV,QAAQ,CAAC,IAAI,CAAC;QACb,MAAM,EAAE,WAAW,CAAC,QAAQ;AAC5B,QAAA,wBAAwB,EAAE,IAAI;QAC9B,WAAW,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,KAAK,EAAE;QAClE,kBAAkB,EAAE,CAAC,SAAS,CAAC;AAC/B,KAAA,CAAC,CACF,CAAC,IAAI,CACL,QAAQ,CAAC,MACR,gBAAgB,CAAC,cAAc,EAAE,CAAC,KAAK,KAAI;AAC1C,QAAA,MAAM,GAAG,GAAI,KAAqB,CAAC,MAAM,CAAC;AAC1C,QAAA,aAAa,CAAC,IAAI,WAAW,CAAC,GAAG,GAAG,CAAA,cAAA,CAAgB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAE7E,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAI;YAC3F,IAAI,CAAC,CAAC,IAAI,KAAK,iBAAiB,CAAC,oBAAoB,EAAE;AACtD,gBAAA,aAAa,CAAC,IAAI,WAAW,CAAC,GAAG,GAAG,CAAA,gBAAA,CAAkB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;aAC/E;AACF,SAAC,CAAC,CAAC;KACH,CAAC,CACF,CACD,CAAC;AACH,CAAC,CAAC,EACF,SAAS,CACR,MACC,eAAe,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,CACtD,GAAG,CAAC,CAAC,MAAM,KAAI;IACd,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC,CAAC,CACF,IAAI,KAAK,CACX,CACD;AACA,KAAA,SAAS,EAAE;AACX,KAAA,GAAG,CAAC,OAAO,CAAC,EACb;AAEJ;;;AAGG;SACa,qBAAqB,CACpC,UAAsB,EACtB,QAAyB,EACzB,OAAa,EAAA;AAEb,IAAA,OAAO,MAAK;QACX,MAAM,WAAW,GAAG,UAAU;aAC5B,GAAG,CAAoB,SAAS,EAAE,GAAG,uCAAuC,GAAG,YAAY,CAAC;AAC5F,aAAA,IAAI,CACJ,GAAG,CAAC,CAAC,OAAO,KAAI;YACf,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAC3C,YAAA,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI,EAAE;gBACnD,WAAW,CAAC,GAAG,GAAG,WAAW,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;aAC9D;SACD,CAAC,CACF,CAAC;AAEH,QAAA,OAAO,cAAc,CAAC,WAAW,CAAC,CAAC;AACpC,KAAC,CAAC;AACH,CAAC;MAEY,YAAY,GAAG,CAAC,UAAsB,KAAK,MACvD,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,OAAO,KAAI;AACtC,IAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,GAAG,+BAA+B,CAAC;AACnE,IAAA,UAAU,CAAC,GAAG,CAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC;AACjD,QAAA,IAAI,EAAE,CAAC,IAAI,KAAI;AACd,YAAA,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC9B,YAAA,OAAO,EAAE,CAAC;SACV;AACD,QAAA,KAAK,EAAE,CAAC,GAAG,KAAI;YACd,OAAO,CAAC,KAAK,CAAC,CAAA,8BAAA,EAAiC,QAAQ,CAAG,CAAA,CAAA,EAAE,GAAG,CAAC,CAAC;AACjE,YAAA,OAAO,EAAE,CAAC;SACV;AACD,KAAA,CAAC,CAAC;AACJ,CAAC;;ACnGF;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"aril-boot-config-api.mjs","sources":["../../projects/aril/boot/config/api/src/interfaces.ts","../../projects/aril/boot/config/api/src/api.service.ts","../../projects/aril/boot/config/api/aril-boot-config-api.ts"],"sourcesContent":["import { Apps } from 'aril/boot/config/apps';\r\n\r\nexport enum AppsRoutes {\r\n\tMNG_BASE_URL = 'mngBaseUrl',\r\n}\r\n\r\nexport interface KeycloakConfig {\r\n\turl: string;\r\n\trealm: string;\r\n\tclientId: string;\r\n}\r\n\r\nexport class ApiConfigsFactory {\r\n\tapi: string = '';\r\n\tfromMail: string = '';\r\n\tmwApi: string = '';\r\n\taiApi: string = '';\r\n\tstatusApi: string = '';\r\n\tenvironment: string = '';\r\n\tkeycloak!: Keycloak.KeycloakConfig;\r\n\troutes: Record<AppsRoutes, string> = {\r\n\t\tmngBaseUrl: '',\r\n\t};\r\n\tprefixMap: Record<Apps, string> = {\r\n\t\t[Apps.THOR]: '',\r\n\t\t[Apps.CRM]: '',\r\n\t\t[Apps.WDM]: '',\r\n\t\t[Apps.BILLING]: '',\r\n\t\t[Apps.PAYMENT]: '',\r\n\t\t[Apps.YEAP]: '',\r\n\t\t[Apps.MW]: '',\r\n\t\t[Apps.LENA]: '',\r\n\t\t[Apps.HES]: '',\r\n\t\t[Apps.CTS]: '',\r\n\t\t[Apps.SIS]: '',\r\n\t\t[Apps.MNG]: '',\r\n\t\t[Apps.STATE_MACHINE]: '',\r\n\t\t[Apps.MDM]:'',\r\n\t\t[Apps.REPORT]: '',\r\n\t\t[Apps.LGC]: '',\r\n\t\t[Apps.DMS]: ''\r\n\t};\r\n\tgetExternalAppEndpoint(appName: Apps): string {\r\n\t\tconst prefix = this.prefixMap[appName] || this.prefixMap[Apps.MNG];\r\n\t\treturn `${new URL(this.api).origin}/${prefix}`;\r\n\t}\r\n}\r\n","import { HttpClient } from '@angular/common/http';\r\nimport { isDevMode } from '@angular/core';\r\n\r\nimport { KeycloakEventType, KeycloakService } from 'keycloak-angular';\r\nimport { EMPTY, catchError, finalize, firstValueFrom, from, fromEvent, switchMap, takeUntil, tap } from 'rxjs';\r\n\r\nimport { RouteConfig, bridge } from 'aril/boot/bridge';\r\nimport { Apps, MicroAppService } from 'aril/boot/config/apps';\r\n\r\nimport { ApiConfigsFactory } from './interfaces';\r\n\r\nexport const API_CONFIGS = new ApiConfigsFactory();\r\n\r\nexport const loadApiConfigs =\r\n\t(httpClient: HttpClient, keycloak: KeycloakService, appName: string, microAppService?: MicroAppService) => () =>\r\n\t\tnew Promise<void>((resolve) =>\r\n\t\t\thttpClient\r\n\t\t\t\t.get<ApiConfigsFactory>(isDevMode() ? './assets/local-configs/api.local.json' : './api.json')\r\n\t\t\t\t.pipe(\r\n\t\t\t\t\tswitchMap((configs) => {\r\n\t\t\t\t\t\tbridge.hostMenuItems.set([]);\r\n\t\t\t\t\t\tbridge.pluginJson.set({});\r\n\r\n\t\t\t\t\t\tObject.assign(API_CONFIGS, { ...configs });\r\n\r\n\t\t\t\t\t\treturn from(\r\n\t\t\t\t\t\t\tkeycloak.init({\r\n\t\t\t\t\t\t\t\tconfig: API_CONFIGS.keycloak,\r\n\t\t\t\t\t\t\t\tloadUserProfileAtStartUp: true,\r\n\t\t\t\t\t\t\t\tinitOptions: { onLoad: 'login-required', checkLoginIframe: false },\r\n\t\t\t\t\t\t\t\tbearerExcludedUrls: ['/assets']\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t).pipe(\r\n\t\t\t\t\t\t\tfinalize(() =>\r\n\t\t\t\t\t\t\t\taddEventListener('module-ready', (event) => {\r\n\t\t\t\t\t\t\t\t\tconst app = (event as CustomEvent).detail;\r\n\t\t\t\t\t\t\t\t\tdispatchEvent(new CustomEvent(`${app}:init-keycloak`, { detail: keycloak }));\r\n\r\n\t\t\t\t\t\t\t\t\tkeycloak.keycloakEvents$.pipe(takeUntil(fromEvent(window, 'beforeunload'))).subscribe((e) => {\r\n\t\t\t\t\t\t\t\t\t\tif (e.type === KeycloakEventType.OnAuthRefreshSuccess) {\r\n\t\t\t\t\t\t\t\t\t\t\tdispatchEvent(new CustomEvent(`${app}:update-keycloak`, { detail: keycloak }));\r\n\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t\t),\r\n\t\t\t\t\t\t\t// Browser arka plandayken refresh edilince token endpoint 400 (invalid_grant /\r\n\t\t\t\t\t\t\t// süresi dolmuş refresh token / silent-SSO timeout) dönüp `keycloak.init()` reject\r\n\t\t\t\t\t\t\t// olabiliyor. Yakalanmazsa \"ERROR undefined\" + auth'suz bozuk açılış oluyordu.\r\n\t\t\t\t\t\t\t// Hatayı yakalayıp temiz yeniden login'e yönlendir (Keycloak login → mevcut URL'e döner).\r\n\t\t\t\t\t\t\tcatchError((err) => {\r\n\t\t\t\t\t\t\t\tconsole.error(\"Keycloak init başarısız — yeniden login'e yönlendiriliyor:\", err);\r\n\t\t\t\t\t\t\t\tvoid keycloak.login();\r\n\t\t\t\t\t\t\t\treturn EMPTY;\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t}),\r\n\t\t\t\t\tswitchMap(\r\n\t\t\t\t\t\t() =>\r\n\t\t\t\t\t\t\tmicroAppService?.init(httpClient, API_CONFIGS.api).pipe(\r\n\t\t\t\t\t\t\t\ttap((result) => {\r\n\t\t\t\t\t\t\t\t\tbridge.hostMenuItems.set(result.menuItems);\r\n\t\t\t\t\t\t\t\t\tbridge.pluginJson.set(result.plugins);\r\n\t\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t\t) ?? EMPTY\r\n\t\t\t\t\t)\r\n\t\t\t\t)\r\n\t\t\t\t.subscribe()\r\n\t\t\t\t.add(resolve)\r\n\t\t);\r\n\r\n/**\r\n * only works when isHostMode is true\r\n * micro-app access its own api.json file when opened in host\r\n */\r\nexport function setApiConfigOnMFEMode(\r\n\thttpClient: HttpClient,\r\n\tkeycloak: KeycloakService,\r\n\tappName: Apps\r\n): () => Promise<any> {\r\n\treturn () => {\r\n\t\tconst observable$ = httpClient\r\n\t\t\t.get<ApiConfigsFactory>(isDevMode() ? './assets/local-configs/api.local.json' : './api.json')\r\n\t\t\t.pipe(\r\n\t\t\t\ttap((configs) => {\r\n\t\t\t\t\tObject.assign(API_CONFIGS, { ...configs });\r\n\t\t\t\t\tif (appName !== Apps.THOR && appName !== Apps.YEAP) {\r\n\t\t\t\t\t\tAPI_CONFIGS.api = API_CONFIGS.getExternalAppEndpoint(appName);\r\n\t\t\t\t\t}\r\n\t\t\t\t})\r\n\t\t\t);\r\n\r\n\t\treturn firstValueFrom(observable$);\r\n\t};\r\n}\r\n\r\nexport const loadInitData = (httpClient: HttpClient) => () =>\r\n\tnew Promise<void>((resolve, _reject) => {\r\n\t\tconst endpoint = API_CONFIGS.api + '/ui-route-content-configs/all';\r\n\t\thttpClient.get<RouteConfig[]>(endpoint).subscribe({\r\n\t\t\tnext: (data) => {\r\n\t\t\t\tbridge.routeConfigs.set(data);\r\n\t\t\t\tresolve();\r\n\t\t\t},\r\n\t\t\terror: (err) => {\r\n\t\t\t\tconsole.error(`Failed to load init data from ${endpoint}:`, err);\r\n\t\t\t\tresolve();\r\n\t\t\t}\r\n\t\t});\r\n\t});\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;AAEA,IAAY,UAEX,CAAA;AAFD,CAAA,UAAY,UAAU,EAAA;AACrB,IAAA,UAAA,CAAA,cAAA,CAAA,GAAA,YAA2B,CAAA;AAC5B,CAAC,EAFW,UAAU,KAAV,UAAU,GAErB,EAAA,CAAA,CAAA,CAAA;MAQY,iBAAiB,CAAA;AAA9B,IAAA,WAAA,GAAA;QACC,IAAG,CAAA,GAAA,GAAW,EAAE,CAAC;QACjB,IAAQ,CAAA,QAAA,GAAW,EAAE,CAAC;QACtB,IAAK,CAAA,KAAA,GAAW,EAAE,CAAC;QACnB,IAAK,CAAA,KAAA,GAAW,EAAE,CAAC;QACnB,IAAS,CAAA,SAAA,GAAW,EAAE,CAAC;QACvB,IAAW,CAAA,WAAA,GAAW,EAAE,CAAC;AAEzB,QAAA,IAAA,CAAA,MAAM,GAA+B;AACpC,YAAA,UAAU,EAAE,EAAE;SACd,CAAC;AACF,QAAA,IAAA,CAAA,SAAS,GAAyB;AACjC,YAAA,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE;AACf,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,OAAO,GAAG,EAAE;AAClB,YAAA,CAAC,IAAI,CAAC,OAAO,GAAG,EAAE;AAClB,YAAA,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE;AACf,YAAA,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE;AACb,YAAA,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE;AACf,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,aAAa,GAAG,EAAE;AACxB,YAAA,CAAC,IAAI,CAAC,GAAG,GAAE,EAAE;AACb,YAAA,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE;AACjB,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;AACd,YAAA,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE;SACd,CAAC;KAKF;AAJA,IAAA,sBAAsB,CAAC,OAAa,EAAA;AACnC,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACnE,QAAA,OAAO,CAAG,EAAA,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAI,CAAA,EAAA,MAAM,EAAE,CAAC;KAC/C;AACD;;ACnCY,MAAA,WAAW,GAAG,IAAI,iBAAiB,GAAG;AAEtC,MAAA,cAAc,GAC1B,CAAC,UAAsB,EAAE,QAAyB,EAAE,OAAe,EAAE,eAAiC,KAAK,MAC1G,IAAI,OAAO,CAAO,CAAC,OAAO,KACzB,UAAU;KACR,GAAG,CAAoB,SAAS,EAAE,GAAG,uCAAuC,GAAG,YAAY,CAAC;AAC5F,KAAA,IAAI,CACJ,SAAS,CAAC,CAAC,OAAO,KAAI;AACrB,IAAA,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAC7B,IAAA,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAE1B,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAE3C,IAAA,OAAO,IAAI,CACV,QAAQ,CAAC,IAAI,CAAC;QACb,MAAM,EAAE,WAAW,CAAC,QAAQ;AAC5B,QAAA,wBAAwB,EAAE,IAAI;QAC9B,WAAW,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,KAAK,EAAE;QAClE,kBAAkB,EAAE,CAAC,SAAS,CAAC;AAC/B,KAAA,CAAC,CACF,CAAC,IAAI,CACL,QAAQ,CAAC,MACR,gBAAgB,CAAC,cAAc,EAAE,CAAC,KAAK,KAAI;AAC1C,QAAA,MAAM,GAAG,GAAI,KAAqB,CAAC,MAAM,CAAC;AAC1C,QAAA,aAAa,CAAC,IAAI,WAAW,CAAC,GAAG,GAAG,CAAA,cAAA,CAAgB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAE7E,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAI;YAC3F,IAAI,CAAC,CAAC,IAAI,KAAK,iBAAiB,CAAC,oBAAoB,EAAE;AACtD,gBAAA,aAAa,CAAC,IAAI,WAAW,CAAC,GAAG,GAAG,CAAA,gBAAA,CAAkB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;aAC/E;AACF,SAAC,CAAC,CAAC;AACJ,KAAC,CAAC,CACF;;;;;AAKD,IAAA,UAAU,CAAC,CAAC,GAAG,KAAI;AAClB,QAAA,OAAO,CAAC,KAAK,CAAC,4DAA4D,EAAE,GAAG,CAAC,CAAC;AACjF,QAAA,KAAK,QAAQ,CAAC,KAAK,EAAE,CAAC;AACtB,QAAA,OAAO,KAAK,CAAC;KACb,CAAC,CACF,CAAC;AACH,CAAC,CAAC,EACF,SAAS,CACR,MACC,eAAe,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,CACtD,GAAG,CAAC,CAAC,MAAM,KAAI;IACd,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC,CAAC,CACF,IAAI,KAAK,CACX,CACD;AACA,KAAA,SAAS,EAAE;AACX,KAAA,GAAG,CAAC,OAAO,CAAC,EACb;AAEJ;;;AAGG;SACa,qBAAqB,CACpC,UAAsB,EACtB,QAAyB,EACzB,OAAa,EAAA;AAEb,IAAA,OAAO,MAAK;QACX,MAAM,WAAW,GAAG,UAAU;aAC5B,GAAG,CAAoB,SAAS,EAAE,GAAG,uCAAuC,GAAG,YAAY,CAAC;AAC5F,aAAA,IAAI,CACJ,GAAG,CAAC,CAAC,OAAO,KAAI;YACf,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAC3C,YAAA,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI,EAAE;gBACnD,WAAW,CAAC,GAAG,GAAG,WAAW,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;aAC9D;SACD,CAAC,CACF,CAAC;AAEH,QAAA,OAAO,cAAc,CAAC,WAAW,CAAC,CAAC;AACpC,KAAC,CAAC;AACH,CAAC;MAEY,YAAY,GAAG,CAAC,UAAsB,KAAK,MACvD,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,OAAO,KAAI;AACtC,IAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,GAAG,+BAA+B,CAAC;AACnE,IAAA,UAAU,CAAC,GAAG,CAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC;AACjD,QAAA,IAAI,EAAE,CAAC,IAAI,KAAI;AACd,YAAA,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC9B,YAAA,OAAO,EAAE,CAAC;SACV;AACD,QAAA,KAAK,EAAE,CAAC,GAAG,KAAI;YACd,OAAO,CAAC,KAAK,CAAC,CAAA,8BAAA,EAAiC,QAAQ,CAAG,CAAA,CAAA,EAAE,GAAG,CAAC,CAAC;AACjE,YAAA,OAAO,EAAE,CAAC;SACV;AACD,KAAA,CAAC,CAAC;AACJ,CAAC;;AC5GF;;AAEG;;;;"}
|