@lastbrain/ai-ui-react 1.0.57 → 1.0.59
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/components/AiStatusButton.d.ts.map +1 -1
- package/dist/components/AiStatusButton.js +29 -2
- package/dist/components/LBConnectButton.d.ts.map +1 -1
- package/dist/components/LBConnectButton.js +11 -1
- package/dist/context/LBAuthProvider.d.ts +12 -2
- package/dist/context/LBAuthProvider.d.ts.map +1 -1
- package/dist/context/LBAuthProvider.js +106 -14
- package/package.json +1 -1
- package/src/components/AiStatusButton.tsx +48 -6
- package/src/components/LBConnectButton.tsx +12 -1
- package/src/context/LBAuthProvider.tsx +132 -16
|
@@ -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;AAmBtD,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,
|
|
1
|
+
{"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAmBtD,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,2CAolCrB"}
|
|
@@ -18,7 +18,10 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
|
|
|
18
18
|
let selectApiKeyWithToken;
|
|
19
19
|
let switchApiKey;
|
|
20
20
|
let lbApiStatus = null;
|
|
21
|
+
let lbBasicStatus = null;
|
|
22
|
+
let lbStorageStatus = null;
|
|
21
23
|
let lbIsLoadingStatus = false;
|
|
24
|
+
let lbIsLoadingStorage = false;
|
|
22
25
|
try {
|
|
23
26
|
const lbContext = useLB();
|
|
24
27
|
lbStatus = lbContext.status;
|
|
@@ -29,7 +32,10 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
|
|
|
29
32
|
selectApiKeyWithToken = lbContext.selectApiKeyWithToken;
|
|
30
33
|
switchApiKey = lbContext.switchApiKey;
|
|
31
34
|
lbApiStatus = lbContext.apiStatus;
|
|
35
|
+
lbBasicStatus = lbContext.basicStatus;
|
|
36
|
+
lbStorageStatus = lbContext.storageStatus;
|
|
32
37
|
lbIsLoadingStatus = lbContext.isLoadingStatus || false;
|
|
38
|
+
lbIsLoadingStorage = lbContext.isLoadingStorage || false;
|
|
33
39
|
}
|
|
34
40
|
catch {
|
|
35
41
|
// LBProvider n'est pas disponible, ignorer
|
|
@@ -38,7 +44,12 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
|
|
|
38
44
|
logout = undefined;
|
|
39
45
|
}
|
|
40
46
|
// Utiliser le status du contexte LB si pas de prop status
|
|
41
|
-
|
|
47
|
+
// Combinaison du basic status et storage status pour backward compatibility
|
|
48
|
+
const effectiveStatus = status || {
|
|
49
|
+
...lbApiStatus,
|
|
50
|
+
...lbBasicStatus,
|
|
51
|
+
storage: lbStorageStatus?.storage,
|
|
52
|
+
};
|
|
42
53
|
// Récupérer refetchProviders depuis AiProvider si disponible
|
|
43
54
|
let refetchProviders;
|
|
44
55
|
try {
|
|
@@ -423,7 +434,23 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
|
|
|
423
434
|
effectiveStatus.api_key?.env ||
|
|
424
435
|
"N/A" })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Rate Limit:" }), _jsxs("span", { style: aiStyles.tooltipValue, children: [effectiveStatus.apiKey?.rate_limit_rpm ||
|
|
425
436
|
effectiveStatus.api_key?.rate_limit_rpm ||
|
|
426
|
-
0, " ", "req/min"] })] })] }), _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:" }), _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:" }),
|
|
437
|
+
0, " ", "req/min"] })] })] }), _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:" }), _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:" }), lbIsLoadingStorage ? (_jsxs("div", { style: {
|
|
438
|
+
display: "flex",
|
|
439
|
+
alignItems: "center",
|
|
440
|
+
gap: "8px",
|
|
441
|
+
}, children: [_jsx("div", { style: {
|
|
442
|
+
height: "16px",
|
|
443
|
+
width: "120px",
|
|
444
|
+
background: "rgba(139, 92, 246, 0.1)",
|
|
445
|
+
borderRadius: "4px",
|
|
446
|
+
animation: "pulse 2s ease-in-out infinite",
|
|
447
|
+
} }), _jsx("div", { style: {
|
|
448
|
+
width: "28px",
|
|
449
|
+
height: "28px",
|
|
450
|
+
borderRadius: "50%",
|
|
451
|
+
background: "rgba(139, 92, 246, 0.1)",
|
|
452
|
+
animation: "pulse 2s ease-in-out infinite",
|
|
453
|
+
} })] })) : (_jsxs(_Fragment, { children: [_jsxs("span", { style: aiStyles.tooltipValue, children: [formatStorage(storageUsed), " /", " ", formatStorage(storageAllocated)] }), renderUsageCircle(storagePercentage)] }))] })] }), _jsxs("div", { style: {
|
|
427
454
|
...aiStyles.tooltipActions,
|
|
428
455
|
width: "100%",
|
|
429
456
|
flexDirection: "row",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LBConnectButton.d.ts","sourceRoot":"","sources":["../../src/components/LBConnectButton.tsx"],"names":[],"mappings":"AAWA,UAAU,oBAAoB;IAC5B,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,EAC9B,KAAkC,EAClC,SAAc,EACd,WAAW,EACX,WAAW,GACZ,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"LBConnectButton.d.ts","sourceRoot":"","sources":["../../src/components/LBConnectButton.tsx"],"names":[],"mappings":"AAWA,UAAU,oBAAoB;IAC5B,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,EAC9B,KAAkC,EAClC,SAAc,EACd,WAAW,EACX,WAAW,GACZ,EAAE,oBAAoB,2CAuDtB;AAED;;GAEG;AACH,UAAU,gBAAgB;IACxB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACrC;AAED,iBAAS,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CA+RjD;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -12,7 +12,17 @@ export function LBConnectButton({ label = "Se connecter à LastBrain", className
|
|
|
12
12
|
const handleClick = () => {
|
|
13
13
|
if (status === "ready" && user) {
|
|
14
14
|
// Déjà connecté, proposer de se déconnecter
|
|
15
|
-
logout()
|
|
15
|
+
logout().then(() => {
|
|
16
|
+
// Redirection propre après logout
|
|
17
|
+
if (typeof window !== "undefined") {
|
|
18
|
+
// Garder la langue actuelle de l'URL
|
|
19
|
+
const currentPath = window.location.pathname;
|
|
20
|
+
const langMatch = currentPath.match(/^\/([a-z]{2})\//);
|
|
21
|
+
const currentLang = langMatch ? langMatch[1] : "en";
|
|
22
|
+
// Rediriger vers la page d'accueil dans la langue actuelle
|
|
23
|
+
window.location.href = `/${currentLang}`;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
16
26
|
}
|
|
17
27
|
else {
|
|
18
28
|
// Pas connecté, ouvrir la modal
|
|
@@ -41,10 +41,20 @@ interface LBContextValue extends LBAuthState {
|
|
|
41
41
|
accessToken?: string;
|
|
42
42
|
/** Status API (balance, storage, API key info) */
|
|
43
43
|
apiStatus: AiStatus | null;
|
|
44
|
-
/**
|
|
44
|
+
/** Status basique (rapide) - balance, API key info sans storage */
|
|
45
|
+
basicStatus: any;
|
|
46
|
+
/** Status storage (lent) avec cache */
|
|
47
|
+
storageStatus: any;
|
|
48
|
+
/** Fonction pour rafraîchir le status rapide */
|
|
49
|
+
refreshBasicStatus: () => Promise<void>;
|
|
50
|
+
/** Fonction pour rafraîchir le storage (avec cache optionnel) */
|
|
51
|
+
refreshStorageStatus: (force?: boolean) => Promise<void>;
|
|
52
|
+
/** Fonction pour rafraîchir le status (backward compatibility) */
|
|
45
53
|
refreshStatus: () => Promise<void>;
|
|
46
|
-
/** Indique si le status est en cours de chargement */
|
|
54
|
+
/** Indique si le status basique est en cours de chargement */
|
|
47
55
|
isLoadingStatus: boolean;
|
|
56
|
+
/** Indique si le storage est en cours de chargement */
|
|
57
|
+
isLoadingStorage: boolean;
|
|
48
58
|
}
|
|
49
59
|
export declare function LBProvider({ children, baseUrl: _baseUrl, proxyUrl, onStatusChange, onAuthChange, }: LBProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
50
60
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LBAuthProvider.d.ts","sourceRoot":"","sources":["../../src/context/LBAuthProvider.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EAIR,QAAQ,EACT,MAAM,uBAAuB,CAAC;AAE/B,UAAU,eAAe;IACvB,QAAQ,EAAE,SAAS,CAAC;IACpB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IACzD,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,UAAU,cAAe,SAAQ,WAAW;IAC1C,4BAA4B;IAC5B,KAAK,EAAE,CACL,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC;QACX,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH,8BAA8B;IAC9B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,6CAA6C;IAC7C,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC3D,gEAAgE;IAChE,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,mDAAmD;IACnD,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,iEAAiE;IACjE,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,oCAAoC;IACpC,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,2BAA2B;IAC3B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,
|
|
1
|
+
{"version":3,"file":"LBAuthProvider.d.ts","sourceRoot":"","sources":["../../src/context/LBAuthProvider.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EAIR,QAAQ,EACT,MAAM,uBAAuB,CAAC;AAE/B,UAAU,eAAe;IACvB,QAAQ,EAAE,SAAS,CAAC;IACpB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IACzD,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,UAAU,cAAe,SAAQ,WAAW;IAC1C,4BAA4B;IAC5B,KAAK,EAAE,CACL,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC;QACX,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH,8BAA8B;IAC9B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,6CAA6C;IAC7C,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC3D,gEAAgE;IAChE,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,mDAAmD;IACnD,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,iEAAiE;IACjE,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,oCAAoC;IACpC,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,2BAA2B;IAC3B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,mEAAmE;IACnE,WAAW,EAAE,GAAG,CAAC;IACjB,uCAAuC;IACvC,aAAa,EAAE,GAAG,CAAC;IACnB,gDAAgD;IAChD,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,iEAAiE;IACjE,oBAAoB,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,kEAAkE;IAClE,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,8DAA8D;IAC9D,eAAe,EAAE,OAAO,CAAC;IACzB,uDAAuD;IACvD,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAID,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,OAAO,EAAE,QAA2B,EACpC,QAA2B,EAC3B,cAAc,EACd,YAAY,GACb,EAAE,eAAe,2CAskBjB;AAED;;GAEG;AACH,wBAAgB,KAAK,IAAI,cAAc,CAMtC"}
|
|
@@ -13,7 +13,11 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
13
13
|
const [apiKeys, setApiKeys] = useState([]);
|
|
14
14
|
const [accessToken, setAccessToken] = useState();
|
|
15
15
|
const [apiStatus, setApiStatus] = useState(null);
|
|
16
|
+
const [basicStatus, setBasicStatus] = useState(null);
|
|
17
|
+
const [storageStatus, setStorageStatus] = useState(null);
|
|
16
18
|
const [isLoadingStatus, setIsLoadingStatus] = useState(false);
|
|
19
|
+
const [isLoadingStorage, setIsLoadingStorage] = useState(false);
|
|
20
|
+
const [storageLastFetch, setStorageLastFetch] = useState(0);
|
|
17
21
|
/**
|
|
18
22
|
* Vérifie si une session existe au chargement
|
|
19
23
|
*/
|
|
@@ -257,35 +261,99 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
257
261
|
}
|
|
258
262
|
}, [proxyUrl, fetchApiKeys, selectApiKey]);
|
|
259
263
|
/**
|
|
260
|
-
* Récupère le status API (balance,
|
|
264
|
+
* Récupère le status API basique (balance, API key info) - RAPIDE
|
|
261
265
|
*/
|
|
262
|
-
const
|
|
266
|
+
const refreshBasicStatus = useCallback(async () => {
|
|
263
267
|
if (state.status !== "ready") {
|
|
264
|
-
|
|
268
|
+
setBasicStatus(null);
|
|
265
269
|
setIsLoadingStatus(false);
|
|
266
270
|
return;
|
|
267
271
|
}
|
|
268
272
|
setIsLoadingStatus(true);
|
|
269
273
|
try {
|
|
270
|
-
const response = await fetch(`${proxyUrl}/auth/status`, {
|
|
274
|
+
const response = await fetch(`${proxyUrl}/auth/status?fast=true`, {
|
|
271
275
|
credentials: "include",
|
|
272
276
|
});
|
|
273
277
|
if (response.ok) {
|
|
274
278
|
const data = await response.json();
|
|
275
|
-
|
|
279
|
+
setBasicStatus(data);
|
|
280
|
+
// Combiner avec le storage existant si disponible
|
|
281
|
+
const combinedStatus = {
|
|
282
|
+
...data,
|
|
283
|
+
storage: storageStatus?.storage || data.storage,
|
|
284
|
+
};
|
|
285
|
+
setApiStatus(combinedStatus);
|
|
276
286
|
}
|
|
277
287
|
else {
|
|
278
|
-
|
|
288
|
+
setBasicStatus(null);
|
|
279
289
|
}
|
|
280
290
|
}
|
|
281
291
|
catch (error) {
|
|
282
|
-
console.error("[LBProvider] Failed to fetch status:", error);
|
|
283
|
-
|
|
292
|
+
console.error("[LBProvider] Failed to fetch basic status:", error);
|
|
293
|
+
setBasicStatus(null);
|
|
284
294
|
}
|
|
285
295
|
finally {
|
|
286
296
|
setIsLoadingStatus(false);
|
|
287
297
|
}
|
|
288
|
-
}, [proxyUrl, state.status]);
|
|
298
|
+
}, [proxyUrl, state.status, storageStatus]);
|
|
299
|
+
/**
|
|
300
|
+
* Récupère le storage - LENT avec cache (5 minutes)
|
|
301
|
+
*/
|
|
302
|
+
const refreshStorageStatus = useCallback(async (force = false) => {
|
|
303
|
+
if (state.status !== "ready") {
|
|
304
|
+
setStorageStatus(null);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
// Cache de 5 minutes sauf si force=true
|
|
308
|
+
const now = Date.now();
|
|
309
|
+
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
|
|
310
|
+
if (!force &&
|
|
311
|
+
storageLastFetch &&
|
|
312
|
+
now - storageLastFetch < CACHE_DURATION) {
|
|
313
|
+
console.log("[LBProvider] Storage cache still valid, skipping fetch");
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
setIsLoadingStorage(true);
|
|
317
|
+
try {
|
|
318
|
+
// Essayer l'endpoint spécialisé storage d'abord
|
|
319
|
+
let response = await fetch(`${proxyUrl}/auth/status/storage`, {
|
|
320
|
+
credentials: "include",
|
|
321
|
+
});
|
|
322
|
+
// Si 404, faire un fallback vers l'endpoint normal (backward compatibility)
|
|
323
|
+
if (!response.ok && response.status === 404) {
|
|
324
|
+
console.log("[LBProvider] Storage endpoint not available, using fallback");
|
|
325
|
+
response = await fetch(`${proxyUrl}/auth/status`, {
|
|
326
|
+
credentials: "include",
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
if (response.ok) {
|
|
330
|
+
const data = await response.json();
|
|
331
|
+
// Si c'est la réponse complète (fallback), extraire juste le storage
|
|
332
|
+
const storageData = data.storage ? { storage: data.storage } : data;
|
|
333
|
+
setStorageStatus(storageData);
|
|
334
|
+
setStorageLastFetch(now);
|
|
335
|
+
// Combiner avec le basic status
|
|
336
|
+
const combinedStatus = {
|
|
337
|
+
...basicStatus,
|
|
338
|
+
storage: storageData.storage,
|
|
339
|
+
};
|
|
340
|
+
setApiStatus(combinedStatus);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
console.warn("[LBProvider] Failed to fetch storage status:", response.status);
|
|
344
|
+
// Arrêter les tentatives répétées si échec persistant
|
|
345
|
+
setStorageLastFetch(now); // Marquer comme essayé pour éviter la boucle
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
console.error("[LBProvider] Failed to fetch storage status:", error);
|
|
350
|
+
// Arrêter les tentatives répétées si erreur persistante
|
|
351
|
+
setStorageLastFetch(now); // Marquer comme essayé pour éviter la boucle
|
|
352
|
+
}
|
|
353
|
+
finally {
|
|
354
|
+
setIsLoadingStorage(false);
|
|
355
|
+
}
|
|
356
|
+
}, [proxyUrl, state.status, basicStatus, storageLastFetch]);
|
|
289
357
|
/**
|
|
290
358
|
* Sélectionne une clé API avec le token déjà stocké (après login)
|
|
291
359
|
*/
|
|
@@ -312,7 +380,9 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
312
380
|
throw new Error(errorData.error || "Failed to switch API key");
|
|
313
381
|
}
|
|
314
382
|
// Refresh le status après le changement
|
|
315
|
-
await
|
|
383
|
+
await refreshBasicStatus();
|
|
384
|
+
// Refresh storage en arrière-plan
|
|
385
|
+
setTimeout(() => refreshStorageStatus(), 100);
|
|
316
386
|
}
|
|
317
387
|
else if (accessToken) {
|
|
318
388
|
// Utiliser la méthode avec access token
|
|
@@ -321,7 +391,14 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
321
391
|
else {
|
|
322
392
|
throw new Error("No valid authentication method available");
|
|
323
393
|
}
|
|
324
|
-
}, [
|
|
394
|
+
}, [
|
|
395
|
+
state.status,
|
|
396
|
+
proxyUrl,
|
|
397
|
+
accessToken,
|
|
398
|
+
selectApiKey,
|
|
399
|
+
refreshBasicStatus,
|
|
400
|
+
refreshStorageStatus,
|
|
401
|
+
]);
|
|
325
402
|
/**
|
|
326
403
|
* Déconnexion
|
|
327
404
|
*/
|
|
@@ -380,14 +457,24 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
380
457
|
// Refresh status quand la session devient ready
|
|
381
458
|
useEffect(() => {
|
|
382
459
|
if (state.status === "ready") {
|
|
383
|
-
|
|
460
|
+
// Appel rapide d'abord
|
|
461
|
+
refreshBasicStatus();
|
|
462
|
+
// Storage en arrière-plan après 100ms
|
|
463
|
+
setTimeout(() => refreshStorageStatus(), 100);
|
|
384
464
|
fetchApiKeysWithSession(); // Also fetch API keys list
|
|
385
465
|
}
|
|
386
466
|
else {
|
|
387
467
|
setApiStatus(null);
|
|
468
|
+
setBasicStatus(null);
|
|
469
|
+
setStorageStatus(null);
|
|
388
470
|
setApiKeys([]);
|
|
389
471
|
}
|
|
390
|
-
}, [
|
|
472
|
+
}, [
|
|
473
|
+
state.status,
|
|
474
|
+
refreshBasicStatus,
|
|
475
|
+
refreshStorageStatus,
|
|
476
|
+
fetchApiKeysWithSession,
|
|
477
|
+
]);
|
|
391
478
|
const value = {
|
|
392
479
|
...state,
|
|
393
480
|
login,
|
|
@@ -400,8 +487,13 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
400
487
|
apiKeys,
|
|
401
488
|
accessToken,
|
|
402
489
|
apiStatus,
|
|
403
|
-
|
|
490
|
+
basicStatus,
|
|
491
|
+
storageStatus,
|
|
492
|
+
refreshStatus: refreshBasicStatus, // backward compatibility
|
|
493
|
+
refreshBasicStatus,
|
|
494
|
+
refreshStorageStatus,
|
|
404
495
|
isLoadingStatus,
|
|
496
|
+
isLoadingStorage,
|
|
405
497
|
};
|
|
406
498
|
return _jsx(LBContext.Provider, { value: value, children: children });
|
|
407
499
|
}
|
package/package.json
CHANGED
|
@@ -39,7 +39,10 @@ export function AiStatusButton({
|
|
|
39
39
|
let selectApiKeyWithToken: ((apiKeyId: string) => Promise<void>) | undefined;
|
|
40
40
|
let switchApiKey: ((apiKeyId: string) => Promise<void>) | undefined;
|
|
41
41
|
let lbApiStatus: any = null;
|
|
42
|
+
let lbBasicStatus: any = null;
|
|
43
|
+
let lbStorageStatus: any = null;
|
|
42
44
|
let lbIsLoadingStatus: boolean = false;
|
|
45
|
+
let lbIsLoadingStorage: boolean = false;
|
|
43
46
|
|
|
44
47
|
try {
|
|
45
48
|
const lbContext = useLB();
|
|
@@ -51,7 +54,10 @@ export function AiStatusButton({
|
|
|
51
54
|
selectApiKeyWithToken = lbContext.selectApiKeyWithToken;
|
|
52
55
|
switchApiKey = lbContext.switchApiKey;
|
|
53
56
|
lbApiStatus = lbContext.apiStatus;
|
|
57
|
+
lbBasicStatus = lbContext.basicStatus;
|
|
58
|
+
lbStorageStatus = lbContext.storageStatus;
|
|
54
59
|
lbIsLoadingStatus = lbContext.isLoadingStatus || false;
|
|
60
|
+
lbIsLoadingStorage = lbContext.isLoadingStorage || false;
|
|
55
61
|
} catch {
|
|
56
62
|
// LBProvider n'est pas disponible, ignorer
|
|
57
63
|
lbStatus = undefined;
|
|
@@ -60,7 +66,12 @@ export function AiStatusButton({
|
|
|
60
66
|
}
|
|
61
67
|
|
|
62
68
|
// Utiliser le status du contexte LB si pas de prop status
|
|
63
|
-
|
|
69
|
+
// Combinaison du basic status et storage status pour backward compatibility
|
|
70
|
+
const effectiveStatus = status || {
|
|
71
|
+
...lbApiStatus,
|
|
72
|
+
...lbBasicStatus,
|
|
73
|
+
storage: lbStorageStatus?.storage,
|
|
74
|
+
};
|
|
64
75
|
|
|
65
76
|
// Récupérer refetchProviders depuis AiProvider si disponible
|
|
66
77
|
let refetchProviders: (() => Promise<void>) | undefined;
|
|
@@ -834,11 +845,42 @@ export function AiStatusButton({
|
|
|
834
845
|
<div style={aiStyles.tooltipSubtitle}>Storage</div>
|
|
835
846
|
<div style={aiStyles.tooltipRow}>
|
|
836
847
|
<span style={aiStyles.tooltipLabel}>Total:</span>
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
848
|
+
{lbIsLoadingStorage ? (
|
|
849
|
+
<div
|
|
850
|
+
style={{
|
|
851
|
+
display: "flex",
|
|
852
|
+
alignItems: "center",
|
|
853
|
+
gap: "8px",
|
|
854
|
+
}}
|
|
855
|
+
>
|
|
856
|
+
<div
|
|
857
|
+
style={{
|
|
858
|
+
height: "16px",
|
|
859
|
+
width: "120px",
|
|
860
|
+
background: "rgba(139, 92, 246, 0.1)",
|
|
861
|
+
borderRadius: "4px",
|
|
862
|
+
animation: "pulse 2s ease-in-out infinite",
|
|
863
|
+
}}
|
|
864
|
+
/>
|
|
865
|
+
<div
|
|
866
|
+
style={{
|
|
867
|
+
width: "28px",
|
|
868
|
+
height: "28px",
|
|
869
|
+
borderRadius: "50%",
|
|
870
|
+
background: "rgba(139, 92, 246, 0.1)",
|
|
871
|
+
animation: "pulse 2s ease-in-out infinite",
|
|
872
|
+
}}
|
|
873
|
+
/>
|
|
874
|
+
</div>
|
|
875
|
+
) : (
|
|
876
|
+
<>
|
|
877
|
+
<span style={aiStyles.tooltipValue}>
|
|
878
|
+
{formatStorage(storageUsed)} /{" "}
|
|
879
|
+
{formatStorage(storageAllocated)}
|
|
880
|
+
</span>
|
|
881
|
+
{renderUsageCircle(storagePercentage)}
|
|
882
|
+
</>
|
|
883
|
+
)}
|
|
842
884
|
</div>
|
|
843
885
|
</div>
|
|
844
886
|
|
|
@@ -32,7 +32,18 @@ export function LBConnectButton({
|
|
|
32
32
|
const handleClick = () => {
|
|
33
33
|
if (status === "ready" && user) {
|
|
34
34
|
// Déjà connecté, proposer de se déconnecter
|
|
35
|
-
logout()
|
|
35
|
+
logout().then(() => {
|
|
36
|
+
// Redirection propre après logout
|
|
37
|
+
if (typeof window !== "undefined") {
|
|
38
|
+
// Garder la langue actuelle de l'URL
|
|
39
|
+
const currentPath = window.location.pathname;
|
|
40
|
+
const langMatch = currentPath.match(/^\/([a-z]{2})\//);
|
|
41
|
+
const currentLang = langMatch ? langMatch[1] : "en";
|
|
42
|
+
|
|
43
|
+
// Rediriger vers la page d'accueil dans la langue actuelle
|
|
44
|
+
window.location.href = `/${currentLang}`;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
36
47
|
} else {
|
|
37
48
|
// Pas connecté, ouvrir la modal
|
|
38
49
|
setShowModal(true);
|
|
@@ -63,10 +63,20 @@ interface LBContextValue extends LBAuthState {
|
|
|
63
63
|
accessToken?: string;
|
|
64
64
|
/** Status API (balance, storage, API key info) */
|
|
65
65
|
apiStatus: AiStatus | null;
|
|
66
|
-
/**
|
|
66
|
+
/** Status basique (rapide) - balance, API key info sans storage */
|
|
67
|
+
basicStatus: any;
|
|
68
|
+
/** Status storage (lent) avec cache */
|
|
69
|
+
storageStatus: any;
|
|
70
|
+
/** Fonction pour rafraîchir le status rapide */
|
|
71
|
+
refreshBasicStatus: () => Promise<void>;
|
|
72
|
+
/** Fonction pour rafraîchir le storage (avec cache optionnel) */
|
|
73
|
+
refreshStorageStatus: (force?: boolean) => Promise<void>;
|
|
74
|
+
/** Fonction pour rafraîchir le status (backward compatibility) */
|
|
67
75
|
refreshStatus: () => Promise<void>;
|
|
68
|
-
/** Indique si le status est en cours de chargement */
|
|
76
|
+
/** Indique si le status basique est en cours de chargement */
|
|
69
77
|
isLoadingStatus: boolean;
|
|
78
|
+
/** Indique si le storage est en cours de chargement */
|
|
79
|
+
isLoadingStorage: boolean;
|
|
70
80
|
}
|
|
71
81
|
|
|
72
82
|
const LBContext = createContext<LBContextValue | undefined>(undefined);
|
|
@@ -84,7 +94,11 @@ export function LBProvider({
|
|
|
84
94
|
const [apiKeys, setApiKeys] = useState<LBApiKey[]>([]);
|
|
85
95
|
const [accessToken, setAccessToken] = useState<string>();
|
|
86
96
|
const [apiStatus, setApiStatus] = useState<AiStatus | null>(null);
|
|
97
|
+
const [basicStatus, setBasicStatus] = useState<any>(null);
|
|
98
|
+
const [storageStatus, setStorageStatus] = useState<any>(null);
|
|
87
99
|
const [isLoadingStatus, setIsLoadingStatus] = useState(false);
|
|
100
|
+
const [isLoadingStorage, setIsLoadingStorage] = useState(false);
|
|
101
|
+
const [storageLastFetch, setStorageLastFetch] = useState<number>(0);
|
|
88
102
|
|
|
89
103
|
/**
|
|
90
104
|
* Vérifie si une session existe au chargement
|
|
@@ -393,34 +407,112 @@ export function LBProvider({
|
|
|
393
407
|
);
|
|
394
408
|
|
|
395
409
|
/**
|
|
396
|
-
* Récupère le status API (balance,
|
|
410
|
+
* Récupère le status API basique (balance, API key info) - RAPIDE
|
|
397
411
|
*/
|
|
398
|
-
const
|
|
412
|
+
const refreshBasicStatus = useCallback(async (): Promise<void> => {
|
|
399
413
|
if (state.status !== "ready") {
|
|
400
|
-
|
|
414
|
+
setBasicStatus(null);
|
|
401
415
|
setIsLoadingStatus(false);
|
|
402
416
|
return;
|
|
403
417
|
}
|
|
404
418
|
|
|
405
419
|
setIsLoadingStatus(true);
|
|
406
420
|
try {
|
|
407
|
-
const response = await fetch(`${proxyUrl}/auth/status`, {
|
|
421
|
+
const response = await fetch(`${proxyUrl}/auth/status?fast=true`, {
|
|
408
422
|
credentials: "include",
|
|
409
423
|
});
|
|
410
424
|
|
|
411
425
|
if (response.ok) {
|
|
412
426
|
const data = await response.json();
|
|
413
|
-
|
|
427
|
+
setBasicStatus(data);
|
|
428
|
+
|
|
429
|
+
// Combiner avec le storage existant si disponible
|
|
430
|
+
const combinedStatus = {
|
|
431
|
+
...data,
|
|
432
|
+
storage: storageStatus?.storage || data.storage,
|
|
433
|
+
};
|
|
434
|
+
setApiStatus(combinedStatus);
|
|
414
435
|
} else {
|
|
415
|
-
|
|
436
|
+
setBasicStatus(null);
|
|
416
437
|
}
|
|
417
438
|
} catch (error) {
|
|
418
|
-
console.error("[LBProvider] Failed to fetch status:", error);
|
|
419
|
-
|
|
439
|
+
console.error("[LBProvider] Failed to fetch basic status:", error);
|
|
440
|
+
setBasicStatus(null);
|
|
420
441
|
} finally {
|
|
421
442
|
setIsLoadingStatus(false);
|
|
422
443
|
}
|
|
423
|
-
}, [proxyUrl, state.status]);
|
|
444
|
+
}, [proxyUrl, state.status, storageStatus]);
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Récupère le storage - LENT avec cache (5 minutes)
|
|
448
|
+
*/
|
|
449
|
+
const refreshStorageStatus = useCallback(
|
|
450
|
+
async (force = false): Promise<void> => {
|
|
451
|
+
if (state.status !== "ready") {
|
|
452
|
+
setStorageStatus(null);
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Cache de 5 minutes sauf si force=true
|
|
457
|
+
const now = Date.now();
|
|
458
|
+
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
|
|
459
|
+
if (
|
|
460
|
+
!force &&
|
|
461
|
+
storageLastFetch &&
|
|
462
|
+
now - storageLastFetch < CACHE_DURATION
|
|
463
|
+
) {
|
|
464
|
+
console.log("[LBProvider] Storage cache still valid, skipping fetch");
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
setIsLoadingStorage(true);
|
|
469
|
+
try {
|
|
470
|
+
// Essayer l'endpoint spécialisé storage d'abord
|
|
471
|
+
let response = await fetch(`${proxyUrl}/auth/status/storage`, {
|
|
472
|
+
credentials: "include",
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
// Si 404, faire un fallback vers l'endpoint normal (backward compatibility)
|
|
476
|
+
if (!response.ok && response.status === 404) {
|
|
477
|
+
console.log("[LBProvider] Storage endpoint not available, using fallback");
|
|
478
|
+
response = await fetch(`${proxyUrl}/auth/status`, {
|
|
479
|
+
credentials: "include",
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (response.ok) {
|
|
484
|
+
const data = await response.json();
|
|
485
|
+
|
|
486
|
+
// Si c'est la réponse complète (fallback), extraire juste le storage
|
|
487
|
+
const storageData = data.storage ? { storage: data.storage } : data;
|
|
488
|
+
|
|
489
|
+
setStorageStatus(storageData);
|
|
490
|
+
setStorageLastFetch(now);
|
|
491
|
+
|
|
492
|
+
// Combiner avec le basic status
|
|
493
|
+
const combinedStatus = {
|
|
494
|
+
...basicStatus,
|
|
495
|
+
storage: storageData.storage,
|
|
496
|
+
};
|
|
497
|
+
setApiStatus(combinedStatus);
|
|
498
|
+
} else {
|
|
499
|
+
console.warn(
|
|
500
|
+
"[LBProvider] Failed to fetch storage status:",
|
|
501
|
+
response.status
|
|
502
|
+
);
|
|
503
|
+
// Arrêter les tentatives répétées si échec persistant
|
|
504
|
+
setStorageLastFetch(now); // Marquer comme essayé pour éviter la boucle
|
|
505
|
+
}
|
|
506
|
+
} catch (error) {
|
|
507
|
+
console.error("[LBProvider] Failed to fetch storage status:", error);
|
|
508
|
+
// Arrêter les tentatives répétées si erreur persistante
|
|
509
|
+
setStorageLastFetch(now); // Marquer comme essayé pour éviter la boucle
|
|
510
|
+
} finally {
|
|
511
|
+
setIsLoadingStorage(false);
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
[proxyUrl, state.status, basicStatus, storageLastFetch]
|
|
515
|
+
);
|
|
424
516
|
|
|
425
517
|
/**
|
|
426
518
|
* Sélectionne une clé API avec le token déjà stocké (après login)
|
|
@@ -458,7 +550,9 @@ export function LBProvider({
|
|
|
458
550
|
}
|
|
459
551
|
|
|
460
552
|
// Refresh le status après le changement
|
|
461
|
-
await
|
|
553
|
+
await refreshBasicStatus();
|
|
554
|
+
// Refresh storage en arrière-plan
|
|
555
|
+
setTimeout(() => refreshStorageStatus(), 100);
|
|
462
556
|
} else if (accessToken) {
|
|
463
557
|
// Utiliser la méthode avec access token
|
|
464
558
|
await selectApiKey(accessToken, apiKeyId);
|
|
@@ -466,7 +560,14 @@ export function LBProvider({
|
|
|
466
560
|
throw new Error("No valid authentication method available");
|
|
467
561
|
}
|
|
468
562
|
},
|
|
469
|
-
[
|
|
563
|
+
[
|
|
564
|
+
state.status,
|
|
565
|
+
proxyUrl,
|
|
566
|
+
accessToken,
|
|
567
|
+
selectApiKey,
|
|
568
|
+
refreshBasicStatus,
|
|
569
|
+
refreshStorageStatus,
|
|
570
|
+
]
|
|
470
571
|
);
|
|
471
572
|
|
|
472
573
|
/**
|
|
@@ -528,13 +629,23 @@ export function LBProvider({
|
|
|
528
629
|
// Refresh status quand la session devient ready
|
|
529
630
|
useEffect(() => {
|
|
530
631
|
if (state.status === "ready") {
|
|
531
|
-
|
|
632
|
+
// Appel rapide d'abord
|
|
633
|
+
refreshBasicStatus();
|
|
634
|
+
// Storage en arrière-plan après 100ms
|
|
635
|
+
setTimeout(() => refreshStorageStatus(), 100);
|
|
532
636
|
fetchApiKeysWithSession(); // Also fetch API keys list
|
|
533
637
|
} else {
|
|
534
638
|
setApiStatus(null);
|
|
639
|
+
setBasicStatus(null);
|
|
640
|
+
setStorageStatus(null);
|
|
535
641
|
setApiKeys([]);
|
|
536
642
|
}
|
|
537
|
-
}, [
|
|
643
|
+
}, [
|
|
644
|
+
state.status,
|
|
645
|
+
refreshBasicStatus,
|
|
646
|
+
refreshStorageStatus,
|
|
647
|
+
fetchApiKeysWithSession,
|
|
648
|
+
]);
|
|
538
649
|
|
|
539
650
|
const value: LBContextValue = {
|
|
540
651
|
...state,
|
|
@@ -548,8 +659,13 @@ export function LBProvider({
|
|
|
548
659
|
apiKeys,
|
|
549
660
|
accessToken,
|
|
550
661
|
apiStatus,
|
|
551
|
-
|
|
662
|
+
basicStatus,
|
|
663
|
+
storageStatus,
|
|
664
|
+
refreshStatus: refreshBasicStatus, // backward compatibility
|
|
665
|
+
refreshBasicStatus,
|
|
666
|
+
refreshStorageStatus,
|
|
552
667
|
isLoadingStatus,
|
|
668
|
+
isLoadingStorage,
|
|
553
669
|
};
|
|
554
670
|
|
|
555
671
|
return <LBContext.Provider value={value}>{children}</LBContext.Provider>;
|