('asc');
const filteredAndSorted = useMemo(() => {
let result = worktrees;
@@ -131,12 +142,18 @@ export default function SessionsPage() {
}
case 'repositoryName': {
comparison = a.repositoryName.toLowerCase().localeCompare(b.repositoryName.toLowerCase());
+ if (comparison === 0) {
+ comparison = a.name.toLowerCase().localeCompare(b.name.toLowerCase());
+ }
break;
}
case 'status': {
const priorityA = WORKTREE_STATUS_PRIORITY[a.status ?? ''] ?? DEFAULT_STATUS_PRIORITY;
const priorityB = WORKTREE_STATUS_PRIORITY[b.status ?? ''] ?? DEFAULT_STATUS_PRIORITY;
comparison = priorityA - priorityB;
+ if (comparison === 0) {
+ comparison = a.repositoryName.toLowerCase().localeCompare(b.repositoryName.toLowerCase());
+ }
break;
}
default:
@@ -265,13 +282,7 @@ export default function SessionsPage() {
{wt.status && (
{formatStatus(wt.status)}
diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx
index cdfe79e5..14fb8c37 100644
--- a/src/components/layout/Header.tsx
+++ b/src/components/layout/Header.tsx
@@ -24,7 +24,7 @@ const NAV_ITEMS: Array<{ label: string; href: string; isActive: (pathname: strin
{ label: 'Home', href: '/', isActive: (p) => p === '/' },
{ label: 'Sessions', href: '/sessions', isActive: (p) => p.startsWith('/sessions') },
{ label: 'Repos', href: '/repositories', isActive: (p) => p.startsWith('/repositories') },
- { label: 'Review', href: '/review', isActive: (p) => p.startsWith('/review') },
+ { label: 'Review/Report', href: '/review', isActive: (p) => p.startsWith('/review') },
{ label: 'More', href: '/more', isActive: (p) => p.startsWith('/more') },
];
diff --git a/src/components/mobile/GlobalMobileNav.tsx b/src/components/mobile/GlobalMobileNav.tsx
index ab6fd8f3..00dbe6de 100644
--- a/src/components/mobile/GlobalMobileNav.tsx
+++ b/src/components/mobile/GlobalMobileNav.tsx
@@ -57,7 +57,7 @@ const MoreIcon = () => (
const MOBILE_NAV_TABS: MobileNavTab[] = [
{ label: 'Home', href: '/', isActive: (p) => p === '/', icon: },
{ label: 'Sessions', href: '/sessions', isActive: (p) => p.startsWith('/sessions'), icon: },
- { label: 'Review', href: '/review', isActive: (p) => p.startsWith('/review'), icon: },
+ { label: 'Review/Report', href: '/review', isActive: (p) => p.startsWith('/review'), icon: },
{ label: 'More', href: '/more', isActive: (p) => p.startsWith('/more'), icon: },
];
diff --git a/src/components/review/ReportTab.tsx b/src/components/review/ReportTab.tsx
index 9882b36e..4b9e8b58 100644
--- a/src/components/review/ReportTab.tsx
+++ b/src/components/review/ReportTab.tsx
@@ -9,7 +9,7 @@
import { useState, useEffect, useCallback } from 'react';
import ReportDatePicker from './ReportDatePicker';
-import { SUMMARY_ALLOWED_TOOLS } from '@/config/review-config';
+import { SUMMARY_ALLOWED_TOOLS, MAX_USER_INSTRUCTION_LENGTH } from '@/config/review-config';
/** Format Date to YYYY-MM-DD */
function formatToday(): string {
@@ -41,6 +41,7 @@ export default function ReportTab() {
const [isGenerating, setIsGenerating] = useState(false);
const [isSaving, setIsSaving] = useState(false);
const [error, setError] = useState(null);
+ const [userInstruction, setUserInstruction] = useState('');
// Fetch report for selected date
const fetchReport = useCallback(async (date: string) => {
@@ -90,6 +91,9 @@ export default function ReportTab() {
if (selectedTool === 'copilot' && modelInput.trim()) {
body.model = modelInput.trim();
}
+ if (userInstruction.trim()) {
+ body.userInstruction = userInstruction.trim();
+ }
const res = await fetch('/api/daily-summary', {
method: 'POST',
@@ -181,6 +185,23 @@ export default function ReportTab() {
)}
+
+
+ {/* User instruction textarea (Issue #612) */}
+
+
+
+ {/* Generate button */}
+