fix: 侧边详情显示产品/项目/版本上下文
所有 Drawer 新增 contextLabel 可选属性: - 从工作台打开时传入"产品 / 项目 / 版本"路径 - 显示在 Drawer 顶部灰色背景条中 - 从版本详情打开时不传,不显示(无需冗余) - 统一样式:px-5 py-2 bg-[var(--bg-subtle)] text-[11px] 涉及组件: - PlanDetailDrawer - DevTaskDetailDrawer - TestCaseDetailDrawer - BugDetailDrawer Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -222,16 +222,16 @@ export default function WorkspacePage() {
|
|||||||
|
|
||||||
{/* Detail Drawers */}
|
{/* Detail Drawers */}
|
||||||
{drawerItem && (drawerItem.type === 'plan_research' || drawerItem.type === 'plan_product' || drawerItem.type === 'plan_ui') && (
|
{drawerItem && (drawerItem.type === 'plan_research' || drawerItem.type === 'plan_product' || drawerItem.type === 'plan_ui') && (
|
||||||
<PlanDetailDrawer planId={drawerItem.id} onClose={() => setDrawerItem(null)} />
|
<PlanDetailDrawer planId={drawerItem.id} onClose={() => setDrawerItem(null)} contextLabel={`${drawerItem.productName} / ${drawerItem.projectName} / ${drawerItem.versionName}`} />
|
||||||
)}
|
)}
|
||||||
{drawerItem && drawerItem.type === 'devTask' && (
|
{drawerItem && drawerItem.type === 'devTask' && (
|
||||||
<DevTaskDetailDrawer taskId={drawerItem.id} allTaskIds={devTasks.map((t) => t.id)} onClose={() => setDrawerItem(null)} />
|
<DevTaskDetailDrawer taskId={drawerItem.id} allTaskIds={devTasks.map((t) => t.id)} onClose={() => setDrawerItem(null)} contextLabel={`${drawerItem.productName} / ${drawerItem.projectName} / ${drawerItem.versionName}`} />
|
||||||
)}
|
)}
|
||||||
{drawerItem && drawerItem.type === 'testCase' && (
|
{drawerItem && drawerItem.type === 'testCase' && (
|
||||||
<TestCaseDetailDrawer testCaseId={drawerItem.id} onClose={() => setDrawerItem(null)} onCreateBug={(tcId) => { setDrawerItem(null); setBugFromTestCaseId(tcId); }} />
|
<TestCaseDetailDrawer testCaseId={drawerItem.id} onClose={() => setDrawerItem(null)} onCreateBug={(tcId) => { setDrawerItem(null); setBugFromTestCaseId(tcId); }} contextLabel={`${drawerItem.productName} / ${drawerItem.projectName} / ${drawerItem.versionName}`} />
|
||||||
)}
|
)}
|
||||||
{drawerItem && drawerItem.type === 'bug' && (
|
{drawerItem && drawerItem.type === 'bug' && (
|
||||||
<BugDetailDrawer bugId={drawerItem.id} onClose={() => setDrawerItem(null)} />
|
<BugDetailDrawer bugId={drawerItem.id} onClose={() => setDrawerItem(null)} contextLabel={`${drawerItem.productName} / ${drawerItem.projectName} / ${drawerItem.versionName}`} />
|
||||||
)}
|
)}
|
||||||
{bugFromTestCaseId && (
|
{bugFromTestCaseId && (
|
||||||
<BugCreateModal testCaseId={bugFromTestCaseId} onClose={() => setBugFromTestCaseId(null)} />
|
<BugCreateModal testCaseId={bugFromTestCaseId} onClose={() => setBugFromTestCaseId(null)} />
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ const LOG_ACTION_LABEL: Record<string, string> = {
|
|||||||
interface Props {
|
interface Props {
|
||||||
bugId: string;
|
bugId: string;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
contextLabel?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BugDetailDrawer({ bugId, onClose }: Props) {
|
export function BugDetailDrawer({ bugId, onClose, contextLabel }: Props) {
|
||||||
const { bugs, changeStatus, transferBug } = useBugStore();
|
const { bugs, changeStatus, transferBug } = useBugStore();
|
||||||
const { testCases } = useTestCaseStore();
|
const { testCases } = useTestCaseStore();
|
||||||
const { requirements } = useRequirementStore();
|
const { requirements } = useRequirementStore();
|
||||||
@@ -66,6 +67,11 @@ export function BugDetailDrawer({ bugId, onClose }: Props) {
|
|||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
|
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
|
||||||
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col" onClick={(e) => e.stopPropagation()}>
|
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col" onClick={(e) => e.stopPropagation()}>
|
||||||
|
{contextLabel && (
|
||||||
|
<div className="px-5 py-2 border-b border-[var(--line)] bg-[var(--bg-subtle)] shrink-0">
|
||||||
|
<span className="text-[11px] text-[var(--ink-muted)]">{contextLabel}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="flex items-center justify-between h-14 px-5 border-b border-[var(--line)] bg-[var(--bg-card)] shrink-0">
|
<div className="flex items-center justify-between h-14 px-5 border-b border-[var(--line)] bg-[var(--bg-card)] shrink-0">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-[12px] font-mono text-[var(--ink-muted)]">{bug.bugNo}</span>
|
<span className="text-[12px] font-mono text-[var(--ink-muted)]">{bug.bugNo}</span>
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ interface Props {
|
|||||||
taskId: string;
|
taskId: string;
|
||||||
allTaskIds: string[];
|
allTaskIds: string[];
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
contextLabel?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DevTaskDetailDrawer({ taskId, allTaskIds, onClose }: Props) {
|
export function DevTaskDetailDrawer({ taskId, allTaskIds, onClose, contextLabel }: Props) {
|
||||||
const { tasks, changeStatus, setBlocked, deleteTask, updateTask } = useDevTaskStore();
|
const { tasks, changeStatus, setBlocked, deleteTask, updateTask } = useDevTaskStore();
|
||||||
const { categories } = useTaskCategoryStore();
|
const { categories } = useTaskCategoryStore();
|
||||||
const { requirements } = useRequirementStore();
|
const { requirements } = useRequirementStore();
|
||||||
@@ -56,6 +57,12 @@ export function DevTaskDetailDrawer({ taskId, allTaskIds, onClose }: Props) {
|
|||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
|
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
|
||||||
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col" onClick={(e) => e.stopPropagation()}>
|
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col" onClick={(e) => e.stopPropagation()}>
|
||||||
|
{/* 上下文 */}
|
||||||
|
{contextLabel && (
|
||||||
|
<div className="px-5 py-2 border-b border-[var(--line)] bg-[var(--bg-subtle)] shrink-0">
|
||||||
|
<span className="text-[11px] text-[var(--ink-muted)]">{contextLabel}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{/* 顶栏 */}
|
{/* 顶栏 */}
|
||||||
<div className="flex items-center justify-between h-14 px-5 border-b border-[var(--line)] bg-[var(--bg-card)] shrink-0">
|
<div className="flex items-center justify-between h-14 px-5 border-b border-[var(--line)] bg-[var(--bg-card)] shrink-0">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
|||||||
@@ -17,9 +17,10 @@ interface Props {
|
|||||||
testCaseId: string;
|
testCaseId: string;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onCreateBug?: (testCaseId: string) => void;
|
onCreateBug?: (testCaseId: string) => void;
|
||||||
|
contextLabel?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TestCaseDetailDrawer({ testCaseId, onClose, onCreateBug }: Props) {
|
export function TestCaseDetailDrawer({ testCaseId, onClose, onCreateBug, contextLabel }: Props) {
|
||||||
const { testCases, changeStatus, deleteTestCase, updateTestCase } = useTestCaseStore();
|
const { testCases, changeStatus, deleteTestCase, updateTestCase } = useTestCaseStore();
|
||||||
const { bugs } = useBugStore();
|
const { bugs } = useBugStore();
|
||||||
const { requirements } = useRequirementStore();
|
const { requirements } = useRequirementStore();
|
||||||
@@ -60,6 +61,11 @@ export function TestCaseDetailDrawer({ testCaseId, onClose, onCreateBug }: Props
|
|||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
|
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
|
||||||
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col" onClick={(e) => e.stopPropagation()}>
|
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col" onClick={(e) => e.stopPropagation()}>
|
||||||
|
{contextLabel && (
|
||||||
|
<div className="px-5 py-2 border-b border-[var(--line)] bg-[var(--bg-subtle)] shrink-0">
|
||||||
|
<span className="text-[11px] text-[var(--ink-muted)]">{contextLabel}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="flex items-center justify-between h-14 px-5 border-b border-[var(--line)] bg-[var(--bg-card)] shrink-0">
|
<div className="flex items-center justify-between h-14 px-5 border-b border-[var(--line)] bg-[var(--bg-card)] shrink-0">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-[12px] font-mono text-[var(--ink-muted)]">{tc.caseNo}</span>
|
<span className="text-[12px] font-mono text-[var(--ink-muted)]">{tc.caseNo}</span>
|
||||||
|
|||||||
@@ -11,13 +11,14 @@ import type { PlanTask, VersionPlan } from '@/lib/version-plan';
|
|||||||
interface Props {
|
interface Props {
|
||||||
planId: string;
|
planId: string;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
contextLabel?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const STATUS_STYLE: Record<string, string> = { pending: 'bg-zinc-100 text-zinc-600', in_progress: 'bg-blue-50 text-blue-600', completed: 'bg-emerald-50 text-emerald-600' };
|
const STATUS_STYLE: Record<string, string> = { pending: 'bg-zinc-100 text-zinc-600', in_progress: 'bg-blue-50 text-blue-600', completed: 'bg-emerald-50 text-emerald-600' };
|
||||||
const STATUS_LABEL: Record<string, string> = { pending: '未开始', in_progress: '进行中', completed: '已完成' };
|
const STATUS_LABEL: Record<string, string> = { pending: '未开始', in_progress: '进行中', completed: '已完成' };
|
||||||
const TYPE_LABEL: Record<string, string> = { research: '调研', product: '产品方案', ui: 'UI设计' };
|
const TYPE_LABEL: Record<string, string> = { research: '调研', product: '产品方案', ui: 'UI设计' };
|
||||||
|
|
||||||
export function PlanDetailDrawer({ planId, onClose }: Props) {
|
export function PlanDetailDrawer({ planId, onClose, contextLabel }: Props) {
|
||||||
const { plans, updatePlan, completePlan } = useVersionPlanStore();
|
const { plans, updatePlan, completePlan } = useVersionPlanStore();
|
||||||
const { requirements } = useRequirementStore();
|
const { requirements } = useRequirementStore();
|
||||||
const { members } = useMemberStore();
|
const { members } = useMemberStore();
|
||||||
@@ -77,6 +78,12 @@ export function PlanDetailDrawer({ planId, onClose }: Props) {
|
|||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
|
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
|
||||||
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col overflow-hidden" onClick={(e) => e.stopPropagation()}>
|
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col overflow-hidden" onClick={(e) => e.stopPropagation()}>
|
||||||
|
{/* Context */}
|
||||||
|
{contextLabel && (
|
||||||
|
<div className="px-5 py-2 border-b border-[var(--line)] bg-[var(--bg-subtle)] shrink-0">
|
||||||
|
<span className="text-[11px] text-[var(--ink-muted)]">{contextLabel}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between px-5 py-4 border-b border-[var(--line)] shrink-0">
|
<div className="flex items-center justify-between px-5 py-4 border-b border-[var(--line)] shrink-0">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
|||||||
Reference in New Issue
Block a user