indas-ui 0.1.3 → 0.1.5
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/dist/auth.d.ts +1 -0
- package/dist/auth.js +5 -0
- package/dist/cjs/auth.js +10 -0
- package/dist/cjs/components/chat/ai-messages.js +3 -2
- package/dist/cjs/components/chat/chat.js +4 -3
- package/dist/cjs/components/dashboard/FilterBar.js +31 -8
- package/dist/cjs/components/dashboard/charts/Area.js +6 -4
- package/dist/cjs/components/dashboard/charts/Bar.js +6 -4
- package/dist/cjs/components/dashboard/charts/FlowMap.js +2 -1
- package/dist/cjs/components/dashboard/charts/Funnel.js +2 -1
- package/dist/cjs/components/dashboard/charts/GeoMap.js +2 -1
- package/dist/cjs/components/dashboard/charts/Line.js +5 -3
- package/dist/cjs/components/dashboard/charts/Pareto.js +2 -1
- package/dist/cjs/components/dashboard/charts/Sankey.js +4 -3
- package/dist/cjs/components/dashboard/charts/Sparkline.js +2 -1
- package/dist/cjs/components/dashboard/charts/Treemap.js +2 -1
- package/dist/cjs/components/dashboard/charts/index.js +7 -1
- package/dist/cjs/components/dashboard/kpi/KpiBreakdown.js +3 -2
- package/dist/cjs/components/dashboard/kpi/KpiComparison.js +2 -1
- package/dist/cjs/components/dashboard/kpi/KpiQuickStats.js +2 -1
- package/dist/cjs/components/dashboard/kpi/KpiRating.js +3 -2
- package/dist/cjs/components/dashboard/time-range.js +71 -27
- package/dist/cjs/components/datagrid/columns/ColumnContextMenu.js +2 -1
- package/dist/cjs/components/datagrid/controls/menu/view/CardView.js +2 -1
- package/dist/cjs/components/datagrid/controls/menu/view/ChartView.js +2 -1
- package/dist/cjs/components/datagrid/utils/grid-helpers.js +6 -5
- package/dist/cjs/components/layout/footer.js +2 -1
- package/dist/cjs/components/layout/side-panel.js +4 -1
- package/dist/cjs/components/layout/sidebar.js +17 -2
- package/dist/cjs/components/messaging/messaging-panel-content.js +2 -2
- package/dist/cjs/components/ui/display/stats-card.js +2 -1
- package/dist/cjs/components/ui/navigation/tabs.js +4 -1
- package/dist/cjs/contexts/EmailContext.js +3 -2
- package/dist/cjs/contexts/MessagingContext.js +2 -2
- package/dist/cjs/contexts/NavigationContext.js +17 -2
- package/dist/cjs/contexts/NotificationContext.js +2 -2
- package/dist/cjs/contexts/SessionAdapterContext.js +8 -0
- package/dist/cjs/hooks/useApproval.js +2 -2
- package/dist/cjs/hooks/useBusinessAudit.js +2 -2
- package/dist/cjs/hooks/useDraft.js +2 -2
- package/dist/cjs/lib/api/utility/menu.js +8 -7
- package/dist/cjs/lib/number-format.js +60 -0
- package/dist/cjs/lib/utils.js +4 -3
- package/dist/cjs/providers.js +3 -3
- package/dist/components/auth/index.js +0 -1
- package/dist/components/chat/ai-messages.js +3 -2
- package/dist/components/chat/chat.js +4 -3
- package/dist/components/chat/index.js +0 -1
- package/dist/components/dashboard/FilterBar.d.ts +5 -1
- package/dist/components/dashboard/FilterBar.js +31 -8
- package/dist/components/dashboard/charts/Area.d.ts +5 -1
- package/dist/components/dashboard/charts/Area.js +6 -4
- package/dist/components/dashboard/charts/Bar.d.ts +5 -1
- package/dist/components/dashboard/charts/Bar.js +6 -4
- package/dist/components/dashboard/charts/FlowMap.js +2 -1
- package/dist/components/dashboard/charts/Funnel.js +2 -1
- package/dist/components/dashboard/charts/GeoMap.js +2 -1
- package/dist/components/dashboard/charts/Line.d.ts +5 -1
- package/dist/components/dashboard/charts/Line.js +5 -3
- package/dist/components/dashboard/charts/Pareto.js +2 -1
- package/dist/components/dashboard/charts/Sankey.js +4 -3
- package/dist/components/dashboard/charts/Sparkline.js +2 -1
- package/dist/components/dashboard/charts/Treemap.js +2 -1
- package/dist/components/dashboard/charts/index.d.ts +1 -0
- package/dist/components/dashboard/charts/index.js +2 -1
- package/dist/components/dashboard/index.js +0 -1
- package/dist/components/dashboard/kpi/KpiBreakdown.js +3 -2
- package/dist/components/dashboard/kpi/KpiComparison.js +2 -1
- package/dist/components/dashboard/kpi/KpiQuickStats.js +2 -1
- package/dist/components/dashboard/kpi/KpiRating.js +3 -2
- package/dist/components/dashboard/kpi/index.js +0 -1
- package/dist/components/dashboard/time-range.d.ts +12 -1
- package/dist/components/dashboard/time-range.js +71 -27
- package/dist/components/datagrid/cells/index.js +0 -1
- package/dist/components/datagrid/columns/ColumnContextMenu.js +2 -1
- package/dist/components/datagrid/controls/menu/grouping/index.js +0 -1
- package/dist/components/datagrid/controls/menu/index.js +0 -1
- package/dist/components/datagrid/controls/menu/view/CardView.js +2 -1
- package/dist/components/datagrid/controls/menu/view/ChartView.js +2 -1
- package/dist/components/datagrid/index.js +0 -1
- package/dist/components/datagrid/utils/grid-helpers.d.ts +1 -1
- package/dist/components/datagrid/utils/grid-helpers.js +3 -2
- package/dist/components/forms/date-picker/index.js +0 -1
- package/dist/components/forms/dropdown/index.js +0 -1
- package/dist/components/forms/file-attachment/index.js +0 -1
- package/dist/components/forms/index.js +0 -1
- package/dist/components/forms/remark-input/index.js +0 -1
- package/dist/components/index.js +0 -1
- package/dist/components/layout/footer.js +2 -1
- package/dist/components/layout/index.js +0 -1
- package/dist/components/layout/side-panel.js +4 -1
- package/dist/components/layout/sidebar.js +17 -2
- package/dist/components/master/editable-cells/index.js +0 -1
- package/dist/components/master/index.js +0 -1
- package/dist/components/messaging/messaging-panel-content.js +2 -2
- package/dist/components/modals/index.js +0 -1
- package/dist/components/ui/display/stats-card.js +2 -1
- package/dist/components/ui/feedback/badge.d.ts +1 -1
- package/dist/components/ui/index.js +0 -1
- package/dist/components/ui/navigation/tabs.js +4 -1
- package/dist/contexts/EmailContext.js +3 -2
- package/dist/contexts/MessagingContext.js +2 -2
- package/dist/contexts/NavigationContext.js +17 -2
- package/dist/contexts/NotificationContext.js +2 -2
- package/dist/contexts/SessionAdapterContext.d.ts +5 -0
- package/dist/contexts/SessionAdapterContext.js +7 -0
- package/dist/hooks/index.js +0 -1
- package/dist/hooks/useApproval.js +2 -2
- package/dist/hooks/useBusinessAudit.js +2 -2
- package/dist/hooks/useDraft.js +2 -2
- package/dist/index.js +0 -1
- package/dist/lib/api/activity/audit/index.js +0 -1
- package/dist/lib/api/activity/email/index.js +0 -1
- package/dist/lib/api/activity/index.js +0 -1
- package/dist/lib/api/activity/notifications/index.js +0 -1
- package/dist/lib/api/activity/remarks/index.js +0 -1
- package/dist/lib/api/approval/index.js +0 -1
- package/dist/lib/api/auth/index.js +0 -1
- package/dist/lib/api/core/index.js +0 -1
- package/dist/lib/api/draft/index.js +0 -1
- package/dist/lib/api/enquiry/index.js +0 -1
- package/dist/lib/api/estimation/index.js +0 -1
- package/dist/lib/api/index.js +0 -1
- package/dist/lib/api/master/index.js +0 -1
- package/dist/lib/api/utility/index.js +0 -1
- package/dist/lib/api/utility/menu.d.ts +7 -3
- package/dist/lib/api/utility/menu.js +8 -7
- package/dist/lib/number-format.d.ts +18 -0
- package/dist/lib/number-format.js +54 -0
- package/dist/lib/utils.js +4 -3
- package/dist/providers.d.ts +0 -1
- package/dist/providers.js +2 -2
- package/package.json +23 -8
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AuthSessionProvider } from './components/providers/session-provider.js';
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Auth entry: `import { AuthSessionProvider } from 'indas-ui/auth'`
|
|
2
|
+
// The one entry that needs next-auth (an optional peer dependency): it feeds next-auth's session into
|
|
3
|
+
// the library's session adapter, which every other component reads. Apps on another sign-in system
|
|
4
|
+
// skip this entry and use SessionAdapterProvider from 'indas-ui/providers' instead.
|
|
5
|
+
export { AuthSessionProvider } from './components/providers/session-provider.js';
|
package/dist/cjs/auth.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.AuthSessionProvider = void 0;
|
|
5
|
+
// Auth entry: `import { AuthSessionProvider } from 'indas-ui/auth'`
|
|
6
|
+
// The one entry that needs next-auth (an optional peer dependency): it feeds next-auth's session into
|
|
7
|
+
// the library's session adapter, which every other component reads. Apps on another sign-in system
|
|
8
|
+
// skip this entry and use SessionAdapterProvider from 'indas-ui/providers' instead.
|
|
9
|
+
var session_provider_1 = require("./components/providers/session-provider.js");
|
|
10
|
+
Object.defineProperty(exports, "AuthSessionProvider", { enumerable: true, get: function () { return session_provider_1.AuthSessionProvider; } });
|
|
@@ -16,6 +16,7 @@ const utils_1 = require("../../lib/utils.js");
|
|
|
16
16
|
const lucide_react_1 = require("lucide-react");
|
|
17
17
|
const react_markdown_1 = __importDefault(require("react-markdown"));
|
|
18
18
|
const remark_gfm_1 = __importDefault(require("remark-gfm"));
|
|
19
|
+
const number_format_1 = require("../../lib/number-format.js");
|
|
19
20
|
// Individual Message Bubble Component
|
|
20
21
|
function Message({ message, onSelectItem, onEditMessage, onRegenerateAi, onFeedback, botAvatar, renderBotContent }) {
|
|
21
22
|
const isUser = message.role === 'user';
|
|
@@ -164,7 +165,7 @@ function Message({ message, onSelectItem, onEditMessage, onRegenerateAi, onFeedb
|
|
|
164
165
|
return full;
|
|
165
166
|
});
|
|
166
167
|
return processed;
|
|
167
|
-
})() }) })) })) })) }), !isEditing && ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('flex items-center gap-2 mt-1 opacity-0 group-hover:opacity-100 transition-opacity duration-200', isUser ? 'justify-end' : 'justify-start'), children: [formattedTimestamp && ((0, jsx_runtime_1.jsx)("span", { className: "text-[0.7rem] text-[rgb(var(--fg-muted))]/70 select-none", children: formattedTimestamp })), isUser && onEditMessage && ((0, jsx_runtime_1.jsx)("button", { onClick: handleRegenerate, className: "w-7 h-7 rounded-md flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-colors", "aria-label": "Regenerate response", title: "Regenerate", children: (0, jsx_runtime_1.jsx)(lucide_react_1.RotateCcw, { className: "w-3.5 h-3.5" }) })), isUser && onEditMessage && ((0, jsx_runtime_1.jsx)("button", { onClick: handleStartEdit, className: "w-7 h-7 rounded-md flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-colors", "aria-label": "Edit message", title: "Edit", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { className: "w-3.5 h-3.5" }) })), (0, jsx_runtime_1.jsx)("button", { onClick: handleCopy, className: "w-7 h-7 rounded-md flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-colors", "aria-label": "Copy message", title: "Copy", children: copied ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Check, { className: "w-3.5 h-3.5" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { className: "w-3.5 h-3.5" })) }), !isUser && onRegenerateAi && ((0, jsx_runtime_1.jsx)("button", { onClick: handleRegenerateAi, className: "w-7 h-7 rounded-md flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-colors", "aria-label": "Regenerate response", title: "Regenerate", children: (0, jsx_runtime_1.jsx)(lucide_react_1.RotateCcw, { className: "w-3.5 h-3.5" }) })), !isUser && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => handleFeedback('up'), className: "w-7 h-7 rounded-md flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-colors", "aria-label": "Good response", title: "Good response", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ThumbsUp, { className: "w-3.5 h-3.5", fill: feedback === 'up' ? 'currentColor' : 'none' }) }), (0, jsx_runtime_1.jsx)("button", { onClick: () => handleFeedback('down'), className: "w-7 h-7 rounded-md flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-colors", "aria-label": "Bad response", title: "Bad response", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ThumbsDown, { className: "w-3.5 h-3.5", fill: feedback === 'down' ? 'currentColor' : 'none' }) })] })), !isUser && message.tokens && process.env.NEXT_PUBLIC_SHOW_TOKENS === 'true' && ((0, jsx_runtime_1.jsxs)("span", { className: "text-[0.65rem] text-[rgb(var(--fg-muted))]/70 font-mono select-none ml-1", children: ["P: ", message.tokens.prompt
|
|
168
|
+
})() }) })) })) })) }), !isEditing && ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('flex items-center gap-2 mt-1 opacity-0 group-hover:opacity-100 transition-opacity duration-200', isUser ? 'justify-end' : 'justify-start'), children: [formattedTimestamp && ((0, jsx_runtime_1.jsx)("span", { className: "text-[0.7rem] text-[rgb(var(--fg-muted))]/70 select-none", children: formattedTimestamp })), isUser && onEditMessage && ((0, jsx_runtime_1.jsx)("button", { onClick: handleRegenerate, className: "w-7 h-7 rounded-md flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-colors", "aria-label": "Regenerate response", title: "Regenerate", children: (0, jsx_runtime_1.jsx)(lucide_react_1.RotateCcw, { className: "w-3.5 h-3.5" }) })), isUser && onEditMessage && ((0, jsx_runtime_1.jsx)("button", { onClick: handleStartEdit, className: "w-7 h-7 rounded-md flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-colors", "aria-label": "Edit message", title: "Edit", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { className: "w-3.5 h-3.5" }) })), (0, jsx_runtime_1.jsx)("button", { onClick: handleCopy, className: "w-7 h-7 rounded-md flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-colors", "aria-label": "Copy message", title: "Copy", children: copied ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Check, { className: "w-3.5 h-3.5" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { className: "w-3.5 h-3.5" })) }), !isUser && onRegenerateAi && ((0, jsx_runtime_1.jsx)("button", { onClick: handleRegenerateAi, className: "w-7 h-7 rounded-md flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-colors", "aria-label": "Regenerate response", title: "Regenerate", children: (0, jsx_runtime_1.jsx)(lucide_react_1.RotateCcw, { className: "w-3.5 h-3.5" }) })), !isUser && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => handleFeedback('up'), className: "w-7 h-7 rounded-md flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-colors", "aria-label": "Good response", title: "Good response", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ThumbsUp, { className: "w-3.5 h-3.5", fill: feedback === 'up' ? 'currentColor' : 'none' }) }), (0, jsx_runtime_1.jsx)("button", { onClick: () => handleFeedback('down'), className: "w-7 h-7 rounded-md flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-colors", "aria-label": "Bad response", title: "Bad response", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ThumbsDown, { className: "w-3.5 h-3.5", fill: feedback === 'down' ? 'currentColor' : 'none' }) })] })), !isUser && message.tokens && process.env.NEXT_PUBLIC_SHOW_TOKENS === 'true' && ((0, jsx_runtime_1.jsxs)("span", { className: "text-[0.65rem] text-[rgb(var(--fg-muted))]/70 font-mono select-none ml-1", children: ["P: ", (0, number_format_1.formatNumber)(message.tokens.prompt), " R: ", (0, number_format_1.formatNumber)(message.tokens.completion), " T: ", (0, number_format_1.formatNumber)(message.tokens.total)] }))] }))] })] }));
|
|
168
169
|
}
|
|
169
170
|
// Synthia thinking phrases — the fun ones
|
|
170
171
|
const SYNTHIA_THINKING = [
|
|
@@ -266,6 +267,6 @@ function Messages({ messages, isLoading = false, onExport, onShare, onSelectItem
|
|
|
266
267
|
}, { prompt: 0, completion: 0, total: 0 });
|
|
267
268
|
if (totals.total === 0)
|
|
268
269
|
return (0, jsx_runtime_1.jsx)("div", {});
|
|
269
|
-
return ((0, jsx_runtime_1.jsxs)("span", { className: "text-[0.65rem] text-[rgb(var(--fg-muted))] font-mono", children: ["P:", totals.prompt
|
|
270
|
+
return ((0, jsx_runtime_1.jsxs)("span", { className: "text-[0.65rem] text-[rgb(var(--fg-muted))] font-mono", children: ["P:", (0, number_format_1.formatNumber)(totals.prompt), " \u00B7 C:", (0, number_format_1.formatNumber)(totals.completion), " \u00B7 T:", (0, number_format_1.formatNumber)(totals.total), " \u00B7 ", messages.filter(m => m.tokens).length, " calls"] }));
|
|
270
271
|
})() : (0, jsx_runtime_1.jsx)("div", {}), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [onExport && ((0, jsx_runtime_1.jsxs)("button", { onClick: onExport, className: "flex items-center gap-2 px-3 py-1.5 text-sm text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] rounded-lg transition-colors", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Download, { className: "w-4 h-4" }), "Export"] })), onShare && ((0, jsx_runtime_1.jsxs)("button", { onClick: onShare, className: "flex items-center gap-2 px-3 py-1.5 text-sm text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] rounded-lg transition-colors", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Share2, { className: "w-4 h-4" }), "Share"] }))] })] })), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 overflow-y-auto", children: (0, jsx_runtime_1.jsxs)("div", { className: "max-w-5xl mx-auto px-3 sm:px-4 py-6 space-y-6 animate-[fadeInUp_0.28s_ease-out]", children: [messages.map((message) => ((0, jsx_runtime_1.jsx)(Message, { message: message, onSelectItem: onSelectItem, onEditMessage: onEditMessage, onRegenerateAi: onRegenerateAi, onFeedback: onFeedback, botAvatar: botAvatar, renderBotContent: renderBotContent }, message.id))), isLoading && (0, jsx_runtime_1.jsx)(TypingIndicator, { lastUserMessage: messages.filter(m => m.role === 'user').at(-1)?.content }), (0, jsx_runtime_1.jsx)("div", { ref: bottomRef })] }, fadeKey) })] }));
|
|
271
272
|
}
|
|
@@ -8,7 +8,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
8
8
|
* Domain-specific branding (logo, title, messages) is injected via props.
|
|
9
9
|
*/
|
|
10
10
|
const react_1 = require("react");
|
|
11
|
-
const
|
|
11
|
+
const SessionAdapterContext_1 = require("../../contexts/SessionAdapterContext.js");
|
|
12
12
|
const navigation_1 = require("next/navigation");
|
|
13
13
|
const lucide_react_1 = require("lucide-react");
|
|
14
14
|
const utils_1 = require("../../lib/utils.js");
|
|
@@ -21,6 +21,7 @@ const multimodal_input_1 = require("./multimodal-input.js");
|
|
|
21
21
|
const chat_prompt_navigator_1 = require("./chat-prompt-navigator.js");
|
|
22
22
|
const date_picker_1 = require("../forms/date-picker/index.js");
|
|
23
23
|
const utils_2 = require("../../lib/utils.js");
|
|
24
|
+
const number_format_1 = require("../../lib/number-format.js");
|
|
24
25
|
function buildSendPayload(ctx, message, autoTitle) {
|
|
25
26
|
if (ctx.mode === 'new') {
|
|
26
27
|
return { message, conversationId: undefined, newChat: true, title: autoTitle };
|
|
@@ -64,7 +65,7 @@ function bucketForDate(iso, now = new Date()) {
|
|
|
64
65
|
return { id: `m-${d.getFullYear()}-${d.getMonth()}`, label: monthLabel, sort };
|
|
65
66
|
}
|
|
66
67
|
function Chat({ mode = 'fullpage', externalMuted, title = 'Chat', sidebarTitle, bubbleLogo, logo, MessagesComponent, fullpagePath, onBeforeEditMessage, initialMessage, initialConversationId, headerActions, onMessagesChange }) {
|
|
67
|
-
const
|
|
68
|
+
const session = (0, SessionAdapterContext_1.useOptionalSessionAdapter)()?.data ?? null;
|
|
68
69
|
const router = (0, navigation_1.useRouter)();
|
|
69
70
|
const alerts = (0, GlobalAlertContext_1.useGlobalAlert)();
|
|
70
71
|
const { t } = (0, LanguageContext_1.useLanguage)();
|
|
@@ -1022,7 +1023,7 @@ function Chat({ mode = 'fullpage', externalMuted, title = 'Chat', sidebarTitle,
|
|
|
1022
1023
|
}, { prompt: 0, completion: 0, total: 0 });
|
|
1023
1024
|
if (totals.total === 0)
|
|
1024
1025
|
return null;
|
|
1025
|
-
return ((0, jsx_runtime_1.jsxs)("span", { className: "text-[0.65rem] text-[rgb(var(--fg-muted))] font-mono", children: ["Prompt: ", totals.prompt
|
|
1026
|
+
return ((0, jsx_runtime_1.jsxs)("span", { className: "text-[0.65rem] text-[rgb(var(--fg-muted))] font-mono", children: ["Prompt: ", (0, number_format_1.formatNumber)(totals.prompt), " \u00B7 Response: ", (0, number_format_1.formatNumber)(totals.completion), " \u00B7 Total: ", (0, number_format_1.formatNumber)(totals.total), " tokens \u00B7 ", messages.filter(m => m.tokens).length, " calls"] }));
|
|
1026
1027
|
})(), (0, jsx_runtime_1.jsxs)("div", { className: "absolute right-3 flex items-center gap-0.5", children: [headerActions, (0, jsx_runtime_1.jsx)("button", { onClick: () => setIsMuted(!isMuted), className: "w-7 h-7 flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] rounded-md transition-colors", title: isMuted ? "Unmute sounds" : "Mute sounds", children: isMuted ? (0, jsx_runtime_1.jsx)(lucide_react_1.VolumeX, { className: "w-3.5 h-3.5" }) : (0, jsx_runtime_1.jsx)(lucide_react_1.Volume2, { className: "w-3.5 h-3.5" }) }), messages.length > 0 && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("button", { onClick: handleExport, className: "w-7 h-7 flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] rounded-md transition-colors", title: t('Export'), children: (0, jsx_runtime_1.jsx)(lucide_react_1.Download, { className: "w-3.5 h-3.5" }) }), (0, jsx_runtime_1.jsx)("button", { onClick: handleShare, className: "w-7 h-7 flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] rounded-md transition-colors", title: t('Share'), children: (0, jsx_runtime_1.jsx)(lucide_react_1.Share2, { className: "w-3.5 h-3.5" }) })] })), fullpagePath && mode === 'modal' && ((0, jsx_runtime_1.jsx)("button", { onClick: () => {
|
|
1027
1028
|
const target = currentConversationId
|
|
1028
1029
|
? `${fullpagePath}?c=${currentConversationId}`
|
|
@@ -220,7 +220,7 @@ const fmtFiscalDay = (d) => `${String(d.getDate()).padStart(2, '0')} ${SHORT_MON
|
|
|
220
220
|
// Fiscal-year-aware dropdown options. FY runs 1 Apr (fyStart) → 31 Mar (fyStart+1).
|
|
221
221
|
// Weeks are W1..W52/53 counting 7-day spans from 1 Apr; months ordered Apr→Mar;
|
|
222
222
|
// quarters Q1 Apr-Jun … Q4 Jan-Mar; year shown as "YYYY-YYYY".
|
|
223
|
-
function buildTimeOptions(fyStart) {
|
|
223
|
+
function buildTimeOptions(fyStart, allTime = false) {
|
|
224
224
|
const fyOpen = new Date(fyStart, 3, 1);
|
|
225
225
|
const fyClose = new Date(fyStart + 1, 2, 31);
|
|
226
226
|
// Monday-aligned weeks clamped to the FY: W1 = 1 Apr → first Sunday (partial),
|
|
@@ -248,7 +248,10 @@ function buildTimeOptions(fyStart) {
|
|
|
248
248
|
{ value: 'Q3', label: `Q3 (Oct – Dec ${fyStart})` },
|
|
249
249
|
{ value: 'Q4', label: `Q4 (Jan – Mar ${fyStart + 1})` },
|
|
250
250
|
];
|
|
251
|
-
|
|
251
|
+
// This financial year and the two before it, newest first; "All Time" last where the host offers it.
|
|
252
|
+
const years = [0, 1, 2].map(n => ({ value: `${fyStart - n}`, label: `FY ${fyStart - n}-${String(fyStart - n + 1).slice(2)}` }));
|
|
253
|
+
if (allTime)
|
|
254
|
+
years.push({ value: 'all', label: 'All Time' });
|
|
252
255
|
return [
|
|
253
256
|
{ value: 'Day', label: 'Day', dropdownOptions: DAY_OPTIONS, quickOptions: DAY_QUICK },
|
|
254
257
|
{ value: 'Week', label: 'Week', dropdownOptions: weeks, quickOptions: WEEK_QUICK },
|
|
@@ -324,11 +327,31 @@ function ForecastControl({ forecast, onForecastChange, timeFilter, onTimeFilterC
|
|
|
324
327
|
? 'text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))]'
|
|
325
328
|
: 'text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-subtle))] hover:border-[rgb(var(--color-primary))] hover:text-[rgb(var(--color-primary))]'), title: t('Forecast'), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.TrendingUp, { className: "w-4 h-4" }), forecast.enabled && !open && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -top-1 -right-1 w-2 h-2 bg-[rgb(var(--color-primary))] rounded-full" }))] }), open && ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('absolute top-full right-0 mt-2 z-50 w-96 max-w-[calc(100vw-2rem)]', 'bg-[rgb(var(--bg-surface))] rounded-xl shadow-xl border border-[rgb(var(--bd-default))]', 'overflow-hidden'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "px-3 py-2 border-b border-[rgb(var(--bd-default))] flex items-center justify-between gap-2", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs font-semibold text-[rgb(var(--fg-default))] shrink-0", children: t('Forecast') }), onTimeFilterChange ? ((0, jsx_runtime_1.jsx)(dropdown_1.Dropdown, { options: TIME_FILTER_OPTIONS.map(o => ({ value: o.value, label: t(o.label) })), value: timeFilter, onValueChange: (v) => onTimeFilterChange(v), searchable: false, size: "sm", triggerClassName: "h-6 text-[11px] min-w-[6.5rem]" })) : ((0, jsx_runtime_1.jsxs)("span", { className: "text-[10px] text-[rgb(var(--fg-muted))]", children: ["\u00B7 ", t(timeFilter)] }))] }), (0, jsx_runtime_1.jsx)(ui_1.Switch, { checked: forecast.enabled, onCheckedChange: (enabled) => onForecastChange({ ...forecast, enabled }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('p-3 space-y-3', !forecast.enabled && 'opacity-50 pointer-events-none'), children: [(0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: exports.FORECAST_METHODS.map(m => ({ id: m.value, label: t(m.label) })), activeTab: forecast.method, onTabChange: (tabId) => onForecastChange({ ...forecast, method: tabId }), variant: "rounded", size: "sm", fullWidth: true }), activeMethod && ((0, jsx_runtime_1.jsx)("p", { className: "text-[10px] text-[rgb(var(--fg-muted))]", children: t(activeMethod.hint) })), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: t('Based On Last') }), (0, jsx_runtime_1.jsx)(Stepper, { value: forecast.period, min: limits.min, max: limits.max, onChange: setPeriod }), (0, jsx_runtime_1.jsx)("p", { className: "mt-1 text-[10px] text-[rgb(var(--fg-muted))] truncate", children: resolvePeriodRange(timeFilter, forecast.period, -1) })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: t('Forecast Ahead') }), (0, jsx_runtime_1.jsx)(Stepper, { value: forecast.horizon, min: horizonLimits.min, max: horizonLimits.max, onChange: setHorizon }), (0, jsx_runtime_1.jsx)("p", { className: "mt-1 text-[10px] text-[rgb(var(--fg-muted))] truncate", children: resolvePeriodRange(timeFilter, forecast.horizon, 1) })] })] })] })] }))] }));
|
|
326
329
|
}
|
|
327
|
-
function FilterBar({ title, contextLabel, secondaryToggle, timeFilter = 'Week', onTimeFilterChange, timeFilterSelection, onTimeFilterSelectionChange, hideTimeFilter = false, filters = [], filterValues = {}, onFilterChange, dateFrom, dateTo, onDateFromChange, onDateToChange, onApply, onReset, reports = [], onReportSelect, onExport, hideFilterButton = false, hideDateRange = false, showApplyButton = false, forecast, onForecastChange, onShare, showInsights = false, insightsActive = false, onInsightsClick, children, className, layout = 'default', fiscalStartYear }) {
|
|
330
|
+
function FilterBar({ title, contextLabel, description, secondaryToggle, timeFilter = 'Week', onTimeFilterChange, timeFilterSelection, onTimeFilterSelectionChange, hideTimeFilter = false, filters = [], filterValues = {}, onFilterChange, dateFrom, dateTo, onDateFromChange, onDateToChange, onApply, onReset, reports = [], onReportSelect, onExport, hideFilterButton = false, hideDateRange = false, showApplyButton = false, forecast, onForecastChange, onShare, showInsights = false, insightsActive = false, onInsightsClick, children, className, layout = 'default', fiscalStartYear, allTime = false, }) {
|
|
328
331
|
const [popoverOpen, setPopoverOpen] = (0, react_1.useState)(false);
|
|
329
332
|
const popoverRef = (0, react_1.useRef)(null);
|
|
330
333
|
const buttonRef = (0, react_1.useRef)(null);
|
|
331
|
-
|
|
334
|
+
// The divider between the secondary toggle and the time tabs only makes sense while they share a
|
|
335
|
+
// line. When the row wraps (narrow screens, long toggle labels), it would be left hanging at the
|
|
336
|
+
// end of the first line, so it hides.
|
|
337
|
+
const toggleRef = (0, react_1.useRef)(null);
|
|
338
|
+
const timeTabsRef = (0, react_1.useRef)(null);
|
|
339
|
+
const [tabsWrapped, setTabsWrapped] = (0, react_1.useState)(false);
|
|
340
|
+
(0, react_1.useEffect)(() => {
|
|
341
|
+
const a = toggleRef.current;
|
|
342
|
+
const b = timeTabsRef.current;
|
|
343
|
+
if (!a || !b || typeof ResizeObserver === 'undefined')
|
|
344
|
+
return;
|
|
345
|
+
const check = () => setTabsWrapped(a.offsetTop !== b.offsetTop);
|
|
346
|
+
const ro = new ResizeObserver(check);
|
|
347
|
+
ro.observe(a);
|
|
348
|
+
ro.observe(b);
|
|
349
|
+
if (a.parentElement)
|
|
350
|
+
ro.observe(a.parentElement);
|
|
351
|
+
check();
|
|
352
|
+
return () => ro.disconnect();
|
|
353
|
+
}, [secondaryToggle, hideTimeFilter]);
|
|
354
|
+
const timeOptions = (0, react_1.useMemo)(() => (fiscalStartYear ? buildTimeOptions(fiscalStartYear, allTime) : TIME_FILTER_OPTIONS), [fiscalStartYear, allTime]);
|
|
332
355
|
// Handle click outside. Ignore clicks landing inside a portalled dropdown/select
|
|
333
356
|
// list (rendered to document.body, outside popoverRef) so selecting a filter
|
|
334
357
|
// option doesn't close this popover before the value commits.
|
|
@@ -391,10 +414,10 @@ function FilterBar({ title, contextLabel, secondaryToggle, timeFilter = 'Week',
|
|
|
391
414
|
...(filter === 'Year' && { years: selectedValues }),
|
|
392
415
|
};
|
|
393
416
|
onTimeFilterSelectionChange?.(newSelection);
|
|
394
|
-
} }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 text-center", children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-sm font-semibold text-[rgb(var(--fg-default))]", children: title }), contextLabel && ((0, jsx_runtime_1.jsx)("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: contextLabel }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [!hideFilterButton && ((0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsxs)("button", { ref: buttonRef, onClick: () => setPopoverOpen(!popoverOpen), className: (0, utils_1.cn)('w-8 h-8 rounded-md flex items-center justify-center transition-colors relative', 'border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))]', 'text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-subtle))] hover:border-[rgb(var(--color-primary))] hover:text-[rgb(var(--color-primary))]', popoverOpen && 'bg-[rgb(var(--color-primary))] text-white border-[rgb(var(--color-primary))] hover:bg-[rgb(var(--color-primary))]'), title: "Filters", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ListFilter, { className: "w-4 h-4" }), hasActiveFilters && !popoverOpen && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -top-1 -right-1 w-2 h-2 bg-[rgb(var(--color-primary))] rounded-full" }))] }), popoverOpen && ((0, jsx_runtime_1.jsxs)("div", { ref: popoverRef, className: (0, utils_1.cn)('absolute top-full right-0 mt-2 z-50', 'w-[95vw] sm:w-auto', 'bg-[rgb(var(--bg-surface))] rounded-xl shadow-xl border border-[rgb(var(--bd-default))]', 'overflow-hidden'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "px-3 py-2 border-b border-[rgb(var(--bd-default))] flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs font-semibold text-[rgb(var(--fg-default))]", children: "Filters" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setPopoverOpen(false), className: "w-5 h-5 rounded flex items-center justify-center hover:bg-[rgb(var(--bg-subtle))] transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-3 space-y-3", children: [filters.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "grid gap-3", style: { gridTemplateColumns: `repeat(${filters.length}, minmax(140px, 1fr))` }, children: filters.map((filter) => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: filter.label }), (0, jsx_runtime_1.jsx)(dropdown_1.Dropdown, { options: filter.options, multiSelect: filter.type === 'multiselect', value: filterValues[filter.id] ?? (filter.type === 'multiselect' ? [] : ''), onValueChange: (value) => onFilterChange?.(filter.id, value), placeholder: filter.placeholder || `All ${filter.label}s`, searchable: true, className: "w-full" })] }, filter.id))) })), children, !hideDateRange && ((0, jsx_runtime_1.jsx)(date_picker_1.DatePicker, { mode: "range", value: dateRangeValue, onChange: handleDateRangeChange, inline: true }))] })] }))] })), forecast && onForecastChange && ((0, jsx_runtime_1.jsx)(ForecastControl, { forecast: forecast, onForecastChange: onForecastChange, timeFilter: timeFilter, onTimeFilterChange: onTimeFilterChange })), showApplyButton && ((0, jsx_runtime_1.jsx)("button", { onClick: onApply, className: (0, utils_1.cn)('h-8 px-4 rounded-md flex items-center gap-1.5', 'bg-[rgb(var(--color-primary))] text-white', 'text-xs font-semibold', 'shadow-sm hover:shadow-md transition-all', 'hover:brightness-110'), children: "Apply" })), (reports.length > 0 || onShare || onExport) && ((0, jsx_runtime_1.jsx)(OverflowMenu, { reports: reports, onReportSelect: onReportSelect, onShare: onShare, onExport: onExport }))] })] }) }) }));
|
|
417
|
+
} }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 text-center", children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-sm font-semibold text-[rgb(var(--fg-default))]", children: title }), contextLabel && ((0, jsx_runtime_1.jsx)("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: contextLabel })), description && (0, jsx_runtime_1.jsx)("p", { className: "mt-0.5 text-xs text-[rgb(var(--fg-muted))]", children: description })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [!hideFilterButton && ((0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsxs)("button", { ref: buttonRef, onClick: () => setPopoverOpen(!popoverOpen), className: (0, utils_1.cn)('w-8 h-8 rounded-md flex items-center justify-center transition-colors relative', 'border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))]', 'text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-subtle))] hover:border-[rgb(var(--color-primary))] hover:text-[rgb(var(--color-primary))]', popoverOpen && 'bg-[rgb(var(--color-primary))] text-white border-[rgb(var(--color-primary))] hover:bg-[rgb(var(--color-primary))]'), title: "Filters", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ListFilter, { className: "w-4 h-4" }), hasActiveFilters && !popoverOpen && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -top-1 -right-1 w-2 h-2 bg-[rgb(var(--color-primary))] rounded-full" }))] }), popoverOpen && ((0, jsx_runtime_1.jsxs)("div", { ref: popoverRef, className: (0, utils_1.cn)('absolute top-full right-0 mt-2 z-50', 'w-[95vw] sm:w-auto', 'bg-[rgb(var(--bg-surface))] rounded-xl shadow-xl border border-[rgb(var(--bd-default))]', 'overflow-hidden'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "px-3 py-2 border-b border-[rgb(var(--bd-default))] flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs font-semibold text-[rgb(var(--fg-default))]", children: "Filters" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setPopoverOpen(false), className: "w-5 h-5 rounded flex items-center justify-center hover:bg-[rgb(var(--bg-subtle))] transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-3 space-y-3", children: [filters.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "grid gap-3", style: { gridTemplateColumns: `repeat(${filters.length}, minmax(140px, 1fr))` }, children: filters.map((filter) => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: filter.label }), (0, jsx_runtime_1.jsx)(dropdown_1.Dropdown, { options: filter.options, multiSelect: filter.type === 'multiselect', value: filterValues[filter.id] ?? (filter.type === 'multiselect' ? [] : ''), onValueChange: (value) => onFilterChange?.(filter.id, value), placeholder: filter.placeholder || `All ${filter.label}s`, searchable: true, className: "w-full" })] }, filter.id))) })), children, !hideDateRange && ((0, jsx_runtime_1.jsx)(date_picker_1.DatePicker, { mode: "range", value: dateRangeValue, onChange: handleDateRangeChange, inline: true }))] })] }))] })), forecast && onForecastChange && ((0, jsx_runtime_1.jsx)(ForecastControl, { forecast: forecast, onForecastChange: onForecastChange, timeFilter: timeFilter, onTimeFilterChange: onTimeFilterChange })), showApplyButton && ((0, jsx_runtime_1.jsx)("button", { onClick: onApply, className: (0, utils_1.cn)('h-8 px-4 rounded-md flex items-center gap-1.5', 'bg-[rgb(var(--color-primary))] text-white', 'text-xs font-semibold', 'shadow-sm hover:shadow-md transition-all', 'hover:brightness-110'), children: "Apply" })), (reports.length > 0 || onShare || onExport) && ((0, jsx_runtime_1.jsx)(OverflowMenu, { reports: reports, onReportSelect: onReportSelect, onShare: onShare, onExport: onExport }))] })] }) }) }));
|
|
395
418
|
}
|
|
396
419
|
// Default layout: Title centered, controls on right
|
|
397
|
-
return ((0, jsx_runtime_1.jsxs)("header", { className: (0, utils_1.cn)('bg-[rgb(var(--bg-surface))] border-b border-[rgb(var(--bd-default))]', 'px-4 py-3 lg:px-6', className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex-
|
|
420
|
+
return ((0, jsx_runtime_1.jsxs)("header", { className: (0, utils_1.cn)('bg-[rgb(var(--bg-surface))] border-b border-[rgb(var(--bd-default))]', 'px-4 py-3 lg:px-6', className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex-auto min-w-0 flex items-center gap-2.5", children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-base sm:text-xl font-bold text-[rgb(var(--fg-default))] leading-tight truncate", children: title }), contextLabel && ((0, jsx_runtime_1.jsxs)("span", { className: "hidden sm:inline-flex items-center gap-1.5 shrink-0 h-6 px-2.5 rounded-full border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-subtle))] text-xs font-medium text-[rgb(var(--fg-muted))]", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CalendarDays, { className: "w-3.5 h-3.5" }), contextLabel] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "ml-auto flex flex-wrap items-center justify-end gap-x-3 gap-y-2", children: [secondaryToggle && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { ref: toggleRef, className: "hidden sm:block", children: (0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: secondaryToggle.options.map(opt => ({ id: opt.value, label: opt.label })), activeTab: secondaryToggle.value, onTabChange: secondaryToggle.onChange, size: "sm" }) }), (0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('hidden h-4 w-px bg-[rgb(var(--bd-default))] self-center', !tabsWrapped && 'sm:block') })] })), !hideTimeFilter && ((0, jsx_runtime_1.jsx)("div", { ref: timeTabsRef, className: "hidden sm:block", children: (0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: timeOptions.map(opt => ({ id: opt.value, label: opt.label, dropdownOptions: opt.dropdownOptions, quickOptions: opt.quickOptions })), activeTab: timeFilter, onTabChange: (tabId) => onTimeFilterChange?.(tabId), variant: "rounded", size: "sm", dropdownValues: {
|
|
398
421
|
Day: timeFilterSelection?.days || [],
|
|
399
422
|
Week: timeFilterSelection?.weeks || [],
|
|
400
423
|
Month: timeFilterSelection?.months || [],
|
|
@@ -413,7 +436,7 @@ function FilterBar({ title, contextLabel, secondaryToggle, timeFilter = 'Week',
|
|
|
413
436
|
onTimeFilterSelectionChange?.(newSelection);
|
|
414
437
|
} }) })), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-0.5 rounded-lg border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] p-0.5", children: [!hideFilterButton && ((0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsxs)("button", { ref: buttonRef, onClick: () => setPopoverOpen(!popoverOpen), className: (0, utils_1.cn)('w-7 h-7 rounded-md flex items-center justify-center transition-colors relative', popoverOpen
|
|
415
438
|
? 'bg-[rgb(var(--color-primary))] text-white shadow-sm'
|
|
416
|
-
: 'text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))]'), title: "Filters", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ListFilter, { className: "w-4 h-4" }), hasActiveFilters && !popoverOpen && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -top-1 -right-1 w-2 h-2 bg-[rgb(var(--color-primary))] rounded-full" }))] }), popoverOpen && ((0, jsx_runtime_1.jsxs)("div", { ref: popoverRef, className: (0, utils_1.cn)('absolute top-full right-0 mt-2 z-50', 'w-[95vw] sm:w-auto', 'bg-[rgb(var(--bg-surface))] rounded-xl shadow-xl border border-[rgb(var(--bd-default))]', 'overflow-hidden'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "px-3 py-2 border-b border-[rgb(var(--bd-default))] flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs font-semibold text-[rgb(var(--fg-default))]", children: "Filters" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setPopoverOpen(false), className: "w-5 h-5 rounded flex items-center justify-center hover:bg-[rgb(var(--bg-subtle))] transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-3 space-y-3", children: [filters.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "grid gap-3", style: { gridTemplateColumns: `repeat(${Math.min(filters.length, 3)}, minmax(140px, 1fr))` }, children: filters.map((filter) => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: filter.label }), (0, jsx_runtime_1.jsx)(dropdown_1.Dropdown, { options: filter.options, multiSelect: filter.type === 'multiselect', value: filterValues[filter.id] ?? (filter.type === 'multiselect' ? [] : ''), onValueChange: (value) => onFilterChange?.(filter.id, value), placeholder: filter.placeholder || `All ${filter.label}s`, searchable: true, className: "w-full" })] }, filter.id))) })), children, !hideDateRange && ((0, jsx_runtime_1.jsx)(date_picker_1.DatePicker, { mode: "range", value: dateRangeValue, onChange: handleDateRangeChange, inline: true }))] })] }))] })), forecast && onForecastChange && ((0, jsx_runtime_1.jsx)(ForecastControl, { forecast: forecast, onForecastChange: onForecastChange, timeFilter: timeFilter, onTimeFilterChange: onTimeFilterChange, bare: true })), (showInsights || reports.length > 0 || onShare || onExport) && ((0, jsx_runtime_1.jsx)(OverflowMenu, { showInsights: showInsights, insightsActive: insightsActive, onInsightsClick: onInsightsClick, reports: reports, onReportSelect: onReportSelect, onShare: onShare, onExport: onExport }))] }), showApplyButton && ((0, jsx_runtime_1.jsx)("button", { onClick: onApply, className: (0, utils_1.cn)('h-8 px-4 rounded-md flex items-center gap-1.5', 'bg-[rgb(var(--color-primary))] text-white', 'text-xs font-semibold', 'shadow-sm hover:shadow-md transition-all', 'hover:brightness-110'), children: "Apply" }))] })] }), contextLabel && ((0, jsx_runtime_1.jsxs)("span", { className: "sm:hidden mt-2 inline-flex items-center gap-1.5 h-6 px-2.5 rounded-full border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-subtle))] text-xs font-medium text-[rgb(var(--fg-muted))]", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CalendarDays, { className: "w-3.5 h-3.5" }), contextLabel] })), (!hideTimeFilter || secondaryToggle) && ((0, jsx_runtime_1.jsxs)("div", { className: "sm:hidden mt-2 flex items-
|
|
439
|
+
: 'text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))]'), title: "Filters", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ListFilter, { className: "w-4 h-4" }), hasActiveFilters && !popoverOpen && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -top-1 -right-1 w-2 h-2 bg-[rgb(var(--color-primary))] rounded-full" }))] }), popoverOpen && ((0, jsx_runtime_1.jsxs)("div", { ref: popoverRef, className: (0, utils_1.cn)('absolute top-full right-0 mt-2 z-50', 'w-[95vw] sm:w-auto', 'bg-[rgb(var(--bg-surface))] rounded-xl shadow-xl border border-[rgb(var(--bd-default))]', 'overflow-hidden'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "px-3 py-2 border-b border-[rgb(var(--bd-default))] flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs font-semibold text-[rgb(var(--fg-default))]", children: "Filters" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setPopoverOpen(false), className: "w-5 h-5 rounded flex items-center justify-center hover:bg-[rgb(var(--bg-subtle))] transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-3 space-y-3", children: [filters.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "grid gap-3", style: { gridTemplateColumns: `repeat(${Math.min(filters.length, 3)}, minmax(140px, 1fr))` }, children: filters.map((filter) => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: filter.label }), (0, jsx_runtime_1.jsx)(dropdown_1.Dropdown, { options: filter.options, multiSelect: filter.type === 'multiselect', value: filterValues[filter.id] ?? (filter.type === 'multiselect' ? [] : ''), onValueChange: (value) => onFilterChange?.(filter.id, value), placeholder: filter.placeholder || `All ${filter.label}s`, searchable: true, className: "w-full" })] }, filter.id))) })), children, !hideDateRange && ((0, jsx_runtime_1.jsx)(date_picker_1.DatePicker, { mode: "range", value: dateRangeValue, onChange: handleDateRangeChange, inline: true }))] })] }))] })), forecast && onForecastChange && ((0, jsx_runtime_1.jsx)(ForecastControl, { forecast: forecast, onForecastChange: onForecastChange, timeFilter: timeFilter, onTimeFilterChange: onTimeFilterChange, bare: true })), (showInsights || reports.length > 0 || onShare || onExport) && ((0, jsx_runtime_1.jsx)(OverflowMenu, { showInsights: showInsights, insightsActive: insightsActive, onInsightsClick: onInsightsClick, reports: reports, onReportSelect: onReportSelect, onShare: onShare, onExport: onExport }))] }), showApplyButton && ((0, jsx_runtime_1.jsx)("button", { onClick: onApply, className: (0, utils_1.cn)('h-8 px-4 rounded-md flex items-center gap-1.5', 'bg-[rgb(var(--color-primary))] text-white', 'text-xs font-semibold', 'shadow-sm hover:shadow-md transition-all', 'hover:brightness-110'), children: "Apply" }))] })] }), contextLabel && ((0, jsx_runtime_1.jsxs)("span", { className: "sm:hidden mt-2 inline-flex items-center gap-1.5 h-6 px-2.5 rounded-full border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-subtle))] text-xs font-medium text-[rgb(var(--fg-muted))]", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CalendarDays, { className: "w-3.5 h-3.5" }), contextLabel] })), (!hideTimeFilter || secondaryToggle) && ((0, jsx_runtime_1.jsxs)("div", { className: "sm:hidden mt-2 flex flex-col items-start gap-2", children: [secondaryToggle && ((0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: secondaryToggle.options.map(opt => ({ id: opt.value, label: opt.label })), activeTab: secondaryToggle.value, onTabChange: secondaryToggle.onChange, size: "sm" })), !hideTimeFilter && ((0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: timeOptions.map(opt => ({ id: opt.value, label: opt.label, dropdownOptions: opt.dropdownOptions, quickOptions: opt.quickOptions })), activeTab: timeFilter, onTabChange: (tabId) => onTimeFilterChange?.(tabId), variant: "rounded", size: "sm", dropdownValues: {
|
|
417
440
|
Day: timeFilterSelection?.days || [],
|
|
418
441
|
Week: timeFilterSelection?.weeks || [],
|
|
419
442
|
Month: timeFilterSelection?.months || [],
|
|
@@ -430,5 +453,5 @@ function FilterBar({ title, contextLabel, secondaryToggle, timeFilter = 'Week',
|
|
|
430
453
|
...(filter === 'Year' && { years: selectedValues }),
|
|
431
454
|
};
|
|
432
455
|
onTimeFilterSelectionChange?.(newSelection);
|
|
433
|
-
} }))] }))] }));
|
|
456
|
+
} }))] })), description && (0, jsx_runtime_1.jsx)("p", { className: "mt-1 text-sm text-[rgb(var(--fg-muted))]", children: description })] }));
|
|
434
457
|
}
|
|
@@ -8,6 +8,7 @@ exports.AreaChart = AreaChart;
|
|
|
8
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
9
|
const echarts_for_react_1 = __importDefault(require("echarts-for-react"));
|
|
10
10
|
const utils_1 = require("../../../lib/utils.js");
|
|
11
|
+
const number_format_1 = require("../../../lib/number-format.js");
|
|
11
12
|
// Convert any color (hex, rgb(), rgba(), space-separated rgb()) to rgba() with given alpha (0–1).
|
|
12
13
|
// Hex+alpha-suffix concat (e.g. color + 'cc') breaks for non-hex inputs and crashes canvas gradients.
|
|
13
14
|
function withAlpha(color, alpha) {
|
|
@@ -37,10 +38,11 @@ function withAlpha(color, alpha) {
|
|
|
37
38
|
/**
|
|
38
39
|
* AreaChart - ECharts Area Chart component
|
|
39
40
|
*/
|
|
40
|
-
function AreaChart({ data, xKey, series, height = 300, showLegend = true, showGrid = true, smooth = true, className }) {
|
|
41
|
+
function AreaChart({ data, xKey, series, height = 300, showLegend = true, showGrid = true, smooth = true, valueFormatter, axisFormatter, className }) {
|
|
41
42
|
const option = {
|
|
42
43
|
tooltip: {
|
|
43
44
|
trigger: 'axis',
|
|
45
|
+
valueFormatter: (v) => (typeof v === 'number' ? (valueFormatter ?? number_format_1.formatNumber)(v) : String(v ?? '')),
|
|
44
46
|
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
|
45
47
|
borderColor: '#e9ecef',
|
|
46
48
|
borderWidth: 1,
|
|
@@ -76,13 +78,13 @@ function AreaChart({ data, xKey, series, height = 300, showLegend = true, showGr
|
|
|
76
78
|
},
|
|
77
79
|
yAxis: series.some(s => s.secondaryAxis)
|
|
78
80
|
? [
|
|
79
|
-
{ type: 'value', axisLine: { show: false }, axisLabel: { color: '#6c757d', fontSize: 11 }, splitLine: { show: showGrid, lineStyle: { color: '#f0f0f0', type: 'dashed' } } },
|
|
80
|
-
{ type: 'value', axisLine: { show: false }, axisLabel: { color: '#6c757d', fontSize: 11 }, splitLine: { show: false } },
|
|
81
|
+
{ type: 'value', axisLine: { show: false }, axisLabel: { color: '#6c757d', fontSize: 11, formatter: (v) => (axisFormatter ?? number_format_1.formatCompactNumber)(v) }, splitLine: { show: showGrid, lineStyle: { color: '#f0f0f0', type: 'dashed' } } },
|
|
82
|
+
{ type: 'value', axisLine: { show: false }, axisLabel: { color: '#6c757d', fontSize: 11, formatter: (v) => (axisFormatter ?? number_format_1.formatCompactNumber)(v) }, splitLine: { show: false } },
|
|
81
83
|
]
|
|
82
84
|
: {
|
|
83
85
|
type: 'value',
|
|
84
86
|
axisLine: { show: false },
|
|
85
|
-
axisLabel: { color: '#6c757d', fontSize: 11 },
|
|
87
|
+
axisLabel: { color: '#6c757d', fontSize: 11, formatter: (v) => (axisFormatter ?? number_format_1.formatCompactNumber)(v) },
|
|
86
88
|
splitLine: { show: showGrid, lineStyle: { color: '#f0f0f0', type: 'dashed' } }
|
|
87
89
|
},
|
|
88
90
|
series: series.map((s, index) => {
|
|
@@ -8,10 +8,11 @@ exports.BarChart = BarChart;
|
|
|
8
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
9
|
const echarts_for_react_1 = __importDefault(require("echarts-for-react"));
|
|
10
10
|
const utils_1 = require("../../../lib/utils.js");
|
|
11
|
+
const number_format_1 = require("../../../lib/number-format.js");
|
|
11
12
|
/**
|
|
12
13
|
* BarChart - ECharts Bar Chart component
|
|
13
14
|
*/
|
|
14
|
-
function BarChart({ data, xKey, series, height = 300, showLegend = true, showGrid = true, horizontal = false, targetKey, className }) {
|
|
15
|
+
function BarChart({ data, xKey, series, height = 300, showLegend = true, showGrid = true, horizontal = false, targetKey, valueFormatter, axisFormatter, className }) {
|
|
15
16
|
// Bullet mode: horizontal KPI-vs-target rows (CSS-rendered, not ECharts).
|
|
16
17
|
if (horizontal && targetKey) {
|
|
17
18
|
const actualKey = series[0]?.key;
|
|
@@ -31,13 +32,14 @@ function BarChart({ data, xKey, series, height = 300, showLegend = true, showGri
|
|
|
31
32
|
: met
|
|
32
33
|
? 'linear-gradient(90deg, #34d399 0%, #10b981 100%)'
|
|
33
34
|
: 'linear-gradient(90deg, #fbbf24 0%, #f59e0b 100%)';
|
|
34
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-1", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-baseline justify-between gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium text-[rgb(var(--fg-default))] truncate", children: name }), (0, jsx_runtime_1.jsxs)("span", { className: "text-xs font-semibold tabular-nums shrink-0", style: { color: barColor }, children: [achievement.toFixed(0), "%"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "relative h-2.5 rounded-full bg-[rgb(var(--bg-subtle))] overflow-visible", children: [(0, jsx_runtime_1.jsx)("div", { className: "absolute inset-y-0 left-0 rounded-full transition-all duration-300", style: { width: `${actualPct}%`, background: barGradient } }), (0, jsx_runtime_1.jsx)("div", { className: "absolute top-1/2 -translate-y-1/2 -translate-x-1/2 w-1 h-4 rounded-full ring-2 ring-[rgb(var(--bg-surface))]", style: { left: `${targetPct}%`, backgroundColor: '#475569' }, title: `Target: ${
|
|
35
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-1", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-baseline justify-between gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium text-[rgb(var(--fg-default))] truncate", children: name }), (0, jsx_runtime_1.jsxs)("span", { className: "text-xs font-semibold tabular-nums shrink-0", style: { color: barColor }, children: [achievement.toFixed(0), "%"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "relative h-2.5 rounded-full bg-[rgb(var(--bg-subtle))] overflow-visible", children: [(0, jsx_runtime_1.jsx)("div", { className: "absolute inset-y-0 left-0 rounded-full transition-all duration-300", style: { width: `${actualPct}%`, background: barGradient } }), (0, jsx_runtime_1.jsx)("div", { className: "absolute top-1/2 -translate-y-1/2 -translate-x-1/2 w-1 h-4 rounded-full ring-2 ring-[rgb(var(--bg-surface))]", style: { left: `${targetPct}%`, backgroundColor: '#475569' }, title: `Target: ${(0, number_format_1.formatNumber)(target)}` })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-baseline justify-between gap-2 text-[0.65rem] text-[rgb(var(--fg-muted))] tabular-nums", children: [(0, jsx_runtime_1.jsx)("span", { children: (0, number_format_1.formatNumber)(actual) }), (0, jsx_runtime_1.jsx)("span", { children: `Target ${(0, number_format_1.formatNumber)(target)}` })] })] }, `${name}-${idx}`));
|
|
35
36
|
}) }));
|
|
36
37
|
}
|
|
37
38
|
const categoryData = data.map(item => item[xKey]);
|
|
38
39
|
const option = {
|
|
39
40
|
tooltip: {
|
|
40
41
|
trigger: 'item',
|
|
42
|
+
valueFormatter: (v) => (typeof v === 'number' ? (valueFormatter ?? number_format_1.formatNumber)(v) : String(v ?? '')),
|
|
41
43
|
backgroundColor: 'rgba(255, 255, 255, 0.98)',
|
|
42
44
|
borderColor: '#e9ecef',
|
|
43
45
|
borderWidth: 1,
|
|
@@ -70,7 +72,7 @@ function BarChart({ data, xKey, series, height = 300, showLegend = true, showGri
|
|
|
70
72
|
type: horizontal ? 'value' : 'category',
|
|
71
73
|
data: horizontal ? undefined : categoryData,
|
|
72
74
|
axisLine: { lineStyle: { color: '#dee2e6' } },
|
|
73
|
-
axisLabel: { color: '#6c757d', fontSize: 11 },
|
|
75
|
+
axisLabel: horizontal ? { color: '#6c757d', fontSize: 11, hideOverlap: true, alignMaxLabel: 'right', formatter: (v) => (axisFormatter ?? number_format_1.formatCompactNumber)(v) } : { color: '#6c757d', fontSize: 11 },
|
|
74
76
|
axisTick: { show: false },
|
|
75
77
|
splitLine: horizontal && showGrid ? {
|
|
76
78
|
lineStyle: { color: '#f0f0f0', type: 'dashed' }
|
|
@@ -80,7 +82,7 @@ function BarChart({ data, xKey, series, height = 300, showLegend = true, showGri
|
|
|
80
82
|
type: horizontal ? 'category' : 'value',
|
|
81
83
|
data: horizontal ? categoryData : undefined,
|
|
82
84
|
axisLine: { show: false },
|
|
83
|
-
axisLabel: { color: '#6c757d', fontSize: 11 },
|
|
85
|
+
axisLabel: horizontal ? { color: '#6c757d', fontSize: 11 } : { color: '#6c757d', fontSize: 11, formatter: (v) => (axisFormatter ?? number_format_1.formatCompactNumber)(v) },
|
|
84
86
|
splitLine: !horizontal && showGrid ? {
|
|
85
87
|
lineStyle: { color: '#f0f0f0', type: 'dashed' }
|
|
86
88
|
} : { show: false }
|
|
@@ -45,6 +45,7 @@ const echarts = __importStar(require("echarts/core"));
|
|
|
45
45
|
const utils_1 = require("../../../lib/utils.js");
|
|
46
46
|
const india_map_1 = require("./india-map.js");
|
|
47
47
|
const theme_1 = require("./theme.js");
|
|
48
|
+
const number_format_1 = require("../../../lib/number-format.js");
|
|
48
49
|
/**
|
|
49
50
|
* FlowMap - Geographic flow/route visualization
|
|
50
51
|
*
|
|
@@ -200,7 +201,7 @@ function FlowMap({ markers = [], lines = [], height = 400, markerColor = '#5470c
|
|
|
200
201
|
}
|
|
201
202
|
if (params.seriesType === 'effectScatter' || params.seriesType === 'scatter') {
|
|
202
203
|
const value = params.value?.[2];
|
|
203
|
-
return `<strong>${params.name}</strong>${value ? `<br/>Value: ${
|
|
204
|
+
return `<strong>${params.name}</strong>${value ? `<br/>Value: ${(0, number_format_1.formatNumber)(value)}` : ''}`;
|
|
204
205
|
}
|
|
205
206
|
return `<strong>${params.name}</strong>`;
|
|
206
207
|
}
|
|
@@ -5,6 +5,7 @@ exports.FunnelChart = FunnelChart;
|
|
|
5
5
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
6
|
const react_1 = require("react");
|
|
7
7
|
const utils_1 = require("../../../lib/utils.js");
|
|
8
|
+
const number_format_1 = require("../../../lib/number-format.js");
|
|
8
9
|
const FUNNEL_COLORS = ['#5470c6', '#3ba272', '#fac858', '#ee6666', '#73c0de', '#9a60b4', '#fc8452', '#91cc75'];
|
|
9
10
|
/**
|
|
10
11
|
* FunnelChart — centered, tapering stage-bar funnel for conversion/process flows.
|
|
@@ -33,6 +34,6 @@ function FunnelChart({ data, height = 300, sort = 'descending', className }) {
|
|
|
33
34
|
background: `linear-gradient(90deg, ${color}, ${color}cc)`,
|
|
34
35
|
transform: isHover ? 'translateY(-1px)' : 'none',
|
|
35
36
|
boxShadow: isHover ? `0 4px 14px ${color}55` : `0 1px 2px rgba(0,0,0,0.06)`,
|
|
36
|
-
}, title: `${item.name}: ${item.value
|
|
37
|
+
}, title: `${item.name}: ${(0, number_format_1.formatNumber)(item.value)} (${pct.toFixed(1)}%)`, children: [(0, jsx_runtime_1.jsx)("span", { className: "text-sm font-semibold text-white truncate", children: item.name }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium text-white/90 tabular-nums shrink-0", children: (0, number_format_1.formatNumber)(item.value) })] }) })] }, item.name));
|
|
37
38
|
}) }));
|
|
38
39
|
}
|
|
@@ -44,6 +44,7 @@ const echarts_for_react_1 = __importDefault(require("echarts-for-react"));
|
|
|
44
44
|
const echarts = __importStar(require("echarts/core"));
|
|
45
45
|
const utils_1 = require("../../../lib/utils.js");
|
|
46
46
|
const india_map_1 = require("./india-map.js");
|
|
47
|
+
const number_format_1 = require("../../../lib/number-format.js");
|
|
47
48
|
/**
|
|
48
49
|
* GeoMap - Geographic scatter/bubble map for India
|
|
49
50
|
* Shows location markers with optional size based on values
|
|
@@ -86,7 +87,7 @@ function GeoMap({ markers = [], height = 400, markerColor = '#5470c6', markerSiz
|
|
|
86
87
|
formatter: (params) => {
|
|
87
88
|
if (params.seriesType === 'effectScatter' || params.seriesType === 'scatter') {
|
|
88
89
|
const value = params.value?.[2];
|
|
89
|
-
return `<strong>${params.name}</strong>${value ? `<br/>Production: ${
|
|
90
|
+
return `<strong>${params.name}</strong>${value ? `<br/>Production: ${(0, number_format_1.formatNumber)(value)} units` : ''}`;
|
|
90
91
|
}
|
|
91
92
|
return `<strong>${params.name}</strong>`;
|
|
92
93
|
}
|
|
@@ -9,16 +9,18 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
9
9
|
const echarts_for_react_1 = __importDefault(require("echarts-for-react"));
|
|
10
10
|
const utils_1 = require("../../../lib/utils.js");
|
|
11
11
|
const theme_1 = require("./theme.js");
|
|
12
|
+
const number_format_1 = require("../../../lib/number-format.js");
|
|
12
13
|
/**
|
|
13
14
|
* LineChart - ECharts Line Chart component (no area fill)
|
|
14
15
|
*/
|
|
15
|
-
function LineChart({ data, xKey, series, height = 300, showLegend = true, showGrid = true, smooth = false, showLabels = false, yMin, yMax, className }) {
|
|
16
|
+
function LineChart({ data, xKey, series, height = 300, showLegend = true, showGrid = true, smooth = false, showLabels = false, yMin, yMax, valueFormatter, axisFormatter, className }) {
|
|
16
17
|
const theme = (0, theme_1.getChartTheme)();
|
|
17
18
|
const axisConfig = (0, theme_1.getAxisConfig)();
|
|
18
19
|
const option = {
|
|
19
20
|
tooltip: {
|
|
20
21
|
trigger: 'axis',
|
|
21
|
-
...(0, theme_1.getTooltipConfig)()
|
|
22
|
+
...(0, theme_1.getTooltipConfig)(),
|
|
23
|
+
valueFormatter: (v) => (typeof v === 'number' ? (valueFormatter ?? number_format_1.formatNumber)(v) : String(v ?? '')),
|
|
22
24
|
},
|
|
23
25
|
legend: showLegend ? (0, theme_1.getLegendConfig)('top') : undefined,
|
|
24
26
|
grid: (0, theme_1.getGridConfig)(showLegend),
|
|
@@ -33,7 +35,7 @@ function LineChart({ data, xKey, series, height = 300, showLegend = true, showGr
|
|
|
33
35
|
min: yMin,
|
|
34
36
|
max: yMax,
|
|
35
37
|
axisLine: { show: false },
|
|
36
|
-
axisLabel: axisConfig.axisLabel,
|
|
38
|
+
axisLabel: { ...axisConfig.axisLabel, formatter: (v) => (axisFormatter ?? number_format_1.formatCompactNumber)(v) },
|
|
37
39
|
splitLine: {
|
|
38
40
|
show: showGrid,
|
|
39
41
|
...axisConfig.splitLine
|
|
@@ -8,6 +8,7 @@ exports.ParetoChart = ParetoChart;
|
|
|
8
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
9
|
const echarts_for_react_1 = __importDefault(require("echarts-for-react"));
|
|
10
10
|
const utils_1 = require("../../../lib/utils.js");
|
|
11
|
+
const number_format_1 = require("../../../lib/number-format.js");
|
|
11
12
|
/**
|
|
12
13
|
* ParetoChart - Combined bar and line chart showing values and cumulative percentage
|
|
13
14
|
* Used for identifying the "vital few" from the "trivial many" (80/20 rule)
|
|
@@ -34,7 +35,7 @@ function ParetoChart({ data, height = 300, showLegend = true, barColor = '#5470c
|
|
|
34
35
|
const bar = params.find((p) => p.seriesType === 'bar');
|
|
35
36
|
const line = params.find((p) => p.seriesType === 'line');
|
|
36
37
|
return `${bar?.name}<br/>
|
|
37
|
-
Value: ${bar?.value
|
|
38
|
+
Value: ${(0, number_format_1.formatNumber)(bar?.value)}<br/>
|
|
38
39
|
Cumulative: ${line?.value}%`;
|
|
39
40
|
}
|
|
40
41
|
},
|
|
@@ -8,6 +8,7 @@ exports.SankeyChart = SankeyChart;
|
|
|
8
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
9
|
const echarts_for_react_1 = __importDefault(require("echarts-for-react"));
|
|
10
10
|
const utils_1 = require("../../../lib/utils.js");
|
|
11
|
+
const number_format_1 = require("../../../lib/number-format.js");
|
|
11
12
|
/**
|
|
12
13
|
* SankeyChart - Flow/relationship visualization
|
|
13
14
|
* Great for: Material flow, process flow, cost flow, conversion funnels
|
|
@@ -41,9 +42,9 @@ function SankeyChart({ nodes, links, height = 300, orient = 'horizontal', nodeWi
|
|
|
41
42
|
textStyle: { color: '#344767', fontSize: 12 },
|
|
42
43
|
formatter: (params) => {
|
|
43
44
|
if (params.dataType === 'edge') {
|
|
44
|
-
return `<strong>${params.data.source}</strong> → <strong>${params.data.target}</strong><br/>Value: ${params.data.value
|
|
45
|
+
return `<strong>${params.data.source}</strong> → <strong>${params.data.target}</strong><br/>Value: ${(0, number_format_1.formatNumber)(params.data.value)}`;
|
|
45
46
|
}
|
|
46
|
-
return `<strong>${params.name}</strong><br/>Value: ${params.value
|
|
47
|
+
return `<strong>${params.name}</strong><br/>Value: ${(0, number_format_1.formatNumber)(params.value) || '-'}`;
|
|
47
48
|
}
|
|
48
49
|
},
|
|
49
50
|
series: [{
|
|
@@ -79,7 +80,7 @@ function SankeyChart({ nodes, links, height = 300, orient = 'horizontal', nodeWi
|
|
|
79
80
|
color: '#344767',
|
|
80
81
|
fontSize: 11,
|
|
81
82
|
fontWeight: 500,
|
|
82
|
-
formatter: (p) => `${p.name} (${p.value
|
|
83
|
+
formatter: (p) => `${p.name} (${(0, number_format_1.formatNumber)(p.value) || '-'})`
|
|
83
84
|
},
|
|
84
85
|
data: nodesWithColors,
|
|
85
86
|
links: links.map(link => ({
|
|
@@ -8,6 +8,7 @@ exports.Sparkline = Sparkline;
|
|
|
8
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
9
|
const echarts_for_react_1 = __importDefault(require("echarts-for-react"));
|
|
10
10
|
const utils_1 = require("../../../lib/utils.js");
|
|
11
|
+
const number_format_1 = require("../../../lib/number-format.js");
|
|
11
12
|
// Convert any color (hex, rgb(), rgba(), space-separated rgb()) to rgba() with given alpha (0–1).
|
|
12
13
|
// Hex+alpha-suffix concat (e.g. color + '40') breaks for non-hex inputs and crashes canvas gradients.
|
|
13
14
|
function withAlpha(color, alpha) {
|
|
@@ -103,7 +104,7 @@ function Sparkline({ data, type = 'line', height = 40, width = '100%', color = '
|
|
|
103
104
|
formatter: (params) => {
|
|
104
105
|
const p = Array.isArray(params) ? params[0] : params;
|
|
105
106
|
const cat = hasLabels && p.axisValue ? `${p.axisValue}<br/>` : '';
|
|
106
|
-
return `${cat}<strong>${valuePrefix}${Number(p.value)
|
|
107
|
+
return `${cat}<strong>${valuePrefix}${(0, number_format_1.formatNumber)(Number(p.value))}${valueSuffix}</strong>`;
|
|
107
108
|
}
|
|
108
109
|
} : undefined,
|
|
109
110
|
grid: {
|
|
@@ -8,6 +8,7 @@ exports.TreemapChart = TreemapChart;
|
|
|
8
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
9
|
const echarts_for_react_1 = __importDefault(require("echarts-for-react"));
|
|
10
10
|
const utils_1 = require("../../../lib/utils.js");
|
|
11
|
+
const number_format_1 = require("../../../lib/number-format.js");
|
|
11
12
|
/**
|
|
12
13
|
* TreemapChart - Hierarchical data visualization
|
|
13
14
|
* Great for: Cost breakdown, category distribution, budget allocation
|
|
@@ -28,7 +29,7 @@ function TreemapChart({ data, height = 300, showBreadcrumb = false, colors = ['#
|
|
|
28
29
|
.map((node) => node.name)
|
|
29
30
|
.filter((name) => name)
|
|
30
31
|
.join(' → ');
|
|
31
|
-
return `<strong>${path || params.name}</strong><br/>Value: ${params.value
|
|
32
|
+
return `<strong>${path || params.name}</strong><br/>Value: ${(0, number_format_1.formatNumber)(params.value) || '-'}`;
|
|
32
33
|
}
|
|
33
34
|
},
|
|
34
35
|
series: [{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.ChartCard = exports.FlowMap = exports.GanttChart = exports.Sparkline = exports.SankeyChart = exports.TreemapChart = exports.GeoMap = exports.BoxPlotChart = exports.BubbleChart = exports.ParetoChart = exports.ScatterChart = exports.HeatmapChart = exports.FunnelChart = exports.RadarChart = exports.LineChart = exports.GaugeChart = exports.DonutChart = exports.BarChart = exports.AreaChart = void 0;
|
|
4
|
+
exports.getNumberLocale = exports.setNumberLocale = exports.formatCompactNumber = exports.formatNumber = exports.ChartCard = exports.FlowMap = exports.GanttChart = exports.Sparkline = exports.SankeyChart = exports.TreemapChart = exports.GeoMap = exports.BoxPlotChart = exports.BubbleChart = exports.ParetoChart = exports.ScatterChart = exports.HeatmapChart = exports.FunnelChart = exports.RadarChart = exports.LineChart = exports.GaugeChart = exports.DonutChart = exports.BarChart = exports.AreaChart = void 0;
|
|
5
5
|
// ECharts Components
|
|
6
6
|
var Area_1 = require("./Area.js");
|
|
7
7
|
Object.defineProperty(exports, "AreaChart", { enumerable: true, get: function () { return Area_1.AreaChart; } });
|
|
@@ -43,3 +43,9 @@ Object.defineProperty(exports, "FlowMap", { enumerable: true, get: function () {
|
|
|
43
43
|
// Chart Wrapper
|
|
44
44
|
var DashboardCard_1 = require("./DashboardCard.js");
|
|
45
45
|
Object.defineProperty(exports, "ChartCard", { enumerable: true, get: function () { return DashboardCard_1.ChartCard; } });
|
|
46
|
+
// Number formatting: Indian grouping by default; setNumberLocale() switches it for a whole app
|
|
47
|
+
var number_format_1 = require("../../../lib/number-format.js");
|
|
48
|
+
Object.defineProperty(exports, "formatNumber", { enumerable: true, get: function () { return number_format_1.formatNumber; } });
|
|
49
|
+
Object.defineProperty(exports, "formatCompactNumber", { enumerable: true, get: function () { return number_format_1.formatCompactNumber; } });
|
|
50
|
+
Object.defineProperty(exports, "setNumberLocale", { enumerable: true, get: function () { return number_format_1.setNumberLocale; } });
|
|
51
|
+
Object.defineProperty(exports, "getNumberLocale", { enumerable: true, get: function () { return number_format_1.getNumberLocale; } });
|
|
@@ -5,6 +5,7 @@ exports.KpiBreakdown = KpiBreakdown;
|
|
|
5
5
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
6
|
const utils_1 = require("../../../lib/utils.js");
|
|
7
7
|
const kpi_shell_1 = require("./kpi-shell.js");
|
|
8
|
+
const number_format_1 = require("../../../lib/number-format.js");
|
|
8
9
|
/**
|
|
9
10
|
* KpiBreakdown - KPI card with list breakdown
|
|
10
11
|
*
|
|
@@ -32,11 +33,11 @@ function KpiBreakdown({ title, total, items, showPercentage = false, loading, co
|
|
|
32
33
|
};
|
|
33
34
|
const totalValue = typeof total === 'number' ? total :
|
|
34
35
|
items.reduce((sum, item) => sum + (typeof item.value === 'number' ? item.value : 0), 0);
|
|
35
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('bg-[rgb(var(--bg-surface))] rounded-xl border border-[rgb(var(--bd-default))] shadow-sm', compact ? 'p-4' : 'p-5', className), children: [(0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('flex items-center justify-between', compact ? 'mb-2' : 'mb-3'), children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-[rgb(var(--fg-muted))]", children: title }), total !== undefined && ((0, jsx_runtime_1.jsx)("p", { className: "text-lg font-bold text-[rgb(var(--fg-default))]", children: typeof total === 'number' ?
|
|
36
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('bg-[rgb(var(--bg-surface))] rounded-xl border border-[rgb(var(--bd-default))] shadow-sm', compact ? 'p-4' : 'p-5', className), children: [(0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('flex items-center justify-between', compact ? 'mb-2' : 'mb-3'), children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-[rgb(var(--fg-muted))]", children: title }), total !== undefined && ((0, jsx_runtime_1.jsx)("p", { className: "text-lg font-bold text-[rgb(var(--fg-default))]", children: typeof total === 'number' ? (0, number_format_1.formatNumber)(total) : total }))] }), (0, jsx_runtime_1.jsx)("div", { className: compact ? 'space-y-1' : 'space-y-2', children: items.map((item, index) => {
|
|
36
37
|
const colorClass = getColorClass(item.color);
|
|
37
38
|
const isCustomColor = item.color?.startsWith('#') || item.color?.startsWith('rgb');
|
|
38
39
|
const numValue = typeof item.value === 'number' ? item.value : 0;
|
|
39
40
|
const percentage = totalValue > 0 ? Math.round((numValue / totalValue) * 100) : 0;
|
|
40
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('w-2 h-2 rounded-full', colorClass), style: isCustomColor ? { backgroundColor: item.color } : undefined }), (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-[rgb(var(--fg-default))]", children: item.label })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-sm font-medium", children: typeof item.value === 'number' ? item.value
|
|
41
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('w-2 h-2 rounded-full', colorClass), style: isCustomColor ? { backgroundColor: item.color } : undefined }), (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-[rgb(var(--fg-default))]", children: item.label })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-sm font-medium", children: typeof item.value === 'number' ? (0, number_format_1.formatNumber)(item.value) : item.value }), showPercentage && ((0, jsx_runtime_1.jsxs)("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: ["(", percentage, "%)"] }))] })] }, index));
|
|
41
42
|
}) })] }));
|
|
42
43
|
}
|
|
@@ -5,6 +5,7 @@ exports.KpiComparison = KpiComparison;
|
|
|
5
5
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
6
|
const utils_1 = require("../../../lib/utils.js");
|
|
7
7
|
const kpi_shell_1 = require("./kpi-shell.js");
|
|
8
|
+
const number_format_1 = require("../../../lib/number-format.js");
|
|
8
9
|
/**
|
|
9
10
|
* KpiComparison - KPI card with comparison progress bars
|
|
10
11
|
*
|
|
@@ -37,5 +38,5 @@ function KpiComparison({ title, value, target, status, bars, loading, className
|
|
|
37
38
|
return 'bg-[rgb(var(--color-error))]/10 text-[rgb(var(--color-error))]';
|
|
38
39
|
}
|
|
39
40
|
};
|
|
40
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('bg-[rgb(var(--bg-surface))] rounded-xl p-5 border border-[rgb(var(--bd-default))] shadow-sm', className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-1", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-[rgb(var(--fg-muted))]", children: title }), status && ((0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)('text-xs px-2 py-0.5 rounded-full', getStatusStyles(status.type)), children: status.label }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-baseline gap-2", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-3xl font-bold text-[rgb(var(--fg-default))]", children: value }), target && ((0, jsx_runtime_1.jsxs)("span", { className: "text-sm text-[rgb(var(--fg-muted))]", children: ["/ ", target, " target"] }))] }), (0, jsx_runtime_1.jsx)("div", { className: "mt-4 space-y-2", children: bars.map((bar, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs text-[rgb(var(--fg-muted))] w-16", children: bar.label }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 h-3 bg-[rgb(var(--bg-subtle))] rounded", children: (0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('h-full rounded', getBarColor(bar.color)), style: { width: `${Math.min(bar.percentage, 100)}%` } }) }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium w-12 text-right", children: typeof bar.value === 'number' ? bar.value
|
|
41
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('bg-[rgb(var(--bg-surface))] rounded-xl p-5 border border-[rgb(var(--bd-default))] shadow-sm', className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-1", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-[rgb(var(--fg-muted))]", children: title }), status && ((0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)('text-xs px-2 py-0.5 rounded-full', getStatusStyles(status.type)), children: status.label }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-baseline gap-2", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-3xl font-bold text-[rgb(var(--fg-default))]", children: value }), target && ((0, jsx_runtime_1.jsxs)("span", { className: "text-sm text-[rgb(var(--fg-muted))]", children: ["/ ", target, " target"] }))] }), (0, jsx_runtime_1.jsx)("div", { className: "mt-4 space-y-2", children: bars.map((bar, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs text-[rgb(var(--fg-muted))] w-16", children: bar.label }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 h-3 bg-[rgb(var(--bg-subtle))] rounded", children: (0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('h-full rounded', getBarColor(bar.color)), style: { width: `${Math.min(bar.percentage, 100)}%` } }) }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium w-12 text-right", children: typeof bar.value === 'number' ? (0, number_format_1.formatNumber)(bar.value) : bar.value })] }, index))) })] }));
|
|
41
42
|
}
|