Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,7 @@
import { PhaseStageProgress } from "@/components/brainstorming/PhaseStageProgress";
import { useRouter } from "next/navigation";
import { useNav } from "@/lib/contexts/NavContext";
import {
buildProjectUrl,
buildPhaseConversationsUrl,
buildPhaseSpecUrl,
buildPhasePromptPlanUrl,
buildPhaseFeaturesUrl,
buildPhaseUrl,
} from "@/lib/url";
import { buildProjectUrl } from "@/lib/url";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
Expand Down Expand Up @@ -63,6 +56,7 @@

const [phase, setPhase] = useState<BrainstormingPhase | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [loadError, setLoadError] = useState<string | null>(null);
const [showArchiveDialog, setShowArchiveDialog] = useState(false);
const [showRenameDialog, setShowRenameDialog] = useState(false);
const [isArchiving, setIsArchiving] = useState(false);
Expand Down Expand Up @@ -96,6 +90,7 @@
setPhase(data);
} catch (err) {
console.error("Failed to load phase:", err);
setLoadError("Phase not found");
} finally {
setIsLoading(false);
}
Expand All @@ -104,63 +99,61 @@
loadPhase();
}, [phaseId]);

// Build tabs using URL builders when project and phase are available
const getTabsForPhase = () => {
if (!currentProject || !phase) {
return [];
}
const projectInfo = { name: currentProject.name, short_id: currentProject.short_id };
const phaseInfo = { title: phase.title, short_id: phase.short_id };
const basePhaseUrl = buildPhaseUrl(projectInfo, phaseInfo);
// Build tabs using URL params directly (always available, no dependency on NavContext timing)
const basePhaseUrl = `/projects/${projectId}/brainstorming/${phaseId}`;

return [
{
name: "Conversations",
href: buildPhaseConversationsUrl(projectInfo, phaseInfo),
icon: MessageSquare,
},
{
name: "Specification",
href: buildPhaseSpecUrl(projectInfo, phaseInfo),
icon: FileText,
},
{
name: "Prompt Plan",
href: buildPhasePromptPlanUrl(projectInfo, phaseInfo),
icon: ClipboardList,
},
{
name: "Phase Features",
href: buildPhaseFeaturesUrl(projectInfo, phaseInfo),
icon: Boxes,
},
{
name: "Description",
href: `${basePhaseUrl}/description`,
icon: Info,
},
{
name: "Activity",
href: `${basePhaseUrl}/activity`,
icon: Clock,
},
];
};
const tabs = [
{
name: "Conversations",
href: `${basePhaseUrl}/conversations`,
icon: MessageSquare,
},
{
name: "Specification",
href: `${basePhaseUrl}/spec`,
icon: FileText,
},
{
name: "Prompt Plan",
href: `${basePhaseUrl}/prompt-plan`,
icon: ClipboardList,
},
{
name: "Phase Features",
href: `${basePhaseUrl}/features`,
icon: Boxes,
},
{
name: "Description",
href: `${basePhaseUrl}/description`,
icon: Info,
},
{
name: "Activity",
href: `${basePhaseUrl}/activity`,
icon: Clock,
},
];

const tabs = getTabsForPhase();
// Determine active tab
const activeTab = tabs.find((tab) => pathname.startsWith(tab.href))?.href || tabs[0].href;

// Determine active tab (only if tabs are available)
const activeTab =
tabs.length > 0 ? tabs.find((tab) => pathname.startsWith(tab.href))?.href || tabs[0].href : "";

if (isLoading || tabs.length === 0) {
if (isLoading) {
return (
<div className="flex items-center justify-center py-12">
<Loader2 className="text-muted-foreground h-8 w-8 animate-spin" />
</div>
);
}

if (loadError || !phase) {
return (
<div className="flex min-h-[200px] items-center justify-center">
<p className="text-destructive">{loadError || "Phase not found"}</p>
</div>
);
}

return (
<div className="space-y-6">
{/* Breadcrumb */}
Expand Down Expand Up @@ -248,7 +241,7 @@
<AlertDialogTitle>Archive Phase?</AlertDialogTitle>
<AlertDialogDescription>
Are you sure you want to archive the phase{" "}
<span className="text-foreground font-medium">"{phase?.title}"</span>?

Check warning on line 244 in frontend/app/projects/[projectId]/brainstorming/[phaseId]/BrainstormingLayoutClient.tsx

View workflow job for this annotation

GitHub Actions / Frontend (ESLint + Prettier)

`"` can be escaped with `&quot;`, `&ldquo;`, `&#34;`, `&rdquo;`

Check warning on line 244 in frontend/app/projects/[projectId]/brainstorming/[phaseId]/BrainstormingLayoutClient.tsx

View workflow job for this annotation

GitHub Actions / Frontend (ESLint + Prettier)

`"` can be escaped with `&quot;`, `&ldquo;`, `&#34;`, `&rdquo;`
<span className="mt-2 block text-amber-600 dark:text-amber-400">
Archived phases can be restored later.
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@

useEffect(() => {
fetchModules();
}, [projectId, phaseId]);

Check warning on line 289 in frontend/app/projects/[projectId]/brainstorming/[phaseId]/conversations/page.tsx

View workflow job for this annotation

GitHub Actions / Frontend (ESLint + Prettier)

React Hook useEffect has a missing dependency: 'fetchModules'. Either include it or remove the dependency array

// Auto-select feature when loaded:
// 1. If ?feature=xxx query param is present, select that feature (for email links)
Expand Down Expand Up @@ -363,7 +363,7 @@
setIsGeneratingLocal(false);
}
}
}, [wsJobs, fetchPhase, isGeneratingLocal, processedJobIds]);

