From 47457e45f4512421081c5d352edd3e7c9e9426f1 Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Mon, 6 May 2024 19:02:29 +0900 Subject: [PATCH] Display information of project on home tab --- frontend/messages/en.json | 1 + frontend/messages/ja.json | 1 + .../home/TestProgressColumnChart.tsx | 60 +++++++++++++++++++ .../projects/[projectId]/home/aggregate.ts | 44 +++++++++++++- .../projects/[projectId]/home/home.tsx | 22 ++++++- .../projects/[projectId]/home/page.tsx | 2 + frontend/types/run.ts | 6 ++ 7 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 frontend/src/app/[locale]/projects/[projectId]/home/TestProgressColumnChart.tsx diff --git a/frontend/messages/en.json b/frontend/messages/en.json index edfa3fb..24b9969 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -36,6 +36,7 @@ "Folders": "Folders", "test_cases": "Test Cases", "test_runs": "Test Runs", + "progress": "Progress", "test_types": "Test types", "other": "Other", "security": "Security", diff --git a/frontend/messages/ja.json b/frontend/messages/ja.json index 9d6ac55..9b12b3b 100644 --- a/frontend/messages/ja.json +++ b/frontend/messages/ja.json @@ -36,6 +36,7 @@ "Folders": "フォルダー", "test_cases": "テストケース", "test_runs": "テスト実行", + "progress": "進捗", "test_types": "テスト種別", "other": "その他", "security": "セキュリティ", diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/TestProgressColumnChart.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/TestProgressColumnChart.tsx new file mode 100644 index 0000000..2919399 --- /dev/null +++ b/frontend/src/app/[locale]/projects/[projectId]/home/TestProgressColumnChart.tsx @@ -0,0 +1,60 @@ +import React from "react"; +import { useState, useEffect } from "react"; +import dynamic from "next/dynamic"; +import { ProgressSeriesType } from "@/types/run"; +const Chart = dynamic(() => import("react-apexcharts"), { ssr: false }); + +type Props = { + progressSeries: ProgressSeriesType[]; + progressCategories: string[]; +}; + +export default function TestProgressBarChart({ + progressSeries, + progressCategories, +}: Props) { + const [chartData, setChartData] = useState({ + series: [], + options: { + labels: [], + colors: [], + }, + }); + + useEffect(() => { + const updateChartDate = () => { + if (progressSeries) { + setChartData({ + series: progressSeries, + options: { + chart: { + toolbar: { + show: false, + }, + stacked: true, + }, + legend: { + position: "right", + }, + xaxis: { + type: "datetime", + categories: progressCategories, + }, + }, + }); + } + }; + + updateChartDate(); + }, [progressSeries, progressCategories]); + + return ( + + ); +} diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts b/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts index 3bc8f47..ada542d 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts +++ b/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts @@ -1,5 +1,5 @@ import { ProjectType } from "@/types/project"; -import { testTypes, priorities } from "@/config/selection"; +import { testTypes, priorities, testRunCaseStatus } from "@/config/selection"; // aggregate folder, case, run mum function aggregateBasicInfo(project: ProjectType) { @@ -49,4 +49,44 @@ function aggregateTestPriority(project: ProjectType) { return result; } -export { aggregateBasicInfo, aggregateTestType, aggregateTestPriority }; +function aggregateProgress(project: ProjectType) { + let series = testRunCaseStatus.map((status) => { + return { name: status.uid, data: [] }; + }); + let categories = []; + + project.Runs.forEach((run) => { + run.RunCases.forEach((runCase) => { + const createdAtDate = new Date(runCase.createdAt); + const dateString = createdAtDate.toISOString().slice(0, 10); + + const alreadyExists = categories.includes(dateString); + if (!alreadyExists) { + categories.push(dateString); + series.forEach((itr) => { + itr.data.push(0); + }); + } + }); + }); + + project.Runs.forEach((run) => { + run.RunCases.forEach((runCase) => { + const createdAtDate = new Date(runCase.createdAt); + const dateString = createdAtDate.toISOString().slice(0, 10); + const index = categories.indexOf(dateString); + + const target = series[runCase.status]; + target.data[index]++; + }); + }); + + return { series, categories }; +} + +export { + aggregateBasicInfo, + aggregateTestType, + aggregateTestPriority, + aggregateProgress, +}; diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/home.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/home.tsx index fb43189..af14d26 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/home.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/home.tsx @@ -5,14 +5,17 @@ import { title } from "@/components/primitives"; import { Card, CardBody, Chip } 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 { aggregateBasicInfo, aggregateTestPriority, aggregateTestType, + aggregateProgress, } from "./aggregate"; import TestTypesChart from "./TestTypesDonutChart"; import TestPriorityChart from "./TestPriorityDonutChart"; +import TestProgressBarChart from "./TestProgressColumnChart"; import Config from "@/config/config"; const apiServer = Config.apiServer; @@ -54,6 +57,8 @@ export function Home({ projectId, messages }: Props) { const [typesCounts, setTypesCounts] = useState(); const [priorityCounts, setPriorityCounts] = useState(); + const [progressCategories, setProgressCategories] = useState(); + const [progressSeries, setProgressSeries] = useState(); const url = `${apiServer}/home/${projectId}`; useEffect(() => { @@ -82,6 +87,10 @@ export function Home({ projectId, messages }: Props) { const priorityRet = aggregateTestPriority(project); setPriorityCounts([...priorityRet]); + + const { series, categories } = aggregateProgress(project); + setProgressSeries([...series]); + setProgressCategories([...categories]); } aggregate(); @@ -119,7 +128,16 @@ export function Home({ projectId, messages }: Props) { - + + {messages.progress} + + + + + {messages.testTypes} @@ -132,8 +150,6 @@ export function Home({ projectId, messages }: Props) { /> - - ); } diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx index 5583605..3721406 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx @@ -5,6 +5,7 @@ export type HomeMessages = { folders: string; testCases: string; testRuns: string; + progress: string; testTypes: string; other: string; security: string; @@ -32,6 +33,7 @@ export default function Page({ params }: { params: { projectId: string } }) { folders: t("Folders"), testCases: t("test_cases"), testRuns: t("test_runs"), + progress: t("progress"), testTypes: t("test_types"), other: t("other"), security: t("security"), diff --git a/frontend/types/run.ts b/frontend/types/run.ts index cdd59e0..8bd6e47 100644 --- a/frontend/types/run.ts +++ b/frontend/types/run.ts @@ -26,6 +26,11 @@ type RunStatusCountType = { count: number; }; +type ProgressSeriesType = { + name: string; + data: number[]; +} + type RunsMessages = { runList: string, id: string; @@ -78,6 +83,7 @@ export { RunCaseType, RunCaseInfoType, RunStatusCountType, + ProgressSeriesType, RunsMessages, RunMessages, };