@lastbrain/ai-ui-react 1.0.67 → 1.0.69

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.
Files changed (60) hide show
  1. package/dist/components/AiChipLabel.d.ts +8 -3
  2. package/dist/components/AiChipLabel.d.ts.map +1 -1
  3. package/dist/components/AiChipLabel.js +21 -70
  4. package/dist/components/AiContextButton.d.ts +5 -1
  5. package/dist/components/AiContextButton.d.ts.map +1 -1
  6. package/dist/components/AiContextButton.js +67 -291
  7. package/dist/components/AiImageButton.d.ts +5 -1
  8. package/dist/components/AiImageButton.d.ts.map +1 -1
  9. package/dist/components/AiImageButton.js +6 -142
  10. package/dist/components/AiInput.d.ts +5 -3
  11. package/dist/components/AiInput.d.ts.map +1 -1
  12. package/dist/components/AiInput.js +13 -25
  13. package/dist/components/AiPromptPanel.d.ts.map +1 -1
  14. package/dist/components/AiPromptPanel.js +58 -212
  15. package/dist/components/AiSelect.d.ts +5 -3
  16. package/dist/components/AiSelect.d.ts.map +1 -1
  17. package/dist/components/AiSelect.js +21 -30
  18. package/dist/components/AiStatusButton.d.ts +4 -1
  19. package/dist/components/AiStatusButton.d.ts.map +1 -1
  20. package/dist/components/AiStatusButton.js +198 -626
  21. package/dist/components/AiTextarea.d.ts +4 -2
  22. package/dist/components/AiTextarea.d.ts.map +1 -1
  23. package/dist/components/AiTextarea.js +14 -26
  24. package/dist/components/LBApiKeySelector.d.ts.map +1 -1
  25. package/dist/components/LBApiKeySelector.js +5 -166
  26. package/dist/components/LBConnectButton.d.ts +4 -7
  27. package/dist/components/LBConnectButton.d.ts.map +1 -1
  28. package/dist/components/LBConnectButton.js +17 -86
  29. package/dist/components/LBSigninModal.d.ts +1 -1
  30. package/dist/components/LBSigninModal.d.ts.map +1 -1
  31. package/dist/components/LBSigninModal.js +42 -320
  32. package/dist/examples/AiUiPremiumShowcase.d.ts +2 -0
  33. package/dist/examples/AiUiPremiumShowcase.d.ts.map +1 -0
  34. package/dist/examples/AiUiPremiumShowcase.js +15 -0
  35. package/dist/index.d.ts +2 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +2 -0
  38. package/dist/styles/inline.d.ts +1 -0
  39. package/dist/styles/inline.d.ts.map +1 -1
  40. package/dist/styles/inline.js +25 -129
  41. package/dist/styles.css +1268 -369
  42. package/dist/types.d.ts +3 -0
  43. package/dist/types.d.ts.map +1 -1
  44. package/package.json +2 -2
  45. package/src/components/AiChipLabel.tsx +64 -101
  46. package/src/components/AiContextButton.tsx +138 -430
  47. package/src/components/AiImageButton.tsx +29 -190
  48. package/src/components/AiInput.tsx +49 -74
  49. package/src/components/AiPromptPanel.tsx +71 -254
  50. package/src/components/AiSelect.tsx +61 -69
  51. package/src/components/AiStatusButton.tsx +477 -1219
  52. package/src/components/AiTextarea.tsx +49 -64
  53. package/src/components/LBApiKeySelector.tsx +86 -274
  54. package/src/components/LBConnectButton.tsx +46 -334
  55. package/src/components/LBSigninModal.tsx +140 -481
  56. package/src/examples/AiUiPremiumShowcase.tsx +91 -0
  57. package/src/index.ts +3 -0
  58. package/src/styles/inline.ts +27 -148
  59. package/src/styles.css +1268 -369
  60. package/src/types.ts +3 -0
@@ -1,21 +1,72 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useState, useRef, useLayoutEffect } from "react";
3
+ import { useLayoutEffect, useMemo, useRef, useState } from "react";
4
4
  import { createPortal } from "react-dom";
5
- import { BarChart3, Settings, FileText, History as HistoryIcon, FolderPlus, Power, LogOut, ArrowRightLeft, } from "lucide-react";
6
- import { aiStyles, calculateTooltipPosition } from "../styles/inline";
5
+ import { ArrowRightLeft, BarChart3, FileText, Folder, History, Loader2, LogOut, Settings, Shield, } from "lucide-react";
7
6
  import { useLB } from "../context/LBAuthProvider";
8
7
  import { useAiContext } from "../context/AiProvider";
9
- import { LBSigninModal } from "./LBSigninModal";
10
8
  import { LBApiKeySelector } from "./LBApiKeySelector";
11
- export function AiStatusButton({ status, loading = false, className = "", }) {
12
- // Rendre l'authentification optionnelle
9
+ import { LBSigninModal } from "./LBSigninModal";
10
+ const QUICK_LINKS = [
11
+ {
12
+ href: "https://prompt.lastbrain.io/auth/ai/tokens",
13
+ title: "Dashboard",
14
+ icon: BarChart3,
15
+ },
16
+ {
17
+ href: "https://prompt.lastbrain.io/auth/ai/history",
18
+ title: "Historique",
19
+ icon: History,
20
+ },
21
+ {
22
+ href: "https://prompt.lastbrain.io/auth/ai/settings",
23
+ title: "Settings",
24
+ icon: Settings,
25
+ },
26
+ {
27
+ href: "https://prompt.lastbrain.io/auth/ai/prompts",
28
+ title: "Prompts",
29
+ icon: FileText,
30
+ },
31
+ {
32
+ href: "https://prompt.lastbrain.io/auth/folder",
33
+ title: "Dossiers",
34
+ icon: Folder,
35
+ },
36
+ ];
37
+ const clamp = (value) => Math.min(100, Math.max(0, value || 0));
38
+ const num = (value) => (typeof value === "number" ? value : 0);
39
+ const fixed = (value, digits) => num(value).toFixed(digits);
40
+ function formatStorage(mb) {
41
+ const value = num(mb);
42
+ if (value >= 1024) {
43
+ return `${(value / 1024).toFixed(2)} GB`;
44
+ }
45
+ return `${value.toFixed(2)} MB`;
46
+ }
47
+ function UsageCircle({ percentage }) {
48
+ const safe = clamp(percentage);
49
+ const toneClass = safe > 90
50
+ ? "ai-usage-circle-value--high"
51
+ : safe > 75
52
+ ? "ai-usage-circle-value--warn"
53
+ : "ai-usage-circle-value--low";
54
+ const size = 28;
55
+ const stroke = 3;
56
+ const radius = (size - stroke) / 2;
57
+ const circumference = 2 * Math.PI * radius;
58
+ const dashOffset = circumference - (safe / 100) * circumference;
59
+ return (_jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, children: [_jsx("circle", { cx: size / 2, cy: size / 2, r: radius, className: "ai-usage-circle-track", strokeWidth: stroke, fill: "transparent" }), _jsx("circle", { cx: size / 2, cy: size / 2, r: radius, className: toneClass, strokeWidth: stroke, fill: "transparent", strokeDasharray: circumference, strokeDashoffset: dashOffset, strokeLinecap: "round", transform: `rotate(-90 ${size / 2} ${size / 2})` }), _jsxs("text", { x: size / 2, y: size / 2, textAnchor: "middle", dominantBaseline: "central", fontSize: "7px", className: toneClass === "ai-usage-circle-value--high"
60
+ ? "ai-usage-circle-text--high"
61
+ : toneClass === "ai-usage-circle-value--warn"
62
+ ? "ai-usage-circle-text--warn"
63
+ : "ai-usage-circle-text--low", fontWeight: "700", children: [safe.toFixed(0), "%"] })] }));
64
+ }
65
+ export function AiStatusButton({ status, loading = false, className = "", size = "md", radius = "full", }) {
13
66
  let lbStatus;
14
67
  let user;
15
68
  let logout;
16
69
  let apiKeys = [];
17
- let accessToken;
18
- let selectApiKeyWithToken;
19
70
  let switchApiKey;
20
71
  let lbApiStatus = null;
21
72
  let lbBasicStatus = null;
@@ -31,8 +82,6 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
31
82
  user = lbContext.user;
32
83
  logout = lbContext.logout;
33
84
  apiKeys = lbContext.apiKeys || [];
34
- accessToken = lbContext.accessToken;
35
- selectApiKeyWithToken = lbContext.selectApiKeyWithToken;
36
85
  switchApiKey = lbContext.switchApiKey;
37
86
  lbApiStatus = lbContext.apiStatus;
38
87
  lbBasicStatus = lbContext.basicStatus;
@@ -44,177 +93,76 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
44
93
  lbRefreshStorageStatus = lbContext.refreshStorageStatus;
45
94
  }
