Display information of project on home tab
This commit is contained in:
@@ -36,6 +36,7 @@
|
|||||||
"Folders": "Folders",
|
"Folders": "Folders",
|
||||||
"test_cases": "Test Cases",
|
"test_cases": "Test Cases",
|
||||||
"test_runs": "Test Runs",
|
"test_runs": "Test Runs",
|
||||||
|
"progress": "Progress",
|
||||||
"test_types": "Test types",
|
"test_types": "Test types",
|
||||||
"other": "Other",
|
"other": "Other",
|
||||||
"security": "Security",
|
"security": "Security",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"Folders": "フォルダー",
|
"Folders": "フォルダー",
|
||||||
"test_cases": "テストケース",
|
"test_cases": "テストケース",
|
||||||
"test_runs": "テスト実行",
|
"test_runs": "テスト実行",
|
||||||
|
"progress": "進捗",
|
||||||
"test_types": "テスト種別",
|
"test_types": "テスト種別",
|
||||||
"other": "その他",
|
"other": "その他",
|
||||||
"security": "セキュリティ",
|
"security": "セキュリティ",
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
<Chart
|
||||||
|
options={chartData.options}
|
||||||
|
series={chartData.series}
|
||||||
|
type="bar"
|
||||||
|
width={"100%"}
|
||||||
|
height={"100%"}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ProjectType } from "@/types/project";
|
import { ProjectType } from "@/types/project";
|
||||||
import { testTypes, priorities } from "@/config/selection";
|
import { testTypes, priorities, testRunCaseStatus } from "@/config/selection";
|
||||||
|
|
||||||
// aggregate folder, case, run mum
|
// aggregate folder, case, run mum
|
||||||
function aggregateBasicInfo(project: ProjectType) {
|
function aggregateBasicInfo(project: ProjectType) {
|
||||||
@@ -49,4 +49,44 @@ function aggregateTestPriority(project: ProjectType) {
|
|||||||
return result;
|
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,
|
||||||
|
};
|
||||||
|
|||||||
@@ -5,14 +5,17 @@ import { title } from "@/components/primitives";
|
|||||||
import { Card, CardBody, Chip } from "@nextui-org/react";
|
import { Card, CardBody, Chip } from "@nextui-org/react";
|
||||||
import { Folder, Clipboard, FlaskConical } from "lucide-react";
|
import { Folder, Clipboard, FlaskConical } from "lucide-react";
|
||||||
import { CaseTypeCountType, CasePriorityCountType } from "@/types/case";
|
import { CaseTypeCountType, CasePriorityCountType } from "@/types/case";
|
||||||
|
import { ProgressSeriesType } from "@/types/run";
|
||||||
import { HomeMessages } from "./page";
|
import { HomeMessages } from "./page";
|
||||||
import {
|
import {
|
||||||
aggregateBasicInfo,
|
aggregateBasicInfo,
|
||||||
aggregateTestPriority,
|
aggregateTestPriority,
|
||||||
aggregateTestType,
|
aggregateTestType,
|
||||||
|
aggregateProgress,
|
||||||
} from "./aggregate";
|
} from "./aggregate";
|
||||||
import TestTypesChart from "./TestTypesDonutChart";
|
import TestTypesChart from "./TestTypesDonutChart";
|
||||||
import TestPriorityChart from "./TestPriorityDonutChart";
|
import TestPriorityChart from "./TestPriorityDonutChart";
|
||||||
|
import TestProgressBarChart from "./TestProgressColumnChart";
|
||||||
import Config from "@/config/config";
|
import Config from "@/config/config";
|
||||||
const apiServer = Config.apiServer;
|
const apiServer = Config.apiServer;
|
||||||
|
|
||||||
@@ -54,6 +57,8 @@ export function Home({ projectId, messages }: Props) {
|
|||||||
const [typesCounts, setTypesCounts] = useState<CaseTypeCountType[]>();
|
const [typesCounts, setTypesCounts] = useState<CaseTypeCountType[]>();
|
||||||
const [priorityCounts, setPriorityCounts] =
|
const [priorityCounts, setPriorityCounts] =
|
||||||
useState<CasePriorityCountType[]>();
|
useState<CasePriorityCountType[]>();
|
||||||
|
const [progressCategories, setProgressCategories] = useState<string[]>();
|
||||||
|
const [progressSeries, setProgressSeries] = useState<ProgressSeriesType[]>();
|
||||||
const url = `${apiServer}/home/${projectId}`;
|
const url = `${apiServer}/home/${projectId}`;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -82,6 +87,10 @@ export function Home({ projectId, messages }: Props) {
|
|||||||
|
|
||||||
const priorityRet = aggregateTestPriority(project);
|
const priorityRet = aggregateTestPriority(project);
|
||||||
setPriorityCounts([...priorityRet]);
|
setPriorityCounts([...priorityRet]);
|
||||||
|
|
||||||
|
const { series, categories } = aggregateProgress(project);
|
||||||
|
setProgressSeries([...series]);
|
||||||
|
setProgressCategories([...categories]);
|
||||||
}
|
}
|
||||||
|
|
||||||
aggregate();
|
aggregate();
|
||||||
@@ -119,7 +128,16 @@ export function Home({ projectId, messages }: Props) {
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Divider className="my-6" />
|
<Divider className="my-6" />
|
||||||
<div className="flex">
|
<div style={{ height: "20rem" }}>
|
||||||
|
<h3>{messages.progress}</h3>
|
||||||
|
<TestProgressBarChart
|
||||||
|
progressSeries={progressSeries}
|
||||||
|
progressCategories={progressCategories}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider className="my-6" />
|
||||||
|
<div className="flex pb-20">
|
||||||
<div style={{ width: "32rem", height: "18rem" }}>
|
<div style={{ width: "32rem", height: "18rem" }}>
|
||||||
<h3>{messages.testTypes}</h3>
|
<h3>{messages.testTypes}</h3>
|
||||||
<TestTypesChart typesCounts={typesCounts} messages={messages} />
|
<TestTypesChart typesCounts={typesCounts} messages={messages} />
|
||||||
@@ -132,8 +150,6 @@ export function Home({ projectId, messages }: Props) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Divider className="my-6" />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export type HomeMessages = {
|
|||||||
folders: string;
|
folders: string;
|
||||||
testCases: string;
|
testCases: string;
|
||||||
testRuns: string;
|
testRuns: string;
|
||||||
|
progress: string;
|
||||||
testTypes: string;
|
testTypes: string;
|
||||||
other: string;
|
other: string;
|
||||||
security: string;
|
security: string;
|
||||||
@@ -32,6 +33,7 @@ export default function Page({ params }: { params: { projectId: string } }) {
|
|||||||
folders: t("Folders"),
|
folders: t("Folders"),
|
||||||
testCases: t("test_cases"),
|
testCases: t("test_cases"),
|
||||||
testRuns: t("test_runs"),
|
testRuns: t("test_runs"),
|
||||||
|
progress: t("progress"),
|
||||||
testTypes: t("test_types"),
|
testTypes: t("test_types"),
|
||||||
other: t("other"),
|
other: t("other"),
|
||||||
security: t("security"),
|
security: t("security"),
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ type RunStatusCountType = {
|
|||||||
count: number;
|
count: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ProgressSeriesType = {
|
||||||
|
name: string;
|
||||||
|
data: number[];
|
||||||
|
}
|
||||||
|
|
||||||
type RunsMessages = {
|
type RunsMessages = {
|
||||||
runList: string,
|
runList: string,
|
||||||
id: string;
|
id: string;
|
||||||
@@ -78,6 +83,7 @@ export {
|
|||||||
RunCaseType,
|
RunCaseType,
|
||||||
RunCaseInfoType,
|
RunCaseInfoType,
|
||||||
RunStatusCountType,
|
RunStatusCountType,
|
||||||
|
ProgressSeriesType,
|
||||||
RunsMessages,
|
RunsMessages,
|
||||||
RunMessages,
|
RunMessages,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user