From 56a46b1ea508c45e1e28685f8213fea85827a0fc Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Wed, 26 Jun 2024 11:50:31 +0200 Subject: [PATCH] change(ui): modal context and alert form --- frontend/app/Router.tsx | 331 +++++---- frontend/app/components/Alerts/AlertForm.js | 698 +++++++++--------- .../Alerts/AlertFormModal/AlertFormModal.tsx | 19 +- .../components/WidgetView/CardViewMenu.tsx | 99 +++ .../WidgetView/WidgetViewHeader.tsx | 58 +- .../components/WidgetWrapper/AlertButton.tsx | 12 +- frontend/app/components/ModalContext.tsx | 64 ++ 7 files changed, 703 insertions(+), 578 deletions(-) create mode 100644 frontend/app/components/Dashboard/components/WidgetView/CardViewMenu.tsx create mode 100644 frontend/app/components/ModalContext.tsx diff --git a/frontend/app/Router.tsx b/frontend/app/Router.tsx index 48bc7d351..51cae3feb 100644 --- a/frontend/app/Router.tsx +++ b/frontend/app/Router.tsx @@ -1,193 +1,196 @@ -import React, { useEffect, useRef } from 'react'; -import { withRouter, RouteComponentProps } from 'react-router-dom'; -import { connect, ConnectedProps } from 'react-redux'; -import { Loader } from 'UI'; -import { fetchUserInfo, setJwt } from 'Duck/user'; -import { fetchList as fetchSiteList } from 'Duck/site'; -import { withStore } from 'App/mstore'; -import { Map } from 'immutable'; +import React, {useEffect, useRef} from 'react'; +import {withRouter, RouteComponentProps} from 'react-router-dom'; +import {connect, ConnectedProps} from 'react-redux'; +import {Loader} from 'UI'; +import {fetchUserInfo, setJwt} from 'Duck/user'; +import {fetchList as fetchSiteList} from 'Duck/site'; +import {withStore} from 'App/mstore'; +import {Map} from 'immutable'; import * as routes from './routes'; -import { fetchTenants } from 'Duck/user'; -import { setSessionPath } from 'Duck/sessions'; -import { ModalProvider } from 'Components/Modal'; -import { GLOBAL_DESTINATION_PATH, IFRAME, JWT_PARAM } from 'App/constants/storageKeys'; +import {fetchTenants} from 'Duck/user'; +import {setSessionPath} from 'Duck/sessions'; +import {ModalProvider} from 'Components/Modal'; +import {GLOBAL_DESTINATION_PATH, IFRAME, JWT_PARAM} from 'App/constants/storageKeys'; import PublicRoutes from 'App/PublicRoutes'; import Layout from 'App/layout/Layout'; -import { fetchListActive as fetchMetadata } from 'Duck/customField'; -import { init as initSite } from 'Duck/site'; +import {fetchListActive as fetchMetadata} from 'Duck/customField'; +import {init as initSite} from 'Duck/site'; import PrivateRoutes from 'App/PrivateRoutes'; -import { checkParam } from 'App/utils'; +import {checkParam} from 'App/utils'; import IFrameRoutes from 'App/IFrameRoutes'; +import {ModalProvider as NewModalProvider} from 'Components/ModalContext'; interface RouterProps extends RouteComponentProps, ConnectedProps { - isLoggedIn: boolean; - sites: Map; - loading: boolean; - changePassword: boolean; - isEnterprise: boolean; - fetchUserInfo: () => any; - fetchTenants: () => any; - setSessionPath: (path: any) => any; - fetchSiteList: (siteId?: number) => any; - match: { - params: { - siteId: string; - } - }; - mstore: any; - setJwt: (jwt: string) => any; - fetchMetadata: (siteId: string) => void; - initSite: (site: any) => void; + isLoggedIn: boolean; + sites: Map; + loading: boolean; + changePassword: boolean; + isEnterprise: boolean; + fetchUserInfo: () => any; + fetchTenants: () => any; + setSessionPath: (path: any) => any; + fetchSiteList: (siteId?: number) => any; + match: { + params: { + siteId: string; + } + }; + mstore: any; + setJwt: (jwt: string) => any; + fetchMetadata: (siteId: string) => void; + initSite: (site: any) => void; } const Router: React.FC = (props) => { - const { - isLoggedIn, - siteId, - sites, - loading, - location, - fetchUserInfo, - fetchSiteList, - history, - match: { params: { siteId: siteIdFromPath } }, - setSessionPath, - } = props; - const [isIframe, setIsIframe] = React.useState(false); - const [isJwt, setIsJwt] = React.useState(false); + const { + isLoggedIn, + siteId, + sites, + loading, + location, + fetchUserInfo, + fetchSiteList, + history, + match: {params: {siteId: siteIdFromPath}}, + setSessionPath, + } = props; + const [isIframe, setIsIframe] = React.useState(false); + const [isJwt, setIsJwt] = React.useState(false); - const handleJwtFromUrl = () => { - const urlJWT = new URLSearchParams(location.search).get('jwt'); - if (urlJWT) { - props.setJwt(urlJWT); + const handleJwtFromUrl = () => { + const urlJWT = new URLSearchParams(location.search).get('jwt'); + if (urlJWT) { + props.setJwt(urlJWT); + } + }; + + const handleDestinationPath = () => { + if (!isLoggedIn && location.pathname !== routes.login()) { + localStorage.setItem(GLOBAL_DESTINATION_PATH, location.pathname + location.search); + } + }; + + const handleUserLogin = async () => { + await fetchUserInfo(); + const siteIdFromPath = parseInt(location.pathname.split('/')[1]); + await fetchSiteList(siteIdFromPath); + props.mstore.initClient(); + + const destinationPath = localStorage.getItem(GLOBAL_DESTINATION_PATH); + if ( + destinationPath && + destinationPath !== routes.login() && + destinationPath !== routes.signup() && + destinationPath !== '/' + ) { + const url = new URL(destinationPath, window.location.origin); + checkParams(url.search) + history.push(destinationPath); + localStorage.removeItem(GLOBAL_DESTINATION_PATH); + } + }; + + const checkParams = (search?: string) => { + const _isIframe = checkParam('iframe', IFRAME, search); + const _isJwt = checkParam('jwt', JWT_PARAM, search); + setIsIframe(_isIframe); + setIsJwt(_isJwt); } - }; - const handleDestinationPath = () => { - if (!isLoggedIn && location.pathname !== routes.login()) { - localStorage.setItem(GLOBAL_DESTINATION_PATH, location.pathname + location.search); - } - }; - - const handleUserLogin = async () => { - await fetchUserInfo(); - const siteIdFromPath = parseInt(location.pathname.split('/')[1]); - await fetchSiteList(siteIdFromPath); - props.mstore.initClient(); - - const destinationPath = localStorage.getItem(GLOBAL_DESTINATION_PATH); - if ( - destinationPath && - destinationPath !== routes.login() && - destinationPath !== routes.signup() && - destinationPath !== '/' - ) { - const url = new URL(destinationPath, window.location.origin); - checkParams(url.search) - history.push(destinationPath); - localStorage.removeItem(GLOBAL_DESTINATION_PATH); - } - }; - - const checkParams = (search?: string) => { - const _isIframe = checkParam('iframe', IFRAME, search); - const _isJwt = checkParam('jwt', JWT_PARAM, search); - setIsIframe(_isIframe); - setIsJwt(_isJwt); - } - - useEffect(() => { - checkParams(); - handleJwtFromUrl(); - }, []); - - useEffect(() => { - // handleJwtFromUrl(); - handleDestinationPath(); - - - setSessionPath(previousLocation ? previousLocation : location); - }, [location]); - - useEffect(() => { - if (prevIsLoggedIn !== isLoggedIn && isLoggedIn) { - handleUserLogin(); - } - }, [isLoggedIn]); - - useEffect(() => { - if (siteId && siteId !== lastFetchedSiteIdRef.current) { - const activeSite = sites.find((s) => s.id == siteId); - props.initSite(activeSite); - props.fetchMetadata(siteId); - lastFetchedSiteIdRef.current = siteId; - } - }, [siteId]); - - const lastFetchedSiteIdRef = useRef(null); - - function usePrevious(value: any) { - const ref = useRef(); useEffect(() => { - ref.current = value; - }, [value]); - return ref.current; - } + checkParams(); + handleJwtFromUrl(); + }, []); - const prevIsLoggedIn = usePrevious(isLoggedIn); - const previousLocation = usePrevious(location); + useEffect(() => { + // handleJwtFromUrl(); + handleDestinationPath(); - const hideHeader = (location.pathname && location.pathname.includes('/session/')) || - location.pathname.includes('/assist/') || location.pathname.includes('multiview'); - if (isIframe) { - return ; - } + setSessionPath(previousLocation ? previousLocation : location); + }, [location]); - return isLoggedIn ? ( - - - - - - - - ) : ; + useEffect(() => { + if (prevIsLoggedIn !== isLoggedIn && isLoggedIn) { + handleUserLogin(); + } + }, [isLoggedIn]); + + useEffect(() => { + if (siteId && siteId !== lastFetchedSiteIdRef.current) { + const activeSite = sites.find((s) => s.id == siteId); + props.initSite(activeSite); + props.fetchMetadata(siteId); + lastFetchedSiteIdRef.current = siteId; + } + }, [siteId]); + + const lastFetchedSiteIdRef = useRef(null); + + function usePrevious(value: any) { + const ref = useRef(); + useEffect(() => { + ref.current = value; + }, [value]); + return ref.current; + } + + const prevIsLoggedIn = usePrevious(isLoggedIn); + const previousLocation = usePrevious(location); + + const hideHeader = (location.pathname && location.pathname.includes('/session/')) || + location.pathname.includes('/assist/') || location.pathname.includes('multiview'); + + if (isIframe) { + return ; + } + + return isLoggedIn ? ( + + + + + + + + + + ) : ; }; const mapStateToProps = (state: Map) => { - const siteId = state.getIn(['site', 'siteId']); - const jwt = state.getIn(['user', 'jwt']); - const changePassword = state.getIn(['user', 'account', 'changePassword']); - const userInfoLoading = state.getIn(['user', 'fetchUserInfoRequest', 'loading']); - const sitesLoading = state.getIn(['site', 'fetchListRequest', 'loading']); + const siteId = state.getIn(['site', 'siteId']); + const jwt = state.getIn(['user', 'jwt']); + const changePassword = state.getIn(['user', 'account', 'changePassword']); + const userInfoLoading = state.getIn(['user', 'fetchUserInfoRequest', 'loading']); + const sitesLoading = state.getIn(['site', 'fetchListRequest', 'loading']); - return { - siteId, - changePassword, - sites: state.getIn(['site', 'list']), - isLoggedIn: jwt !== null && !changePassword, - loading: siteId === null || userInfoLoading || sitesLoading, - email: state.getIn(['user', 'account', 'email']), - account: state.getIn(['user', 'account']), - organisation: state.getIn(['user', 'account', 'name']), - tenantId: state.getIn(['user', 'account', 'tenantId']), - tenants: state.getIn(['user', 'tenants']), - isEnterprise: - state.getIn(['user', 'account', 'edition']) === 'ee' || - state.getIn(['user', 'authDetails', 'edition']) === 'ee' - }; + return { + siteId, + changePassword, + sites: state.getIn(['site', 'list']), + isLoggedIn: jwt !== null && !changePassword, + loading: siteId === null || userInfoLoading || sitesLoading, + email: state.getIn(['user', 'account', 'email']), + account: state.getIn(['user', 'account']), + organisation: state.getIn(['user', 'account', 'name']), + tenantId: state.getIn(['user', 'account', 'tenantId']), + tenants: state.getIn(['user', 'tenants']), + isEnterprise: + state.getIn(['user', 'account', 'edition']) === 'ee' || + state.getIn(['user', 'authDetails', 'edition']) === 'ee' + }; }; const mapDispatchToProps = { - fetchUserInfo, - fetchTenants, - setSessionPath, - fetchSiteList, - setJwt, - fetchMetadata, - initSite + fetchUserInfo, + fetchTenants, + setSessionPath, + fetchSiteList, + setJwt, + fetchMetadata, + initSite }; const connector = connect(mapStateToProps, mapDispatchToProps); diff --git a/frontend/app/components/Alerts/AlertForm.js b/frontend/app/components/Alerts/AlertForm.js index fcec66918..852780e9b 100644 --- a/frontend/app/components/Alerts/AlertForm.js +++ b/frontend/app/components/Alerts/AlertForm.js @@ -1,382 +1,384 @@ -import React, { useEffect } from 'react'; -import { Button, Form, Input, SegmentSelection, Checkbox, Icon } from 'UI'; -import { alertConditions as conditions } from 'App/constants'; +import React, {useEffect} from 'react'; +import {Form, Input, SegmentSelection, Checkbox, Icon} from 'UI'; +import {alertConditions as conditions} from 'App/constants'; import stl from './alertForm.module.css'; import DropdownChips from './DropdownChips'; -import { validateEmail } from 'App/validate'; +import {validateEmail} from 'App/validate'; import cn from 'classnames'; -import { useStore } from 'App/mstore' -import { observer } from 'mobx-react-lite' +import {useStore} from 'App/mstore' +import {observer} from 'mobx-react-lite' import Select from 'Shared/Select'; +import {Button} from "antd"; const thresholdOptions = [ - { label: '15 minutes', value: 15 }, - { label: '30 minutes', value: 30 }, - { label: '1 hour', value: 60 }, - { label: '2 hours', value: 120 }, - { label: '4 hours', value: 240 }, - { label: '1 day', value: 1440 }, + {label: '15 minutes', value: 15}, + {label: '30 minutes', value: 30}, + {label: '1 hour', value: 60}, + {label: '2 hours', value: 120}, + {label: '4 hours', value: 240}, + {label: '1 day', value: 1440}, ]; const changeOptions = [ - { label: 'change', value: 'change' }, - { label: '% change', value: 'percent' }, + {label: 'change', value: 'change'}, + {label: '% change', value: 'percent'}, ]; -const Circle = ({ text }) => ( -
- {text} -
+const Circle = ({text}) => ( +
+ {text} +
); -const Section = ({ index, title, description, content }) => ( -
-
- -
- {title} - {description &&
{description}
} -
-
+const Section = ({index, title, description, content}) => ( +
+
+ +
+ {title} + {description &&
{description}
} +
+
-
{content}
-
+
{content}
+
); function AlertForm(props) { - const { - slackChannels, - msTeamsChannels, - webhooks, - onDelete, - style = { width: '580px', height: '100vh' }, - } = props; - const { alertsStore } = useStore() - const { - triggerOptions, - loading, - } = alertsStore - const instance = alertsStore.instance - const deleting = loading + const { + slackChannels, + msTeamsChannels, + webhooks, + onDelete, + style = {height: "calc('100vh - 40px')"}, + } = props; + const {alertsStore} = useStore() + const { + triggerOptions, + loading, + } = alertsStore + const instance = alertsStore.instance + const deleting = loading - const write = ({ target: { value, name } }) => alertsStore.edit({ [name]: value }); - const writeOption = (e, { name, value }) => alertsStore.edit({ [name]: value.value }); - const onChangeCheck = ({ target: { checked, name } }) => alertsStore.edit({ [name]: checked }); + const write = ({target: {value, name}}) => alertsStore.edit({[name]: value}); + const writeOption = (e, {name, value}) => alertsStore.edit({[name]: value.value}); + const onChangeCheck = ({target: {checked, name}}) => alertsStore.edit({[name]: checked}); - useEffect(() => { - void alertsStore.fetchTriggerOptions(); - }, []); + useEffect(() => { + void alertsStore.fetchTriggerOptions(); + }, []); - const writeQueryOption = (e, { name, value }) => { - const { query } = instance; - alertsStore.edit({ query: { ...query, [name]: value } }); - }; + const writeQueryOption = (e, {name, value}) => { + const {query} = instance; + alertsStore.edit({query: {...query, [name]: value}}); + }; - const writeQuery = ({ target: { value, name } }) => { - const { query } = instance; - alertsStore.edit({ query: { ...query, [name]: value } }); - }; + const writeQuery = ({target: {value, name}}) => { + const {query} = instance; + alertsStore.edit({query: {...query, [name]: value}}); + }; - const metric = - instance && instance.query.left - ? triggerOptions.find((i) => i.value === instance.query.left) - : null; - const unit = metric ? metric.unit : ''; - const isThreshold = instance.detectionMethod === 'threshold'; + const metric = + instance && instance.query.left + ? triggerOptions.find((i) => i.value === instance.query.left) + : null; + const unit = metric ? metric.unit : ''; + const isThreshold = instance.detectionMethod === 'threshold'; - return ( -
props.onSubmit(instance)} - id="alert-form" - > -
- -
-
- alertsStore.edit({ [name]: value })} - value={{ value: instance.detectionMethod }} - list={[ - { name: 'Threshold', value: 'threshold' }, - { name: 'Change', value: 'change' }, - ]} - /> -
- {isThreshold && - 'Eg. Alert me if memory.avg is greater than 500mb over the past 4 hours.'} - {!isThreshold && - 'Eg. Alert me if % change of memory.avg is greater than 10% over the past 4 hours compared to the previous 4 hours.'} -
-
-
- } - /> - -
- -
- {!isThreshold && ( -
- - i.value === instance.query.left)} - // onChange={ writeQueryOption } - onChange={({ value }) => - writeQueryOption(null, { name: 'left', value: value.value }) - } + return ( + props.onSubmit(instance)} + id="alert-form" + > +
+ -
- -
- -
- writeOption(null, {name: 'change', value})} + id="change-dropdown" + /> +
+ )} + +
+ + + writeQueryOption(null, {name: 'operator', value: value.value}) + } + /> + {unit && ( + <> + + {'test'} + + )} + {!unit && ( + + )} +
+
+ +
+ + writeOption(null, {name: 'previousPeriod', value})} + /> +
+ )} +
+ } + /> + +
+ +
+
+ + + + +
+ + {instance.slack && ( +
+ +
+ alertsStore.edit({slackInput: selected})} + /> +
+
+ )} + {instance.msteams && ( +
+ +
+ alertsStore.edit({msteamsInput: selected})} + /> +
+
+ )} + + {instance.email && ( +
+ +
+ alertsStore.edit({emailInput: selected})} + /> +
+
+ )} + + {instance.webhook && ( +
+ + alertsStore.edit({webhookInput: selected})} + /> +
+ )} +
} - /> - {unit && ( - <> - - {'test'} - - )} - {!unit && ( - - )} -
- - -
- - writeOption(null, { name: 'previousPeriod', value })} - /> -
- )} - } - /> -
- -
-
- - - - -
- - {instance.slack && ( -
- -
- alertsStore.edit({ slackInput: selected })} - /> -
+
+
+ +
+
- )} - {instance.msteams && ( -
- -
- alertsStore.edit({ msteamsInput: selected })} - /> -
+
+ {instance.exists() && ( + + )}
- )} - - {instance.email && ( -
- -
- alertsStore.edit({ emailInput: selected })} - /> -
-
- )} - - {instance.webhook && ( -
- - alertsStore.edit({ webhookInput: selected })} - /> -
- )}
- } - /> -
- -
-
- -
- -
-
- {instance.exists() && ( - - )} -
-
- - ); + + ); }; export default observer(AlertForm); diff --git a/frontend/app/components/Alerts/AlertFormModal/AlertFormModal.tsx b/frontend/app/components/Alerts/AlertFormModal/AlertFormModal.tsx index 3821a3f45..50e0c3cf6 100644 --- a/frontend/app/components/Alerts/AlertFormModal/AlertFormModal.tsx +++ b/frontend/app/components/Alerts/AlertFormModal/AlertFormModal.tsx @@ -1,10 +1,10 @@ -import React, { useEffect, useState } from 'react'; -import { SlideModal } from 'UI'; -import { useStore } from 'App/mstore' -import { observer } from 'mobx-react-lite' +import React, {useEffect, useState} from 'react'; +import {SlideModal} from 'UI'; +import {useStore} from 'App/mstore' +import {observer} from 'mobx-react-lite' import AlertForm from '../AlertForm'; -import { SLACK, TEAMS, WEBHOOK } from 'App/constants/schedule'; -import { confirm } from 'UI'; +import {SLACK, TEAMS, WEBHOOK} from 'App/constants/schedule'; +import {confirm} from 'UI'; interface Select { label: string; @@ -17,9 +17,10 @@ interface Props { metricId?: number; onClose?: () => void; } + function AlertFormModal(props: Props) { - const { alertsStore, settingsStore } = useStore() - const { metricId = null, showModal = false } = props; + const {alertsStore, settingsStore} = useStore() + const {metricId = null, showModal = false} = props; const [showForm, setShowForm] = useState(false); const webhooks = settingsStore.webhooks useEffect(() => { @@ -32,7 +33,7 @@ function AlertFormModal(props: Props) { const msTeamsChannels: Select[] = [] webhooks.forEach((hook) => { - const option = { value: hook.webhookId, label: hook.name } + const option = {value: hook.webhookId, label: hook.name} if (hook.type === SLACK) { slackChannels.push(option) } diff --git a/frontend/app/components/Dashboard/components/WidgetView/CardViewMenu.tsx b/frontend/app/components/Dashboard/components/WidgetView/CardViewMenu.tsx new file mode 100644 index 000000000..a90ff63f1 --- /dev/null +++ b/frontend/app/components/Dashboard/components/WidgetView/CardViewMenu.tsx @@ -0,0 +1,99 @@ +import {useHistory} from "react-router"; +import {useStore} from "App/mstore"; +import {useObserver} from "mobx-react-lite"; +import {Button, Drawer, Dropdown, MenuProps, message, Modal} from "antd"; +import {BellIcon, EllipsisVertical, TrashIcon} from "lucide-react"; +import {toast} from "react-toastify"; +import React from "react"; +import {useModal} from "Components/ModalContext"; +import AlertFormModal from "Components/Alerts/AlertFormModal/AlertFormModal"; + +const CardViewMenu = () => { + const history = useHistory(); + const {alertsStore, dashboardStore, metricStore} = useStore(); + const widget = useObserver(() => metricStore.instance); + const {openModal, closeModal} = useModal(); + + const showAlertModal = () => { + const seriesId = widget.series[0] && widget.series[0].seriesId || ''; + alertsStore.init({query: {left: seriesId}}) + openModal(, { + // title: 'Set Alerts', + placement: 'right', + width: 620, + }); + } + + const items: MenuProps['items'] = [ + { + key: 'alert', + label: "Set Alerts", + icon: , + disabled: !widget.exists() || widget.metricType === 'predefined', + onClick: showAlertModal, + }, + { + key: 'remove', + danger: true, + label: 'Remove', + icon: , + onClick: () => { + Modal.confirm({ + title: 'Are you sure you want to remove this card?', + icon: null, + // content: 'Bla bla ...', + footer: (_, {OkBtn, CancelBtn}) => ( + <> + + + + ), + onOk: () => { + metricStore.delete(widget).then(r => { + history.goBack(); + }).catch(() => { + toast.error('Failed to remove card'); + }); + }, + }) + } + }, + ]; + + const onClick: MenuProps['onClick'] = ({key}) => { + if (key === 'alert') { + message.info('Set Alerts'); + } else if (key === 'remove') { + Modal.confirm({ + title: 'Are you sure you want to remove this card?', + icon: null, + // content: 'Bla bla ...', + footer: (_, {OkBtn, CancelBtn}) => ( + <> + + + + ), + onOk: () => { + metricStore.delete(widget).then(r => { + history.goBack(); + }).catch(() => { + toast.error('Failed to remove card'); + }); + }, + }) + } + }; + + return ( +
+ +
+ ); +}; + +export default CardViewMenu; diff --git a/frontend/app/components/Dashboard/components/WidgetView/WidgetViewHeader.tsx b/frontend/app/components/Dashboard/components/WidgetView/WidgetViewHeader.tsx index 4fc81338a..49a22e3a1 100644 --- a/frontend/app/components/Dashboard/components/WidgetView/WidgetViewHeader.tsx +++ b/frontend/app/components/Dashboard/components/WidgetView/WidgetViewHeader.tsx @@ -5,10 +5,8 @@ import {useStore} from "App/mstore"; import {useObserver} from "mobx-react-lite"; import AddToDashboardButton from "Components/Dashboard/components/AddToDashboardButton"; import WidgetDateRange from "Components/Dashboard/components/WidgetDateRange/WidgetDateRange"; -import {Button, Dropdown, MenuProps, Space, message, Modal} from "antd"; -import {BellIcon, EllipsisVertical, TrashIcon} from "lucide-react"; -import {useHistory} from "react-router"; -import {toast} from "react-toastify"; +import {Button, Space} from "antd"; +import CardViewMenu from "Components/Dashboard/components/WidgetView/CardViewMenu"; interface Props { onClick?: () => void; @@ -48,55 +46,3 @@ function WidgetViewHeader({onClick, onSave, undoChanges}: Props) { } export default WidgetViewHeader; - -const CardViewMenu = () => { - const history = useHistory(); - const {dashboardStore, metricStore} = useStore(); - const widget = useObserver(() => metricStore.instance); - const items: MenuProps['items'] = [ - { - key: 'alert', - label: "Set Alerts", - icon: , - }, - { - key: 'remove', - danger: true, - label: 'Remove', - icon: , - }, - ]; - - const onClick: MenuProps['onClick'] = ({key}) => { - if (key === 'alert') { - message.info('Set Alerts'); - } else if (key === 'remove') { - Modal.confirm({ - title: 'Are you sure you want to remove this card?', - icon: null, - // content: 'Bla bla ...', - footer: (_, {OkBtn, CancelBtn}) => ( - <> - - - - ), - onOk: () => { - metricStore.delete(widget).then(r => { - history.goBack(); - }).catch(() => { - toast.error('Failed to remove card'); - }); - }, - }) - } - }; - - return ( -
- -
- ); -}; diff --git a/frontend/app/components/Dashboard/components/WidgetWrapper/AlertButton.tsx b/frontend/app/components/Dashboard/components/WidgetWrapper/AlertButton.tsx index 6ff3ddda0..c9cbac62f 100644 --- a/frontend/app/components/Dashboard/components/WidgetWrapper/AlertButton.tsx +++ b/frontend/app/components/Dashboard/components/WidgetWrapper/AlertButton.tsx @@ -3,6 +3,8 @@ import WidgetIcon from './WidgetIcon'; import {useStore} from 'App/mstore'; import {Button} from "antd"; import {BellIcon} from "lucide-react"; +import {useModal} from "Components/ModalContext"; +import AlertFormModal from "Components/Alerts/AlertFormModal/AlertFormModal"; interface Props { seriesId: string; @@ -12,9 +14,17 @@ interface Props { function AlertButton(props: Props) { const {seriesId} = props; const {dashboardStore, alertsStore} = useStore(); + const {openModal, closeModal} = useModal(); const onClick = () => { - dashboardStore.toggleAlertModal(true); + // dashboardStore.toggleAlertModal(true); alertsStore.init({query: {left: seriesId}}) + openModal(, { + // title: 'Set Alerts', + placement: 'right', + width: 620, + }); } return (