feat: test case detail dialog
This commit is contained in:
@@ -43,12 +43,12 @@ export default function Page({
|
||||
template: t('template'),
|
||||
testDetail: t('test_detail'),
|
||||
preconditions: t('preconditions'),
|
||||
expectedResult: t('expected_result'),
|
||||
step: t('step'),
|
||||
text: t('text'),
|
||||
steps: t('steps'),
|
||||
newStep: t('new_step'),
|
||||
detailsOfTheStep: t('details_of_the_step'),
|
||||
expectedResult: t('expected_result'),
|
||||
deleteThisStep: t('delete_this_step'),
|
||||
insertStep: t('insert_step'),
|
||||
attachments: t('attachments'),
|
||||
|
||||
@@ -310,7 +310,7 @@ export default function RunEditor({ projectId, runId, messages, locale }: Props)
|
||||
isDisabled={!context.isProjectReporter(Number(projectId))}
|
||||
selectedKeys={selectedKeys}
|
||||
onSelectionChange={setSelectedKeys}
|
||||
onStatusChange={handleChangeStatus}
|
||||
onChangeStatus={handleChangeStatus}
|
||||
onIncludeCase={(includeTestId) => handleIncludeExcludeCase(true, includeTestId)}
|
||||
onExcludeCase={(excludeCaseId) => handleIncludeExcludeCase(false, excludeCaseId)}
|
||||
messages={messages}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
import { Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Chip, Divider } from '@nextui-org/react';
|
||||
import { RunMessages } from '@/types/run';
|
||||
import { CaseType } from '@/types/case';
|
||||
import { Circle } from 'lucide-react';
|
||||
import { priorities, testTypes, templates } from '@/config/selection';
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
testCase: CaseType;
|
||||
onCancel: () => void;
|
||||
onChangeStatus: (changeCaseId: number, status: number) => {};
|
||||
messages: RunMessages;
|
||||
};
|
||||
|
||||
export default function showTestCaseDetailDialog({ isOpen, testCase, onCancel, onChangeStatus, messages }: Props) {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
size="3xl"
|
||||
onOpenChange={() => {
|
||||
onCancel();
|
||||
}}
|
||||
classNames={{
|
||||
header: 'border-b-[1px] border-[#e5e5e5]',
|
||||
body: 'border-b-[1px] border-[#e5e5e5]',
|
||||
}}
|
||||
>
|
||||
<ModalContent>
|
||||
<ModalHeader className="flex flex-col gap-1">{testCase.title}</ModalHeader>
|
||||
<ModalBody>
|
||||
<p className={'font-bold mt-2'}>{messages.description}</p>
|
||||
<div>{testCase.description}</div>
|
||||
|
||||
<div className="flex my-2">
|
||||
<div className="w-1/2">
|
||||
<p className={'font-bold'}>{messages.priority}</p>
|
||||
<Chip
|
||||
startContent={
|
||||
<Circle
|
||||
size={8}
|
||||
className="me-2"
|
||||
color={priorities[testCase.priority].color}
|
||||
fill={priorities[testCase.priority].color}
|
||||
/>
|
||||
}
|
||||
variant="light"
|
||||
>
|
||||
{messages[priorities[testCase.priority].uid]}
|
||||
</Chip>
|
||||
</div>
|
||||
|
||||
<div className="w-1/2">
|
||||
<p className={'font-bold'}>{messages.type}</p>
|
||||
<div>{messages[testTypes[testCase.type].uid]}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ModalBody>
|
||||
<ModalBody>
|
||||
{templates[testCase.template].uid === 'text' ? (
|
||||
<div className="flex my-2">
|
||||
<div className="w-1/2">
|
||||
<p className={'font-bold'}>{messages.preconditions}</p>
|
||||
<div>{testCase.preConditions}</div>
|
||||
</div>
|
||||
|
||||
<div className="w-1/2">
|
||||
<p className={'font-bold'}>{messages.expectedResult}</p>
|
||||
<div>{testCase.expectedResults}</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex my-2">
|
||||
{testCase.Steps &&
|
||||
testCase.Steps.map((step, index) => (
|
||||
<>
|
||||
<div className="w-1/2">
|
||||
<p className={'font-bold'}>{messages.preconditions}</p>
|
||||
<div>{step.step}</div>
|
||||
</div>
|
||||
|
||||
<div className="w-1/2">
|
||||
<p className={'font-bold'}>{messages.expectedResult}</p>
|
||||
<div>{step.result}</div>
|
||||
</div>
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant="light" onPress={onCancel}>
|
||||
{messages.close}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -25,16 +25,18 @@ import {
|
||||
CircleX,
|
||||
CircleSlash2,
|
||||
} from 'lucide-react';
|
||||
import { NextUiLinkClasses } from '@/src/navigation';
|
||||
import { priorities, testRunCaseStatus } from '@/config/selection';
|
||||
import { CaseType } from '@/types/case';
|
||||
import { RunMessages } from '@/types/run';
|
||||
import TestCaseDetailDialog from './TestCaseDetailDialog';
|
||||
|
||||
type Props = {
|
||||
cases: CaseType[];
|
||||
isDisabled: boolean;
|
||||
selectedKeys: Selection;
|
||||
onSelectionChange: React.Dispatch<React.SetStateAction<Selection>>;
|
||||
onStatusChange: (changeCaseId: number, status: number) => {};
|
||||
onChangeStatus: (changeCaseId: number, status: number) => {};
|
||||
onIncludeCase: (includeCaseId: number) => {};
|
||||
onExcludeCase: (excludeCaseId: number) => {};
|
||||
messages: RunMessages;
|
||||
@@ -45,7 +47,7 @@ export default function TestCaseSelector({
|
||||
isDisabled,
|
||||
selectedKeys,
|
||||
onSelectionChange,
|
||||
onStatusChange,
|
||||
onChangeStatus,
|
||||
onIncludeCase,
|
||||
onExcludeCase,
|
||||
messages,
|
||||
@@ -124,6 +126,17 @@ export default function TestCaseSelector({
|
||||
const runStatus = testCase.RunCases && testCase.RunCases.length > 0 ? testCase.RunCases[0].status : 0;
|
||||
|
||||
switch (columnKey) {
|
||||
case 'title':
|
||||
return (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="light"
|
||||
className="data-[hover=true]:bg-transparent"
|
||||
onPress={() => showTestCaseDetailDialog(testCase)}
|
||||
>
|
||||
<span className={NextUiLinkClasses}>{cellValue}</span>
|
||||
</Button>
|
||||
);
|
||||
case 'priority':
|
||||
return (
|
||||
<div className={isIncluded ? chipBaseClass : chipBaseClass + notIncludedCaseClass}>
|
||||
@@ -154,7 +167,7 @@ export default function TestCaseSelector({
|
||||
<DropdownItem
|
||||
key={runCaseStatus.uid}
|
||||
startContent={renderStatusIcon(runCaseStatus.uid)}
|
||||
onPress={() => onStatusChange(testCase.id, index)}
|
||||
onPress={() => onChangeStatus(testCase.id, index)}
|
||||
>
|
||||
{messages[runCaseStatus.uid]}
|
||||
</DropdownItem>
|
||||
@@ -226,6 +239,29 @@ export default function TestCaseSelector({
|
||||
onSelectionChange(keys);
|
||||
};
|
||||
|
||||
// Test Case Detail
|
||||
const [isTestCaseDetailDialogOpen, setIsTestCaseDetailDialogOpen] = useState(false);
|
||||
const [showingTestCase, setShowingTestCase] = useState<CaseType>({
|
||||
id: 0,
|
||||
title: '',
|
||||
state: 0,
|
||||
priority: 0,
|
||||
type: 0,
|
||||
automationStatus: 0,
|
||||
description: '',
|
||||
template: 0,
|
||||
preConditions: '',
|
||||
expectedResults: '',
|
||||
folderId: 0,
|
||||
});
|
||||
const showTestCaseDetailDialog = (showTestCase: CaseType) => {
|
||||
setIsTestCaseDetailDialogOpen(true);
|
||||
setShowingTestCase(showTestCase);
|
||||
};
|
||||
const hideTestCaseDetailDialog = () => {
|
||||
setIsTestCaseDetailDialogOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Table
|
||||
@@ -260,6 +296,14 @@ export default function TestCaseSelector({
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<TestCaseDetailDialog
|
||||
isOpen={isTestCaseDetailDialogOpen}
|
||||
testCase={showingTestCase}
|
||||
onCancel={hideTestCaseDetailDialog}
|
||||
onChangeStatus={(showingCaseId, newStatus) => onChangeStatus(showingCaseId, newStatus)}
|
||||
messages={messages}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,24 @@ export default function Page({ params }: { params: { projectId: string; runId: s
|
||||
excludeFromRun: t('exclude_from_run'),
|
||||
noCasesFound: t('no_cases_found'),
|
||||
areYouSureLeave: t('are_you_sure_leave'),
|
||||
type: t('type'),
|
||||
other: t('other'),
|
||||
security: t('security'),
|
||||
performance: t('performance'),
|
||||
accessibility: t('accessibility'),
|
||||
functional: t('functional'),
|
||||
acceptance: t('acceptance'),
|
||||
usability: t('usability'),
|
||||
smokeSanity: t('smoke_sanity'),
|
||||
compatibility: t('compatibility'),
|
||||
destructive: t('destructive'),
|
||||
regression: t('regression'),
|
||||
automated: t('automated'),
|
||||
manual: t('manual'),
|
||||
preconditions: t('preconditions'),
|
||||
expectedResult: t('expected_result'),
|
||||
detailsOfTheStep: t('details_of_the_step'),
|
||||
close: t('close'),
|
||||
};
|
||||
|
||||
return <RunEditor projectId={params.projectId} runId={params.runId} messages={messages} locale={params.locale} />;
|
||||
|
||||
Reference in New Issue
Block a user