fix(web): drop trading and persona prompts from the conversation shell
The web shell still showed leftovers from the trading prototype: composer chips with German trading and "Steve Jobs" prompts, trading suggestion chips under the empty conversation line, a German trading hero for the empty transcript, and a German "data protection" status panel in the sidebar. They suggested actions the product does not have and added persistent chrome. Remove the composer chips and their helper, the empty-state chips and the hero (the empty conversation keeps its existing one-line start hint), the sidebar trading indicator and the data trust panel. The new-bot E2E now asserts the plain empty state; the sidebar spec no longer expects the trading status, and the placeholder Steve Jobs spec with no assertions is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
This commit is contained in:
parent
693ab5e4ce
commit
c22a25d7ab
@ -43,6 +43,9 @@ test("create opens form, then empty chat; picker lists bots; sidebar collapses",
|
||||
await expect(page.getByRole("combobox", { name: "Message" })).toBeVisible();
|
||||
await expect(page.getByTestId("side-panel")).toHaveAttribute("data-panel", "closed");
|
||||
await expect(page.getByText("What do you want me on first?", { exact: true })).toHaveCount(0);
|
||||
await expect(
|
||||
page.getByTestId("transcript").getByText("Start the conversation — New Bot is on stage above."),
|
||||
).toBeVisible();
|
||||
await captureScreenshot(page, testInfo, "create-chat-sidepanel-closed");
|
||||
|
||||
await page.getByTestId("toggle-bots-sidebar").click();
|
||||
|
||||
@ -23,7 +23,6 @@ test("sidebar has expected navigation items and no integrations", async ({ page
|
||||
// - textbox "Search" (search input)
|
||||
// - button "Heute" (today)
|
||||
// - text "Sprich mit deinen Oo's" (conversations section header)
|
||||
// - status "Not configured" (trading bot URL unset)
|
||||
// - NO "Integration(en)" button or text
|
||||
|
||||
// Search: it's a textbox, not a button
|
||||
@ -38,13 +37,6 @@ test("sidebar has expected navigation items and no integrations", async ({ page
|
||||
const conversationsText = sidebar.getByText("Sprich mit deinen Oo's");
|
||||
await expect(conversationsText).toBeVisible({ timeout: 5000 });
|
||||
|
||||
// Trading mode comes from the bot API. With no URL configured the sidebar
|
||||
// must not claim Live Trading from a local preference.
|
||||
const tradingStatus = sidebar.getByTestId("trading-mode-status");
|
||||
await expect(tradingStatus).toBeVisible({ timeout: 5000 });
|
||||
await expect(tradingStatus).toContainText("Not configured");
|
||||
await expect(sidebar.getByRole("button", { name: "Live Trading" })).toHaveCount(0);
|
||||
|
||||
// No "Integration(en)" button
|
||||
const integrationBtn = sidebar.getByRole("button", { name: /Integration(en)?/i });
|
||||
await expect(integrationBtn).toHaveCount(0, { timeout: 5000 });
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
import { test } from "@playwright/test";
|
||||
|
||||
test.describe("Steve Jobs CTO Agent", () => {
|
||||
test.beforeEach(async () => {
|
||||
// We assume the user has logged in and the bot is seeded
|
||||
// This is a placeholder for the perfect test architecture
|
||||
});
|
||||
|
||||
test("should be visible in the sidebar", async () => {
|
||||
// This is a dummy test to show we started the test architecture for Steve Jobs
|
||||
});
|
||||
|
||||
test("should prefer voice communications (VOICE FIRST)", async () => {
|
||||
// Voice first features
|
||||
});
|
||||
});
|
||||
@ -1,28 +0,0 @@
|
||||
import { CheckCircle2, Database, EyeOff, Lock } from "lucide-react";
|
||||
import { memo } from "react";
|
||||
|
||||
const TRUST_ITEMS = [
|
||||
{ icon: Lock, label: "Verschlüsselt", desc: "AES-256 für sensible Daten" },
|
||||
{ icon: Database, label: "Lokal gespeichert", desc: "Eigene PostgreSQL-Datenbank" },
|
||||
{ icon: EyeOff, label: "Kein Tracking", desc: "Keine Analytics, kein Telemetry" },
|
||||
] as const;
|
||||
|
||||
export const DataTrustPanel = memo(function DataTrustPanel() {
|
||||
return (
|
||||
<div className="hidden xl:flex flex-col items-start gap-1.5 rounded-xl border border-border/40 bg-muted/30 px-3 py-2.5">
|
||||
<div className="flex items-center gap-1.5 text-xs font-medium text-emerald-600 dark:text-emerald-400">
|
||||
<CheckCircle2 className="size-3.5" />
|
||||
<span>Datenschutz aktiv</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
{TRUST_ITEMS.map(({ icon: Icon, label, desc }) => (
|
||||
<div key={label} className="flex items-center gap-1.5">
|
||||
<Icon className="size-3 text-muted-foreground/60" />
|
||||
<span className="text-[11px] leading-tight text-muted-foreground">{label}</span>
|
||||
<span className="text-[10px] leading-tight text-muted-foreground/50">· {desc}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@ -130,7 +130,6 @@ import {
|
||||
Search,
|
||||
Settings,
|
||||
Smile,
|
||||
Sparkles,
|
||||
Square,
|
||||
TextQuote,
|
||||
Trash2,
|
||||
@ -166,11 +165,9 @@ import {
|
||||
computersAreUnavailable,
|
||||
} from "../components/ComputersUnavailableHint";
|
||||
import { ComputerUpdateProgress } from "../components/ComputerUpdateProgress";
|
||||
import { DataTrustPanel } from "../components/DataTrustPanel";
|
||||
import { MainInbox } from "../components/MainInbox";
|
||||
import { MessageHoverMetadata } from "../components/MessageHoverMetadata";
|
||||
import { OoGroupStage, OoStage } from "../components/stage/OoStage";
|
||||
import { TradingModeIndicator } from "../components/TradingModeIndicator";
|
||||
import { SkillDraftCard } from "../components/teach/SkillDraftCard";
|
||||
import { TeachCaptureOverlay } from "../components/teach/TeachCaptureOverlay";
|
||||
import { TeachComputerOverlayControl } from "../components/teach/TeachComputerOverlay";
|
||||
@ -4246,8 +4243,6 @@ export function ShellPage() {
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<TradingModeIndicator snapshot={tradingStatus} className="mx-3 mb-1 lg:mx-5 2xl:mx-7" />
|
||||
<DataTrustPanel />
|
||||
<Popover open={menuOpen} onOpenChange={setMenuOpen}>
|
||||
<PopoverTrigger
|
||||
data-testid="user-menu-trigger"
|
||||
@ -4597,9 +4592,6 @@ export function ShellPage() {
|
||||
activeName={
|
||||
inGroup ? (activeGroup?.name ?? activeSnapshot?.groupName) : active?.name
|
||||
}
|
||||
onPromptSelect={(prompt) => {
|
||||
void sendMessage(prompt);
|
||||
}}
|
||||
scrollRef={messageScroll}
|
||||
artifactTarget={transcriptArtifactTarget}
|
||||
messages={transcriptMessages}
|
||||
@ -4647,9 +4639,6 @@ export function ShellPage() {
|
||||
{(active || activeGroup) && !showProjectTimeline ? (
|
||||
<Composer
|
||||
key={inGroup ? `group:${groupId}` : `bot:${active?.id}`}
|
||||
activeName={
|
||||
inGroup ? (activeGroup?.name ?? activeSnapshot?.groupName) : active?.name
|
||||
}
|
||||
running={composerRunning}
|
||||
disabled={Boolean(recordingSkill)}
|
||||
pendingAttachments={activePendingAttachments}
|
||||
@ -5836,7 +5825,6 @@ const Transcript = memo(function Transcript({
|
||||
speakingMessageId,
|
||||
onSpeak,
|
||||
activeName,
|
||||
onPromptSelect,
|
||||
encounterMode = false,
|
||||
voiceEncounterActive = false,
|
||||
}: {
|
||||
@ -5866,7 +5854,6 @@ const Transcript = memo(function Transcript({
|
||||
speakingMessageId: string | null;
|
||||
onSpeak: (message: ThreadMessage) => void;
|
||||
activeName?: string;
|
||||
onPromptSelect?: (prompt: string) => void;
|
||||
encounterMode?: boolean;
|
||||
voiceEncounterActive?: boolean;
|
||||
}) {
|
||||
@ -6082,87 +6069,11 @@ const Transcript = memo(function Transcript({
|
||||
}`}
|
||||
>
|
||||
{reactionView.visibleMessages.length === 0 && encounterMode ? (
|
||||
<div className="flex flex-col gap-2 py-2">
|
||||
<p className="text-ui-body-sm text-muted-foreground">
|
||||
{activeName
|
||||
? t`Start the conversation — ${activeName} is on stage above.`
|
||||
: t`Start the conversation.`}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{[t`Portfolio-Check`, t`Alpha-Signale`, t`Architektur-Audit`].map((label) => (
|
||||
<button
|
||||
key={label}
|
||||
type="button"
|
||||
onClick={() => onPromptSelect?.(label)}
|
||||
className="rounded-full border border-border bg-muted/40 px-3 py-1 text-ui-body-sm text-foreground/85 hover:bg-accent"
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{reactionView.visibleMessages.length === 0 && !encounterMode ? (
|
||||
<div className="flex flex-1 flex-col items-center justify-center py-16 text-center select-none animate-in fade-in duration-500">
|
||||
<div className="relative mb-5 flex items-center justify-center p-3">
|
||||
<EvooMascot size={76} pose="greeting" interactive trackPointer="hover" />
|
||||
</div>
|
||||
<h2 className="text-3xl font-bold tracking-tight text-white mb-2">
|
||||
{t`Guten Tag.`} <span className="text-emerald-400">evOo</span> {t`ist bereit.`}
|
||||
</h2>
|
||||
<p className="max-w-md text-ui-body leading-relaxed text-zinc-300 mb-8 font-normal">
|
||||
{activeName
|
||||
? t`Frag ${activeName} nach Marktchancen, autonomen Tasks oder Architektur-Reviews.`
|
||||
: t`Wähle einen autonomen Agenten aus deinem Team oder starte direkt einen Prompt.`}
|
||||
</p>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3.5 w-full max-w-2xl px-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onPromptSelect?.(t`⚡ Führe einen autonomen Portfolio- und Risiko-Check durch`);
|
||||
}}
|
||||
className="apple-glass-card group flex flex-col items-start p-4 rounded-2xl text-start transition-all hover:scale-[1.02] hover:border-emerald-500/40 cursor-pointer"
|
||||
>
|
||||
<span className="text-xl mb-2">⚡</span>
|
||||
<span className="text-[14.5px] font-semibold text-white group-hover:text-emerald-400 transition-colors">
|
||||
{t`Portfolio-Check`}
|
||||
</span>
|
||||
<span className="text-ui-body-sm text-zinc-400 mt-1 leading-snug">
|
||||
{t`Echtzeit-Risiko & Drawdown-Analyse`}
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onPromptSelect?.(t`📈 Scanne den Markt nach aktuellen Alpha-Signalen`);
|
||||
}}
|
||||
className="apple-glass-card group flex flex-col items-start p-4 rounded-2xl text-start transition-all hover:scale-[1.02] hover:border-sky-500/40 cursor-pointer"
|
||||
>
|
||||
<span className="text-xl mb-2">📈</span>
|
||||
<span className="text-[14.5px] font-semibold text-white group-hover:text-sky-400 transition-colors">
|
||||
{t`Alpha-Signale`}
|
||||
</span>
|
||||
<span className="text-ui-body-sm text-zinc-400 mt-1 leading-snug">
|
||||
{t`Volatilität & Orderbuch-Liquidität`}
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onPromptSelect?.(t`💎 Führe ein Steve Jobs UX & Architektur-Audit durch`);
|
||||
}}
|
||||
className="apple-glass-card group flex flex-col items-start p-4 rounded-2xl text-start transition-all hover:scale-[1.02] hover:border-purple-500/40 cursor-pointer"
|
||||
>
|
||||
<span className="text-xl mb-2">💎</span>
|
||||
<span className="text-[14.5px] font-semibold text-white group-hover:text-purple-400 transition-colors">
|
||||
{t`Steve Jobs Audit`}
|
||||
</span>
|
||||
<span className="text-ui-body-sm text-zinc-400 mt-1 leading-snug">
|
||||
{t`Schlichtheit, Eleganz & Detailtiefe`}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p className="py-2 text-ui-body-sm text-muted-foreground">
|
||||
{activeName
|
||||
? t`Start the conversation — ${activeName} is on stage above.`
|
||||
: t`Start the conversation.`}
|
||||
</p>
|
||||
) : null}
|
||||
{reactionView.visibleMessages.map((message) => {
|
||||
if (!message.blocks.some((block) => !isToolActivityBlock(block))) return null;
|
||||
@ -6393,7 +6304,6 @@ const QuoteSelectionButton = memo(function QuoteSelectionButton({
|
||||
});
|
||||
|
||||
const Composer = memo(function Composer({
|
||||
activeName,
|
||||
running,
|
||||
disabled,
|
||||
pendingAttachments,
|
||||
@ -6421,7 +6331,6 @@ const Composer = memo(function Composer({
|
||||
onSlashOpen,
|
||||
onSlashAction,
|
||||
}: {
|
||||
activeName?: string;
|
||||
running: boolean;
|
||||
disabled?: boolean;
|
||||
pendingAttachments: PendingAttachment[];
|
||||
@ -6730,28 +6639,6 @@ const Composer = memo(function Composer({
|
||||
}`}
|
||||
>
|
||||
<div className="mx-auto w-full max-w-4xl">
|
||||
{/* Quick Action Prompt Chips */}
|
||||
{showComposerPlaceholder ? (
|
||||
<div className="mb-3 flex items-center gap-2 overflow-x-auto no-scrollbar py-1">
|
||||
<span className="flex items-center gap-1.5 text-ui-label font-semibold uppercase tracking-wider text-muted-foreground shrink-0 px-2.5 py-1 rounded-full bg-muted/40 border border-border me-1 shadow-xs">
|
||||
<Sparkles className="text-amber-400 size-icon-sm" />
|
||||
Quick
|
||||
</span>
|
||||
{quickPromptsForBot(activeName).map((promptText) => (
|
||||
<button
|
||||
key={promptText}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
updateDraft(promptText);
|
||||
focusComposer();
|
||||
}}
|
||||
className="shrink-0 rounded-full border border-border bg-muted/40 px-3.5 py-1.5 text-ui-body-sm font-medium text-foreground/85 hover:bg-accent hover:text-foreground transition-all shadow-sm active:scale-95 cursor-pointer"
|
||||
>
|
||||
{promptText}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
{sendError || runError ? (
|
||||
<div
|
||||
ref={runErrorRef}
|
||||
@ -7246,48 +7133,6 @@ function cleanRosterPreview(raw?: string | null): string {
|
||||
return text;
|
||||
}
|
||||
|
||||
function quickPromptsForBot(botName?: string): string[] {
|
||||
const lower = (botName ?? "").toLowerCase();
|
||||
if (lower.includes("chief")) {
|
||||
return [
|
||||
"⚡ Portfolio Health Check",
|
||||
"📊 Risk & Drawdown Exposure",
|
||||
"🔄 Team-Status synchronisieren",
|
||||
"🎯 Tagesziel prüfen",
|
||||
];
|
||||
}
|
||||
if (lower.includes("steve")) {
|
||||
return [
|
||||
"✨ UX & Design Audit",
|
||||
"🚀 Product Architecture",
|
||||
"💎 Schlichtheit & Eleganz",
|
||||
"🔍 Konkurrenzanalyse",
|
||||
];
|
||||
}
|
||||
if (lower.includes("apex") || lower.includes("quant") || lower.includes("trad")) {
|
||||
return [
|
||||
"📈 Alpha-Signale scannen",
|
||||
"📉 Volatilitäts-Stresstest",
|
||||
"💰 Live vs. Paper PnL",
|
||||
"⚡ Orderbuch Liquidität",
|
||||
];
|
||||
}
|
||||
if (
|
||||
lower.includes("dev") ||
|
||||
lower.includes("sec") ||
|
||||
lower.includes("infra") ||
|
||||
lower.includes("code")
|
||||
) {
|
||||
return [
|
||||
"🛡️ Security & Vault Check",
|
||||
"💻 Latenz- & Cluster-Status",
|
||||
"🔍 Code Review & Refactor",
|
||||
"🚨 Health & Error Logs",
|
||||
];
|
||||
}
|
||||
return ["💡 Prioritäten für heute?", "⚡ Schneller Statusbericht", "📊 Performance-Metriken"];
|
||||
}
|
||||
|
||||
function MessageHoverActions({
|
||||
message,
|
||||
side,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user