@lastbrain/ai-ui-react 1.0.76 → 1.0.77
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/AiContextButton.d.ts.map +1 -1
- package/dist/components/AiContextButton.js +17 -1
- package/dist/components/AiImageButton.d.ts.map +1 -1
- package/dist/components/AiImageButton.js +17 -1
- package/dist/components/AiInput.d.ts.map +1 -1
- package/dist/components/AiInput.js +17 -1
- package/dist/components/AiSelect.d.ts.map +1 -1
- package/dist/components/AiSelect.js +17 -1
- package/dist/components/AiStatusButton.d.ts.map +1 -1
- package/dist/components/AiStatusButton.js +16 -2
- package/dist/components/AiTextarea.d.ts.map +1 -1
- package/dist/components/AiTextarea.js +14 -5
- package/dist/context/LBAuthProvider.d.ts +2 -0
- package/dist/context/LBAuthProvider.d.ts.map +1 -1
- package/dist/context/LBAuthProvider.js +31 -5
- package/dist/hooks/useAiStatus.d.ts.map +1 -1
- package/dist/hooks/useAiStatus.js +22 -7
- package/package.json +1 -1
- package/src/components/AiContextButton.tsx +19 -1
- package/src/components/AiImageButton.tsx +19 -1
- package/src/components/AiInput.tsx +19 -1
- package/src/components/AiSelect.tsx +19 -1
- package/src/components/AiStatusButton.tsx +24 -2
- package/src/components/AiTextarea.tsx +15 -7
- package/src/context/LBAuthProvider.tsx +34 -4
- package/src/hooks/useAiStatus.ts +22 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiContextButton.d.ts","sourceRoot":"","sources":["../../src/components/AiContextButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAY5D,KAAK,WAAW,GACZ,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,OAAO,EAAE,GACT;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,CAAC;AAE3B,MAAM,WAAW,oBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvE,WAAW,EAAE,WAAW,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,CACT,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC7C,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,IAAW,EACX,MAAe,EACf,OAAmB,EACnB,OAAO,EAAE,QAAQ,EACjB,GAAG,WAAW,EACf,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"AiContextButton.d.ts","sourceRoot":"","sources":["../../src/components/AiContextButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAY5D,KAAK,WAAW,GACZ,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,OAAO,EAAE,GACT;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,CAAC;AAE3B,MAAM,WAAW,oBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvE,WAAW,EAAE,WAAW,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,CACT,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC7C,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,IAAW,EACX,MAAe,EACf,OAAmB,EACnB,OAAO,EAAE,QAAQ,EACjB,GAAG,WAAW,EACf,EAAE,oBAAoB,2CA+TtB"}
|
|
@@ -22,12 +22,23 @@ export function AiContextButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId,
|
|
|
22
22
|
const { showErrorToast, errorData, errorKey, clearError } = useErrorToast();
|
|
23
23
|
const resolvedContextDescription = contextDescription || t("ai.context.description", "Data to analyze");
|
|
24
24
|
let lbStatus;
|
|
25
|
+
let lbHasSession = false;
|
|
26
|
+
let lbHasSelectedKey = false;
|
|
27
|
+
let lbHasSelectedApiKeyCookie = false;
|
|
28
|
+
let hasLBProvider = false;
|
|
25
29
|
try {
|
|
26
30
|
const lbContext = useLB();
|
|
27
31
|
lbStatus = lbContext.status;
|
|
32
|
+
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
33
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
34
|
+
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
35
|
+
hasLBProvider = true;
|
|
28
36
|
}
|
|
29
37
|
catch {
|
|
30
38
|
lbStatus = undefined;
|
|
39
|
+
lbHasSession = false;
|
|
40
|
+
lbHasSelectedKey = false;
|
|
41
|
+
hasLBProvider = false;
|
|
31
42
|
}
|
|
32
43
|
const aiContext = useAiContext();
|
|
33
44
|
const baseUrl = propBaseUrl ?? aiContext.baseUrl;
|
|
@@ -36,7 +47,12 @@ export function AiContextButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId,
|
|
|
36
47
|
baseUrl,
|
|
37
48
|
apiKeyId,
|
|
38
49
|
});
|
|
39
|
-
const
|
|
50
|
+
const needsApiKeySelection = hasLBProvider &&
|
|
51
|
+
lbStatus === "ready" &&
|
|
52
|
+
lbHasSession &&
|
|
53
|
+
(!lbHasSelectedKey || !lbHasSelectedApiKeyCookie);
|
|
54
|
+
const isAuthReady = !needsApiKeySelection &&
|
|
55
|
+
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
40
56
|
const handleOpenPanel = () => {
|
|
41
57
|
if (!isAuthReady) {
|
|
42
58
|
setShowAuthModal(true);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiImageButton.d.ts","sourceRoot":"","sources":["../../src/components/AiImageButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAS5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAY5D,MAAM,WAAW,kBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvE,OAAO,CAAC,EAAE,CACR,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC7C,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,aAAoB,EACpB,WAAW,EACX,YAAY,EACZ,aAAa,EACb,IAAW,EACX,MAAe,EACf,OAAmB,EACnB,GAAG,WAAW,EACf,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"AiImageButton.d.ts","sourceRoot":"","sources":["../../src/components/AiImageButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAS5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAY5D,MAAM,WAAW,kBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvE,OAAO,CAAC,EAAE,CACR,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC7C,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,aAAoB,EACpB,WAAW,EACX,YAAY,EACZ,aAAa,EACb,IAAW,EACX,MAAe,EACf,OAAmB,EACnB,GAAG,WAAW,EACf,EAAE,kBAAkB,2CAsSpB"}
|
|
@@ -22,13 +22,24 @@ export function AiImageButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, ui
|
|
|
22
22
|
const { showErrorToast, errorData, errorKey, clearError } = useErrorToast();
|
|
23
23
|
// Rendre l'authentification optionnelle
|
|
24
24
|
let lbStatus;
|
|
25
|
+
let lbHasSession = false;
|
|
26
|
+
let lbHasSelectedKey = false;
|
|
27
|
+
let lbHasSelectedApiKeyCookie = false;
|
|
28
|
+
let hasLBProvider = false;
|
|
25
29
|
try {
|
|
26
30
|
const lbContext = useLB();
|
|
27
31
|
lbStatus = lbContext.status;
|
|
32
|
+
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
33
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
34
|
+
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
35
|
+
hasLBProvider = true;
|
|
28
36
|
}
|
|
29
37
|
catch {
|
|
30
38
|
// LBProvider n'est pas disponible, ignorer
|
|
31
39
|
lbStatus = undefined;
|
|
40
|
+
lbHasSession = false;
|
|
41
|
+
lbHasSelectedKey = false;
|
|
42
|
+
hasLBProvider = false;
|
|
32
43
|
}
|
|
33
44
|
// Récupérer le contexte AiProvider avec fallback sur les props
|
|
34
45
|
const aiContext = useAiContext();
|
|
@@ -36,7 +47,12 @@ export function AiImageButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, ui
|
|
|
36
47
|
const apiKeyId = propApiKeyId ?? aiContext.apiKeyId;
|
|
37
48
|
const { generateImage, loading } = useAiCallImage({ baseUrl, apiKeyId });
|
|
38
49
|
const { formatted: loadingElapsed } = useLoadingTimer(loading);
|
|
39
|
-
const
|
|
50
|
+
const needsApiKeySelection = hasLBProvider &&
|
|
51
|
+
lbStatus === "ready" &&
|
|
52
|
+
lbHasSession &&
|
|
53
|
+
(!lbHasSelectedKey || !lbHasSelectedApiKeyCookie);
|
|
54
|
+
const isAuthReady = !needsApiKeySelection &&
|
|
55
|
+
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
40
56
|
const handleOpenPanel = () => {
|
|
41
57
|
if (!isAuthReady) {
|
|
42
58
|
setShowAuthModal(true);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiInput.d.ts","sourceRoot":"","sources":["../../src/components/AiInput.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAc,EAAoB,KAAK,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAE1E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAY9D,MAAM,WAAW,YACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACjE,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,wBAAgB,OAAO,CAAC,EACtB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,IAAW,EACX,MAAe,EACf,OAAO,EACP,KAAK,EACL,MAAM,EACN,QAAQ,EAAE,SAAiB,EAC3B,qBAA4B,EAC5B,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,UAAU,EACd,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"AiInput.d.ts","sourceRoot":"","sources":["../../src/components/AiInput.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAc,EAAoB,KAAK,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAE1E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAY9D,MAAM,WAAW,YACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACjE,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,wBAAgB,OAAO,CAAC,EACtB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,IAAW,EACX,MAAe,EACf,OAAO,EACP,KAAK,EACL,MAAM,EACN,QAAQ,EAAE,SAAiB,EAC3B,qBAA4B,EAC5B,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,UAAU,EACd,EAAE,YAAY,2CAgPd"}
|
|
@@ -22,13 +22,24 @@ export function AiInput({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode =
|
|
|
22
22
|
const { showUsageToast: _showUsageToast, toastData, toastKey, clearToast, } = useUsageToast();
|
|
23
23
|
// Rendre l'authentification optionnelle
|
|
24
24
|
let lbStatus;
|
|
25
|
+
let lbHasSession = false;
|
|
26
|
+
let lbHasSelectedKey = false;
|
|
27
|
+
let lbHasSelectedApiKeyCookie = false;
|
|
28
|
+
let hasLBProvider = false;
|
|
25
29
|
try {
|
|
26
30
|
const lbContext = useLB();
|
|
27
31
|
lbStatus = lbContext.status;
|
|
32
|
+
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
33
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
34
|
+
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
35
|
+
hasLBProvider = true;
|
|
28
36
|
}
|
|
29
37
|
catch {
|
|
30
38
|
// LBProvider n'est pas disponible, ignorer
|
|
31
39
|
lbStatus = undefined;
|
|
40
|
+
lbHasSession = false;
|
|
41
|
+
lbHasSelectedKey = false;
|
|
42
|
+
hasLBProvider = false;
|
|
32
43
|
}
|
|
33
44
|
let ctxBaseUrl;
|
|
34
45
|
let ctxApiKeyId;
|
|
@@ -51,7 +62,12 @@ export function AiInput({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode =
|
|
|
51
62
|
const { generateText, loading } = useAiCallText({ baseUrl, apiKeyId });
|
|
52
63
|
const { formatted: loadingElapsed } = useLoadingTimer(loading);
|
|
53
64
|
const hasConfiguration = Boolean(model && prompt);
|
|
54
|
-
const
|
|
65
|
+
const needsApiKeySelection = hasLBProvider &&
|
|
66
|
+
lbStatus === "ready" &&
|
|
67
|
+
lbHasSession &&
|
|
68
|
+
(!lbHasSelectedKey || !lbHasSelectedApiKeyCookie);
|
|
69
|
+
const isAuthReady = !needsApiKeySelection &&
|
|
70
|
+
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
55
71
|
const shouldShowSparkles = isAuthReady && !disabled;
|
|
56
72
|
const handleOpenPanel = () => {
|
|
57
73
|
if (!isAuthReady) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiSelect.d.ts","sourceRoot":"","sources":["../../src/components/AiSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAW9D,MAAM,WAAW,aACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACnE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,IAAW,EACX,MAAe,EACf,OAAO,EACP,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,GAAG,WAAW,EACf,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"AiSelect.d.ts","sourceRoot":"","sources":["../../src/components/AiSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAW9D,MAAM,WAAW,aACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACnE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,IAAW,EACX,MAAe,EACf,OAAO,EACP,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,GAAG,WAAW,EACf,EAAE,aAAa,2CAkKf"}
|
|
@@ -19,13 +19,24 @@ export function AiSelect({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode
|
|
|
19
19
|
const { showUsageToast, toastData, toastKey, clearToast } = useUsageToast();
|
|
20
20
|
// Rendre l'authentification optionnelle
|
|
21
21
|
let lbStatus;
|
|
22
|
+
let lbHasSession = false;
|
|
23
|
+
let lbHasSelectedKey = false;
|
|
24
|
+
let lbHasSelectedApiKeyCookie = false;
|
|
25
|
+
let hasLBProvider = false;
|
|
22
26
|
try {
|
|
23
27
|
const lbContext = useLB();
|
|
24
28
|
lbStatus = lbContext.status;
|
|
29
|
+
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
30
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
31
|
+
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
32
|
+
hasLBProvider = true;
|
|
25
33
|
}
|
|
26
34
|
catch {
|
|
27
35
|
// LBProvider n'est pas disponible, ignorer
|
|
28
36
|
lbStatus = undefined;
|
|
37
|
+
lbHasSession = false;
|
|
38
|
+
lbHasSelectedKey = false;
|
|
39
|
+
hasLBProvider = false;
|
|
29
40
|
}
|
|
30
41
|
let ctxBaseUrl;
|
|
31
42
|
let ctxApiKeyId;
|
|
@@ -46,7 +57,12 @@ export function AiSelect({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode
|
|
|
46
57
|
modelType: "text-or-language",
|
|
47
58
|
});
|
|
48
59
|
const { generateText, loading } = useAiCallText({ baseUrl, apiKeyId });
|
|
49
|
-
const
|
|
60
|
+
const needsApiKeySelection = hasLBProvider &&
|
|
61
|
+
lbStatus === "ready" &&
|
|
62
|
+
lbHasSession &&
|
|
63
|
+
(!lbHasSelectedKey || !lbHasSelectedApiKeyCookie);
|
|
64
|
+
const isAuthReady = !needsApiKeySelection &&
|
|
65
|
+
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
50
66
|
const shouldShowSparkles = isAuthReady && !disabled;
|
|
51
67
|
const handleOpenPanel = () => {
|
|
52
68
|
if (!isAuthReady) {
|
|
@@ -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;
|
|
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;AA8B9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGjD,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,2CA6jBrB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import "../styles/register";
|
|
4
|
-
import { useLayoutEffect, useMemo, useRef, useState, useContext } from "react";
|
|
4
|
+
import { useLayoutEffect, useMemo, useRef, useState, useContext, useEffect, } from "react";
|
|
5
5
|
import { createPortal } from "react-dom";
|
|
6
6
|
import { ArrowRightLeft, BarChart3, FileText, Folder, History, Loader2, LogOut, Settings, Shield, } from "lucide-react";
|
|
7
7
|
import { LBContext, } from "../context/LBAuthProvider";
|
|
@@ -79,6 +79,8 @@ export function AiStatusButton({ status, loading = false, className = "", size =
|
|
|
79
79
|
let lbSelectedKey = null;
|
|
80
80
|
let lbRefreshBasicStatus;
|
|
81
81
|
let lbRefreshStorageStatus;
|
|
82
|
+
let lbSessionToken;
|
|
83
|
+
let lbHasSelectedApiKeyCookie = false;
|
|
82
84
|
const lbContext = useContext(LBContext);
|
|
83
85
|
if (lbContext) {
|
|
84
86
|
lbStatus = lbContext.status;
|
|
@@ -94,6 +96,8 @@ export function AiStatusButton({ status, loading = false, className = "", size =
|
|
|
94
96
|
lbSelectedKey = lbContext.selectedKey || null;
|
|
95
97
|
lbRefreshBasicStatus = lbContext.refreshBasicStatus;
|
|
96
98
|
lbRefreshStorageStatus = lbContext.refreshStorageStatus;
|
|
99
|
+
lbSessionToken = lbContext.session?.sessionToken;
|
|
100
|
+
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
97
101
|
}
|
|
98
102
|
else {
|
|
99
103
|
lbStatus = undefined;
|
|
@@ -128,9 +132,19 @@ export function AiStatusButton({ status, loading = false, className = "", size =
|
|
|
128
132
|
typeof effectiveStatus.authType === "string"
|
|
129
133
|
? effectiveStatus.authType
|
|
130
134
|
: undefined;
|
|
131
|
-
const
|
|
135
|
+
const hasLbSession = Boolean(lbSessionToken);
|
|
136
|
+
const requiresApiKeySelection = lbStatus === "ready" &&
|
|
137
|
+
hasLbSession &&
|
|
138
|
+
(!lbHasSelectedApiKeyCookie || !hasApiKeySelected) &&
|
|
139
|
+
apiKeys.length > 0;
|
|
132
140
|
const isApiKeyAuthMode = authTypeValue === "api_key";
|
|
133
141
|
const [tooltipStyle, setTooltipStyle] = useState({});
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
if (requiresApiKeySelection) {
|
|
144
|
+
setShowApiKeySelector(true);
|
|
145
|
+
setShowTooltip(false);
|
|
146
|
+
}
|
|
147
|
+
}, [requiresApiKeySelection]);
|
|
134
148
|
useLayoutEffect(() => {
|
|
135
149
|
if (!showTooltip || !buttonRef.current || !canPortal) {
|
|
136
150
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiTextarea.d.ts","sourceRoot":"","sources":["../../src/components/AiTextarea.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAc,EAIZ,KAAK,sBAAsB,EAC5B,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAY9D,MAAM,WAAW,eACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,sBAAsB,CAAC,mBAAmB,CAAC,EAAE,SAAS,CAAC;IAC9D,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,IAAW,EACX,MAAa,EACb,iBAAiB,EACjB,OAAO,EACP,KAAK,EACL,MAAM,EACN,QAAQ,EAAE,SAAiB,EAC3B,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,aAAa,EACjB,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"AiTextarea.d.ts","sourceRoot":"","sources":["../../src/components/AiTextarea.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAc,EAIZ,KAAK,sBAAsB,EAC5B,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAY9D,MAAM,WAAW,eACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,sBAAsB,CAAC,mBAAmB,CAAC,EAAE,SAAS,CAAC;IAC9D,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,IAAW,EACX,MAAa,EACb,iBAAiB,EACjB,OAAO,EACP,KAAK,EACL,MAAM,EACN,QAAQ,EAAE,SAAiB,EAC3B,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,aAAa,EACjB,EAAE,eAAe,2CAqQjB"}
|
|
@@ -24,10 +24,16 @@ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMod
|
|
|
24
24
|
const { showUsageToast, toastData, toastKey, clearToast } = useUsageToast();
|
|
25
25
|
// Rendre l'authentification optionnelle
|
|
26
26
|
let lbStatus;
|
|
27
|
+
let lbHasSession = false;
|
|
28
|
+
let lbHasSelectedKey = false;
|
|
29
|
+
let lbHasSelectedApiKeyCookie = false;
|
|
27
30
|
let hasLBProvider = false;
|
|
28
31
|
try {
|
|
29
32
|
const lbContext = useLB();
|
|
30
33
|
lbStatus = lbContext.status;
|
|
34
|
+
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
35
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
36
|
+
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
31
37
|
hasLBProvider = true;
|
|
32
38
|
}
|
|
33
39
|
catch {
|
|
@@ -48,8 +54,10 @@ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMod
|
|
|
48
54
|
}
|
|
49
55
|
const baseUrl = propBaseUrl ?? ctxBaseUrl;
|
|
50
56
|
const apiKeyId = propApiKeyId ?? ctxApiKeyId;
|
|
51
|
-
const
|
|
52
|
-
|
|
57
|
+
const needsApiKeySelection = hasLBProvider &&
|
|
58
|
+
lbStatus === "ready" &&
|
|
59
|
+
lbHasSession &&
|
|
60
|
+
(!lbHasSelectedKey || !lbHasSelectedApiKeyCookie);
|
|
53
61
|
const { models: _models } = useAiModels({
|
|
54
62
|
baseUrl,
|
|
55
63
|
apiKeyId,
|
|
@@ -58,9 +66,10 @@ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMod
|
|
|
58
66
|
const { generateText, loading } = useAiCallText({ baseUrl, apiKeyId });
|
|
59
67
|
const { formatted: loadingElapsed } = useLoadingTimer(loading);
|
|
60
68
|
const hasConfiguration = Boolean(model && prompt);
|
|
61
|
-
const isAuthReady =
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
const isAuthReady = hasLBProvider
|
|
70
|
+
? !needsApiKeySelection &&
|
|
71
|
+
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY))
|
|
72
|
+
: Boolean(process.env.LB_API_KEY);
|
|
64
73
|
const shouldShowSparkles = isAuthReady && !disabled;
|
|
65
74
|
const handleOpenPanel = () => {
|
|
66
75
|
if (!isAuthReady) {
|
|
@@ -88,6 +88,8 @@ interface LBContextValue extends LBAuthState {
|
|
|
88
88
|
isLoadingStatus: boolean;
|
|
89
89
|
/** Indique si le storage est en cours de chargement */
|
|
90
90
|
isLoadingStorage: boolean;
|
|
91
|
+
/** True si le cookie api_key_selected est présent */
|
|
92
|
+
hasSelectedApiKeyCookie: boolean;
|
|
91
93
|
}
|
|
92
94
|
declare const LBContext: import("react").Context<LBContextValue | undefined>;
|
|
93
95
|
export { LBContext };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LBAuthProvider.d.ts","sourceRoot":"","sources":["../../src/context/LBAuthProvider.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"LBAuthProvider.d.ts","sourceRoot":"","sources":["../../src/context/LBAuthProvider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
4
4
|
* Provider d'authentification LastBrain
|
|
5
5
|
* Gère l'état de connexion, la session et les appels IA
|
|
6
6
|
*/
|
|
7
|
-
import { createContext, useContext, useEffect, useCallback, useMemo, useState, } from "react";
|
|
7
|
+
import { createContext, useContext, useEffect, useCallback, useMemo, useRef, useState, } from "react";
|
|
8
8
|
import { createLBClient } from "@lastbrain/ai-ui-core";
|
|
9
9
|
import { I18nProvider } from "./I18nContext";
|
|
10
10
|
const LBContext = createContext(undefined);
|
|
@@ -22,6 +22,17 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
22
22
|
const [isLoadingStatus, setIsLoadingStatus] = useState(false);
|
|
23
23
|
const [isLoadingStorage, setIsLoadingStorage] = useState(false);
|
|
24
24
|
const [storageLastFetch, setStorageLastFetch] = useState(0);
|
|
25
|
+
const [hasSelectedApiKeyCookie, setHasSelectedApiKeyCookie] = useState(false);
|
|
26
|
+
const previousStatusRef = useRef("loading");
|
|
27
|
+
const syncSelectedApiKeyCookie = useCallback(() => {
|
|
28
|
+
if (typeof document === "undefined")
|
|
29
|
+
return;
|
|
30
|
+
const hasCookie = document.cookie
|
|
31
|
+
.split(";")
|
|
32
|
+
.map((part) => part.trim())
|
|
33
|
+
.some((part) => part.startsWith("api_key_selected=") && part.length > 17);
|
|
34
|
+
setHasSelectedApiKeyCookie(hasCookie);
|
|
35
|
+
}, []);
|
|
25
36
|
const lbClient = useMemo(() => createLBClient({
|
|
26
37
|
baseUrl: proxyUrl,
|
|
27
38
|
mode: process.env.LB_API_KEY ? "env-key" : "auto",
|
|
@@ -97,6 +108,13 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
97
108
|
useEffect(() => {
|
|
98
109
|
checkSession();
|
|
99
110
|
}, [checkSession]);
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
syncSelectedApiKeyCookie();
|
|
113
|
+
if (typeof window === "undefined")
|
|
114
|
+
return;
|
|
115
|
+
const interval = window.setInterval(syncSelectedApiKeyCookie, 1000);
|
|
116
|
+
return () => window.clearInterval(interval);
|
|
117
|
+
}, [syncSelectedApiKeyCookie]);
|
|
100
118
|
/**
|
|
101
119
|
* Récupère les clés API de l'utilisateur
|
|
102
120
|
*/
|
|
@@ -134,6 +152,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
134
152
|
});
|
|
135
153
|
setAccessToken(undefined); // Nettoyer l'access token temporaire
|
|
136
154
|
setApiKeys([]); // Nettoyer les clés API temporaires
|
|
155
|
+
setTimeout(() => syncSelectedApiKeyCookie(), 100);
|
|
137
156
|
onStatusChange?.("ready");
|
|
138
157
|
onAuthChange?.(); // Refresh provider after signin
|
|
139
158
|
}
|
|
@@ -145,7 +164,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
145
164
|
});
|
|
146
165
|
throw error;
|
|
147
166
|
}
|
|
148
|
-
}, [lbClient, state.user,
|
|
167
|
+
}, [lbClient, onAuthChange, onStatusChange, state.user, syncSelectedApiKeyCookie]);
|
|
149
168
|
/**
|
|
150
169
|
* Connexion utilisateur (étape 1 : login)
|
|
151
170
|
* Retourne le token et les clés API sans créer de session
|
|
@@ -361,6 +380,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
361
380
|
}
|
|
362
381
|
await refreshBasicStatus();
|
|
363
382
|
setTimeout(() => refreshStorageStatus(), 100);
|
|
383
|
+
setTimeout(() => syncSelectedApiKeyCookie(), 100);
|
|
364
384
|
}
|
|
365
385
|
else {
|
|
366
386
|
throw new Error("No valid authentication method available");
|
|
@@ -373,6 +393,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
373
393
|
lbClient,
|
|
374
394
|
refreshBasicStatus,
|
|
375
395
|
refreshStorageStatus,
|
|
396
|
+
syncSelectedApiKeyCookie,
|
|
376
397
|
]);
|
|
377
398
|
/**
|
|
378
399
|
* Déconnexion
|
|
@@ -393,6 +414,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
393
414
|
setBasicStatus(null);
|
|
394
415
|
setStorageStatus(null);
|
|
395
416
|
setStorageLastFetch(0);
|
|
417
|
+
setHasSelectedApiKeyCookie(false);
|
|
396
418
|
onStatusChange?.("needs_auth");
|
|
397
419
|
onAuthChange?.(); // Refresh provider after logout
|
|
398
420
|
}
|
|
@@ -420,16 +442,19 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
420
442
|
setApiKeys([]);
|
|
421
443
|
}
|
|
422
444
|
}, [lbClient, state.status]);
|
|
423
|
-
// Refresh status
|
|
445
|
+
// Refresh status uniquement lors de la transition vers "ready"
|
|
446
|
+
// (évite les boucles status/user causées par des callbacks recréés)
|
|
424
447
|
useEffect(() => {
|
|
425
|
-
|
|
448
|
+
const wasReady = previousStatusRef.current === "ready";
|
|
449
|
+
previousStatusRef.current = state.status;
|
|
450
|
+
if (state.status === "ready" && !wasReady) {
|
|
426
451
|
// Appel rapide d'abord
|
|
427
452
|
refreshBasicStatus();
|
|
428
453
|
// Storage en arrière-plan après 100ms
|
|
429
454
|
setTimeout(() => refreshStorageStatus(), 100);
|
|
430
455
|
fetchApiKeysWithSession(); // Also fetch API keys list
|
|
431
456
|
}
|
|
432
|
-
else {
|
|
457
|
+
else if (state.status !== "ready") {
|
|
433
458
|
setApiStatus(null);
|
|
434
459
|
setBasicStatus(null);
|
|
435
460
|
setStorageStatus(null);
|
|
@@ -460,6 +485,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
460
485
|
refreshStorageStatus,
|
|
461
486
|
isLoadingStatus,
|
|
462
487
|
isLoadingStorage,
|
|
488
|
+
hasSelectedApiKeyCookie,
|
|
463
489
|
};
|
|
464
490
|
return (_jsx(I18nProvider, { lang: lang, children: _jsx(LBContext.Provider, { value: value, children: children }) }));
|
|
465
491
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAiStatus.d.ts","sourceRoot":"","sources":["../../src/hooks/useAiStatus.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAItD,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,iBAAiB,
|
|
1
|
+
{"version":3,"file":"useAiStatus.d.ts","sourceRoot":"","sources":["../../src/hooks/useAiStatus.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAItD,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,iBAAiB,CA2F3E"}
|
|
@@ -25,13 +25,22 @@ export function useAiStatus(options) {
|
|
|
25
25
|
return null;
|
|
26
26
|
}, [lbContext]);
|
|
27
27
|
const fetchStatus = useCallback(async () => {
|
|
28
|
-
// If LBProvider
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
// If LBProvider exists, never call getStatus directly here:
|
|
29
|
+
// - ready: delegate refresh to provider
|
|
30
|
+
// - non-ready: avoid unauthorized polling loops
|
|
31
|
+
if (lbContext) {
|
|
32
|
+
if (lbContext.status === "ready") {
|
|
33
|
+
try {
|
|
34
|
+
await lbContext.refreshBasicStatus();
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Ignore: provider already tracks errors/status
|
|
38
|
+
}
|
|
32
39
|
}
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
else {
|
|
41
|
+
setStatus(null);
|
|
42
|
+
setLoading(false);
|
|
43
|
+
setError(null);
|
|
35
44
|
}
|
|
36
45
|
return;
|
|
37
46
|
}
|
|
@@ -52,6 +61,12 @@ export function useAiStatus(options) {
|
|
|
52
61
|
}
|
|
53
62
|
}, [client, lbContext]);
|
|
54
63
|
useEffect(() => {
|
|
64
|
+
if (lbContext && lbContext.status !== "ready") {
|
|
65
|
+
setStatus(null);
|
|
66
|
+
setLoading(false);
|
|
67
|
+
setError(null);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
55
70
|
if (statusFromLB) {
|
|
56
71
|
setStatus(statusFromLB);
|
|
57
72
|
setLoading(false);
|
|
@@ -59,7 +74,7 @@ export function useAiStatus(options) {
|
|
|
59
74
|
return;
|
|
60
75
|
}
|
|
61
76
|
fetchStatus();
|
|
62
|
-
}, [fetchStatus, statusFromLB]);
|
|
77
|
+
}, [fetchStatus, lbContext, statusFromLB]);
|
|
63
78
|
const isLoadingFromLB = !!lbContext &&
|
|
64
79
|
lbContext.status === "ready" &&
|
|
65
80
|
!statusFromLB &&
|
package/package.json
CHANGED
|
@@ -83,11 +83,22 @@ export function AiContextButton({
|
|
|
83
83
|
contextDescription || t("ai.context.description", "Data to analyze");
|
|
84
84
|
|
|
85
85
|
let lbStatus: string | undefined;
|
|
86
|
+
let lbHasSession = false;
|
|
87
|
+
let lbHasSelectedKey = false;
|
|
88
|
+
let lbHasSelectedApiKeyCookie = false;
|
|
89
|
+
let hasLBProvider = false;
|
|
86
90
|
try {
|
|
87
91
|
const lbContext = useLB();
|
|
88
92
|
lbStatus = lbContext.status;
|
|
93
|
+
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
94
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
95
|
+
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
96
|
+
hasLBProvider = true;
|
|
89
97
|
} catch {
|
|
90
98
|
lbStatus = undefined;
|
|
99
|
+
lbHasSession = false;
|
|
100
|
+
lbHasSelectedKey = false;
|
|
101
|
+
hasLBProvider = false;
|
|
91
102
|
}
|
|
92
103
|
|
|
93
104
|
const aiContext = useAiContext();
|
|
@@ -99,7 +110,14 @@ export function AiContextButton({
|
|
|
99
110
|
apiKeyId,
|
|
100
111
|
});
|
|
101
112
|
|
|
102
|
-
const
|
|
113
|
+
const needsApiKeySelection =
|
|
114
|
+
hasLBProvider &&
|
|
115
|
+
lbStatus === "ready" &&
|
|
116
|
+
lbHasSession &&
|
|
117
|
+
(!lbHasSelectedKey || !lbHasSelectedApiKeyCookie);
|
|
118
|
+
const isAuthReady =
|
|
119
|
+
!needsApiKeySelection &&
|
|
120
|
+
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
103
121
|
|
|
104
122
|
const handleOpenPanel = () => {
|
|
105
123
|
if (!isAuthReady) {
|
|
@@ -79,12 +79,23 @@ export function AiImageButton({
|
|
|
79
79
|
|
|
80
80
|
// Rendre l'authentification optionnelle
|
|
81
81
|
let lbStatus: string | undefined;
|
|
82
|
+
let lbHasSession = false;
|
|
83
|
+
let lbHasSelectedKey = false;
|
|
84
|
+
let lbHasSelectedApiKeyCookie = false;
|
|
85
|
+
let hasLBProvider = false;
|
|
82
86
|
try {
|
|
83
87
|
const lbContext = useLB();
|
|
84
88
|
lbStatus = lbContext.status;
|
|
89
|
+
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
90
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
91
|
+
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
92
|
+
hasLBProvider = true;
|
|
85
93
|
} catch {
|
|
86
94
|
// LBProvider n'est pas disponible, ignorer
|
|
87
95
|
lbStatus = undefined;
|
|
96
|
+
lbHasSession = false;
|
|
97
|
+
lbHasSelectedKey = false;
|
|
98
|
+
hasLBProvider = false;
|
|
88
99
|
}
|
|
89
100
|
|
|
90
101
|
// Récupérer le contexte AiProvider avec fallback sur les props
|
|
@@ -95,7 +106,14 @@ export function AiImageButton({
|
|
|
95
106
|
const { generateImage, loading } = useAiCallImage({ baseUrl, apiKeyId });
|
|
96
107
|
const { formatted: loadingElapsed } = useLoadingTimer(loading);
|
|
97
108
|
|
|
98
|
-
const
|
|
109
|
+
const needsApiKeySelection =
|
|
110
|
+
hasLBProvider &&
|
|
111
|
+
lbStatus === "ready" &&
|
|
112
|
+
lbHasSession &&
|
|
113
|
+
(!lbHasSelectedKey || !lbHasSelectedApiKeyCookie);
|
|
114
|
+
const isAuthReady =
|
|
115
|
+
!needsApiKeySelection &&
|
|
116
|
+
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
99
117
|
|
|
100
118
|
const handleOpenPanel = () => {
|
|
101
119
|
if (!isAuthReady) {
|
|
@@ -60,12 +60,23 @@ export function AiInput({
|
|
|
60
60
|
|
|
61
61
|
// Rendre l'authentification optionnelle
|
|
62
62
|
let lbStatus: string | undefined;
|
|
63
|
+
let lbHasSession = false;
|
|
64
|
+
let lbHasSelectedKey = false;
|
|
65
|
+
let lbHasSelectedApiKeyCookie = false;
|
|
66
|
+
let hasLBProvider = false;
|
|
63
67
|
try {
|
|
64
68
|
const lbContext = useLB();
|
|
65
69
|
lbStatus = lbContext.status;
|
|
70
|
+
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
71
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
72
|
+
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
73
|
+
hasLBProvider = true;
|
|
66
74
|
} catch {
|
|
67
75
|
// LBProvider n'est pas disponible, ignorer
|
|
68
76
|
lbStatus = undefined;
|
|
77
|
+
lbHasSession = false;
|
|
78
|
+
lbHasSelectedKey = false;
|
|
79
|
+
hasLBProvider = false;
|
|
69
80
|
}
|
|
70
81
|
|
|
71
82
|
let ctxBaseUrl: string | undefined;
|
|
@@ -91,7 +102,14 @@ export function AiInput({
|
|
|
91
102
|
const { formatted: loadingElapsed } = useLoadingTimer(loading);
|
|
92
103
|
|
|
93
104
|
const hasConfiguration = Boolean(model && prompt);
|
|
94
|
-
const
|
|
105
|
+
const needsApiKeySelection =
|
|
106
|
+
hasLBProvider &&
|
|
107
|
+
lbStatus === "ready" &&
|
|
108
|
+
lbHasSession &&
|
|
109
|
+
(!lbHasSelectedKey || !lbHasSelectedApiKeyCookie);
|
|
110
|
+
const isAuthReady =
|
|
111
|
+
!needsApiKeySelection &&
|
|
112
|
+
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
95
113
|
const shouldShowSparkles = isAuthReady && !disabled;
|
|
96
114
|
|
|
97
115
|
const handleOpenPanel = () => {
|
|
@@ -49,12 +49,23 @@ export function AiSelect({
|
|
|
49
49
|
|
|
50
50
|
// Rendre l'authentification optionnelle
|
|
51
51
|
let lbStatus: string | undefined;
|
|
52
|
+
let lbHasSession = false;
|
|
53
|
+
let lbHasSelectedKey = false;
|
|
54
|
+
let lbHasSelectedApiKeyCookie = false;
|
|
55
|
+
let hasLBProvider = false;
|
|
52
56
|
try {
|
|
53
57
|
const lbContext = useLB();
|
|
54
58
|
lbStatus = lbContext.status;
|
|
59
|
+
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
60
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
61
|
+
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
62
|
+
hasLBProvider = true;
|
|
55
63
|
} catch {
|
|
56
64
|
// LBProvider n'est pas disponible, ignorer
|
|
57
65
|
lbStatus = undefined;
|
|
66
|
+
lbHasSession = false;
|
|
67
|
+
lbHasSelectedKey = false;
|
|
68
|
+
hasLBProvider = false;
|
|
58
69
|
}
|
|
59
70
|
|
|
60
71
|
let ctxBaseUrl: string | undefined;
|
|
@@ -78,7 +89,14 @@ export function AiSelect({
|
|
|
78
89
|
});
|
|
79
90
|
const { generateText, loading } = useAiCallText({ baseUrl, apiKeyId });
|
|
80
91
|
|
|
81
|
-
const
|
|
92
|
+
const needsApiKeySelection =
|
|
93
|
+
hasLBProvider &&
|
|
94
|
+
lbStatus === "ready" &&
|
|
95
|
+
lbHasSession &&
|
|
96
|
+
(!lbHasSelectedKey || !lbHasSelectedApiKeyCookie);
|
|
97
|
+
const isAuthReady =
|
|
98
|
+
!needsApiKeySelection &&
|
|
99
|
+
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
82
100
|
const shouldShowSparkles = isAuthReady && !disabled;
|
|
83
101
|
|
|
84
102
|
const handleOpenPanel = () => {
|
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
import "../styles/register";
|
|
4
4
|
import type { AiStatus, LBUser } from "@lastbrain/ai-ui-core";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
useLayoutEffect,
|
|
7
|
+
useMemo,
|
|
8
|
+
useRef,
|
|
9
|
+
useState,
|
|
10
|
+
useContext,
|
|
11
|
+
useEffect,
|
|
12
|
+
} from "react";
|
|
6
13
|
import { createPortal } from "react-dom";
|
|
7
14
|
import {
|
|
8
15
|
ArrowRightLeft,
|
|
@@ -169,6 +176,8 @@ export function AiStatusButton({
|
|
|
169
176
|
let lbSelectedKey: LBApiKey | null = null;
|
|
170
177
|
let lbRefreshBasicStatus: (() => Promise<void>) | undefined;
|
|
171
178
|
let lbRefreshStorageStatus: ((force?: boolean) => Promise<void>) | undefined;
|
|
179
|
+
let lbSessionToken: string | undefined;
|
|
180
|
+
let lbHasSelectedApiKeyCookie = false;
|
|
172
181
|
|
|
173
182
|
const lbContext = useContext(LBContext);
|
|
174
183
|
if (lbContext) {
|
|
@@ -185,6 +194,8 @@ export function AiStatusButton({
|
|
|
185
194
|
lbSelectedKey = lbContext.selectedKey || null;
|
|
186
195
|
lbRefreshBasicStatus = lbContext.refreshBasicStatus;
|
|
187
196
|
lbRefreshStorageStatus = lbContext.refreshStorageStatus;
|
|
197
|
+
lbSessionToken = lbContext.session?.sessionToken;
|
|
198
|
+
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
188
199
|
} else {
|
|
189
200
|
lbStatus = undefined;
|
|
190
201
|
}
|
|
@@ -230,12 +241,23 @@ export function AiStatusButton({
|
|
|
230
241
|
typeof effectiveStatus.authType === "string"
|
|
231
242
|
? effectiveStatus.authType
|
|
232
243
|
: undefined;
|
|
244
|
+
const hasLbSession = Boolean(lbSessionToken);
|
|
233
245
|
const requiresApiKeySelection =
|
|
234
|
-
lbStatus === "ready" &&
|
|
246
|
+
lbStatus === "ready" &&
|
|
247
|
+
hasLbSession &&
|
|
248
|
+
(!lbHasSelectedApiKeyCookie || !hasApiKeySelected) &&
|
|
249
|
+
apiKeys.length > 0;
|
|
235
250
|
const isApiKeyAuthMode = authTypeValue === "api_key";
|
|
236
251
|
|
|
237
252
|
const [tooltipStyle, setTooltipStyle] = useState<Record<string, string>>({});
|
|
238
253
|
|
|
254
|
+
useEffect(() => {
|
|
255
|
+
if (requiresApiKeySelection) {
|
|
256
|
+
setShowApiKeySelector(true);
|
|
257
|
+
setShowTooltip(false);
|
|
258
|
+
}
|
|
259
|
+
}, [requiresApiKeySelection]);
|
|
260
|
+
|
|
239
261
|
useLayoutEffect(() => {
|
|
240
262
|
if (!showTooltip || !buttonRef.current || !canPortal) {
|
|
241
263
|
return;
|
|
@@ -63,10 +63,16 @@ export function AiTextarea({
|
|
|
63
63
|
|
|
64
64
|
// Rendre l'authentification optionnelle
|
|
65
65
|
let lbStatus: string | undefined;
|
|
66
|
+
let lbHasSession = false;
|
|
67
|
+
let lbHasSelectedKey = false;
|
|
68
|
+
let lbHasSelectedApiKeyCookie = false;
|
|
66
69
|
let hasLBProvider = false;
|
|
67
70
|
try {
|
|
68
71
|
const lbContext = useLB();
|
|
69
72
|
lbStatus = lbContext.status;
|
|
73
|
+
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
74
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
75
|
+
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
70
76
|
hasLBProvider = true;
|
|
71
77
|
} catch {
|
|
72
78
|
// LBProvider n'est pas disponible, ignorer
|
|
@@ -87,9 +93,11 @@ export function AiTextarea({
|
|
|
87
93
|
|
|
88
94
|
const baseUrl = propBaseUrl ?? ctxBaseUrl;
|
|
89
95
|
const apiKeyId = propApiKeyId ?? ctxApiKeyId;
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
const needsApiKeySelection =
|
|
97
|
+
hasLBProvider &&
|
|
98
|
+
lbStatus === "ready" &&
|
|
99
|
+
lbHasSession &&
|
|
100
|
+
(!lbHasSelectedKey || !lbHasSelectedApiKeyCookie);
|
|
93
101
|
|
|
94
102
|
const { models: _models } = useAiModels({
|
|
95
103
|
baseUrl,
|
|
@@ -100,10 +108,10 @@ export function AiTextarea({
|
|
|
100
108
|
const { formatted: loadingElapsed } = useLoadingTimer(loading);
|
|
101
109
|
|
|
102
110
|
const hasConfiguration = Boolean(model && prompt);
|
|
103
|
-
const isAuthReady =
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
Boolean(process.env.LB_API_KEY);
|
|
111
|
+
const isAuthReady = hasLBProvider
|
|
112
|
+
? !needsApiKeySelection &&
|
|
113
|
+
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY))
|
|
114
|
+
: Boolean(process.env.LB_API_KEY);
|
|
107
115
|
const shouldShowSparkles = isAuthReady && !disabled;
|
|
108
116
|
|
|
109
117
|
const handleOpenPanel = () => {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
useEffect,
|
|
12
12
|
useCallback,
|
|
13
13
|
useMemo,
|
|
14
|
+
useRef,
|
|
14
15
|
useState,
|
|
15
16
|
type ReactNode,
|
|
16
17
|
} from "react";
|
|
@@ -114,6 +115,8 @@ interface LBContextValue extends LBAuthState {
|
|
|
114
115
|
isLoadingStatus: boolean;
|
|
115
116
|
/** Indique si le storage est en cours de chargement */
|
|
116
117
|
isLoadingStorage: boolean;
|
|
118
|
+
/** True si le cookie api_key_selected est présent */
|
|
119
|
+
hasSelectedApiKeyCookie: boolean;
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
const LBContext = createContext<LBContextValue | undefined>(undefined);
|
|
@@ -142,6 +145,17 @@ export function LBProvider({
|
|
|
142
145
|
const [isLoadingStatus, setIsLoadingStatus] = useState(false);
|
|
143
146
|
const [isLoadingStorage, setIsLoadingStorage] = useState(false);
|
|
144
147
|
const [storageLastFetch, setStorageLastFetch] = useState<number>(0);
|
|
148
|
+
const [hasSelectedApiKeyCookie, setHasSelectedApiKeyCookie] = useState(false);
|
|
149
|
+
const previousStatusRef = useRef<LBAuthState["status"]>("loading");
|
|
150
|
+
|
|
151
|
+
const syncSelectedApiKeyCookie = useCallback(() => {
|
|
152
|
+
if (typeof document === "undefined") return;
|
|
153
|
+
const hasCookie = document.cookie
|
|
154
|
+
.split(";")
|
|
155
|
+
.map((part) => part.trim())
|
|
156
|
+
.some((part) => part.startsWith("api_key_selected=") && part.length > 17);
|
|
157
|
+
setHasSelectedApiKeyCookie(hasCookie);
|
|
158
|
+
}, []);
|
|
145
159
|
|
|
146
160
|
const lbClient = useMemo(
|
|
147
161
|
() =>
|
|
@@ -223,6 +237,13 @@ export function LBProvider({
|
|
|
223
237
|
checkSession();
|
|
224
238
|
}, [checkSession]);
|
|
225
239
|
|
|
240
|
+
useEffect(() => {
|
|
241
|
+
syncSelectedApiKeyCookie();
|
|
242
|
+
if (typeof window === "undefined") return;
|
|
243
|
+
const interval = window.setInterval(syncSelectedApiKeyCookie, 1000);
|
|
244
|
+
return () => window.clearInterval(interval);
|
|
245
|
+
}, [syncSelectedApiKeyCookie]);
|
|
246
|
+
|
|
226
247
|
/**
|
|
227
248
|
* Récupère les clés API de l'utilisateur
|
|
228
249
|
*/
|
|
@@ -272,6 +293,7 @@ export function LBProvider({
|
|
|
272
293
|
|
|
273
294
|
setAccessToken(undefined); // Nettoyer l'access token temporaire
|
|
274
295
|
setApiKeys([]); // Nettoyer les clés API temporaires
|
|
296
|
+
setTimeout(() => syncSelectedApiKeyCookie(), 100);
|
|
275
297
|
onStatusChange?.("ready");
|
|
276
298
|
onAuthChange?.(); // Refresh provider after signin
|
|
277
299
|
} catch (error) {
|
|
@@ -284,7 +306,7 @@ export function LBProvider({
|
|
|
284
306
|
throw error;
|
|
285
307
|
}
|
|
286
308
|
},
|
|
287
|
-
[lbClient, state.user,
|
|
309
|
+
[lbClient, onAuthChange, onStatusChange, state.user, syncSelectedApiKeyCookie]
|
|
288
310
|
);
|
|
289
311
|
|
|
290
312
|
/**
|
|
@@ -550,6 +572,7 @@ export function LBProvider({
|
|
|
550
572
|
}
|
|
551
573
|
await refreshBasicStatus();
|
|
552
574
|
setTimeout(() => refreshStorageStatus(), 100);
|
|
575
|
+
setTimeout(() => syncSelectedApiKeyCookie(), 100);
|
|
553
576
|
} else {
|
|
554
577
|
throw new Error("No valid authentication method available");
|
|
555
578
|
}
|
|
@@ -562,6 +585,7 @@ export function LBProvider({
|
|
|
562
585
|
lbClient,
|
|
563
586
|
refreshBasicStatus,
|
|
564
587
|
refreshStorageStatus,
|
|
588
|
+
syncSelectedApiKeyCookie,
|
|
565
589
|
]
|
|
566
590
|
);
|
|
567
591
|
|
|
@@ -582,6 +606,7 @@ export function LBProvider({
|
|
|
582
606
|
setBasicStatus(null);
|
|
583
607
|
setStorageStatus(null);
|
|
584
608
|
setStorageLastFetch(0);
|
|
609
|
+
setHasSelectedApiKeyCookie(false);
|
|
585
610
|
onStatusChange?.("needs_auth");
|
|
586
611
|
onAuthChange?.(); // Refresh provider after logout
|
|
587
612
|
}
|
|
@@ -612,15 +637,19 @@ export function LBProvider({
|
|
|
612
637
|
}
|
|
613
638
|
}, [lbClient, state.status]);
|
|
614
639
|
|
|
615
|
-
// Refresh status
|
|
640
|
+
// Refresh status uniquement lors de la transition vers "ready"
|
|
641
|
+
// (évite les boucles status/user causées par des callbacks recréés)
|
|
616
642
|
useEffect(() => {
|
|
617
|
-
|
|
643
|
+
const wasReady = previousStatusRef.current === "ready";
|
|
644
|
+
previousStatusRef.current = state.status;
|
|
645
|
+
|
|
646
|
+
if (state.status === "ready" && !wasReady) {
|
|
618
647
|
// Appel rapide d'abord
|
|
619
648
|
refreshBasicStatus();
|
|
620
649
|
// Storage en arrière-plan après 100ms
|
|
621
650
|
setTimeout(() => refreshStorageStatus(), 100);
|
|
622
651
|
fetchApiKeysWithSession(); // Also fetch API keys list
|
|
623
|
-
} else {
|
|
652
|
+
} else if (state.status !== "ready") {
|
|
624
653
|
setApiStatus(null);
|
|
625
654
|
setBasicStatus(null);
|
|
626
655
|
setStorageStatus(null);
|
|
@@ -652,6 +681,7 @@ export function LBProvider({
|
|
|
652
681
|
refreshStorageStatus,
|
|
653
682
|
isLoadingStatus,
|
|
654
683
|
isLoadingStorage,
|
|
684
|
+
hasSelectedApiKeyCookie,
|
|
655
685
|
};
|
|
656
686
|
|
|
657
687
|
return (
|
package/src/hooks/useAiStatus.ts
CHANGED
|
@@ -43,12 +43,20 @@ export function useAiStatus(options?: UseAiStatusOptions): UseAiStatusResult {
|
|
|
43
43
|
}, [lbContext]);
|
|
44
44
|
|
|
45
45
|
const fetchStatus = useCallback(async () => {
|
|
46
|
-
// If LBProvider
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
// If LBProvider exists, never call getStatus directly here:
|
|
47
|
+
// - ready: delegate refresh to provider
|
|
48
|
+
// - non-ready: avoid unauthorized polling loops
|
|
49
|
+
if (lbContext) {
|
|
50
|
+
if (lbContext.status === "ready") {
|
|
51
|
+
try {
|
|
52
|
+
await lbContext.refreshBasicStatus();
|
|
53
|
+
} catch {
|
|
54
|
+
// Ignore: provider already tracks errors/status
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
setStatus(null);
|
|
58
|
+
setLoading(false);
|
|
59
|
+
setError(null);
|
|
52
60
|
}
|
|
53
61
|
return;
|
|
54
62
|
}
|
|
@@ -72,6 +80,13 @@ export function useAiStatus(options?: UseAiStatusOptions): UseAiStatusResult {
|
|
|
72
80
|
}, [client, lbContext]);
|
|
73
81
|
|
|
74
82
|
useEffect(() => {
|
|
83
|
+
if (lbContext && lbContext.status !== "ready") {
|
|
84
|
+
setStatus(null);
|
|
85
|
+
setLoading(false);
|
|
86
|
+
setError(null);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
75
90
|
if (statusFromLB) {
|
|
76
91
|
setStatus(statusFromLB);
|
|
77
92
|
setLoading(false);
|
|
@@ -79,7 +94,7 @@ export function useAiStatus(options?: UseAiStatusOptions): UseAiStatusResult {
|
|
|
79
94
|
return;
|
|
80
95
|
}
|
|
81
96
|
fetchStatus();
|
|
82
|
-
}, [fetchStatus, statusFromLB]);
|
|
97
|
+
}, [fetchStatus, lbContext, statusFromLB]);
|
|
83
98
|
|
|
84
99
|
const isLoadingFromLB =
|
|
85
100
|
!!lbContext &&
|