feat: comment to test run's case (#390)
This commit is contained in:
@@ -15,7 +15,7 @@ import {
|
||||
SortDescriptor,
|
||||
Chip,
|
||||
} from '@heroui/react';
|
||||
import { ChevronDown, MoreVertical, CopyPlus, CopyMinus } from 'lucide-react';
|
||||
import { ChevronDown, MoreVertical, CopyPlus, CopyMinus, MessageCircle } from 'lucide-react';
|
||||
import RunCaseStatus from './RunCaseStatus';
|
||||
import { Link, NextUiLinkClasses } from '@/src/i18n/routing';
|
||||
import { testRunCaseStatus } from '@/config/selection';
|
||||
@@ -64,6 +64,7 @@ export default function TestCaseSelector({
|
||||
{ name: messages.priority, uid: 'priority', sortable: true },
|
||||
{ name: messages.tags, uid: 'tags', sortable: false },
|
||||
{ name: messages.status, uid: 'runStatus', sortable: true },
|
||||
{ name: messages.comments, uid: 'comments', sortable: false },
|
||||
{ name: messages.actions, uid: 'actions' },
|
||||
];
|
||||
|
||||
@@ -115,6 +116,7 @@ export default function TestCaseSelector({
|
||||
const cellValue = testCase[columnKey as keyof CaseType];
|
||||
const isIncluded = isCaseIncluded(testCase);
|
||||
const runStatus = testCase.RunCases && testCase.RunCases.length > 0 ? testCase.RunCases[0].status : 0;
|
||||
const commentCount = testCase.RunCases && testCase.RunCases.length > 0 ? testCase.RunCases[0].commentCount || 0 : 0;
|
||||
|
||||
switch (columnKey) {
|
||||
case 'title':
|
||||
@@ -179,6 +181,24 @@ export default function TestCaseSelector({
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
);
|
||||
case 'comments':
|
||||
return (
|
||||
<div className={isIncluded ? '' : notIncludedCaseClass}>
|
||||
{isIncluded && commentCount > 0 ? (
|
||||
<Link
|
||||
href={`/projects/${projectId}/runs/${runId}/cases/${testCase.id}?tab=comments`}
|
||||
locale={locale}
|
||||
className="flex items-center gap-1"
|
||||
onPointerDown={(e) => e.stopPropagation()}
|
||||
>
|
||||
<MessageCircle size={16} />
|
||||
<span>{commentCount}</span>
|
||||
</Link>
|
||||
) : (
|
||||
<span className="text-default-400">-</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
case 'actions':
|
||||
return (
|
||||
<Dropdown>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState, useContext } from 'react';
|
||||
import { Tabs, Tab, Chip } from '@heroui/react';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { Tabs, Tab } from '@heroui/react';
|
||||
import CaseDetail from './CaseDetail';
|
||||
import Comments from '@/components/Comments';
|
||||
import History from '@/components/History';
|
||||
@@ -9,30 +9,50 @@ import { TokenContext } from '@/utils/TokenProvider';
|
||||
import { fetchCase } from '@/utils/caseControl';
|
||||
import { logError } from '@/utils/errorHandler';
|
||||
import type { CaseType, StepType } from '@/types/case';
|
||||
import type { RunDetailMessages } from '@/types/run';
|
||||
import type { RunCaseType, RunDetailMessages } from '@/types/run';
|
||||
import type { PriorityMessages } from '@/types/priority';
|
||||
import type { TestTypeMessages } from '@/types/testType';
|
||||
import type { CommentMessages } from '@/types/comment';
|
||||
|
||||
type Props = {
|
||||
projectId: string;
|
||||
runId: string;
|
||||
locale: string;
|
||||
caseId: string;
|
||||
messages: RunDetailMessages;
|
||||
testTypeMessages: TestTypeMessages;
|
||||
priorityMessages: PriorityMessages;
|
||||
commentMessages: CommentMessages;
|
||||
};
|
||||
|
||||
export default function TestCaseDetailPane({
|
||||
projectId,
|
||||
runId,
|
||||
locale,
|
||||
caseId,
|
||||
messages,
|
||||
testTypeMessages,
|
||||
priorityMessages,
|
||||
commentMessages,
|
||||
}: Props) {
|
||||
const context = useContext(TokenContext);
|
||||
const searchParams = useSearchParams();
|
||||
const [selectedTab, setSelectedTab] = useState('caseDetail');
|
||||
const [isFetching, setIsFetching] = useState(false);
|
||||
const [testCase, setTestCase] = useState<CaseType | null>(null);
|
||||
const [runCaseId, setRunCaseId] = useState<number | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
// if the url has ?tab=comments, then select the comments tab
|
||||
const tab = searchParams.get('tab');
|
||||
if (tab === 'comments') {
|
||||
setSelectedTab('comments');
|
||||
} else if (tab === 'history') {
|
||||
setSelectedTab('history');
|
||||
} else {
|
||||
setSelectedTab('caseDetail');
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchDataEffect() {
|
||||
@@ -46,6 +66,14 @@ export default function TestCaseDetailPane({
|
||||
data.Steps.sort((a: StepType, b: StepType) => a.caseSteps.stepNo - b.caseSteps.stepNo);
|
||||
}
|
||||
setTestCase(data);
|
||||
|
||||
// Find the runCase for this case in this run
|
||||
if (data.RunCases && data.RunCases.length > 0) {
|
||||
const runCase = data.RunCases.find((rc: RunCaseType) => rc.runId === Number(runId));
|
||||
if (runCase) {
|
||||
setRunCaseId(runCase.id);
|
||||
}
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
logError('Error fetching case data', error);
|
||||
} finally {
|
||||
@@ -54,15 +82,20 @@ export default function TestCaseDetailPane({
|
||||
}
|
||||
|
||||
fetchDataEffect();
|
||||
}, [context, caseId]);
|
||||
}, [context, caseId, runId]);
|
||||
|
||||
if (isFetching || !testCase) {
|
||||
return <div>loading...</div>;
|
||||
} else {
|
||||
return (
|
||||
<div className="flex w-full flex-col p-3">
|
||||
<Tabs aria-label="Options" size="sm">
|
||||
<Tab key="caseDetail" title="Case Detail">
|
||||
<div className="flex h-full w-full flex-col p-3">
|
||||
<Tabs
|
||||
aria-label="Options"
|
||||
size="sm"
|
||||
selectedKey={selectedTab}
|
||||
onSelectionChange={(key) => setSelectedTab(String(key))}
|
||||
>
|
||||
<Tab key="caseDetail" title={messages.caseDetail}>
|
||||
<CaseDetail
|
||||
projectId={projectId}
|
||||
testCase={testCase}
|
||||
@@ -72,20 +105,15 @@ export default function TestCaseDetailPane({
|
||||
priorityMessages={priorityMessages}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab
|
||||
key="comments"
|
||||
title={
|
||||
<div className="flex items-center space-x-2">
|
||||
<span>Comments</span>
|
||||
<Chip size="sm" variant="faded">
|
||||
3
|
||||
</Chip>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Comments />
|
||||
<Tab key="comments" title={messages.comments}>
|
||||
<Comments
|
||||
projectId={projectId}
|
||||
commentableType="RunCase"
|
||||
commentableId={runCaseId}
|
||||
messages={commentMessages}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab key="history" title="History">
|
||||
<Tab key="history" title={messages.history}>
|
||||
<History />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
@@ -21,6 +21,9 @@ export default function Page({
|
||||
preconditions: t('preconditions'),
|
||||
expectedResult: t('expected_result'),
|
||||
detailsOfTheStep: t('details_of_the_step'),
|
||||
caseDetail: t('case_detail'),
|
||||
comments: t('comments'),
|
||||
history: t('history'),
|
||||
};
|
||||
|
||||
const pt = useTranslations('Priority');
|
||||
@@ -48,14 +51,33 @@ export default function Page({
|
||||
manual: tt('manual'),
|
||||
};
|
||||
|
||||
const ct = useTranslations('Comments');
|
||||
const commentMessages = {
|
||||
comments: ct('comments'),
|
||||
noComments: ct('no_comments'),
|
||||
addComment: ct('add_comment'),
|
||||
save: ct('save'),
|
||||
cancel: ct('cancel'),
|
||||
placeholder: ct('placeholder'),
|
||||
notIncludedInRun: ct('not_included_in_run'),
|
||||
commentAdded: ct('comment_added'),
|
||||
failedToAddComment: ct('failed_to_add_comment'),
|
||||
commentUpdated: ct('comment_updated'),
|
||||
failedToUpdateComment: ct('failed_to_update_comment'),
|
||||
commentDeleted: ct('comment_deleted'),
|
||||
failedToDeleteComment: ct('failed_to_delete_comment'),
|
||||
};
|
||||
|
||||
return (
|
||||
<DetailPane
|
||||
projectId={params.projectId}
|
||||
runId={params.runId}
|
||||
caseId={params.caseId}
|
||||
locale={params.locale}
|
||||
messages={messages}
|
||||
priorityMessages={priorityMessages}
|
||||
testTypeMessages={testTypeMessages}
|
||||
commentMessages={commentMessages}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ export default function RunLayout({
|
||||
selected: t('selected'),
|
||||
tags: t('tags'),
|
||||
selectTags: t('select_tags'),
|
||||
comments: t('comments'),
|
||||
};
|
||||
|
||||
const rst = useTranslations('RunStatus');
|
||||
|
||||
Reference in New Issue
Block a user