From 94fc25bec24810818fa4ba120789a4538f8d3df1 Mon Sep 17 00:00:00 2001 From: Santosh Preetham S Date: Tue, 8 Oct 2024 18:24:54 +0530 Subject: [PATCH 1/4] upcoming: [DI-21270] - Added the Alerts tab --- packages/manager/src/featureFlags.ts | 6 ++ .../AlertsLanding/AlertsDefinitionLanding.tsx | 25 +++++++ .../Alerts/AlertsLanding/AlertsLanding.tsx | 70 +++++++++++++++++++ .../features/CloudPulse/CloudPulseTabs.tsx | 45 ++++++++---- 4 files changed, 133 insertions(+), 13 deletions(-) create mode 100644 packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsDefinitionLanding.tsx create mode 100644 packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx diff --git a/packages/manager/src/featureFlags.ts b/packages/manager/src/featureFlags.ts index c1ba34244f5..455ef53a0f1 100644 --- a/packages/manager/src/featureFlags.ts +++ b/packages/manager/src/featureFlags.ts @@ -80,8 +80,14 @@ interface DesignUpdatesBannerFlag extends BaseFeatureFlag { link: string; } +interface AclpAlerting { + alertDefinitions: boolean; + notificationChannels: boolean; + recentActivity: boolean; +} export interface Flags { aclp: AclpFlag; + aclpAlerting: AclpAlerting; aclpReadEndpoint: string; aclpResourceTypeMap: CloudPulseResourceTypeMapFlag[]; apiMaintenance: APIMaintenance; diff --git a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsDefinitionLanding.tsx b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsDefinitionLanding.tsx new file mode 100644 index 00000000000..381eb9cf31f --- /dev/null +++ b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsDefinitionLanding.tsx @@ -0,0 +1,25 @@ +import * as React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import { Paper } from 'src/components/Paper'; +import { Typography } from 'src/components/Typography'; + +export const AlertDefinitionLanding = () => { + return ( + + + + ); +}; + +const AlertDefinition = () => { + return ( + + Alert Definition + + ); +}; diff --git a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx new file mode 100644 index 00000000000..c169ee3405e --- /dev/null +++ b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx @@ -0,0 +1,70 @@ +import * as React from 'react'; +import { + Redirect, + Route, + Switch, + matchPath, + useHistory, + useLocation, + useRouteMatch, +} from 'react-router-dom'; + +import { Box } from 'src/components/Box'; +import { Paper } from 'src/components/Paper'; +import { TabLinkList } from 'src/components/Tabs/TabLinkList'; +import { Tabs } from 'src/components/Tabs/Tabs'; +import { useFlags } from 'src/hooks/useFlags'; + +import { AlertDefinitionLanding } from './AlertsDefinitionLanding'; + +export const AlertsLanding = React.memo(() => { + const flags = useFlags(); + const { path } = useRouteMatch(); + const history = useHistory(); + const tabs = [ + { + accessible: flags.aclpAlerting?.alertDefinitions, + routeName: `${path}/definitions`, + title: 'Definitions', + }, + ]; + const accessibleTabs = tabs.filter((tab) => tab.accessible); + const location = useLocation(); + const navToURL = (index: number) => { + history.push(accessibleTabs[index].routeName); + }; + const matches = (p: string) => { + return Boolean(matchPath(location.pathname, { exact: false, path: p })); + }; + return ( + + matches(tab.routeName))} + onChange={navToURL} + style={{ width: '100%' }} + > + + + + + + + + + + ); +}); diff --git a/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx b/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx index ddcb223c17f..c11af63dec7 100644 --- a/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx +++ b/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx @@ -1,50 +1,69 @@ import { styled } from '@mui/material/styles'; import * as React from 'react'; -import { matchPath } from 'react-router-dom'; +import { Redirect, Route, Switch, matchPath } from 'react-router-dom'; import { SuspenseLoader } from 'src/components/SuspenseLoader'; -import { SafeTabPanel } from 'src/components/Tabs/SafeTabPanel'; import { TabLinkList } from 'src/components/Tabs/TabLinkList'; -import { TabPanels } from 'src/components/Tabs/TabPanels'; import { Tabs } from 'src/components/Tabs/Tabs'; +import { useFlags } from 'src/hooks/useFlags'; +import { AlertsLanding } from './Alerts/AlertsLanding/AlertsLanding'; import { CloudPulseDashboardLanding } from './Dashboard/CloudPulseDashboardLanding'; import type { RouteComponentProps } from 'react-router-dom'; type Props = RouteComponentProps<{}>; export const CloudPulseTabs = React.memo((props: Props) => { + const flags = useFlags(); const tabs = [ { + accessible: true, routeName: `${props.match.url}/dashboards`, title: 'Dashboards', }, + { + accessible: + flags.aclpAlerting?.alertDefinitions || + flags.aclpAlerting?.recentActivity || + flags.aclpAlerting?.notificationChannels, + routeName: `${props.match.url}/alerts`, + title: 'Alerts', + }, ]; - + const accessibleTabs = tabs.filter((tab) => tab.accessible); const matches = (p: string) => { - return Boolean(matchPath(p, { path: props.location.pathname })); + return Boolean( + matchPath(props.location.pathname, { exact: false, path: p }) + ); }; const navToURL = (index: number) => { - props.history.push(tabs[index].routeName); + props.history.push(accessibleTabs[index].routeName); }; return ( matches(tab.routeName)), + accessibleTabs.findIndex((tab) => matches(tab.routeName)), 0 )} onChange={navToURL} > - + }> - - - - - + + + + + ); From 0b1bf94e9007a110250fc9eceef5cc9315f1dc35 Mon Sep 17 00:00:00 2001 From: Santosh Preetham S Date: Mon, 14 Oct 2024 14:03:44 +0530 Subject: [PATCH 2/4] Upcoming: [DI-21270] - Addressed the review comments --- .../Alerts/AlertsLanding/AlertsLanding.tsx | 46 +++++----- .../features/CloudPulse/CloudPulseTabs.tsx | 89 +++++++++---------- 2 files changed, 63 insertions(+), 72 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx index c169ee3405e..5a57b9b4b71 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx @@ -3,8 +3,6 @@ import { Redirect, Route, Switch, - matchPath, - useHistory, useLocation, useRouteMatch, } from 'react-router-dom'; @@ -19,30 +17,30 @@ import { AlertDefinitionLanding } from './AlertsDefinitionLanding'; export const AlertsLanding = React.memo(() => { const flags = useFlags(); - const { path } = useRouteMatch(); - const history = useHistory(); - const tabs = [ - { - accessible: flags.aclpAlerting?.alertDefinitions, - routeName: `${path}/definitions`, - title: 'Definitions', - }, - ]; + const { url } = useRouteMatch(); + const { pathname } = useLocation(); + const tabs = React.useMemo( + () => [ + { + accessible: flags.aclpAlerting?.alertDefinitions, + routeName: `${url}/definitions`, + title: 'Definitions', + }, + ], + [url, flags.aclpAlerting] + ); const accessibleTabs = tabs.filter((tab) => tab.accessible); - const location = useLocation(); - const navToURL = (index: number) => { - history.push(accessibleTabs[index].routeName); - }; - const matches = (p: string) => { - return Boolean(matchPath(location.pathname, { exact: false, path: p })); - }; + const activeTabIndex = React.useMemo( + () => + Math.max( + accessibleTabs.findIndex((tab) => pathname.startsWith(tab.routeName)), + 0 + ), + [accessibleTabs, pathname] + ); return ( - - matches(tab.routeName))} - onChange={navToURL} - style={{ width: '100%' }} - > + + ; - -export const CloudPulseTabs = React.memo((props: Props) => { +export const CloudPulseTabs = () => { const flags = useFlags(); - const tabs = [ - { - accessible: true, - routeName: `${props.match.url}/dashboards`, - title: 'Dashboards', - }, - { - accessible: - flags.aclpAlerting?.alertDefinitions || - flags.aclpAlerting?.recentActivity || - flags.aclpAlerting?.notificationChannels, - routeName: `${props.match.url}/alerts`, - title: 'Alerts', - }, - ]; + const { url } = useRouteMatch(); + const { pathname } = useLocation(); + const tabs = React.useMemo( + () => [ + { + accessible: true, + routeName: `${url}/dashboards`, + title: 'Dashboards', + }, + { + accessible: + flags.aclpAlerting?.alertDefinitions || + flags.aclpAlerting?.recentActivity || + flags.aclpAlerting?.notificationChannels, + routeName: `${url}/alerts`, + title: 'Alerts', + }, + ], + [url, flags.aclpAlerting] + ); const accessibleTabs = tabs.filter((tab) => tab.accessible); - const matches = (p: string) => { - return Boolean( - matchPath(props.location.pathname, { exact: false, path: p }) - ); - }; - - const navToURL = (index: number) => { - props.history.push(accessibleTabs[index].routeName); - }; - - return ( - matches(tab.routeName)), + const activeTabIndex = React.useMemo( + () => + Math.max( + accessibleTabs.findIndex((tab) => pathname.startsWith(tab.routeName)), 0 - )} - onChange={navToURL} - > + ), + [accessibleTabs, pathname] + ); + return ( + }> - + { /> - + ); -}); - -const StyledTabs = styled(Tabs, { - label: 'StyledTabs', -})(() => ({ - marginTop: 0, -})); +}; From 4d02c60baadf071a54777e18f554de19cfd3ce02 Mon Sep 17 00:00:00 2001 From: Santosh Preetham S Date: Wed, 16 Oct 2024 21:17:03 +0530 Subject: [PATCH 3/4] Upcoming : [DI:21270] - Added the custom type for the Tab with isEnabled property and memoized the filtering of enabled flags --- .../Alerts/AlertsLanding/AlertsLanding.tsx | 17 ++++++--- .../features/CloudPulse/CloudPulseTabs.tsx | 37 ++++++++++++++----- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx index 5a57b9b4b71..3b835df1c1f 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx @@ -15,21 +15,28 @@ import { useFlags } from 'src/hooks/useFlags'; import { AlertDefinitionLanding } from './AlertsDefinitionLanding'; +import type { EnabledTab } from '../../CloudPulseTabs'; + export const AlertsLanding = React.memo(() => { const flags = useFlags(); const { url } = useRouteMatch(); const { pathname } = useLocation(); - const tabs = React.useMemo( + const tabFlags = React.useMemo( () => [ { - accessible: flags.aclpAlerting?.alertDefinitions, - routeName: `${url}/definitions`, - title: 'Definitions', + isEnabled: Boolean(flags.aclpAlerting?.alertDefinitions), + tab: { routeName: `${url}/definitions`, title: 'Definitions' }, }, ], [url, flags.aclpAlerting] ); - const accessibleTabs = tabs.filter((tab) => tab.accessible); + const accessibleTabs = React.useMemo( + () => + tabFlags + .filter((tabFlag) => tabFlag.isEnabled) + .map((tabFlag) => tabFlag.tab), + [tabFlags] + ); const activeTabIndex = React.useMemo( () => Math.max( diff --git a/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx b/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx index e977e1b4e87..3e56de0cc2b 100644 --- a/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx +++ b/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx @@ -15,29 +15,46 @@ import { useFlags } from 'src/hooks/useFlags'; import { AlertsLanding } from './Alerts/AlertsLanding/AlertsLanding'; import { CloudPulseDashboardLanding } from './Dashboard/CloudPulseDashboardLanding'; +import type { Tab } from 'src/components/Tabs/TabLinkList'; + +export type EnabledTab = { + isEnabled: boolean; + tab: Tab; +}; export const CloudPulseTabs = () => { const flags = useFlags(); const { url } = useRouteMatch(); const { pathname } = useLocation(); - const tabs = React.useMemo( + const tabFlags = React.useMemo( () => [ { - accessible: true, - routeName: `${url}/dashboards`, - title: 'Dashboards', + isEnabled: true, + tab: { + routeName: `${url}/dashboards`, + title: 'Dashboards', + }, }, { - accessible: + isEnabled: Boolean( flags.aclpAlerting?.alertDefinitions || - flags.aclpAlerting?.recentActivity || - flags.aclpAlerting?.notificationChannels, - routeName: `${url}/alerts`, - title: 'Alerts', + flags.aclpAlerting?.recentActivity || + flags.aclpAlerting?.notificationChannels + ), + tab: { + routeName: `${url}/alerts`, + title: 'Alerts', + }, }, ], [url, flags.aclpAlerting] ); - const accessibleTabs = tabs.filter((tab) => tab.accessible); + const accessibleTabs = React.useMemo( + () => + tabFlags + .filter((tabFlag) => tabFlag.isEnabled) + .map((tabFlag) => tabFlag.tab), + [tabFlags] + ); const activeTabIndex = React.useMemo( () => Math.max( From 9700cd0d194ec4cb7ee3ded2a69673167fd5a127 Mon Sep 17 00:00:00 2001 From: Santosh Preetham S Date: Wed, 16 Oct 2024 21:37:46 +0530 Subject: [PATCH 4/4] Upcoming: [DI:21270] - Improved the names for clarity --- .../Alerts/AlertsLanding/AlertsLanding.tsx | 12 ++++++------ .../src/features/CloudPulse/CloudPulseTabs.tsx | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx index 3b835df1c1f..72a1f01c157 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx @@ -15,13 +15,13 @@ import { useFlags } from 'src/hooks/useFlags'; import { AlertDefinitionLanding } from './AlertsDefinitionLanding'; -import type { EnabledTab } from '../../CloudPulseTabs'; +import type { EnabledAlertTab } from '../../CloudPulseTabs'; export const AlertsLanding = React.memo(() => { const flags = useFlags(); const { url } = useRouteMatch(); const { pathname } = useLocation(); - const tabFlags = React.useMemo( + const alertTabs = React.useMemo( () => [ { isEnabled: Boolean(flags.aclpAlerting?.alertDefinitions), @@ -32,10 +32,10 @@ export const AlertsLanding = React.memo(() => { ); const accessibleTabs = React.useMemo( () => - tabFlags - .filter((tabFlag) => tabFlag.isEnabled) - .map((tabFlag) => tabFlag.tab), - [tabFlags] + alertTabs + .filter((alertTab) => alertTab.isEnabled) + .map((alertTab) => alertTab.tab), + [alertTabs] ); const activeTabIndex = React.useMemo( () => diff --git a/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx b/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx index 3e56de0cc2b..418bee1322c 100644 --- a/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx +++ b/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx @@ -17,7 +17,7 @@ import { CloudPulseDashboardLanding } from './Dashboard/CloudPulseDashboardLandi import type { Tab } from 'src/components/Tabs/TabLinkList'; -export type EnabledTab = { +export type EnabledAlertTab = { isEnabled: boolean; tab: Tab; }; @@ -25,7 +25,7 @@ export const CloudPulseTabs = () => { const flags = useFlags(); const { url } = useRouteMatch(); const { pathname } = useLocation(); - const tabFlags = React.useMemo( + const alertTabs = React.useMemo( () => [ { isEnabled: true, @@ -50,10 +50,10 @@ export const CloudPulseTabs = () => { ); const accessibleTabs = React.useMemo( () => - tabFlags - .filter((tabFlag) => tabFlag.isEnabled) - .map((tabFlag) => tabFlag.tab), - [tabFlags] + alertTabs + .filter((alertTab) => alertTab.isEnabled) + .map((alertTab) => alertTab.tab), + [alertTabs] ); const activeTabIndex = React.useMemo( () =>