jettypod 4.4.118 → 4.4.121
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/.env +4 -3
- package/Cargo.lock +6450 -0
- package/Cargo.toml +35 -0
- package/README.md +5 -1
- package/TAURI-MIGRATION-PLAN.md +840 -0
- package/apps/dashboard/app/connect-claude/page.tsx +5 -6
- package/apps/dashboard/app/decision/[id]/page.tsx +63 -58
- package/apps/dashboard/app/demo/gates/page.tsx +43 -45
- package/apps/dashboard/app/design-system/page.tsx +868 -0
- package/apps/dashboard/app/globals.css +80 -4
- package/apps/dashboard/app/install-claude/page.tsx +4 -6
- package/apps/dashboard/app/login/page.tsx +72 -54
- package/apps/dashboard/app/page.tsx +101 -48
- package/apps/dashboard/app/settings/page.tsx +61 -13
- package/apps/dashboard/app/signup/page.tsx +242 -0
- package/apps/dashboard/app/subscribe/page.tsx +0 -2
- package/apps/dashboard/app/tests/page.tsx +37 -4
- package/apps/dashboard/app/welcome/page.tsx +13 -16
- package/apps/dashboard/app/work/[id]/page.tsx +117 -118
- package/apps/dashboard/app/work/[id]/proof/page.tsx +1489 -0
- package/apps/dashboard/components/AppShell.tsx +92 -85
- package/apps/dashboard/components/CardMenu.tsx +45 -12
- package/apps/dashboard/components/ClaudePanel.tsx +771 -850
- package/apps/dashboard/components/ClaudePanelInput.tsx +43 -15
- package/apps/dashboard/components/ConnectClaudeScreen.tsx +17 -34
- package/apps/dashboard/components/CopyableId.tsx +3 -4
- package/apps/dashboard/components/DetailReviewActions.tsx +100 -0
- package/apps/dashboard/components/DragContext.tsx +134 -63
- package/apps/dashboard/components/DraggableCard.tsx +3 -5
- package/apps/dashboard/components/DropZone.tsx +6 -7
- package/apps/dashboard/components/EditableDetailDescription.tsx +7 -13
- package/apps/dashboard/components/EditableDetailTitle.tsx +6 -13
- package/apps/dashboard/components/EditableTitle.tsx +26 -7
- package/apps/dashboard/components/ElapsedTimer.tsx +66 -0
- package/apps/dashboard/components/EpicGroup.tsx +359 -0
- package/apps/dashboard/components/GateCard.tsx +79 -17
- package/apps/dashboard/components/GateChoiceCard.tsx +15 -18
- package/apps/dashboard/components/InstallClaudeScreen.tsx +15 -32
- package/apps/dashboard/components/JettyLoader.tsx +37 -0
- package/apps/dashboard/components/KanbanBoard.tsx +368 -958
- package/apps/dashboard/components/KanbanCard.tsx +740 -0
- package/apps/dashboard/components/LazyCard.tsx +62 -0
- package/apps/dashboard/components/LazyMarkdown.tsx +11 -0
- package/apps/dashboard/components/MainNav.tsx +38 -73
- package/apps/dashboard/components/MessageBlock.tsx +468 -0
- package/apps/dashboard/components/ModeStartCard.tsx +15 -16
- package/apps/dashboard/components/OnboardingWelcome.tsx +213 -0
- package/apps/dashboard/components/PlaceholderCard.tsx +3 -4
- package/apps/dashboard/components/ProjectSwitcher.tsx +30 -30
- package/apps/dashboard/components/PrototypeTimeline.tsx +72 -51
- package/apps/dashboard/components/RealTimeKanbanWrapper.tsx +406 -388
- package/apps/dashboard/components/RealTimeTestsWrapper.tsx +373 -235
- package/apps/dashboard/components/ReviewFooter.tsx +139 -0
- package/apps/dashboard/components/SessionList.tsx +19 -19
- package/apps/dashboard/components/SubscribeContent.tsx +91 -47
- package/apps/dashboard/components/TestTree.tsx +16 -16
- package/apps/dashboard/components/TipCard.tsx +16 -17
- package/apps/dashboard/components/Toast.tsx +5 -6
- package/apps/dashboard/components/TypeIcon.tsx +55 -0
- package/apps/dashboard/components/ViewModeToolbar.tsx +104 -0
- package/apps/dashboard/components/WaveCompletionAnimation.tsx +52 -65
- package/apps/dashboard/components/WelcomeScreen.tsx +19 -35
- package/apps/dashboard/components/WorkItemHeader.tsx +4 -5
- package/apps/dashboard/components/WorkItemTree.tsx +11 -32
- package/apps/dashboard/components/settings/AccountSection.tsx +55 -35
- package/apps/dashboard/components/settings/AiContextSection.tsx +89 -0
- package/apps/dashboard/components/settings/ContextDocumentsSection.tsx +317 -0
- package/apps/dashboard/components/settings/EnvVarsSection.tsx +74 -152
- package/apps/dashboard/components/settings/GeneralSection.tsx +162 -56
- package/apps/dashboard/components/settings/ProjectStackSection.tsx +948 -0
- package/apps/dashboard/components/settings/SettingsLayout.tsx +4 -5
- package/apps/dashboard/components/ui/Button.tsx +104 -0
- package/apps/dashboard/components/ui/Input.tsx +78 -0
- package/apps/dashboard/components.json +1 -1
- package/apps/dashboard/contexts/ClaudeSessionContext.tsx +711 -418
- package/apps/dashboard/contexts/ConnectionStatusContext.tsx +25 -5
- package/apps/dashboard/contexts/UsageContext.tsx +87 -32
- package/apps/dashboard/dev.sh +35 -0
- package/apps/dashboard/eslint.config.mjs +9 -9
- package/apps/dashboard/hooks/useKanbanAnimation.ts +29 -0
- package/apps/dashboard/hooks/useKanbanUndo.ts +83 -0
- package/apps/dashboard/hooks/useWebSocket.ts +138 -83
- package/apps/dashboard/index.html +73 -0
- package/apps/dashboard/lib/constants.ts +43 -0
- package/apps/dashboard/lib/data-bridge.ts +722 -0
- package/apps/dashboard/lib/db.ts +69 -1265
- package/apps/dashboard/lib/environment-config.ts +173 -0
- package/apps/dashboard/lib/environment-verification.ts +119 -0
- package/apps/dashboard/lib/kanban-utils.ts +270 -0
- package/apps/dashboard/lib/proof-run.ts +495 -0
- package/apps/dashboard/lib/proof-scenario-runner.ts +346 -0
- package/apps/dashboard/lib/run-migrations.js +27 -2
- package/apps/dashboard/lib/service-recovery.ts +326 -0
- package/apps/dashboard/lib/session-state-machine.ts +1 -0
- package/apps/dashboard/lib/session-state-utils.ts +0 -164
- package/apps/dashboard/lib/session-stream-manager.ts +308 -134
- package/apps/dashboard/lib/shadows.ts +7 -0
- package/apps/dashboard/lib/stream-manager-registry.ts +46 -6
- package/apps/dashboard/lib/tauri-bridge.ts +102 -0
- package/apps/dashboard/lib/tauri.ts +106 -0
- package/apps/dashboard/lib/utils.ts +6 -0
- package/apps/dashboard/next-env.d.ts +1 -1
- package/apps/dashboard/package.json +21 -32
- package/apps/dashboard/public/bug-icon.png +0 -0
- package/apps/dashboard/public/buoy-icon.png +0 -0
- package/apps/dashboard/public/fonts/Satoshi-Variable.woff2 +0 -0
- package/apps/dashboard/public/fonts/Satoshi-VariableItalic.woff2 +0 -0
- package/apps/dashboard/public/in-flight-seagull.png +0 -0
- package/apps/dashboard/public/jetty-icon-loading-alt.svg +11 -0
- package/apps/dashboard/public/jetty-icon-loading.svg +11 -0
- package/apps/dashboard/public/jettypod_logo.png +0 -0
- package/apps/dashboard/public/pier-icon.png +0 -0
- package/apps/dashboard/public/star-icon.png +0 -0
- package/apps/dashboard/public/wrench-icon.png +0 -0
- package/apps/dashboard/scripts/tauri-build.js +228 -0
- package/apps/dashboard/scripts/upload-tauri-to-r2.js +125 -0
- package/apps/dashboard/scripts/ws-server.js +191 -0
- package/apps/dashboard/src/main.tsx +12 -0
- package/apps/dashboard/src/router.tsx +107 -0
- package/apps/dashboard/src/vite-env.d.ts +1 -0
- package/apps/dashboard/tsconfig.json +7 -12
- package/apps/dashboard/tsconfig.tsbuildinfo +1 -1
- package/apps/dashboard/vite.config.ts +33 -0
- package/apps/update-server/src/index.ts +228 -80
- package/claude-hooks/global-guardrails.js +14 -13
- package/crates/jettypod-cli/Cargo.toml +19 -0
- package/crates/jettypod-cli/src/commands.rs +1249 -0
- package/crates/jettypod-cli/src/main.rs +595 -0
- package/crates/jettypod-core/Cargo.toml +26 -0
- package/crates/jettypod-core/build.rs +98 -0
- package/crates/jettypod-core/migrations/V1__baseline.sql +197 -0
- package/crates/jettypod-core/migrations/V2__work_items_indexes.sql +6 -0
- package/crates/jettypod-core/migrations/V3__qa_steps.sql +2 -0
- package/crates/jettypod-core/src/auth.rs +294 -0
- package/crates/jettypod-core/src/config.rs +397 -0
- package/crates/jettypod-core/src/db/mod.rs +507 -0
- package/crates/jettypod-core/src/db/recovery.rs +114 -0
- package/crates/jettypod-core/src/db/startup.rs +101 -0
- package/crates/jettypod-core/src/db/validate.rs +149 -0
- package/crates/jettypod-core/src/error.rs +76 -0
- package/crates/jettypod-core/src/git.rs +458 -0
- package/crates/jettypod-core/src/lib.rs +20 -0
- package/crates/jettypod-core/src/sessions.rs +625 -0
- package/crates/jettypod-core/src/skills.rs +556 -0
- package/crates/jettypod-core/src/work.rs +1086 -0
- package/crates/jettypod-core/src/worktree.rs +628 -0
- package/crates/jettypod-core/src/ws.rs +767 -0
- package/cucumber-test.cjs +6 -0
- package/cucumber.js +9 -3
- package/docs/COMMAND_REFERENCE.md +34 -0
- package/hooks/post-checkout +32 -75
- package/hooks/post-merge +111 -10
- package/jest.setup.js +1 -0
- package/jettypod.js +145 -116
- package/lib/bdd-preflight.js +96 -0
- package/lib/chore-taxonomy.js +33 -10
- package/lib/database.js +36 -16
- package/lib/db-watcher.js +1 -1
- package/lib/git-hooks/pre-commit +1 -1
- package/lib/jettypod-backup.js +27 -4
- package/lib/merge-lock.js +111 -253
- package/lib/migrations/027-plan-at-creation-column.js +3 -1
- package/lib/migrations/029-remove-autoincrement.js +307 -0
- package/lib/migrations/029-rename-corrupted-to-cleaned.js +149 -0
- package/lib/migrations/030-rejection-round-columns.js +54 -0
- package/lib/migrations/031-session-isolation-index.js +17 -0
- package/lib/migrations/index.js +47 -4
- package/lib/schema.js +10 -5
- package/lib/seed-onboarding.js +1 -1
- package/lib/update-command/index.js +9 -175
- package/lib/work-commands/index.js +144 -19
- package/lib/work-tracking/index.js +148 -27
- package/lib/worktree-diagnostics.js +16 -16
- package/lib/worktree-facade.js +1 -1
- package/lib/worktree-manager.js +8 -8
- package/lib/worktree-reconciler.js +5 -5
- package/package.json +9 -2
- package/scripts/ndjson-to-cucumber-json.js +152 -0
- package/scripts/postinstall.js +25 -0
- package/skills-templates/bug-mode/SKILL.md +79 -20
- package/skills-templates/bug-planning/SKILL.md +25 -29
- package/skills-templates/chore-mode/SKILL.md +171 -69
- package/skills-templates/chore-mode/verification.js +51 -10
- package/skills-templates/chore-planning/SKILL.md +47 -18
- package/skills-templates/design-system-selection/SKILL.md +273 -0
- package/skills-templates/epic-planning/SKILL.md +82 -48
- package/skills-templates/external-transition/SKILL.md +47 -47
- package/skills-templates/feature-planning/SKILL.md +173 -74
- package/skills-templates/production-mode/SKILL.md +69 -49
- package/skills-templates/request-routing/SKILL.md +4 -4
- package/skills-templates/simple-improvement/SKILL.md +74 -29
- package/skills-templates/speed-mode/SKILL.md +217 -141
- package/skills-templates/stable-mode/SKILL.md +148 -89
- package/apps/dashboard/README.md +0 -36
- package/apps/dashboard/app/api/claude/[workItemId]/message/route.ts +0 -386
- package/apps/dashboard/app/api/claude/[workItemId]/pin/route.ts +0 -24
- package/apps/dashboard/app/api/claude/[workItemId]/route.ts +0 -167
- package/apps/dashboard/app/api/claude/sessions/[sessionId]/content/route.ts +0 -52
- package/apps/dashboard/app/api/claude/sessions/[sessionId]/message/route.ts +0 -378
- package/apps/dashboard/app/api/claude/sessions/[sessionId]/pin/route.ts +0 -24
- package/apps/dashboard/app/api/claude/sessions/cleanup/route.ts +0 -34
- package/apps/dashboard/app/api/claude/sessions/route.ts +0 -184
- package/apps/dashboard/app/api/decisions/[id]/route.ts +0 -25
- package/apps/dashboard/app/api/internal/set-project/route.ts +0 -17
- package/apps/dashboard/app/api/kanban/route.ts +0 -15
- package/apps/dashboard/app/api/settings/env-vars/route.ts +0 -125
- package/apps/dashboard/app/api/settings/general/route.ts +0 -21
- package/apps/dashboard/app/api/tests/route.ts +0 -9
- package/apps/dashboard/app/api/tests/run/route.ts +0 -82
- package/apps/dashboard/app/api/tests/run/stream/route.ts +0 -71
- package/apps/dashboard/app/api/tests/undefined/route.ts +0 -9
- package/apps/dashboard/app/api/usage/route.ts +0 -17
- package/apps/dashboard/app/api/work/[id]/description/route.ts +0 -21
- package/apps/dashboard/app/api/work/[id]/epic/route.ts +0 -21
- package/apps/dashboard/app/api/work/[id]/order/route.ts +0 -21
- package/apps/dashboard/app/api/work/[id]/status/route.ts +0 -21
- package/apps/dashboard/app/api/work/[id]/title/route.ts +0 -21
- package/apps/dashboard/app/layout.tsx +0 -43
- package/apps/dashboard/components/UpgradeBanner.tsx +0 -29
- package/apps/dashboard/electron/ipc-handlers.js +0 -1028
- package/apps/dashboard/electron/main.js +0 -2124
- package/apps/dashboard/electron/preload.js +0 -123
- package/apps/dashboard/electron/session-manager.js +0 -141
- package/apps/dashboard/electron-builder.config.js +0 -357
- package/apps/dashboard/hooks/useClaudeSessions.ts +0 -299
- package/apps/dashboard/lib/claude-process-manager.ts +0 -492
- package/apps/dashboard/lib/db-bridge.ts +0 -282
- package/apps/dashboard/lib/prototypes.ts +0 -202
- package/apps/dashboard/lib/test-results-db.ts +0 -307
- package/apps/dashboard/lib/tests.ts +0 -282
- package/apps/dashboard/next.config.js +0 -50
- package/apps/dashboard/postcss.config.mjs +0 -7
- package/apps/dashboard/public/file.svg +0 -1
- package/apps/dashboard/public/globe.svg +0 -1
- package/apps/dashboard/public/next.svg +0 -1
- package/apps/dashboard/public/vercel.svg +0 -1
- package/apps/dashboard/public/window.svg +0 -1
- package/apps/dashboard/scripts/download-node.js +0 -104
- package/apps/dashboard/scripts/upload-to-r2.js +0 -89
- package/docs/bdd-guidance.md +0 -390
|
@@ -1,121 +1,138 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import { useParams, Link, useNavigate } from 'react-router-dom';
|
|
2
3
|
import { WorkItemTree } from '@/components/WorkItemTree';
|
|
3
4
|
import { WorkItemHeader } from '@/components/WorkItemHeader';
|
|
4
5
|
import { EditableDetailTitle } from '@/components/EditableDetailTitle';
|
|
5
6
|
import { EditableDetailDescription } from '@/components/EditableDetailDescription';
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
7
|
+
import { TYPE_LABELS, STATUS_LABELS, MODE_LABELS_FULL } from '@/lib/constants';
|
|
8
|
+
import { TypeIcon } from '@/components/TypeIcon';
|
|
9
|
+
import { DetailReviewActions } from '@/components/DetailReviewActions';
|
|
10
|
+
import { dataBridge, prefetch } from '@/lib/data-bridge';
|
|
11
|
+
import type { WorkItemData, DecisionData } from '@/lib/data-bridge';
|
|
12
|
+
|
|
13
|
+
export default function WorkItemPage() {
|
|
14
|
+
const { id } = useParams<{ id: string }>();
|
|
15
|
+
const navigate = useNavigate();
|
|
16
|
+
const [item, setItem] = useState<WorkItemData | null>(null);
|
|
17
|
+
const [children, setChildren] = useState<WorkItemData[]>([]);
|
|
18
|
+
const [decisions, setDecisions] = useState<DecisionData[]>([]);
|
|
19
|
+
const [parentItem, setParentItem] = useState<WorkItemData | null>(null);
|
|
20
|
+
const [loading, setLoading] = useState(true);
|
|
21
|
+
const [notFound, setNotFound] = useState(false);
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
async function loadData() {
|
|
25
|
+
const workItemId = parseInt(id || '', 10);
|
|
26
|
+
if (isNaN(workItemId)) {
|
|
27
|
+
setNotFound(true);
|
|
28
|
+
setLoading(false);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
// Uses prefetch cache — if the user hovered the kanban card, data is
|
|
34
|
+
// already loaded. Otherwise fetches fresh (same parallel IPC calls).
|
|
35
|
+
const { item: workItem, children: childItems, decisions: decisionItems } =
|
|
36
|
+
await prefetch.workItem(workItemId);
|
|
37
|
+
|
|
38
|
+
if (!workItem) {
|
|
39
|
+
setNotFound(true);
|
|
40
|
+
setLoading(false);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Parent fetch depends on the work item's parent_id, but we can
|
|
45
|
+
// overlap it with setState calls since React batches them.
|
|
46
|
+
const parent = workItem.parent_id
|
|
47
|
+
? await dataBridge.getWorkItem(workItem.parent_id)
|
|
48
|
+
: null;
|
|
49
|
+
|
|
50
|
+
setItem(workItem);
|
|
51
|
+
setChildren(childItems);
|
|
52
|
+
setDecisions(decisionItems);
|
|
53
|
+
setParentItem(parent);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
console.error('Failed to load work item:', err);
|
|
56
|
+
setNotFound(true);
|
|
57
|
+
} finally {
|
|
58
|
+
setLoading(false);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
loadData();
|
|
62
|
+
}, [id]);
|
|
63
|
+
|
|
64
|
+
const handleTitleChange = useCallback((newTitle: string) => {
|
|
65
|
+
setItem(prev => prev ? { ...prev, title: newTitle } : prev);
|
|
66
|
+
}, []);
|
|
67
|
+
|
|
68
|
+
const handleDescriptionChange = useCallback((newDescription: string) => {
|
|
69
|
+
setItem(prev => prev ? { ...prev, description: newDescription } : prev);
|
|
70
|
+
}, []);
|
|
71
|
+
|
|
72
|
+
if (loading) return null;
|
|
73
|
+
|
|
74
|
+
if (notFound) {
|
|
75
|
+
return (
|
|
76
|
+
<div className="flex-1 flex items-center justify-center">
|
|
77
|
+
<div className="text-center">
|
|
78
|
+
<h1 className="text-2xl font-bold text-zinc-900 dark:text-zinc-100 mb-2">Not Found</h1>
|
|
79
|
+
<p className="text-zinc-500 mb-4">Work item not found.</p>
|
|
80
|
+
<Link to="/" viewTransition className="text-[#5a7d7f] hover:underline">← Back to Dashboard</Link>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
46
84
|
}
|
|
47
85
|
|
|
48
|
-
|
|
49
|
-
const decisions = getDecisionsForWorkItem(workItemId);
|
|
50
|
-
const parentItem = item.parent_id ? getWorkItem(item.parent_id) : null;
|
|
86
|
+
if (!item) return null;
|
|
51
87
|
|
|
52
|
-
const typeInfo =
|
|
53
|
-
const statusInfo =
|
|
88
|
+
const typeInfo = TYPE_LABELS[item.type] || { icon: '📄', label: 'Item' };
|
|
89
|
+
const statusInfo = STATUS_LABELS[item.status] || STATUS_LABELS.backlog;
|
|
54
90
|
|
|
55
91
|
return (
|
|
56
|
-
<div className="
|
|
57
|
-
{/* Header */}
|
|
92
|
+
<div className="flex-1 overflow-y-auto bg-zinc-50 dark:bg-zinc-950">
|
|
58
93
|
<header className="border-b border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900">
|
|
59
|
-
<div className="max-w-4xl mx-auto px-
|
|
60
|
-
<Link
|
|
61
|
-
← Back to Dashboard
|
|
62
|
-
</Link>
|
|
94
|
+
<div className="max-w-4xl mx-auto px-6 py-6">
|
|
95
|
+
<Link to="/" viewTransition className="text-[#5a7d7f] dark:text-[#a3bfc0] hover:underline text-base">← Back to Dashboard</Link>
|
|
63
96
|
</div>
|
|
64
97
|
</header>
|
|
65
98
|
|
|
66
99
|
<main className="max-w-4xl mx-auto px-4 py-6">
|
|
67
|
-
{/* Breadcrumb */}
|
|
68
100
|
{parentItem && (
|
|
69
|
-
<div className="mb-
|
|
70
|
-
<Link
|
|
71
|
-
{
|
|
101
|
+
<div className="mb-6 text-base text-zinc-500">
|
|
102
|
+
<Link to={`/work/${parentItem.id}`} viewTransition className="inline-flex items-center gap-1.5 hover:underline">
|
|
103
|
+
<TypeIcon type={parentItem.type} className="w-6 h-6" /> #{parentItem.id} {parentItem.title}
|
|
72
104
|
</Link>
|
|
73
105
|
<span className="mx-2">→</span>
|
|
74
106
|
</div>
|
|
75
107
|
)}
|
|
76
108
|
|
|
77
|
-
{/* Main card */}
|
|
78
109
|
<div className="bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800 overflow-hidden">
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
<div className="flex items-start justify-between gap-4">
|
|
110
|
+
<div className="px-8 py-6 border-b border-zinc-200 dark:border-zinc-800">
|
|
111
|
+
<div className="flex items-start justify-between gap-6">
|
|
82
112
|
<div className="flex-1 min-w-0">
|
|
83
|
-
<WorkItemHeader
|
|
84
|
-
|
|
85
|
-
title={item.title}
|
|
86
|
-
type={item.type}
|
|
87
|
-
typeIcon={typeInfo.icon}
|
|
88
|
-
typeLabel={typeInfo.label}
|
|
89
|
-
/>
|
|
90
|
-
<EditableDetailTitle title={item.title} itemId={item.id} />
|
|
113
|
+
<WorkItemHeader id={item.id} title={item.title} type={item.type} typeLabel={typeInfo.label} />
|
|
114
|
+
<EditableDetailTitle title={item.title} itemId={item.id} onTitleChange={handleTitleChange} />
|
|
91
115
|
</div>
|
|
92
116
|
<div className="flex items-center gap-2">
|
|
93
|
-
{item.mode &&
|
|
94
|
-
<span className={`text-
|
|
95
|
-
{
|
|
117
|
+
{item.mode && MODE_LABELS_FULL[item.mode] && (
|
|
118
|
+
<span className={`text-base px-3 py-1.5 rounded ${MODE_LABELS_FULL[item.mode].color}`}>
|
|
119
|
+
{MODE_LABELS_FULL[item.mode].label}
|
|
96
120
|
</span>
|
|
97
121
|
)}
|
|
98
|
-
<span className={`text-
|
|
99
|
-
|
|
100
|
-
</span>
|
|
122
|
+
<span className={`text-base px-3 py-1.5 rounded ${statusInfo.color}`}>{statusInfo.label}</span>
|
|
123
|
+
{!!item.ready_for_review && <DetailReviewActions workItemId={item.id} />}
|
|
101
124
|
</div>
|
|
102
125
|
</div>
|
|
103
126
|
</div>
|
|
104
127
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
<
|
|
108
|
-
Description
|
|
109
|
-
</h2>
|
|
110
|
-
<EditableDetailDescription description={item.description} itemId={item.id} />
|
|
128
|
+
<div className="px-8 py-6 border-b border-zinc-200 dark:border-zinc-800">
|
|
129
|
+
<h2 className="text-base font-semibold text-zinc-500 uppercase tracking-wide mb-3">Description</h2>
|
|
130
|
+
<EditableDetailDescription description={item.description} itemId={item.id} onDescriptionChange={handleDescriptionChange} />
|
|
111
131
|
</div>
|
|
112
132
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
<
|
|
116
|
-
Details
|
|
117
|
-
</h2>
|
|
118
|
-
<dl className="grid grid-cols-2 gap-4 text-sm">
|
|
133
|
+
<div className="px-8 py-6 border-b border-zinc-200 dark:border-zinc-800">
|
|
134
|
+
<h2 className="text-base font-semibold text-zinc-500 uppercase tracking-wide mb-4">Details</h2>
|
|
135
|
+
<dl className="grid grid-cols-2 gap-6 text-base">
|
|
119
136
|
{item.branch_name && (
|
|
120
137
|
<div>
|
|
121
138
|
<dt className="text-zinc-500">Branch</dt>
|
|
@@ -130,59 +147,41 @@ export default async function WorkItemPage({ params }: PageProps) {
|
|
|
130
147
|
)}
|
|
131
148
|
<div>
|
|
132
149
|
<dt className="text-zinc-500">Created</dt>
|
|
133
|
-
<dd className="text-zinc-900 dark:text-zinc-100">
|
|
134
|
-
{new Date(item.created_at).toLocaleDateString()}
|
|
135
|
-
</dd>
|
|
150
|
+
<dd className="text-zinc-900 dark:text-zinc-100">{new Date(item.created_at).toLocaleDateString()}</dd>
|
|
136
151
|
</div>
|
|
137
152
|
{item.completed_at && (
|
|
138
153
|
<div>
|
|
139
154
|
<dt className="text-zinc-500">Completed</dt>
|
|
140
|
-
<dd className="text-zinc-900 dark:text-zinc-100">
|
|
141
|
-
{new Date(item.completed_at).toLocaleDateString()}
|
|
142
|
-
</dd>
|
|
155
|
+
<dd className="text-zinc-900 dark:text-zinc-100">{new Date(item.completed_at).toLocaleDateString()}</dd>
|
|
143
156
|
</div>
|
|
144
157
|
)}
|
|
145
158
|
</dl>
|
|
146
159
|
</div>
|
|
147
160
|
|
|
148
|
-
{/* Decisions */}
|
|
149
161
|
{decisions.length > 0 && (
|
|
150
|
-
<div className="px-
|
|
151
|
-
<h2 className="text-
|
|
152
|
-
|
|
153
|
-
</h2>
|
|
154
|
-
<div className="space-y-4">
|
|
162
|
+
<div className="px-8 py-6 border-b border-zinc-200 dark:border-zinc-800">
|
|
163
|
+
<h2 className="text-base font-semibold text-zinc-500 uppercase tracking-wide mb-3">Decisions</h2>
|
|
164
|
+
<div className="space-y-6">
|
|
155
165
|
{decisions.map((decision) => (
|
|
156
|
-
<div key={decision.id} className="bg-zinc-50 dark:bg-zinc-800 rounded-lg p-
|
|
157
|
-
<div className="flex items-center gap-
|
|
158
|
-
<span className="text-
|
|
159
|
-
|
|
160
|
-
</span>
|
|
161
|
-
<span className="text-xs text-zinc-500">
|
|
162
|
-
{new Date(decision.created_at).toLocaleDateString()}
|
|
163
|
-
</span>
|
|
166
|
+
<div key={decision.id} className="bg-zinc-50 dark:bg-zinc-800 rounded-lg p-6">
|
|
167
|
+
<div className="flex items-center gap-3 mb-3">
|
|
168
|
+
<span className="text-base font-medium text-zinc-900 dark:text-zinc-100">{decision.aspect}</span>
|
|
169
|
+
<span className="text-base text-zinc-500">{new Date(decision.created_at).toLocaleDateString()}</span>
|
|
164
170
|
</div>
|
|
165
|
-
<p className="text-zinc-700 dark:text-zinc-300 font-medium">
|
|
166
|
-
|
|
167
|
-
</p>
|
|
168
|
-
{decision.rationale && (
|
|
169
|
-
<p className="text-sm text-zinc-500 mt-1">
|
|
170
|
-
{decision.rationale}
|
|
171
|
-
</p>
|
|
172
|
-
)}
|
|
171
|
+
<p className="text-zinc-700 dark:text-zinc-300 font-medium">{decision.decision}</p>
|
|
172
|
+
{decision.rationale && <p className="text-base text-zinc-500 mt-1.5">{decision.rationale}</p>}
|
|
173
173
|
</div>
|
|
174
174
|
))}
|
|
175
175
|
</div>
|
|
176
176
|
</div>
|
|
177
177
|
)}
|
|
178
178
|
|
|
179
|
-
{/* Children */}
|
|
180
179
|
{children.length > 0 && (
|
|
181
|
-
<div className="px-
|
|
182
|
-
<h2 className="text-
|
|
180
|
+
<div className="px-8 py-6">
|
|
181
|
+
<h2 className="text-base font-semibold text-zinc-500 uppercase tracking-wide mb-4">
|
|
183
182
|
{item.type === 'epic' ? 'Features & Chores' : 'Child Items'} ({children.length})
|
|
184
183
|
</h2>
|
|
185
|
-
<WorkItemTree items={children.map(c => ({ ...c, children: [] }))} />
|
|
184
|
+
<WorkItemTree items={children.map(c => ({ ...c, type: c.type, children: [], epic_id: c.parent_id, rejection_round: c.rejection_round ?? null, rejection_history: c.rejection_history ?? null }))} />
|
|
186
185
|
</div>
|
|
187
186
|
)}
|
|
188
187
|
</div>
|