@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.
- package/dist/components/AiContextButton.d.ts +1 -1
- 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 +19 -3
- package/dist/components/AiInput.d.ts +1 -1
- package/dist/components/AiInput.d.ts.map +1 -1
- package/dist/components/AiInput.js +21 -5
- package/dist/components/AiPromptPanel.js +30 -6
- package/dist/components/AiSelect.d.ts +1 -1
- package/dist/components/AiSelect.d.ts.map +1 -1
- package/dist/components/AiSelect.js +18 -2
- package/dist/components/AiStatusButton.d.ts.map +1 -1
- package/dist/components/AiStatusButton.js +18 -4
- package/dist/components/AiTextarea.d.ts +2 -1
- package/dist/components/AiTextarea.d.ts.map +1 -1
- package/dist/components/AiTextarea.js +25 -6
- package/dist/components/ErrorToast.js +3 -3
- package/dist/components/LBKeyPicker.js +9 -9
- package/dist/components/LBSigninModal.d.ts.map +1 -1
- package/dist/components/UsageToast.d.ts +3 -3
- package/dist/components/UsageToast.d.ts.map +1 -1
- package/dist/context/LBAuthProvider.d.ts +2 -0
- package/dist/context/LBAuthProvider.d.ts.map +1 -1
- package/dist/context/LBAuthProvider.js +43 -10
- package/dist/examples/AiImageGenerator.js +1 -1
- package/dist/hooks/useAiStatus.d.ts.map +1 -1
- package/dist/hooks/useAiStatus.js +58 -5
- package/dist/styles.css +3 -3
- package/dist/utils/errorHandler.d.ts +2 -2
- package/dist/utils/errorHandler.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/AiContextButton.tsx +20 -2
- package/src/components/AiImageButton.tsx +21 -3
- package/src/components/AiInput.tsx +28 -5
- package/src/components/AiPromptPanel.tsx +31 -6
- package/src/components/AiSelect.tsx +21 -3
- package/src/components/AiStatusButton.tsx +35 -10
- package/src/components/AiTextarea.tsx +33 -9
- package/src/components/ErrorToast.tsx +3 -3
- package/src/components/LBKeyPicker.tsx +10 -10
- package/src/components/LBSigninModal.tsx +2 -1
- package/src/components/UsageToast.tsx +4 -4
- package/src/context/LBAuthProvider.tsx +46 -9
- package/src/examples/AiImageGenerator.tsx +1 -1
- package/src/hooks/useAiStatus.ts +62 -5
- package/src/styles.css +3 -3
- package/src/utils/errorHandler.ts +3 -3
- 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]:
|
|
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,
|
|
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"}
|
|
@@ -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
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
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:
|
|
292
|
+
return createPortal(_jsx("div", { style: panelContainerStyle, onKeyDown: handleKeyDown, children: children(renderProps) }), portalRoot);
|
|
274
293
|
}
|
|
275
|
-
return createPortal(_jsxs("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
|
-
...
|
|
299
|
+
...panelContentStyle,
|
|
281
300
|
opacity: isClosing ? 0 : 1,
|
|
282
|
-
transform: isClosing
|
|
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,
|
|
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
|
|
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;
|
|
@@ -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
|
|
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;
|
|
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
|
|
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 =
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
|
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;
|
|
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:
|
|
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:
|
|
10
|
-
toastData:
|
|
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,
|
|
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 };
|