From adc64d8816b5190f2362e652f0c7219c4f7b76ca Mon Sep 17 00:00:00 2001 From: Josh Slaughter <8338893+jdslaugh@users.noreply.github.com> Date: Thu, 25 Jul 2024 09:58:51 -0700 Subject: [PATCH 01/12] frontend: feature - Adding Application Banner support --- .../packages/core/src/AppLayout/header.tsx | 10 ++ .../packages/core/src/AppProvider/index.tsx | 103 +++++++++++++++++- frontend/packages/core/src/Feedback/alert.tsx | 11 +- 3 files changed, 116 insertions(+), 8 deletions(-) diff --git a/frontend/packages/core/src/AppLayout/header.tsx b/frontend/packages/core/src/AppLayout/header.tsx index 6100e8f403..2e65462ac7 100644 --- a/frontend/packages/core/src/AppLayout/header.tsx +++ b/frontend/packages/core/src/AppLayout/header.tsx @@ -12,6 +12,7 @@ import Notifications from "./notifications"; import SearchField from "./search"; import ShortLinker from "./shortLinker"; import { UserInformation } from "./user"; +import { Alert } from "../Feedback"; export const APP_BAR_HEIGHT = "64px"; @@ -70,6 +71,10 @@ const StyledLogo = styled("img")({ verticalAlign: "middle", }); +const StyledAlert = styled(Alert)({ + padding: "8px 16px 8px 16px", +}); + const Header: React.FC = ({ title = "clutch", logo = , @@ -88,6 +93,11 @@ const Header: React.FC = ({ {typeof logo === "string" ? : logo} {title} + + + This is an alert to test! + + {search && ( diff --git a/frontend/packages/core/src/AppProvider/index.tsx b/frontend/packages/core/src/AppProvider/index.tsx index 9b846577b2..ef8a6b5b1c 100644 --- a/frontend/packages/core/src/AppProvider/index.tsx +++ b/frontend/packages/core/src/AppProvider/index.tsx @@ -20,6 +20,9 @@ import ShortLinkStateHydrator from "./short-link-state-hydrator"; import { Theme } from "./themes"; import type { ConfiguredRoute, Workflow, WorkflowConfiguration } from "./workflow"; import ErrorBoundary from "./workflow"; +import { Alert } from "../Feedback"; +import Grid from "../grid"; +import type { AlertProps } from "../Feedback/alert"; export interface WorkflowIcon { path: string; @@ -32,11 +35,33 @@ export interface UserConfiguration { }; } +interface Banner extends Pick { + message: string; +} + +interface PerWorkflowBanner { + [workflowName: string]: Notification; +} + +interface WorkflowsBanner extends Banner { + workflows: string[]; +} + +interface AppBanners { + /** Will display a notification banner at the top of the application */ + header?: Notification; + /** Allows for setting a notification banner on a per workflow basis */ + perWorkflow?: PerWorkflowBanner; + /** Allows for setting a notification banner across multiple workflows */ + multiWorkflow?: WorkflowsBanner; +} + export interface AppConfiguration { /** Will override the title of the given application */ title?: string; /** Supports a react node or a string representing a public assets path */ logo?: React.ReactNode | string; + banners?: AppBanners; } /** @@ -80,6 +105,49 @@ interface ClutchAppProps { children?: ClutchAppChild | ClutchAppChild[]; } +const LayoutWithNotifications = ({ + children, + config, + workflow, +}: { + children: React.ReactNode; + config: AppConfiguration; + workflow?: string; +}) => { + const { banners: { perWorkflow = {}, multiWorkflow = {} } = {} } = config; + + if (workflow) { + if (Object.keys(perWorkflow).length > 0) { + const foundWorkflow = Object.entries(perWorkflow).find( + ([key]) => key.toLowerCase() === workflow.toLowerCase() + )?.[1]; + + console.log("FOUND", foundWorkflow); + } + // const perWorkflowKeys = Object.keys(perWorkflow) + // .map(key => key.toLowerCase()) + // .filter(key => key === workflow.toLowerCase()); + + // const multiWorkflowKeys = multiWorkflow?.workflows.map(key => key.toLowerCase()); + // console.log(workflow.toLowerCase(), perWorkflow, multiWorkflow); + } + + return ( + <> + {config && config.banners && ( + + + + This is an info alert — check it out! + + + + )} + {children} + + ); +}; + const ClutchApp = ({ availableWorkflows, configuration: userConfiguration, @@ -181,7 +249,17 @@ const ClutchApp = ({ /> } > - {!hasCustomLanding && } />} + {!hasCustomLanding && ( + + + + } + /> + )} {workflows.map((workflow: Workflow) => { const workflowPath = workflow.path.replace(/^\/+/, "").replace(/\/+$/, ""); const workflowKey = workflow.path.split("/")[0]; @@ -208,11 +286,26 @@ const ClutchApp = ({ , { - ...route.componentProps, - heading, - })} + element={ + + {React.cloneElement(, { + ...route.componentProps, + heading, + })} + + } /> + // , { + // ...route.componentProps, + // heading, + // })} + // /> ); })} ( +const StyledAlert = styled(MuiAlert)<{ + $title: MuiAlertProps["title"]; + severity: MuiAlertProps["severity"]; +}>( ({ theme }: { theme: Theme }) => ({ borderRadius: "8px", padding: "16px", @@ -17,6 +20,7 @@ const StyledAlert = styled(MuiAlert)<{ severity: MuiAlertProps["severity"] }>( color: alpha(theme.palette.secondary[900], 0.75), fontSize: "14px", overflow: "auto", + display: "flex", ".MuiAlert-icon": { marginRight: "16px", padding: "0", @@ -40,6 +44,7 @@ const StyledAlert = styled(MuiAlert)<{ severity: MuiAlertProps["severity"] }>( }; return { + ...(props.$title ? {} : { alignItems: "end" }), background: backgroundColors[props.severity], }; } @@ -79,13 +84,13 @@ export const SEVERITIES = Object.keys(iconMappings); export interface AlertProps extends Pick< MuiAlertProps, - "severity" | "action" | "onClose" | "elevation" | "variant" | "icon" + "severity" | "action" | "onClose" | "elevation" | "variant" | "icon" | "className" > { title?: React.ReactNode; } export const Alert: React.FC = ({ severity = "info", title, children, ...props }) => ( - + {title && {title}} {children} From 277f054823dc66f0d98a1085ac3f56511a0e8f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=ADa=20Echenique=20=C3=81lvarez?= Date: Tue, 20 Aug 2024 12:58:25 -0600 Subject: [PATCH 02/12] app notification part 1 --- frontend/packages/app/src/index.jsx | 32 ++++++- .../packages/core/src/AppLayout/header.tsx | 4 +- .../packages/core/src/AppProvider/index.tsx | 85 +------------------ .../src/LayoutWithNotifications/index.tsx | 52 ++++++++++++ frontend/packages/core/src/Types/app.tsx | 9 ++ frontend/packages/core/src/Types/banner.tsx | 32 +++++++ frontend/packages/core/src/Types/index.tsx | 2 + 7 files changed, 130 insertions(+), 86 deletions(-) create mode 100644 frontend/packages/core/src/LayoutWithNotifications/index.tsx create mode 100644 frontend/packages/core/src/Types/app.tsx create mode 100644 frontend/packages/core/src/Types/banner.tsx create mode 100644 frontend/packages/core/src/Types/index.tsx diff --git a/frontend/packages/app/src/index.jsx b/frontend/packages/app/src/index.jsx index de87684055..1f87f97328 100644 --- a/frontend/packages/app/src/index.jsx +++ b/frontend/packages/app/src/index.jsx @@ -8,7 +8,37 @@ import "./index.css"; const config = require("./clutch.config"); +const banners = { + header: { + title: "this is a header banner", + message: "this is message header", + dismissed: false, + }, + perWorkflow: { + Envoy: { + title: "this is a per workout banner fro envoy", + message: "this is message banner fro envoy", + dismissed: false, + }, + K8s: { + title: "this is a per workout banner for k8s", + message: "this is message banner for k8s", + dismissed: false, + }, + }, + multiWorkflow: { + title: "multi title", + message: "message for multi workflow", + dismissed: false, + workflows: ["EC2", "Envoy"], + }, +}; + ReactDOM.render( - , + , document.getElementById("root") ); diff --git a/frontend/packages/core/src/AppLayout/header.tsx b/frontend/packages/core/src/AppLayout/header.tsx index 2e65462ac7..5bdcf64385 100644 --- a/frontend/packages/core/src/AppLayout/header.tsx +++ b/frontend/packages/core/src/AppLayout/header.tsx @@ -3,16 +3,16 @@ import { Link } from "react-router-dom"; import styled from "@emotion/styled"; import { AppBar as MuiAppBar, Box, Grid, Theme, Toolbar, Typography } from "@mui/material"; -import type { AppConfiguration } from "../AppProvider"; +import { Alert } from "../Feedback"; import { FeatureOn, SimpleFeatureFlag } from "../flags"; import { NPSHeader } from "../NPS"; +import type { AppConfiguration } from "../Types"; import Logo from "./logo"; import Notifications from "./notifications"; import SearchField from "./search"; import ShortLinker from "./shortLinker"; import { UserInformation } from "./user"; -import { Alert } from "../Feedback"; export const APP_BAR_HEIGHT = "64px"; diff --git a/frontend/packages/core/src/AppProvider/index.tsx b/frontend/packages/core/src/AppProvider/index.tsx index ef8a6b5b1c..3a93490e10 100644 --- a/frontend/packages/core/src/AppProvider/index.tsx +++ b/frontend/packages/core/src/AppProvider/index.tsx @@ -11,8 +11,10 @@ import type { HydratedData, HydrateState } from "../Contexts/workflow-storage-co import { Toast } from "../Feedback"; import { FEATURE_FLAG_POLL_RATE, featureFlags } from "../flags"; import Landing from "../landing"; +import LayoutWithNotifications from "../LayoutWithNotifications"; import type { ClutchError } from "../Network/errors"; import NotFound from "../not-found"; +import { AppConfiguration } from "../Types"; import { registeredWorkflows } from "./registrar"; import ShortLinkProxy, { ShortLinkBaseRoute } from "./short-link-proxy"; @@ -20,9 +22,6 @@ import ShortLinkStateHydrator from "./short-link-state-hydrator"; import { Theme } from "./themes"; import type { ConfiguredRoute, Workflow, WorkflowConfiguration } from "./workflow"; import ErrorBoundary from "./workflow"; -import { Alert } from "../Feedback"; -import Grid from "../grid"; -import type { AlertProps } from "../Feedback/alert"; export interface WorkflowIcon { path: string; @@ -35,35 +34,6 @@ export interface UserConfiguration { }; } -interface Banner extends Pick { - message: string; -} - -interface PerWorkflowBanner { - [workflowName: string]: Notification; -} - -interface WorkflowsBanner extends Banner { - workflows: string[]; -} - -interface AppBanners { - /** Will display a notification banner at the top of the application */ - header?: Notification; - /** Allows for setting a notification banner on a per workflow basis */ - perWorkflow?: PerWorkflowBanner; - /** Allows for setting a notification banner across multiple workflows */ - multiWorkflow?: WorkflowsBanner; -} - -export interface AppConfiguration { - /** Will override the title of the given application */ - title?: string; - /** Supports a react node or a string representing a public assets path */ - logo?: React.ReactNode | string; - banners?: AppBanners; -} - /** * Filter workflow routes using available feature flags. * @param workflows a list of valid Workflow objects. @@ -105,49 +75,6 @@ interface ClutchAppProps { children?: ClutchAppChild | ClutchAppChild[]; } -const LayoutWithNotifications = ({ - children, - config, - workflow, -}: { - children: React.ReactNode; - config: AppConfiguration; - workflow?: string; -}) => { - const { banners: { perWorkflow = {}, multiWorkflow = {} } = {} } = config; - - if (workflow) { - if (Object.keys(perWorkflow).length > 0) { - const foundWorkflow = Object.entries(perWorkflow).find( - ([key]) => key.toLowerCase() === workflow.toLowerCase() - )?.[1]; - - console.log("FOUND", foundWorkflow); - } - // const perWorkflowKeys = Object.keys(perWorkflow) - // .map(key => key.toLowerCase()) - // .filter(key => key === workflow.toLowerCase()); - - // const multiWorkflowKeys = multiWorkflow?.workflows.map(key => key.toLowerCase()); - // console.log(workflow.toLowerCase(), perWorkflow, multiWorkflow); - } - - return ( - <> - {config && config.banners && ( - - - - This is an info alert — check it out! - - - - )} - {children} - - ); -}; - const ClutchApp = ({ availableWorkflows, configuration: userConfiguration, @@ -298,14 +225,6 @@ const ClutchApp = ({ } /> - // , { - // ...route.componentProps, - // heading, - // })} - // /> ); })} { + const { + banners: { perWorkflow, multiWorkflow }, + } = config; + + const showAlertPerWorkflow = + workflow && perWorkflow[workflow] && !perWorkflow[workflow]?.dismissed; + const showAlertMultiWorkflow = + workflow && multiWorkflow?.workflows.includes(workflow) && !multiWorkflow.dismissed; + + return ( + <> + {config && config.banners && ( + + + {showAlertMultiWorkflow && ( + + {multiWorkflow?.message} + + )} + {showAlertPerWorkflow && ( + + {perWorkflow[workflow]?.message} + + )} + + + )} + {children} + + ); +}; + +export default LayoutWithNotifications; diff --git a/frontend/packages/core/src/Types/app.tsx b/frontend/packages/core/src/Types/app.tsx new file mode 100644 index 0000000000..6c6de3b21b --- /dev/null +++ b/frontend/packages/core/src/Types/app.tsx @@ -0,0 +1,9 @@ +import { AppBanners } from "./banner"; + +export interface AppConfiguration { + /** Will override the title of the given application */ + title?: string; + /** Supports a react node or a string representing a public assets path */ + logo?: React.ReactNode | string; + banners?: AppBanners; +} diff --git a/frontend/packages/core/src/Types/banner.tsx b/frontend/packages/core/src/Types/banner.tsx new file mode 100644 index 0000000000..ce7c81be48 --- /dev/null +++ b/frontend/packages/core/src/Types/banner.tsx @@ -0,0 +1,32 @@ +import type { AlertProps as MuiAlertProps } from "@mui/lab"; + +export interface AlertProps + extends Pick< + MuiAlertProps, + "severity" | "action" | "onClose" | "elevation" | "variant" | "icon" | "className" + > { + title?: React.ReactNode; +} + +export interface Banner extends Pick { + message: string; + dismissed: boolean; + link: string; +} + +export interface PerWorkflowBanner { + [workflowName: string]: Banner; +} + +export interface WorkflowsBanner extends Banner { + workflows: string[]; +} + +export interface AppBanners { + /** Will display a notification banner at the top of the application */ + header?: Banner; + /** Allows for setting a notification banner on a per workflow basis */ + perWorkflow?: PerWorkflowBanner; + /** Allows for setting a notification banner across multiple workflows */ + multiWorkflow?: WorkflowsBanner; +} diff --git a/frontend/packages/core/src/Types/index.tsx b/frontend/packages/core/src/Types/index.tsx new file mode 100644 index 0000000000..909f979201 --- /dev/null +++ b/frontend/packages/core/src/Types/index.tsx @@ -0,0 +1,2 @@ +export * from "./app"; +export * from "./banner"; From 256441061b61fb2fd0b5985a7e5752153f0e1ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=ADa=20Echenique=20=C3=81lvarez?= Date: Wed, 21 Aug 2024 16:37:38 -0600 Subject: [PATCH 03/12] app notifications part 2 --- frontend/packages/app/src/index.jsx | 13 ++- .../packages/core/src/AppLayout/header.tsx | 16 +--- .../packages/core/src/AppLayout/index.tsx | 2 +- .../AppNotifications/HeaderNotification.tsx | 51 +++++++++++ .../LayoutWithNotifications.tsx | 91 +++++++++++++++++++ .../core/src/AppNotifications/index.tsx | 54 +++++++++++ .../useCompareAppNotificationsData.tsx | 75 +++++++++++++++ .../packages/core/src/AppProvider/index.tsx | 20 ++-- .../core/src/Contexts/preferences-context.tsx | 5 + .../src/LayoutWithNotifications/index.tsx | 52 ----------- frontend/packages/core/src/Types/app.tsx | 2 +- frontend/packages/core/src/Types/index.tsx | 2 +- .../Types/{banner.tsx => notification.tsx} | 0 13 files changed, 306 insertions(+), 77 deletions(-) create mode 100644 frontend/packages/core/src/AppNotifications/HeaderNotification.tsx create mode 100644 frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx create mode 100644 frontend/packages/core/src/AppNotifications/index.tsx create mode 100644 frontend/packages/core/src/AppNotifications/useCompareAppNotificationsData.tsx delete mode 100644 frontend/packages/core/src/LayoutWithNotifications/index.tsx rename frontend/packages/core/src/Types/{banner.tsx => notification.tsx} (100%) diff --git a/frontend/packages/app/src/index.jsx b/frontend/packages/app/src/index.jsx index 1f87f97328..37ef703c56 100644 --- a/frontend/packages/app/src/index.jsx +++ b/frontend/packages/app/src/index.jsx @@ -12,25 +12,30 @@ const banners = { header: { title: "this is a header banner", message: "this is message header", - dismissed: false, + link: "localhost:3000", }, perWorkflow: { Envoy: { title: "this is a per workout banner fro envoy", message: "this is message banner fro envoy", - dismissed: false, + link: "localhost:3000", }, K8s: { title: "this is a per workout banner for k8s", message: "this is message banner for k8s", - dismissed: false, + link: "localhost:3000", + }, + test: { + title: "this is a per workout banner for test", + message: "this is message banner for test", + link: "localhost:3000", }, }, multiWorkflow: { title: "multi title", message: "message for multi workflow", - dismissed: false, workflows: ["EC2", "Envoy"], + link: "localhost:3000", }, }; diff --git a/frontend/packages/core/src/AppLayout/header.tsx b/frontend/packages/core/src/AppLayout/header.tsx index 5bdcf64385..b23a7ad805 100644 --- a/frontend/packages/core/src/AppLayout/header.tsx +++ b/frontend/packages/core/src/AppLayout/header.tsx @@ -3,10 +3,10 @@ import { Link } from "react-router-dom"; import styled from "@emotion/styled"; import { AppBar as MuiAppBar, Box, Grid, Theme, Toolbar, Typography } from "@mui/material"; -import { Alert } from "../Feedback"; +import AppNotification from "../AppNotifications"; import { FeatureOn, SimpleFeatureFlag } from "../flags"; import { NPSHeader } from "../NPS"; -import type { AppConfiguration } from "../Types"; +import type { AppBanners, AppConfiguration } from "../Types"; import Logo from "./logo"; import Notifications from "./notifications"; @@ -44,6 +44,7 @@ interface HeaderProps extends AppConfiguration { * Will enable the user information component in the header */ userInfo?: boolean; + banners?: AppBanners; } const AppBar = styled(MuiAppBar)(({ theme }: { theme: Theme }) => ({ @@ -71,13 +72,10 @@ const StyledLogo = styled("img")({ verticalAlign: "middle", }); -const StyledAlert = styled(Alert)({ - padding: "8px 16px 8px 16px", -}); - const Header: React.FC = ({ title = "clutch", logo = , + banners, enableNPS = false, search = true, feedback = true, @@ -93,11 +91,7 @@ const Header: React.FC = ({ {typeof logo === "string" ? : logo} {title} - - - This is an alert to test! - - + {search && ( diff --git a/frontend/packages/core/src/AppLayout/index.tsx b/frontend/packages/core/src/AppLayout/index.tsx index 96487bf10a..4510e13e53 100644 --- a/frontend/packages/core/src/AppLayout/index.tsx +++ b/frontend/packages/core/src/AppLayout/index.tsx @@ -3,8 +3,8 @@ import { Outlet } from "react-router-dom"; import styled from "@emotion/styled"; import { Grid as MuiGrid } from "@mui/material"; -import type { AppConfiguration } from "../AppProvider"; import Loadable from "../loading"; +import type { AppConfiguration } from "../Types"; import Drawer from "./drawer"; import Header, { APP_BAR_HEIGHT } from "./header"; diff --git a/frontend/packages/core/src/AppNotifications/HeaderNotification.tsx b/frontend/packages/core/src/AppNotifications/HeaderNotification.tsx new file mode 100644 index 0000000000..d57d162224 --- /dev/null +++ b/frontend/packages/core/src/AppNotifications/HeaderNotification.tsx @@ -0,0 +1,51 @@ +import React from "react"; +import styled from "@emotion/styled"; +import isEmpty from "lodash/isEmpty"; + +import { Alert } from "../Feedback"; +import Grid from "../grid"; +import { Link as LinkComponent } from "../link"; +import type { AppBanners } from "../Types"; + +const StyledAlert = styled(Alert)({ + padding: "8px 16px 8px 16px", +}); + +interface HeaderNotificationProps { + bannersData: AppBanners; + onDismissAlert: (updatedData: AppBanners) => void; +} + +const HeaderNotification = ({ bannersData, onDismissAlert }: HeaderNotificationProps) => { + const headerBannerData = bannersData?.header; + + const onDismissAlertHeader = () => { + onDismissAlert({ + ...bannersData, + header: { + ...headerBannerData, + dismissed: true, + }, + }); + }; + + return ( + <> + {!isEmpty(headerBannerData) && !headerBannerData?.dismissed && ( + + + {headerBannerData?.message} + {headerBannerData?.link && {headerBannerData?.link}} + + + )} + + ); +}; + +export default HeaderNotification; diff --git a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx new file mode 100644 index 0000000000..7adfec013a --- /dev/null +++ b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx @@ -0,0 +1,91 @@ +import React from "react"; +import isEmpty from "lodash/isEmpty"; + +import { Alert } from "../Feedback"; +import Grid from "../grid"; +import { Link as LinkComponent } from "../link"; +import type { AppBanners } from "../Types"; + +interface LayoutWithNotificationsProps { + bannersData: AppBanners; + onDismissAlert: (updatedData: AppBanners) => void; + children: React.ReactNode; + workflow?: string; +} + +const LayoutWithNotifications = ({ + bannersData, + onDismissAlert, + children, + workflow, +}: LayoutWithNotificationsProps) => { + const perWorkflowData = bannersData?.perWorkflow; + const multiWorkflowData = bannersData?.multiWorkflow; + + const showAlertPerWorkflow = + workflow && perWorkflowData[workflow] && !perWorkflowData[workflow]?.dismissed; + const showAlertMultiWorkflow = + workflow && multiWorkflowData?.workflows?.includes(workflow) && !multiWorkflowData?.dismissed; + + const onDismissAlertPerWorkflow = () => { + onDismissAlert({ + ...bannersData, + perWorkflow: { + ...perWorkflowData, + [workflow]: { ...perWorkflowData[workflow], dismissed: true }, + }, + }); + }; + + const onDismissAlertMultiWorkflow = () => { + onDismissAlert({ + ...bannersData, + multiWorkflow: { + ...multiWorkflowData, + dismissed: true, + }, + }); + }; + + const showContainer = !isEmpty(perWorkflowData) || !isEmpty(multiWorkflowData); + + return ( + <> + {showContainer && ( + + + {showAlertMultiWorkflow && ( + + {multiWorkflowData?.message} + {multiWorkflowData?.link && ( + {multiWorkflowData?.link} + )} + + )} + {showAlertPerWorkflow && ( + + {perWorkflowData[workflow]?.message} + {perWorkflowData[workflow]?.link && ( + {perWorkflowData[workflow]?.link} + )} + + )} + + + )} + {children} + + ); +}; + +export default LayoutWithNotifications; diff --git a/frontend/packages/core/src/AppNotifications/index.tsx b/frontend/packages/core/src/AppNotifications/index.tsx new file mode 100644 index 0000000000..1d2b5abc8e --- /dev/null +++ b/frontend/packages/core/src/AppNotifications/index.tsx @@ -0,0 +1,54 @@ +import React, { useEffect } from "react"; + +import type { AppBanners } from "../Types"; + +import HeaderNotification from "./HeaderNotification"; +import LayoutWithNotifications from "./LayoutWithNotifications"; +import compareAppNotificationsData from "./useCompareAppNotificationsData"; + +interface AppNotificationProps { + type: "header" | "layout"; + banners: AppBanners; + workflow?: string; + children?: React.ReactNode; +} + +const AppNotification = ({ type, banners, children, workflow }: AppNotificationProps) => { + const { shouldUpdate, bannersData, dispatch } = compareAppNotificationsData(banners); + + useEffect(() => { + if (shouldUpdate) { + dispatch({ + type: "SetPref", + payload: { + key: "banners", + value: bannersData, + }, + }); + } + }, [shouldUpdate]); + + const onDismissAlert = (updatedData: AppBanners) => { + dispatch({ + type: "SetPref", + payload: { + key: "banners", + value: updatedData, + }, + }); + }; + + return type === "header" ? ( + + ) : ( + + {children} + + ); +}; + +export default AppNotification; diff --git a/frontend/packages/core/src/AppNotifications/useCompareAppNotificationsData.tsx b/frontend/packages/core/src/AppNotifications/useCompareAppNotificationsData.tsx new file mode 100644 index 0000000000..74c0a02245 --- /dev/null +++ b/frontend/packages/core/src/AppNotifications/useCompareAppNotificationsData.tsx @@ -0,0 +1,75 @@ +import get from "lodash/get"; +import isEmpty from "lodash/isEmpty"; +import isEqual from "lodash/isEqual"; + +import { useUserPreferences } from "../Contexts/preferences-context"; +import type { AppBanners } from "../Types"; + +const useCompareAppNotificationsData = (banners: AppBanners) => { + const { preferences, dispatch } = useUserPreferences(); + const bannersPreferences: AppBanners = get(preferences, "banners"); + + const bannersData = { + header: {}, + multiWorkflow: {}, + perWorkflow: {}, + }; + let shouldUpdate = false; + + if (!isEmpty(banners?.header)) { + const headerPreferences = { + title: bannersPreferences?.header?.title, + message: bannersPreferences?.header?.message, + link: bannersPreferences?.header.link, + }; + + if (!isEqual(banners?.header, headerPreferences)) { + bannersData.header = { ...banners?.header, dismissed: false }; + shouldUpdate = true; + } else { + bannersData.header = { ...bannersPreferences?.header }; + } + } + + if (!isEmpty(banners?.multiWorkflow)) { + const multiWorkflowPreferences = { + title: bannersPreferences?.multiWorkflow?.title, + message: bannersPreferences?.multiWorkflow?.message, + workflows: bannersPreferences?.multiWorkflow.workflows, + link: bannersPreferences?.multiWorkflow.link, + }; + + if (!isEqual(banners?.multiWorkflow, multiWorkflowPreferences)) { + bannersData.multiWorkflow = { ...banners?.multiWorkflow, dismissed: false }; + shouldUpdate = true; + } else { + bannersData.multiWorkflow = { ...bannersPreferences?.multiWorkflow }; + } + } + + if (!isEmpty(banners?.perWorkflow)) { + Object.keys(banners?.perWorkflow).forEach(key => { + if (bannersPreferences?.perWorkflow?.[key]) { + const perWorkflowPreferences = { + title: bannersPreferences?.perWorkflow?.[key]?.title, + message: bannersPreferences?.perWorkflow?.[key]?.message, + link: bannersPreferences?.perWorkflow?.[key].link, + }; + + if (!isEqual(banners?.perWorkflow?.[key], perWorkflowPreferences)) { + bannersData.perWorkflow[key] = { ...banners?.perWorkflow?.[key], dismissed: false }; + shouldUpdate = true; + } else { + bannersData.perWorkflow[key] = bannersPreferences?.perWorkflow?.[key]; + } + } else { + bannersData.perWorkflow[key] = { ...banners?.perWorkflow?.[key], dismissed: false }; + shouldUpdate = true; + } + }); + } + + return { shouldUpdate, bannersData, dispatch }; +}; + +export default useCompareAppNotificationsData; diff --git a/frontend/packages/core/src/AppProvider/index.tsx b/frontend/packages/core/src/AppProvider/index.tsx index 3a93490e10..39595f623a 100644 --- a/frontend/packages/core/src/AppProvider/index.tsx +++ b/frontend/packages/core/src/AppProvider/index.tsx @@ -4,6 +4,7 @@ import Bugsnag from "@bugsnag/js"; import BugsnagPluginReact from "@bugsnag/plugin-react"; import AppLayout from "../AppLayout"; +import AppNotification from "../AppNotifications"; import { ApplicationContext, ShortLinkContext, UserPreferencesProvider } from "../Contexts"; import type { HeaderItem, TriggeredHeaderData } from "../Contexts/app-context"; import type { ShortLinkContextProps } from "../Contexts/short-link-context"; @@ -11,10 +12,9 @@ import type { HydratedData, HydrateState } from "../Contexts/workflow-storage-co import { Toast } from "../Feedback"; import { FEATURE_FLAG_POLL_RATE, featureFlags } from "../flags"; import Landing from "../landing"; -import LayoutWithNotifications from "../LayoutWithNotifications"; import type { ClutchError } from "../Network/errors"; import NotFound from "../not-found"; -import { AppConfiguration } from "../Types"; +import type { AppConfiguration } from "../Types"; import { registeredWorkflows } from "./registrar"; import ShortLinkProxy, { ShortLinkBaseRoute } from "./short-link-proxy"; @@ -103,6 +103,7 @@ const ClutchApp = ({ React.useEffect(() => { loadWorkflows(); const interval = setInterval(loadWorkflows, FEATURE_FLAG_POLL_RATE); + return () => clearInterval(interval); }, []); @@ -181,9 +182,13 @@ const ClutchApp = ({ key="landing" path="" element={ - + - + } /> )} @@ -214,15 +219,16 @@ const ClutchApp = ({ key={workflow.path} path={`${route.path.replace(/^\/+/, "").replace(/\/+$/, "")}`} element={ - {React.cloneElement(, { ...route.componentProps, heading, })} - + } /> ); diff --git a/frontend/packages/core/src/Contexts/preferences-context.tsx b/frontend/packages/core/src/Contexts/preferences-context.tsx index b582b93ea6..7f2e7a6964 100644 --- a/frontend/packages/core/src/Contexts/preferences-context.tsx +++ b/frontend/packages/core/src/Contexts/preferences-context.tsx @@ -9,6 +9,11 @@ type Dispatch = (action: Action) => void; type UserPreferencesProviderProps = { children: React.ReactNode }; const DEFAULT_PREFERENCES: State = { timeFormat: "UTC", + banners: { + header: {}, + multiWorkflow: {}, + perWorkflow: {}, + }, } as any; interface ContextProps { preferences: State; diff --git a/frontend/packages/core/src/LayoutWithNotifications/index.tsx b/frontend/packages/core/src/LayoutWithNotifications/index.tsx deleted file mode 100644 index 07221de63d..0000000000 --- a/frontend/packages/core/src/LayoutWithNotifications/index.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React from "react"; - -import { Alert } from "../Feedback"; -import Grid from "../grid"; -import type { AppConfiguration } from "../Types"; - -const LayoutWithNotifications = ({ - children, - config, - workflow, -}: { - children: React.ReactNode; - config: AppConfiguration; - workflow?: string; -}) => { - const { - banners: { perWorkflow, multiWorkflow }, - } = config; - - const showAlertPerWorkflow = - workflow && perWorkflow[workflow] && !perWorkflow[workflow]?.dismissed; - const showAlertMultiWorkflow = - workflow && multiWorkflow?.workflows.includes(workflow) && !multiWorkflow.dismissed; - - return ( - <> - {config && config.banners && ( - - - {showAlertMultiWorkflow && ( - - {multiWorkflow?.message} - - )} - {showAlertPerWorkflow && ( - - {perWorkflow[workflow]?.message} - - )} - - - )} - {children} - - ); -}; - -export default LayoutWithNotifications; diff --git a/frontend/packages/core/src/Types/app.tsx b/frontend/packages/core/src/Types/app.tsx index 6c6de3b21b..67443716ea 100644 --- a/frontend/packages/core/src/Types/app.tsx +++ b/frontend/packages/core/src/Types/app.tsx @@ -1,4 +1,4 @@ -import { AppBanners } from "./banner"; +import type { AppBanners } from "./notification"; export interface AppConfiguration { /** Will override the title of the given application */ diff --git a/frontend/packages/core/src/Types/index.tsx b/frontend/packages/core/src/Types/index.tsx index 909f979201..773b780fd4 100644 --- a/frontend/packages/core/src/Types/index.tsx +++ b/frontend/packages/core/src/Types/index.tsx @@ -1,2 +1,2 @@ export * from "./app"; -export * from "./banner"; +export * from "./notification"; diff --git a/frontend/packages/core/src/Types/banner.tsx b/frontend/packages/core/src/Types/notification.tsx similarity index 100% rename from frontend/packages/core/src/Types/banner.tsx rename to frontend/packages/core/src/Types/notification.tsx From 016adf6e08c066cf430fdd38be38deede3111755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=ADa=20Echenique=20=C3=81lvarez?= Date: Mon, 26 Aug 2024 14:13:25 -0600 Subject: [PATCH 04/12] small update --- frontend/packages/app/src/index.jsx | 21 ++++++------ .../core/src/AppLayout/tests/layout.test.tsx | 9 ++++++ .../AppNotifications/HeaderNotification.tsx | 8 +++-- .../LayoutWithNotifications.tsx | 32 +++++++++++-------- .../packages/core/src/Types/notification.tsx | 3 +- 5 files changed, 47 insertions(+), 26 deletions(-) diff --git a/frontend/packages/app/src/index.jsx b/frontend/packages/app/src/index.jsx index 37ef703c56..9b576098f7 100644 --- a/frontend/packages/app/src/index.jsx +++ b/frontend/packages/app/src/index.jsx @@ -12,30 +12,33 @@ const banners = { header: { title: "this is a header banner", message: "this is message header", - link: "localhost:3000", + linkText: "infra docs", + link: "https://infradocs.lyft.net/index.html", + severity: "error", }, perWorkflow: { Envoy: { title: "this is a per workout banner fro envoy", message: "this is message banner fro envoy", - link: "localhost:3000", + linkText: "infra docs", + link: "https://infradocs.lyft.net/index.html", + severity: "success", }, K8s: { title: "this is a per workout banner for k8s", message: "this is message banner for k8s", - link: "localhost:3000", - }, - test: { - title: "this is a per workout banner for test", - message: "this is message banner for test", - link: "localhost:3000", + linkText: "infra docs", + link: "https://infradocs.lyft.net/index.html", + severity: "warning", }, }, multiWorkflow: { title: "multi title", message: "message for multi workflow", workflows: ["EC2", "Envoy"], - link: "localhost:3000", + severity: "info", + linkText: "infra docs", + link: "https://infradocs.lyft.net/index.html", }, }; diff --git a/frontend/packages/core/src/AppLayout/tests/layout.test.tsx b/frontend/packages/core/src/AppLayout/tests/layout.test.tsx index 353f75ad34..f863843357 100644 --- a/frontend/packages/core/src/AppLayout/tests/layout.test.tsx +++ b/frontend/packages/core/src/AppLayout/tests/layout.test.tsx @@ -5,11 +5,20 @@ import { render, waitFor } from "@testing-library/react"; import "@testing-library/jest-dom"; import * as appContext from "../../Contexts/app-context"; +import * as preferencesContext from "../../Contexts/preferences-context"; import { client } from "../../Network"; import { ThemeProvider } from "../../Theme"; import AppLayout from ".."; jest.spyOn(appContext, "useAppContext").mockReturnValue({ workflows: [] }); +jest.spyOn(preferencesContext, "useUserPreferences").mockReturnValue({ + timeFormat: "UTC", + banners: { + header: {}, + multiWorkflow: {}, + perWorkflow: {}, + }, +}); jest.spyOn(client, "post").mockReturnValue( new Promise((resolve, reject) => { resolve({ diff --git a/frontend/packages/core/src/AppNotifications/HeaderNotification.tsx b/frontend/packages/core/src/AppNotifications/HeaderNotification.tsx index d57d162224..447e50cf07 100644 --- a/frontend/packages/core/src/AppNotifications/HeaderNotification.tsx +++ b/frontend/packages/core/src/AppNotifications/HeaderNotification.tsx @@ -32,7 +32,7 @@ const HeaderNotification = ({ bannersData, onDismissAlert }: HeaderNotificationP return ( <> {!isEmpty(headerBannerData) && !headerBannerData?.dismissed && ( - + {headerBannerData?.message} - {headerBannerData?.link && {headerBannerData?.link}} + {headerBannerData?.link && headerBannerData?.linkText && ( + + {headerBannerData?.linkText} + + )} )} diff --git a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx index 7adfec013a..733c07bc93 100644 --- a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx +++ b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx @@ -54,29 +54,33 @@ const LayoutWithNotifications = ({ {showContainer && ( - {showAlertMultiWorkflow && ( + {showAlertPerWorkflow && ( - {multiWorkflowData?.message} - {multiWorkflowData?.link && ( - {multiWorkflowData?.link} + {perWorkflowData[workflow]?.message} + {perWorkflowData[workflow]?.link && perWorkflowData[workflow]?.linkText && ( + + {perWorkflowData[workflow]?.linkText} + )} )} - {showAlertPerWorkflow && ( + {showAlertMultiWorkflow && !showAlertPerWorkflow && ( - {perWorkflowData[workflow]?.message} - {perWorkflowData[workflow]?.link && ( - {perWorkflowData[workflow]?.link} + {multiWorkflowData?.message} + {multiWorkflowData?.link && multiWorkflowData?.linkText && ( + + {multiWorkflowData?.linkText} + )} )} diff --git a/frontend/packages/core/src/Types/notification.tsx b/frontend/packages/core/src/Types/notification.tsx index ce7c81be48..add3dddd3b 100644 --- a/frontend/packages/core/src/Types/notification.tsx +++ b/frontend/packages/core/src/Types/notification.tsx @@ -11,7 +11,8 @@ export interface AlertProps export interface Banner extends Pick { message: string; dismissed: boolean; - link: string; + linkText?: string; + link?: string; } export interface PerWorkflowBanner { From bee350b0c5f25c47a25110d44214f1c4c2552cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=ADa=20Echenique=20=C3=81lvarez?= Date: Mon, 26 Aug 2024 14:50:48 -0600 Subject: [PATCH 05/12] small update --- frontend/packages/app/src/index.jsx | 1 - .../AppNotifications/HeaderNotification.tsx | 35 ++++++++++++++----- .../LayoutWithNotifications.tsx | 10 ++++-- .../useCompareAppNotificationsData.tsx | 7 +++- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/frontend/packages/app/src/index.jsx b/frontend/packages/app/src/index.jsx index 9b576098f7..1195d61a29 100644 --- a/frontend/packages/app/src/index.jsx +++ b/frontend/packages/app/src/index.jsx @@ -10,7 +10,6 @@ const config = require("./clutch.config"); const banners = { header: { - title: "this is a header banner", message: "this is message header", linkText: "infra docs", link: "https://infradocs.lyft.net/index.html", diff --git a/frontend/packages/core/src/AppNotifications/HeaderNotification.tsx b/frontend/packages/core/src/AppNotifications/HeaderNotification.tsx index 447e50cf07..fd27fb0dba 100644 --- a/frontend/packages/core/src/AppNotifications/HeaderNotification.tsx +++ b/frontend/packages/core/src/AppNotifications/HeaderNotification.tsx @@ -9,6 +9,22 @@ import type { AppBanners } from "../Types"; const StyledAlert = styled(Alert)({ padding: "8px 16px 8px 16px", + justifyContent: "center", + alignItems: "center", +}); + +const StyledAlertContent = styled.div({ + display: "flex", +}); + +const StyledMessage = styled.div({ + flexWrap: "wrap", + maxHeight: "40px", + overflowY: "auto", +}); + +const StyledLink = styled.div({ + marginLeft: "10px", }); interface HeaderNotificationProps { @@ -34,17 +50,20 @@ const HeaderNotification = ({ bannersData, onDismissAlert }: HeaderNotificationP {!isEmpty(headerBannerData) && !headerBannerData?.dismissed && ( - {headerBannerData?.message} - {headerBannerData?.link && headerBannerData?.linkText && ( - - {headerBannerData?.linkText} - - )} + + {headerBannerData.message} + {headerBannerData?.link && headerBannerData?.linkText && ( + + + {headerBannerData?.linkText} + + + )} + )} diff --git a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx index 733c07bc93..578e7b4a73 100644 --- a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx +++ b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx @@ -25,7 +25,11 @@ const LayoutWithNotifications = ({ const showAlertPerWorkflow = workflow && perWorkflowData[workflow] && !perWorkflowData[workflow]?.dismissed; const showAlertMultiWorkflow = - workflow && multiWorkflowData?.workflows?.includes(workflow) && !multiWorkflowData?.dismissed; + showAlertPerWorkflow || perWorkflowData[workflow]?.dismissed + ? false + : workflow && + multiWorkflowData?.workflows?.includes(workflow) && + !multiWorkflowData?.dismissed; const onDismissAlertPerWorkflow = () => { onDismissAlert({ @@ -56,7 +60,7 @@ const LayoutWithNotifications = ({ {showAlertPerWorkflow && ( { if (!isEmpty(banners?.header)) { const headerPreferences = { - title: bannersPreferences?.header?.title, message: bannersPreferences?.header?.message, + linkText: bannersPreferences?.header.linkText, link: bannersPreferences?.header.link, + severity: bannersPreferences?.header.severity, }; if (!isEqual(banners?.header, headerPreferences)) { @@ -37,6 +38,8 @@ const useCompareAppNotificationsData = (banners: AppBanners) => { message: bannersPreferences?.multiWorkflow?.message, workflows: bannersPreferences?.multiWorkflow.workflows, link: bannersPreferences?.multiWorkflow.link, + linkText: bannersPreferences?.multiWorkflow.linkText, + severity: bannersPreferences?.multiWorkflow.severity, }; if (!isEqual(banners?.multiWorkflow, multiWorkflowPreferences)) { @@ -53,7 +56,9 @@ const useCompareAppNotificationsData = (banners: AppBanners) => { const perWorkflowPreferences = { title: bannersPreferences?.perWorkflow?.[key]?.title, message: bannersPreferences?.perWorkflow?.[key]?.message, + linkText: bannersPreferences?.perWorkflow?.[key].linkText, link: bannersPreferences?.perWorkflow?.[key].link, + severity: bannersPreferences?.perWorkflow?.[key].severity, }; if (!isEqual(banners?.perWorkflow?.[key], perWorkflowPreferences)) { From 6a586a3999b86cb1a5781faa3fb5985c4230939e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=ADa=20Echenique=20=C3=81lvarez?= Date: Mon, 26 Aug 2024 15:29:40 -0600 Subject: [PATCH 06/12] small update --- frontend/packages/app/src/index.jsx | 39 +---------------------------- 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/frontend/packages/app/src/index.jsx b/frontend/packages/app/src/index.jsx index 1195d61a29..de87684055 100644 --- a/frontend/packages/app/src/index.jsx +++ b/frontend/packages/app/src/index.jsx @@ -8,44 +8,7 @@ import "./index.css"; const config = require("./clutch.config"); -const banners = { - header: { - message: "this is message header", - linkText: "infra docs", - link: "https://infradocs.lyft.net/index.html", - severity: "error", - }, - perWorkflow: { - Envoy: { - title: "this is a per workout banner fro envoy", - message: "this is message banner fro envoy", - linkText: "infra docs", - link: "https://infradocs.lyft.net/index.html", - severity: "success", - }, - K8s: { - title: "this is a per workout banner for k8s", - message: "this is message banner for k8s", - linkText: "infra docs", - link: "https://infradocs.lyft.net/index.html", - severity: "warning", - }, - }, - multiWorkflow: { - title: "multi title", - message: "message for multi workflow", - workflows: ["EC2", "Envoy"], - severity: "info", - linkText: "infra docs", - link: "https://infradocs.lyft.net/index.html", - }, -}; - ReactDOM.render( - , + , document.getElementById("root") ); From 4380060d5b3b04f1d90463c9e4b8a07961b0af8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=ADa=20Echenique=20=C3=81lvarez?= Date: Tue, 3 Sep 2024 15:25:41 -0600 Subject: [PATCH 07/12] add paths for banner per workflow --- .../src/AppNotifications/LayoutWithNotifications.tsx | 9 ++++++++- .../AppNotifications/useCompareAppNotificationsData.tsx | 1 + frontend/packages/core/src/Types/notification.tsx | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx index 578e7b4a73..8dba1de336 100644 --- a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx +++ b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useLocation } from "react-router-dom"; import isEmpty from "lodash/isEmpty"; import { Alert } from "../Feedback"; @@ -22,8 +23,14 @@ const LayoutWithNotifications = ({ const perWorkflowData = bannersData?.perWorkflow; const multiWorkflowData = bannersData?.multiWorkflow; - const showAlertPerWorkflow = + const location = useLocation(); + + const hasPerWorkflowAlert = workflow && perWorkflowData[workflow] && !perWorkflowData[workflow]?.dismissed; + const showAlertPerWorkflow = !isEmpty(perWorkflowData[workflow]?.paths) + ? hasPerWorkflowAlert && perWorkflowData[workflow]?.paths?.includes(location.pathname) + : hasPerWorkflowAlert; + const showAlertMultiWorkflow = showAlertPerWorkflow || perWorkflowData[workflow]?.dismissed ? false diff --git a/frontend/packages/core/src/AppNotifications/useCompareAppNotificationsData.tsx b/frontend/packages/core/src/AppNotifications/useCompareAppNotificationsData.tsx index c87df15e48..e22c692cda 100644 --- a/frontend/packages/core/src/AppNotifications/useCompareAppNotificationsData.tsx +++ b/frontend/packages/core/src/AppNotifications/useCompareAppNotificationsData.tsx @@ -59,6 +59,7 @@ const useCompareAppNotificationsData = (banners: AppBanners) => { linkText: bannersPreferences?.perWorkflow?.[key].linkText, link: bannersPreferences?.perWorkflow?.[key].link, severity: bannersPreferences?.perWorkflow?.[key].severity, + paths: bannersPreferences?.perWorkflow?.[key].paths, }; if (!isEqual(banners?.perWorkflow?.[key], perWorkflowPreferences)) { diff --git a/frontend/packages/core/src/Types/notification.tsx b/frontend/packages/core/src/Types/notification.tsx index add3dddd3b..e0caedbd21 100644 --- a/frontend/packages/core/src/Types/notification.tsx +++ b/frontend/packages/core/src/Types/notification.tsx @@ -13,6 +13,7 @@ export interface Banner extends Pick { dismissed: boolean; linkText?: string; link?: string; + paths?: string[]; } export interface PerWorkflowBanner { From d69e1717185d0b239601a6a53447bf3afcc7819b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=ADa=20Echenique=20=C3=81lvarez?= Date: Fri, 6 Sep 2024 13:29:50 -0600 Subject: [PATCH 08/12] removing unwanted changes --- .../reboot-instance.test.tsx.snap | 20 +-- .../__snapshots__/resize-asg.test.tsx.snap | 20 +-- .../terminate-instance.test.tsx.snap | 120 ++++++++---------- .../__snapshots__/remote-triage.test.tsx.snap | 120 ++++++++++-------- .../__snapshots__/delete-pod.test.tsx.snap | 20 +-- .../__snapshots__/resize-hpa.test.tsx.snap | 20 +-- .../scale-resources.test.tsx.snap | 18 +-- 7 files changed, 169 insertions(+), 169 deletions(-) diff --git a/frontend/workflows/ec2/src/tests/__snapshots__/reboot-instance.test.tsx.snap b/frontend/workflows/ec2/src/tests/__snapshots__/reboot-instance.test.tsx.snap index fbdb53f202..0d27a7fda2 100644 --- a/frontend/workflows/ec2/src/tests/__snapshots__/reboot-instance.test.tsx.snap +++ b/frontend/workflows/ec2/src/tests/__snapshots__/reboot-instance.test.tsx.snap @@ -3,19 +3,19 @@ exports[`renders correctly 1`] = `
- Verify + Modify @@ -112,7 +112,7 @@ exports[`renders correctly 1`] = `
- Modify + Verify @@ -112,7 +112,7 @@ exports[`renders correctly 1`] = `
- Verify - - - -
-
-
- -
- - -
-
- 3 -
-
-
- - - Result + Details
@@ -140,30 +100,60 @@ exports[`renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 css-1lwj3w1-MuiGrid-root" >
- - + IP Address + +
- - - + +
+
+
+ +
- Details + Verify + + + +
+
+
+ +
+ + +
+
+ 3 +
+
+
+ + + Result
@@ -100,60 +140,30 @@ exports[`renders correctly 1`] = ` class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 css-1lwj3w1-MuiGrid-root" >
-
- -
- - -
-
-
- -
+ +
- Verify + Modify @@ -112,7 +112,7 @@ exports[`renders correctly 1`] = `
- Modify + Verify @@ -112,7 +112,7 @@ exports[`renders correctly 1`] = `
Date: Fri, 6 Sep 2024 13:34:02 -0600 Subject: [PATCH 09/12] removing unwanted changes --- .../reboot-instance.test.tsx.snap | 2 +- .../__snapshots__/resize-asg.test.tsx.snap | 2 +- .../terminate-instance.test.tsx.snap | 104 ++++++++++-------- .../__snapshots__/remote-triage.test.tsx.snap | 104 ++++++++---------- .../__snapshots__/delete-pod.test.tsx.snap | 2 +- .../__snapshots__/resize-hpa.test.tsx.snap | 2 +- 6 files changed, 108 insertions(+), 108 deletions(-) diff --git a/frontend/workflows/ec2/src/tests/__snapshots__/reboot-instance.test.tsx.snap b/frontend/workflows/ec2/src/tests/__snapshots__/reboot-instance.test.tsx.snap index 0d27a7fda2..38d61b7ec5 100644 --- a/frontend/workflows/ec2/src/tests/__snapshots__/reboot-instance.test.tsx.snap +++ b/frontend/workflows/ec2/src/tests/__snapshots__/reboot-instance.test.tsx.snap @@ -88,7 +88,7 @@ exports[`renders correctly 1`] = ` - Modify + Verify diff --git a/frontend/workflows/ec2/src/tests/__snapshots__/resize-asg.test.tsx.snap b/frontend/workflows/ec2/src/tests/__snapshots__/resize-asg.test.tsx.snap index 38d61b7ec5..0d27a7fda2 100644 --- a/frontend/workflows/ec2/src/tests/__snapshots__/resize-asg.test.tsx.snap +++ b/frontend/workflows/ec2/src/tests/__snapshots__/resize-asg.test.tsx.snap @@ -88,7 +88,7 @@ exports[`renders correctly 1`] = ` - Verify + Modify diff --git a/frontend/workflows/ec2/src/tests/__snapshots__/terminate-instance.test.tsx.snap b/frontend/workflows/ec2/src/tests/__snapshots__/terminate-instance.test.tsx.snap index 4acc3c0d26..38d61b7ec5 100644 --- a/frontend/workflows/ec2/src/tests/__snapshots__/terminate-instance.test.tsx.snap +++ b/frontend/workflows/ec2/src/tests/__snapshots__/terminate-instance.test.tsx.snap @@ -88,7 +88,47 @@ exports[`renders correctly 1`] = ` - Details + Verify + + + +
+
+
+ +
+ + +
+
+ 3 +
+
+
+ + + Result
@@ -105,55 +145,25 @@ exports[`renders correctly 1`] = `
-
- -
- - -
-
-
- -
+ +
- Verify - - - -
-
-
- -
- - -
-
- 3 -
-
-
- - - Result + Details
@@ -145,25 +105,55 @@ exports[`renders correctly 1`] = `
- - + IP Address + +
- - - + +
+
+
+ +
- Modify + Verify diff --git a/frontend/workflows/k8s/src/tests/__snapshots__/resize-hpa.test.tsx.snap b/frontend/workflows/k8s/src/tests/__snapshots__/resize-hpa.test.tsx.snap index 38d61b7ec5..0d27a7fda2 100644 --- a/frontend/workflows/k8s/src/tests/__snapshots__/resize-hpa.test.tsx.snap +++ b/frontend/workflows/k8s/src/tests/__snapshots__/resize-hpa.test.tsx.snap @@ -88,7 +88,7 @@ exports[`renders correctly 1`] = ` - Verify + Modify From cfc74792e7a60a08d9ac72ac6eb93a5549941d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=ADa=20Echenique=20=C3=81lvarez?= Date: Tue, 10 Sep 2024 16:49:37 -0600 Subject: [PATCH 10/12] testing path matching --- .../src/AppNotifications/LayoutWithNotifications.tsx | 3 +++ frontend/packages/core/src/utils/index.ts | 1 + frontend/packages/core/src/utils/pathMatching.tsx | 11 +++++++++++ 3 files changed, 15 insertions(+) create mode 100644 frontend/packages/core/src/utils/pathMatching.tsx diff --git a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx index 8dba1de336..392fa88880 100644 --- a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx +++ b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx @@ -6,6 +6,7 @@ import { Alert } from "../Feedback"; import Grid from "../grid"; import { Link as LinkComponent } from "../link"; import type { AppBanners } from "../Types"; +import { checkPathMatchList } from "../utils"; interface LayoutWithNotificationsProps { bannersData: AppBanners; @@ -25,6 +26,8 @@ const LayoutWithNotifications = ({ const location = useLocation(); + checkPathMatchList(location?.pathname, perWorkflowData[workflow]?.paths); + const hasPerWorkflowAlert = workflow && perWorkflowData[workflow] && !perWorkflowData[workflow]?.dismissed; const showAlertPerWorkflow = !isEmpty(perWorkflowData[workflow]?.paths) diff --git a/frontend/packages/core/src/utils/index.ts b/frontend/packages/core/src/utils/index.ts index 9d2bd6851f..a08d37eaee 100644 --- a/frontend/packages/core/src/utils/index.ts +++ b/frontend/packages/core/src/utils/index.ts @@ -1,2 +1,3 @@ // eslint-disable-next-line import/prefer-default-export export { default as getDisplayName } from "./getDisplayName"; +export { default as checkPathMatchList } from "./pathMatching"; diff --git a/frontend/packages/core/src/utils/pathMatching.tsx b/frontend/packages/core/src/utils/pathMatching.tsx new file mode 100644 index 0000000000..944f2477cd --- /dev/null +++ b/frontend/packages/core/src/utils/pathMatching.tsx @@ -0,0 +1,11 @@ +import { matchPath } from "react-router"; + +const checkPathMatchList = (locationPathname: string, pathstoMatch: string[]) => { + pathstoMatch.forEach(path => { + const match = matchPath({ path }, locationPathname); + + console.log("match: ", match); + }); +}; + +export default checkPathMatchList; From c79a29aefd60c37784bfc77685740a1759f438bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=ADa=20Echenique=20=C3=81lvarez?= Date: Tue, 10 Sep 2024 17:11:05 -0600 Subject: [PATCH 11/12] add path match logic --- .../AppNotifications/LayoutWithNotifications.tsx | 7 ++++--- frontend/packages/core/src/utils/index.ts | 2 +- frontend/packages/core/src/utils/pathMatching.tsx | 14 ++++++++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx index 392fa88880..323360bf96 100644 --- a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx +++ b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx @@ -6,7 +6,7 @@ import { Alert } from "../Feedback"; import Grid from "../grid"; import { Link as LinkComponent } from "../link"; import type { AppBanners } from "../Types"; -import { checkPathMatchList } from "../utils"; +import { findPathMatchList } from "../utils"; interface LayoutWithNotificationsProps { bannersData: AppBanners; @@ -26,12 +26,13 @@ const LayoutWithNotifications = ({ const location = useLocation(); - checkPathMatchList(location?.pathname, perWorkflowData[workflow]?.paths); + const pathMatches = findPathMatchList(location?.pathname, perWorkflowData[workflow]?.paths); const hasPerWorkflowAlert = workflow && perWorkflowData[workflow] && !perWorkflowData[workflow]?.dismissed; const showAlertPerWorkflow = !isEmpty(perWorkflowData[workflow]?.paths) - ? hasPerWorkflowAlert && perWorkflowData[workflow]?.paths?.includes(location.pathname) + ? hasPerWorkflowAlert && + (perWorkflowData[workflow]?.paths?.includes(location.pathname) || pathMatches) : hasPerWorkflowAlert; const showAlertMultiWorkflow = diff --git a/frontend/packages/core/src/utils/index.ts b/frontend/packages/core/src/utils/index.ts index a08d37eaee..b42b50a982 100644 --- a/frontend/packages/core/src/utils/index.ts +++ b/frontend/packages/core/src/utils/index.ts @@ -1,3 +1,3 @@ // eslint-disable-next-line import/prefer-default-export export { default as getDisplayName } from "./getDisplayName"; -export { default as checkPathMatchList } from "./pathMatching"; +export { default as findPathMatchList } from "./pathMatching"; diff --git a/frontend/packages/core/src/utils/pathMatching.tsx b/frontend/packages/core/src/utils/pathMatching.tsx index 944f2477cd..ea6a6d07e3 100644 --- a/frontend/packages/core/src/utils/pathMatching.tsx +++ b/frontend/packages/core/src/utils/pathMatching.tsx @@ -1,11 +1,17 @@ import { matchPath } from "react-router"; -const checkPathMatchList = (locationPathname: string, pathstoMatch: string[]) => { - pathstoMatch.forEach(path => { +const findPathMatchList = (locationPathname: string, pathstoMatch: string[]) => { + let pathFound = false; + + pathstoMatch?.forEach((path: string) => { const match = matchPath({ path }, locationPathname); - console.log("match: ", match); + if (match) { + pathFound = true; + } }); + + return pathFound; }; -export default checkPathMatchList; +export default findPathMatchList; From 0eb3670a653a1c3ce83075b37150e4f74da8e263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=ADa=20Echenique=20=C3=81lvarez?= Date: Fri, 13 Sep 2024 10:40:42 -0600 Subject: [PATCH 12/12] feedback update --- .../LayoutWithNotifications.tsx | 37 +++++++++++++------ .../packages/core/src/utils/pathMatching.tsx | 12 +----- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx index 323360bf96..a34c57304e 100644 --- a/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx +++ b/frontend/packages/core/src/AppNotifications/LayoutWithNotifications.tsx @@ -1,5 +1,6 @@ import React from "react"; import { useLocation } from "react-router-dom"; +import styled from "@emotion/styled"; import isEmpty from "lodash/isEmpty"; import { Alert } from "../Feedback"; @@ -15,6 +16,14 @@ interface LayoutWithNotificationsProps { workflow?: string; } +const AlertContent = styled.div({ + display: "flex", +}); + +const StyledLink = styled(LinkComponent)({ + marginLeft: "8px", +}); + const LayoutWithNotifications = ({ bannersData, onDismissAlert, @@ -76,12 +85,14 @@ const LayoutWithNotifications = ({ elevation={6} onClose={onDismissAlertPerWorkflow} > - {perWorkflowData[workflow]?.message} - {perWorkflowData[workflow]?.link && perWorkflowData[workflow]?.linkText && ( - - {perWorkflowData[workflow]?.linkText} - - )} + + {perWorkflowData[workflow]?.message} + {perWorkflowData[workflow]?.link && perWorkflowData[workflow]?.linkText && ( + + {perWorkflowData[workflow]?.linkText} + + )} + )} {showAlertMultiWorkflow && !showAlertPerWorkflow && ( @@ -91,12 +102,14 @@ const LayoutWithNotifications = ({ elevation={6} onClose={onDismissAlertMultiWorkflow} > - {multiWorkflowData?.message} - {multiWorkflowData?.link && multiWorkflowData?.linkText && ( - - {multiWorkflowData?.linkText} - - )} + + {multiWorkflowData?.message} + {multiWorkflowData?.link && multiWorkflowData?.linkText && ( + + {multiWorkflowData?.linkText} + + )} + )} diff --git a/frontend/packages/core/src/utils/pathMatching.tsx b/frontend/packages/core/src/utils/pathMatching.tsx index ea6a6d07e3..c83c40d0a4 100644 --- a/frontend/packages/core/src/utils/pathMatching.tsx +++ b/frontend/packages/core/src/utils/pathMatching.tsx @@ -1,15 +1,7 @@ import { matchPath } from "react-router"; -const findPathMatchList = (locationPathname: string, pathstoMatch: string[]) => { - let pathFound = false; - - pathstoMatch?.forEach((path: string) => { - const match = matchPath({ path }, locationPathname); - - if (match) { - pathFound = true; - } - }); +const findPathMatchList = (locationPathname: string, pathsToMatch: string[]) => { + const pathFound = pathsToMatch?.find((path: string) => matchPath({ path }, locationPathname)); return pathFound; };