@lastbrain/ai-ui-react 1.0.46 → 1.0.47
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,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAkBtD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAe,EACf,SAAc,GACf,EAAE,mBAAmB,2CA+9BrB"}
|
|
@@ -2,20 +2,27 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useRef, useLayoutEffect } from "react";
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
5
|
-
import { BarChart3, Settings, FileText, History as HistoryIcon, FolderPlus, Power, } from "lucide-react";
|
|
5
|
+
import { BarChart3, Settings, FileText, History as HistoryIcon, FolderPlus, Power, LogOut, Key, } from "lucide-react";
|
|
6
6
|
import { aiStyles, calculateTooltipPosition } from "../styles/inline";
|
|
7
7
|
import { useLB } from "../context/LBAuthProvider";
|
|
8
8
|
import { LBSigninModal } from "./LBSigninModal";
|
|
9
|
+
import { LBApiKeySelector } from "./LBApiKeySelector";
|
|
9
10
|
export function AiStatusButton({ status, loading = false, className = "", }) {
|
|
10
11
|
// Rendre l'authentification optionnelle
|
|
11
12
|
let lbStatus;
|
|
12
13
|
let user;
|
|
13
14
|
let logout;
|
|
15
|
+
let apiKeys = [];
|
|
16
|
+
let accessToken;
|
|
17
|
+
let selectApiKeyWithToken;
|
|
14
18
|
try {
|
|
15
19
|
const lbContext = useLB();
|
|
16
20
|
lbStatus = lbContext.status;
|
|
17
21
|
user = lbContext.user;
|
|
18
22
|
logout = lbContext.logout;
|
|
23
|
+
apiKeys = lbContext.apiKeys || [];
|
|
24
|
+
accessToken = lbContext.accessToken;
|
|
25
|
+
selectApiKeyWithToken = lbContext.selectApiKeyWithToken;
|
|
19
26
|
}
|
|
20
27
|
catch {
|
|
21
28
|
// LBProvider n'est pas disponible, ignorer
|
|
@@ -24,6 +31,7 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
|
|
|
24
31
|
logout = undefined;
|
|
25
32
|
}
|
|
26
33
|
const [showSigninModal, setShowSigninModal] = useState(false);
|
|
34
|
+
const [showApiKeySelector, setShowApiKeySelector] = useState(false);
|
|
27
35
|
const formatNumber = (value) => typeof value === "number" ? value.toLocaleString() : "0";
|
|
28
36
|
const formatFixed = (value, digits) => typeof value === "number" ? value.toFixed(digits) : "0.00";
|
|
29
37
|
const formatStorage = (valueMb) => {
|
|
@@ -335,10 +343,23 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
|
|
|
335
343
|
...aiStyles.tooltip,
|
|
336
344
|
...tooltipPosition,
|
|
337
345
|
zIndex: 50,
|
|
338
|
-
}, onMouseEnter: () => setShowTooltip(true), onMouseLeave: handleMouseLeave, children: [_jsx("div", { style: aiStyles.tooltipHeader, children: "API Status" }),
|
|
346
|
+
}, onMouseEnter: () => setShowTooltip(true), onMouseLeave: handleMouseLeave, children: [_jsx("div", { style: aiStyles.tooltipHeader, children: "API Status" }), status.user?.email && (_jsx("div", { style: {
|
|
339
347
|
...aiStyles.tooltipSection,
|
|
340
348
|
...aiStyles.tooltipSectionFirst,
|
|
341
|
-
}, children:
|
|
349
|
+
}, children: _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "User:" }), _jsx("span", { style: {
|
|
350
|
+
...aiStyles.tooltipValue,
|
|
351
|
+
fontSize: "12px",
|
|
352
|
+
maxWidth: "200px",
|
|
353
|
+
overflow: "hidden",
|
|
354
|
+
textOverflow: "ellipsis",
|
|
355
|
+
}, children: status.user.email })] }) })), _jsxs("div", { style: {
|
|
356
|
+
...aiStyles.tooltipSection,
|
|
357
|
+
...(status.user?.email
|
|
358
|
+
? {}
|
|
359
|
+
: aiStyles.tooltipSectionFirst),
|
|
360
|
+
}, children: [_jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "API Key:" }), _jsx("span", { style: aiStyles.tooltipValue, children: status.apiKey?.name ||
|
|
361
|
+
status.api_key?.name ||
|
|
362
|
+
"N/A" })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Env:" }), _jsx("span", { style: aiStyles.tooltipValue, children: status.api_key?.env || "N/A" })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Rate Limit:" }), _jsxs("span", { style: aiStyles.tooltipValue, children: [status.api_key?.rate_limit_rpm || 0, " req/min"] })] })] }), _jsxs("div", { style: aiStyles.tooltipSection, children: [_jsx("div", { style: aiStyles.tooltipSubtitle, children: "Balance" }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Total:" }), _jsxs("span", { style: aiStyles.tooltipValue, children: ["$", formatFixed(balanceUsed, 6), " / $", formatNumber(balanceTotal)] }), 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:" }), _jsxs("span", { style: aiStyles.tooltipValue, children: [formatStorage(storageUsed), " /", " ", formatStorage(storageAllocated)] }), renderUsageCircle(storagePercentage)] })] }), _jsxs("div", { style: {
|
|
342
363
|
...aiStyles.tooltipActions,
|
|
343
364
|
width: "100%",
|
|
344
365
|
flexDirection: "row",
|
|
@@ -436,5 +457,58 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
|
|
|
436
457
|
Object.assign(e.currentTarget.style, {
|
|
437
458
|
background: "transparent",
|
|
438
459
|
});
|
|
439
|
-
}, title: "New Folder", children: _jsx(FolderPlus, { size: 18 }) })
|
|
460
|
+
}, title: "New Folder", children: _jsx(FolderPlus, { size: 18 }) }), selectApiKeyWithToken && apiKeys.length > 1 && (_jsx("button", { onClick: () => setShowApiKeySelector(true), style: {
|
|
461
|
+
background: "transparent",
|
|
462
|
+
border: "none",
|
|
463
|
+
padding: "14px",
|
|
464
|
+
cursor: "pointer",
|
|
465
|
+
display: "flex",
|
|
466
|
+
alignItems: "center",
|
|
467
|
+
justifyContent: "center",
|
|
468
|
+
color: "#8b5cf6",
|
|
469
|
+
transition: "all 0.2s ease",
|
|
470
|
+
}, onMouseEnter: (e) => {
|
|
471
|
+
Object.assign(e.currentTarget.style, {
|
|
472
|
+
background: "rgba(139, 92, 246, 0.1)",
|
|
473
|
+
});
|
|
474
|
+
}, onMouseLeave: (e) => {
|
|
475
|
+
Object.assign(e.currentTarget.style, {
|
|
476
|
+
background: "transparent",
|
|
477
|
+
});
|
|
478
|
+
}, title: "Change API Key", children: _jsx(Key, { size: 18 }) })), logout && (_jsx("button", { onClick: async () => {
|
|
479
|
+
try {
|
|
480
|
+
await logout();
|
|
481
|
+
setShowTooltip(false);
|
|
482
|
+
}
|
|
483
|
+
catch (error) {
|
|
484
|
+
console.error("Logout failed:", error);
|
|
485
|
+
}
|
|
486
|
+
}, style: {
|
|
487
|
+
background: "transparent",
|
|
488
|
+
border: "none",
|
|
489
|
+
padding: "14px",
|
|
490
|
+
cursor: "pointer",
|
|
491
|
+
display: "flex",
|
|
492
|
+
alignItems: "center",
|
|
493
|
+
justifyContent: "center",
|
|
494
|
+
color: "#ef4444",
|
|
495
|
+
transition: "all 0.2s ease",
|
|
496
|
+
}, onMouseEnter: (e) => {
|
|
497
|
+
Object.assign(e.currentTarget.style, {
|
|
498
|
+
background: "rgba(239, 68, 68, 0.1)",
|
|
499
|
+
});
|
|
500
|
+
}, onMouseLeave: (e) => {
|
|
501
|
+
Object.assign(e.currentTarget.style, {
|
|
502
|
+
background: "transparent",
|
|
503
|
+
});
|
|
504
|
+
}, title: "Logout", children: _jsx(LogOut, { size: 18 }) }))] })] }), document.body), showApiKeySelector && selectApiKeyWithToken && (_jsx(LBApiKeySelector, { isOpen: showApiKeySelector, apiKeys: apiKeys, onSelect: async (keyId) => {
|
|
505
|
+
try {
|
|
506
|
+
await selectApiKeyWithToken(keyId);
|
|
507
|
+
setShowApiKeySelector(false);
|
|
508
|
+
setShowTooltip(false);
|
|
509
|
+
}
|
|
510
|
+
catch (error) {
|
|
511
|
+
console.error("Failed to select API key:", error);
|
|
512
|
+
}
|
|
513
|
+
}, onCancel: () => setShowApiKeySelector(false) }))] }));
|
|
440
514
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lastbrain/ai-ui-react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.47",
|
|
4
4
|
"description": "Headless React components for LastBrain AI UI Kit",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"lucide-react": "^0.257.0",
|
|
51
|
-
"@lastbrain/ai-ui-core": "1.0.
|
|
51
|
+
"@lastbrain/ai-ui-core": "1.0.38"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/react": "^19.2.0",
|
|
@@ -10,10 +10,13 @@ import {
|
|
|
10
10
|
History as HistoryIcon,
|
|
11
11
|
FolderPlus,
|
|
12
12
|
Power,
|
|
13
|
+
LogOut,
|
|
14
|
+
Key,
|
|
13
15
|
} from "lucide-react";
|
|
14
16
|
import { aiStyles, calculateTooltipPosition } from "../styles/inline";
|
|
15
17
|
import { useLB } from "../context/LBAuthProvider";
|
|
16
18
|
import { LBSigninModal } from "./LBSigninModal";
|
|
19
|
+
import { LBApiKeySelector } from "./LBApiKeySelector";
|
|
17
20
|
|
|
18
21
|
export interface AiStatusButtonProps {
|
|
19
22
|
status: AiStatus | null;
|
|
@@ -30,12 +33,20 @@ export function AiStatusButton({
|
|
|
30
33
|
let lbStatus: string | undefined;
|
|
31
34
|
let user: any;
|
|
32
35
|
let logout: (() => Promise<void>) | undefined;
|
|
36
|
+
let apiKeys: any[] = [];
|
|
37
|
+
let accessToken: string | undefined;
|
|
38
|
+
let selectApiKeyWithToken:
|
|
39
|
+
| ((apiKeyId: string) => Promise<void>)
|
|
40
|
+
| undefined;
|
|
33
41
|
|
|
34
42
|
try {
|
|
35
43
|
const lbContext = useLB();
|
|
36
44
|
lbStatus = lbContext.status;
|
|
37
45
|
user = lbContext.user;
|
|
38
46
|
logout = lbContext.logout;
|
|
47
|
+
apiKeys = lbContext.apiKeys || [];
|
|
48
|
+
accessToken = lbContext.accessToken;
|
|
49
|
+
selectApiKeyWithToken = lbContext.selectApiKeyWithToken;
|
|
39
50
|
} catch {
|
|
40
51
|
// LBProvider n'est pas disponible, ignorer
|
|
41
52
|
lbStatus = undefined;
|
|
@@ -44,6 +55,7 @@ export function AiStatusButton({
|
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
const [showSigninModal, setShowSigninModal] = useState(false);
|
|
58
|
+
const [showApiKeySelector, setShowApiKeySelector] = useState(false);
|
|
47
59
|
|
|
48
60
|
type BalanceUsage = {
|
|
49
61
|
used?: number;
|
|
@@ -664,16 +676,45 @@ export function AiStatusButton({
|
|
|
664
676
|
>
|
|
665
677
|
<div style={aiStyles.tooltipHeader}>API Status</div>
|
|
666
678
|
|
|
679
|
+
{/* User Info Section */}
|
|
680
|
+
{status.user?.email && (
|
|
681
|
+
<div
|
|
682
|
+
style={{
|
|
683
|
+
...aiStyles.tooltipSection,
|
|
684
|
+
...aiStyles.tooltipSectionFirst,
|
|
685
|
+
}}
|
|
686
|
+
>
|
|
687
|
+
<div style={aiStyles.tooltipRow}>
|
|
688
|
+
<span style={aiStyles.tooltipLabel}>User:</span>
|
|
689
|
+
<span
|
|
690
|
+
style={{
|
|
691
|
+
...aiStyles.tooltipValue,
|
|
692
|
+
fontSize: "12px",
|
|
693
|
+
maxWidth: "200px",
|
|
694
|
+
overflow: "hidden",
|
|
695
|
+
textOverflow: "ellipsis",
|
|
696
|
+
}}
|
|
697
|
+
>
|
|
698
|
+
{status.user.email}
|
|
699
|
+
</span>
|
|
700
|
+
</div>
|
|
701
|
+
</div>
|
|
702
|
+
)}
|
|
703
|
+
|
|
667
704
|
<div
|
|
668
705
|
style={{
|
|
669
706
|
...aiStyles.tooltipSection,
|
|
670
|
-
...
|
|
707
|
+
...(status.user?.email
|
|
708
|
+
? {}
|
|
709
|
+
: aiStyles.tooltipSectionFirst),
|
|
671
710
|
}}
|
|
672
711
|
>
|
|
673
712
|
<div style={aiStyles.tooltipRow}>
|
|
674
713
|
<span style={aiStyles.tooltipLabel}>API Key:</span>
|
|
675
714
|
<span style={aiStyles.tooltipValue}>
|
|
676
|
-
{status.
|
|
715
|
+
{status.apiKey?.name ||
|
|
716
|
+
status.api_key?.name ||
|
|
717
|
+
"N/A"}
|
|
677
718
|
</span>
|
|
678
719
|
</div>
|
|
679
720
|
<div style={aiStyles.tooltipRow}>
|
|
@@ -885,10 +926,97 @@ export function AiStatusButton({
|
|
|
885
926
|
>
|
|
886
927
|
<FolderPlus size={18} />
|
|
887
928
|
</button>
|
|
929
|
+
|
|
930
|
+
{/* Change API Key Button */}
|
|
931
|
+
{selectApiKeyWithToken && apiKeys.length > 1 && (
|
|
932
|
+
<button
|
|
933
|
+
onClick={() => setShowApiKeySelector(true)}
|
|
934
|
+
style={{
|
|
935
|
+
background: "transparent",
|
|
936
|
+
border: "none",
|
|
937
|
+
padding: "14px",
|
|
938
|
+
cursor: "pointer",
|
|
939
|
+
display: "flex",
|
|
940
|
+
alignItems: "center",
|
|
941
|
+
justifyContent: "center",
|
|
942
|
+
color: "#8b5cf6",
|
|
943
|
+
transition: "all 0.2s ease",
|
|
944
|
+
}}
|
|
945
|
+
onMouseEnter={(e) => {
|
|
946
|
+
Object.assign(e.currentTarget.style, {
|
|
947
|
+
background: "rgba(139, 92, 246, 0.1)",
|
|
948
|
+
});
|
|
949
|
+
}}
|
|
950
|
+
onMouseLeave={(e) => {
|
|
951
|
+
Object.assign(e.currentTarget.style, {
|
|
952
|
+
background: "transparent",
|
|
953
|
+
});
|
|
954
|
+
}}
|
|
955
|
+
title="Change API Key"
|
|
956
|
+
>
|
|
957
|
+
<Key size={18} />
|
|
958
|
+
</button>
|
|
959
|
+
)}
|
|
960
|
+
|
|
961
|
+
{/* Logout Button */}
|
|
962
|
+
{logout && (
|
|
963
|
+
<button
|
|
964
|
+
onClick={async () => {
|
|
965
|
+
try {
|
|
966
|
+
await logout();
|
|
967
|
+
setShowTooltip(false);
|
|
968
|
+
} catch (error) {
|
|
969
|
+
console.error("Logout failed:", error);
|
|
970
|
+
}
|
|
971
|
+
}}
|
|
972
|
+
style={{
|
|
973
|
+
background: "transparent",
|
|
974
|
+
border: "none",
|
|
975
|
+
padding: "14px",
|
|
976
|
+
cursor: "pointer",
|
|
977
|
+
display: "flex",
|
|
978
|
+
alignItems: "center",
|
|
979
|
+
justifyContent: "center",
|
|
980
|
+
color: "#ef4444",
|
|
981
|
+
transition: "all 0.2s ease",
|
|
982
|
+
}}
|
|
983
|
+
onMouseEnter={(e) => {
|
|
984
|
+
Object.assign(e.currentTarget.style, {
|
|
985
|
+
background: "rgba(239, 68, 68, 0.1)",
|
|
986
|
+
});
|
|
987
|
+
}}
|
|
988
|
+
onMouseLeave={(e) => {
|
|
989
|
+
Object.assign(e.currentTarget.style, {
|
|
990
|
+
background: "transparent",
|
|
991
|
+
});
|
|
992
|
+
}}
|
|
993
|
+
title="Logout"
|
|
994
|
+
>
|
|
995
|
+
<LogOut size={18} />
|
|
996
|
+
</button>
|
|
997
|
+
)}
|
|
888
998
|
</div>
|
|
889
999
|
</div>,
|
|
890
1000
|
document.body
|
|
891
1001
|
)}
|
|
1002
|
+
|
|
1003
|
+
{/* API Key Selector Modal */}
|
|
1004
|
+
{showApiKeySelector && selectApiKeyWithToken && (
|
|
1005
|
+
<LBApiKeySelector
|
|
1006
|
+
isOpen={showApiKeySelector}
|
|
1007
|
+
apiKeys={apiKeys}
|
|
1008
|
+
onSelect={async (keyId) => {
|
|
1009
|
+
try {
|
|
1010
|
+
await selectApiKeyWithToken(keyId);
|
|
1011
|
+
setShowApiKeySelector(false);
|
|
1012
|
+
setShowTooltip(false);
|
|
1013
|
+
} catch (error) {
|
|
1014
|
+
console.error("Failed to select API key:", error);
|
|
1015
|
+
}
|
|
1016
|
+
}}
|
|
1017
|
+
onCancel={() => setShowApiKeySelector(false)}
|
|
1018
|
+
/>
|
|
1019
|
+
)}
|
|
892
1020
|
</div>
|
|
893
1021
|
);
|
|
894
1022
|
}
|