feat: view customize on member's role cases pane

This commit is contained in:
Takeshi Kimata
2024-06-06 21:39:52 +09:00
parent f9cf3ef209
commit 07259f6daf
11 changed files with 167 additions and 24 deletions

View File

@@ -25,7 +25,7 @@ export default function FoldersPane({ projectId, messages, locale }: Props) {
const [selectedFolder, setSelectedFolder] = useState<FolderType | null>(null);
const { folderId } = useGetCurrentIds();
const [isFolderDialogOpen, setIsFolderDialogOpen] = useState(false);
const [editingFolder, setEditingProject] = useState<FolderType | null>(null);
const [editingFolder, setEditingFolder] = useState<FolderType | null>(null);
useEffect(() => {
async function fetchDataEffect() {
@@ -54,12 +54,12 @@ export default function FoldersPane({ projectId, messages, locale }: Props) {
const openDialogForCreate = () => {
setIsFolderDialogOpen(true);
setEditingProject(null);
setEditingFolder(null);
};
const closeDialog = () => {
setIsFolderDialogOpen(false);
setEditingProject(null);
setEditingFolder(null);
};
const onSubmit = async (name: string, detail: string) => {
@@ -82,7 +82,7 @@ export default function FoldersPane({ projectId, messages, locale }: Props) {
};
const onEditClick = (folder: FolderType) => {
setEditingProject(folder);
setEditingFolder(folder);
setIsFolderDialogOpen(true);
};

View File

@@ -0,0 +1,102 @@
'use client';
import React from 'react';
import { useState, useEffect } from 'react';
import { Button, Input, Textarea, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@nextui-org/react';
import { CasesMessages } from '@/types/case';
type Props = {
isOpen: boolean;
onCancel: () => void;
onSubmit: (title: string, description: string) => void;
messages: CasesMessages;
};
export default function CaseDialog({ isOpen, onCancel, onSubmit, messages }: Props) {
const [caseTitle, setCaseName] = useState({
text: 'Untitled Case',
isValid: false,
errorMessage: '',
});
const [caseDescription, setCaseDescription] = useState({
text: '',
isValid: false,
errorMessage: '',
});
const clear = () => {
setCaseName({
isValid: false,
text: 'Untitled Case',
errorMessage: '',
});
setCaseDescription({
isValid: false,
text: '',
errorMessage: '',
});
};
const validate = () => {
if (!caseTitle.text) {
setCaseName({
text: '',
isValid: true,
errorMessage: messages.pleaseEnter,
});
return;
}
onSubmit(caseTitle.text, caseDescription.text);
clear();
};
return (
<Modal
isOpen={isOpen}
onOpenChange={() => {
onCancel();
}}
>
<ModalContent>
<ModalHeader className="flex flex-col gap-1">{messages.newTestCase}</ModalHeader>
<ModalBody>
<Input
type="text"
label={messages.caseTitle}
value={caseTitle.text}
isInvalid={caseTitle.isValid}
errorMessage={caseTitle.errorMessage}
onChange={(e) => {
setCaseName({
...caseTitle,
text: e.target.value,
});
}}
/>
<Textarea
label={messages.caseDescription}
value={caseDescription.text}
isInvalid={caseDescription.isValid}
errorMessage={caseDescription.errorMessage}
onChange={(e) => {
setCaseDescription({
...caseDescription,
text: e.target.value,
});
}}
/>
</ModalBody>
<ModalFooter>
<Button variant="light" onPress={onCancel}>
{messages.close}
</Button>
<Button color="primary" onPress={validate}>
{messages.create}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}

View File

@@ -5,6 +5,7 @@ import TestCaseTable from './TestCaseTable';
import { fetchCases, createCase, deleteCases } from './caseControl';
import { CaseType, CasesMessages } from '@/types/case';
import DeleteConfirmDialog from '@/components/DeleteConfirmDialog';
import CaseDialog from './CaseDialog';
type Props = {
projectId: string;
@@ -16,6 +17,7 @@ type Props = {
export default function CasesPane({ projectId, folderId, messages, locale }: Props) {
const [cases, setCases] = useState<CaseType[]>([]);
const context = useContext(TokenContext);
const [isCaseDialogOpen, setIsCaseDialogOpen] = useState(false);
useEffect(() => {
async function fetchDataEffect() {
@@ -33,11 +35,14 @@ export default function CasesPane({ projectId, folderId, messages, locale }: Pro
fetchDataEffect();
}, [context, folderId]);
const handleCreateCase = async (folderId: string) => {
const newCase = await createCase(context.token.access_token, folderId);
const updateCases = [...cases];
updateCases.push(newCase);
setCases(updateCases);
const closeDialog = () => {
setIsCaseDialogOpen(false);
};
const onSubmit = async (title: string, description: string) => {
const newCase = await createCase(context.token.access_token, folderId, title, description);
setCases([...cases, newCase]);
closeDialog();
};
// Delete confirm dialog
@@ -70,14 +75,17 @@ export default function CasesPane({ projectId, folderId, messages, locale }: Pro
<>
<TestCaseTable
projectId={projectId}
isDisabled={!context.isProjectDeveloper(Number(projectId))}
cases={cases}
onCreateCase={() => handleCreateCase(folderId)}
onCreateCase={() => setIsCaseDialogOpen(true)}
onDeleteCase={onDeleteCase}
onDeleteCases={onDeleteCases}
messages={messages}
locale={locale}
/>
<CaseDialog isOpen={isCaseDialogOpen} onCancel={closeDialog} onSubmit={onSubmit} messages={messages} />
<DeleteConfirmDialog
isOpen={isDeleteConfirmDialogOpen}
onCancel={closeDeleteConfirmDialog}

View File

@@ -21,6 +21,7 @@ import { priorities } from '@/config/selection';
type Props = {
projectId: string;
isDisabled: boolean;
cases: CaseType[];
onCreateCase: () => void;
onDeleteCase: (caseId: number) => void;
@@ -31,6 +32,7 @@ type Props = {
export default function TestCaseTable({
projectId,
isDisabled,
cases,
onCreateCase,
onDeleteCase,
@@ -99,7 +101,11 @@ export default function TestCaseTable({
</Button>
</DropdownTrigger>
<DropdownMenu aria-label="test case actions">
<DropdownItem className="text-danger" onPress={() => handleDeleteCase(testCase.id)}>
<DropdownItem
className="text-danger"
isDisabled={isDisabled}
onPress={() => handleDeleteCase(testCase.id)}
>
{messages.deleteCase}
</DropdownItem>
</DropdownMenu>
@@ -149,6 +155,7 @@ export default function TestCaseTable({
<Button
startContent={<Trash size={16} />}
size="sm"
isDisabled={isDisabled}
color="danger"
className="me-2"
onPress={handleDeleteCases}
@@ -156,7 +163,13 @@ export default function TestCaseTable({
{messages.delete}
</Button>
)}
<Button startContent={<Plus size={16} />} size="sm" color="primary" onPress={onCreateCase}>
<Button
startContent={<Plus size={16} />}
size="sm"
isDisabled={isDisabled}
color="primary"
onPress={onCreateCase}
>
{messages.newTestCase}
</Button>
</div>

View File

@@ -175,6 +175,7 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca
<Button
startContent={<Save size={16} />}
size="sm"
isDisabled={!context.isProjectDeveloper(Number(projectId))}
color="primary"
isLoading={isUpdating}
onPress={async () => {
@@ -316,6 +317,7 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca
<Button
startContent={<Plus size={16} />}
size="sm"
isDisabled={!context.isProjectDeveloper(Number(projectId))}
color="primary"
className="ms-3"
onPress={() => onPlusClick(1)}

View File

@@ -48,14 +48,14 @@ async function fetchCases(jwt: string, folderId: string) {
}
}
async function createCase(jwt: string, folderId: string) {
async function createCase(jwt: string, folderId: string, title: string, description: string) {
const newCase = {
title: 'untitled case',
title: title,
state: 0,
priority: 2,
type: 0,
automationStatus: 0,
description: '',
description: description,
template: 0,
preConditions: '',
expectedResults: '',

View File

@@ -20,6 +20,10 @@ export default function Page({ params }: { params: { projectId: string; folderId
medium: t('medium'),
low: t('low'),
noCasesFound: t('no_cases_found'),
caseTitle: t('case_title'),
caseDescription: t('case_description'),
create: t('create'),
pleaseEnter: t('please_enter'),
};
return (