diff --git a/kraken-app/kraken-app-portal/src/__test__/pages/Homepage/components/ActivityDiagrams.test.tsx b/kraken-app/kraken-app-portal/src/__test__/pages/Homepage/components/ActivityDiagrams.test.tsx index 997ab9a3..673b8d14 100644 --- a/kraken-app/kraken-app-portal/src/__test__/pages/Homepage/components/ActivityDiagrams.test.tsx +++ b/kraken-app/kraken-app-portal/src/__test__/pages/Homepage/components/ActivityDiagrams.test.tsx @@ -1,10 +1,9 @@ import ActivityDiagrams from '@/pages/HomePage/components/ActivityDiagrams'; -import { queryClient } from "@/utils/helpers/reactQuery"; -import { QueryClientProvider } from "@tanstack/react-query"; -import { fireEvent, render } from "@testing-library/react"; -import { BrowserRouter } from "react-router-dom"; +import { fireEvent } from "@testing-library/react"; +import * as homepageHooks from '@/hooks/homepage' +import { render } from "@/__test__/utils"; -test("ActivityDiagrams test", () => { +test("ActivityDiagrams test with data", () => { const envs = { data: [ { @@ -16,14 +15,89 @@ test("ActivityDiagrams test", () => { ], }; + vi.spyOn(homepageHooks, "useGetErrorBrakedown").mockReturnValue({ + data: { + errorBreakdowns: [ + { + date: "2024-05-30T13:02:03.224486Z", + errors: { + 400: 1, + 401: 1, + 404: 1, + 500: 1, + } + }, + ], + }, + isLoading: false, + refetch: vi.fn() + } as any); + + + vi.spyOn(homepageHooks, "useGetActivityRequests").mockReturnValue({ + data: { + requestStatistics: [ + { + date: "2024-05-30T13:02:03.224486Z", + success: 1, + error: 2, + }, + ], + }, + isLoading: false, + refetch: vi.fn(), + isRefetching: false + } as any); + const { container, getByTestId } = render( - - - - - + ); expect(container).toBeInTheDocument(); - const recentButton = getByTestId('recent-7-days'); + const recentButton = getByTestId('recent-90-days'); fireEvent.click(recentButton); }); + +test("ActivityDiagrams test with no data", () => { + const envs = { + data: [ + { + id: "32b4832f-fb2f-4c99-b89a-c5c995b18dfc", + productId: "mef.sonata", + createdAt: "2024-05-30T13:02:03.224486Z", + name: "stage", + }, + ], + }; + + vi.spyOn(homepageHooks, "useGetErrorBrakedown").mockReturnValue({ + data: { + errorBreakdowns: [], + }, + isLoading: false, + refetch: vi.fn() + } as any); + + + vi.spyOn(homepageHooks, "useGetActivityRequests").mockReturnValue({ + data: {}, + isLoading: false, + refetch: vi.fn(), + isRefetching: false + } as any); + + const { container } = render( + + ); + expect(container).toBeInTheDocument(); +}); + +test("ActivityDiagrams test with no data", () => { + const envs = { + data: [], + }; + + const { container } = render( + + ); + expect(container).toBeInTheDocument(); +}); \ No newline at end of file diff --git a/kraken-app/kraken-app-portal/src/pages/HomePage/components/ActivityDiagrams/ApiActivityDiagram/index.tsx b/kraken-app/kraken-app-portal/src/pages/HomePage/components/ActivityDiagrams/ApiActivityDiagram/index.tsx index cff22200..c9924011 100644 --- a/kraken-app/kraken-app-portal/src/pages/HomePage/components/ActivityDiagrams/ApiActivityDiagram/index.tsx +++ b/kraken-app/kraken-app-portal/src/pages/HomePage/components/ActivityDiagrams/ApiActivityDiagram/index.tsx @@ -38,7 +38,11 @@ const ApiActivityDiagram = ({ props }: Props) => { }, [props]); const activityData = useMemo( - () => data?.requestStatistics, + () => (data?.requestStatistics || []).map(entry => ({ + ...entry, + error: entry.error || 0, + success: entry.success || 0, + })), [isLoading, data] ); @@ -49,7 +53,7 @@ const ApiActivityDiagram = ({ props }: Props) => { {!isLoading && !activityData - ? + ? : { /> capitalize(value)} /> }) => ( barSize={10} stackId="error" dataKey={key} - fill={["#A8071A", "#F5222D", "#FF7875", "#FFF1F0"][index]} + fill={["#A8071A", "#F5222D", "#FF7875", "#FFA39E"][index]} radius={key === "400" ? [10, 10, 0, 0] : 0} /> ))} diff --git a/kraken-app/kraken-app-portal/src/pages/HomePage/components/ActivityDiagrams/index.tsx b/kraken-app/kraken-app-portal/src/pages/HomePage/components/ActivityDiagrams/index.tsx index 8e3f6c56..6cc0bf35 100644 --- a/kraken-app/kraken-app-portal/src/pages/HomePage/components/ActivityDiagrams/index.tsx +++ b/kraken-app/kraken-app-portal/src/pages/HomePage/components/ActivityDiagrams/index.tsx @@ -1,8 +1,7 @@ import { Text } from "@/components/Text"; import { - getCurrentTimeWithZone, + parseDateStartOrEnd, recentXDays, - TIME_ZONE_FORMAT, } from "@/utils/constants/format"; import { IEnv } from "@/utils/types/env.type"; import { @@ -16,7 +15,7 @@ import { Select, } from "antd"; import dayjs from "dayjs"; -import { useCallback, useMemo, useState } from "react"; +import { useMemo, useState } from "react"; import ApiActivityDiagram from "./ApiActivityDiagram"; import ErrorBrakedownDiagram from "./ErrorDiagram"; import MostPopularEndpoints from "./MostPopularEndpoints"; @@ -25,9 +24,9 @@ import { capitalize } from 'lodash'; export type DiagramProps = { envId: string; - requestStartTime: string; - requestEndTime: string; - buyer: string | undefined; + requestStartTime?: string; + requestEndTime?: string; + buyer?: string; requestTime?: any; }; @@ -37,42 +36,30 @@ type Props = { const { RangePicker } = DatePicker; -const DiagramWrapper = ({ envs }: Props) => { +const ActivityDiagrams = ({ envs }: Props) => { const stageEnvId = envs?.find((env: IEnv) => env.name?.toLowerCase() === "stage")?.id ?? ""; - const currentTime = getCurrentTimeWithZone(); const [form] = Form.useForm(); + const [selectedRecentDate, setSelectedRecentDate] = useState(7); + const { requestStartTime, requestEndTime } = recentXDays(selectedRecentDate); + const [params, setParams] = useState({ envId: stageEnvId, - requestStartTime: currentTime, - requestEndTime: currentTime, + requestStartTime, + requestEndTime, buyer: undefined, }); - const handleFormValues = useCallback( - (values: DiagramProps) => { - const { requestTime = [] } = values ?? {}; - setParams({ - envId: values.envId || params.envId, - buyer: values.buyer || params.buyer, - requestStartTime: requestTime?.[0] - ? dayjs(requestTime[0]).startOf("day").format(TIME_ZONE_FORMAT) - : currentTime, - requestEndTime: requestTime?.[1] - ? dayjs(requestTime[1]).endOf("day").format(TIME_ZONE_FORMAT) - : currentTime, - }); - }, - [setParams, params] - ); - - const handleFormValuesChange = useCallback( - (t: any, values: any) => { - if (t.path) return; - handleFormValues(values); - }, - [setParams] - ); + const handleFormValues = (_: unknown, values: DiagramProps) => { + const { requestTime = [] } = values ?? {}; + if(requestTime?.[0]) setSelectedRecentDate(undefined); + setParams({ + envId: values.envId || params.envId, + buyer: values.buyer || params.buyer, + requestStartTime: parseDateStartOrEnd(requestTime?.[0], "start") || params.requestStartTime, + requestEndTime: parseDateStartOrEnd(requestTime?.[1], "end") || params.requestEndTime + }); + } const envOptions = useMemo(() => { return ( @@ -83,9 +70,16 @@ const DiagramWrapper = ({ envs }: Props) => { ); }, [envs]); - const setRecentDate = (e: RadioChangeEvent) => { - const { requestStartTime, requestEndTime } = recentXDays(e); - setParams({ ...params, requestStartTime, requestEndTime }); + const setRecentDate = ({ target: { value } }: RadioChangeEvent) => { + form.setFieldsValue({ requestTime: null }); + const { requestStartTime, requestEndTime } = recentXDays(value); + + setSelectedRecentDate(Number(value)); + setParams({ + ...params, + requestStartTime, + requestEndTime, + }); }; return ( @@ -95,7 +89,7 @@ const DiagramWrapper = ({ envs }: Props) => { form={form} layout="inline" colon={false} - onValuesChange={handleFormValuesChange} + onValuesChange={handleFormValues} > { > Activity diagrams - { - - Recent 7 days - Recent 3 months + + Recent 7 days + Recent 3 months @@ -166,4 +152,4 @@ const DiagramWrapper = ({ envs }: Props) => { ); }; -export default DiagramWrapper; +export default ActivityDiagrams; diff --git a/kraken-app/kraken-app-portal/src/pages/HomePage/index.tsx b/kraken-app/kraken-app-portal/src/pages/HomePage/index.tsx index eecef795..9ca9947f 100644 --- a/kraken-app/kraken-app-portal/src/pages/HomePage/index.tsx +++ b/kraken-app/kraken-app-portal/src/pages/HomePage/index.tsx @@ -6,12 +6,12 @@ import QuickStartGuide from "./components/QuickStartGuide"; const HomePage = () => { const { currentProduct } = useAppStore(); - const { data: envs } = useGetProductEnvs(currentProduct); + const { data: envs, isLoading } = useGetProductEnvs(currentProduct); return ( - {envs && } + {(!isLoading && envs) && } ); }; diff --git a/kraken-app/kraken-app-portal/src/utils/constants/format.ts b/kraken-app/kraken-app-portal/src/utils/constants/format.ts index e092f894..e48c1c19 100644 --- a/kraken-app/kraken-app-portal/src/utils/constants/format.ts +++ b/kraken-app/kraken-app-portal/src/utils/constants/format.ts @@ -1,4 +1,3 @@ -import { RadioChangeEvent } from 'antd'; import dayjs from "dayjs"; import timezone from "dayjs/plugin/timezone"; import utc from "dayjs/plugin/utc"; @@ -18,11 +17,18 @@ export const formatDiagramDate = (value: any): string => { return dayjs(value).format("D-M"); }; -export const recentXDays = (e: RadioChangeEvent) => { +export const recentXDays = (value?: number) => { + if(!value) return {} + const requestEndTime = getCurrentTimeWithZone(); const requestStartTime = - e.target.value === "7" + value === 7 ? dayjs().subtract(7, "days").format(TIME_ZONE_FORMAT) - : dayjs().subtract(7, "months").format(TIME_ZONE_FORMAT); + : dayjs().subtract(3, "months").format(TIME_ZONE_FORMAT); return { requestStartTime, requestEndTime } }; + +export const parseDateStartOrEnd = (date: string | undefined, type: "start" | "end") => + date + ? dayjs(date)[type === "start" ? "startOf" : "endOf"]("day").format(TIME_ZONE_FORMAT) + : getCurrentTimeWithZone(); \ No newline at end of file