diff --git a/frontend/src/app/[locale]/projects/ProjectsPage.tsx b/frontend/src/app/[locale]/projects/ProjectsPage.tsx
index 6ebd48b..80424f9 100644
--- a/frontend/src/app/[locale]/projects/ProjectsPage.tsx
+++ b/frontend/src/app/[locale]/projects/ProjectsPage.tsx
@@ -3,17 +3,19 @@ import { useEffect, useState, useContext } from 'react';
import { Button } from '@nextui-org/react';
import { Plus } from 'lucide-react';
import { TokenContext } from '@/utils/TokenProvider';
-import { ProjectType, ProjectsMessages } from '@/types/project';
+import { ProjectDialogMessages, ProjectType, ProjectsMessages } from '@/types/project';
import ProjectsTable from './ProjectsTable';
import ProjectDialog from '@/components/ProjectDialog';
import { fetchProjects, createProject } from '@/utils/projectsControl';
+import { LocaleCodeType } from '@/types/locale';
export type Props = {
messages: ProjectsMessages;
- locale: string;
+ projectDialogMessages: ProjectDialogMessages;
+ locale: LocaleCodeType;
};
-export default function ProjectsPage({ messages, locale }: Props) {
+export default function ProjectsPage({ messages, projectDialogMessages, locale }: Props) {
const context = useContext(TokenContext);
const [projects, setProjects] = useState
([]);
@@ -73,7 +75,7 @@ export default function ProjectsPage({ messages, locale }: Props) {
editingProject={editingProject}
onCancel={closeDialog}
onSubmit={onSubmit}
- messages={messages}
+ projectDialogMessages={projectDialogMessages}
/>
);
diff --git a/frontend/src/app/[locale]/projects/ProjectsTable.tsx b/frontend/src/app/[locale]/projects/ProjectsTable.tsx
index d7ab4d0..1744358 100644
--- a/frontend/src/app/[locale]/projects/ProjectsTable.tsx
+++ b/frontend/src/app/[locale]/projects/ProjectsTable.tsx
@@ -1,14 +1,15 @@
-import { useState, useMemo, useCallback } from 'react';
+import { useState, useMemo, useCallback, ReactNode } from 'react';
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, SortDescriptor } from '@nextui-org/react';
import { Link, NextUiLinkClasses } from '@/src/navigation';
import { ProjectType, ProjectsMessages } from '@/types/project';
import dayjs from 'dayjs';
import PublicityChip from '@/components/PublicityChip';
+import { LocaleCodeType } from '@/types/locale';
type Props = {
projects: ProjectType[];
messages: ProjectsMessages;
- locale: string;
+ locale: LocaleCodeType;
};
export default function ProjectsTable({ projects, messages, locale }: Props) {
@@ -38,21 +39,23 @@ export default function ProjectsTable({ projects, messages, locale }: Props) {
return text.length > maxLength ? text.slice(0, maxLength) + '...' : text;
};
- const renderCell = useCallback((project: ProjectType, columnKey: Key) => {
+ const renderCell = useCallback((project: ProjectType, columnKey: string): ReactNode => {
const cellValue = project[columnKey as keyof ProjectType];
switch (columnKey) {
case 'id':
- return
{cellValue};
+ return
{cellValue as number};
case 'isPublic':
- return
;
+ return (
+
+ );
case 'name':
const maxLength = 30;
const truncatedDetail = truncateText(project.detail, maxLength);
return (
- {cellValue}
+ {cellValue as string}
{truncatedDetail}
@@ -60,9 +63,9 @@ export default function ProjectsTable({ projects, messages, locale }: Props) {
);
case 'updatedAt':
- return
{dayjs(cellValue).format('YYYY/MM/DD HH:mm')};
+ return
{dayjs(cellValue as number).format('YYYY/MM/DD HH:mm')};
default:
- return cellValue;
+ return cellValue as string;
}
}, []);
@@ -107,7 +110,9 @@ export default function ProjectsTable({ projects, messages, locale }: Props) {
{(item) => (
- {(columnKey) => {renderCell(item, columnKey)}}
+
+ {(columnKey) => {renderCell(item, columnKey as string)}}
+
)}
diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/FoldersPane.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/FoldersPane.tsx
index d215e97..2e8ff59 100644
--- a/frontend/src/app/[locale]/projects/[projectId]/folders/FoldersPane.tsx
+++ b/frontend/src/app/[locale]/projects/[projectId]/folders/FoldersPane.tsx
@@ -33,7 +33,7 @@ export default function FoldersPane({ projectId, messages, locale }: Props) {
return;
}
try {
- const folders: FolderType[] = await fetchFolders(context.token.access_token, projectId);
+ const folders: FolderType[] = await fetchFolders(context.token.access_token, Number(projectId));
setFolders(folders);
// no folder on project
diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx
index bb8bf12..c0ea790 100644
--- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx
+++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx
@@ -6,15 +6,18 @@ import { fetchCases, createCase, deleteCases } from '@/utils/caseControl';
import { CaseType, CasesMessages } from '@/types/case';
import DeleteConfirmDialog from '@/components/DeleteConfirmDialog';
import CaseDialog from './CaseDialog';
+import { PriorityMessages } from '@/types/priority';
+import { LocaleCodeType } from '@/types/locale';
type Props = {
projectId: string;
folderId: string;
messages: CasesMessages;
- locale: string;
+ priorityMessages: PriorityMessages;
+ locale: LocaleCodeType;
};
-export default function CasesPane({ projectId, folderId, messages, locale }: Props) {
+export default function CasesPane({ projectId, folderId, messages, priorityMessages, locale }: Props) {
const [cases, setCases] = useState
([]);
const context = useContext(TokenContext);
const [isCaseDialogOpen, setIsCaseDialogOpen] = useState(false);
@@ -65,7 +68,7 @@ export default function CasesPane({ projectId, folderId, messages, locale }: Pro
const onConfirm = async () => {
if (deleteCaseIds.length > 0) {
- await deleteCases(context.token.access_token, deleteCaseIds, projectId);
+ await deleteCases(context.token.access_token, deleteCaseIds, Number(projectId));
setCases(cases.filter((entry) => !deleteCaseIds.includes(entry.id)));
closeDeleteConfirmDialog();
}
@@ -81,6 +84,7 @@ export default function CasesPane({ projectId, folderId, messages, locale }: Pro
onDeleteCase={onDeleteCase}
onDeleteCases={onDeleteCases}
messages={messages}
+ priorityMessages={priorityMessages}
locale={locale}
/>
diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx
index 6de21ac..e040f25 100644
--- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx
+++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx
@@ -1,4 +1,4 @@
-import { useState, useMemo, useCallback } from 'react';
+import { useState, useMemo, useCallback, ReactNode } from 'react';
import {
Table,
TableHeader,
@@ -15,9 +15,11 @@ import {
SortDescriptor,
} from '@nextui-org/react';
import { Link, NextUiLinkClasses } from '@/src/navigation';
-import { Plus, MoreVertical, Trash, Circle } from 'lucide-react';
+import { Plus, MoreVertical, Trash } from 'lucide-react';
import { CaseType, CasesMessages } from '@/types/case';
-import { priorities } from '@/config/selection';
+import { PriorityMessages } from '@/types/priority';
+import TestCasePriority from '@/components/TestCasePriority';
+import { LocaleCodeType } from '@/types/locale';
type Props = {
projectId: string;
@@ -27,7 +29,8 @@ type Props = {
onDeleteCase: (caseId: number) => void;
onDeleteCases: (caseIds: number[]) => void;
messages: CasesMessages;
- locale: string;
+ priorityMessages: PriorityMessages;
+ locale: LocaleCodeType;
};
export default function TestCaseTable({
@@ -38,6 +41,7 @@ export default function TestCaseTable({
onDeleteCase,
onDeleteCases,
messages,
+ priorityMessages,
locale,
}: Props) {
const headerColumns = [
@@ -70,12 +74,12 @@ export default function TestCaseTable({
onDeleteCase(deleteCaseId);
};
- const renderCell = useCallback((testCase: CaseType, columnKey: Key) => {
+ const renderCell = useCallback((testCase: CaseType, columnKey: string): ReactNode => {
const cellValue = testCase[columnKey as keyof CaseType];
switch (columnKey) {
case 'id':
- return {cellValue};
+ return {cellValue as number};
case 'title':
return (
);
case 'priority':
- return (
-
-
-
{messages[priorities[cellValue].uid]}
-
- );
+ return ;
case 'actions':
return (
@@ -115,7 +114,7 @@ export default function TestCaseTable({
);
default:
- return cellValue;
+ return cellValue as string;
}
}, []);
@@ -154,7 +153,7 @@ export default function TestCaseTable({
{messages.testCaseList}
- {(selectedKeys.size > 0 || selectedKeys === 'all') && (
+ {((selectedKeys !== 'all' && selectedKeys.size > 0) || selectedKeys === 'all') && (
}
size="sm"
@@ -202,7 +201,9 @@ export default function TestCaseTable({
{(item) => (
- {(columnKey) => {renderCell(item, columnKey)}}
+
+ {(columnKey) => {renderCell(item, columnKey as string)}}
+
)}
diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseAttachmentsEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseAttachmentsEditor.tsx
index 0255db7..b6d85f0 100644
--- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseAttachmentsEditor.tsx
+++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseAttachmentsEditor.tsx
@@ -9,7 +9,7 @@ type Props = {
attachments: AttachmentType[];
onAttachmentDownload: (attachmentId: number, downloadFileName: string) => void;
onAttachmentDelete: (attachmentId: number) => void;
- onFilesDrop: (event: DragEvent) => void;
+ onFilesDrop: (event: DragEvent
) => void;
onFilesInput: (event: ChangeEvent) => void;
messages: CaseMessages;
};
diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx
index d9728ef..d78992e 100644
--- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx
+++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx
@@ -1,17 +1,19 @@
'use client';
-import { useState, useEffect, useContext } from 'react';
+import { useState, useEffect, useContext, ChangeEvent, DragEvent } from 'react';
import { Input, Textarea, Select, SelectItem, Button, Divider, Tooltip } from '@nextui-org/react';
import { useRouter } from '@/src/navigation';
import { Save, Plus, ArrowLeft, Circle } from 'lucide-react';
import { priorities, testTypes, templates } from '@/config/selection';
import CaseStepsEditor from './CaseStepsEditor';
import CaseAttachmentsEditor from './CaseAttachmentsEditor';
-import { CaseType, AttachmentType, CaseMessages, StepType } from '@/types/case';
import { fetchCase, updateCase } from '@/utils/caseControl';
import { updateSteps } from './stepControl';
import { fetchCreateAttachments, fetchDownloadAttachment, fetchDeleteAttachment } from './attachmentControl';
import { TokenContext } from '@/utils/TokenProvider';
import { useFormGuard } from '@/utils/formGuard';
+import { CaseType, AttachmentType, CaseMessages, StepType } from '@/types/case';
+import { PriorityMessages } from '@/types/priority';
+import { TestTypeMessages } from '@/types/testType';
const defaultTestCase = {
id: 0,
@@ -36,10 +38,20 @@ type Props = {
folderId: string;
caseId: string;
messages: CaseMessages;
+ testTypeMessages: TestTypeMessages;
+ priorityMessages: PriorityMessages;
locale: string;
};
-export default function CaseEditor({ projectId, folderId, caseId, messages, locale }: Props) {
+export default function CaseEditor({
+ projectId,
+ folderId,
+ caseId,
+ messages,
+ testTypeMessages,
+ priorityMessages,
+ locale,
+}: Props) {
const context = useContext(TokenContext);
const [testCase, setTestCase] = useState(defaultTestCase);
const [isTitleInvalid, setIsTitleInvalid] = useState(false);
@@ -122,13 +134,22 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca
}
};
- const handleDrop = async (event: DragEvent) => {
+ const handleDrop = (event: DragEvent) => {
event.preventDefault();
- handleFetchCreateAttachments(Number(caseId), event.dataTransfer.files);
+ if (event.dataTransfer) {
+ const filesArray = Array.from(event.dataTransfer.files);
+ handleFetchCreateAttachments(Number(caseId), filesArray);
+ }
};
- const handleInput = (event: DragEvent) => {
- handleFetchCreateAttachments(Number(caseId), event.target.files);
+ const handleInput = (event: ChangeEvent) => {
+ if (event.target) {
+ const input = event.target as HTMLInputElement;
+ if (input.files) {
+ const filesArray = Array.from(input.files);
+ handleFetchCreateAttachments(Number(caseId), filesArray);
+ }
+ }
};
const handleFetchCreateAttachments = async (caseId: number, files: File[]) => {
@@ -137,28 +158,36 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca
if (newAttachments) {
const newAttachmentsWithJoinTable = [];
newAttachments.forEach((attachment: AttachmentType) => {
- attachment.caseAttachments = { AttachmentId: attachment.id };
+ attachment.caseAttachments = {
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ caseId: 0,
+ attachmentId: attachment.id,
+ };
newAttachmentsWithJoinTable.push(attachment);
});
const updatedAttachments = testCase.Attachments;
- updatedAttachments.push(...newAttachments);
+ if (updatedAttachments) {
+ updatedAttachments.push(...newAttachments);
- setTestCase({
- ...testCase,
- Attachments: updatedAttachments,
- });
+ setTestCase({
+ ...testCase,
+ Attachments: updatedAttachments,
+ });
+ }
}
};
const onAttachmentDelete = async (attachmentId: number) => {
await fetchDeleteAttachment(attachmentId);
+ if (testCase.Attachments) {
+ const filteredAttachments = testCase.Attachments.filter((attachment) => attachment.id !== attachmentId);
- const filteredAttachments = testCase.Attachments.filter((attachment) => attachment.id !== attachmentId);
-
- setTestCase({
- ...testCase,
- Attachments: filteredAttachments,
- });
+ setTestCase({
+ ...testCase,
+ Attachments: filteredAttachments,
+ });
+ }
};
useEffect(() => {
@@ -249,10 +278,12 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca
size="sm"
variant="bordered"
selectedKeys={[priorities[testCase.priority].uid]}
- onSelectionChange={(e) => {
- const selectedUid = e.anchorKey;
- const index = priorities.findIndex((priority) => priority.uid === selectedUid);
- setTestCase({ ...testCase, priority: index });
+ onSelectionChange={(newSelection) => {
+ if (newSelection !== 'all' && newSelection.size !== 0) {
+ const selectedUid = Array.from(newSelection)[0];
+ const index = priorities.findIndex((priority) => priority.uid === selectedUid);
+ setTestCase({ ...testCase, priority: index });
+ }
}}
startContent={
@@ -262,7 +293,7 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca
>
{priorities.map((priority, index) => (
- {messages[priority.uid]}
+ {priorityMessages[priority.uid]}
))}
@@ -273,17 +304,19 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca
size="sm"
variant="bordered"
selectedKeys={[testTypes[testCase.type].uid]}
- onSelectionChange={(e) => {
- const selectedUid = e.anchorKey;
- const index = testTypes.findIndex((type) => type.uid === selectedUid);
- setTestCase({ ...testCase, type: index });
+ onSelectionChange={(newSelection) => {
+ if (newSelection !== 'all' && newSelection.size !== 0) {
+ const selectedUid = Array.from(newSelection)[0];
+ const index = testTypes.findIndex((type) => type.uid === selectedUid);
+ setTestCase({ ...testCase, type: index });
+ }
}}
label={messages.type}
className="mt-3 max-w-xs"
>
{testTypes.map((type, index) => (
- {messages[type.uid]}
+ {testTypeMessages[type.uid]}
))}
@@ -294,10 +327,12 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca
size="sm"
variant="bordered"
selectedKeys={[templates[testCase.template].uid]}
- onSelectionChange={(e) => {
- const selectedUid = e.anchorKey;
- const index = templates.findIndex((template) => template.uid === selectedUid);
- setTestCase({ ...testCase, template: index });
+ onSelectionChange={(newSelection) => {
+ if (newSelection !== 'all' && newSelection.size !== 0) {
+ const selectedUid = Array.from(newSelection)[0];
+ const index = templates.findIndex((template) => template.uid === selectedUid);
+ setTestCase({ ...testCase, template: index });
+ }
}}
label={messages.template}
className="mt-3 max-w-xs"
@@ -353,41 +388,47 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca
{messages.newStep}
-
{
- setTestCase({
- ...testCase,
- Steps: testCase.Steps.map((step) => {
- if (step.id === stepId) {
- return changeStep;
- } else {
- return step;
- }
- }),
- });
- }}
- onStepPlus={onPlusClick}
- onStepDelete={onDeleteClick}
- messages={messages}
- />
+ {testCase.Steps && (
+ {
+ if (testCase.Steps) {
+ setTestCase({
+ ...testCase,
+ Steps: testCase.Steps.map((step) => {
+ if (step.id === stepId) {
+ return changeStep;
+ } else {
+ return step;
+ }
+ }),
+ });
+ }
+ }}
+ onStepPlus={onPlusClick}
+ onStepDelete={onDeleteClick}
+ messages={messages}
+ />
+ )}
)}
{messages.attachments}
-
- fetchDownloadAttachment(attachmentId, downloadFileName)
- }
- onAttachmentDelete={onAttachmentDelete}
- onFilesDrop={handleDrop}
- onFilesInput={handleInput}
- messages={messages}
- />
+ {testCase.Attachments && (
+
+ fetchDownloadAttachment(attachmentId, downloadFileName)
+ }
+ onAttachmentDelete={onAttachmentDelete}
+ onFilesDrop={handleDrop}
+ onFilesInput={handleInput}
+ messages={messages}
+ />
+ )}
>
);
diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx
index e859a4f..e2ace79 100644
--- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx
+++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx
@@ -1,5 +1,7 @@
+import { PriorityMessages } from '@/types/priority';
import CaseEditor from './CaseEditor';
import { useTranslations } from 'next-intl';
+import { TestTypeMessages } from '@/types/testType';
export default function Page({
params,
@@ -22,33 +24,16 @@ export default function Page({
description: t('description'),
testCaseDescription: t('test_case_description'),
priority: t('priority'),
- critical: t('critical'),
- high: t('high'),
- medium: t('medium'),
- low: t('low'),
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'),
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'),
@@ -61,12 +46,39 @@ export default function Page({
areYouSureLeave: t('are_you_sure_leave'),
};
+ const tt = useTranslations('Type');
+ const testTypeMessages: TestTypeMessages = {
+ other: tt('other'),
+ security: tt('security'),
+ performance: tt('performance'),
+ accessibility: tt('accessibility'),
+ functional: tt('functional'),
+ acceptance: tt('acceptance'),
+ usability: tt('usability'),
+ smokeSanity: tt('smoke_sanity'),
+ compatibility: tt('compatibility'),
+ destructive: tt('destructive'),
+ regression: tt('regression'),
+ automated: tt('automated'),
+ manual: tt('manual'),
+ };
+
+ const priorityTranslation = useTranslations('Priority');
+ const priorityMessages: PriorityMessages = {
+ critical: priorityTranslation('critical'),
+ high: priorityTranslation('high'),
+ medium: priorityTranslation('medium'),
+ low: priorityTranslation('low'),
+ };
+
return (
);
diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/page.tsx
index ce43a1c..9247666 100644
--- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/page.tsx
+++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/page.tsx
@@ -1,5 +1,7 @@
+import { PriorityMessages } from '@/types/priority';
import CasesPane from './CasesPane';
import { useTranslations } from 'next-intl';
+import { LocaleCodeType } from '@/types/locale';
export default function Page({ params }: { params: { projectId: string; folderId: string; locale: string } }) {
const t = useTranslations('Cases');
@@ -15,10 +17,6 @@ export default function Page({ params }: { params: { projectId: string; folderId
areYouSure: t('are_you_sure'),
newTestCase: t('new_test_case'),
status: t('status'),
- critical: t('critical'),
- high: t('high'),
- medium: t('medium'),
- low: t('low'),
noCasesFound: t('no_cases_found'),
caseTitle: t('case_title'),
caseDescription: t('case_description'),
@@ -26,9 +24,23 @@ export default function Page({ params }: { params: { projectId: string; folderId
pleaseEnter: t('please_enter'),
};
+ const priorityTranslation = useTranslations('Priority');
+ const priorityMessages: PriorityMessages = {
+ critical: priorityTranslation('critical'),
+ high: priorityTranslation('high'),
+ medium: priorityTranslation('medium'),
+ low: priorityTranslation('low'),
+ };
+
return (
<>
-
+
>
);
}
diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx
index 06f00b5..d157663 100644
--- a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx
+++ b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx
@@ -3,16 +3,21 @@ import { useState, useEffect, useContext } from 'react';
import { title, subtitle } from '@/components/primitives';
import { Card, CardBody, Chip, Divider } from '@nextui-org/react';
import { Folder, Clipboard, FlaskConical } from 'lucide-react';
-import { CaseTypeCountType, CasePriorityCountType } from '@/types/case';
import { ProgressSeriesType } from '@/types/run';
import { HomeMessages } from './page';
import { TokenContext } from '@/utils/TokenProvider';
import { aggregateBasicInfo, aggregateTestPriority, aggregateTestType, aggregateProgress } from './aggregate';
+import Config from '@/config/config';
+import { useTheme } from 'next-themes';
import TestTypesChart from './TestTypesDonutChart';
import TestPriorityChart from './TestPriorityDonutChart';
import TestProgressBarChart from './TestProgressColumnChart';
-import Config from '@/config/config';
-import { useTheme } from 'next-themes';
+import { TestRunCaseStatusMessages } from '@/types/status';
+import { TestTypeMessages } from '@/types/testType';
+import { PriorityMessages } from '@/types/priority';
+import { ProjectType } from '@/types/project';
+import { CasePriorityCountType, CaseTypeCountType } from '@/types/chart';
+
const apiServer = Config.apiServer;
async function fetchProject(jwt: string, projectId: number) {
@@ -41,24 +46,38 @@ async function fetchProject(jwt: string, projectId: number) {
type Props = {
projectId: string;
messages: HomeMessages;
+ testRunCaseStatusMessages: TestRunCaseStatusMessages;
+ testTypeMessages: TestTypeMessages;
+ priorityMessages: PriorityMessages;
};
-export function ProjectHome({ projectId, messages }: Props) {
+export function ProjectHome({
+ projectId,
+ messages,
+ testRunCaseStatusMessages,
+ testTypeMessages,
+ priorityMessages,
+}: Props) {
const context = useContext(TokenContext);
const { theme, setTheme } = useTheme();
- const [project, setProject] = useState({
+ const [project, setProject] = useState
({
+ id: 0,
name: '',
detail: '',
- Folders: [{ Cases: [] }],
- Runs: [{ RunCases: [] }],
+ isPublic: false,
+ userId: 0,
+ createdAt: '',
+ updatedAt: '',
+ Folders: [],
+ Runs: [],
});
const [folderNum, setFolderNum] = useState(0);
const [caseNum, setCaseNum] = useState(0);
const [runNum, setRunNum] = useState(0);
- const [typesCounts, setTypesCounts] = useState();
- const [priorityCounts, setPriorityCounts] = useState();
- const [progressCategories, setProgressCategories] = useState();
- const [progressSeries, setProgressSeries] = useState();
+ const [typesCounts, setTypesCounts] = useState([]);
+ const [priorityCounts, setPriorityCounts] = useState([]);
+ const [progressCategories, setProgressCategories] = useState([]);
+ const [progressSeries, setProgressSeries] = useState([]);
useEffect(() => {
async function fetchDataEffect() {
@@ -67,7 +86,7 @@ export function ProjectHome({ projectId, messages }: Props) {
}
try {
- const data = await fetchProject(context.token.access_token, projectId);
+ const data = await fetchProject(context.token.access_token, Number(projectId));
setProject(data);
} catch (error: any) {
console.error('Error in effect:', error.message);
@@ -79,6 +98,9 @@ export function ProjectHome({ projectId, messages }: Props) {
useEffect(() => {
async function aggregate() {
+ if (!project) {
+ return;
+ }
const { folderNum, runNum, caseNum } = aggregateBasicInfo(project);
setFolderNum(folderNum);
setRunNum(runNum);
@@ -90,7 +112,7 @@ export function ProjectHome({ projectId, messages }: Props) {
const priorityRet = aggregateTestPriority(project);
setPriorityCounts([...priorityRet]);
- const { series, categories } = aggregateProgress(project, messages);
+ const { series, categories } = aggregateProgress(project, testRunCaseStatusMessages);
setProgressSeries([...series]);
setProgressCategories([...categories]);
}
@@ -130,11 +152,11 @@ export function ProjectHome({ projectId, messages }: Props) {
{messages.byType}
-
+
{messages.byPriority}
-
+
diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx
index 67330e1..487e2de 100644
--- a/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx
+++ b/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx
@@ -2,18 +2,19 @@ import React from 'react';
import { useState, useEffect } from 'react';
import dynamic from 'next/dynamic';
import { priorities } from '@/config/selection';
-import { CasePriorityCountType } from '@/types/case';
-import { HomeMessages } from './page';
+import { CasePriorityCountType } from '@/types/chart';
+import { PriorityMessages } from '@/types/priority';
+import { ChartDataType } from '@/types/chart';
const Chart = dynamic(() => import('react-apexcharts'), { ssr: false });
type Props = {
priorityCounts: CasePriorityCountType[];
- messages: HomeMessages;
- theme: string;
+ priorityMessages: PriorityMessages;
+ theme: string | undefined;
};
-export default function TestPriorityDonutChart({ priorityCounts, messages, theme }: Props) {
- const [chartData, setChartData] = useState({
+export default function TestPriorityDonutChart({ priorityCounts, priorityMessages, theme }: Props) {
+ const [chartData, setChartData] = useState