@lastbrain/ai-ui-react 1.0.75 → 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.
Files changed (49) hide show
  1. package/dist/components/AiContextButton.d.ts +1 -1
  2. package/dist/components/AiContextButton.d.ts.map +1 -1
  3. package/dist/components/AiContextButton.js +17 -1
  4. package/dist/components/AiImageButton.d.ts.map +1 -1
  5. package/dist/components/AiImageButton.js +19 -3
  6. package/dist/components/AiInput.d.ts +1 -1
  7. package/dist/components/AiInput.d.ts.map +1 -1
  8. package/dist/components/AiInput.js +21 -5
  9. package/dist/components/AiPromptPanel.js +30 -6
  10. package/dist/components/AiSelect.d.ts +1 -1
  11. package/dist/components/AiSelect.d.ts.map +1 -1
  12. package/dist/components/AiSelect.js +18 -2
  13. package/dist/components/AiStatusButton.d.ts.map +1 -1
  14. package/dist/components/AiStatusButton.js +18 -4
  15. package/dist/components/AiTextarea.d.ts +2 -1
  16. package/dist/components/AiTextarea.d.ts.map +1 -1
  17. package/dist/components/AiTextarea.js +25 -6
  18. package/dist/components/ErrorToast.js +3 -3
  19. package/dist/components/LBKeyPicker.js +9 -9
  20. package/dist/components/LBSigninModal.d.ts.map +1 -1
  21. package/dist/components/UsageToast.d.ts +3 -3
  22. package/dist/components/UsageToast.d.ts.map +1 -1
  23. package/dist/context/LBAuthProvider.d.ts +2 -0
  24. package/dist/context/LBAuthProvider.d.ts.map +1 -1
  25. package/dist/context/LBAuthProvider.js +43 -10
  26. package/dist/examples/AiImageGenerator.js +1 -1
  27. package/dist/hooks/useAiStatus.d.ts.map +1 -1
  28. package/dist/hooks/useAiStatus.js +58 -5
  29. package/dist/styles.css +3 -3
  30. package/dist/utils/errorHandler.d.ts +2 -2
  31. package/dist/utils/errorHandler.d.ts.map +1 -1
  32. package/package.json +2 -2
  33. package/src/components/AiContextButton.tsx +20 -2
  34. package/src/components/AiImageButton.tsx +21 -3
  35. package/src/components/AiInput.tsx +28 -5
  36. package/src/components/AiPromptPanel.tsx +31 -6
  37. package/src/components/AiSelect.tsx +21 -3
  38. package/src/components/AiStatusButton.tsx +35 -10
  39. package/src/components/AiTextarea.tsx +33 -9
  40. package/src/components/ErrorToast.tsx +3 -3
  41. package/src/components/LBKeyPicker.tsx +10 -10
  42. package/src/components/LBSigninModal.tsx +2 -1
  43. package/src/components/UsageToast.tsx +4 -4
  44. package/src/context/LBAuthProvider.tsx +46 -9
  45. package/src/examples/AiImageGenerator.tsx +1 -1
  46. package/src/hooks/useAiStatus.ts +62 -5
  47. package/src/styles.css +3 -3
  48. package/src/utils/errorHandler.ts +3 -3
  49. package/src/utils/modelManagement.ts +3 -3
@@ -3,7 +3,7 @@ import { type ButtonHTMLAttributes } from "react";
3
3
  import type { BaseAiProps } from "../types";
4
4
  import type { AiRadius, AiSize, AiVariant } from "../types";
5
5
  type ContextData = string | number | boolean | object | unknown[] | {
6
- [key: string]: unknown;
6
+ [key: string]: any;
7
7
  };
8
8
  export interface AiContextButtonProps extends Omit<BaseAiProps, "onValue" | "type">, Omit<ButtonHTMLAttributes<HTMLButtonElement>, "baseUrl" | "apiKeyId"> {
9
9
  contextData: ContextData;
@@ -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,OAAO,CAAA;CAAE,CAAC;AAE/B,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,2CA6StB"}
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 isAuthReady = lbStatus === "ready" || Boolean(process.env.LB_API_KEY);
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,2CAoRpB"}
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"}
@@ -18,17 +18,28 @@ export function AiImageButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, ui
18
18
  const [isOpen, setIsOpen] = useState(false);
19
19
  const [showAuthModal, setShowAuthModal] = useState(false);
20
20
  const [generatedImage, setGeneratedImage] = useState(null);
21
- const { showUsageToast, toastData, toastKey, clearToast } = useUsageToast();
21
+ const { showUsageToast } = useUsageToast();
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 isAuthReady = lbStatus === "ready" || Boolean(process.env.LB_API_KEY);
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);
@@ -66,7 +82,7 @@ export function AiImageButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, ui
66
82
  message: t("ai.image.savedSuccess", "Image saved"),
