@apptimate/core-lib 3.5.0 → 3.6.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/package.json +1 -1
- package/src/constants/menus.ts +27 -1
- package/src/utils/apiProxy.ts +6 -2
- package/src/utils/httpClient.ts +10 -0
package/package.json
CHANGED
package/src/constants/menus.ts
CHANGED
|
@@ -3,6 +3,7 @@ export interface SubMenuItem {
|
|
|
3
3
|
label: string;
|
|
4
4
|
path: string;
|
|
5
5
|
permission?: string | null;
|
|
6
|
+
iconName?: string;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
export interface SubMenuGroup {
|
|
@@ -211,6 +212,16 @@ export const MENU_ITEM_REGISTRY: RegistryItem[] = [
|
|
|
211
212
|
{ key: 'reports__all', label: 'All Reports', path: '/reports', module: 'Reporting', defaultGroup: 'General', permission: null },
|
|
212
213
|
{ key: 'reports__builder', label: 'Report Builder', path: '/reports/admin/reports', module: 'Reporting', defaultGroup: 'Administration', permission: null },
|
|
213
214
|
{ key: 'reports__configurator', label: 'Dashboard Configurator', path: '/reports/admin/dashboards', module: 'Reporting', defaultGroup: 'Administration', permission: null },
|
|
215
|
+
|
|
216
|
+
// ── AI Analytics Module ──
|
|
217
|
+
{ key: 'ai_analytics__dashboard', label: 'Overview', path: '/ai-analytics', module: 'AI Analytics', defaultGroup: 'Overview', permission: null },
|
|
218
|
+
{ key: 'ai_analytics__recommendations', label: 'Recommendations', path: '/ai-analytics/recommendations', module: 'AI Analytics', defaultGroup: 'Insights', permission: null },
|
|
219
|
+
{ key: 'ai_analytics__reports', label: 'AI Reports', path: '/ai-analytics/reports', module: 'AI Analytics', defaultGroup: 'Insights', permission: null },
|
|
220
|
+
{ key: 'ai_analytics__usage', label: 'Usage Analytics', path: '/ai-analytics/usage', module: 'AI Analytics', defaultGroup: 'Insights', permission: null },
|
|
221
|
+
{ key: 'ai_analytics__forecasting', label: 'Forecasting', path: '/ai-analytics/forecasting', module: 'AI Analytics', defaultGroup: 'Advanced Models', permission: null },
|
|
222
|
+
{ key: 'ai_analytics__anomalies', label: 'Anomaly Detection', path: '/ai-analytics/anomalies', module: 'AI Analytics', defaultGroup: 'Advanced Models', permission: null },
|
|
223
|
+
{ key: 'ai_analytics__customer_intel', label: 'Customer Intel', path: '/ai-analytics/customer-intel', module: 'AI Analytics', defaultGroup: 'Intelligence', permission: null },
|
|
224
|
+
{ key: 'ai_analytics__pricing_intel', label: 'Pricing Intel', path: '/ai-analytics/pricing-intel', module: 'AI Analytics', defaultGroup: 'Intelligence', permission: null },
|
|
214
225
|
];
|
|
215
226
|
|
|
216
227
|
/**
|
|
@@ -400,6 +411,21 @@ export const MENU_PRESETS: MenuPreset[] = [
|
|
|
400
411
|
'reports__jewelry', 'reports__inventory', 'reports__finance',
|
|
401
412
|
'reports__all', 'reports__builder', 'reports__configurator'
|
|
402
413
|
]
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
id: 'ai_analytics',
|
|
417
|
+
label: 'AI',
|
|
418
|
+
iconName: 'BrainCircuit',
|
|
419
|
+
secondaryItems: [
|
|
420
|
+
'ai_analytics__dashboard',
|
|
421
|
+
'ai_analytics__recommendations',
|
|
422
|
+
'ai_analytics__reports',
|
|
423
|
+
'ai_analytics__usage',
|
|
424
|
+
'ai_analytics__forecasting',
|
|
425
|
+
'ai_analytics__anomalies',
|
|
426
|
+
'ai_analytics__customer_intel',
|
|
427
|
+
'ai_analytics__pricing_intel',
|
|
428
|
+
],
|
|
403
429
|
}
|
|
404
430
|
],
|
|
405
431
|
},
|
|
@@ -436,7 +462,7 @@ export function filterMenusByPermission(menus: MainMenuItem[], can: (code: strin
|
|
|
436
462
|
});
|
|
437
463
|
return { ...group, items: filteredItems };
|
|
438
464
|
}).filter(group => group.items.length > 0);
|
|
439
|
-
|
|
465
|
+
|
|
440
466
|
return { ...mainMenu, groups: filteredGroups };
|
|
441
467
|
}).filter(mainMenu => mainMenu.groups.length > 0);
|
|
442
468
|
}
|
package/src/utils/apiProxy.ts
CHANGED
|
@@ -86,7 +86,10 @@ export function createSessionLogoutResponse(): Response {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
export async function forwardApiProxyRequest(request: Request, pathSegments: string[]): Promise<Response> {
|
|
89
|
-
const
|
|
89
|
+
const targetApi = request.headers.get("x-target-api");
|
|
90
|
+
const apiBaseUrl = targetApi === 'ai_analytics'
|
|
91
|
+
? (process.env.NEXT_PUBLIC_AI_ANALYTICS_API_URL || "http://localhost:8002")
|
|
92
|
+
: process.env.NEXT_PUBLIC_API_URL;
|
|
90
93
|
|
|
91
94
|
if (!apiBaseUrl) {
|
|
92
95
|
return new Response(JSON.stringify({
|
|
@@ -143,7 +146,8 @@ export async function forwardApiProxyRequest(request: Request, pathSegments: str
|
|
|
143
146
|
|
|
144
147
|
const responseHeaders = new Headers();
|
|
145
148
|
upstreamResponse.headers.forEach((value, key) => {
|
|
146
|
-
|
|
149
|
+
const lowerKey = key.toLowerCase();
|
|
150
|
+
if (!HOP_BY_HOP_HEADERS.has(lowerKey) && lowerKey !== "x-target-api") {
|
|
147
151
|
responseHeaders.set(key, value);
|
|
148
152
|
}
|
|
149
153
|
});
|
package/src/utils/httpClient.ts
CHANGED
|
@@ -93,6 +93,15 @@ export async function sendRequest<T = any>({ url, method, data, params, headers,
|
|
|
93
93
|
// Client-side requests are routed through a same-origin proxy so the
|
|
94
94
|
// browser never needs direct access to the bearer token.
|
|
95
95
|
if (typeof window !== 'undefined') {
|
|
96
|
+
try {
|
|
97
|
+
const aiApiUrl = process.env.NEXT_PUBLIC_AI_ANALYTICS_API_URL;
|
|
98
|
+
if (aiApiUrl && finalUrl.startsWith(aiApiUrl)) {
|
|
99
|
+
defaultHeaders['X-Target-Api'] = 'ai_analytics';
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
// ignore
|
|
103
|
+
}
|
|
104
|
+
|
|
96
105
|
finalUrl = buildBrowserProxyUrl(finalUrl);
|
|
97
106
|
|
|
98
107
|
// Automatically inject selected organization ID into every request
|
|
@@ -119,6 +128,7 @@ export async function sendRequest<T = any>({ url, method, data, params, headers,
|
|
|
119
128
|
headers: { ...defaultHeaders, ...headers },
|
|
120
129
|
body: data instanceof FormData ? data : (data ? JSON.stringify(data) : undefined),
|
|
121
130
|
signal,
|
|
131
|
+
cache: 'no-store'
|
|
122
132
|
});
|
|
123
133
|
|
|
124
134
|
// Handle 401 Unauthorized globally — clear auth and redirect to login
|