46
95
  catch {
47
- // LBProvider n'est pas disponible, ignorer
48
96
  lbStatus = undefined;
49
- user = undefined;
50
- logout = undefined;
51
97
  }
52
- // Toujours prioriser les données du contexte LB quand disponibles
53
- // pour éviter d'afficher un status externe obsolète (Unknown/0).
54
- const lbEffectiveStatus = lbStatus === "ready"
55
- ? {
56
- ...(lbApiStatus || {}),
57
- ...(lbBasicStatus || {}),
58
- storage: lbStorageStatus?.storage || lbApiStatus?.storage,
59
- }
60
- : null;
61
- const effectiveStatus = lbEffectiveStatus || status || null;
62
- // Récupérer refetchProviders depuis AiProvider si disponible
63
98
  let refetchProviders;
64
99
  try {
65
- const aiContext = useAiContext();
66
- refetchProviders = aiContext.refetchProviders;
100
+ refetchProviders = useAiContext().refetchProviders;
67
101
  }
68
102
  catch {
69
- // AiProvider n'est pas disponible, ignorer
70
103
  refetchProviders = undefined;
71
104
  }
72
105
  const [showSigninModal, setShowSigninModal] = useState(false);
73
106
  const [showApiKeySelector, setShowApiKeySelector] = useState(false);
74
- const [isSelectingApiKey, setIsSelectingApiKey] = useState(false);
75
- const [isLoadingStatus, setIsLoadingStatus] = useState(false);
76
- const formatFixed = (value, digits) => typeof value === "number" ? value.toFixed(digits) : "0.00";
77
- const formatStorage = (valueMb) => {
78
- const mb = typeof valueMb === "number" ? valueMb : 0;
79
- if (mb >= 1024) {
80
- const gb = mb / 1024;
81
- return `${gb.toFixed(2)} GB`;
82
- }
83
- return `${mb.toFixed(2)} MB`;
84
- };
85
- const safeNumber = (value) => typeof value === "number" ? value : 0;
86
- const clampPercentage = (value) => Math.min(100, Math.max(0, safeNumber(value)));
87
- const getUsageColor = (percentage) => {
88
- if (percentage > 90) {
89
- return aiStyles.tooltipValueWarning.color;
90
- }
91
- if (percentage > 75) {
92
- return aiStyles.tooltipValueWarning.color;
93
- }
94
- return aiStyles.tooltipValueSuccess.color;
95
- };
96
- const renderUsageCircle = (percentageValue) => {
97
- const percentage = clampPercentage(percentageValue);
98
- const size = 28;
99
- const stroke = 3;
100
- const radius = (size - stroke) / 2;
101
- const circumference = 2 * Math.PI * radius;
102
- const offset = circumference - (percentage / 100) * circumference;
103
- const color = getUsageColor(percentage);
104
- return (_jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, children: [_jsx("circle", { cx: size / 2, cy: size / 2, r: radius, stroke: aiStyles.tooltipLabel.color, strokeWidth: stroke, fill: "transparent", opacity: 0.3 }), _jsx("circle", { cx: size / 2, cy: size / 2, r: radius, stroke: color, strokeWidth: stroke, fill: "transparent", strokeDasharray: circumference, strokeDashoffset: offset, strokeLinecap: "round", transform: `rotate(-90 ${size / 2} ${size / 2})` }), _jsxs("text", { x: size / 2, y: size / 2, textAnchor: "middle", dominantBaseline: "central", fontSize: "7px", fill: color, fontWeight: "600", children: [percentage.toFixed(0), "%"] })] }));
105
- };
106
- const balanceUsage = effectiveStatus?.balance;
107
- const storageUsage = effectiveStatus?.storage;
108
- const balanceUsed = safeNumber(balanceUsage?.used);
109
- const balanceRemaining = safeNumber(balanceUsage?.remaining);
110
- const rawBalanceTotal = balanceUsage?.total ??
111
- safeNumber(balanceUsage?.purchased) + safeNumber(balanceUsage?.quota);
112
- const balanceTotal = rawBalanceTotal > 0 ? rawBalanceTotal : balanceUsed + balanceRemaining;
113
- const balancePercentage = balanceUsage?.percentage ??
114
- (balanceTotal > 0 ? Math.round((balanceUsed / balanceTotal) * 100) : 0);
115
- const storageAllocated = storageUsage?.allocated_mb ?? storageUsage?.total_mb ?? 0;
116
- const storageUsed = storageUsage?.used_mb ?? storageUsage?.total_mb ?? 0;
117
- const storagePercentage = storageUsage?.percentage ??
118
- (storageAllocated > 0
119
- ? Math.round((storageUsed / storageAllocated) * 100)
120
- : 0);
121
- const showFastStatusSkeleton = lbStatus === "ready" &&
122
- (lbIsLoadingStatus || isLoadingStatus) &&
123
- !lbBasicStatus &&
124
- !effectiveStatus;
125
107
  const [showTooltip, setShowTooltip] = useState(false);
