@promptbook/cli 0.112.0-125 → 0.112.0-127
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/README.md +5 -5
- package/apps/agents-server/README.md +3 -0
- package/apps/agents-server/playwright.config.ts +1 -0
- package/apps/agents-server/public/promptbook-logo-blue.png +0 -0
- package/apps/agents-server/public/promptbook-logo-white.png +0 -0
- package/apps/agents-server/src/app/[agentName]/layout.tsx +1 -0
- package/apps/agents-server/src/app/actions.ts +2 -2
- package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +68 -36
- package/apps/agents-server/src/app/agents/[agentName]/ActiveAgentBreadcrumbBinder.tsx +30 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +2 -0
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistoryPayloadState.ts +38 -4
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistorySyncOperations.ts +4 -1
- package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatSurface.tsx +19 -15
- package/apps/agents-server/src/app/agents/[agentName]/chat/useCanonicalAgentChatPanelState.ts +58 -7
- package/apps/agents-server/src/app/agents/[agentName]/layout.tsx +47 -1
- package/apps/agents-server/src/app/api/chat/citation-label/route.ts +133 -0
- package/apps/agents-server/src/app/globals.css +78 -0
- package/apps/agents-server/src/components/Header/ActiveAgentBreadcrumbContext.tsx +82 -0
- package/apps/agents-server/src/components/Header/useHeaderActiveAgent.ts +26 -7
- package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +35 -32
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/ManGoNewAgentWizard.tsx +151 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/ManGoOnboardingNavigation.tsx +50 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/BookLanguagePanel.tsx +125 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/DropZone.tsx +83 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/EmailTestRun.tsx +216 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/KnowledgeList.tsx +79 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/Logo.tsx +20 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownBookEditor.tsx +154 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownPreview.tsx +188 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/RailStepper.tsx +115 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/StepFrame.tsx +47 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/TestChat.tsx +159 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/WizardShell.tsx +114 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/brand/RailArtwork.tsx +60 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/BookStep.tsx +135 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/DoneStep.tsx +215 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/KnowledgeStep.tsx +152 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/TestStep.tsx +262 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/ZadaniStep.tsx +64 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Badge.tsx +41 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Banner.tsx +69 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Button.tsx +77 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Card.tsx +33 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Field.tsx +103 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/IconButton.tsx +40 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Spinner.tsx +14 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/tokens.ts +37 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/bookSections.ts +62 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/emailScenarios.ts +22 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/steps.ts +46 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/index.ts +11 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/cn.ts +4 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/format.ts +9 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/id.ts +11 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/agentEvalService.ts +30 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/agentTestService.ts +69 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/bookService.ts +21 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/createManGoAgentSource.ts +107 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/draftService.ts +45 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/uploadService.ts +27 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/state/OnboardingProvider.tsx +121 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/types.ts +52 -0
- package/apps/agents-server/src/components/NewAgentDialog/createNewAgentWizardSource.ts +1 -1
- package/apps/agents-server/src/components/NewAgentDialog/trackNewAgentCreationEvent.ts +1 -1
- package/apps/agents-server/src/components/NewAgentDialog/useNewAgentDialog.tsx +76 -0
- package/apps/agents-server/src/constants/newAgentWizard.ts +17 -8
- package/apps/agents-server/src/database/getMetadata.ts +37 -1
- package/apps/agents-server/src/database/metadataDefaults.ts +18 -7
- package/apps/agents-server/src/database/migrations/2026-06-2200-new-agent-wizard-metadata-key.sql +27 -0
- package/apps/agents-server/src/database/migrations/2026-06-2201-new-agent-wizard-mango-default.sql +11 -0
- package/apps/agents-server/src/generated/reservedPaths.ts +2 -0
- package/apps/agents-server/src/languages/translations/english.yaml +1 -1
- package/apps/agents-server/src/tools/createChatAttachmentToolFunctions.ts +8 -4
- package/apps/agents-server/src/utils/chat/resolveAgentsServerCitationLabel.ts +130 -0
- package/apps/agents-server/src/utils/chat/resolveCitationSourceLabel.ts +436 -0
- package/apps/agents-server/src/utils/knowledge/resolveWebsiteKnowledgeSourcesForServer.ts +10 -1
- package/apps/agents-server/src/utils/session.ts +62 -5
- package/apps/agents-server/src/utils/transpilers/resolveTranspiledTeamExport.ts +10 -10
- package/apps/agents-server/src/utils/userChat/userChatProgressCard.ts +198 -63
- package/apps/agents-server/src/utils/vpsConfiguration.ts +1 -0
- package/apps/agents-server/src/utils/vpsSelfUpdate.ts +81 -8
- package/esm/index.es.js +1052 -455
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
- package/esm/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -2
- package/esm/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +50 -0
- package/esm/scripts/run-codex-prompts/server/buildCoderServerRunState.d.ts +23 -0
- package/esm/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/server/runCoderHttpServer.d.ts +13 -1
- package/esm/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -0
- package/esm/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +4 -0
- package/esm/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +1 -0
- package/esm/src/_packages/components.index.d.ts +2 -0
- package/esm/src/_packages/types.index.d.ts +2 -0
- package/esm/src/avatars/avatarAnimationScheduler.d.ts +4 -0
- package/esm/src/book-components/Chat/Chat/ChatCitationModal.d.ts +2 -0
- package/esm/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
- package/esm/src/book-components/Chat/Chat/ChatMessageList.d.ts +4 -0
- package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
- package/esm/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +2 -0
- package/esm/src/book-components/Chat/Chat/ChatToolCallModalContent.d.ts +3 -1
- package/esm/src/book-components/Chat/Chat/TeamToolCallModalContent.d.ts +2 -0
- package/esm/src/book-components/Chat/SourceChip/SourceChip.d.ts +6 -1
- package/esm/src/book-components/Chat/hooks/useResolvedCitationLabel.d.ts +12 -0
- package/esm/src/book-components/Chat/types/ChatMessage.d.ts +4 -0
- package/esm/src/book-components/Chat/types/ChatParticipant.d.ts +1 -1
- package/esm/src/book-components/Chat/types/CitationLabelResolver.d.ts +8 -0
- package/esm/src/book-components/Chat/utils/citationHelpers.d.ts +9 -0
- package/esm/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.d.ts +14 -0
- package/esm/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.test.d.ts +1 -0
- package/esm/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +4 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/_packages/components.index.ts +2 -0
- package/src/_packages/types.index.ts +2 -0
- package/src/avatars/avatarAnimationScheduler.ts +61 -20
- package/src/avatars/visuals/octopus3d2AvatarVisual.ts +106 -21
- package/src/avatars/visuals/octopus3d3AvatarVisual.ts +131 -28
- package/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/augmentAgentModelRequirementsFromSource.ts +18 -2
- package/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.ts +7 -1
- package/src/book-components/Chat/Chat/Chat.tsx +4 -0
- package/src/book-components/Chat/Chat/ChatCitationModal.tsx +17 -3
- package/src/book-components/Chat/Chat/ChatMessageItem.tsx +22 -2
- package/src/book-components/Chat/Chat/ChatMessageList.tsx +6 -0
- package/src/book-components/Chat/Chat/ChatProps.tsx +6 -0
- package/src/book-components/Chat/Chat/ChatToolCallModal.tsx +4 -0
- package/src/book-components/Chat/Chat/ChatToolCallModalContent.tsx +4 -0
- package/src/book-components/Chat/Chat/TeamToolCallModalContent.tsx +16 -3
- package/src/book-components/Chat/Chat/useChatPostprocessedMessages.ts +13 -2
- package/src/book-components/Chat/SourceChip/SourceChip.module.css +8 -0
- package/src/book-components/Chat/SourceChip/SourceChip.tsx +19 -5
- package/src/book-components/Chat/hooks/useResolvedCitationLabel.ts +65 -0
- package/src/book-components/Chat/save/html/htmlSaveFormatDefinition.ts +315 -88
- package/src/book-components/Chat/save/react/reactSaveFormatDefinition.ts +7 -1
- package/src/book-components/Chat/types/ChatMessage.ts +5 -0
- package/src/book-components/Chat/types/ChatParticipant.ts +1 -1
- package/src/book-components/Chat/types/CitationLabelResolver.ts +9 -0
- package/src/book-components/Chat/utils/citationHelpers.ts +90 -2
- package/src/book-components/Chat/utils/createCitationFootnoteRenderModel.ts +3 -0
- package/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.ts +178 -0
- package/src/book-components/Chat/utils/parseCitationsFromContent.ts +6 -0
- package/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.ts +13 -2
- package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
- package/src/cli/cli-commands/coder/run.ts +17 -20
- package/src/cli/cli-commands/coder/server.ts +13 -16
- package/src/cli/common/$deprecateCliCommand.ts +10 -1
- package/src/commitments/GOAL/GOAL.ts +7 -2
- package/src/commitments/LANGUAGE/LANGUAGE.ts +7 -2
- package/src/commitments/TEAM/TEAM.ts +12 -1
- package/src/commitments/USE_PROJECT/createUseProjectToolFunctions.ts +8 -1
- package/src/import-plugins/JsonFileImportPlugin.ts +15 -2
- package/src/import-plugins/TextFileImportPlugin.ts +8 -1
- package/src/llm-providers/_common/register/$registeredLlmToolsMessage.ts +6 -1
- package/src/other/templates/getTemplatesPipelineCollection.ts +696 -941
- package/src/utils/chat/chatAttachments/resolveChatAttachmentContent.ts +8 -1
- package/src/version.ts +2 -2
- package/src/versions.txt +2 -1
- package/umd/index.umd.js +1055 -458
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
- package/umd/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -2
- package/umd/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +50 -0
- package/umd/scripts/run-codex-prompts/server/buildCoderServerRunState.d.ts +23 -0
- package/umd/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/server/runCoderHttpServer.d.ts +13 -1
- package/umd/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -0
- package/umd/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +4 -0
- package/umd/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +1 -0
- package/umd/src/_packages/components.index.d.ts +2 -0
- package/umd/src/_packages/types.index.d.ts +2 -0
- package/umd/src/avatars/avatarAnimationScheduler.d.ts +4 -0
- package/umd/src/book-components/Chat/Chat/ChatCitationModal.d.ts +2 -0
- package/umd/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
- package/umd/src/book-components/Chat/Chat/ChatMessageList.d.ts +4 -0
- package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
- package/umd/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +2 -0
- package/umd/src/book-components/Chat/Chat/ChatToolCallModalContent.d.ts +3 -1
- package/umd/src/book-components/Chat/Chat/TeamToolCallModalContent.d.ts +2 -0
- package/umd/src/book-components/Chat/SourceChip/SourceChip.d.ts +6 -1
- package/umd/src/book-components/Chat/hooks/useResolvedCitationLabel.d.ts +12 -0
- package/umd/src/book-components/Chat/types/ChatMessage.d.ts +4 -0
- package/umd/src/book-components/Chat/types/ChatParticipant.d.ts +1 -1
- package/umd/src/book-components/Chat/types/CitationLabelResolver.d.ts +8 -0
- package/umd/src/book-components/Chat/utils/citationHelpers.d.ts +9 -0
- package/umd/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.d.ts +14 -0
- package/umd/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.test.d.ts +1 -0
- package/umd/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +4 -0
- package/umd/src/version.d.ts +1 -1
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useRef, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import { EMAIL_SCENARIOS } from '../../config/emailScenarios';
|
|
6
|
+
import { ONBOARDING_STEPS } from '../../config/steps';
|
|
7
|
+
import { createId } from '../../lib/id';
|
|
8
|
+
import { cn } from '../../lib/cn';
|
|
9
|
+
import { agentTestService } from '../../services/agentTestService';
|
|
10
|
+
import { useManGoOnboardingNavigation } from '../../ManGoOnboardingNavigation';
|
|
11
|
+
import { useOnboarding } from '../../state/OnboardingProvider';
|
|
12
|
+
import type { ChatMessage } from '../../types';
|
|
13
|
+
import { EmailTestRun } from '../EmailTestRun';
|
|
14
|
+
import { SectionLabel, StepFooter, StepHeader } from '../StepFrame';
|
|
15
|
+
import { TestChat } from '../TestChat';
|
|
16
|
+
import { Badge } from '../ui/Badge';
|
|
17
|
+
import { Button } from '../ui/Button';
|
|
18
|
+
import { Card } from '../ui/Card';
|
|
19
|
+
|
|
20
|
+
type TestMode = 'email' | 'chat';
|
|
21
|
+
|
|
22
|
+
const SAMPLE_PROMPTS = [
|
|
23
|
+
'Zákazník reklamuje zboží, které přišlo poškozené.',
|
|
24
|
+
'Zákazník se ptá, proč mu nedorazilo zboží objednané před 3 dny.',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export function TestStep() {
|
|
28
|
+
const { navigateToPath } = useManGoOnboardingNavigation();
|
|
29
|
+
const { state, update } = useOnboarding();
|
|
30
|
+
|
|
31
|
+
const [mode, setMode] = useState<TestMode>('email');
|
|
32
|
+
const [email, setEmail] = useState(EMAIL_SCENARIOS[1].email);
|
|
33
|
+
|
|
34
|
+
const [isSending, setIsSending] = useState(false);
|
|
35
|
+
const requestRef = useRef(0);
|
|
36
|
+
|
|
37
|
+
async function runAgent(history: readonly ChatMessage[]) {
|
|
38
|
+
const requestId = (requestRef.current += 1);
|
|
39
|
+
setIsSending(true);
|
|
40
|
+
try {
|
|
41
|
+
const reply = await agentTestService.send({
|
|
42
|
+
bookSource: state.bookSource,
|
|
43
|
+
knowledge: state.knowledge,
|
|
44
|
+
messages: history,
|
|
45
|
+
});
|
|
46
|
+
if (requestRef.current !== requestId) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
update((prev) => ({
|
|
50
|
+
testMessages: [...prev.testMessages, { id: createId(), role: 'agent', content: reply.content }],
|
|
51
|
+
}));
|
|
52
|
+
} catch {
|
|
53
|
+
if (requestRef.current !== requestId) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
update((prev) => ({
|
|
57
|
+
testMessages: [
|
|
58
|
+
...prev.testMessages,
|
|
59
|
+
{ id: createId(), role: 'agent', content: 'Omlouvám se, něco se pokazilo. Zkuste to prosím znovu.' },
|
|
60
|
+
],
|
|
61
|
+
}));
|
|
62
|
+
} finally {
|
|
63
|
+
if (requestRef.current === requestId) {
|
|
64
|
+
setIsSending(false);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function send(text: string) {
|
|
70
|
+
const trimmed = text.trim();
|
|
71
|
+
if (!trimmed || isSending) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const history = [...state.testMessages, { id: createId(), role: 'user' as const, content: trimmed }];
|
|
75
|
+
update(() => ({ testMessages: history }));
|
|
76
|
+
void runAgent(history);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function retry() {
|
|
80
|
+
if (isSending) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const messages = state.testMessages;
|
|
84
|
+
let lastUser = -1;
|
|
85
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
86
|
+
if (messages[index].role === 'user') {
|
|
87
|
+
lastUser = index;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (lastUser < 0) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const history = messages.slice(0, lastUser + 1);
|
|
95
|
+
update(() => ({ testMessages: history }));
|
|
96
|
+
void runAgent(history);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function stop() {
|
|
100
|
+
requestRef.current += 1;
|
|
101
|
+
setIsSending(false);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const agentName = state.agentName.trim() || 'Nepojmenovaný agent';
|
|
105
|
+
const readyKnowledge = state.knowledge.filter((item) => item.status === 'ready').length;
|
|
106
|
+
const isRetryAvailable = !isSending && state.testMessages.some((message) => message.role === 'user');
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<div className="mx-auto max-w-4xl">
|
|
110
|
+
<StepHeader
|
|
111
|
+
eyebrow="Ověření agenta"
|
|
112
|
+
title="Otestujte agenta"
|
|
113
|
+
subtitle="Vyzkoušejte, jak agent reaguje na reálná zadání. Odpovídá naživo přes model — je to testovací režim, nic se zákazníkům neodesílá."
|
|
114
|
+
/>
|
|
115
|
+
|
|
116
|
+
<div className="mb-6">
|
|
117
|
+
<ModeToggle mode={mode} onChange={setMode} />
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<div className="grid items-start gap-6 md:grid-cols-[1fr_1.4fr]">
|
|
121
|
+
<div className="space-y-4">
|
|
122
|
+
<Card className="p-5">
|
|
123
|
+
<SectionLabel className="mb-3">Konfigurace agenta</SectionLabel>
|
|
124
|
+
<div className="text-sm font-bold text-zinc-900">{agentName}</div>
|
|
125
|
+
<div className="mt-4 space-y-2.5 border-t border-zinc-100 pt-4 text-sm">
|
|
126
|
+
<div className="flex items-center justify-between">
|
|
127
|
+
<span className="text-zinc-500">Book</span>
|
|
128
|
+
<button
|
|
129
|
+
type="button"
|
|
130
|
+
onClick={() => navigateToPath(ONBOARDING_STEPS[0].path)}
|
|
131
|
+
className="inline-flex items-center gap-1 rounded-full bg-[color:var(--ob-accent-50)] px-2.5 py-0.5 text-xs font-medium text-[color:var(--ob-accent-700)] transition-colors hover:bg-[color:var(--ob-accent-100)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ob-ring)]"
|
|
132
|
+
>
|
|
133
|
+
<span aria-hidden>✏️</span> Upravit
|
|
134
|
+
</button>
|
|
135
|
+
</div>
|
|
136
|
+
<div className="flex items-center justify-between">
|
|
137
|
+
<span className="text-zinc-500">Znalosti</span>
|
|
138
|
+
<Badge tone={readyKnowledge > 0 ? 'success' : 'neutral'} dot={readyKnowledge > 0}>
|
|
139
|
+
{readyKnowledge} {readyKnowledge === 1 ? 'zdroj' : 'zdroje/ů'}
|
|
140
|
+
</Badge>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</Card>
|
|
144
|
+
|
|
145
|
+
{mode === 'email' ? (
|
|
146
|
+
<div>
|
|
147
|
+
<div className="mb-2 text-[13px] font-semibold text-zinc-600">Simulace vstupu:</div>
|
|
148
|
+
<div className="space-y-2">
|
|
149
|
+
{EMAIL_SCENARIOS.map((scenario) => (
|
|
150
|
+
<button
|
|
151
|
+
key={scenario.id}
|
|
152
|
+
type="button"
|
|
153
|
+
onClick={() => setEmail(scenario.email)}
|
|
154
|
+
className="flex w-full items-start gap-2.5 rounded-xl border border-zinc-200 bg-white px-3.5 py-2.5 text-left shadow-[var(--ob-shadow-xs)] transition-all hover:-translate-y-px hover:border-[color:var(--ob-accent-300)] hover:shadow-[var(--ob-shadow-sm)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ob-ring)]"
|
|
155
|
+
>
|
|
156
|
+
<span className="text-base" aria-hidden>
|
|
157
|
+
{scenario.icon}
|
|
158
|
+
</span>
|
|
159
|
+
<span>
|
|
160
|
+
<span className="block text-[13px] font-semibold text-zinc-800">
|
|
161
|
+
{scenario.label}
|
|
162
|
+
</span>
|
|
163
|
+
<span className="block text-[11px] text-zinc-400">
|
|
164
|
+
Vzorový e-mail — předvyplní vstup
|
|
165
|
+
</span>
|
|
166
|
+
</span>
|
|
167
|
+
</button>
|
|
168
|
+
))}
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
) : (
|
|
172
|
+
<div>
|
|
173
|
+
<div className="mb-2 text-[13px] font-semibold text-zinc-600">Zkuste zadat:</div>
|
|
174
|
+
<div className="space-y-2">
|
|
175
|
+
{SAMPLE_PROMPTS.map((prompt) => (
|
|
176
|
+
<button
|
|
177
|
+
key={prompt}
|
|
178
|
+
type="button"
|
|
179
|
+
disabled={isSending}
|
|
180
|
+
onClick={() => send(prompt)}
|
|
181
|
+
className="group flex w-full items-start gap-2 rounded-xl border border-zinc-200 bg-white px-3.5 py-2.5 text-left text-[13px] leading-relaxed text-zinc-600 shadow-[var(--ob-shadow-xs)] transition-all hover:-translate-y-px hover:border-[color:var(--ob-accent-300)] hover:text-zinc-900 hover:shadow-[var(--ob-shadow-sm)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ob-ring)] disabled:cursor-not-allowed disabled:opacity-60"
|
|
182
|
+
>
|
|
183
|
+
<span
|
|
184
|
+
className="mt-0.5 text-[color:var(--ob-accent-400)] transition-colors group-hover:text-[color:var(--ob-accent-600)]"
|
|
185
|
+
aria-hidden
|
|
186
|
+
>
|
|
187
|
+
↳
|
|
188
|
+
</span>
|
|
189
|
+
<span>„{prompt}“</span>
|
|
190
|
+
</button>
|
|
191
|
+
))}
|
|
192
|
+
</div>
|
|
193
|
+
</div>
|
|
194
|
+
)}
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
{mode === 'email' ? (
|
|
198
|
+
<EmailTestRun
|
|
199
|
+
email={email}
|
|
200
|
+
onEmailChange={setEmail}
|
|
201
|
+
bookSource={state.bookSource}
|
|
202
|
+
knowledge={state.knowledge}
|
|
203
|
+
onEditBook={() => navigateToPath(ONBOARDING_STEPS[0].path)}
|
|
204
|
+
/>
|
|
205
|
+
) : (
|
|
206
|
+
<TestChat
|
|
207
|
+
messages={state.testMessages}
|
|
208
|
+
isSending={isSending}
|
|
209
|
+
onSend={send}
|
|
210
|
+
onStop={stop}
|
|
211
|
+
onRetry={isRetryAvailable ? retry : undefined}
|
|
212
|
+
/>
|
|
213
|
+
)}
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
<StepFooter
|
|
217
|
+
left={
|
|
218
|
+
<Button variant="ghost" onClick={() => navigateToPath(ONBOARDING_STEPS[1].path)}>
|
|
219
|
+
← Znalosti
|
|
220
|
+
</Button>
|
|
221
|
+
}
|
|
222
|
+
right={
|
|
223
|
+
<Button trailingIcon={<span aria-hidden>→</span>} onClick={() => navigateToPath(ONBOARDING_STEPS[3].path)}>
|
|
224
|
+
Uložit první verzi
|
|
225
|
+
</Button>
|
|
226
|
+
}
|
|
227
|
+
/>
|
|
228
|
+
</div>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function ModeToggle({ mode, onChange }: { readonly mode: TestMode; readonly onChange: (mode: TestMode) => void }) {
|
|
233
|
+
const options: ReadonlyArray<{ id: TestMode; label: string; icon: string }> = [
|
|
234
|
+
{ id: 'email', label: 'E-mailový test', icon: '📨' },
|
|
235
|
+
{ id: 'chat', label: 'Konverzace', icon: '💬' },
|
|
236
|
+
];
|
|
237
|
+
return (
|
|
238
|
+
<div className="inline-flex rounded-xl border border-zinc-200 bg-white p-0.5 shadow-[var(--ob-shadow-xs)]" role="tablist" aria-label="Režim testu">
|
|
239
|
+
{options.map((option) => {
|
|
240
|
+
const isActive = option.id === mode;
|
|
241
|
+
return (
|
|
242
|
+
<button
|
|
243
|
+
key={option.id}
|
|
244
|
+
type="button"
|
|
245
|
+
role="tab"
|
|
246
|
+
aria-selected={isActive}
|
|
247
|
+
onClick={() => onChange(option.id)}
|
|
248
|
+
className={cn(
|
|
249
|
+
'inline-flex items-center gap-1.5 rounded-lg px-3.5 py-1.5 text-[13px] font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ob-ring)]',
|
|
250
|
+
isActive
|
|
251
|
+
? 'bg-[color:var(--ob-accent-600)] text-white'
|
|
252
|
+
: 'text-zinc-500 hover:bg-zinc-100 hover:text-zinc-800',
|
|
253
|
+
)}
|
|
254
|
+
>
|
|
255
|
+
<span aria-hidden>{option.icon}</span>
|
|
256
|
+
{option.label}
|
|
257
|
+
</button>
|
|
258
|
+
);
|
|
259
|
+
})}
|
|
260
|
+
</div>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ONBOARDING_STEPS } from '../../config/steps';
|
|
4
|
+
import { useManGoOnboardingNavigation } from '../../ManGoOnboardingNavigation';
|
|
5
|
+
import { useOnboarding } from '../../state/OnboardingProvider';
|
|
6
|
+
import { SectionLabel, StepCard, StepFooter } from '../StepFrame';
|
|
7
|
+
import { Button } from '../ui/Button';
|
|
8
|
+
import { InputField, TextareaField } from '../ui/Field';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Entry screen of the wizard ("Řekněte mi o agentovi"). Captures the agent name + a
|
|
12
|
+
* one-sentence brief, then continues to the Book step where the draft is generated.
|
|
13
|
+
*/
|
|
14
|
+
export function ZadaniStep() {
|
|
15
|
+
const { navigateToPath } = useManGoOnboardingNavigation();
|
|
16
|
+
const { state, update } = useOnboarding();
|
|
17
|
+
const isContinueEnabled = state.agentName.trim().length > 0 && state.agentBrief.trim().length > 0;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div className="mx-auto max-w-2xl">
|
|
21
|
+
<StepCard>
|
|
22
|
+
<SectionLabel className="text-[color:var(--ob-accent-600)]">Začněme</SectionLabel>
|
|
23
|
+
<h1 className="mt-2 text-balance text-3xl font-extrabold tracking-tight text-zinc-900">
|
|
24
|
+
Řekněte mi o agentovi
|
|
25
|
+
</h1>
|
|
26
|
+
<p className="mt-2.5 text-sm leading-relaxed text-zinc-500">
|
|
27
|
+
Stačí název a jedna věta o tom, co má agent dělat. Z toho připravíme draft booku, který si pak
|
|
28
|
+
libovolně upravíte.
|
|
29
|
+
</p>
|
|
30
|
+
|
|
31
|
+
<div className="mt-8 space-y-6">
|
|
32
|
+
<InputField
|
|
33
|
+
label="Název agenta"
|
|
34
|
+
placeholder="např. E-mail asistent pro Alzu"
|
|
35
|
+
value={state.agentName}
|
|
36
|
+
hint="Vyberte název srozumitelný pro klienta, ne pro technika."
|
|
37
|
+
onChange={(event) => update({ agentName: event.target.value })}
|
|
38
|
+
/>
|
|
39
|
+
<TextareaField
|
|
40
|
+
label="Co má agent dělat?"
|
|
41
|
+
labelSuffix={<span className="font-normal text-zinc-400">(jedna věta stačí)</span>}
|
|
42
|
+
rows={2}
|
|
43
|
+
placeholder="např. Pomáhá zákaznickému servisu odpovídat na příchozí e-maily od zákazníků."
|
|
44
|
+
value={state.agentBrief}
|
|
45
|
+
onChange={(event) => update({ agentBrief: event.target.value })}
|
|
46
|
+
/>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<StepFooter
|
|
50
|
+
right={
|
|
51
|
+
<Button
|
|
52
|
+
disabled={!isContinueEnabled}
|
|
53
|
+
leadingIcon={<span aria-hidden>✨</span>}
|
|
54
|
+
trailingIcon={<span aria-hidden>→</span>}
|
|
55
|
+
onClick={() => navigateToPath(ONBOARDING_STEPS[0].path)}
|
|
56
|
+
>
|
|
57
|
+
Vygenerovat draft booku
|
|
58
|
+
</Button>
|
|
59
|
+
}
|
|
60
|
+
/>
|
|
61
|
+
</StepCard>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Badge.tsx
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../lib/cn';
|
|
4
|
+
|
|
5
|
+
export type BadgeTone = 'neutral' | 'accent' | 'success' | 'warning' | 'error';
|
|
6
|
+
|
|
7
|
+
type BadgeProps = {
|
|
8
|
+
readonly tone?: BadgeTone;
|
|
9
|
+
/** Renders a small leading status dot. */
|
|
10
|
+
readonly dot?: boolean;
|
|
11
|
+
readonly children: ReactNode;
|
|
12
|
+
readonly className?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const TONES: Record<BadgeTone, { chip: string; dot: string }> = {
|
|
16
|
+
neutral: { chip: 'bg-zinc-100 text-zinc-600', dot: 'bg-zinc-400' },
|
|
17
|
+
accent: {
|
|
18
|
+
chip: 'bg-[color:var(--ob-accent-50)] text-[color:var(--ob-accent-700)] ring-1 ring-inset ring-[color:var(--ob-accent-100)]',
|
|
19
|
+
dot: 'bg-[color:var(--ob-accent-500)]',
|
|
20
|
+
},
|
|
21
|
+
success: { chip: 'bg-emerald-100 text-emerald-700', dot: 'bg-emerald-500' },
|
|
22
|
+
warning: { chip: 'bg-amber-100 text-amber-700', dot: 'bg-amber-500' },
|
|
23
|
+
error: { chip: 'bg-red-100 text-red-700', dot: 'bg-red-500' },
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** Compact status pill / chip. */
|
|
27
|
+
export function Badge({ tone = 'neutral', dot = false, children, className }: BadgeProps) {
|
|
28
|
+
const t = TONES[tone];
|
|
29
|
+
return (
|
|
30
|
+
<span
|
|
31
|
+
className={cn(
|
|
32
|
+
'inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium',
|
|
33
|
+
t.chip,
|
|
34
|
+
className,
|
|
35
|
+
)}
|
|
36
|
+
>
|
|
37
|
+
{dot && <span className={cn('h-1.5 w-1.5 rounded-full', t.dot)} aria-hidden />}
|
|
38
|
+
{children}
|
|
39
|
+
</span>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../lib/cn';
|
|
4
|
+
|
|
5
|
+
export type BannerTone = 'info' | 'success' | 'warning' | 'error';
|
|
6
|
+
|
|
7
|
+
type BannerProps = {
|
|
8
|
+
readonly tone?: BannerTone;
|
|
9
|
+
/** Optional bold heading shown above the body. */
|
|
10
|
+
readonly title?: ReactNode;
|
|
11
|
+
readonly children?: ReactNode;
|
|
12
|
+
/** Override the default emoji/icon for the tone. Pass `null` to hide it. */
|
|
13
|
+
readonly icon?: ReactNode;
|
|
14
|
+
readonly className?: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const TONES: Record<BannerTone, { wrap: string; icon: string; title: string; defaultIcon: string }> = {
|
|
18
|
+
info: {
|
|
19
|
+
wrap: 'border-[color:var(--ob-accent-200)] bg-[color:var(--ob-accent-50)] text-[color:var(--ob-accent-900)]',
|
|
20
|
+
icon: 'text-[color:var(--ob-accent-600)]',
|
|
21
|
+
title: 'text-[color:var(--ob-accent-900)]',
|
|
22
|
+
defaultIcon: 'ℹ️',
|
|
23
|
+
},
|
|
24
|
+
success: {
|
|
25
|
+
wrap: 'border-emerald-200 bg-emerald-50 text-emerald-800',
|
|
26
|
+
icon: 'text-emerald-600',
|
|
27
|
+
title: 'text-emerald-900',
|
|
28
|
+
defaultIcon: '✓',
|
|
29
|
+
},
|
|
30
|
+
warning: {
|
|
31
|
+
wrap: 'border-amber-200 bg-amber-50 text-amber-800',
|
|
32
|
+
icon: 'text-amber-600',
|
|
33
|
+
title: 'text-amber-900',
|
|
34
|
+
defaultIcon: '⚠️',
|
|
35
|
+
},
|
|
36
|
+
error: {
|
|
37
|
+
wrap: 'border-red-200 bg-red-50 text-red-800',
|
|
38
|
+
icon: 'text-red-600',
|
|
39
|
+
title: 'text-red-900',
|
|
40
|
+
defaultIcon: '⚠️',
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** Inline contextual message — info / success / warning / error. */
|
|
45
|
+
export function Banner({ tone = 'info', title, children, icon, className }: BannerProps) {
|
|
46
|
+
const t = TONES[tone];
|
|
47
|
+
const isIconShown = icon !== null;
|
|
48
|
+
return (
|
|
49
|
+
<div
|
|
50
|
+
role={tone === 'error' || tone === 'warning' ? 'alert' : 'status'}
|
|
51
|
+
className={cn(
|
|
52
|
+
'flex gap-3 rounded-xl border px-4 py-3 text-sm leading-relaxed',
|
|
53
|
+
'shadow-[var(--ob-shadow-xs)]',
|
|
54
|
+
t.wrap,
|
|
55
|
+
className,
|
|
56
|
+
)}
|
|
57
|
+
>
|
|
58
|
+
{isIconShown && (
|
|
59
|
+
<span className={cn('mt-px shrink-0 text-base leading-none', t.icon)} aria-hidden>
|
|
60
|
+
{icon ?? t.defaultIcon}
|
|
61
|
+
</span>
|
|
62
|
+
)}
|
|
63
|
+
<div className="min-w-0">
|
|
64
|
+
{title && <div className={cn('font-semibold', t.title)}>{title}</div>}
|
|
65
|
+
{children && <div className={cn(Boolean(title) && 'mt-0.5 opacity-90')}>{children}</div>}
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../lib/cn';
|
|
4
|
+
import { Spinner } from './Spinner';
|
|
5
|
+
import { FOCUS_RING } from './tokens';
|
|
6
|
+
|
|
7
|
+
export type ButtonVariant = 'primary' | 'outline' | 'ghost' | 'inverted';
|
|
8
|
+
export type ButtonSize = 'md' | 'sm';
|
|
9
|
+
|
|
10
|
+
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
11
|
+
readonly variant?: ButtonVariant;
|
|
12
|
+
readonly size?: ButtonSize;
|
|
13
|
+
/** When true, shows a spinner and disables the button (additive — defaults to false). */
|
|
14
|
+
readonly isLoading?: boolean;
|
|
15
|
+
/** Optional icon rendered before the label. */
|
|
16
|
+
readonly leadingIcon?: ReactNode;
|
|
17
|
+
/** Optional icon rendered after the label. */
|
|
18
|
+
readonly trailingIcon?: ReactNode;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const BASE =
|
|
22
|
+
'inline-flex select-none items-center justify-center gap-2 rounded-xl font-semibold ' +
|
|
23
|
+
'transition-[box-shadow,transform,filter,color,border-color,background-color] duration-150 ease-out ' +
|
|
24
|
+
'active:translate-y-px disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-45 ' +
|
|
25
|
+
FOCUS_RING;
|
|
26
|
+
|
|
27
|
+
const VARIANTS: Record<ButtonVariant, string> = {
|
|
28
|
+
primary:
|
|
29
|
+
'text-[color:var(--ob-ink)] bg-[image:var(--ob-grad-primary)] ' +
|
|
30
|
+
'shadow-[var(--ob-shadow-accent)] hover:shadow-[var(--ob-shadow-lg)] hover:brightness-[1.04] active:brightness-95',
|
|
31
|
+
outline:
|
|
32
|
+
'border border-zinc-200/80 bg-white text-zinc-700 shadow-[var(--ob-shadow-xs)] ' +
|
|
33
|
+
'hover:border-zinc-300 hover:bg-zinc-50 hover:text-zinc-900 active:bg-zinc-100',
|
|
34
|
+
ghost: 'text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900 active:bg-zinc-200/70',
|
|
35
|
+
inverted:
|
|
36
|
+
'bg-white text-[color:var(--ob-accent-700)] shadow-[var(--ob-shadow-sm)] ' +
|
|
37
|
+
'hover:bg-white/90 active:bg-white/80',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const SIZES: Record<ButtonSize, string> = {
|
|
41
|
+
md: 'h-10 px-5 text-sm',
|
|
42
|
+
sm: 'h-8 px-3.5 text-[13px]',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export function Button({
|
|
46
|
+
variant = 'primary',
|
|
47
|
+
size = 'md',
|
|
48
|
+
isLoading = false,
|
|
49
|
+
leadingIcon,
|
|
50
|
+
trailingIcon,
|
|
51
|
+
className,
|
|
52
|
+
type = 'button',
|
|
53
|
+
disabled,
|
|
54
|
+
children,
|
|
55
|
+
...props
|
|
56
|
+
}: ButtonProps) {
|
|
57
|
+
const spinnerSize = size === 'sm' ? 'h-3.5 w-3.5' : 'h-4 w-4';
|
|
58
|
+
return (
|
|
59
|
+
<button
|
|
60
|
+
type={type}
|
|
61
|
+
disabled={disabled || isLoading}
|
|
62
|
+
aria-busy={isLoading || undefined}
|
|
63
|
+
className={cn(BASE, VARIANTS[variant], SIZES[size], className)}
|
|
64
|
+
{...props}
|
|
65
|
+
>
|
|
66
|
+
{isLoading ? (
|
|
67
|
+
<Spinner className={cn(spinnerSize, variant === 'primary' && 'border-white/40 border-t-white')} />
|
|
68
|
+
) : (
|
|
69
|
+
leadingIcon && <span className="-ml-0.5 inline-flex shrink-0 items-center">{leadingIcon}</span>
|
|
70
|
+
)}
|
|
71
|
+
{children}
|
|
72
|
+
{!isLoading && trailingIcon && (
|
|
73
|
+
<span className="-mr-0.5 inline-flex shrink-0 items-center">{trailingIcon}</span>
|
|
74
|
+
)}
|
|
75
|
+
</button>
|
|
76
|
+
);
|
|
77
|
+
}
|
package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Card.tsx
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../lib/cn';
|
|
4
|
+
import { FOCUS_RING } from './tokens';
|
|
5
|
+
|
|
6
|
+
export type CardVariant = 'default' | 'elevated' | 'interactive';
|
|
7
|
+
|
|
8
|
+
type CardProps = HTMLAttributes<HTMLDivElement> & {
|
|
9
|
+
/** Visual weight. `elevated` lifts off the page; `interactive` adds hover feedback. */
|
|
10
|
+
readonly variant?: CardVariant;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const VARIANTS: Record<CardVariant, string> = {
|
|
14
|
+
default: 'shadow-[var(--ob-shadow-sm)]',
|
|
15
|
+
elevated: 'shadow-[var(--ob-shadow-lg)]',
|
|
16
|
+
interactive:
|
|
17
|
+
'shadow-[var(--ob-shadow-sm)] cursor-pointer transition-[box-shadow,border-color,transform] ' +
|
|
18
|
+
'duration-200 hover:-translate-y-0.5 hover:border-[color:var(--ob-accent-200)] hover:shadow-[var(--ob-shadow-md)] ' +
|
|
19
|
+
FOCUS_RING,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function Card({ variant = 'default', className, ...props }: CardProps) {
|
|
23
|
+
return (
|
|
24
|
+
<div
|
|
25
|
+
className={cn(
|
|
26
|
+
'rounded-2xl border border-zinc-200/60 bg-white',
|
|
27
|
+
VARIANTS[variant],
|
|
28
|
+
className,
|
|
29
|
+
)}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
}
|
package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Field.tsx
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { useId } from 'react';
|
|
2
|
+
import type { InputHTMLAttributes, ReactNode, TextareaHTMLAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
import { cn } from '../../lib/cn';
|
|
5
|
+
import { FOCUS_RING_INPUT } from './tokens';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Shared control styling for text inputs / textareas. Exported so hand-rolled inputs
|
|
9
|
+
* elsewhere in the module (URL field, chat composer) stay visually identical — DRY.
|
|
10
|
+
*/
|
|
11
|
+
export const CONTROL =
|
|
12
|
+
'w-full rounded-xl border border-zinc-300 bg-white px-3.5 py-2.5 text-sm text-zinc-900 ' +
|
|
13
|
+
'shadow-[var(--ob-shadow-xs)] placeholder:text-zinc-400 transition-[border-color,box-shadow] ' +
|
|
14
|
+
'disabled:cursor-not-allowed disabled:bg-zinc-50 disabled:text-zinc-400 ' +
|
|
15
|
+
FOCUS_RING_INPUT;
|
|
16
|
+
|
|
17
|
+
/** Applied on top of CONTROL when a field is in an error state. */
|
|
18
|
+
export const CONTROL_ERROR =
|
|
19
|
+
'border-red-300 focus:border-red-400 focus:ring-red-500/15';
|
|
20
|
+
|
|
21
|
+
type FieldShellProps = {
|
|
22
|
+
readonly label: string;
|
|
23
|
+
readonly hint?: ReactNode;
|
|
24
|
+
readonly htmlFor: string;
|
|
25
|
+
readonly children: ReactNode;
|
|
26
|
+
readonly labelSuffix?: ReactNode;
|
|
27
|
+
readonly error?: ReactNode;
|
|
28
|
+
readonly describedById?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function FieldShell({ label, hint, htmlFor, children, labelSuffix, error, describedById }: FieldShellProps) {
|
|
32
|
+
return (
|
|
33
|
+
<div className="space-y-1.5">
|
|
34
|
+
<label htmlFor={htmlFor} className="flex items-center gap-2 text-[13px] font-semibold text-zinc-700">
|
|
35
|
+
{label}
|
|
36
|
+
{labelSuffix}
|
|
37
|
+
</label>
|
|
38
|
+
{children}
|
|
39
|
+
{error ? (
|
|
40
|
+
<p id={describedById} className="flex items-center gap-1.5 text-xs font-medium text-red-600">
|
|
41
|
+
<svg viewBox="0 0 16 16" className="h-3.5 w-3.5 shrink-0" fill="currentColor" aria-hidden>
|
|
42
|
+
<path d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM7.25 5a.75.75 0 011.5 0v3.5a.75.75 0 01-1.5 0V5zM8 10.25a.9.9 0 100 1.8.9.9 0 000-1.8z" />
|
|
43
|
+
</svg>
|
|
44
|
+
{error}
|
|
45
|
+
</p>
|
|
46
|
+
) : (
|
|
47
|
+
hint && (
|
|
48
|
+
<p id={describedById} className="text-xs leading-relaxed text-zinc-400">
|
|
49
|
+
{hint}
|
|
50
|
+
</p>
|
|
51
|
+
)
|
|
52
|
+
)}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
type InputFieldProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'id'> & {
|
|
58
|
+
readonly label: string;
|
|
59
|
+
readonly hint?: ReactNode;
|
|
60
|
+
readonly labelSuffix?: ReactNode;
|
|
61
|
+
/** When set, the control turns red and this message replaces the hint. Additive. */
|
|
62
|
+
readonly error?: ReactNode;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export function InputField({ label, hint, labelSuffix, error, className, ...props }: InputFieldProps) {
|
|
66
|
+
const id = useId();
|
|
67
|
+
const descId = `${id}-desc`;
|
|
68
|
+
return (
|
|
69
|
+
<FieldShell label={label} hint={hint} htmlFor={id} labelSuffix={labelSuffix} error={error} describedById={descId}>
|
|
70
|
+
<input
|
|
71
|
+
id={id}
|
|
72
|
+
aria-invalid={error ? true : undefined}
|
|
73
|
+
aria-describedby={error || hint ? descId : undefined}
|
|
74
|
+
className={cn(CONTROL, Boolean(error) && CONTROL_ERROR, className)}
|
|
75
|
+
{...props}
|
|
76
|
+
/>
|
|
77
|
+
</FieldShell>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
type TextareaFieldProps = Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'id'> & {
|
|
82
|
+
readonly label: string;
|
|
83
|
+
readonly hint?: ReactNode;
|
|
84
|
+
readonly labelSuffix?: ReactNode;
|
|
85
|
+
/** When set, the control turns red and this message replaces the hint. Additive. */
|
|
86
|
+
readonly error?: ReactNode;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export function TextareaField({ label, hint, labelSuffix, error, className, ...props }: TextareaFieldProps) {
|
|
90
|
+
const id = useId();
|
|
91
|
+
const descId = `${id}-desc`;
|
|
92
|
+
return (
|
|
93
|
+
<FieldShell label={label} hint={hint} htmlFor={id} labelSuffix={labelSuffix} error={error} describedById={descId}>
|
|
94
|
+
<textarea
|
|
95
|
+
id={id}
|
|
96
|
+
aria-invalid={error ? true : undefined}
|
|
97
|
+
aria-describedby={error || hint ? descId : undefined}
|
|
98
|
+
className={cn(CONTROL, 'resize-y', Boolean(error) && CONTROL_ERROR, className)}
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
</FieldShell>
|
|
102
|
+
);
|
|
103
|
+
}
|