From 6ccbf1be29f1f26c6779bb9bf25ee818fc910e2b Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Mon, 6 May 2024 17:51:45 +0900 Subject: [PATCH] Display information of project on home tab --- frontend/config/selection.ts | 8 +-- frontend/messages/en.json | 9 ++- frontend/messages/ja.json | 7 +- .../home/TestPriorityDonutChart.tsx | 56 ++++++++++++++++ .../projects/[projectId]/home/aggregate.ts | 52 +++++++++++++++ .../projects/[projectId]/home/home.tsx | 66 ++++++++----------- .../projects/[projectId]/home/page.tsx | 10 +++ frontend/types/case.ts | 7 +- frontend/types/folder.ts | 3 + frontend/types/project.ts | 5 ++ 10 files changed, 177 insertions(+), 46 deletions(-) create mode 100644 frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx create mode 100644 frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts diff --git a/frontend/config/selection.ts b/frontend/config/selection.ts index 0706437..98f1748 100644 --- a/frontend/config/selection.ts +++ b/frontend/config/selection.ts @@ -1,8 +1,8 @@ const priorities = [ - { uid: "critical", color: "#d00002" }, - { uid: "high", color: "#ee6b4e" }, - { uid: "medium", color: "#fccb69" }, - { uid: "low", color: "#0b62e8" }, + { uid: "critical", color: "#d00002", chartColor: "#d00002" }, + { uid: "high", color: "#ee6b4e", chartColor: "#ee6b4e" }, + { uid: "medium", color: "#fccb69", chartColor: "#fccb69" }, + { uid: "low", color: "#0b62e8", chartColor: "#0b62e8" }, ]; const testTypes = [ diff --git a/frontend/messages/en.json b/frontend/messages/en.json index eec5365..edfa3fb 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -30,7 +30,7 @@ "Project": { "home": "Home", "test_cases": "Test Cases", - "test_run": "Test Runs" + "test_runs": "Test Runs" }, "Home": { "Folders": "Folders", @@ -49,7 +49,12 @@ "destructive": "Destructive", "regression": "Regression", "automated": "Automated", - "manual": "Manual" + "manual": "Manual", + "priority": "Priority", + "critical": "Critical", + "high": "High", + "medium": "Medium", + "low": "Low" }, "Folders": { "folder": "Folder", diff --git a/frontend/messages/ja.json b/frontend/messages/ja.json index c089d87..9d6ac55 100644 --- a/frontend/messages/ja.json +++ b/frontend/messages/ja.json @@ -49,7 +49,12 @@ "destructive": "破壊", "regression": "回帰", "automated": "自動", - "manual": "手動" + "manual": "手動", + "priority": "優先度", + "critical": "致", + "high": "高", + "medium": "中", + "low": "低" }, "Folders": { "folder": "フォルダー", diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx new file mode 100644 index 0000000..974a278 --- /dev/null +++ b/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx @@ -0,0 +1,56 @@ +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"; +const Chart = dynamic(() => import("react-apexcharts"), { ssr: false }); + +type Props = { + priorityCounts: CasePriorityCountType[]; + messages: HomeMessages; +}; + +export default function TestPriorityDonutChart({ + priorityCounts, + messages, +}: Props) { + const [chartData, setChartData] = useState({ + series: [], + options: { + labels: [], + colors: [], + }, + }); + + useEffect(() => { + const updateChartDate = () => { + if (priorityCounts) { + const series = priorities.map((entry, index) => { + const found = priorityCounts.find((itr) => itr.priority === index); + return found ? found.count : 0; + }); + + const labels = priorities.map((entry) => messages[entry.uid]); + const colors = priorities.map((entry) => entry.chartColor); + + setChartData({ + series, + options: { labels, colors }, + }); + } + }; + + updateChartDate(); + }, [priorityCounts]); + + return ( + + ); +} diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts b/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts new file mode 100644 index 0000000..3bc8f47 --- /dev/null +++ b/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts @@ -0,0 +1,52 @@ +import { ProjectType } from "@/types/project"; +import { testTypes, priorities } from "@/config/selection"; + +// aggregate folder, case, run mum +function aggregateBasicInfo(project: ProjectType) { + const folderNum = project.Folders.length; + const runNum = project.Runs.length; + + let caseNum = 0; + project.Folders.forEach((folder) => { + caseNum += folder.Cases.length; + }); + + return { folderNum, runNum, caseNum }; +} + +// aggregate test types of each case +function aggregateTestType(project: ProjectType) { + const typesCounts = {}; + project.Folders.forEach((folder) => { + folder.Cases.forEach((testcase) => { + const type = testcase.type; + typesCounts[type] = (typesCounts[type] || 0) + 1; + }); + }); + + const result = []; + for (let type = 0; type <= testTypes.length; type++) { + result.push({ type: type, count: typesCounts[type] || 0 }); + } + + return result; +} + +function aggregateTestPriority(project: ProjectType) { + const priorityCounts = {}; + project.Folders.forEach((folder) => { + folder.Cases.forEach((testcase) => { + const priority = testcase.priority; + priorityCounts[priority] = (priorityCounts[priority] || 0) + 1; + }); + }); + + const result = []; + for (let priority = 0; priority <= priorities.length; priority++) { + result.push({ priority: priority, count: priorityCounts[priority] || 0 }); + } + + return result; +} + +export { aggregateBasicInfo, aggregateTestType, aggregateTestPriority }; diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/home.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/home.tsx index c78778c..fb43189 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/home.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/home.tsx @@ -4,10 +4,15 @@ import { Divider } from "@nextui-org/react"; import { title } from "@/components/primitives"; import { Card, CardBody, Chip } from "@nextui-org/react"; import { Folder, Clipboard, FlaskConical } from "lucide-react"; -import { CaseTypeCountType } from "@/types/case"; +import { CaseTypeCountType, CasePriorityCountType } from "@/types/case"; import { HomeMessages } from "./page"; -import { testTypes } from "@/config/selection"; +import { + aggregateBasicInfo, + aggregateTestPriority, + aggregateTestType, +} from "./aggregate"; import TestTypesChart from "./TestTypesDonutChart"; +import TestPriorityChart from "./TestPriorityDonutChart"; import Config from "@/config/config"; const apiServer = Config.apiServer; @@ -47,6 +52,8 @@ export function Home({ projectId, messages }: Props) { const [caseNum, setCaseNum] = useState(0); const [runNum, setRunNum] = useState(0); const [typesCounts, setTypesCounts] = useState(); + const [priorityCounts, setPriorityCounts] = + useState(); const url = `${apiServer}/home/${projectId}`; useEffect(() => { @@ -65,42 +72,21 @@ export function Home({ projectId, messages }: Props) { useEffect(() => { async function aggregate() { - aggregateBasicInfo(); - aggregateTestType(); + const { folderNum, runNum, caseNum } = aggregateBasicInfo(project); + setFolderNum(folderNum); + setRunNum(runNum); + setCaseNum(caseNum); + + const typeRet = aggregateTestType(project); + setTypesCounts([...typeRet]); + + const priorityRet = aggregateTestPriority(project); + setPriorityCounts([...priorityRet]); } aggregate(); }, [project]); - // aggregate folder, case, run mum - function aggregateBasicInfo() { - let num = 0; - setFolderNum(project.Folders.length); - setRunNum(project.Runs.length); - project.Folders.forEach((folder) => { - num += folder.Cases.length; - }); - setCaseNum(num); - } - - // aggregate test types of each case - function aggregateTestType() { - const tempTypesCounts = {}; - project.Folders.forEach((folder) => { - folder.Cases.forEach((testcase) => { - const type = testcase.type; - tempTypesCounts[type] = (tempTypesCounts[type] || 0) + 1; - }); - }); - - const result = []; - for (let type = 0; type <= testTypes.length; type++) { - result.push({ type: type, count: tempTypesCounts[type] || 0 }); - } - - setTypesCounts([...result]); - } - return (

{project.name}

@@ -133,17 +119,21 @@ export function Home({ projectId, messages }: Props) { -
-
+

{messages.testTypes}

-
-

{messages.testTypes}

- +
+

{messages.priority}

+
+ +
); } diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx index 591b411..5583605 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx @@ -19,6 +19,11 @@ export type HomeMessages = { regression: string; automated: string; manual: string; + priority: string; + critical: string; + high: string; + medium: string; + low: string; }; export default function Page({ params }: { params: { projectId: string } }) { @@ -41,6 +46,11 @@ export default function Page({ params }: { params: { projectId: string } }) { regression: t("regression"), automated: t("automated"), manual: t("manual"), + priority: t("priority"), + critical: t("critical"), + high: t("high"), + medium: t("medium"), + low: t("low"), }; return ( <> diff --git a/frontend/types/case.ts b/frontend/types/case.ts index bf353a7..cde45a2 100644 --- a/frontend/types/case.ts +++ b/frontend/types/case.ts @@ -54,6 +54,11 @@ type CaseTypeCountType = { count: number; }; +type CasePriorityCountType = { + priority: number; + count: number; +}; + export type CasesMessages = { testCaseList: string; id: string; @@ -119,4 +124,4 @@ export type CaseMessages = { maxFileSize: string; }; -export { CaseType, StepType, AttachmentType, CaseTypeCountType, CasesMessages, CaseMessages }; +export { CaseType, StepType, AttachmentType, CaseTypeCountType, CasePriorityCountType, CasesMessages, CaseMessages }; diff --git a/frontend/types/folder.ts b/frontend/types/folder.ts index 4150dd6..fe5edf7 100644 --- a/frontend/types/folder.ts +++ b/frontend/types/folder.ts @@ -1,3 +1,5 @@ +import { CaseType } from "./case"; + export type FolderType = { id: number; name: string; @@ -6,6 +8,7 @@ export type FolderType = { parentFolderId: number | null; createdAt: string; updatedAt: string; + Cases: CaseType[]; // additional property }; export type FoldersMessages = { diff --git a/frontend/types/project.ts b/frontend/types/project.ts index 45988f0..0938e62 100644 --- a/frontend/types/project.ts +++ b/frontend/types/project.ts @@ -1,9 +1,14 @@ +import { FolderType } from "./folder"; +import { RunType } from "./run"; + export type ProjectType = { id: number; name: string; detail: string; createdAt: string; updatedAt: string; + Folders: FolderType[]; // additional property + Runs: RunType[]; // additional property }; export type ProjectsMessages = {