126
- const [isHovered, setIsHovered] = useState(false);
127
- const [tooltipPosition, setTooltipPosition] = useState({});
108
+ const [isSelectingApiKey, setIsSelectingApiKey] = useState(false);
128
109
  const buttonRef = useRef(null);
129
110
  const tooltipRef = useRef(null);
130
111
  const canPortal = typeof document !== "undefined";
131
- const hasApiKeySelected = Boolean(effectiveStatus?.apiKey?.id || effectiveStatus?.api_key?.id || lbSelectedKey?.id);
112
+ const effectiveStatus = lbStatus === "ready"
113
+ ? {
114
+ ...(lbApiStatus || {}),
115
+ ...(lbBasicStatus || {}),
116
+ storage: lbStorageStatus?.storage || lbApiStatus?.storage,
117
+ }
118
+ : status || null;
119
+ const hasApiKeySelected = Boolean(effectiveStatus?.apiKey?.id ||
120
+ effectiveStatus?.api_key?.id ||
121
+ lbSelectedKey?.id);
132
122
  const requiresApiKeySelection = lbStatus === "ready" && !hasApiKeySelected && apiKeys.length > 0;
123
+ const isApiKeyAuthMode = effectiveStatus?.authType === "api_key";
124
+ const [tooltipStyle, setTooltipStyle] = useState({});
133
125
  useLayoutEffect(() => {
134
- if (!showTooltip || !buttonRef.current) {
126
+ if (!showTooltip || !buttonRef.current || !canPortal) {
135
127
  return;
136
128
  }
137
- const updatePosition = () => {
138
- if (!buttonRef.current) {
129
+ const update = () => {
130
+ if (!buttonRef.current)
139
131
  return;
140
- }
141
- const buttonRect = buttonRef.current.getBoundingClientRect();
142
- if (canPortal) {
143
- const tooltipRect = tooltipRef.current?.getBoundingClientRect();
144
- const tooltipWidth = tooltipRect?.width ?? 360;
145
- const tooltipHeight = tooltipRect?.height ?? 520;
146
- const viewportWidth = window.innerWidth;
147
- const viewportHeight = window.innerHeight;
148
- const margin = 8;
149
- const spaceBelow = viewportHeight - buttonRect.bottom;
150
- const spaceAbove = buttonRect.top;
151
- const spaceRight = viewportWidth - buttonRect.right;
152
- const spaceLeft = buttonRect.left;
153
- const preferBelow = spaceBelow >= spaceAbove;
154
- const preferRight = spaceRight >= spaceLeft;
155
- let top = preferBelow
156
- ? buttonRect.bottom + margin
157
- : buttonRect.top - tooltipHeight - margin;
158
- if (top < margin) {
159
- top = margin;
160
- }
161
- if (top + tooltipHeight > viewportHeight - margin) {
162
- top = Math.max(margin, viewportHeight - tooltipHeight - margin);
163
- }
164
- let left = preferRight
165
- ? buttonRect.left
166
- : buttonRect.right - tooltipWidth;
167
- if (left < margin) {
168
- left = margin;
169
- }
170
- if (left + tooltipWidth > viewportWidth - margin) {
171
- left = Math.max(margin, viewportWidth - tooltipWidth - margin);
172
- }
173
- setTooltipPosition({
174
- top: `${top}px`,
175
- left: `${left}px`,
176
- position: "fixed",
177
- });
178
- }
179
- else {
180
- const position = calculateTooltipPosition(buttonRect);
181
- setTooltipPosition(position);
182
- }
132
+ const rect = buttonRef.current.getBoundingClientRect();
133
+ const tipRect = tooltipRef.current?.getBoundingClientRect();
134
+ const tipWidth = tipRect?.width ?? 360;
135
+ const tipHeight = tipRect?.height ?? 520;
136
+ const margin = 8;
137
+ const viewportW = window.innerWidth;
138
+ const viewportH = window.innerHeight;
139
+ const placeBelow = viewportH - rect.bottom >= rect.top;
140
+ let top = placeBelow
141
+ ? rect.bottom + margin
142
+ : rect.top - tipHeight - margin;
143
+ top = Math.max(margin, Math.min(top, viewportH - tipHeight - margin));
144
+ const placeRight = viewportW - rect.right >= rect.left;
145
+ let left = placeRight ? rect.left : rect.right - tipWidth;
146
+ left = Math.max(margin, Math.min(left, viewportW - tipWidth - margin));
147
+ setTooltipStyle({
148
+ position: "fixed",
149
+ top: `${top}px`,
150
+ left: `${left}px`,
151
+ });
183
152
  };
184
- const rafId = requestAnimationFrame(updatePosition);
185
- const rafId2 = requestAnimationFrame(updatePosition);
186
- const handleResize = () => updatePosition();
187
- window.addEventListener("resize", handleResize);
188
- window.addEventListener("scroll", handleResize, true);
153
+ const raf1 = requestAnimationFrame(update);
154
+ const raf2 = requestAnimationFrame(update);
155
+ window.addEventListener("resize", update);
156
+ window.addEventListener("scroll", update, true);
189
157
  return () => {
190
- cancelAnimationFrame(rafId);
191
- cancelAnimationFrame(rafId2);
192
- window.removeEventListener("resize", handleResize);
193
- window.removeEventListener("scroll", handleResize, true);
158
+ cancelAnimationFrame(raf1);
159
+ cancelAnimationFrame(raf2);
160
+ window.removeEventListener("resize", update);
161
+ window.removeEventListener("scroll", update, true);
194
162
  };
195
163
  }, [showTooltip, canPortal]);
196
- const handleMouseEnter = () => {
197
- if (requiresApiKeySelection) {
198
- return;
199
- }
200
- setShowTooltip(true);
201
- setIsHovered(true);
202
- };
203
- const handleMouseLeave = () => {
204
- if (requiresApiKeySelection) {
205
- return;
206
- }
207
- // Keep tooltip visible if hovering over it
208
- setTimeout(() => {
209
- if (!tooltipRef.current?.matches(":hover") &&
210
- !buttonRef.current?.matches(":hover")) {
211
- setShowTooltip(false);
212
- setIsHovered(false);
213
- }
214
- }, 100);
215
- };
216
164
  useLayoutEffect(() => {
217
- if (!showTooltip || requiresApiKeySelection || lbStatus !== "ready") {
165
+ if (!showTooltip || lbStatus !== "ready" || requiresApiKeySelection) {
218
166
  return;
219
167
  }
220
168
  if (!lbBasicStatus && !lbIsLoadingStatus && lbRefreshBasicStatus) {
@@ -227,8 +175,8 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
227
175
  }
228
176
  }, [
229
177
  showTooltip,
230
- requiresApiKeySelection,
231
178
  lbStatus,
179
+ requiresApiKeySelection,
232
180
  lbBasicStatus,
233
181
  lbStorageStatus,
234
182
  lbIsLoadingStatus,
@@ -236,454 +184,88 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
236
184
  lbRefreshBasicStatus,
237
185
  lbRefreshStorageStatus,
238
186
  ]);
239
- if (loading || isSelectingApiKey) {
240
- return (_jsx("button", { ref: buttonRef, style: {
241
- ...aiStyles.statusButton,
242
- ...aiStyles.statusButtonDisabled,
243
- }, className: className, disabled: true, children: _jsx("svg", { style: aiStyles.spinner, width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("path", { d: "M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83" }) }) }));
244
- }
245
- if (requiresApiKeySelection) {
246
- return (_jsxs("div", { style: { position: "relative", display: "inline-block" }, children: [_jsx("button", { ref: buttonRef, style: {
247
- ...aiStyles.statusButton,
248
- color: "#f59e0b",
249
- ...(isHovered && aiStyles.statusButtonHover),
250
- }, className: className, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), onClick: () => setShowApiKeySelector(true), title: "Select an API key to enable AI status and generation", children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("polyline", { points: "22 12 18 12 15 21 9 3 6 12 2 12" }) }) }), showApiKeySelector && apiKeys.length > 0 && (_jsx(LBApiKeySelector, { isOpen: showApiKeySelector, apiKeys: apiKeys, onSelect: async (keyId) => {
251
- setIsSelectingApiKey(true);
252
- try {
253
- if (switchApiKey) {
254
- await switchApiKey(keyId);
255
- }
256
- setShowApiKeySelector(false);
257
- if (refetchProviders) {
258
- await refetchProviders();
259
- }
260
- }
261
- catch (error) {
262
- console.error("Failed to select API key:", error);
263
- }
264
- finally {
265
- setIsSelectingApiKey(false);
266
- }
267
- }, onCancel: () => setShowApiKeySelector(false) }))] }));
268
- }
269
- if (!effectiveStatus) {
270
- // Si pas de statut API et pas de LBProvider, afficher message simple
271
- if (!lbStatus && lbStatus !== "ready") {
272
- return (_jsxs("div", { style: { position: "relative", display: "inline-block" }, children: [_jsx("button", { ref: buttonRef, style: {
273
- ...aiStyles.statusButton,
274
- color: "#ef4444",
275
- ...(isHovered && aiStyles.statusButtonHover),
276
- }, className: className, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("polyline", { points: "22 12 18 12 15 21 9 3 6 12 2 12" }) }) }), showTooltip &&
277
- canPortal &&
278
- createPortal(_jsx("div", { ref: tooltipRef, style: {
279
- ...aiStyles.tooltip,
280
- ...tooltipPosition,
281
- zIndex: 50,
282
- }, onMouseEnter: () => setShowTooltip(true), onMouseLeave: handleMouseLeave, children: "No status available" }), document.body)] }));
187
+ const balance = (effectiveStatus?.balance || {});
188
+ const storage = (effectiveStatus?.storage || {});
189
+ const balanceUsed = num(balance.used);
190
+ const balanceRemaining = num(balance.remaining);
191
+ const rawBalanceTotal = balance.total ?? num(balance.purchased) + num(balance.quota);
192
+ const balanceTotal = rawBalanceTotal > 0 ? rawBalanceTotal : balanceUsed + balanceRemaining;
193
+ const balancePct = balance.percentage ??
194
+ (balanceTotal > 0 ? Math.round((balanceUsed / balanceTotal) * 100) : 0);
195
+ const storageUsed = storage.used_mb ?? storage.total_mb ?? 0;
196
+ const storageTotal = storage.allocated_mb ?? storage.total_mb ?? 0;
197
+ const storagePct = storage.percentage ??
198
+ (storageTotal > 0 ? Math.round((storageUsed / storageTotal) * 100) : 0);
199
+ const showFastSkeleton = lbStatus === "ready" &&
200
+ lbIsLoadingStatus &&
201
+ !lbBasicStatus &&
202
+ !effectiveStatus;
203
+ const showCornerLoading = lbStatus === "ready" &&
204
+ (showFastSkeleton || lbIsLoadingStatus || lbIsLoadingStorage);
205
+ const triggerTone = useMemo(() => {
206
+ if (requiresApiKeySelection)
207
+ return "warning";
208
+ if (lbStatus && lbStatus !== "ready")
209
+ return "danger";
210
+ if (effectiveStatus)
211
+ return "success";
212
+ return "neutral";
213
+ }, [requiresApiKeySelection, lbStatus, effectiveStatus]);
214
+ const openTooltip = () => {
215
+ if (requiresApiKeySelection) {
216
+ return;
283
217
  }
284
- return (_jsxs(_Fragment, { children: [_jsxs("div", { style: { position: "relative", display: "inline-block" }, children: [_jsx("button", { ref: buttonRef, style: {
285
- ...aiStyles.statusButton,
286
- color: lbStatus === "ready" ? "#10b981" : "#ef4444",
287
- ...(isHovered && aiStyles.statusButtonHover),
288
- }, className: className, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onClick: () => {
289
- if (lbStatus !== "ready") {
290
- setShowSigninModal(true);
291
- }
292
- }, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("polyline", { points: "22 12 18 12 15 21 9 3 6 12 2 12" }) }) }), showTooltip &&
293
- canPortal &&
294
- createPortal(_jsx("div", { ref: tooltipRef, style: {
295
- ...aiStyles.tooltip,
296
- ...tooltipPosition,
297
- zIndex: 50,
298
- }, onMouseEnter: () => setShowTooltip(true), onMouseLeave: handleMouseLeave, children: lbStatus === "ready" && user ? (_jsxs(_Fragment, { children: [_jsx("div", { style: aiStyles.tooltipHeader, children: "API Status" }), _jsx("div", { style: {
299
- ...aiStyles.tooltipSection,
300
- ...aiStyles.tooltipSectionFirst,
301
- }, children: _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "User:" }), _jsx("span", { style: aiStyles.tooltipValue, children: user.email })] }) }), showFastStatusSkeleton && (_jsxs(_Fragment, { children: [_jsxs("div", { style: aiStyles.tooltipSection, children: [_jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "API Key:" }), _jsx("div", { style: {
302
- height: "16px",
303
- width: "110px",
304
- background: "rgba(139, 92, 246, 0.12)",
305
- borderRadius: "4px",
306
- animation: "pulse 2s ease-in-out infinite",
307
- } })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Env:" }), _jsx("div", { style: {
308
- height: "16px",
309
- width: "48px",
310
- background: "rgba(139, 92, 246, 0.12)",
311
- borderRadius: "4px",
312
- animation: "pulse 2s ease-in-out infinite",
313
- } })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Rate Limit:" }), _jsx("div", { style: {
314
- height: "16px",
315
- width: "84px",
316
- background: "rgba(139, 92, 246, 0.12)",
317
- borderRadius: "4px",
318
- animation: "pulse 2s ease-in-out infinite",
319
- } })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Auth:" }), _jsx("div", { style: {
320
- height: "16px",
321
- width: "72px",
322
- background: "rgba(139, 92, 246, 0.12)",
323
- borderRadius: "4px",
324
- animation: "pulse 2s ease-in-out infinite",
325
- } })] })] }), _jsxs("div", { style: aiStyles.tooltipSection, children: [_jsx("div", { style: aiStyles.tooltipSubtitle, children: "Wallet" }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Total:" }), _jsx("div", { style: {
326
- height: "16px",
327
- width: "120px",
328
- background: "rgba(139, 92, 246, 0.12)",
329
- borderRadius: "4px",
330
- animation: "pulse 2s ease-in-out infinite",
331
- } })] })] })] })), _jsxs("div", { style: {
332
- display: "flex",
333
- gap: "8px",
334
- borderTop: "1px solid var(--ai-border-primary, #374151)",
335
- paddingTop: "12px",
336
- }, children: [_jsx("button", { onClick: () => window.open("https://prompt.lastbrain.io/auth/dashboard", "_blank"), style: {
337
- flex: 1,
338
- background: "transparent",
339
- border: "none",
340
- padding: "14px",
341
- cursor: "pointer",
342
- display: "flex",
343
- alignItems: "center",
344
- justifyContent: "center",
345
- color: "#8b5cf6",
346
- transition: "all 0.2s ease",
347
- }, onMouseEnter: (e) => {
348
- Object.assign(e.currentTarget.style, {
349
- background: "rgba(139, 92, 246, 0.1)",
350
- });
351
- }, onMouseLeave: (e) => {
352
- Object.assign(e.currentTarget.style, {
353
- background: "transparent",
354
- });
355
- }, title: "View Metrics", children: _jsx(BarChart3, { size: 18 }) }), _jsx("button", { onClick: () => window.open("https://prompt.lastbrain.io/auth/ai/settings", "_blank"), style: {
356
- flex: 1,
357
- background: "transparent",
358
- border: "none",
359
- padding: "14px",
360
- cursor: "pointer",
361
- display: "flex",
362
- alignItems: "center",
363
- justifyContent: "center",
364
- color: "#8b5cf6",
365
- transition: "all 0.2s ease",
366
- }, onMouseEnter: (e) => {
367
- Object.assign(e.currentTarget.style, {
368
- background: "rgba(139, 92, 246, 0.1)",
369
- });
370
- }, onMouseLeave: (e) => {
371
- Object.assign(e.currentTarget.style, {
372
- background: "transparent",
373
- });
374
- }, title: "Settings", children: _jsx(Settings, { size: 18 }) }), _jsx("button", { onClick: () => window.open("https://prompt.lastbrain.io/auth/ai/prompts", "_blank"), style: {
375
- flex: 1,
376
- background: "transparent",
377
- border: "none",
378
- padding: "14px",
379
- cursor: "pointer",
380
- display: "flex",
381
- alignItems: "center",
382
- justifyContent: "center",
383
- color: "#8b5cf6",
384
- transition: "all 0.2s ease",
385
- }, onMouseEnter: (e) => {
386
- Object.assign(e.currentTarget.style, {
387
- background: "rgba(139, 92, 246, 0.1)",
388
- });
389
- }, onMouseLeave: (e) => {
390
- Object.assign(e.currentTarget.style, {
391
- background: "transparent",
392
- });
393
- }, title: "My Prompts", children: _jsx(FileText, { size: 18 }) }), _jsx("button", { onClick: () => window.open("https://prompt.lastbrain.io/auth/folder", "_blank"), style: {
394
- flex: 1,
395
- background: "transparent",
396
- border: "none",
397
- padding: "14px",
398
- cursor: "pointer",
399
- display: "flex",
400
- alignItems: "center",
401
- justifyContent: "center",
402
- color: "#8b5cf6",
403
- transition: "all 0.2s ease",
404
- }, onMouseEnter: (e) => {
405
- Object.assign(e.currentTarget.style, {
406
- background: "rgba(139, 92, 246, 0.1)",
407
- });
408
- }, onMouseLeave: (e) => {
409
- Object.assign(e.currentTarget.style, {
410
- background: "transparent",
411
- });
412
- }, title: "New Folder", children: _jsx(FolderPlus, { size: 18 }) }), _jsx("button", { onClick: async () => {
413
- if (logout) {
414
- await logout();
415
- // Refresh provider data after logout
416
- if (refetchProviders) {
417
- await refetchProviders();
418
- }
419
- }
420
- setShowTooltip(false);
421
- }, style: {
422
- flex: 1,
423
- background: "transparent",
424
- border: "none",
425
- padding: "14px",
426
- cursor: "pointer",
427
- display: "flex",
428
- alignItems: "center",
429
- justifyContent: "center",
430
- color: "#ef4444",
431
- transition: "all 0.2s ease",
432
- }, onMouseEnter: (e) => {
433
- Object.assign(e.currentTarget.style, {
434
- background: "rgba(239, 68, 68, 0.1)",
435
- });
436
- }, onMouseLeave: (e) => {
437
- Object.assign(e.currentTarget.style, {
438
- background: "transparent",
439
- });
440
- }, title: "Logout", children: _jsx(Power, { size: 18 }) })] })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { style: aiStyles.tooltipHeader, children: "LastBrain Authentication" }), _jsx("div", { style: {
441
- paddingBottom: "12px",
442
- }, children: _jsx("p", { style: {
443
- margin: 0,
444
- fontSize: "13px",
445
- color: "var(--ai-text-secondary, #9ca3af)",
446
- lineHeight: "1.5",
447
- }, children: "Connectez-vous pour acc\u00E9der aux fonctionnalit\u00E9s IA" }) }), _jsx("button", { onClick: () => {
448
- setShowSigninModal(true);
449
- setShowTooltip(false);
450
- }, style: {
451
- width: "100%",
452
- padding: "10px",
453
- background: "linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%)",
454
- border: "none",
455
- borderRadius: "6px",
456
- color: "#ffffff",
457
- fontSize: "13px",
458
- fontWeight: 600,
459
- cursor: "pointer",
460
- transition: "all 0.2s ease",
461
- }, onMouseEnter: (e) => {
462
- e.currentTarget.style.transform = "translateY(-1px)";
463
- e.currentTarget.style.boxShadow =
464
- "0 4px 12px rgba(139, 92, 246, 0.3)";
465
- }, onMouseLeave: (e) => {
466
- e.currentTarget.style.transform = "translateY(0)";
467
- e.currentTarget.style.boxShadow = "none";
468
- }, children: "\uD83D\uDD10 Se connecter" })] })) }), document.body)] }), _jsx(LBSigninModal, { isOpen: showSigninModal, onClose: () => setShowSigninModal(false) })] }));
469
- }
470
- return (_jsxs("div", { style: { position: "relative", display: "inline-block" }, children: [_jsx("button", { ref: buttonRef, style: {
471
- ...aiStyles.statusButton,
472
- color: "#10b981",
473
- ...(isHovered && aiStyles.statusButtonHover),
474
- }, className: className, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("polyline", { points: "22 12 18 12 15 21 9 3 6 12 2 12" }) }) }), showTooltip &&
475
- canPortal &&
476
- createPortal(_jsxs("div", { ref: tooltipRef, style: {
477
- ...aiStyles.tooltip,
478
- ...tooltipPosition,
479
- zIndex: 50,
480
- }, onMouseEnter: () => setShowTooltip(true), onMouseLeave: handleMouseLeave, children: [_jsx("div", { style: aiStyles.tooltipHeader, children: "API Status" }), effectiveStatus.user?.email && (_jsx("div", { style: {
481
- ...aiStyles.tooltipSection,
482
- ...aiStyles.tooltipSectionFirst,
483
- }, children: _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "User:" }), _jsx("span", { style: {
484
- ...aiStyles.tooltipValue,
485
- fontSize: "12px",
486
- maxWidth: "200px",
487
- overflow: "hidden",
488
- textOverflow: "ellipsis",
489
- }, children: effectiveStatus.user.email })] }) })), _jsxs("div", { style: {
490
- ...aiStyles.tooltipSection,
491
- ...(effectiveStatus.user?.email
492
- ? {}
493
- : aiStyles.tooltipSectionFirst),
494
- }, children: [_jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "API Key:" }), _jsxs("div", { style: {
495
- display: "flex",
496
- alignItems: "center",
497
- gap: "8px",
498
- }, children: [_jsx("span", { style: aiStyles.tooltipValue, children: lbIsLoadingStatus ? (_jsx("div", { style: {
499
- height: "16px",
500
- width: "100px",
501
- background: "rgba(139, 92, 246, 0.1)",
502
- borderRadius: "4px",
503
- animation: "pulse 2s ease-in-out infinite",
504
- } })) : (effectiveStatus?.apiKey?.name ||
218
+ setShowTooltip(true);
219
+ };
220
+ const closeTooltip = () => {
221
+ if (requiresApiKeySelection) {
222
+ return;
223
+ }
224
+ setTimeout(() => {
225
+ if (!tooltipRef.current?.matches(":hover") &&
226
+ !buttonRef.current?.matches(":hover")) {
227
+ setShowTooltip(false);
228
+ }
229
+ }, 100);
230
+ };
231
+ const renderTriggerIcon = () => {
232
+ if (loading || isSelectingApiKey) {
233
+ return _jsx(Loader2, { size: 14, className: "ai-spinner" });
234
+ }
235
+ return _jsx(Shield, { size: 14 });
236
+ };
237
+ const triggerClass = [
238
+ "ai-status-trigger",
239
+ `ai-size-${size}`,
240
+ `ai-radius-${radius}`,
241
+ triggerTone === "warning" ? "ai-status-trigger--warning" : "",
242
+ triggerTone === "danger" ? "ai-status-trigger--danger" : "",
243
+ triggerTone === "success" ? "ai-status-trigger--success" : "",
244
+ className,
245
+ ]
246
+ .filter(Boolean)
247
+ .join(" ");
248
+ const tooltipNode = showTooltip && canPortal
249
+ ? createPortal(_jsx("div", { ref: tooltipRef, className: "ai-popover ai-tooltip ai-status-tooltip", style: tooltipStyle, onMouseEnter: () => setShowTooltip(true), onMouseLeave: closeTooltip, children: lbStatus === "ready" && user ? (_jsx(_Fragment, { children: _jsxs("div", { className: "ai-popover-body", children: [_jsx("div", { className: "ai-popover-header", children: "API Status" }), _jsx("div", { className: "ai-popover-section ai-popover-section--first", children: _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: "User" }), _jsx("span", { className: "ai-popover-value ai-truncate max-w-[200px]", children: user.email })] }) }), _jsxs("div", { className: "ai-popover-section", children: [_jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: "API Key" }), _jsxs("div", { className: "ai-row", children: [lbIsLoadingStatus ? (_jsx("div", { className: "ai-kv-skeleton w-[110px]" })) : (_jsx("span", { className: "ai-popover-value", children: effectiveStatus?.apiKey?.name ||
505
250
  effectiveStatus?.api_key?.name ||
506
- "Unknown") }), switchApiKey && (_jsx("button", { onClick: (e) => {
251
+ "Unknown" })), switchApiKey ? (_jsx("button", { type: "button", className: "ai-icon-btn", onClick: (e) => {
507
252
  e.stopPropagation();
508
253
  setShowTooltip(false);
509
254
  setShowApiKeySelector(true);
510
- }, style: {
511
- background: "rgba(139, 92, 246, 0.1)",
512
- border: "1px solid rgba(139, 92, 246, 0.3)",
513
- borderRadius: "50%",
514
- width: "24px",
515
- height: "24px",
516
- display: "flex",
517
- alignItems: "center",
518
- justifyContent: "center",
519
- cursor: "pointer",
520
- padding: 0,
521
- transition: "all 0.2s ease",
522
- }, onMouseEnter: (e) => {
523
- e.currentTarget.style.background =
524
- "rgba(139, 92, 246, 0.2)";
525
- e.currentTarget.style.borderColor =
526
- "rgba(139, 92, 246, 0.5)";
527
- }, onMouseLeave: (e) => {
528
- e.currentTarget.style.background =
529
- "rgba(139, 92, 246, 0.1)";
530
- e.currentTarget.style.borderColor =
531
- "rgba(139, 92, 246, 0.3)";
532
- }, title: "Change API Key", children: _jsx(ArrowRightLeft, { size: 12, style: { color: "rgba(139, 92, 246, 1)" } }) }))] })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Env:" }), lbIsLoadingStatus && !effectiveStatus?.apiKey?.env ? (_jsx("div", { style: {
533
- height: "16px",
534
- width: "48px",
535
- background: "rgba(139, 92, 246, 0.1)",
536
- borderRadius: "4px",
537
- animation: "pulse 2s ease-in-out infinite",
538
- } })) : (_jsx("span", { style: aiStyles.tooltipValue, children: effectiveStatus.apiKey?.env ||
539
- effectiveStatus.api_key?.env ||
540
- "N/A" }))] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Rate Limit:" }), lbIsLoadingStatus &&
541
- !effectiveStatus?.apiKey?.rate_limit_rpm &&
542
- !effectiveStatus?.api_key?.rate_limit_rpm ? (_jsx("div", { style: {
543
- height: "16px",
544
- width: "92px",
545
- background: "rgba(139, 92, 246, 0.1)",
546
- borderRadius: "4px",
547
- animation: "pulse 2s ease-in-out infinite",
548
- } })) : (_jsxs("span", { style: aiStyles.tooltipValue, children: [effectiveStatus.apiKey?.rate_limit_rpm ||
549
- effectiveStatus.api_key?.rate_limit_rpm ||
550
- 0, " ", "req/min"] }))] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Auth:" }), _jsx("span", { style: aiStyles.tooltipValue, children: lbIsLoadingStatus
255
+ }, title: "Changer de cl\u00E9 API", children: _jsx(ArrowRightLeft, { size: 12 }) })) : null] })] }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: "Env" }), lbIsLoadingStatus && !effectiveStatus?.apiKey?.env ? (_jsx("div", { className: "ai-kv-skeleton w-12" })) : (_jsx("span", { className: "ai-popover-value", children: effectiveStatus?.apiKey?.env ||
256
+ effectiveStatus?.api_key?.env ||
257
+ "N/A" }))] }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: "Rate Limit" }), lbIsLoadingStatus &&
258
+ !effectiveStatus?.apiKey?.rate_limit_rpm ? (_jsx("div", { className: "ai-kv-skeleton w-[92px]" })) : (_jsxs("span", { className: "ai-popover-value", children: [effectiveStatus?.apiKey?.rate_limit_rpm ||
259
+ effectiveStatus?.api_key?.rate_limit_rpm ||
260
+ 0, " ", "req/min"] }))] }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: "Auth" }), _jsx("span", { className: "ai-popover-value", children: lbIsLoadingStatus
551
261
  ? "..."
552
- : effectiveStatus?.authType || lbStatus || "unknown" })] })] }), _jsxs("div", { style: aiStyles.tooltipSection, children: [_jsx("div", { style: aiStyles.tooltipSubtitle, children: "Wallet" }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Total:" }), lbIsLoadingStatus && !effectiveStatus?.balance ? (_jsxs("div", { style: {
553
- display: "flex",
554
- alignItems: "center",
555
- gap: "8px",
556
- }, children: [_jsx("div", { style: {
557
- height: "16px",
558
- width: "120px",
559
- background: "rgba(139, 92, 246, 0.1)",
560
- borderRadius: "4px",
561
- animation: "pulse 2s ease-in-out infinite",
562
- } }), _jsx("div", { style: {
563
- width: "28px",
564
- height: "28px",
565
- borderRadius: "50%",
566
- background: "rgba(139, 92, 246, 0.1)",
567
- animation: "pulse 2s ease-in-out infinite",
568
- } })] })) : (_jsxs(_Fragment, { children: [_jsxs("span", { style: aiStyles.tooltipValue, children: ["$", formatFixed(balanceUsed, 2), " / $", formatFixed(balanceTotal, 2)] }), renderUsageCircle(balancePercentage)] }))] })] }), _jsxs("div", { style: aiStyles.tooltipSection, children: [_jsx("div", { style: aiStyles.tooltipSubtitle, children: "Storage" }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Total:" }), lbIsLoadingStorage ? (_jsxs("div", { style: {
569
- display: "flex",
570
- alignItems: "center",
571
- gap: "8px",
572
- }, children: [_jsx("div", { style: {
573
- height: "16px",
574
- width: "120px",
575
- background: "rgba(139, 92, 246, 0.1)",
576
- borderRadius: "4px",
577
- animation: "pulse 2s ease-in-out infinite",
578
- } }), _jsx("div", { style: {
579
- width: "28px",
580
- height: "28px",
581
- borderRadius: "50%",
582
- background: "rgba(139, 92, 246, 0.1)",
583
- animation: "pulse 2s ease-in-out infinite",
584
- } })] })) : (_jsxs(_Fragment, { children: [_jsxs("span", { style: aiStyles.tooltipValue, children: [formatStorage(storageUsed), " /", " ", formatStorage(storageAllocated)] }), renderUsageCircle(storagePercentage)] }))] })] }), _jsxs("div", { style: {
585
- ...aiStyles.tooltipActions,
586
- width: "100%",
587
- flexDirection: "row",
588
- }, children: [_jsx("button", { onClick: () => window.open("https://prompt.lastbrain.io/auth/ai/tokens", "_blank"), style: {
589
- background: "transparent",
590
- border: "none",
591
- borderRadius: "4px",
592
- padding: "14px",
593
- cursor: "pointer",
594
- display: "flex",
595
- alignItems: "center",
596
- justifyContent: "center",
597
- color: "#8b5cf6",
598
- transition: "all 0.2s ease",
599
- }, onMouseEnter: (e) => {
600
- Object.assign(e.currentTarget.style, {
601
- background: "rgba(139, 92, 246, 0.1)",
602
- });
603
- }, onMouseLeave: (e) => {
604
- Object.assign(e.currentTarget.style, {
605
- background: "transparent",
606
- });
607
- }, title: "Dashboard", children: _jsx(BarChart3, { size: 18 }) }), _jsx("button", { onClick: () => window.open("https://prompt.lastbrain.io/auth/ai/history", "_blank"), style: {
608
- background: "transparent",
609
- border: "none",
610
- borderRadius: "4px",
611
- padding: "14px",
612
- cursor: "pointer",
613
- display: "flex",
614
- alignItems: "center",
615
- justifyContent: "center",
616
- color: "#8b5cf6",
617
- transition: "all 0.2s ease",
618
- }, onMouseEnter: (e) => {
619
- Object.assign(e.currentTarget.style, {
620
- background: "rgba(139, 92, 246, 0.1)",
621
- });
622
- }, onMouseLeave: (e) => {
623
- Object.assign(e.currentTarget.style, {
624
- background: "transparent",
625
- });
626
- }, title: "History", children: _jsx(HistoryIcon, { size: 18 }) }), _jsx("button", { onClick: () => window.open("https://prompt.lastbrain.io/auth/ai/settings", "_blank"), style: {
627
- background: "transparent",
628
- border: "none",
629
- borderRadius: "4px",
630
- padding: "14px",
631
- cursor: "pointer",
632
- display: "flex",
633
- alignItems: "center",
634
- justifyContent: "center",
635
- color: "#8b5cf6",
636
- transition: "all 0.2s ease",
637
- }, onMouseEnter: (e) => {
638
- Object.assign(e.currentTarget.style, {
639
- background: "rgba(139, 92, 246, 0.1)",
640
- });
641
- }, onMouseLeave: (e) => {
642
- Object.assign(e.currentTarget.style, {
643
- background: "transparent",
644
- });
645
- }, title: "Settings", children: _jsx(Settings, { size: 18 }) }), _jsx("button", { onClick: () => window.open("https://prompt.lastbrain.io/auth/ai/prompts", "_blank"), style: {
646
- background: "transparent",
647
- border: "none",
648
- borderRadius: "4px",
649
- padding: "14px",
650
- cursor: "pointer",
651
- display: "flex",
652
- alignItems: "center",
653
- justifyContent: "center",
654
- color: "#8b5cf6",
655
- transition: "all 0.2s ease",
656
- }, onMouseEnter: (e) => {
657
- Object.assign(e.currentTarget.style, {
658
- background: "rgba(139, 92, 246, 0.1)",
659
- });
660
- }, onMouseLeave: (e) => {
661
- Object.assign(e.currentTarget.style, {
662
- background: "transparent",
663
- });
664
- }, title: "New Prompt", children: _jsx(FileText, { size: 18 }) }), _jsx("button", { onClick: () => window.open("https://prompt.lastbrain.io/auth/folder", "_blank"), style: {
665
- background: "transparent",
666
- border: "none",
667
- padding: "14px",
668
- cursor: "pointer",
669
- display: "flex",
670
- alignItems: "center",
671
- justifyContent: "center",
672
- color: "#8b5cf6",
673
- transition: "all 0.2s ease",
674
- }, onMouseEnter: (e) => {
675
- Object.assign(e.currentTarget.style, {
676
- background: "rgba(139, 92, 246, 0.1)",
677
- });
678
- }, onMouseLeave: (e) => {
679
- Object.assign(e.currentTarget.style, {
680
- background: "transparent",
681
- });
682
- }, title: "New Folder", children: _jsx(FolderPlus, { size: 18 }) }), logout && (_jsx("button", { onClick: async () => {
262
+ : effectiveStatus?.authType || lbStatus || "unknown" })] })] }), _jsxs("div", { className: "ai-popover-section", children: [_jsx("div", { className: "ai-popover-header text-xs mb-2", children: "Wallet" }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: "Total" }), lbIsLoadingStatus && !effectiveStatus?.balance ? (_jsxs("div", { className: "ai-row", children: [_jsx("div", { className: "ai-kv-skeleton w-[120px]" }), _jsx("div", { className: "ai-kv-skeleton w-7 h-7 rounded-full" })] })) : (_jsxs("div", { className: "ai-row", children: [_jsxs("span", { className: "ai-popover-value", children: ["$", fixed(balanceUsed, 2), " / $", fixed(balanceTotal, 2)] }), _jsx(UsageCircle, { percentage: balancePct })] }))] })] }), _jsxs("div", { className: "ai-popover-section", children: [_jsx("div", { className: "ai-popover-header text-xs mb-2", children: "Storage" }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: "Total" }), lbIsLoadingStorage ? (_jsxs("div", { className: "ai-row", children: [_jsx("div", { className: "ai-kv-skeleton w-[120px]" }), _jsx("div", { className: "ai-kv-skeleton w-7 h-7 rounded-full" })] })) : (_jsxs("div", { className: "ai-row", children: [_jsxs("span", { className: "ai-popover-value", children: [formatStorage(storageUsed), " /", " ", formatStorage(storageTotal)] }), _jsx(UsageCircle, { percentage: storagePct })] }))] })] }), _jsxs("div", { className: "ai-status-actions", children: [QUICK_LINKS.map((item) => {
263
+ const Icon = item.icon;
264
+ return (_jsx("button", { type: "button", className: "ai-status-action-btn", onClick: () => window.open(item.href, "_blank"), title: item.title, children: _jsx(Icon, { size: 17 }) }, item.href));
265
+ }), logout && !isApiKeyAuthMode ? (_jsx("button", { type: "button", className: "ai-status-action-btn ai-status-action-btn--danger", onClick: async () => {
683
266
  try {
684
267
  await logout();
685
268
  setShowTooltip(false);
686
- // Refresh provider data after logout
687
269
  if (refetchProviders) {
688
270
  await refetchProviders();
689
271
  }
@@ -691,39 +273,30 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
691
273
  catch (error) {
692
274
  console.error("Logout failed:", error);
693
275
  }
694
- }, style: {
695
- background: "transparent",
696
- border: "none",
697
- padding: "14px",
698
- cursor: "pointer",
699
- display: "flex",
700
- alignItems: "center",
701
- justifyContent: "center",
702
- color: "#ef4444",
703
- transition: "all 0.2s ease",
704
- borderRadius: "4px",
705
- }, onMouseEnter: (e) => {
706
- Object.assign(e.currentTarget.style, {
707
- background: "rgba(239, 68, 68, 0.1)",
708
- });
709
- }, onMouseLeave: (e) => {
710
- Object.assign(e.currentTarget.style, {
711
- background: "transparent",
712
- });
713
- }, title: "Logout", children: _jsx(LogOut, { size: 18 }) }))] })] }), document.body), showApiKeySelector && apiKeys.length > 0 && (_jsx(LBApiKeySelector, { isOpen: showApiKeySelector, apiKeys: apiKeys, onSelect: async (keyId) => {
276
+ }, title: "Logout", children: _jsx(LogOut, { size: 17 }) })) : null] })] }) })) : (_jsxs("div", { className: "ai-popover-body", children: [_jsx("div", { className: "ai-popover-header", children: "LastBrain Authentication" }), _jsx("p", { className: "ai-signin-subtitle mt-0", children: "Connectez-vous pour acc\u00E9der aux fonctionnalit\u00E9s IA." }), _jsx("button", { type: "button", className: "ai-btn ai-btn--auth w-full mt-2", onClick: () => {
277
+ setShowSigninModal(true);
278
+ setShowTooltip(false);
279
+ }, children: "Se connecter" })] })) }), document.body)
280
+ : null;
281
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "relative inline-block", children: [_jsx("button", { ref: buttonRef, className: triggerClass, onMouseEnter: openTooltip, onMouseLeave: closeTooltip, onClick: () => {
282
+ if (requiresApiKeySelection) {
283
+ setShowApiKeySelector(true);
284
+ return;
285
+ }
286
+ if (!effectiveStatus && lbStatus !== "ready") {
287
+ setShowSigninModal(true);
288
+ }
289
+ }, disabled: loading || isSelectingApiKey, title: requiresApiKeySelection
290
+ ? "Sélectionnez une clé API"
291
+ : "Voir le status", "aria-label": "AI status", children: renderTriggerIcon() }), showCornerLoading ? (_jsx("span", { className: "ai-status-loading-dot", "aria-hidden": "true", children: _jsx(Loader2, { size: 7, className: "ai-spinner text-[var(--ai-primary)]" }) })) : null] }), tooltipNode, showApiKeySelector && apiKeys.length > 0 ? (_jsx(LBApiKeySelector, { isOpen: showApiKeySelector, apiKeys: apiKeys, onSelect: async (keyId) => {
714
292
  setIsSelectingApiKey(true);
715
293
  try {
716
- // Utiliser la nouvelle fonction switchApiKey qui gère automatiquement le contexte
717
- if (switchApiKey) {
718
- await switchApiKey(keyId);
719
- }
720
- else {
294
+ if (!switchApiKey) {
721
295
  throw new Error("Switch API key function not available");
722
296
  }
297
+ await switchApiKey(keyId);
723
298
  setShowApiKeySelector(false);
724
299
  setShowTooltip(false);
725
- setIsLoadingStatus(true);
726
- // Refresh provider data after API key selection
727
300
  if (refetchProviders) {
728
301
  await refetchProviders();
729
302
  }
@@ -733,7 +306,6 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
733
306
  }
734
307
  finally {
735
308
  setIsSelectingApiKey(false);
736
- setIsLoadingStatus(false);
737
309
  }
738
- }, onCancel: () => setShowApiKeySelector(false) }))] }));
310
+ }, onCancel: () => setShowApiKeySelector(false) })) : null, _jsx(LBSigninModal, { isOpen: showSigninModal, onClose: () => setShowSigninModal(false) })] }));
739
311
  }