Check warning on line 366 in frontend/app/projects/[projectId]/brainstorming/[phaseId]/conversations/page.tsx

View workflow job for this annotation

GitHub Actions / Frontend (ESLint + Prettier)

React Hook useEffect has a missing dependency: 'fetchModules'. Either include it or remove the dependency array

// Handle initial generation from empty state
const handleInitialGenerate = async () => {
Expand Down Expand Up @@ -461,7 +461,7 @@
<FeatureThreadPanel
key={selectedFeature.id}
feature={selectedFeature}
projectId={currentProject?.id || ""}
projectId={projectId}
orgId={orgId}
onClose={handleCloseThread}
onAnswered={() => fetchModules(true)}
Expand All @@ -472,10 +472,10 @@
} else {
setSidePanelContent(null);
}
}, [

Check warning on line 475 in frontend/app/projects/[projectId]/brainstorming/[phaseId]/conversations/page.tsx

View workflow job for this annotation

GitHub Actions / Frontend (ESLint + Prettier)

React Hook useEffect has a missing dependency: 'fetchModules'. Either include it or remove the dependency array
selectedFeature,
orgId,
currentProject?.id,
projectId,
highlightedItemId,
targetMessageSequence,
setSidePanelContent,
Expand Down Expand Up @@ -791,7 +791,7 @@
<AlertDialogTitle>Delete Aspect?</AlertDialogTitle>
<AlertDialogDescription>
Are you sure you want to delete the aspect{" "}
<span className="text-foreground font-medium">"{moduleToDelete?.title}"</span>?

Check warning on line 794 in frontend/app/projects/[projectId]/brainstorming/[phaseId]/conversations/page.tsx

View workflow job for this annotation

GitHub Actions / Frontend (ESLint + Prettier)

`"` can be escaped with `&quot;`, `&ldquo;`, `&#34;`, `&rdquo;`

Check warning on line 794 in frontend/app/projects/[projectId]/brainstorming/[phaseId]/conversations/page.tsx

View workflow job for this annotation

GitHub Actions / Frontend (ESLint + Prettier)

`"` can be escaped with `&quot;`, `&ldquo;`, `&#34;`, `&rdquo;`
<span className="mt-2 block text-amber-600 dark:text-amber-400">
This will also delete all clarification questions within this aspect.
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@

import { useParams } from "next/navigation";
import { DraftFinalTabs } from "@/components/brainstorming";
import { useNav } from "@/lib/contexts/NavContext";

export default function BrainstormingPromptPlanPage() {
const params = useParams();
const { currentProject } = useNav();
const projectId = params.projectId as string;
const phaseId = params.phaseId as string;

return (
<DraftFinalTabs phaseId={phaseId} projectId={currentProject?.id || ""} docType="prompt_plan" />
);
return <DraftFinalTabs phaseId={phaseId} projectId={projectId} docType="prompt_plan" />;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,11 @@

import { useParams } from "next/navigation";
import { DraftFinalTabs } from "@/components/brainstorming";
import { useNav } from "@/lib/contexts/NavContext";

export default function BrainstormingSpecPage() {
const params = useParams();
const { currentProject } = useNav();
const projectId = params.projectId as string;
const phaseId = params.phaseId as string;

return (
<DraftFinalTabs
phaseId={phaseId}
projectId={currentProject?.id || ""}
docType="specification"
/>
);
return <DraftFinalTabs phaseId={phaseId} projectId={projectId} docType="specification" />;
}
11 changes: 10 additions & 1 deletion frontend/components/MarkdownWithMentions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import React, { Fragment } from "react";
import ReactMarkdown from "react-markdown";
import type { Components } from "react-markdown";
import remarkGfm from "remark-gfm";
import { useRouter } from "next/navigation";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";

Expand Down Expand Up @@ -271,11 +272,19 @@ export function MarkdownWithMentions({
<table className="min-w-full border-collapse">{children}</table>
</div>
),
th: ({ children }) => (
<th className="border-border bg-muted border px-3 py-1.5 text-left text-sm font-semibold">
{children}
</th>
),
td: ({ children }) => <td className="border-border border px-3 py-1.5 text-sm">{children}</td>,
};

return (
<div className={className}>
<ReactMarkdown components={components}>{text}</ReactMarkdown>
<ReactMarkdown remarkPlugins={[remarkGfm]} components={components}>
{text}
</ReactMarkdown>
</div>
);
}
Loading