67
83
  });
68
84
  }
69
- catch (_error) {
85
+ catch {
70
86
  onToast?.({
71
87
  type: "error",
72
88
  message: t("ai.image.saveError", "Error while saving"),
@@ -7,5 +7,5 @@ export interface AiInputProps extends Omit<BaseAiProps, "type">, Omit<InputHTMLA
7
7
  size?: AiSize;
8
8
  radius?: AiRadius;
9
9
  }
10
- export declare function AiInput({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode, size, radius, context, model, prompt, editMode, enableModelManagement, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...inputProps }: AiInputProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function AiInput({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode, size, radius, context, model, prompt, editMode: _editMode, enableModelManagement, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...inputProps }: AiInputProps): import("react/jsx-runtime").JSX.Element;
11
11
  //# sourceMappingURL=AiInput.d.ts.map
@@ -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,QAAgB,EAChB,qBAA4B,EAC5B,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,UAAU,EACd,EAAE,YAAY,2CAyNd"}
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"}
@@ -13,22 +13,33 @@ import { LBSigninModal } from "./LBSigninModal";
13
13
  import { useAiContext } from "../context/AiProvider";
14
14
  import { useI18n } from "../context/I18nContext";
15
15
  import { useLoadingTimer } from "../hooks/useLoadingTimer";
16
- export function AiInput({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode = "modal", size = "md", radius = "full", context, model, prompt, editMode = false, enableModelManagement = true, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...inputProps }) {
16
+ export function AiInput({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode = "modal", size = "md", radius = "full", context, model, prompt, editMode: _editMode = false, enableModelManagement = true, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...inputProps }) {
17
17
  const { t } = useI18n();
18
18
  const [isOpen, setIsOpen] = useState(false);
19
19
  const [showAuthModal, setShowAuthModal] = useState(false);
20
20
  const [inputValue, setInputValue] = useState(inputProps.value?.toString() || inputProps.defaultValue?.toString() || "");
21
21
  const inputRef = useRef(null);
22
- const { showUsageToast, toastData, toastKey, clearToast } = useUsageToast();
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;
@@ -43,7 +54,7 @@ export function AiInput({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode =
43
54
  }
44
55
  const baseUrl = propBaseUrl ?? ctxBaseUrl;
45
56
  const apiKeyId = propApiKeyId ?? ctxApiKeyId;
46
- const { models } = useAiModels({
57
+ const { models: _models } = useAiModels({
47
58
  baseUrl,
48
59
  apiKeyId,
49
60
  modelType: "text-or-language",
@@ -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 isAuthReady = lbStatus === "ready" || Boolean(process.env.LB_API_KEY);
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) {
@@ -63,7 +79,7 @@ export function AiInput({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode =
63
79
  const handleClosePanel = () => {
64
80
  setIsOpen(false);
65
81
  };
66
- const handleSubmit = async (selectedModel, selectedPrompt, promptId) => {
82
+ const handleSubmit = async (selectedModel, selectedPrompt, _promptId) => {
67
83
  try {
68
84
  const resolvedContext = inputValue || context || undefined;
69
85
  const hasContext = Boolean(resolvedContext && String(resolvedContext).trim());
@@ -32,7 +32,7 @@ export function AiPromptPanel(props) {
32
32
  // Sinon, utiliser le contexte existant
33
33
  return _jsx(AiPromptPanelInternal, { ...props });
34
34
  }
35
- function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "modal", models = [], sourceText, children, enableModelManagement = true, modelCategory = "text", availableModels = [], userModels = [], onModelToggle, apiKey, baseUrl, showOnlyUserModels = false, }) {
35
+ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode = "modal", models = [], sourceText, children, enableModelManagement = true, modelCategory = "text", availableModels = [], userModels = [], onModelToggle, apiKey, baseUrl, showOnlyUserModels = false, }) {
36
36
  const { t } = useI18n();
37
37
  const [selectedModel, setSelectedModel] = useState("");
38
38
  const [prompt, setPrompt] = useState("");
@@ -269,21 +269,45 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
269
269
  if (!portalRoot) {
270
270
  return null;
271
271
  }
272
+ const isDrawer = uiMode === "drawer";
273
+ const panelContainerStyle = isDrawer
274
+ ? {
275
+ ...aiStyles.modal,
276
+ alignItems: "stretch",
277
+ justifyContent: "flex-end",
278
+ padding: "0",
279
+ }
280
+ : aiStyles.modal;
281
+ const panelContentStyle = isDrawer
282
+ ? {
283
+ ...aiStyles.modalContent,
284
+ width: "min(92vw, 640px)",
285
+ maxWidth: "640px",
286
+ maxHeight: "100vh",
287
+ height: "100vh",
288
+ borderRadius: "16px 0 0 16px",
289
+ }
290
+ : aiStyles.modalContent;
272
291
  if (children) {
273
- return createPortal(_jsx("div", { style: aiStyles.modal, onKeyDown: handleKeyDown, children: children(renderProps) }), portalRoot);
292
+ return createPortal(_jsx("div", { style: panelContainerStyle, onKeyDown: handleKeyDown, children: children(renderProps) }), portalRoot);
274
293
  }
275
- return createPortal(_jsxs("div", { style: aiStyles.modal, onKeyDown: handleKeyDown, children: [_jsx("div", { style: {
294
+ return createPortal(_jsxs("div", { style: panelContainerStyle, onKeyDown: handleKeyDown, children: [_jsx("div", { style: {
276
295
  ...aiStyles.modalOverlay,
277
296
  opacity: isClosing ? 0 : 1,
278
297
  transition: "opacity 200ms ease",
279
298
  }, onClick: handleClose }), _jsxs("div", { style: {
280
- ...aiStyles.modalContent,
299
+ ...panelContentStyle,
281
300
  opacity: isClosing ? 0 : 1,
282
- transform: isClosing ? "translateY(12px)" : "translateY(0)",
301
+ transform: isClosing
302
+ ? isDrawer
303
+ ? "translateX(16px)"
304
+ : "translateY(12px)"
305
+ : isDrawer
306
+ ? "translateX(0)"
307
+ : "translateY(0)",
283
308
  transition: "opacity 200ms ease, transform 200ms ease",
284
309
  display: "flex",
285
310
  flexDirection: "column",
286
- maxHeight: "85vh",
287
311
  overflow: "hidden",
288
312
  }, children: [isGenerating && (_jsxs("div", { style: {
289
313
  position: "absolute",
@@ -7,5 +7,5 @@ export interface AiSelectProps extends Omit<BaseAiProps, "type">, Omit<SelectHTM
7
7
  size?: AiSize;
8
8
  radius?: AiRadius;
9
9
  }
10
- export declare function AiSelect({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode, size, radius, context, model, prompt, storeOutputs, artifactTitle, onValue, onToast, disabled, className, children, ...selectProps }: AiSelectProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function AiSelect({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode, size, radius, context, model: _model, prompt: _prompt, storeOutputs, artifactTitle, onValue, onToast, disabled, className, children, ...selectProps }: AiSelectProps): import("react/jsx-runtime").JSX.Element;
11
11
  //# sourceMappingURL=AiSelect.d.ts.map
@@ -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,EACL,MAAM,EACN,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,GAAG,WAAW,EACf,EAAE,aAAa,2CAgJf"}
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"}
@@ -12,20 +12,31 @@ import { handleAIError } from "../utils/errorHandler";
12
12
  import { useLB } from "../context/LBAuthProvider";
13
13
  import { useAiContext } from "../context/AiProvider";
14
14
  import { useI18n } from "../context/I18nContext";
15
- export function AiSelect({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode = "modal", size = "md", radius = "full", context, model, prompt, storeOutputs, artifactTitle, onValue, onToast, disabled, className, children, ...selectProps }) {
15
+ export function AiSelect({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode = "modal", size = "md", radius = "full", context, model: _model, prompt: _prompt, storeOutputs, artifactTitle, onValue, onToast, disabled, className, children, ...selectProps }) {
16
16
  const { t } = useI18n();
17
17
  const [isOpen, setIsOpen] = useState(false);
18
18
  const [showAuthModal, setShowAuthModal] = useState(false);
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 isAuthReady = lbStatus === "ready" || Boolean(process.env.LB_API_KEY);
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;AAuB9D,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,2CA2iBrB"}
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;
@@ -113,13 +117,13 @@ export function AiStatusButton({ status, loading = false, className = "", size =
113
117
  const buttonRef = useRef(null);
114
118
  const tooltipRef = useRef(null);
115
119
  const canPortal = typeof document !== "undefined";
116
- const effectiveStatus = lbStatus === "ready"
120
+ const effectiveStatus = useMemo(() => lbStatus === "ready"
117
121
  ? {
118
122
  ...(lbApiStatus || {}),
119
123
  ...(lbBasicStatus || {}),
120
124
  storage: lbStorageStatus?.storage || lbApiStatus?.storage,
121
125
  }
122
- : status || null;
126
+ : status || null, [lbApiStatus, lbBasicStatus, lbStatus, lbStorageStatus, status]);
123
127
  const hasApiKeySelected = Boolean(effectiveStatus?.apiKey?.id ||
124
128
  effectiveStatus?.api_key?.id ||
125
129
  lbSelectedKey?.id);
@@ -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 requiresApiKeySelection = lbStatus === "ready" && !hasApiKeySelected && apiKeys.length > 0;
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;
@@ -5,6 +5,7 @@ export interface AiTextareaProps extends Omit<BaseAiProps, "type">, Omit<Textare
5
5
  uiMode?: "modal" | "drawer";
6
6
  size?: AiSize;
7
7
  radius?: AiRadius;
8
+ onPanelOpenChange?: (isOpen: boolean) => void;
8
9
  }
9
- export declare function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode, size, radius, context, model, prompt, editMode, enableModelManagement, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...textareaProps }: AiTextareaProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode, size, radius, onPanelOpenChange, context, model, prompt, editMode: _editMode, enableModelManagement, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...textareaProps }: AiTextareaProps): import("react/jsx-runtime").JSX.Element;
10
11
  //# sourceMappingURL=AiTextarea.d.ts.map
@@ -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;CACnB;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,IAAW,EACX,MAAa,EACb,OAAO,EACP,KAAK,EACL,MAAM,EACN,QAAgB,EAChB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,aAAa,EACjB,EAAE,eAAe,2CA+OjB"}
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"}
@@ -13,7 +13,7 @@ import { LBSigninModal } from "./LBSigninModal";
13
13
  import { useAiContext } from "../context/AiProvider";
14
14
  import { useI18n } from "../context/I18nContext";
15
15
  import { useLoadingTimer } from "../hooks/useLoadingTimer";
16
- export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode = "modal", size = "md", radius = "lg", context, model, prompt, editMode = false, enableModelManagement, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...textareaProps }) {
16
+ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode = "modal", size = "md", radius = "lg", onPanelOpenChange, context, model, prompt, editMode: _editMode = false, enableModelManagement, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...textareaProps }) {
17
17
  const { t } = useI18n();
18
18
  const [isOpen, setIsOpen] = useState(false);
19
19
  const [showAuthModal, setShowAuthModal] = useState(false);
@@ -24,13 +24,22 @@ 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;
30
+ let hasLBProvider = false;
27
31
  try {
28
32
  const lbContext = useLB();
29
33
  lbStatus = lbContext.status;
34
+ lbHasSession = Boolean(lbContext.session?.sessionToken);
35
+ lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
36
+ lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
37
+ hasLBProvider = true;
30
38
  }
31
39
  catch {
32
40
  // LBProvider n'est pas disponible, ignorer
33
41
  lbStatus = undefined;
42
+ hasLBProvider = false;
34
43
  }
35
44
  let ctxBaseUrl;
36
45
  let ctxApiKeyId;
@@ -45,7 +54,11 @@ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMod
45
54
  }
46
55
  const baseUrl = propBaseUrl ?? ctxBaseUrl;
47
56
  const apiKeyId = propApiKeyId ?? ctxApiKeyId;
48
- const { models } = useAiModels({
57
+ const needsApiKeySelection = hasLBProvider &&
58
+ lbStatus === "ready" &&
59
+ lbHasSession &&
60
+ (!lbHasSelectedKey || !lbHasSelectedApiKeyCookie);
61
+ const { models: _models } = useAiModels({
49
62
  baseUrl,
50
63
  apiKeyId,
51
64
  modelType: "text-or-language",
@@ -53,7 +66,10 @@ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMod
53
66
  const { generateText, loading } = useAiCallText({ baseUrl, apiKeyId });
54
67
  const { formatted: loadingElapsed } = useLoadingTimer(loading);
55
68
  const hasConfiguration = Boolean(model && prompt);
56
- const isAuthReady = lbStatus === "ready" || Boolean(process.env.LB_API_KEY);
69
+ const isAuthReady = hasLBProvider
70
+ ? !needsApiKeySelection &&
71
+ (lbStatus === "ready" || Boolean(process.env.LB_API_KEY))
72
+ : Boolean(process.env.LB_API_KEY);
57
73
  const shouldShowSparkles = isAuthReady && !disabled;
58
74
  const handleOpenPanel = () => {
59
75
  if (!isAuthReady) {
@@ -61,11 +77,13 @@ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMod
61
77
  return;
62
78
  }
63
79
  setIsOpen(true);
80
+ onPanelOpenChange?.(true);
64
81
  };
65
82
  const handleClosePanel = () => {
66
83
  setIsOpen(false);
84
+ onPanelOpenChange?.(false);
67
85
  };
68
- const handleSubmit = async (selectedModel, selectedPrompt, promptId) => {
86
+ const handleSubmit = async (selectedModel, selectedPrompt, _promptId) => {
69
87
  try {
70
88
  const resolvedContext = textareaValue || context || undefined;
71
89
  const hasContext = Boolean(resolvedContext && String(resolvedContext).trim());
@@ -93,7 +111,7 @@ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMod
93
111
  showUsageToast(result);
94
112
  }
95
113
  }
96
- catch (error) {
114
+ catch {
97
115
  onToast?.({
98
116
  type: "error",
99
117
  message: t("ai.generationError", "Failed to generate text"),
@@ -101,6 +119,7 @@ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMod
101
119
  }
102
120
  finally {
103
121
  setIsOpen(false);
122
+ onPanelOpenChange?.(false);
104
123
  }
105
124
  };
106
125
  const handleQuickGenerate = async () => {
@@ -162,5 +181,5 @@ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMod
162
181
  ? t("auth.required", "Authentication required")
163
182
  : hasConfiguration
164
183
  ? t("ai.generate", "Generate with AI")
165
- : t("ai.setup", "Setup AI"), children: loading ? (_jsx(Loader2, { size: 16, className: "ai-spinner" })) : shouldShowSparkles ? (_jsx(Sparkles, { size: 16 })) : (_jsx(Lock, { size: 16 })) })] }), loading ? (_jsx("span", { className: "ai-control-timer", children: t("ai.loading.elapsed", "{seconds}", { seconds: loadingElapsed }) })) : null, isOpen && (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: handleClosePanel, onSubmit: handleSubmit, uiMode: uiMode, models: [], modelCategory: "text", sourceText: textareaValue || undefined, baseUrl: baseUrl, apiKey: apiKeyId, enableModelManagement: enableModelManagement, showOnlyUserModels: true })), Boolean(toastData) && (_jsx(UsageToast, { result: toastData, position: "bottom-right", onComplete: clearToast }, toastKey)), _jsx(LBSigninModal, { isOpen: showAuthModal, onClose: () => setShowAuthModal(false) })] }));
184
+ : t("ai.setup", "Setup AI"), children: loading ? (_jsx(Loader2, { size: 16, className: "ai-spinner" })) : shouldShowSparkles ? (_jsx(Sparkles, { size: 16 })) : (_jsx(Lock, { size: 16 })) })] }), loading ? (_jsx("span", { className: "ai-control-timer", children: t("ai.loading.elapsed", "{seconds}", { seconds: loadingElapsed }) })) : null, isOpen && (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: handleClosePanel, onSubmit: handleSubmit, uiMode: uiMode, models: [], modelCategory: "text", sourceText: textareaValue || undefined, baseUrl: baseUrl, apiKey: apiKeyId, enableModelManagement: enableModelManagement, showOnlyUserModels: true })), Boolean(toastData) && (_jsx(UsageToast, { result: toastData, position: "bottom-right", onComplete: clearToast }, toastKey)), hasLBProvider ? (_jsx(LBSigninModal, { isOpen: showAuthModal, onClose: () => setShowAuthModal(false) })) : null] }));
166
185
  }
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import "../styles/register";
4
- import { useEffect, useRef, useState } from "react";
4
+ import { useCallback, useEffect, useRef, useState } from "react";
5
5
  import { X, AlertCircle } from "lucide-react";
6
6
  import { useI18n } from "../context/I18nContext";
7
7
  export function ErrorToast({ error, position = "bottom-right", onComplete, }) {
@@ -10,7 +10,7 @@ export function ErrorToast({ error, position = "bottom-right", onComplete, }) {
10
10
  const [isClosing, setIsClosing] = useState(false);
11
11
  const fadeTimeoutRef = useRef(null);
12
12
  const autoCloseTimeoutRef = useRef(null);
13
- const handleClose = () => {
13
+ const handleClose = useCallback(() => {
14
14
  if (isClosing)
15
15
  return;
16
16
  // Clear auto-close timeout if user closes manually
@@ -22,7 +22,7 @@ export function ErrorToast({ error, position = "bottom-right", onComplete, }) {
22
22
  setIsVisible(false);
23
23
  onComplete?.();
24
24
  }, 200);
25
- };
25
+ }, [isClosing, onComplete]);
26
26
  useEffect(() => {
27
27
  if (error) {
28
28
  // Show toast immediately
@@ -5,7 +5,7 @@ import "../styles/register";
5
5
  * Composant LBKeyPicker
6
6
  * Permet de changer de clé API sans se reconnecter
7
7
  */
8
- import { useEffect, useState } from "react";
8
+ import { useCallback, useEffect, useState } from "react";
9
9
  import { useLB } from "../hooks/useLB";
10
10
  import { useI18n } from "../context/I18nContext";
11
11
  export function LBKeyPicker({ className = "", onKeyChanged, }) {
@@ -15,12 +15,7 @@ export function LBKeyPicker({ className = "", onKeyChanged, }) {
15
15
  const [loading, setLoading] = useState(false);
16
16
  const [error, setError] = useState("");
17
17
  const [showDropdown, setShowDropdown] = useState(false);
18
- useEffect(() => {
19
- if (status === "ready" && accessToken) {
20
- loadKeys();
21
- }
22
- }, [status, accessToken]);
23
- const loadKeys = async () => {
18
+ const loadKeys = useCallback(async () => {
24
19
  if (!accessToken)
25
20
  return;
26
21
  try {
@@ -28,13 +23,18 @@ export function LBKeyPicker({ className = "", onKeyChanged, }) {
28
23
  const keys = await fetchApiKeys(accessToken);
29
24
  setApiKeys(keys);
30
25
  }
31
- catch (err) {
26
+ catch {
32
27
  setError(t("lb.keypicker.loadError", "Unable to load API keys"));
33
28
  }
34
29
  finally {
35
30
  setLoading(false);
36
31
  }
37
- };
32
+ }, [accessToken, fetchApiKeys, t]);
33
+ useEffect(() => {
34
+ if (status === "ready" && accessToken) {
35
+ loadKeys();
36
+ }
37
+ }, [accessToken, loadKeys, status]);
38
38
  const handleSelectKey = async (keyId) => {
39
39
  if (!accessToken)
40
40
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"LBSigninModal.d.ts","sourceRoot":"","sources":["../../src/components/LBSigninModal.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAQ5B,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,kBAAkB,sCAsPpE"}
1
+ {"version":3,"file":"LBSigninModal.d.ts","sourceRoot":"","sources":["../../src/components/LBSigninModal.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAS5B,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,kBAAkB,sCAsPpE"}
@@ -1,13 +1,13 @@
1
1
  import "../styles/register";
2
2
  interface UsageToastProps {
3
- result: unknown;
3
+ result: any;
4
4
  position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
5
5
  onComplete?: () => void;
6
6
  }
7
7
  export declare function UsageToast({ result, position, onComplete, }: UsageToastProps): import("react/jsx-runtime").JSX.Element | null;
8
8
  export declare function useUsageToast(): {
9
- showUsageToast: (result: unknown) => void;
10
- toastData: unknown;
9
+ showUsageToast: (result: any) => void;
10
+ toastData: any;
11
11
  toastKey: number;
12
12
  clearToast: () => void;
13
13
  };
@@ -1 +1 @@
1
- {"version":3,"file":"UsageToast.d.ts","sourceRoot":"","sources":["../../src/components/UsageToast.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAK5B,UAAU,eAAe;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;IACrE,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,QAAyB,EACzB,UAAU,GACX,EAAE,eAAe,kDAmJjB;AAED,wBAAgB,aAAa;6BAIK,OAAO;;;;EAgBxC"}
1
+ {"version":3,"file":"UsageToast.d.ts","sourceRoot":"","sources":["../../src/components/UsageToast.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAK5B,UAAU,eAAe;IACvB,MAAM,EAAE,GAAG,CAAC;IACZ,QAAQ,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;IACrE,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,QAAyB,EACzB,UAAU,GACX,EAAE,eAAe,kDAmJjB;AAED,wBAAgB,aAAa;6BAIK,GAAG;;;;EAgBpC"}
@@ -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 };