Merge story-31: View Upcoming Stories
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> # Conflicts: # frontend/src/api/workflow.ts # frontend/src/components/Chat.test.tsx # frontend/src/components/Chat.tsx # server/src/http/workflow.rs
This commit is contained in:
@@ -3,13 +3,14 @@ import Markdown from "react-markdown";
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";
|
||||
import { api, ChatWebSocket } from "../api/client";
|
||||
import type { ReviewStory } from "../api/workflow";
|
||||
import type { ReviewStory, UpcomingStory } from "../api/workflow";
|
||||
import { workflowApi } from "../api/workflow";
|
||||
import type { Message, ProviderConfig, ToolCall } from "../types";
|
||||
import { ChatHeader } from "./ChatHeader";
|
||||
import { GatePanel } from "./GatePanel";
|
||||
import { ReviewPanel } from "./ReviewPanel";
|
||||
import { TodoPanel } from "./TodoPanel";
|
||||
import { UpcomingPanel } from "./UpcomingPanel";
|
||||
|
||||
const { useCallback, useEffect, useRef, useState } = React;
|
||||
|
||||
@@ -68,6 +69,12 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
|
||||
const [todoError, setTodoError] = useState<string | null>(null);
|
||||
const [isTodoLoading, setIsTodoLoading] = useState(false);
|
||||
const [lastTodoRefresh, setLastTodoRefresh] = useState<Date | null>(null);
|
||||
const [upcomingStories, setUpcomingStories] = useState<UpcomingStory[]>([]);
|
||||
const [upcomingError, setUpcomingError] = useState<string | null>(null);
|
||||
const [isUpcomingLoading, setIsUpcomingLoading] = useState(false);
|
||||
const [lastUpcomingRefresh, setLastUpcomingRefresh] = useState<Date | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
const storyId = "26_establish_tdd_workflow_and_gates";
|
||||
const gateStatusColor = isGateLoading
|
||||
@@ -375,6 +382,58 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
setIsUpcomingLoading(true);
|
||||
setUpcomingError(null);
|
||||
|
||||
workflowApi
|
||||
.getUpcomingStories()
|
||||
.then((response) => {
|
||||
if (!active) return;
|
||||
setUpcomingStories(response.stories);
|
||||
setLastUpcomingRefresh(new Date());
|
||||
})
|
||||
.catch((error) => {
|
||||
if (!active) return;
|
||||
const message =
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Failed to load upcoming stories.";
|
||||
setUpcomingError(message);
|
||||
setUpcomingStories([]);
|
||||
})
|
||||
.finally(() => {
|
||||
if (active) {
|
||||
setIsUpcomingLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const refreshUpcomingStories = async () => {
|
||||
setIsUpcomingLoading(true);
|
||||
setUpcomingError(null);
|
||||
|
||||
try {
|
||||
const response = await workflowApi.getUpcomingStories();
|
||||
setUpcomingStories(response.stories);
|
||||
setLastUpcomingRefresh(new Date());
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Failed to load upcoming stories.";
|
||||
setUpcomingError(message);
|
||||
setUpcomingStories([]);
|
||||
} finally {
|
||||
setIsUpcomingLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const refreshReviewQueue = async () => {
|
||||
setIsReviewLoading(true);
|
||||
setReviewError(null);
|
||||
@@ -676,6 +735,14 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
|
||||
lastTodoRefresh={lastTodoRefresh}
|
||||
onRefresh={refreshTodos}
|
||||
/>
|
||||
|
||||
<UpcomingPanel
|
||||
stories={upcomingStories}
|
||||
isLoading={isUpcomingLoading}
|
||||
error={upcomingError}
|
||||
lastRefresh={lastUpcomingRefresh}
|
||||
onRefresh={refreshUpcomingStories}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user