diff --git a/frontend/src/container/GridGraphLayout/Graph/WidgetGraphComponent.tsx b/frontend/src/container/GridGraphLayout/Graph/WidgetGraphComponent.tsx index 57f74a8c0a..75a69f129b 100644 --- a/frontend/src/container/GridGraphLayout/Graph/WidgetGraphComponent.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/WidgetGraphComponent.tsx @@ -53,9 +53,7 @@ function WidgetGraphComponent({ setLayout, onDragSelect, onClickHandler, - allowClone = true, - allowDelete = true, - allowEdit = true, + headerMenuList, }: WidgetGraphComponentProps): JSX.Element { const [deleteModal, setDeleteModal] = useState(false); const [modal, setModal] = useState(false); @@ -281,9 +279,7 @@ function WidgetGraphComponent({ onClone={onCloneHandler} queryResponse={queryResponse} errorMessage={errorMessage} - allowClone={allowClone} - allowDelete={allowDelete} - allowEdit={allowEdit} + headerMenuList={headerMenuList} /> )} @@ -313,9 +309,6 @@ WidgetGraphComponent.defaultProps = { setLayout: undefined, onDragSelect: undefined, onClickHandler: undefined, - allowDelete: true, - allowClone: true, - allowEdit: true, }; const mapDispatchToProps = ( diff --git a/frontend/src/container/GridGraphLayout/Graph/index.tsx b/frontend/src/container/GridGraphLayout/Graph/index.tsx index f3675c2da8..ee75c509f0 100644 --- a/frontend/src/container/GridGraphLayout/Graph/index.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/index.tsx @@ -15,6 +15,7 @@ import { GlobalReducer } from 'types/reducer/globalTime'; import { getSelectedDashboardVariable } from 'utils/dashboard/selectedDashboard'; import EmptyWidget from '../EmptyWidget'; +import { MenuItemKeys } from '../WidgetHeader/contants'; import { GridCardGraphProps } from './types'; import WidgetGraphComponent from './WidgetGraphComponent'; @@ -26,9 +27,7 @@ function GridCardGraph({ setLayout, onDragSelect, onClickHandler, - allowDelete, - allowClone, - allowEdit, + headerMenuList = [MenuItemKeys.View], isQueryEnabled, }: GridCardGraphProps): JSX.Element { const { isAddWidget } = useSelector( @@ -121,9 +120,7 @@ function GridCardGraph({ yAxisUnit={yAxisUnit} layout={layout} setLayout={setLayout} - allowClone={allowClone} - allowDelete={allowDelete} - allowEdit={allowEdit} + headerMenuList={headerMenuList} /> )} @@ -145,9 +142,7 @@ function GridCardGraph({ yAxisUnit={yAxisUnit} layout={layout} setLayout={setLayout} - allowClone={allowClone} - allowDelete={allowDelete} - allowEdit={allowEdit} + headerMenuList={headerMenuList} onClickHandler={onClickHandler} /> ) : ( @@ -170,9 +165,7 @@ function GridCardGraph({ name={name} yAxisUnit={yAxisUnit} onDragSelect={onDragSelect} - allowClone={allowClone} - allowDelete={allowDelete} - allowEdit={allowEdit} + headerMenuList={headerMenuList} onClickHandler={onClickHandler} /> )} @@ -185,10 +178,8 @@ function GridCardGraph({ GridCardGraph.defaultProps = { onDragSelect: undefined, onClickHandler: undefined, - allowDelete: true, - allowClone: true, - allowEdit: true, isQueryEnabled: true, + headerMenuList: [MenuItemKeys.View], }; export default memo(GridCardGraph); diff --git a/frontend/src/container/GridGraphLayout/Graph/types.ts b/frontend/src/container/GridGraphLayout/Graph/types.ts index 23c7a77645..cbcd9d8718 100644 --- a/frontend/src/container/GridGraphLayout/Graph/types.ts +++ b/frontend/src/container/GridGraphLayout/Graph/types.ts @@ -10,6 +10,7 @@ import { Widgets } from 'types/api/dashboard/getAll'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; import { LayoutProps } from '..'; +import { MenuItemKeys } from '../WidgetHeader/contants'; import { LegendEntryProps } from './FullView/types'; export interface GraphVisibilityLegendEntryProps { @@ -38,25 +39,19 @@ export interface WidgetGraphComponentProps extends DispatchProps { setLayout?: Dispatch>; onDragSelect?: (start: number, end: number) => void; onClickHandler?: GraphOnClickHandler; - allowDelete?: boolean; - allowClone?: boolean; - allowEdit?: boolean; + headerMenuList: MenuItemKeys[]; } export interface GridCardGraphProps { widget: Widgets; name: string; yAxisUnit: string | undefined; - // eslint-disable-next-line react/require-default-props layout?: Layout[]; - // eslint-disable-next-line react/require-default-props setLayout?: Dispatch>; onDragSelect?: (start: number, end: number) => void; onClickHandler?: GraphOnClickHandler; - allowDelete?: boolean; - allowClone?: boolean; - allowEdit?: boolean; - isQueryEnabled?: boolean; + headerMenuList?: WidgetGraphComponentProps['headerMenuList']; + isQueryEnabled: boolean; } export interface GetGraphVisibilityStateOnLegendClickProps { diff --git a/frontend/src/container/GridGraphLayout/WidgetHeader/contants.ts b/frontend/src/container/GridGraphLayout/WidgetHeader/contants.ts index f3ba263e1b..6f3871bd3d 100644 --- a/frontend/src/container/GridGraphLayout/WidgetHeader/contants.ts +++ b/frontend/src/container/GridGraphLayout/WidgetHeader/contants.ts @@ -3,6 +3,7 @@ export enum MenuItemKeys { Edit = 'edit', Delete = 'delete', Clone = 'clone', + CreateAlerts = 'createAlerts', } export const MENUITEM_KEYS_VS_LABELS = { @@ -10,4 +11,5 @@ export const MENUITEM_KEYS_VS_LABELS = { [MenuItemKeys.Edit]: 'Edit', [MenuItemKeys.Delete]: 'Delete', [MenuItemKeys.Clone]: 'Clone', + [MenuItemKeys.CreateAlerts]: 'Create Alerts', }; diff --git a/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx b/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx index 0f89593eb6..98766ab54b 100644 --- a/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx +++ b/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx @@ -7,9 +7,9 @@ import { FullscreenOutlined, } from '@ant-design/icons'; import { Dropdown, MenuProps, Tooltip, Typography } from 'antd'; -import { MenuItemType } from 'antd/es/menu/hooks/useItems'; import Spinner from 'components/Spinner'; import { queryParamNamesMap } from 'constants/queryBuilderQueryNames'; +import ROUTES from 'constants/routes'; import useComponentPermission from 'hooks/useComponentPermission'; import history from 'lib/history'; import { useCallback, useMemo, useState } from 'react'; @@ -33,7 +33,7 @@ import { HeaderContainer, HeaderContentContainer, } from './styles'; -import { KeyMethodMappingProps, MenuItem, TWidgetOptions } from './types'; +import { MenuItem } from './types'; import { generateMenuList, isTWidgetOptions } from './utils'; interface IWidgetHeaderProps { @@ -47,10 +47,9 @@ interface IWidgetHeaderProps { SuccessResponse | ErrorResponse >; errorMessage: string | undefined; - allowDelete?: boolean; - allowClone?: boolean; - allowEdit?: boolean; + headerMenuList?: MenuItemKeys[]; } + function WidgetHeader({ title, widget, @@ -60,9 +59,7 @@ function WidgetHeader({ parentHover, queryResponse, errorMessage, - allowClone = true, - allowDelete = true, - allowEdit = true, + headerMenuList, }: IWidgetHeaderProps): JSX.Element { const [localHover, setLocalHover] = useState(false); const [isOpen, setIsOpen] = useState(false); @@ -78,32 +75,30 @@ function WidgetHeader({ ); }, [widget.id, widget.panelTypes, widget.query]); - const keyMethodMapping: KeyMethodMappingProps = useMemo( + const onCreateAlertsHandler = useCallback(() => { + history.push( + `${ROUTES.ALERTS_NEW}?${ + queryParamNamesMap.compositeQuery + }=${encodeURIComponent(JSON.stringify(widget.query))}`, + ); + }, [widget]); + + const keyMethodMapping = useMemo( () => ({ - view: { - key: MenuItemKeys.View, - method: onView, - }, - edit: { - key: MenuItemKeys.Edit, - method: onEditHandler, - }, - delete: { - key: MenuItemKeys.Delete, - method: onDelete, - }, - clone: { - key: MenuItemKeys.Clone, - method: onClone, - }, + [MenuItemKeys.View]: onView, + [MenuItemKeys.Edit]: onEditHandler, + [MenuItemKeys.Delete]: onDelete, + [MenuItemKeys.Clone]: onClone, + [MenuItemKeys.CreateAlerts]: onCreateAlertsHandler, }), - [onDelete, onEditHandler, onView, onClone], + [onDelete, onEditHandler, onView, onClone, onCreateAlertsHandler], ); const onMenuItemSelectHandler: MenuProps['onClick'] = useCallback( ({ key }: { key: string }): void => { if (isTWidgetOptions(key)) { - const functionToCall = keyMethodMapping[key]?.method; + const functionToCall = keyMethodMapping[key]; + if (functionToCall) { functionToCall(); setIsOpen(false); @@ -125,46 +120,43 @@ function WidgetHeader({ key: MenuItemKeys.View, icon: , label: MENUITEM_KEYS_VS_LABELS[MenuItemKeys.View], - isVisible: true, + isVisible: headerMenuList?.includes(MenuItemKeys.View) || false, disabled: queryResponse.isLoading, }, { key: MenuItemKeys.Edit, icon: , label: MENUITEM_KEYS_VS_LABELS[MenuItemKeys.Edit], - isVisible: allowEdit, + isVisible: headerMenuList?.includes(MenuItemKeys.Edit) || false, disabled: !editWidget, }, { key: MenuItemKeys.Clone, icon: , label: MENUITEM_KEYS_VS_LABELS[MenuItemKeys.Clone], - isVisible: allowClone, + isVisible: headerMenuList?.includes(MenuItemKeys.Clone) || false, disabled: !editWidget, }, { key: MenuItemKeys.Delete, icon: , label: MENUITEM_KEYS_VS_LABELS[MenuItemKeys.Delete], - isVisible: allowDelete, + isVisible: headerMenuList?.includes(MenuItemKeys.Delete) || false, disabled: !deleteWidget, danger: true, }, + { + key: MenuItemKeys.CreateAlerts, + icon: , + label: MENUITEM_KEYS_VS_LABELS[MenuItemKeys.CreateAlerts], + isVisible: headerMenuList?.includes(MenuItemKeys.CreateAlerts) || false, + disabled: false, + }, ], - [ - allowEdit, - allowClone, - allowDelete, - queryResponse.isLoading, - deleteWidget, - editWidget, - ], + [queryResponse.isLoading, headerMenuList, editWidget, deleteWidget], ); - const menuList: MenuItemType[] = useMemo( - (): MenuItemType[] => generateMenuList(actions, keyMethodMapping), - [actions, keyMethodMapping], - ); + const updatedMenuList = useMemo(() => generateMenuList(actions), [actions]); const onClickHandler = useCallback(() => { setIsOpen((open) => !open); @@ -172,10 +164,10 @@ function WidgetHeader({ const menu = useMemo( () => ({ - items: menuList, + items: updatedMenuList, onClick: onMenuItemSelectHandler, }), - [menuList, onMenuItemSelectHandler], + [updatedMenuList, onMenuItemSelectHandler], ); return ( @@ -219,9 +211,7 @@ function WidgetHeader({ WidgetHeader.defaultProps = { onDelete: undefined, onClone: undefined, - allowDelete: true, - allowClone: true, - allowEdit: true, + headerMenuList: [MenuItemKeys.View], }; export default WidgetHeader; diff --git a/frontend/src/container/GridGraphLayout/WidgetHeader/types.ts b/frontend/src/container/GridGraphLayout/WidgetHeader/types.ts index 26a7a366fb..0891c6634c 100644 --- a/frontend/src/container/GridGraphLayout/WidgetHeader/types.ts +++ b/frontend/src/container/GridGraphLayout/WidgetHeader/types.ts @@ -3,23 +3,10 @@ import { ReactNode } from 'react'; import { MenuItemKeys } from './contants'; export interface MenuItem { - key: TWidgetOptions; + key: MenuItemKeys; icon: ReactNode; label: string; isVisible: boolean; disabled: boolean; danger?: boolean; } - -export type TWidgetOptions = - | MenuItemKeys.View - | MenuItemKeys.Edit - | MenuItemKeys.Delete - | MenuItemKeys.Clone; - -export type KeyMethodMappingProps = { - [K in T]: { - key: TWidgetOptions; - method?: VoidFunction; - }; -}; diff --git a/frontend/src/container/GridGraphLayout/WidgetHeader/utils.ts b/frontend/src/container/GridGraphLayout/WidgetHeader/utils.ts index 8473ebc11b..482994aa8c 100644 --- a/frontend/src/container/GridGraphLayout/WidgetHeader/utils.ts +++ b/frontend/src/container/GridGraphLayout/WidgetHeader/utils.ts @@ -1,24 +1,22 @@ import { MenuItemType } from 'antd/es/menu/hooks/useItems'; import { MenuItemKeys } from './contants'; -import { KeyMethodMappingProps, MenuItem, TWidgetOptions } from './types'; +import { MenuItem } from './types'; -export const generateMenuList = ( - actions: MenuItem[], - keyMethodMapping: KeyMethodMappingProps, -): MenuItemType[] => +export const generateMenuList = (actions: MenuItem[]): MenuItemType[] => actions .filter((action: MenuItem) => action.isVisible) .map(({ key, icon: Icon, label, disabled, ...rest }) => ({ - key: keyMethodMapping[key].key, + key, icon: Icon, label, disabled, ...rest, })); -export const isTWidgetOptions = (value: string): value is TWidgetOptions => +export const isTWidgetOptions = (value: string): value is MenuItemKeys => value === MenuItemKeys.View || value === MenuItemKeys.Edit || value === MenuItemKeys.Delete || - value === MenuItemKeys.Clone; + value === MenuItemKeys.Clone || + value === MenuItemKeys.CreateAlerts; diff --git a/frontend/src/container/GridGraphLayout/config.ts b/frontend/src/container/GridGraphLayout/config.ts new file mode 100644 index 0000000000..0357c7795c --- /dev/null +++ b/frontend/src/container/GridGraphLayout/config.ts @@ -0,0 +1,8 @@ +import { MenuItemKeys } from 'container/GridGraphLayout/WidgetHeader/contants'; + +export const headerMenuList = [ + MenuItemKeys.View, + MenuItemKeys.Clone, + MenuItemKeys.Delete, + MenuItemKeys.Edit, +]; diff --git a/frontend/src/container/GridGraphLayout/index.tsx b/frontend/src/container/GridGraphLayout/index.tsx index f728781a28..fe65154fd9 100644 --- a/frontend/src/container/GridGraphLayout/index.tsx +++ b/frontend/src/container/GridGraphLayout/index.tsx @@ -29,6 +29,7 @@ import { Dashboard, Widgets } from 'types/api/dashboard/getAll'; import AppReducer from 'types/reducer/app'; import DashboardReducer from 'types/reducer/dashboards'; +import { headerMenuList } from './config'; import Graph from './Graph'; import GraphLayoutContainer from './GraphLayout'; import { UpdateDashboard } from './utils'; @@ -49,6 +50,7 @@ export const getPreLayouts = ( yAxisUnit={widget?.yAxisUnit} layout={layout} setLayout={setLayout} + headerMenuList={headerMenuList} /> ); }, @@ -233,6 +235,7 @@ function GridGraph(props: Props): JSX.Element { layout={layout} setLayout={setLayout} onDragSelect={onDragSelect} + headerMenuList={headerMenuList} /> ), }; diff --git a/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx b/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx index 678d271d11..83e6da6db2 100644 --- a/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx @@ -117,9 +117,6 @@ function DBCall(): JSX.Element { 'database_call_rps', ); }} - allowClone={false} - allowDelete={false} - allowEdit={false} /> @@ -153,9 +150,6 @@ function DBCall(): JSX.Element { 'database_call_avg_duration', ); }} - allowClone={false} - allowDelete={false} - allowEdit={false} /> diff --git a/frontend/src/container/MetricsApplication/Tabs/External.tsx b/frontend/src/container/MetricsApplication/Tabs/External.tsx index 6595a11808..3abe8d4ca4 100644 --- a/frontend/src/container/MetricsApplication/Tabs/External.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/External.tsx @@ -156,9 +156,6 @@ function External(): JSX.Element { 'external_call_error_percentage', ); }} - allowClone={false} - allowDelete={false} - allowEdit={false} /> @@ -194,9 +191,6 @@ function External(): JSX.Element { 'external_call_duration', ); }} - allowClone={false} - allowDelete={false} - allowEdit={false} /> @@ -233,9 +227,6 @@ function External(): JSX.Element { 'external_call_rps_by_address', ); }} - allowClone={false} - allowDelete={false} - allowEdit={false} /> @@ -271,9 +262,6 @@ function External(): JSX.Element { 'external_call_duration_by_address', ); }} - allowClone={false} - allowDelete={false} - allowEdit={false} /> diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview/ServiceOverview.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview/ServiceOverview.tsx index 28895d2909..5de62035c2 100644 --- a/frontend/src/container/MetricsApplication/Tabs/Overview/ServiceOverview.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/Overview/ServiceOverview.tsx @@ -75,9 +75,6 @@ function ServiceOverview({ widget={latencyWidget} yAxisUnit="ns" onClickHandler={handleGraphClick('Service')} - allowClone={false} - allowDelete={false} - allowEdit={false} isQueryEnabled={isQueryEnabled} /> diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview/TopLevelOperations.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview/TopLevelOperations.tsx index 6d4a624a04..903ff3a15f 100644 --- a/frontend/src/container/MetricsApplication/Tabs/Overview/TopLevelOperations.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/Overview/TopLevelOperations.tsx @@ -39,9 +39,6 @@ function TopLevelOperation({ onClickHandler={handleGraphClick(opName)} yAxisUnit={yAxisUnit} onDragSelect={onDragSelect} - allowClone={false} - allowDelete={false} - allowEdit={false} /> )}