@lastbrain/ai-ui-react 1.0.72 → 1.0.74
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/AiChipLabel.d.ts.map +1 -1
- package/dist/components/AiChipLabel.js +10 -7
- package/dist/components/AiContextButton.d.ts +1 -1
- package/dist/components/AiContextButton.d.ts.map +1 -1
- package/dist/components/AiContextButton.js +25 -12
- package/dist/components/AiImageButton.d.ts.map +1 -1
- package/dist/components/AiImageButton.js +32 -16
- package/dist/components/AiInput.d.ts.map +1 -1
- package/dist/components/AiInput.js +15 -5
- package/dist/components/AiModelSelect.d.ts.map +1 -1
- package/dist/components/AiModelSelect.js +3 -1
- package/dist/components/AiPromptPanel.d.ts.map +1 -1
- package/dist/components/AiPromptPanel.js +72 -47
- package/dist/components/AiSelect.d.ts.map +1 -1
- package/dist/components/AiSelect.js +8 -3
- package/dist/components/AiStatusButton.d.ts.map +1 -1
- package/dist/components/AiStatusButton.js +55 -28
- package/dist/components/AiTextarea.d.ts.map +1 -1
- package/dist/components/AiTextarea.js +19 -6
- package/dist/components/ErrorToast.d.ts.map +1 -1
- package/dist/components/ErrorToast.js +4 -2
- package/dist/components/LBApiKeySelector.d.ts.map +1 -1
- package/dist/components/LBApiKeySelector.js +13 -5
- package/dist/components/LBConnectButton.d.ts.map +1 -1
- package/dist/components/LBConnectButton.js +8 -3
- package/dist/components/LBKeyPicker.d.ts.map +1 -1
- package/dist/components/LBKeyPicker.js +8 -4
- package/dist/components/LBSigninModal.d.ts.map +1 -1
- package/dist/components/LBSigninModal.js +13 -7
- package/dist/components/UsageToast.d.ts.map +1 -1
- package/dist/components/UsageToast.js +4 -2
- package/dist/context/I18nContext.d.ts +15 -0
- package/dist/context/I18nContext.d.ts.map +1 -0
- package/dist/context/I18nContext.js +44 -0
- package/dist/context/LBAuthProvider.d.ts +4 -1
- package/dist/context/LBAuthProvider.d.ts.map +1 -1
- package/dist/context/LBAuthProvider.js +3 -2
- package/dist/hooks/useAiCallImage.d.ts.map +1 -1
- package/dist/hooks/useAiCallImage.js +1 -107
- package/dist/hooks/useAiCallText.d.ts.map +1 -1
- package/dist/hooks/useAiCallText.js +1 -25
- package/dist/hooks/useLoadingTimer.d.ts +5 -0
- package/dist/hooks/useLoadingTimer.d.ts.map +1 -0
- package/dist/hooks/useLoadingTimer.js +27 -0
- package/dist/i18n/de.json +62 -0
- package/dist/i18n/en.json +128 -0
- package/dist/i18n/es.json +70 -0
- package/dist/i18n/fr.json +128 -0
- package/dist/i18n/it.json +62 -0
- package/dist/i18n/pt.json +62 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/styles.css +142 -1
- package/package.json +3 -3
- package/src/components/AiChipLabel.tsx +17 -8
- package/src/components/AiContextButton.tsx +44 -20
- package/src/components/AiImageButton.tsx +52 -25
- package/src/components/AiInput.tsx +20 -5
- package/src/components/AiModelSelect.tsx +3 -1
- package/src/components/AiPromptPanel.tsx +177 -59
- package/src/components/AiSelect.tsx +8 -3
- package/src/components/AiStatusButton.tsx +100 -57
- package/src/components/AiTextarea.tsx +24 -6
- package/src/components/ErrorToast.tsx +4 -2
- package/src/components/LBApiKeySelector.tsx +33 -13
- package/src/components/LBConnectButton.tsx +9 -3
- package/src/components/LBKeyPicker.tsx +10 -4
- package/src/components/LBSigninModal.tsx +31 -15
- package/src/components/UsageToast.tsx +4 -2
- package/src/context/I18nContext.tsx +71 -0
- package/src/context/LBAuthProvider.tsx +9 -1
- package/src/hooks/useAiCallImage.ts +1 -149
- package/src/hooks/useAiCallText.ts +1 -30
- package/src/hooks/useLoadingTimer.ts +32 -0
- package/src/i18n/de.json +62 -0
- package/src/i18n/en.json +128 -0
- package/src/i18n/es.json +70 -0
- package/src/i18n/fr.json +128 -0
- package/src/i18n/it.json +62 -0
- package/src/i18n/pt.json +62 -0
- package/src/index.ts +2 -0
- package/src/styles.css +142 -1
|
@@ -3,12 +3,14 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import "../styles/register";
|
|
4
4
|
import { useState, useEffect, useRef, useLayoutEffect, } from "react";
|
|
5
5
|
import { createPortal } from "react-dom";
|
|
6
|
-
import { BookOpen, Search, Sparkles, Star, Tag, Settings } from "lucide-react";
|
|
6
|
+
import { BookOpen, 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";
|
|
10
10
|
import { useModelManagement } from "../hooks/useModelManagement";
|
|
11
11
|
import { AiProvider, useAiContext } from "../context/AiProvider";
|
|
12
|
+
import { useI18n } from "../context/I18nContext";
|
|
13
|
+
import { useLoadingTimer } from "../hooks/useLoadingTimer";
|
|
12
14
|
export function AiPromptPanel(props) {
|
|
13
15
|
const { apiKey, baseUrl } = props;
|
|
14
16
|
let hasContext = false;
|
|
@@ -31,6 +33,7 @@ export function AiPromptPanel(props) {
|
|
|
31
33
|
return _jsx(AiPromptPanelInternal, { ...props });
|
|
32
34
|
}
|
|
33
35
|
function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "modal", models = [], sourceText, children, enableModelManagement = true, modelCategory = "text", availableModels = [], userModels = [], onModelToggle, apiKey, baseUrl, showOnlyUserModels = false, }) {
|
|
36
|
+
const { t } = useI18n();
|
|
34
37
|
const [selectedModel, setSelectedModel] = useState("");
|
|
35
38
|
const [prompt, setPrompt] = useState("");
|
|
36
39
|
const [promptId, setPromptId] = useState(undefined);
|
|
@@ -50,6 +53,7 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
50
53
|
const [isModelManagementOpen, setIsModelManagementOpen] = useState(false);
|
|
51
54
|
const [loadingModels, setLoadingModels] = useState([]);
|
|
52
55
|
const [modelSearchQuery, setModelSearchQuery] = useState("");
|
|
56
|
+
const { formatted: loadingElapsed } = useLoadingTimer(isGenerating);
|
|
53
57
|
const { prompts, loading: promptsLoading, fetchPrompts, incrementStat, } = usePrompts();
|
|
54
58
|
// Hook de gestion des modèles (automatique si enableModelManagement et pas de models/availableModels externes)
|
|
55
59
|
const autoModelManagement = useModelManagement({
|
|
@@ -76,6 +80,7 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
76
80
|
: autoModelManagement.availableModels;
|
|
77
81
|
const effectiveUserModels = userModels.length > 0 ? userModels : autoModelManagement.userModels;
|
|
78
82
|
const effectiveToggleModel = onModelToggle || autoModelManagement.toggleModel;
|
|
83
|
+
const isModelsLoading = autoModelManagement.loading && effectiveAvailableModels.length === 0;
|
|
79
84
|
// Gestion des modèles
|
|
80
85
|
const handleModelToggle = async (modelId, isActive) => {
|
|
81
86
|
if (!effectiveToggleModel)
|
|
@@ -99,7 +104,7 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
99
104
|
id: m.id,
|
|
100
105
|
name: m.name,
|
|
101
106
|
category: m.type === "image" ? "image" : "text",
|
|
102
|
-
provider: "Unknown",
|
|
107
|
+
provider: t("common.unknown", "Unknown"),
|
|
103
108
|
}));
|
|
104
109
|
}
|
|
105
110
|
const categoryModels = effectiveAvailableModels.filter((m) => m.category === modelCategory);
|
|
@@ -309,23 +314,27 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
309
314
|
fontWeight: 600,
|
|
310
315
|
color: "var(--ai-text-secondary)",
|
|
311
316
|
letterSpacing: "0.02em",
|
|
312
|
-
}, children: "
|
|
317
|
+
}, children: t("prompt.modal.generating", "Generating...") }), _jsx("div", { className: "ai-loading-meta", children: t("ai.loading.elapsed", "{seconds}", {
|
|
318
|
+
seconds: loadingElapsed,
|
|
319
|
+
}) })] })), _jsxs("div", { style: {
|
|
313
320
|
...aiStyles.modalHeader,
|
|
314
321
|
position: "sticky",
|
|
315
322
|
top: 0,
|
|
316
323
|
zIndex: 5,
|
|
317
324
|
backdropFilter: "blur(8px)",
|
|
318
|
-
}, children: [_jsx("h2", { style: aiStyles.modalTitle, children: showPromptLibrary
|
|
325
|
+
}, children: [_jsx("h2", { style: aiStyles.modalTitle, children: showPromptLibrary
|
|
326
|
+
? t("prompt.modal.selectPrompt", "Select a Prompt")
|
|
327
|
+
: t("prompt.modal.title", "AI Prompt Configuration") }), _jsx("button", { style: {
|
|
319
328
|
...aiStyles.modalCloseButton,
|
|
320
329
|
...(isCloseHovered && aiStyles.modalCloseButtonHover),
|
|
321
|
-
}, onClick: handleClose, onMouseEnter: () => setIsCloseHovered(true), onMouseLeave: () => setIsCloseHovered(false), "aria-label": "Close", children: "\u00D7" })] }), _jsx("div", { style: {
|
|
330
|
+
}, onClick: handleClose, onMouseEnter: () => setIsCloseHovered(true), onMouseLeave: () => setIsCloseHovered(false), "aria-label": t("common.closeLabel", "Close"), children: "\u00D7" })] }), _jsx("div", { style: {
|
|
322
331
|
...aiStyles.modalBody,
|
|
323
332
|
flex: 1,
|
|
324
333
|
overflow: "auto",
|
|
325
334
|
}, children: !showPromptLibrary ? (_jsxs(_Fragment, { children: [sourceText && (_jsxs("div", { style: {
|
|
326
335
|
...aiStyles.modalInputGroup,
|
|
327
336
|
marginBottom: "16px",
|
|
328
|
-
}, children: [_jsx("label", { style: aiStyles.modalLabel, children: "Source Text" }), _jsx("div", { style: {
|
|
337
|
+
}, children: [_jsx("label", { style: aiStyles.modalLabel, children: t("prompt.modal.sourceText", "Source Text") }), _jsx("div", { style: {
|
|
329
338
|
padding: "12px",
|
|
330
339
|
background: aiStyles.textarea.background,
|
|
331
340
|
border: `1px solid ${aiStyles.input.border}`,
|
|
@@ -343,7 +352,7 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
343
352
|
justifyContent: "space-between",
|
|
344
353
|
alignItems: "center",
|
|
345
354
|
marginBottom: "8px",
|
|
346
|
-
}, children: [_jsx("label", { htmlFor: "model-select", style: aiStyles.modalLabel, children: "AI Model" }), effectiveAvailableModels.length > 0
|
|
355
|
+
}, children: [_jsx("label", { htmlFor: "model-select", style: aiStyles.modalLabel, children: "AI Model" }), isModelsLoading ? (_jsx("span", { className: "ai-inline-skeleton", "aria-hidden": "true" })) : effectiveAvailableModels.length > 0 ? (_jsxs("button", { onClick: () => setIsModelManagementOpen(true), className: "ai-inline-btn", title: t("prompt.modal.manageModels", "Manage models"), children: [_jsx(Settings, { size: 14 }), t("prompt.modal.manageModels", "Manage models"), effectiveAvailableModels.filter((m) => m.category === modelCategory &&
|
|
347
356
|
!effectiveUserModels.includes(m.id)).length > 0 && (_jsxs("span", { style: {
|
|
348
357
|
marginLeft: "2px",
|
|
349
358
|
padding: "2px 6px",
|
|
@@ -353,42 +362,44 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
353
362
|
borderRadius: "10px",
|
|
354
363
|
fontWeight: "600",
|
|
355
364
|
}, children: ["+", effectiveAvailableModels.filter((m) => m.category === modelCategory &&
|
|
356
|
-
!effectiveUserModels.includes(m.id)).length] }))] }))] }), _jsxs("select", { id: "model-select", value: activeModelId, onChange: (e) => setSelectedModel(e.target.value), onFocus: () => setModelFocused(true), onBlur: () => setModelFocused(false), style: {
|
|
365
|
+
!effectiveUserModels.includes(m.id)).length] }))] })) : null] }), _jsxs("select", { id: "model-select", value: activeModelId, onChange: (e) => setSelectedModel(e.target.value), onFocus: () => setModelFocused(true), onBlur: () => setModelFocused(false), style: {
|
|
357
366
|
...aiStyles.select,
|
|
358
367
|
...(modelFocused && aiStyles.selectFocus),
|
|
359
368
|
}, children: [modelOptions.length === 0 && (_jsx("option", { value: "", children: showOnlyUserModels
|
|
360
|
-
? "No active models. Open '
|
|
361
|
-
: "Loading models..." })), modelOptions.map((model) => {
|
|
369
|
+
? t("prompt.modal.noActiveModels", "No active models. Open 'Manage models'.")
|
|
370
|
+
: t("prompt.modal.loadingModels", "Loading models...") })), modelOptions.map((model) => {
|
|
362
371
|
const isActive = effectiveUserModels.includes(model.id);
|
|
363
372
|
return (_jsxs("option", { value: model.id, style: {
|
|
364
373
|
opacity: showAllModels && !isActive ? 0.6 : 1,
|
|
365
|
-
}, children: [model.name, showAllModels && isActive && " ✓", showAllModels && !isActive
|
|
366
|
-
|
|
374
|
+
}, children: [model.name, showAllModels && isActive && " ✓", showAllModels && !isActive
|
|
375
|
+
? ` (${t("common.inactive", "Inactive")})`
|
|
376
|
+
: ""] }, model.id));
|
|
377
|
+
})] }), showAllModels && onModelToggle && (_jsxs("div", { style: {
|
|
367
378
|
fontSize: "11px",
|
|
368
379
|
color: "var(--ai-text-secondary)",
|
|
369
380
|
marginTop: "4px",
|
|
370
|
-
}, children: "\uD83D\uDCA1
|
|
381
|
+
}, children: ["\uD83D\uDCA1", " ", t("prompt.modal.clickSettingsHint", "Click ⚙️ to enable/disable models")] }))] })) : (
|
|
371
382
|
// Version classique
|
|
372
383
|
_jsxs(_Fragment, { children: [_jsx("label", { htmlFor: "model-select", style: aiStyles.modalLabel, children: "AI Model" }), _jsxs("select", { id: "model-select", value: activeModelId, onChange: (e) => setSelectedModel(e.target.value), onFocus: () => setModelFocused(true), onBlur: () => setModelFocused(false), style: {
|
|
373
384
|
...aiStyles.select,
|
|
374
385
|
...(modelFocused && aiStyles.selectFocus),
|
|
375
|
-
}, children: [models.length === 0 && (_jsx("option", { value: "", children: "Loading models..." })), models.map((model) => (_jsx("option", { value: model.id, children: model.name }, model.id)))] })] })) }), _jsxs("div", { style: aiStyles.modalInputGroup, children: [_jsxs("div", { style: {
|
|
386
|
+
}, children: [models.length === 0 && (_jsx("option", { value: "", children: t("prompt.modal.loadingModels", "Loading models...") })), models.map((model) => (_jsx("option", { value: model.id, children: model.name }, model.id)))] })] })) }), _jsxs("div", { style: aiStyles.modalInputGroup, children: [_jsxs("div", { style: {
|
|
376
387
|
display: "flex",
|
|
377
388
|
justifyContent: "space-between",
|
|
378
389
|
alignItems: "center",
|
|
379
390
|
marginBottom: "8px",
|
|
380
|
-
}, children: [_jsxs("label", { htmlFor: "prompt-input", style: aiStyles.modalLabel, children: ["Prompt", _jsx("span", { style: {
|
|
391
|
+
}, children: [_jsxs("label", { htmlFor: "prompt-input", style: aiStyles.modalLabel, children: [t("prompt.modal.prompt", "Prompt"), _jsx("span", { style: {
|
|
381
392
|
color: "var(--ai-text-secondary)",
|
|
382
393
|
marginLeft: "4px",
|
|
383
394
|
fontSize: "12px",
|
|
384
395
|
fontWeight: 400,
|
|
385
|
-
}, children: "(Cmd/Ctrl + Enter to submit)" })] }), filteredPrompts.length > 0
|
|
386
|
-
? "Enter your AI prompt... e.g., '
|
|
387
|
-
: "Enter your AI prompt... e.g., 'Write a blog post about AI', 'Generate product description'", rows: 6, style: {
|
|
396
|
+
}, children: t("prompt.modal.promptHint", "(Cmd/Ctrl + Enter to submit)") })] }), promptsLoading ? (_jsx("span", { className: "ai-inline-skeleton", "aria-hidden": "true" })) : filteredPrompts.length > 0 ? (_jsxs("button", { onClick: () => setShowPromptLibrary(true), className: "ai-inline-btn", 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
|
|
397
|
+
? t("prompt.modal.promptPlaceholderWithSource", "Enter your AI prompt... e.g., 'Fix grammar', 'Make it more professional', 'Translate to English'")
|
|
398
|
+
: t("prompt.modal.promptPlaceholderNoSource", "Enter your AI prompt... e.g., 'Write a blog post about AI', 'Generate product description'"), rows: 6, style: {
|
|
388
399
|
...aiStyles.textarea,
|
|
389
400
|
padding: "12px 16px",
|
|
390
401
|
...(promptFocused && aiStyles.textareaFocus),
|
|
391
|
-
} })] })] })) : (_jsxs("div", { children: [
|
|
402
|
+
} })] })] })) : (_jsxs("div", { children: [_jsxs("button", { onClick: () => setShowPromptLibrary(false), style: {
|
|
392
403
|
padding: "8px 0",
|
|
393
404
|
fontSize: "14px",
|
|
394
405
|
color: "var(--ai-primary)",
|
|
@@ -399,7 +410,7 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
399
410
|
display: "flex",
|
|
400
411
|
alignItems: "center",
|
|
401
412
|
gap: "4px",
|
|
402
|
-
}, children: "\u2190 Back to form" }), _jsxs("div", { style: { marginBottom: "12px" }, children: [_jsxs("div", { style: {
|
|
413
|
+
}, children: ["\u2190 ", t("prompt.modal.backToFormNoArrow", "Back to form")] }), _jsxs("div", { style: { marginBottom: "12px" }, children: [_jsxs("div", { style: {
|
|
403
414
|
...aiStyles.inputWrapper,
|
|
404
415
|
marginBottom: "10px",
|
|
405
416
|
}, children: [_jsx(Search, { size: 16, style: {
|
|
@@ -408,7 +419,7 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
408
419
|
top: "50%",
|
|
409
420
|
transform: "translateY(-50%)",
|
|
410
421
|
color: aiStyles.tooltipLabel.color,
|
|
411
|
-
} }), _jsx("input", { value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: "Search prompts...", style: {
|
|
422
|
+
} }), _jsx("input", { value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: t("prompt.modal.searchPrompts", "Search prompts..."), style: {
|
|
412
423
|
...aiStyles.input,
|
|
413
424
|
padding: "10px 12px 10px 36px",
|
|
414
425
|
} })] }), availableTags.length > 0 && (_jsxs("div", { style: {
|
|
@@ -422,7 +433,7 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
422
433
|
gap: "6px",
|
|
423
434
|
fontSize: "12px",
|
|
424
435
|
color: aiStyles.tooltipLabel.color,
|
|
425
|
-
}, children: [_jsx(Tag, { size: 14 }), "Tags"] }), _jsx("button", { onClick: () => setSelectedTag("all"), style: {
|
|
436
|
+
}, children: [_jsx(Tag, { size: 14 }), t("prompt.modal.tags", "Tags")] }), _jsx("button", { onClick: () => setSelectedTag("all"), style: {
|
|
426
437
|
...aiStyles.chip,
|
|
427
438
|
borderColor: selectedTag === "all"
|
|
428
439
|
? "var(--ai-primary)"
|
|
@@ -430,7 +441,7 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
430
441
|
background: selectedTag === "all"
|
|
431
442
|
? "color-mix(in srgb, var(--ai-primary) 20%, transparent)"
|
|
432
443
|
: aiStyles.chip.background,
|
|
433
|
-
}, children: "All" }), availableTags.map((tag) => (_jsx("button", { onClick: () => setSelectedTag(tag), style: {
|
|
444
|
+
}, children: t("common.all", "All") }), availableTags.map((tag) => (_jsx("button", { onClick: () => setSelectedTag(tag), style: {
|
|
434
445
|
...aiStyles.chip,
|
|
435
446
|
borderColor: selectedTag === tag
|
|
436
447
|
? "var(--ai-primary)"
|
|
@@ -438,11 +449,17 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
438
449
|
background: selectedTag === tag
|
|
439
450
|
? "color-mix(in srgb, var(--ai-primary) 20%, transparent)"
|
|
440
451
|
: aiStyles.chip.background,
|
|
441
|
-
}, children: tag }, tag)))] }))] }), promptsLoading ? (_jsx("div", { style: {
|
|
452
|
+
}, children: tag }, tag)))] }))] }), promptsLoading ? (_jsx("div", { style: {
|
|
453
|
+
display: "flex",
|
|
454
|
+
flexDirection: "column",
|
|
455
|
+
gap: "12px",
|
|
456
|
+
maxHeight: "400px",
|
|
457
|
+
overflow: "auto",
|
|
458
|
+
}, children: Array.from({ length: 4 }).map((_, idx) => (_jsxs("div", { className: "ai-list-skeleton", children: [_jsx("div", { className: "ai-list-skeleton__line ai-list-skeleton__line--lg" }), _jsx("div", { className: "ai-list-skeleton__line ai-list-skeleton__line--md" })] }, `prompt-skeleton-${idx}`))) })) : visiblePrompts.length === 0 ? (_jsx("div", { style: {
|
|
442
459
|
textAlign: "center",
|
|
443
460
|
padding: "40px 0",
|
|
444
461
|
color: "var(--ai-text-secondary)",
|
|
445
|
-
}, children: "No prompts available for this model type" })) : (_jsxs("div", { style: {
|
|
462
|
+
}, children: t("prompt.modal.noPrompts", "No prompts available for this model type") })) : (_jsxs("div", { style: {
|
|
446
463
|
display: "flex",
|
|
447
464
|
flexDirection: "column",
|
|
448
465
|
gap: "12px",
|
|
@@ -454,7 +471,7 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
454
471
|
fontWeight: 600,
|
|
455
472
|
textTransform: "uppercase",
|
|
456
473
|
marginBottom: "8px",
|
|
457
|
-
}, children: "Favorites" }), _jsx("div", { style: {
|
|
474
|
+
}, children: t("prompt.modal.favorites", "Favorites") }), _jsx("div", { style: {
|
|
458
475
|
display: "flex",
|
|
459
476
|
flexDirection: "column",
|
|
460
477
|
gap: "12px",
|
|
@@ -499,7 +516,7 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
499
516
|
textTransform: "uppercase",
|
|
500
517
|
marginTop: favoritePrompts.length > 0 ? "12px" : undefined,
|
|
501
518
|
marginBottom: "8px",
|
|
502
|
-
}, children: "All prompts" }), _jsx("div", { style: {
|
|
519
|
+
}, children: t("prompt.modal.allPrompts", "All prompts") }), _jsx("div", { style: {
|
|
503
520
|
display: "flex",
|
|
504
521
|
flexDirection: "column",
|
|
505
522
|
gap: "12px",
|
|
@@ -540,7 +557,11 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
540
557
|
bottom: 0,
|
|
541
558
|
zIndex: 5,
|
|
542
559
|
backdropFilter: "blur(8px)",
|
|
543
|
-
}, children: [_jsx("button", { onClick: handleClose, className: "ai-btn ai-btn--ghost", children: "Cancel" }), _jsx("button", { onClick: handleSubmit, disabled: !selectedModel || !prompt.trim(), className: "ai-btn ai-btn--primary", children:
|
|
560
|
+
}, children: [_jsx("button", { onClick: handleClose, className: "ai-btn ai-btn--ghost", children: t("prompt.modal.cancel", "Cancel") }), _jsx("button", { onClick: handleSubmit, disabled: isGenerating || !selectedModel || !prompt.trim(), className: "ai-btn ai-btn--primary", children: isGenerating ? (_jsxs("span", { className: "ai-loading-stack", children: [_jsxs("span", { className: "ai-loading-row", children: [_jsx(Loader2, { size: 16, className: "ai-spinner" }), _jsx("span", { children: sourceText
|
|
561
|
+
? t("prompt.modal.transforming", "Transforming...")
|
|
562
|
+
: t("prompt.modal.generating", "Generating...") })] }), _jsx("span", { className: "ai-loading-meta", children: t("ai.loading.elapsed", "{seconds}", {
|
|
563
|
+
seconds: loadingElapsed,
|
|
564
|
+
}) })] })) : sourceText ? (t("prompt.modal.transform", "Transform with AI")) : (t("prompt.modal.generate", "Generate with AI")) })] })] }), enableModelManagement && isModelManagementOpen && (_jsxs("div", { style: {
|
|
544
565
|
...aiStyles.modal,
|
|
545
566
|
zIndex: 2147483646, // Au-dessus du modal principal
|
|
546
567
|
}, children: [_jsx("div", { style: {
|
|
@@ -557,10 +578,10 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
557
578
|
display: "flex",
|
|
558
579
|
flexDirection: "column",
|
|
559
580
|
boxShadow: "var(--ai-shadow-lg)",
|
|
560
|
-
}, children: [_jsxs("div", { style: aiStyles.modalHeader, children: [_jsx("h2", { style: aiStyles.modalTitle, children: "
|
|
581
|
+
}, children: [_jsxs("div", { style: aiStyles.modalHeader, children: [_jsx("h2", { style: aiStyles.modalTitle, children: t("prompt.modal.modelMgmtTitle", "AI Model Management") }), _jsx("button", { style: aiStyles.modalCloseButton, onClick: () => {
|
|
561
582
|
setIsModelManagementOpen(false);
|
|
562
583
|
setModelSearchQuery("");
|
|
563
|
-
}, "aria-label": "Close", children: "\u00D7" })] }), _jsxs("div", { style: {
|
|
584
|
+
}, "aria-label": t("common.closeLabel", "Close"), children: "\u00D7" })] }), _jsxs("div", { style: {
|
|
564
585
|
...aiStyles.modalBody,
|
|
565
586
|
flex: 1,
|
|
566
587
|
overflow: "auto",
|
|
@@ -568,11 +589,14 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
568
589
|
fontSize: "14px",
|
|
569
590
|
color: "var(--ai-muted)",
|
|
570
591
|
margin: "0 0 8px 0",
|
|
571
|
-
}, children: "
|
|
592
|
+
}, children: t("prompt.modal.modelMgmtSubtitle", "Enable or disable models based on your needs") }), _jsx("p", { style: {
|
|
572
593
|
fontSize: "12px",
|
|
573
594
|
color: "var(--ai-text-tertiary)",
|
|
574
595
|
margin: "0 0 16px 0",
|
|
575
|
-
}, children:
|
|
596
|
+
}, children: t("prompt.modal.modelAvailableCount", "{available} models available • {active} enabled", {
|
|
597
|
+
available: effectiveAvailableModels.filter((m) => m.category === modelCategory).length,
|
|
598
|
+
active: effectiveUserModels.filter((id) => effectiveAvailableModels.some((m) => m.id === id && m.category === modelCategory)).length,
|
|
599
|
+
}) }), _jsxs("div", { style: {
|
|
576
600
|
...aiStyles.inputWrapper,
|
|
577
601
|
marginBottom: "16px",
|
|
578
602
|
}, children: [_jsx(Search, { size: 16, style: {
|
|
@@ -581,11 +605,11 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
581
605
|
top: "50%",
|
|
582
606
|
transform: "translateY(-50%)",
|
|
583
607
|
color: "var(--ai-text-tertiary)",
|
|
584
|
-
} }), _jsx("input", { value: modelSearchQuery, onChange: (e) => setModelSearchQuery(e.target.value), placeholder: "
|
|
608
|
+
} }), _jsx("input", { value: modelSearchQuery, onChange: (e) => setModelSearchQuery(e.target.value), placeholder: t("prompt.modal.searchModel", "Search a model..."), style: {
|
|
585
609
|
...aiStyles.input,
|
|
586
610
|
padding: "10px 12px 10px 36px",
|
|
587
611
|
background: "var(--ai-bg)",
|
|
588
|
-
} })] })] }), _jsxs("div", { className: "ai-model-mgmt-list", children: [effectiveAvailableModels
|
|
612
|
+
} })] })] }), _jsxs("div", { className: "ai-model-mgmt-list", children: [isModelsLoading ? (_jsx(_Fragment, { children: Array.from({ length: 4 }).map((_, idx) => (_jsxs("div", { className: "ai-list-skeleton", children: [_jsx("div", { className: "ai-list-skeleton__line ai-list-skeleton__line--lg" }), _jsx("div", { className: "ai-list-skeleton__line ai-list-skeleton__line--md" })] }, `model-skeleton-${idx}`))) })) : null, effectiveAvailableModels
|
|
589
613
|
.filter((model) => {
|
|
590
614
|
if (model.category !== modelCategory)
|
|
591
615
|
return false;
|
|
@@ -624,24 +648,25 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
624
648
|
height: 0,
|
|
625
649
|
position: "absolute",
|
|
626
650
|
} }), _jsx("span", { className: `ai-toggle ${isActive ? "ai-toggle--active" : ""}` })] })] }, modelData.id));
|
|
627
|
-
}),
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
model.
|
|
635
|
-
|
|
636
|
-
|
|
651
|
+
}), !isModelsLoading &&
|
|
652
|
+
effectiveAvailableModels.filter((model) => {
|
|
653
|
+
if (model.category !== modelCategory)
|
|
654
|
+
return false;
|
|
655
|
+
if (!modelSearchQuery.trim())
|
|
656
|
+
return true;
|
|
657
|
+
const query = modelSearchQuery.toLowerCase();
|
|
658
|
+
return (model.name.toLowerCase().includes(query) ||
|
|
659
|
+
model.provider.toLowerCase().includes(query) ||
|
|
660
|
+
model.description?.toLowerCase().includes(query));
|
|
661
|
+
}).length === 0 && (_jsx("div", { style: {
|
|
637
662
|
textAlign: "center",
|
|
638
663
|
padding: "32px 16px",
|
|
639
664
|
color: "var(--ai-text-tertiary)",
|
|
640
665
|
fontSize: "14px",
|
|
641
666
|
}, children: modelSearchQuery.trim()
|
|
642
|
-
? "
|
|
643
|
-
: "
|
|
667
|
+
? t("prompt.modal.noModelMatch", "No model matches your search")
|
|
668
|
+
: t("prompt.modal.noModelAvailable", "No models available") }))] })] }), _jsx("div", { style: aiStyles.modalFooter, children: _jsx("button", { onClick: () => {
|
|
644
669
|
setIsModelManagementOpen(false);
|
|
645
670
|
setModelSearchQuery("");
|
|
646
|
-
}, className: "ai-btn ai-btn--ghost", children: "
|
|
671
|
+
}, className: "ai-btn ai-btn--ghost", children: t("prompt.modal.closeModelMgmt", "Close") }) })] })] }))] }), portalRoot);
|
|
647
672
|
}
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"AiSelect.d.ts","sourceRoot":"","sources":["../../src/components/AiSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAW9D,MAAM,WAAW,aACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACnE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,IAAW,EACX,MAAe,EACf,OAAO,EACP,KAAK,EACL,MAAM,EACN,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,GAAG,WAAW,EACf,EAAE,aAAa,2CAgJf"}
|
|
@@ -11,7 +11,9 @@ import { LBSigninModal } from "./LBSigninModal";
|
|
|
11
11
|
import { handleAIError } from "../utils/errorHandler";
|
|
12
12
|
import { useLB } from "../context/LBAuthProvider";
|
|
13
13
|
import { useAiContext } from "../context/AiProvider";
|
|
14
|
+
import { useI18n } from "../context/I18nContext";
|
|
14
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 }) {
|
|
16
|
+
const { t } = useI18n();
|
|
15
17
|
const [isOpen, setIsOpen] = useState(false);
|
|
16
18
|
const [showAuthModal, setShowAuthModal] = useState(false);
|
|
17
19
|
const { showUsageToast, toastData, toastKey, clearToast } = useUsageToast();
|
|
@@ -68,7 +70,10 @@ export function AiSelect({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode
|
|
|
68
70
|
});
|
|
69
71
|
if (result.text) {
|
|
70
72
|
onValue?.(result.text);
|
|
71
|
-
onToast?.({
|
|
73
|
+
onToast?.({
|
|
74
|
+
type: "success",
|
|
75
|
+
message: t("ai.select.suggestionReady", "AI suggestion ready"),
|
|
76
|
+
});
|
|
72
77
|
showUsageToast(result);
|
|
73
78
|
}
|
|
74
79
|
}
|
|
@@ -82,6 +87,6 @@ export function AiSelect({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode
|
|
|
82
87
|
const sizeClass = `ai-size-${size}`;
|
|
83
88
|
const radiusClass = `ai-radius-${radius}`;
|
|
84
89
|
return (_jsxs("div", { className: `ai-control-group ai-glow ${className || ""}`, children: [_jsxs("div", { className: `ai-shell ${sizeClass} ${radiusClass}`, children: [_jsx("select", { ...selectProps, className: `ai-control ai-control-input ai-control-select ${sizeClass} ${radiusClass}`, disabled: disabled || loading, children: children }), _jsx("span", { className: "ai-control-select-chevron", "aria-hidden": "true", children: _jsx(ChevronDown, { size: 14 }) }), _jsx("button", { className: `ai-control-action ai-spark ${sizeClass} ${radiusClass}`, onClick: handleOpenPanel, title: shouldShowSparkles
|
|
85
|
-
? "
|
|
86
|
-
: "
|
|
90
|
+
? t("ai.generate", "Generate with AI")
|
|
91
|
+
: t("auth.connectToUseAi", "Sign in to use AI"), disabled: disabled || loading, type: "button", children: loading ? (_jsx(Loader2, { size: 16, className: "ai-spinner" })) : shouldShowSparkles ? (_jsx(Sparkles, { size: 16 })) : (_jsx(Lock, { size: 16 })) })] }), isOpen && (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: handleClosePanel, onSubmit: handleSubmit, uiMode: uiMode, models: models || [] })), Boolean(toastData) && (_jsx(UsageToast, { result: toastData, position: "bottom-right", onComplete: clearToast }, toastKey)), _jsx(LBSigninModal, { isOpen: showAuthModal, onClose: () => setShowAuthModal(false) })] }));
|
|
87
92
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAU,MAAM,uBAAuB,CAAC;AAuB9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAU,MAAM,uBAAuB,CAAC;AAuB9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGjD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAmHD,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAe,EACf,SAAc,EACd,IAAW,EACX,MAAe,GAChB,EAAE,mBAAmB,2CAyhBrB"}
|
|
@@ -8,30 +8,31 @@ import { LBContext, } from "../context/LBAuthProvider";
|
|
|
8
8
|
import { AiContext } from "../context/AiProvider";
|
|
9
9
|
import { LBApiKeySelector } from "./LBApiKeySelector";
|
|
10
10
|
import { LBSigninModal } from "./LBSigninModal";
|
|
11
|
+
import { useI18n } from "../context/I18nContext";
|
|
11
12
|
const QUICK_LINKS = [
|
|
12
13
|
{
|
|
13
14
|
href: "https://prompt.lastbrain.io/auth/ai/tokens",
|
|
14
|
-
|
|
15
|
+
titleKey: "status.dashboard",
|
|
15
16
|
icon: BarChart3,
|
|
16
17
|
},
|
|
17
18
|
{
|
|
18
19
|
href: "https://prompt.lastbrain.io/auth/ai/history",
|
|
19
|
-
|
|
20
|
+
titleKey: "status.history",
|
|
20
21
|
icon: History,
|
|
21
22
|
},
|
|
22
23
|
{
|
|
23
24
|
href: "https://prompt.lastbrain.io/auth/ai/settings",
|
|
24
|
-
|
|
25
|
+
titleKey: "status.settings",
|
|
25
26
|
icon: Settings,
|
|
26
27
|
},
|
|
27
28
|
{
|
|
28
29
|
href: "https://prompt.lastbrain.io/auth/ai/prompts",
|
|
29
|
-
|
|
30
|
+
titleKey: "status.prompts",
|
|
30
31
|
icon: FileText,
|
|
31
32
|
},
|
|
32
33
|
{
|
|
33
34
|
href: "https://prompt.lastbrain.io/auth/folder",
|
|
34
|
-
|
|
35
|
+
titleKey: "status.folders",
|
|
35
36
|
icon: Folder,
|
|
36
37
|
},
|
|
37
38
|
];
|
|
@@ -64,6 +65,7 @@ function UsageCircle({ percentage }) {
|
|
|
64
65
|
: "ai-usage-circle-text--low", fontWeight: "700", children: [safe.toFixed(0), "%"] })] }));
|
|
65
66
|
}
|
|
66
67
|
export function AiStatusButton({ status, loading = false, className = "", size = "md", radius = "full", }) {
|
|
68
|
+
const { t } = useI18n();
|
|
67
69
|
let lbStatus;
|
|
68
70
|
let user = null;
|
|
69
71
|
let logout;
|
|
@@ -121,10 +123,13 @@ export function AiStatusButton({ status, loading = false, className = "", size =
|
|
|
121
123
|
const hasApiKeySelected = Boolean(effectiveStatus?.apiKey?.id ||
|
|
122
124
|
effectiveStatus?.api_key?.id ||
|
|
123
125
|
lbSelectedKey?.id);
|
|
124
|
-
const
|
|
125
|
-
const isApiKeyAuthMode = effectiveStatus &&
|
|
126
|
+
const authTypeValue = effectiveStatus &&
|
|
126
127
|
"authType" in effectiveStatus &&
|
|
127
|
-
effectiveStatus.authType === "
|
|
128
|
+
typeof effectiveStatus.authType === "string"
|
|
129
|
+
? effectiveStatus.authType
|
|
130
|
+
: undefined;
|
|
131
|
+
const requiresApiKeySelection = lbStatus === "ready" && !hasApiKeySelected && apiKeys.length > 0;
|
|
132
|
+
const isApiKeyAuthMode = authTypeValue === "api_key";
|
|
128
133
|
const [tooltipStyle, setTooltipStyle] = useState({});
|
|
129
134
|
useLayoutEffect(() => {
|
|
130
135
|
if (!showTooltip || !buttonRef.current || !canPortal) {
|
|
@@ -200,12 +205,31 @@ export function AiStatusButton({ status, loading = false, className = "", size =
|
|
|
200
205
|
const storageTotal = storage.allocated_mb ?? storage.total_mb ?? 0;
|
|
201
206
|
const storagePct = storage.percentage ??
|
|
202
207
|
(storageTotal > 0 ? Math.round((storageUsed / storageTotal) * 100) : 0);
|
|
208
|
+
const hasApiKeyMeta = Boolean(effectiveStatus?.apiKey?.name ||
|
|
209
|
+
effectiveStatus?.api_key?.name ||
|
|
210
|
+
effectiveStatus?.apiKey?.env ||
|
|
211
|
+
effectiveStatus?.api_key?.env ||
|
|
212
|
+
effectiveStatus?.apiKey?.rate_limit_rpm ||
|
|
213
|
+
effectiveStatus?.api_key?.rate_limit_rpm);
|
|
214
|
+
const hasBalanceMeta = Boolean(effectiveStatus?.balance);
|
|
215
|
+
const hasStorageMeta = Boolean(effectiveStatus?.storage);
|
|
216
|
+
const isImplicitStatusLoading = lbStatus === "ready" &&
|
|
217
|
+
!!user &&
|
|
218
|
+
!requiresApiKeySelection &&
|
|
219
|
+
(!authTypeValue || !hasApiKeyMeta || !hasBalanceMeta);
|
|
220
|
+
const isImplicitStorageLoading = lbStatus === "ready" &&
|
|
221
|
+
!!user &&
|
|
222
|
+
!requiresApiKeySelection &&
|
|
223
|
+
!hasStorageMeta;
|
|
203
224
|
const showFastSkeleton = lbStatus === "ready" &&
|
|
204
|
-
lbIsLoadingStatus
|
|
205
|
-
|
|
206
|
-
|
|
225
|
+
(lbIsLoadingStatus ||
|
|
226
|
+
isImplicitStatusLoading ||
|
|
227
|
+
(!lbBasicStatus && !effectiveStatus));
|
|
207
228
|
const showCornerLoading = lbStatus === "ready" &&
|
|
208
|
-
(showFastSkeleton ||
|
|
229
|
+
(showFastSkeleton ||
|
|
230
|
+
lbIsLoadingStatus ||
|
|
231
|
+
lbIsLoadingStorage ||
|
|
232
|
+
isImplicitStorageLoading);
|
|
209
233
|
const triggerTone = useMemo(() => {
|
|
210
234
|
if (requiresApiKeySelection)
|
|
211
235
|
return "warning";
|
|
@@ -250,26 +274,29 @@ export function AiStatusButton({ status, loading = false, className = "", size =
|
|
|
250
274
|
.filter(Boolean)
|
|
251
275
|
.join(" ");
|
|
252
276
|
const tooltipNode = showTooltip && canPortal
|
|
253
|
-
? createPortal(_jsx("div", { ref: tooltipRef, className: "ai-popover ai-tooltip ai-status-tooltip", style: tooltipStyle, onMouseEnter: () => setShowTooltip(true), onMouseLeave: closeTooltip, children: lbStatus === "ready" && user ? (_jsx(_Fragment, { children: _jsxs("div", { className: "ai-popover-body", children: [_jsx("div", { className: "ai-popover-header", children: "API Status" }), _jsx("div", { className: "ai-popover-section ai-popover-section--first", children: _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: "User" }), _jsx("span", { className: "ai-popover-value ai-truncate
|
|
277
|
+
? createPortal(_jsx("div", { ref: tooltipRef, className: "ai-popover ai-tooltip ai-status-tooltip", style: tooltipStyle, onMouseEnter: () => setShowTooltip(true), onMouseLeave: closeTooltip, children: lbStatus === "ready" && user ? (_jsx(_Fragment, { children: _jsxs("div", { className: "ai-popover-body", children: [_jsx("div", { className: "ai-popover-header", children: t("status.title", "API Status") }), _jsx("div", { className: "ai-popover-section ai-popover-section--first", children: _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: t("status.user", "User") }), _jsx("span", { className: "ai-popover-value ai-truncate", style: { maxWidth: 200 }, children: user.email })] }) }), _jsxs("div", { className: "ai-popover-section", children: [_jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: t("status.apiKey", "API Key") }), _jsxs("div", { className: "ai-row", children: [lbIsLoadingStatus || isImplicitStatusLoading ? (_jsx("div", { className: "ai-kv-skeleton ai-kv-skeleton--110" })) : (_jsx("span", { className: "ai-popover-value", children: effectiveStatus?.apiKey?.name ||
|
|
254
278
|
effectiveStatus?.api_key?.name ||
|
|
255
|
-
"Unknown" })), switchApiKey &&
|
|
279
|
+
t("common.unknown", "Unknown") })), switchApiKey &&
|
|
280
|
+
!isApiKeyAuthMode &&
|
|
281
|
+
!isImplicitStatusLoading ? (_jsx("button", { type: "button", className: "ai-icon-btn", onClick: (e) => {
|
|
256
282
|
e.stopPropagation();
|
|
257
283
|
setShowTooltip(false);
|
|
258
284
|
setShowApiKeySelector(true);
|
|
259
|
-
}, title: "
|
|
285
|
+
}, title: t("status.changeApiKey", "Switch API key"), children: _jsx(ArrowRightLeft, { size: 12 }) })) : null] })] }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: t("status.env", "Env") }), (lbIsLoadingStatus || isImplicitStatusLoading) &&
|
|
286
|
+
!effectiveStatus?.apiKey?.env ? (_jsx("div", { className: "ai-kv-skeleton ai-kv-skeleton--48" })) : (_jsx("span", { className: "ai-popover-value", children: effectiveStatus?.apiKey?.env ||
|
|
260
287
|
effectiveStatus?.api_key?.env ||
|
|
261
|
-
"N/A" }))] }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: "Rate Limit" }), lbIsLoadingStatus &&
|
|
262
|
-
!effectiveStatus?.apiKey?.rate_limit_rpm ? (_jsx("div", { className: "ai-kv-skeleton
|
|
288
|
+
"N/A" }))] }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: t("status.rateLimit", "Rate Limit") }), (lbIsLoadingStatus || isImplicitStatusLoading) &&
|
|
289
|
+
!effectiveStatus?.apiKey?.rate_limit_rpm ? (_jsx("div", { className: "ai-kv-skeleton ai-kv-skeleton--92" })) : (_jsxs("span", { className: "ai-popover-value", children: [effectiveStatus?.apiKey?.rate_limit_rpm ||
|
|
263
290
|
effectiveStatus?.api_key?.rate_limit_rpm ||
|
|
264
|
-
0, " ", "req/min"] }))] }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: "Auth" }), _jsx("span", { className: "ai-popover-value", children: lbIsLoadingStatus
|
|
291
|
+
0, " ", "req/min"] }))] }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: t("status.auth", "Auth") }), _jsx("span", { className: "ai-popover-value", children: lbIsLoadingStatus || isImplicitStatusLoading
|
|
265
292
|
? "..."
|
|
266
|
-
:
|
|
267
|
-
"authType" in effectiveStatus &&
|
|
268
|
-
effectiveStatus.authType) ||
|
|
293
|
+
: authTypeValue ||
|
|
269
294
|
lbStatus ||
|
|
270
|
-
"unknown"
|
|
295
|
+
t("status.unknown", "unknown") })] })] }), _jsxs("div", { className: "ai-popover-section", children: [_jsx("div", { className: "ai-popover-header ai-popover-header--sub", children: t("status.wallet", "Wallet") }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: t("status.total", "Total") }), (lbIsLoadingStatus || isImplicitStatusLoading) &&
|
|
296
|
+
!effectiveStatus?.balance ? (_jsxs("div", { className: "ai-row", children: [_jsx("div", { className: "ai-kv-skeleton ai-kv-skeleton--120" }), _jsx("div", { className: "ai-kv-skeleton ai-kv-skeleton--circle" })] })) : (_jsxs("div", { className: "ai-row", children: [_jsxs("span", { className: "ai-popover-value", children: ["$", fixed(balanceUsed, 2), " / $", fixed(balanceTotal, 2)] }), _jsx(UsageCircle, { percentage: balancePct })] }))] })] }), _jsxs("div", { className: "ai-popover-section", children: [_jsx("div", { className: "ai-popover-header ai-popover-header--sub", children: t("status.storage", "Storage") }), _jsxs("div", { className: "ai-popover-row", children: [_jsx("span", { className: "ai-popover-label", children: t("status.total", "Total") }), lbIsLoadingStorage || isImplicitStorageLoading ? (_jsxs("div", { className: "ai-row", children: [_jsx("div", { className: "ai-kv-skeleton ai-kv-skeleton--120" }), _jsx("div", { className: "ai-kv-skeleton ai-kv-skeleton--circle" })] })) : (_jsxs("div", { className: "ai-row", children: [_jsxs("span", { className: "ai-popover-value", children: [formatStorage(storageUsed), " /", " ", formatStorage(storageTotal)] }), _jsx(UsageCircle, { percentage: storagePct })] }))] })] }), _jsxs("div", { className: "ai-status-actions", children: [QUICK_LINKS.map((item) => {
|
|
271
297
|
const Icon = item.icon;
|
|
272
|
-
|
|
298
|
+
const label = t(item.titleKey, item.titleKey);
|
|
299
|
+
return (_jsx("button", { type: "button", className: "ai-status-action-btn", onClick: () => window.open(item.href, "_blank"), title: label, "data-ai-tip": label, children: _jsx(Icon, { size: 17 }) }, item.href));
|
|
273
300
|
}), logout && !isApiKeyAuthMode ? (_jsx("button", { type: "button", className: "ai-status-action-btn ai-status-action-btn--danger", onClick: async () => {
|
|
274
301
|
try {
|
|
275
302
|
await logout();
|
|
@@ -281,12 +308,12 @@ export function AiStatusButton({ status, loading = false, className = "", size =
|
|
|
281
308
|
catch (error) {
|
|
282
309
|
console.error("Logout failed:", error);
|
|
283
310
|
}
|
|
284
|
-
}, title: "Logout", children: _jsx(LogOut, { size: 17 }) })) : null] })] }) })) : (_jsxs("div", { className: "ai-popover-body", children: [_jsx("div", { className: "ai-popover-header", children: "LastBrain Authentication" }), _jsx("p", { className: "ai-signin-subtitle
|
|
311
|
+
}, title: t("status.logout", "Logout"), "data-ai-tip": t("status.logout", "Logout"), children: _jsx(LogOut, { size: 17 }) })) : null] })] }) })) : (_jsxs("div", { className: "ai-popover-body", children: [_jsx("div", { className: "ai-popover-header", children: t("status.lastbrainAuth", "LastBrain Authentication") }), _jsx("p", { className: "ai-signin-subtitle", style: { marginTop: 0 }, children: t("status.connectToAccess", "Sign in to access AI features.") }), _jsx("button", { type: "button", className: "ai-btn ai-btn--auth", style: { width: "100%", marginTop: 8 }, onClick: () => {
|
|
285
312
|
setShowSigninModal(true);
|
|
286
313
|
setShowTooltip(false);
|
|
287
|
-
}, children: "
|
|
314
|
+
}, children: t("auth.signIn", "Sign in") })] })) }), document.body)
|
|
288
315
|
: null;
|
|
289
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", {
|
|
316
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { style: { position: "relative", display: "inline-block" }, children: [_jsx("button", { ref: buttonRef, className: triggerClass, onMouseEnter: openTooltip, onMouseLeave: closeTooltip, onClick: () => {
|
|
290
317
|
if (requiresApiKeySelection) {
|
|
291
318
|
setShowApiKeySelector(true);
|
|
292
319
|
return;
|
|
@@ -295,8 +322,8 @@ export function AiStatusButton({ status, loading = false, className = "", size =
|
|
|
295
322
|
setShowSigninModal(true);
|
|
296
323
|
}
|
|
297
324
|
}, disabled: loading || isSelectingApiKey, title: requiresApiKeySelection
|
|
298
|
-
? "
|
|
299
|
-
: "
|
|
325
|
+
? t("status.selectApiKey", "Select an API key")
|
|
326
|
+
: 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 && apiKeys.length > 0 ? (_jsx(LBApiKeySelector, { isOpen: showApiKeySelector, apiKeys: apiKeys, onSelect: async (keyId) => {
|
|
300
327
|
setIsSelectingApiKey(true);
|
|
301
328
|
try {
|
|
302
329
|
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;
|
|
1
|
+
{"version":3,"file":"AiTextarea.d.ts","sourceRoot":"","sources":["../../src/components/AiTextarea.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAc,EAIZ,KAAK,sBAAsB,EAC5B,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAY9D,MAAM,WAAW,eACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,sBAAsB,CAAC,mBAAmB,CAAC,EAAE,SAAS,CAAC;IAC9D,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,IAAW,EACX,MAAa,EACb,OAAO,EACP,KAAK,EACL,MAAM,EACN,QAAgB,EAChB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,aAAa,EACjB,EAAE,eAAe,2CA+OjB"}
|