@lastbrain/ai-ui-react 1.0.78 → 1.0.80
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 +12 -6
- package/dist/components/AiImageButton.d.ts.map +1 -1
- package/dist/components/AiImageButton.js +11 -5
- package/dist/components/AiInput.js +4 -4
- package/dist/components/AiPromptPanel.d.ts +2 -0
- package/dist/components/AiPromptPanel.d.ts.map +1 -1
- package/dist/components/AiPromptPanel.js +138 -5
- package/dist/components/AiSelect.js +4 -4
- package/dist/components/AiStatusButton.js +3 -3
- package/dist/components/AiTextarea.d.ts.map +1 -1
- package/dist/components/AiTextarea.js +15 -4
- package/dist/components/LBApiKeySelector.d.ts.map +1 -1
- package/dist/components/LBApiKeySelector.js +12 -2
- package/dist/components/UsageToast.js +1 -1
- package/dist/context/LBAuthProvider.d.ts +3 -1
- package/dist/context/LBAuthProvider.d.ts.map +1 -1
- package/dist/context/LBAuthProvider.js +65 -29
- package/dist/styles.css +6 -4
- package/package.json +1 -1
- package/src/components/AiContextButton.tsx +14 -6
- package/src/components/AiImageButton.tsx +12 -6
- package/src/components/AiInput.tsx +4 -4
- package/src/components/AiPromptPanel.tsx +279 -12
- package/src/components/AiSelect.tsx +4 -4
- package/src/components/AiStatusButton.tsx +3 -3
- package/src/components/AiTextarea.tsx +16 -5
- package/src/components/LBApiKeySelector.tsx +14 -2
- package/src/components/UsageToast.tsx +1 -1
- package/src/context/LBAuthProvider.tsx +84 -30
- package/src/styles.css +6 -4
|
@@ -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,2CAuUtB"}
|
|
@@ -23,21 +23,20 @@ export function AiContextButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId,
|
|
|
23
23
|
const resolvedContextDescription = contextDescription || t("ai.context.description", "Data to analyze");
|
|
24
24
|
let lbStatus;
|
|
25
25
|
let lbHasSession = false;
|
|
26
|
-
let lbHasSelectedKey = false;
|
|
27
26
|
let lbHasSelectedApiKeyCookie = false;
|
|
27
|
+
let lbHasSelectedKey = false;
|
|
28
28
|
let hasLBProvider = false;
|
|
29
29
|
try {
|
|
30
30
|
const lbContext = useLB();
|
|
31
31
|
lbStatus = lbContext.status;
|
|
32
32
|
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
33
|
-
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
34
33
|
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
34
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
35
35
|
hasLBProvider = true;
|
|
36
36
|
}
|
|
37
37
|
catch {
|
|
38
38
|
lbStatus = undefined;
|
|
39
39
|
lbHasSession = false;
|
|
40
|
-
lbHasSelectedKey = false;
|
|
41
40
|
hasLBProvider = false;
|
|
42
41
|
}
|
|
43
42
|
const aiContext = useAiContext();
|
|
@@ -50,7 +49,8 @@ export function AiContextButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId,
|
|
|
50
49
|
const needsApiKeySelection = hasLBProvider &&
|
|
51
50
|
lbStatus === "ready" &&
|
|
52
51
|
lbHasSession &&
|
|
53
|
-
|
|
52
|
+
!lbHasSelectedApiKeyCookie &&
|
|
53
|
+
!lbHasSelectedKey;
|
|
54
54
|
const isAuthReady = !needsApiKeySelection &&
|
|
55
55
|
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
56
56
|
const handleOpenPanel = () => {
|
|
@@ -156,9 +156,15 @@ export function AiContextButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId,
|
|
|
156
156
|
const sizeClass = `ai-size-${size}`;
|
|
157
157
|
const radiusClass = `ai-radius-${radius}`;
|
|
158
158
|
const variantClass = variant === "light" ? "ai-btn--light" : "";
|
|
159
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "relative inline-block ai-glow", children: [_jsx("button", { ...buttonProps, onClick:
|
|
159
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "relative inline-block ai-glow", children: [_jsx("button", { ...buttonProps, onClick: () => {
|
|
160
|
+
if (!isAuthReady) {
|
|
161
|
+
setShowAuthModal(true);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
handleOpenPanel();
|
|
165
|
+
}, disabled: disabled || loading, className: `ai-btn ai-context-btn ${variantClass} ${sizeClass} ${radiusClass} ${className || ""}`, title: !isAuthReady
|
|
160
166
|
? t("auth.required", "Authentication required")
|
|
161
|
-
: t("ai.analyze", "Analyze with AI"), children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "ai-spinner" }), _jsx("span", { children: t("ai.analyzing", "Analyzing...") })] })) : !isAuthReady ? (_jsxs(_Fragment, { children: [_jsx(Lock, { size: 16 }), children || (_jsx("span", { children: t("auth.connectRequired", "Connection required") }))] })) : (_jsxs(_Fragment, { children: [_jsx(Sparkles, { size: 16 }), children || (_jsx("span", { children: t("ai.context.buttonAnalyze", "Analyze") }))] })) }), isOpen ? (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: () => setIsOpen(false), onSubmit: handleSubmit, uiMode: uiMode, models: [], enableModelManagement: true, modelCategory: "text", baseUrl: baseUrl, apiKey: apiKeyId })) : null] }), isResultOpen && analysisResult ? (_jsx("div", { className: "ai-signin-overlay ai-overlay-panel", onClick: (e) => {
|
|
167
|
+
: t("ai.analyze", "Analyze with AI"), children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "ai-spinner" }), _jsx("span", { children: t("ai.analyzing", "Analyzing...") })] })) : !isAuthReady ? (_jsxs(_Fragment, { children: [_jsx(Lock, { size: 16 }), children || (_jsx("span", { children: t("auth.connectRequired", "Connection required") }))] })) : (_jsxs(_Fragment, { children: [_jsx(Sparkles, { size: 16 }), children || (_jsx("span", { children: t("ai.context.buttonAnalyze", "Analyze") }))] })) }), isOpen ? (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: () => setIsOpen(false), onSubmit: handleSubmit, uiMode: uiMode, models: [], enableModelManagement: true, modelCategory: "text", baseUrl: baseUrl, apiKey: apiKeyId, contextPreview: formatContextData(contextData), contextPreviewTitle: resolvedContextDescription })) : null] }), isResultOpen && analysisResult ? (_jsx("div", { className: "ai-signin-overlay ai-overlay-panel", onClick: (e) => {
|
|
162
168
|
if (e.target === e.currentTarget) {
|
|
163
169
|
setIsResultOpen(false);
|
|
164
170
|
setAnalysisResult(null);
|
|
@@ -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,2CA4SpB"}
|
|
@@ -23,22 +23,21 @@ export function AiImageButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, ui
|
|
|
23
23
|
// Rendre l'authentification optionnelle
|
|
24
24
|
let lbStatus;
|
|
25
25
|
let lbHasSession = false;
|
|
26
|
-
let lbHasSelectedKey = false;
|
|
27
26
|
let lbHasSelectedApiKeyCookie = false;
|
|
27
|
+
let lbHasSelectedKey = false;
|
|
28
28
|
let hasLBProvider = false;
|
|
29
29
|
try {
|
|
30
30
|
const lbContext = useLB();
|
|
31
31
|
lbStatus = lbContext.status;
|
|
32
32
|
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
33
|
-
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
34
33
|
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
34
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
35
35
|
hasLBProvider = true;
|
|
36
36
|
}
|
|
37
37
|
catch {
|
|
38
38
|
// LBProvider n'est pas disponible, ignorer
|
|
39
39
|
lbStatus = undefined;
|
|
40
40
|
lbHasSession = false;
|
|
41
|
-
lbHasSelectedKey = false;
|
|
42
41
|
hasLBProvider = false;
|
|
43
42
|
}
|
|
44
43
|
// Récupérer le contexte AiProvider avec fallback sur les props
|
|
@@ -50,7 +49,8 @@ export function AiImageButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, ui
|
|
|
50
49
|
const needsApiKeySelection = hasLBProvider &&
|
|
51
50
|
lbStatus === "ready" &&
|
|
52
51
|
lbHasSession &&
|
|
53
|
-
|
|
52
|
+
!lbHasSelectedApiKeyCookie &&
|
|
53
|
+
!lbHasSelectedKey;
|
|
54
54
|
const isAuthReady = !needsApiKeySelection &&
|
|
55
55
|
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
56
56
|
const handleOpenPanel = () => {
|
|
@@ -150,7 +150,13 @@ export function AiImageButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, ui
|
|
|
150
150
|
const sizeClass = `ai-size-${size}`;
|
|
151
151
|
const radiusClass = `ai-radius-${radius}`;
|
|
152
152
|
const variantClass = variant === "light" ? "ai-btn--light" : "";
|
|
153
|
-
return (_jsxs("div", { className: "flex items-start gap-4", children: [_jsxs("div", { className: "relative inline-block ai-glow", children: [_jsx("button", { ...buttonProps, onClick:
|
|
153
|
+
return (_jsxs("div", { className: "flex items-start gap-4", children: [_jsxs("div", { className: "relative inline-block ai-glow", children: [_jsx("button", { ...buttonProps, onClick: () => {
|
|
154
|
+
if (!isAuthReady) {
|
|
155
|
+
setShowAuthModal(true);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
handleOpenPanel();
|
|
159
|
+
}, disabled: disabled || loading, className: `ai-btn ai-image-btn ${variantClass} ${sizeClass} ${radiusClass} ${className || ""}`, style: buttonProps.style, "data-ai-image-button": true, title: !isAuthReady
|
|
154
160
|
? t("auth.required", "Authentication required")
|
|
155
161
|
: t("ai.image.generate", "Generate image"), children: loading ? (_jsxs("span", { className: "ai-loading-stack", children: [_jsxs("span", { className: "ai-loading-row", children: [_jsx(Loader2, { size: 18, className: "ai-spinner" }), _jsx("span", { className: "ai-text-microtracking", children: t("ai.image.generating", "Generating...") })] }), _jsx("span", { className: "ai-loading-meta", children: t("ai.loading.elapsed", "{seconds}", {
|
|
156
162
|
seconds: loadingElapsed,
|
|
@@ -23,22 +23,21 @@ export function AiInput({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode =
|
|
|
23
23
|
// Rendre l'authentification optionnelle
|
|
24
24
|
let lbStatus;
|
|
25
25
|
let lbHasSession = false;
|
|
26
|
-
let lbHasSelectedKey = false;
|
|
27
26
|
let lbHasSelectedApiKeyCookie = false;
|
|
27
|
+
let lbHasSelectedKey = false;
|
|
28
28
|
let hasLBProvider = false;
|
|
29
29
|
try {
|
|
30
30
|
const lbContext = useLB();
|
|
31
31
|
lbStatus = lbContext.status;
|
|
32
32
|
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
33
|
-
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
34
33
|
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
34
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
35
35
|
hasLBProvider = true;
|
|
36
36
|
}
|
|
37
37
|
catch {
|
|
38
38
|
// LBProvider n'est pas disponible, ignorer
|
|
39
39
|
lbStatus = undefined;
|
|
40
40
|
lbHasSession = false;
|
|
41
|
-
lbHasSelectedKey = false;
|
|
42
41
|
hasLBProvider = false;
|
|
43
42
|
}
|
|
44
43
|
let ctxBaseUrl;
|
|
@@ -65,7 +64,8 @@ export function AiInput({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode =
|
|
|
65
64
|
const needsApiKeySelection = hasLBProvider &&
|
|
66
65
|
lbStatus === "ready" &&
|
|
67
66
|
lbHasSession &&
|
|
68
|
-
|
|
67
|
+
!lbHasSelectedApiKeyCookie &&
|
|
68
|
+
!lbHasSelectedKey;
|
|
69
69
|
const isAuthReady = !needsApiKeySelection &&
|
|
70
70
|
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
71
71
|
const shouldShowSparkles = isAuthReady && !disabled;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiPromptPanel.d.ts","sourceRoot":"","sources":["../../src/components/AiPromptPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,
|
|
1
|
+
{"version":3,"file":"AiPromptPanel.d.ts","sourceRoot":"","sources":["../../src/components/AiPromptPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAcf,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AASvC,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAkBrD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,SAAS,CAAC;IAE1D,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,IAAI,CAAC;IAExB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,2CA0BtD"}
|
|
@@ -1,9 +1,9 @@
|
|
|
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 { useState, useEffect, useRef, useLayoutEffect, } from "react";
|
|
4
|
+
import { useState, useEffect, useRef, useLayoutEffect, useMemo, } from "react";
|
|
5
5
|
import { createPortal } from "react-dom";
|
|
6
|
-
import { BookOpen, Search, Sparkles, Star, Tag, Settings, Loader2, } from "lucide-react";
|
|
6
|
+
import { BookOpen, Check, Copy, Eye, Search, Sparkles, Star, Tag, Settings, Loader2, } from "lucide-react";
|
|
7
7
|
import { aiStyles } from "../styles/inline";
|
|
8
8
|
import { handleAIError } from "../utils/errorHandler";
|
|
9
9
|
import { usePrompts, } from "../hooks/usePrompts";
|
|
@@ -11,6 +11,19 @@ import { useModelManagement } from "../hooks/useModelManagement";
|
|
|
11
11
|
import { AiProvider, useAiContext } from "../context/AiProvider";
|
|
12
12
|
import { useI18n } from "../context/I18nContext";
|
|
13
13
|
import { useLoadingTimer } from "../hooks/useLoadingTimer";
|
|
14
|
+
function tryFormatJson(input) {
|
|
15
|
+
const raw = (input || "").trim();
|
|
16
|
+
if (!raw) {
|
|
17
|
+
return { formatted: "", isJson: false };
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(raw);
|
|
21
|
+
return { formatted: JSON.stringify(parsed, null, 2), isJson: true };
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return { formatted: input || "", isJson: false };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
14
27
|
export function AiPromptPanel(props) {
|
|
15
28
|
const { apiKey, baseUrl } = props;
|
|
16
29
|
let hasContext = false;
|
|
@@ -32,7 +45,7 @@ export function AiPromptPanel(props) {
|
|
|
32
45
|
// Sinon, utiliser le contexte existant
|
|
33
46
|
return _jsx(AiPromptPanelInternal, { ...props });
|
|
34
47
|
}
|
|
35
|
-
function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode = "modal", models = [], sourceText, children, enableModelManagement = true, modelCategory = "text", availableModels = [], userModels = [], onModelToggle, apiKey, baseUrl, showOnlyUserModels = false, }) {
|
|
48
|
+
function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode = "modal", models = [], sourceText, children, enableModelManagement = true, modelCategory = "text", availableModels = [], userModels = [], onModelToggle, apiKey, baseUrl, showOnlyUserModels = false, contextPreview, contextPreviewTitle, }) {
|
|
36
49
|
const { t } = useI18n();
|
|
37
50
|
const [selectedModel, setSelectedModel] = useState("");
|
|
38
51
|
const [prompt, setPrompt] = useState("");
|
|
@@ -45,6 +58,8 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode = "modal", mo
|
|
|
45
58
|
const [selectedTag, setSelectedTag] = useState("all");
|
|
46
59
|
const [isGenerating, setIsGenerating] = useState(false);
|
|
47
60
|
const [isClosing, setIsClosing] = useState(false);
|
|
61
|
+
const [showContextPreview, setShowContextPreview] = useState(false);
|
|
62
|
+
const [contextCopied, setContextCopied] = useState(false);
|
|
48
63
|
const [portalRoot, setPortalRoot] = useState(null);
|
|
49
64
|
const promptRef = useRef(null);
|
|
50
65
|
const closeTimeoutRef = useRef(null);
|
|
@@ -157,6 +172,8 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode = "modal", mo
|
|
|
157
172
|
setPrompt("");
|
|
158
173
|
setPromptId(undefined);
|
|
159
174
|
setShowPromptLibrary(false);
|
|
175
|
+
setShowContextPreview(false);
|
|
176
|
+
setContextCopied(false);
|
|
160
177
|
setSearchQuery("");
|
|
161
178
|
setSelectedTag("all");
|
|
162
179
|
setIsClosing(false);
|
|
@@ -177,6 +194,12 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode = "modal", mo
|
|
|
177
194
|
}
|
|
178
195
|
};
|
|
179
196
|
}, []);
|
|
197
|
+
useEffect(() => {
|
|
198
|
+
if (!contextCopied)
|
|
199
|
+
return;
|
|
200
|
+
const timeout = window.setTimeout(() => setContextCopied(false), 1200);
|
|
201
|
+
return () => window.clearTimeout(timeout);
|
|
202
|
+
}, [contextCopied]);
|
|
180
203
|
useEffect(() => {
|
|
181
204
|
setPortalRoot(document.body);
|
|
182
205
|
}, []);
|
|
@@ -221,6 +244,8 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode = "modal", mo
|
|
|
221
244
|
useLayoutEffect(() => {
|
|
222
245
|
adjustPromptHeight();
|
|
223
246
|
}, [prompt]);
|
|
247
|
+
const contextPreviewData = useMemo(() => tryFormatJson(contextPreview), [contextPreview]);
|
|
248
|
+
const contextPreviewLines = useMemo(() => contextPreviewData.formatted.split("\n"), [contextPreviewData.formatted]);
|
|
224
249
|
if (!isOpen)
|
|
225
250
|
return null;
|
|
226
251
|
const activeModelId = selectedModel || modelOptions[0]?.id || "";
|
|
@@ -270,6 +295,8 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode = "modal", mo
|
|
|
270
295
|
return null;
|
|
271
296
|
}
|
|
272
297
|
const isDrawer = uiMode === "drawer";
|
|
298
|
+
const hasContextPreview = Boolean(contextPreview?.trim());
|
|
299
|
+
const contextCharCount = contextPreview?.length || 0;
|
|
273
300
|
const panelContainerStyle = isDrawer
|
|
274
301
|
? {
|
|
275
302
|
...aiStyles.modal,
|
|
@@ -288,6 +315,40 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode = "modal", mo
|
|
|
288
315
|
borderRadius: "16px 0 0 16px",
|
|
289
316
|
}
|
|
290
317
|
: aiStyles.modalContent;
|
|
318
|
+
const renderContextLine = (line, lineIndex) => {
|
|
319
|
+
if (!contextPreviewData.isJson) {
|
|
320
|
+
return (_jsx("span", { style: { color: "var(--ai-text-secondary)" }, children: line || " " }, `line-${lineIndex}`));
|
|
321
|
+
}
|
|
322
|
+
const tokenRegex = /("(?:\\.|[^"\\])*"(?=\s*:)|"(?:\\.|[^"\\])*"|true|false|null|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|[{}[\],:])/g;
|
|
323
|
+
const parts = [];
|
|
324
|
+
let lastIndex = 0;
|
|
325
|
+
let match;
|
|
326
|
+
while ((match = tokenRegex.exec(line)) !== null) {
|
|
327
|
+
const token = match[0];
|
|
328
|
+
const index = match.index;
|
|
329
|
+
if (index > lastIndex) {
|
|
330
|
+
parts.push(_jsx("span", { style: { color: "var(--ai-text-secondary)" }, children: line.slice(lastIndex, index) }, `txt-${lineIndex}-${lastIndex}`));
|
|
331
|
+
}
|
|
332
|
+
const isKey = /^".*"$/.test(token) && line.slice(match.index).includes(":");
|
|
333
|
+
const color = isKey
|
|
334
|
+
? "#7cc5ff"
|
|
335
|
+
: /^".*"$/.test(token)
|
|
336
|
+
? "#9ad07f"
|
|
337
|
+
: /^(true|false)$/.test(token)
|
|
338
|
+
? "#f4a259"
|
|
339
|
+
: token === "null"
|
|
340
|
+
? "#d3869b"
|
|
341
|
+
: /^-?\d/.test(token)
|
|
342
|
+
? "#f7dc6f"
|
|
343
|
+
: "var(--ai-text-secondary)";
|
|
344
|
+
parts.push(_jsx("span", { style: { color }, children: token }, `tok-${lineIndex}-${index}`));
|
|
345
|
+
lastIndex = index + token.length;
|
|
346
|
+
}
|
|
347
|
+
if (lastIndex < line.length) {
|
|
348
|
+
parts.push(_jsx("span", { style: { color: "var(--ai-text-secondary)" }, children: line.slice(lastIndex) }, `txt-end-${lineIndex}`));
|
|
349
|
+
}
|
|
350
|
+
return (_jsx("span", { style: { whiteSpace: "pre" }, children: parts.length > 0 ? parts : " " }, `line-${lineIndex}`));
|
|
351
|
+
};
|
|
291
352
|
if (children) {
|
|
292
353
|
return createPortal(_jsx("div", { style: panelContainerStyle, onKeyDown: handleKeyDown, children: children(renderProps) }), portalRoot);
|
|
293
354
|
}
|
|
@@ -417,7 +478,13 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode = "modal", mo
|
|
|
417
478
|
marginLeft: "4px",
|
|
418
479
|
fontSize: "12px",
|
|
419
480
|
fontWeight: 400,
|
|
420
|
-
}, children: t("prompt.modal.promptHint", "(Cmd/Ctrl + Enter to submit)") })] }),
|
|
481
|
+
}, children: t("prompt.modal.promptHint", "(Cmd/Ctrl + Enter to submit)") })] }), _jsxs("div", { style: {
|
|
482
|
+
display: "flex",
|
|
483
|
+
alignItems: "center",
|
|
484
|
+
flexWrap: "wrap",
|
|
485
|
+
justifyContent: "flex-end",
|
|
486
|
+
gap: "8px",
|
|
487
|
+
}, children: [hasContextPreview ? (_jsxs("button", { type: "button", onClick: () => setShowContextPreview(true), className: "ai-inline-btn", style: { whiteSpace: "nowrap" }, children: [_jsx(Eye, { size: 14 }), t("prompt.modal.contextPreview", "Context preview")] })) : null, promptsLoading ? (_jsx("span", { className: "ai-inline-skeleton", "aria-hidden": "true" })) : filteredPrompts.length > 0 ? (_jsxs("button", { onClick: () => setShowPromptLibrary(true), className: "ai-inline-btn", style: { whiteSpace: "nowrap" }, children: [_jsx(BookOpen, { size: 14 }), t("prompt.modal.browsePrompts", "Browse Prompts"), " (", filteredPrompts.length, ")"] })) : null] })] }), _jsx("textarea", { id: "prompt-input", ref: promptRef, value: prompt, onChange: (e) => setPrompt(e.target.value), onFocus: () => setPromptFocused(true), onBlur: () => setPromptFocused(false), placeholder: sourceText
|
|
421
488
|
? t("prompt.modal.promptPlaceholderWithSource", "Enter your AI prompt... e.g., 'Fix grammar', 'Make it more professional', 'Translate to English'")
|
|
422
489
|
: t("prompt.modal.promptPlaceholderNoSource", "Enter your AI prompt... e.g., 'Write a blog post about AI', 'Generate product description'"), rows: 6, style: {
|
|
423
490
|
...aiStyles.textarea,
|
|
@@ -575,7 +642,73 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode = "modal", mo
|
|
|
575
642
|
marginTop: "8px",
|
|
576
643
|
fontSize: "11px",
|
|
577
644
|
color: "var(--ai-primary)",
|
|
578
|
-
}, children: String(promptData.category) })) : null] }, promptData.id))) })] }))] }))] })) }),
|
|
645
|
+
}, children: String(promptData.category) })) : null] }, promptData.id))) })] }))] }))] })) }), showContextPreview ? (_jsx("div", { style: {
|
|
646
|
+
position: "absolute",
|
|
647
|
+
inset: 0,
|
|
648
|
+
zIndex: 12,
|
|
649
|
+
background: "var(--ai-overlay)",
|
|
650
|
+
backdropFilter: "blur(3px)",
|
|
651
|
+
WebkitBackdropFilter: "blur(3px)",
|
|
652
|
+
display: "flex",
|
|
653
|
+
alignItems: "stretch",
|
|
654
|
+
justifyContent: "center",
|
|
655
|
+
padding: "10px",
|
|
656
|
+
}, onClick: () => setShowContextPreview(false), children: _jsxs("div", { style: {
|
|
657
|
+
width: "min(980px, 100%)",
|
|
658
|
+
maxHeight: "100%",
|
|
659
|
+
background: "var(--ai-bg-secondary)",
|
|
660
|
+
border: "1px solid var(--ai-border)",
|
|
661
|
+
borderRadius: "12px",
|
|
662
|
+
boxShadow: "var(--ai-shadow-lg)",
|
|
663
|
+
overflow: "hidden",
|
|
664
|
+
display: "flex",
|
|
665
|
+
flexDirection: "column",
|
|
666
|
+
}, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { style: {
|
|
667
|
+
padding: "12px 14px",
|
|
668
|
+
borderBottom: "1px solid var(--ai-border)",
|
|
669
|
+
display: "flex",
|
|
670
|
+
alignItems: "center",
|
|
671
|
+
justifyContent: "space-between",
|
|
672
|
+
gap: "10px",
|
|
673
|
+
}, children: [_jsxs("div", { style: { minWidth: 0 }, children: [_jsx("div", { style: { fontSize: "14px", fontWeight: 600 }, children: contextPreviewTitle ||
|
|
674
|
+
t("prompt.modal.contextPreview", "Context preview") }), _jsx("div", { style: {
|
|
675
|
+
marginTop: "2px",
|
|
676
|
+
fontSize: "12px",
|
|
677
|
+
color: "var(--ai-text-secondary)",
|
|
678
|
+
}, children: t("prompt.modal.contextChars", "{count} chars", {
|
|
679
|
+
count: contextCharCount.toLocaleString(),
|
|
680
|
+
}) })] }), _jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [_jsxs("button", { type: "button", className: "ai-inline-btn", onClick: async () => {
|
|
681
|
+
try {
|
|
682
|
+
await navigator.clipboard.writeText(contextPreviewData.formatted || "");
|
|
683
|
+
setContextCopied(true);
|
|
684
|
+
}
|
|
685
|
+
catch {
|
|
686
|
+
setContextCopied(false);
|
|
687
|
+
}
|
|
688
|
+
}, style: { whiteSpace: "nowrap" }, children: [contextCopied ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }), contextCopied
|
|
689
|
+
? t("common.copied", "Copied")
|
|
690
|
+
: t("common.copy", "Copy")] }), _jsx("button", { type: "button", className: "ai-icon-btn", onClick: () => setShowContextPreview(false), "aria-label": t("common.closeLabel", "Close"), children: "\u00D7" })] })] }), _jsx("pre", { style: {
|
|
691
|
+
margin: 0,
|
|
692
|
+
padding: "14px",
|
|
693
|
+
flex: 1,
|
|
694
|
+
overflow: "auto",
|
|
695
|
+
background: "color-mix(in srgb, var(--ai-bg) 70%, transparent)",
|
|
696
|
+
borderTop: "1px solid var(--ai-border)",
|
|
697
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
|
|
698
|
+
fontSize: "12px",
|
|
699
|
+
lineHeight: 1.5,
|
|
700
|
+
}, children: contextPreviewLines.map((line, index) => (_jsxs("div", { style: {
|
|
701
|
+
display: "grid",
|
|
702
|
+
gridTemplateColumns: "44px 1fr",
|
|
703
|
+
gap: "12px",
|
|
704
|
+
minHeight: "18px",
|
|
705
|
+
}, children: [_jsx("span", { style: {
|
|
706
|
+
color: "var(--ai-text-tertiary)",
|
|
707
|
+
textAlign: "right",
|
|
708
|
+
userSelect: "none",
|
|
709
|
+
paddingRight: "8px",
|
|
710
|
+
borderRight: "1px solid var(--ai-border)",
|
|
711
|
+
}, children: index + 1 }), renderContextLine(line, index)] }, `context-line-${index}`))) })] }) })) : null, _jsxs("div", { style: {
|
|
579
712
|
...aiStyles.modalFooter,
|
|
580
713
|
position: "sticky",
|
|
581
714
|
bottom: 0,
|
|
@@ -20,22 +20,21 @@ export function AiSelect({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode
|
|
|
20
20
|
// Rendre l'authentification optionnelle
|
|
21
21
|
let lbStatus;
|
|
22
22
|
let lbHasSession = false;
|
|
23
|
-
let lbHasSelectedKey = false;
|
|
24
23
|
let lbHasSelectedApiKeyCookie = false;
|
|
24
|
+
let lbHasSelectedKey = false;
|
|
25
25
|
let hasLBProvider = false;
|
|
26
26
|
try {
|
|
27
27
|
const lbContext = useLB();
|
|
28
28
|
lbStatus = lbContext.status;
|
|
29
29
|
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
30
|
-
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
31
30
|
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
31
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
32
32
|
hasLBProvider = true;
|
|
33
33
|
}
|
|
34
34
|
catch {
|
|
35
35
|
// LBProvider n'est pas disponible, ignorer
|
|
36
36
|
lbStatus = undefined;
|
|
37
37
|
lbHasSession = false;
|
|
38
|
-
lbHasSelectedKey = false;
|
|
39
38
|
hasLBProvider = false;
|
|
40
39
|
}
|
|
41
40
|
let ctxBaseUrl;
|
|
@@ -60,7 +59,8 @@ export function AiSelect({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode
|
|
|
60
59
|
const needsApiKeySelection = hasLBProvider &&
|
|
61
60
|
lbStatus === "ready" &&
|
|
62
61
|
lbHasSession &&
|
|
63
|
-
|
|
62
|
+
!lbHasSelectedApiKeyCookie &&
|
|
63
|
+
!lbHasSelectedKey;
|
|
64
64
|
const isAuthReady = !needsApiKeySelection &&
|
|
65
65
|
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
66
66
|
const shouldShowSparkles = isAuthReady && !disabled;
|
|
@@ -135,8 +135,8 @@ export function AiStatusButton({ status, loading = false, className = "", size =
|
|
|
135
135
|
const hasLbSession = Boolean(lbSessionToken);
|
|
136
136
|
const requiresApiKeySelection = lbStatus === "ready" &&
|
|
137
137
|
hasLbSession &&
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
!lbHasSelectedApiKeyCookie &&
|
|
139
|
+
!hasApiKeySelected;
|
|
140
140
|
const isApiKeyAuthMode = authTypeValue === "api_key";
|
|
141
141
|
const [tooltipStyle, setTooltipStyle] = useState({});
|
|
142
142
|
useEffect(() => {
|
|
@@ -337,7 +337,7 @@ export function AiStatusButton({ status, loading = false, className = "", size =
|
|
|
337
337
|
}
|
|
338
338
|
}, disabled: loading || isSelectingApiKey, title: requiresApiKeySelection
|
|
339
339
|
? t("status.selectApiKey", "Select an API key")
|
|
340
|
-
: t("status.view", "View status"), "aria-label": t("status.aiStatusAria", "AI status"), children: renderTriggerIcon() }), showCornerLoading ? (_jsx("span", { className: "ai-status-loading-dot", "aria-hidden": "true", children: _jsx(Loader2, { size: 7, className: "ai-spinner" }) })) : null] }), tooltipNode, showApiKeySelector
|
|
340
|
+
: t("status.view", "View status"), "aria-label": t("status.aiStatusAria", "AI status"), children: renderTriggerIcon() }), showCornerLoading ? (_jsx("span", { className: "ai-status-loading-dot", "aria-hidden": "true", children: _jsx(Loader2, { size: 7, className: "ai-spinner" }) })) : null] }), tooltipNode, showApiKeySelector ? (_jsx(LBApiKeySelector, { isOpen: showApiKeySelector, apiKeys: apiKeys, onSelect: async (keyId) => {
|
|
341
341
|
setIsSelectingApiKey(true);
|
|
342
342
|
try {
|
|
343
343
|
if (!switchApiKey) {
|
|
@@ -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,2CAgRjB"}
|
|
@@ -25,15 +25,15 @@ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMod
|
|
|
25
25
|
// Rendre l'authentification optionnelle
|
|
26
26
|
let lbStatus;
|
|
27
27
|
let lbHasSession = false;
|
|
28
|
-
let lbHasSelectedKey = false;
|
|
29
28
|
let lbHasSelectedApiKeyCookie = false;
|
|
29
|
+
let lbHasSelectedKey = false;
|
|
30
30
|
let hasLBProvider = false;
|
|
31
31
|
try {
|
|
32
32
|
const lbContext = useLB();
|
|
33
33
|
lbStatus = lbContext.status;
|
|
34
34
|
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
35
|
-
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
36
35
|
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
36
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
37
37
|
hasLBProvider = true;
|
|
38
38
|
}
|
|
39
39
|
catch {
|
|
@@ -57,7 +57,8 @@ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMod
|
|
|
57
57
|
const needsApiKeySelection = hasLBProvider &&
|
|
58
58
|
lbStatus === "ready" &&
|
|
59
59
|
lbHasSession &&
|
|
60
|
-
|
|
60
|
+
!lbHasSelectedApiKeyCookie &&
|
|
61
|
+
!lbHasSelectedKey;
|
|
61
62
|
const { models: _models } = useAiModels({
|
|
62
63
|
baseUrl,
|
|
63
64
|
apiKeyId,
|
|
@@ -177,7 +178,17 @@ export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMod
|
|
|
177
178
|
adjustHeight();
|
|
178
179
|
}, onBlur: (e) => {
|
|
179
180
|
textareaProps.onBlur?.(e);
|
|
180
|
-
}, "aria-invalid": Boolean(textareaProps["aria-invalid"]), disabled: disabled || loading }), _jsx("button", { className: `ai-control-action ai-spark ${sizeClass} ${radiusClass}`, onClick:
|
|
181
|
+
}, "aria-invalid": Boolean(textareaProps["aria-invalid"]), disabled: disabled || loading }), _jsx("button", { className: `ai-control-action ai-spark ${sizeClass} ${radiusClass}`, onClick: () => {
|
|
182
|
+
if (!isAuthReady) {
|
|
183
|
+
setShowAuthModal(true);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (hasConfiguration) {
|
|
187
|
+
void handleQuickGenerate();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
handleOpenPanel();
|
|
191
|
+
}, disabled: disabled || loading, type: "button", title: !isAuthReady
|
|
181
192
|
? t("auth.required", "Authentication required")
|
|
182
193
|
: hasConfiguration
|
|
183
194
|
? t("ai.generate", "Generate with AI")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LBApiKeySelector.d.ts","sourceRoot":"","sources":["../../src/components/LBApiKeySelector.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LBApiKeySelector.d.ts","sourceRoot":"","sources":["../../src/components/LBApiKeySelector.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,UAAU,qBAAqB;IAC7B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,MAAM,GACP,EAAE,qBAAqB,kDAmKvB"}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useState } from "react";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
4
|
import { CheckCircle2, KeyRound, Loader2, XCircle } from "lucide-react";
|
|
5
|
+
import { createPortal } from "react-dom";
|
|
5
6
|
import { useI18n } from "../context/I18nContext";
|
|
6
7
|
export function LBApiKeySelector({ apiKeys, onSelect, onCancel, isOpen, }) {
|
|
7
8
|
const { t } = useI18n();
|
|
9
|
+
const [canPortal, setCanPortal] = useState(false);
|
|
8
10
|
const [selectedKeyId, setSelectedKeyId] = useState(apiKeys.find((k) => k.isActive)?.id || apiKeys[0]?.id || "");
|
|
9
11
|
const [loading, setLoading] = useState(false);
|
|
10
12
|
const [error, setError] = useState("");
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
setCanPortal(true);
|
|
15
|
+
return () => setCanPortal(false);
|
|
16
|
+
}, []);
|
|
11
17
|
if (!isOpen)
|
|
12
18
|
return null;
|
|
13
19
|
const handleSubmit = async (e) => {
|
|
@@ -30,7 +36,7 @@ export function LBApiKeySelector({ apiKeys, onSelect, onCancel, isOpen, }) {
|
|
|
30
36
|
setLoading(false);
|
|
31
37
|
}
|
|
32
38
|
};
|
|
33
|
-
|
|
39
|
+
const modal = (_jsx("div", { className: "ai-signin-overlay", onClick: onCancel, children: _jsxs("div", { className: "ai-signin-panel ai-key-modal-panel", onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "ai-signin-header", children: [_jsx("div", { className: "ai-center mb-3", children: _jsx("span", { className: "ai-icon-badge", children: _jsx(KeyRound, { size: 20 }) }) }), _jsx("h2", { className: "ai-signin-title", children: t("status.selectApiKey", "Select an API key") }), _jsx("p", { className: "ai-signin-subtitle", children: t("status.selectApiKeySubtitle", "Choose the API key to use for your AI requests.") })] }), _jsx("div", { className: "ai-signin-content", children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsx("div", { className: "ai-model-mgmt-list", style: { maxHeight: 300, overflowY: "auto", marginBottom: 16 }, children: apiKeys.map((key) => {
|
|
34
40
|
const isSelected = key.id === selectedKeyId;
|
|
35
41
|
const isActive = key.isActive;
|
|
36
42
|
const rawEnv = key.env;
|
|
@@ -38,4 +44,8 @@ export function LBApiKeySelector({ apiKeys, onSelect, onCancel, isOpen, }) {
|
|
|
38
44
|
const isDev = rawEnv === "dev";
|
|
39
45
|
return (_jsxs("label", { className: `ai-model-item ${isSelected ? "ai-model-item--active" : ""} ${!isActive ? "ai-model-item--disabled" : ""}`, children: [_jsxs("div", { className: "ai-model-item-main", children: [_jsx("input", { type: "radio", name: "apiKey", value: key.id, checked: isSelected, disabled: !isActive, onChange: (e) => setSelectedKeyId(e.target.value), className: "ai-key-radio" }), _jsxs("div", { children: [_jsx("div", { className: "ai-model-item-title", children: key.name }), _jsxs("div", { className: "ai-model-item-meta", children: [_jsx("span", { children: key.keyPrefix || key.id.substring(0, 12) + "..." }), _jsx("span", { className: `ai-pill ai-pill--cost ${isDev ? "ai-pill--warning" : ""}`, style: { marginLeft: 8 }, children: keyEnv })] })] })] }), isActive ? (_jsxs("span", { className: "ai-pill ai-pill--cost", children: [_jsx(CheckCircle2, { size: 12 }), t("common.active", "Active")] })) : (_jsxs("span", { className: "ai-pill ai-pill--cost", children: [_jsx(XCircle, { size: 12 }), t("common.inactive", "Inactive")] }))] }, key.id));
|
|
40
46
|
}) }), error ? (_jsxs("div", { className: "ai-signin-error", role: "alert", children: [_jsx(XCircle, { size: 16 }), _jsx("span", { children: error })] })) : null, _jsxs("div", { className: "ai-signin-actions", children: [_jsx("button", { type: "button", onClick: onCancel, disabled: loading, className: "ai-btn ai-btn--ghost", children: t("common.cancel", "Cancel") }), _jsx("button", { type: "submit", disabled: loading || !selectedKeyId, className: "ai-btn ai-btn--primary", children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "ai-spinner" }), t("auth.modal.connecting", "Signing in...")] })) : (t("common.continue", "Continue")) })] })] }) })] }) }));
|
|
47
|
+
if (!canPortal) {
|
|
48
|
+
return modal;
|
|
49
|
+
}
|
|
50
|
+
return createPortal(modal, document.body);
|
|
41
51
|
}
|
|
@@ -100,7 +100,7 @@ export function UsageToast({ result, position = "bottom-right", onComplete, }) {
|
|
|
100
100
|
padding: "4px 6px",
|
|
101
101
|
borderRadius: "6px",
|
|
102
102
|
marginBottom: "4px",
|
|
103
|
-
right: "
|
|
103
|
+
right: "52px",
|
|
104
104
|
background: "rgba(22, 163, 74, 0.12)",
|
|
105
105
|
border: "1px solid rgba(22, 163, 74, 0.3)",
|
|
106
106
|
color: "#16a34a",
|
|
@@ -25,6 +25,8 @@ export interface BasicStatus {
|
|
|
25
25
|
used?: number;
|
|
26
26
|
total?: number;
|
|
27
27
|
percentage?: number;
|
|
28
|
+
remaining?: number;
|
|
29
|
+
providerBudget?: number;
|
|
28
30
|
};
|
|
29
31
|
storage?: StorageStatus["storage"];
|
|
30
32
|
}
|
|
@@ -88,7 +90,7 @@ interface LBContextValue extends LBAuthState {
|
|
|
88
90
|
isLoadingStatus: boolean;
|
|
89
91
|
/** Indique si le storage est en cours de chargement */
|
|
90
92
|
isLoadingStorage: boolean;
|
|
91
|
-
/** True si le cookie api_key_selected est présent */
|
|
93
|
+
/** True si le cookie api_key_selected est présent (info backend) */
|
|
92
94
|
hasSelectedApiKeyCookie: boolean;
|
|
93
95
|
}
|
|
94
96
|
declare const LBContext: import("react").Context<LBContextValue | undefined>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LBAuthProvider.d.ts","sourceRoot":"","sources":["../../src/context/LBAuthProvider.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EAGR,QAAQ,EACT,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAEnE,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE;QACL,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,IAAI,CAAC;IACT,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC3B,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"LBAuthProvider.d.ts","sourceRoot":"","sources":["../../src/context/LBAuthProvider.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EAGR,QAAQ,EACT,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAEnE,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE;QACL,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,IAAI,CAAC;IACT,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC3B,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,OAAO,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,IAAI,CAAC;CACV;AAgBD,UAAU,eAAe;IACvB,QAAQ,EAAE,SAAS,CAAC;IACpB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IACzD,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,mDAAmD;IACnD,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB;AAED,UAAU,cAAe,SAAQ,WAAW;IAC1C,4BAA4B;IAC5B,KAAK,EAAE,CACL,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC;QACX,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH,8BAA8B;IAC9B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,6CAA6C;IAC7C,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC3D,gEAAgE;IAChE,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,mDAAmD;IACnD,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,iEAAiE;IACjE,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,oCAAoC;IACpC,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,2BAA2B;IAC3B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,mEAAmE;IACnE,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,uCAAuC;IACvC,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IACpC,gDAAgD;IAChD,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,iEAAiE;IACjE,oBAAoB,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,kEAAkE;IAClE,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,8DAA8D;IAC9D,eAAe,EAAE,OAAO,CAAC;IACzB,uDAAuD;IACvD,gBAAgB,EAAE,OAAO,CAAC;IAC1B,oEAAoE;IACpE,uBAAuB,EAAE,OAAO,CAAC;CAClC;AAED,QAAA,MAAM,SAAS,qDAAuD,CAAC;AAGvE,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,OAAO,EAAE,QAA2B,EACpC,QAA2B,EAC3B,cAAc,EACd,YAAY,EACZ,IAAW,GACZ,EAAE,eAAe,2CAslBjB;AAED;;GAEG;AACH,wBAAgB,KAAK,IAAI,cAAc,CAMtC;AAGD,YAAY,EAAE,QAAQ,EAAE,CAAC"}
|