@lastbrain/ai-ui-react 1.0.71 → 1.0.73

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.
@@ -1 +1 @@
1
- {"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAU,MAAM,uBAAuB,CAAC;AAuB9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEjD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAmHD,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAe,EACf,SAAc,EACd,IAAW,EACX,MAAe,GAChB,EAAE,mBAAmB,2CA+erB"}
1
+ {"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAU,MAAM,uBAAuB,CAAC;AAuB9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEjD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAmHD,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAe,EACf,SAAc,EACd,IAAW,EACX,MAAe,GAChB,EAAE,mBAAmB,2CA+gBrB"}
@@ -121,10 +121,13 @@ export function AiStatusButton({ status, loading = false, className = "", size =
121
121
  const hasApiKeySelected = Boolean(effectiveStatus?.apiKey?.id ||
122
122
  effectiveStatus?.api_key?.id ||
123
123
  lbSelectedKey?.id);
124
- const requiresApiKeySelection = lbStatus === "ready" && !hasApiKeySelected && apiKeys.length > 0;
125
- const isApiKeyAuthMode = effectiveStatus &&
124
+ const authTypeValue = effectiveStatus &&
126
125
  "authType" in effectiveStatus &&
127
- effectiveStatus.authType === "api_key";
126
+ typeof effectiveStatus.authType === "string"
127
+ ? effectiveStatus.authType
128
+ : undefined;
129
+ const requiresApiKeySelection = lbStatus === "ready" && !hasApiKeySelected && apiKeys.length > 0;
130
+ const isApiKeyAuthMode = authTypeValue === "api_key";
128
131
  const [tooltipStyle, setTooltipStyle] = useState({});
129
132
  useLayoutEffect(() => {
130
133
  if (!showTooltip || !buttonRef.current || !canPortal) {
@@ -200,12 +203,31 @@ export function AiStatusButton({ status, loading = false, className = "", size =
200
203
  const storageTotal = storage.allocated_mb ?? storage.total_mb ?? 0;
201
204
  const storagePct = storage.percentage ??
202
205
  (storageTotal > 0 ? Math.round((storageUsed / storageTotal) * 100) : 0);
206
+ const hasApiKeyMeta = Boolean(effectiveStatus?.apiKey?.name ||
207
+ effectiveStatus?.api_key?.name ||
208
+ effectiveStatus?.apiKey?.env ||
209
+ effectiveStatus?.api_key?.env ||
210
+ effectiveStatus?.apiKey?.rate_limit_rpm ||
211
+ effectiveStatus?.api_key?.rate_limit_rpm);
212
+ const hasBalanceMeta = Boolean(effectiveStatus?.balance);
213
+ const hasStorageMeta = Boolean(effectiveStatus?.storage);
214
+ const isImplicitStatusLoading = lbStatus === "ready" &&
215
+ !!user &&
216
+ !requiresApiKeySelection &&
217
+ (!authTypeValue || !hasApiKeyMeta || !hasBalanceMeta);
218
+ const isImplicitStorageLoading = lbStatus === "ready" &&
219
+ !!user &&
220
+ !requiresApiKeySelection &&
221
+ !hasStorageMeta;
203
222
  const showFastSkeleton = lbStatus === "ready" &&
204
- lbIsLoadingStatus &&
205
- !lbBasicStatus &&
206
- !effectiveStatus;
223
+ (lbIsLoadingStatus ||
224
+ isImplicitStatusLoading ||
225
+ (!lbBasicStatus && !effectiveStatus));
207
226
  const showCornerLoading = lbStatus === "ready" &&
208
- (showFastSkeleton || lbIsLoadingStatus || lbIsLoadingStorage);
227
+ (showFastSkeleton ||
228
+ lbIsLoadingStatus ||
229
+ lbIsLoadingStorage ||
230
+ isImplicitStorageLoading);
209
231
  const triggerTone = useMemo(() => {
210
232
  if (requiresApiKeySelection)
211
233
  return "warning";
@@ -250,24 +272,26 @@ export function AiStatusButton({ status, loading = false, className = "", size =
250
272
  .filter(Boolean)
251
273
  .join(" ");
252
274
  const tooltipNode = showTooltip && canPortal
253
- ? 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 ||
275
+ ? 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 || isImplicitStatusLoading ? (_jsx("div", { className: "ai-kv-skeleton w-[110px]" })) : (_jsx("span", { className: "ai-popover-value", children: effectiveStatus?.apiKey?.name ||
254
276
  effectiveStatus?.api_key?.name ||
255
- "Unknown" })), switchApiKey ? (_jsx("button", { type: "button", className: "ai-icon-btn", onClick: (e) => {
277
+ "Unknown" })), switchApiKey &&
278
+ !isApiKeyAuthMode &&
279
+ !isImplicitStatusLoading ? (_jsx("button", { type: "button", className: "ai-icon-btn", onClick: (e) => {
256
280
  e.stopPropagation();
257
281
  setShowTooltip(false);
258
282
  setShowApiKeySelector(true);
259
- }, 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 ||
283
+ }, 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 || isImplicitStatusLoading) &&
284
+ !effectiveStatus?.apiKey?.env ? (_jsx("div", { className: "ai-kv-skeleton w-12" })) : (_jsx("span", { className: "ai-popover-value", children: effectiveStatus?.apiKey?.env ||
260
285
  effectiveStatus?.api_key?.env ||
261
- "N/A" }))] }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: "Rate Limit" }), lbIsLoadingStatus &&
286
+ "N/A" }))] }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: "Rate Limit" }), (lbIsLoadingStatus || isImplicitStatusLoading) &&
262
287
  !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 ||
263
288
  effectiveStatus?.api_key?.rate_limit_rpm ||
264
- 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
289
+ 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 || isImplicitStatusLoading
265
290
  ? "..."
266
- : (effectiveStatus &&
267
- "authType" in effectiveStatus &&
268
- effectiveStatus.authType) ||
291
+ : authTypeValue ||
269
292
  lbStatus ||
270
- "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) => {
293
+ "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 || isImplicitStatusLoading) &&
294
+ !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 || isImplicitStorageLoading ? (_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) => {
271
295
  const Icon = item.icon;
272
296
  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));
273
297
  }), logout && !isApiKeyAuthMode ? (_jsx("button", { type: "button", className: "ai-status-action-btn ai-status-action-btn--danger", onClick: async () => {
package/dist/styles.css CHANGED
@@ -518,6 +518,7 @@
518
518
  display: flex;
519
519
  flex-wrap: wrap;
520
520
  gap: 8px;
521
+ margin-top: 6px;
521
522
  }
522
523
 
523
524
  .ai-chip {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lastbrain/ai-ui-react",
3
- "version": "1.0.71",
3
+ "version": "1.0.73",
4
4
  "description": "Headless React components for LastBrain AI UI Kit",
5
5
  "private": false,
6
6
  "type": "module",
@@ -219,12 +219,16 @@ export function AiStatusButton({
219
219
  effectiveStatus?.api_key?.id ||
220
220
  lbSelectedKey?.id
221
221
  );
222
+ const authTypeValue =
223
+ effectiveStatus &&
224
+ "authType" in effectiveStatus &&
225
+ typeof effectiveStatus.authType === "string"
226
+ ? effectiveStatus.authType
227
+ : undefined;
222
228
  const requiresApiKeySelection =
223
229
  lbStatus === "ready" && !hasApiKeySelected && apiKeys.length > 0;
224
230
  const isApiKeyAuthMode =
225
- effectiveStatus &&
226
- "authType" in effectiveStatus &&
227
- effectiveStatus.authType === "api_key";
231
+ authTypeValue === "api_key";
228
232
 
229
233
  const [tooltipStyle, setTooltipStyle] = useState<Record<string, string>>({});
230
234
 
@@ -320,15 +324,41 @@ export function AiStatusButton({
320
324
  storage.percentage ??
321
325
  (storageTotal > 0 ? Math.round((storageUsed / storageTotal) * 100) : 0);
322
326
 
327
+ const hasApiKeyMeta = Boolean(
328
+ effectiveStatus?.apiKey?.name ||
329
+ effectiveStatus?.api_key?.name ||
330
+ effectiveStatus?.apiKey?.env ||
331
+ effectiveStatus?.api_key?.env ||
332
+ effectiveStatus?.apiKey?.rate_limit_rpm ||
333
+ effectiveStatus?.api_key?.rate_limit_rpm
334
+ );
335
+ const hasBalanceMeta = Boolean(effectiveStatus?.balance);
336
+ const hasStorageMeta = Boolean(effectiveStatus?.storage);
337
+
338
+ const isImplicitStatusLoading =
339
+ lbStatus === "ready" &&
340
+ !!user &&
341
+ !requiresApiKeySelection &&
342
+ (!authTypeValue || !hasApiKeyMeta || !hasBalanceMeta);
343
+
344
+ const isImplicitStorageLoading =
345
+ lbStatus === "ready" &&
346
+ !!user &&
347
+ !requiresApiKeySelection &&
348
+ !hasStorageMeta;
349
+
323
350
  const showFastSkeleton =
324
351
  lbStatus === "ready" &&
325
- lbIsLoadingStatus &&
326
- !lbBasicStatus &&
327
- !effectiveStatus;
352
+ (lbIsLoadingStatus ||
353
+ isImplicitStatusLoading ||
354
+ (!lbBasicStatus && !effectiveStatus));
328
355
 
329
356
  const showCornerLoading =
330
357
  lbStatus === "ready" &&
331
- (showFastSkeleton || lbIsLoadingStatus || lbIsLoadingStorage);
358
+ (showFastSkeleton ||
359
+ lbIsLoadingStatus ||
360
+ lbIsLoadingStorage ||
361
+ isImplicitStorageLoading);
332
362
 
333
363
  const triggerTone = useMemo(() => {
334
364
  if (requiresApiKeySelection) return "warning";
@@ -404,7 +434,7 @@ export function AiStatusButton({
404
434
  <div className="ai-popover-row">
405
435
  <span className="ai-popover-label">API Key</span>
406
436
  <div className="ai-row">
407
- {lbIsLoadingStatus ? (
437
+ {lbIsLoadingStatus || isImplicitStatusLoading ? (
408
438
  <div className="ai-kv-skeleton w-[110px]" />
409
439
  ) : (
410
440
  <span className="ai-popover-value">
@@ -413,7 +443,9 @@ export function AiStatusButton({
413
443
  "Unknown"}
414
444
  </span>
415
445
  )}
416
- {switchApiKey ? (
446
+ {switchApiKey &&
447
+ !isApiKeyAuthMode &&
448
+ !isImplicitStatusLoading ? (
417
449
  <button
418
450
  type="button"
419
451
  className="ai-icon-btn"
@@ -432,7 +464,8 @@ export function AiStatusButton({
432
464
 
433
465
  <div className="ai-popover-row">
434
466
  <span className="ai-popover-label">Env</span>
435
- {lbIsLoadingStatus && !effectiveStatus?.apiKey?.env ? (
467
+ {(lbIsLoadingStatus || isImplicitStatusLoading) &&
468
+ !effectiveStatus?.apiKey?.env ? (
436
469
  <div className="ai-kv-skeleton w-12" />
437
470
  ) : (
438
471
  <span className="ai-popover-value">
@@ -445,7 +478,7 @@ export function AiStatusButton({
445
478
 
446
479
  <div className="ai-popover-row">
447
480
  <span className="ai-popover-label">Rate Limit</span>
448
- {lbIsLoadingStatus &&
481
+ {(lbIsLoadingStatus || isImplicitStatusLoading) &&
449
482
  !effectiveStatus?.apiKey?.rate_limit_rpm ? (
450
483
  <div className="ai-kv-skeleton w-[92px]" />
451
484
  ) : (
@@ -461,11 +494,9 @@ export function AiStatusButton({
461
494
  <div className="ai-popover-row">
462
495
  <span className="ai-popover-label">Auth</span>
463
496
  <span className="ai-popover-value">
464
- {lbIsLoadingStatus
497
+ {lbIsLoadingStatus || isImplicitStatusLoading
465
498
  ? "..."
466
- : (effectiveStatus &&
467
- "authType" in effectiveStatus &&
468
- effectiveStatus.authType) ||
499
+ : authTypeValue ||
469
500
  lbStatus ||
470
501
  "unknown"}
471
502
  </span>
@@ -476,7 +507,8 @@ export function AiStatusButton({
476
507
  <div className="ai-popover-header text-xs mb-2">Wallet</div>
477
508
  <div className="ai-popover-row">
478
509
  <span className="ai-popover-label">Total</span>
479
- {lbIsLoadingStatus && !effectiveStatus?.balance ? (
510
+ {(lbIsLoadingStatus || isImplicitStatusLoading) &&
511
+ !effectiveStatus?.balance ? (
480
512
  <div className="ai-row">
481
513
  <div className="ai-kv-skeleton w-[120px]" />
482
514
  <div className="ai-kv-skeleton w-7 h-7 rounded-full" />
@@ -498,7 +530,7 @@ export function AiStatusButton({
498
530
  </div>
499
531
  <div className="ai-popover-row">
500
532
  <span className="ai-popover-label">Total</span>
501
- {lbIsLoadingStorage ? (
533
+ {lbIsLoadingStorage || isImplicitStorageLoading ? (
502
534
  <div className="ai-row">
503
535
  <div className="ai-kv-skeleton w-[120px]" />
504
536
  <div className="ai-kv-skeleton w-7 h-7 rounded-full" />
package/src/styles.css CHANGED
@@ -518,6 +518,7 @@
518
518
  display: flex;
519
519
  flex-wrap: wrap;
520
520
  gap: 8px;
521
+ margin-top: 6px;
521
522
  }
522
523
 
523
524
  .ai-chip {