From ed3465126fe0309d1461daa6f05dc6fc4a054894 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Tue, 18 Jun 2024 18:08:09 +0530 Subject: [PATCH 1/5] upcoming: [DI-19062] - Dashboard Select component in cloudpulse global filters view --- packages/api-v4/src/cloudpulse/dashboards.ts | 15 ++++ packages/api-v4/src/cloudpulse/index.ts | 2 + packages/api-v4/src/cloudpulse/types.ts | 45 +++++++++++ packages/api-v4/src/index.ts | 2 + .../CloudPulse/Overview/GlobalFilters.tsx | 22 +++++- .../shared/CloudPulseDashboardSelect.test.tsx | 18 +++++ .../shared/CloudPulseDashboardSelect.tsx | 78 +++++++++++++++++++ .../shared/CloudPulseRegionSelect.tsx | 21 +++-- .../shared/CloudPulseResourcesSelect.tsx | 2 +- packages/manager/src/mocks/serverHandlers.ts | 58 ++++++++++++++ .../src/queries/cloudpulse/dashboards.ts | 32 ++++++++ 11 files changed, 279 insertions(+), 16 deletions(-) create mode 100644 packages/api-v4/src/cloudpulse/dashboards.ts create mode 100644 packages/api-v4/src/cloudpulse/index.ts create mode 100644 packages/api-v4/src/cloudpulse/types.ts create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx create mode 100644 packages/manager/src/queries/cloudpulse/dashboards.ts diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts new file mode 100644 index 00000000000..5e7584f4984 --- /dev/null +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -0,0 +1,15 @@ +import { ResourcePage } from 'src/types'; +import Request, { setHeaders, setMethod, setURL } from '../request'; +import { Dashboard } from './types'; + +//Returns the list of all the dashboards available +export const getDashboards = () => + Request>( + setURL( + `http://blr-lhv95n.bangalore.corp.akamai.com:9000/v4/monitor/services/linode/dashboards` + ), + setMethod('GET'), + setHeaders({ + Authorization: 'Bearer vagrant', + }) + ); \ No newline at end of file diff --git a/packages/api-v4/src/cloudpulse/index.ts b/packages/api-v4/src/cloudpulse/index.ts new file mode 100644 index 00000000000..e3f1384cfff --- /dev/null +++ b/packages/api-v4/src/cloudpulse/index.ts @@ -0,0 +1,2 @@ +export * from './types' +export * from './dashboards' \ No newline at end of file diff --git a/packages/api-v4/src/cloudpulse/types.ts b/packages/api-v4/src/cloudpulse/types.ts new file mode 100644 index 00000000000..27c11c9f1d0 --- /dev/null +++ b/packages/api-v4/src/cloudpulse/types.ts @@ -0,0 +1,45 @@ +export interface Dashboard { + id: number; + label: string; + widgets: Widgets[]; + created: string; + updated: string; + time_duration: TimeDuration; + service_type: string; +} + +export interface TimeGranularity { + unit: string; + value: number; +} + +export interface TimeDuration { + unit: string; + value: number; +} + +export interface Widgets { + label: string; + metric: string; + aggregate_function: string; + group_by: string; + region_id: number; + namespace_id: number; + color: string; + size: number; + chart_type: string; + y_label: string; + filters: Filters[]; + serviceType: string; + service_type: string; + resource_id: string[]; + time_granularity: TimeGranularity; + time_duration: TimeDuration; + unit: string; +} + +export interface Filters { + key: string; + operator: string; + value: string; +} \ No newline at end of file diff --git a/packages/api-v4/src/index.ts b/packages/api-v4/src/index.ts index 8de3cbfcf6f..5c6d9a81d94 100644 --- a/packages/api-v4/src/index.ts +++ b/packages/api-v4/src/index.ts @@ -2,6 +2,8 @@ export * from './account'; export * from './aclb'; +export * from './cloudpulse' + export * from './databases'; export * from './domains'; diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index c134e02cd63..e7068d7b865 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -8,6 +8,8 @@ import { CloudPulseTimeRangeSelect } from '../shared/CloudPulseTimeRangeSelect'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; import type { WithStartAndEnd } from 'src/features/Longview/request.types'; +import { Dashboard } from '@linode/api-v4'; +import { CloudPulseDashboardSelect } from '../shared/CloudPulseDashboardSelect'; export interface GlobalFilterProperties { handleAnyFilterChange(filters: FiltersObject): undefined | void; @@ -27,8 +29,10 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { start: 0, }); - const [selectedRegion, setRegion] = React.useState(); + const [selectedDashboard, setSelectedDashboard] = React.useState(); + const [selectedRegion, setRegion] = React.useState(null); const [, setResources] = React.useState(); // removed the unused variable, this will be used later point of time + React.useEffect(() => { const triggerGlobalFilterChange = () => { const globalFilters: FiltersObject = { @@ -53,7 +57,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { [] ); - const handleRegionChange = React.useCallback((region: string | undefined) => { + const handleRegionChange = React.useCallback((region: string | null) => { setRegion(region); }, []); @@ -64,12 +68,24 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { [] ); + const handleDashboardChange = React.useCallback((dashboard: Dashboard | undefined) => { + setSelectedDashboard(dashboard); + setRegion(null); + }, []) + return ( + + + @@ -77,7 +93,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx new file mode 100644 index 00000000000..cc2acdf59b1 --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx @@ -0,0 +1,18 @@ +import { renderWithTheme } from "src/utilities/testHelpers"; +import { CloudPulseDashboardSelect, CloudPulseDashboardSelectProps } from "./CloudPulseDashboardSelect"; +import React from "react"; + +const props : CloudPulseDashboardSelectProps = { + handleDashboardChange : vi.fn(), +} + +describe("CloudPulse Dashboard select", ()=>{ + it("Should render dashboard select component", ()=>{ + const {getByTestId} = renderWithTheme( + + ); + + expect(getByTestId('cloudview-dashboard-select')).toBeInTheDocument(); + + }) +}) \ No newline at end of file diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx new file mode 100644 index 00000000000..123bb7803e0 --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -0,0 +1,78 @@ +import React from 'react'; + +import { Dashboard } from '@linode/api-v4' +import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; +import { Box } from 'src/components/Box'; +import { Typography } from 'src/components/Typography'; +import { useCloudViewDashboardsQuery } from 'src/queries/cloudpulse/dashboards'; + + +export interface CloudPulseDashboardSelectProps { + handleDashboardChange: ( + dashboard: Dashboard | undefined + ) => void +} + +export const CloudPulseDashboardSelect = React.memo((props: CloudPulseDashboardSelectProps) => { + + const { + data: dashboardsList, + error, + isLoading, + } = useCloudViewDashboardsQuery(); //Fetch the list of dashboards + + const errorText: string = error ? 'Error loading dashboards' : ''; + + // sorts dashboards by service type. Required due to unexpected autocomplete grouping behaviour + const getSortedDashboardsList = (options: Dashboard[]) => { + return options.sort( + (a, b) => -b.service_type.localeCompare(a.service_type) + ); + }; + + if (!dashboardsList) { + return ( + {}} + data-testid="cloudview-dashboard-select" + placeholder='Select Dashboard' + /> + ) + } + + return ( + { + props.handleDashboardChange(dashboard); + }} + options={ + !dashboardsList ? [] : getSortedDashboardsList(dashboardsList.data) + } + renderGroup={(params) => ( + + + {params.group} + + {params.children} + + )} + autoHighlight + clearOnBlur + data-testid="cloudview-dashboard-select" + errorText={errorText} + fullWidth + groupBy={(option: Dashboard) => option.service_type} + isOptionEqualToValue={(option, value) => option.label === value.label} + label="" + loading={isLoading} + noMarginTop + placeholder="Select a Dashboard" + /> + ); +}); \ No newline at end of file diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 898f947a94a..2dd3d78aa6d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -1,34 +1,31 @@ +/* eslint-disable no-console */ +import { Dashboard } from '@linode/api-v4'; import * as React from 'react'; import { RegionSelect } from 'src/components/RegionSelect/RegionSelect'; import { useRegionsQuery } from 'src/queries/regions/regions'; export interface CloudPulseRegionSelectProps { - handleRegionChange: (region: string | undefined) => void; + handleRegionChange: (region: string | null) => void; + selectedDashboard: Dashboard | undefined; + selectedRegion: string | null; } export const CloudPulseRegionSelect = React.memo( (props: CloudPulseRegionSelectProps) => { const { data: regions } = useRegionsQuery(); - const [selectedRegion, setRegion] = React.useState(); - - React.useEffect(() => { - if (selectedRegion) { - props.handleRegionChange(selectedRegion); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedRegion]); return ( setRegion(region.id)} + onChange={(e, region) => props.handleRegionChange(region?.id ?? null)} regions={regions ? regions : []} - value={undefined} + disabled={!props.selectedDashboard} + value={props.selectedRegion} /> ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index b04b1c7b28b..bf7e6da354d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -14,7 +14,7 @@ export interface CloudPulseResourcesSelectProps { defaultSelection?: number[]; handleResourcesSelection: (resources: CloudPulseResources[]) => void; placeholder?: string; - region: string | undefined; + region: string | null; resourceType: string | undefined; } diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index f0ad8f8fc6d..0fb9b0203b3 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -2336,6 +2336,64 @@ export const handlers = [ return HttpResponse.json(response); }), + http.get('*/v4/monitor/services/linode/dashboards', () => { + const response = { + "data": [ + { + "id": 1, + "type": "standard", + "service_type": "linode", + "label": "Linode Service I/O Statistics", + "created": "2024-04-29T17:09:29", + "updated": null, + "widgets": [ + { + "metric": "system_cpu_utilization_percent", + "unit": "%", + "label": "CPU utilization", + "color": "blue", + "size": 12, + "chart_type": "area", + "y_label": "system_cpu_utilization_ratio", + "aggregate_function": "avg" + }, + { + "metric": "system_memory_usage_by_resource", + "unit": "Bytes", + "label": "Memory Usage", + "color": "red", + "size": 12, + "chart_type": "area", + "y_label": "system_memory_usage_bytes", + "aggregate_function": "avg" + }, + { + "metric": "system_network_io_by_resource", + "unit": "Bytes", + "label": "Network Traffic", + "color": "green", + "size": 6, + "chart_type": "area", + "y_label": "system_network_io_bytes_total", + "aggregate_function": "avg" + }, + { + "metric": "system_disk_OPS_total", + "unit": "OPS", + "label": "Disk I/O", + "color": "yellow", + "size": 6, + "chart_type": "area", + "y_label": "system_disk_operations_total", + "aggregate_function": "avg" + } + ] + } + ] + } + + return HttpResponse.json(response); + }), ...entityTransfers, ...statusPage, ...databases, diff --git a/packages/manager/src/queries/cloudpulse/dashboards.ts b/packages/manager/src/queries/cloudpulse/dashboards.ts new file mode 100644 index 00000000000..b3b87e8d522 --- /dev/null +++ b/packages/manager/src/queries/cloudpulse/dashboards.ts @@ -0,0 +1,32 @@ +import { Dashboard, getDashboards } from "@linode/api-v4"; +import { APIError, ResourcePage } from "@linode/api-v4/lib/types"; +import { createQueryKeys } from "@lukemorales/query-key-factory"; +import { useQuery } from "@tanstack/react-query"; + +export const queryKey = 'cloudview-dashboards'; + +export const dashboardQueries = createQueryKeys('cloudview-dashboards', { + availability: { + contextQueries: { + dashboard: (dashboardId: number) => ({ + queryFn: () => { }, //Todo: Add its implementation once ready + queryKey: [dashboardId], + }), + }, + queryKey: null + }, + dashboards: { + queryFn: getDashboards, + queryKey: null + } +}); + +export const useCloudViewDashboardsQuery = () => { + return useQuery, APIError[]>({ + // querykey and dashboardId makes this uniquely identifiable + ...dashboardQueries.dashboards, + enabled: true + + } + ); +}; \ No newline at end of file From ce2cfc30e4a67560d81ca4b14529f45d4e76a250 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Tue, 18 Jun 2024 18:43:51 +0530 Subject: [PATCH 2/5] upcoming: [DI-19062] - Added change set --- .../.changeset/pr-10589-upcoming-features-1718716331830.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-10589-upcoming-features-1718716331830.md diff --git a/packages/manager/.changeset/pr-10589-upcoming-features-1718716331830.md b/packages/manager/.changeset/pr-10589-upcoming-features-1718716331830.md new file mode 100644 index 00000000000..2d179125d88 --- /dev/null +++ b/packages/manager/.changeset/pr-10589-upcoming-features-1718716331830.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Added Dashboard Selection component inside the Global Filters of CloudPulse view. ([#10589](https://github.com/linode/manager/pull/10589)) From c4ac08a6feffcde0b7588d15e3f5e8baa13a8568 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Wed, 19 Jun 2024 12:22:08 +0530 Subject: [PATCH 3/5] upcoming: [DI-19062] - Replaced the hard-coded url with placeholder --- packages/api-v4/src/cloudpulse/dashboards.ts | 5 ++- packages/api-v4/src/cloudpulse/index.ts | 3 +- .../CloudPulse/Overview/GlobalFilters.tsx | 6 +-- .../shared/CloudPulseDashboardSelect.tsx | 4 +- .../shared/CloudPulseRegionSelect.tsx | 8 ++-- .../shared/CloudPulseResourcesSelect.tsx | 2 +- .../src/queries/cloudpulse/dashboards.ts | 39 +++++++++++-------- 7 files changed, 37 insertions(+), 30 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts index 5e7584f4984..7459249472c 100644 --- a/packages/api-v4/src/cloudpulse/dashboards.ts +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -1,15 +1,16 @@ import { ResourcePage } from 'src/types'; import Request, { setHeaders, setMethod, setURL } from '../request'; import { Dashboard } from './types'; +import { API_ROOT } from 'src/constants'; //Returns the list of all the dashboards available export const getDashboards = () => Request>( setURL( - `http://blr-lhv95n.bangalore.corp.akamai.com:9000/v4/monitor/services/linode/dashboards` + `${API_ROOT}/monitor/services/linode/dashboards` ), setMethod('GET'), setHeaders({ - Authorization: 'Bearer vagrant', + Authorization: '', //Authorization will be updated once the end-point is ready, till then will use mock data }) ); \ No newline at end of file diff --git a/packages/api-v4/src/cloudpulse/index.ts b/packages/api-v4/src/cloudpulse/index.ts index e3f1384cfff..172f53aa4ef 100644 --- a/packages/api-v4/src/cloudpulse/index.ts +++ b/packages/api-v4/src/cloudpulse/index.ts @@ -1,2 +1,3 @@ export * from './types' -export * from './dashboards' \ No newline at end of file + +export * from './dashboards' diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index e7068d7b865..e99a918846e 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -30,7 +30,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { }); const [selectedDashboard, setSelectedDashboard] = React.useState(); - const [selectedRegion, setRegion] = React.useState(null); + const [selectedRegion, setRegion] = React.useState(); const [, setResources] = React.useState(); // removed the unused variable, this will be used later point of time React.useEffect(() => { @@ -57,7 +57,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { [] ); - const handleRegionChange = React.useCallback((region: string | null) => { + const handleRegionChange = React.useCallback((region: string | undefined) => { setRegion(region); }, []); @@ -70,7 +70,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { const handleDashboardChange = React.useCallback((dashboard: Dashboard | undefined) => { setSelectedDashboard(dashboard); - setRegion(null); + setRegion(undefined); }, []) return ( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 123bb7803e0..a78615749a2 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -19,7 +19,7 @@ export const CloudPulseDashboardSelect = React.memo((props: CloudPulseDashboardS data: dashboardsList, error, isLoading, - } = useCloudViewDashboardsQuery(); //Fetch the list of dashboards + } = useCloudViewDashboardsQuery(true); //Fetch the list of dashboards const errorText: string = error ? 'Error loading dashboards' : ''; @@ -75,4 +75,4 @@ export const CloudPulseDashboardSelect = React.memo((props: CloudPulseDashboardS placeholder="Select a Dashboard" /> ); -}); \ No newline at end of file +}); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 2dd3d78aa6d..eb9d4081f9d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -6,9 +6,9 @@ import { RegionSelect } from 'src/components/RegionSelect/RegionSelect'; import { useRegionsQuery } from 'src/queries/regions/regions'; export interface CloudPulseRegionSelectProps { - handleRegionChange: (region: string | null) => void; + handleRegionChange: (region: string | undefined) => void; selectedDashboard: Dashboard | undefined; - selectedRegion: string | null; + selectedRegion: string | undefined; } export const CloudPulseRegionSelect = React.memo( @@ -22,10 +22,10 @@ export const CloudPulseRegionSelect = React.memo( fullWidth label="" noMarginTop - onChange={(e, region) => props.handleRegionChange(region?.id ?? null)} + onChange={(e, region) => props.handleRegionChange(region?.id)} regions={regions ? regions : []} disabled={!props.selectedDashboard} - value={props.selectedRegion} + value={props.selectedRegion ?? null} /> ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index bf7e6da354d..b04b1c7b28b 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -14,7 +14,7 @@ export interface CloudPulseResourcesSelectProps { defaultSelection?: number[]; handleResourcesSelection: (resources: CloudPulseResources[]) => void; placeholder?: string; - region: string | null; + region: string | undefined; resourceType: string | undefined; } diff --git a/packages/manager/src/queries/cloudpulse/dashboards.ts b/packages/manager/src/queries/cloudpulse/dashboards.ts index b3b87e8d522..1a6dfa21204 100644 --- a/packages/manager/src/queries/cloudpulse/dashboards.ts +++ b/packages/manager/src/queries/cloudpulse/dashboards.ts @@ -6,27 +6,32 @@ import { useQuery } from "@tanstack/react-query"; export const queryKey = 'cloudview-dashboards'; export const dashboardQueries = createQueryKeys('cloudview-dashboards', { - availability: { + lists: { contextQueries: { - dashboard: (dashboardId: number) => ({ - queryFn: () => { }, //Todo: Add its implementation once ready - queryKey: [dashboardId], - }), + allDashboards: { + queryFn: getDashboards, + queryKey: null + } }, queryKey: null }, - dashboards: { - queryFn: getDashboards, - queryKey: null - } + + dashboardById: (dashboardId: number) => ({ + contextQueries: { + dashboard: { + queryFn: () => { }, //Todo: will be implemented later + queryKey: [dashboardId] + } + }, + queryKey: [dashboardId] + }) + }); -export const useCloudViewDashboardsQuery = () => { +//Fetch the list of all the dashboard available +export const useCloudViewDashboardsQuery = (enabled: boolean) => { return useQuery, APIError[]>({ - // querykey and dashboardId makes this uniquely identifiable - ...dashboardQueries.dashboards, - enabled: true - - } - ); -}; \ No newline at end of file + ...dashboardQueries.lists._ctx.allDashboards, + enabled + }); +}; From e526c9a4a5c54828a78388bf9bb3f83974b6006b Mon Sep 17 00:00:00 2001 From: nikhagra Date: Wed, 19 Jun 2024 12:31:39 +0530 Subject: [PATCH 4/5] upcoming: [DI-19062] - Updated placeholder in dashboard select component --- .../CloudPulse/shared/CloudPulseDashboardSelect.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index a78615749a2..2b051ff41de 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -23,6 +23,8 @@ export const CloudPulseDashboardSelect = React.memo((props: CloudPulseDashboardS const errorText: string = error ? 'Error loading dashboards' : ''; + const placeHolder = "Select Dashboard"; + // sorts dashboards by service type. Required due to unexpected autocomplete grouping behaviour const getSortedDashboardsList = (options: Dashboard[]) => { return options.sort( @@ -36,9 +38,10 @@ export const CloudPulseDashboardSelect = React.memo((props: CloudPulseDashboardS options={[]} label='' disabled={true} - onChange={() => {}} + onChange={() => { }} data-testid="cloudview-dashboard-select" - placeholder='Select Dashboard' + placeholder={placeHolder} + errorText={errorText} /> ) } @@ -48,9 +51,7 @@ export const CloudPulseDashboardSelect = React.memo((props: CloudPulseDashboardS onChange={(_: any, dashboard: Dashboard) => { props.handleDashboardChange(dashboard); }} - options={ - !dashboardsList ? [] : getSortedDashboardsList(dashboardsList.data) - } + options={ getSortedDashboardsList(dashboardsList.data) } renderGroup={(params) => ( ); }); From f53fd9858ca2cf62f1c1f4606789d8d87fd92680 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Fri, 21 Jun 2024 18:47:52 +0530 Subject: [PATCH 5/5] upcoming: [DI-19062] - Added test cases --- ...r-10589-upcoming-features-1718971604339.md | 5 ++ packages/api-v4/src/cloudpulse/dashboards.ts | 17 ++--- .../shared/CloudPulseDashboardSelect.test.tsx | 74 ++++++++++++++++--- .../shared/CloudPulseDashboardSelect.tsx | 2 +- .../shared/CloudPulseRegionSelect.test.tsx | 2 + .../shared/CloudPulseRegionSelect.tsx | 2 +- 6 files changed, 80 insertions(+), 22 deletions(-) create mode 100644 packages/api-v4/.changeset/pr-10589-upcoming-features-1718971604339.md diff --git a/packages/api-v4/.changeset/pr-10589-upcoming-features-1718971604339.md b/packages/api-v4/.changeset/pr-10589-upcoming-features-1718971604339.md new file mode 100644 index 00000000000..31b076dc1d7 --- /dev/null +++ b/packages/api-v4/.changeset/pr-10589-upcoming-features-1718971604339.md @@ -0,0 +1,5 @@ +--- +"@linode/api-v4": Upcoming Features +--- + +Added types needed for DashboardSelect component ([#10589](https://github.com/linode/manager/pull/10589)) diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts index 7459249472c..6afd2f7a851 100644 --- a/packages/api-v4/src/cloudpulse/dashboards.ts +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -1,16 +1,13 @@ import { ResourcePage } from 'src/types'; -import Request, { setHeaders, setMethod, setURL } from '../request'; +import Request, { setMethod, setURL } from '../request'; import { Dashboard } from './types'; import { API_ROOT } from 'src/constants'; //Returns the list of all the dashboards available export const getDashboards = () => - Request>( - setURL( - `${API_ROOT}/monitor/services/linode/dashboards` - ), - setMethod('GET'), - setHeaders({ - Authorization: '', //Authorization will be updated once the end-point is ready, till then will use mock data - }) - ); \ No newline at end of file + Request>( + setURL( + `${API_ROOT}/monitor/services/linode/dashboards` + ), + setMethod('GET'), + ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx index cc2acdf59b1..8db2c68246b 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx @@ -1,18 +1,72 @@ import { renderWithTheme } from "src/utilities/testHelpers"; import { CloudPulseDashboardSelect, CloudPulseDashboardSelectProps } from "./CloudPulseDashboardSelect"; import React from "react"; +import { fireEvent, screen } from '@testing-library/react'; -const props : CloudPulseDashboardSelectProps = { - handleDashboardChange : vi.fn(), +const props: CloudPulseDashboardSelectProps = { + handleDashboardChange: vi.fn(), } -describe("CloudPulse Dashboard select", ()=>{ - it("Should render dashboard select component", ()=>{ - const {getByTestId} = renderWithTheme( - - ); - - expect(getByTestId('cloudview-dashboard-select')).toBeInTheDocument(); +const queryMocks = vi.hoisted(() => ({ + useCloudViewDashboardsQuery: vi.fn().mockReturnValue({}), +})); +vi.mock('src/queries/cloudpulse/dashboards', async () => { + const actual = await vi.importActual('src/queries/cloudpulse/dashboards'); + return { + ...actual, + useCloudViewDashboardsQuery: queryMocks.useCloudViewDashboardsQuery, + }; +}); + +queryMocks.useCloudViewDashboardsQuery.mockReturnValue({ + data: + { + data: [ + { + id: 1, + type: "standard", + service_type: "linode", + label: "Dashboard 1", + created: "2024-04-29T17:09:29", + updated: null, + widgets: {} + } + ] + } + , + isLoading: false, + error: false +}); + +describe("CloudPulse Dashboard select", () => { + it("Should render dashboard select component", () => { + const { getByTestId, getByPlaceholderText } = renderWithTheme( + + ); + + expect(getByTestId('cloudview-dashboard-select')).toBeInTheDocument(); + expect(getByPlaceholderText('Select a Dashboard')).toBeInTheDocument(); + + }), + + it("Should render dashboard select component with data", () => { + + + renderWithTheme() + + fireEvent.click(screen.getByRole('button', { name: 'Open' })); + + expect(screen.getByRole('option', { name: 'Dashboard 1' })).toBeInTheDocument(); + }), + + it("Should select the option on click", () => { + + renderWithTheme(); + + fireEvent.click(screen.getByRole("button", { name: "Open" })); + fireEvent.click(screen.getByRole("option", { name: "Dashboard 1" })); + + expect(screen.getByRole("combobox")).toHaveAttribute("value", "Dashboard 1"); }) -}) \ No newline at end of file +}) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 2b051ff41de..8c3178574ab 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -23,7 +23,7 @@ export const CloudPulseDashboardSelect = React.memo((props: CloudPulseDashboardS const errorText: string = error ? 'Error loading dashboards' : ''; - const placeHolder = "Select Dashboard"; + const placeHolder = "Select a Dashboard"; // sorts dashboards by service type. Required due to unexpected autocomplete grouping behaviour const getSortedDashboardsList = (options: Dashboard[]) => { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index 6f17a20649d..6570bdd8934 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -7,6 +7,8 @@ import { CloudPulseRegionSelect } from './CloudPulseRegionSelect'; const props: CloudPulseRegionSelectProps = { handleRegionChange: vi.fn(), + selectedDashboard: undefined, + selectedRegion: undefined }; describe('CloudViewRegionSelect', () => { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index eb9d4081f9d..1f45fb150b7 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -25,7 +25,7 @@ export const CloudPulseRegionSelect = React.memo( onChange={(e, region) => props.handleRegionChange(region?.id)} regions={regions ? regions : []} disabled={!props.selectedDashboard} - value={props.selectedRegion ?? null} + value={props.selectedRegion} /> ); }