Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Impl [Alerts history] Add “Expandable Alert Table” with Expanded Rows #2982

Merged
merged 29 commits into from
Dec 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
bb0bb80
add applcaition drill down to alerts table
pinis-gini-apps Dec 14, 2024
a1275d7
update alerts.util,alerts-api, add fetchProjects action to Alerts
pinis-gini-apps Dec 14, 2024
70d08cf
Merge branch 'development' into ML-8514
pinis-gini-apps Dec 15, 2024
22aa970
update generateRequestParamsalerts in alerts reducer
pinis-gini-apps Dec 15, 2024
4799a0e
merge with development
pinis-gini-apps Dec 16, 2024
040cef2
rebase with ML-8104
pinis-gini-apps Dec 16, 2024
8ea9b46
update hidden property to projectName column
pinis-gini-apps Dec 17, 2024
9b56dfc
minor fix according to pr comment, fix bug with missing name property…
pinis-gini-apps Dec 17, 2024
f221006
update createAlertRowData logic for application type based on new str…
pinis-gini-apps Dec 17, 2024
0f5e925
add to generateRequestParams logic for the entity param, fix bug with…
pinis-gini-apps Dec 17, 2024
2114ce4
Merge branch 'development' into ML-8104
pinis-gini-apps Dec 17, 2024
63cb52e
merge with ML-8104
pinis-gini-apps Dec 17, 2024
e090a84
Merge branch 'development' into ML-8514
pinis-gini-apps Dec 17, 2024
b356916
add detailsMetrics to DetailsDrillDownAlert
pinis-gini-apps Dec 18, 2024
ce9a1fe
merge with ML-8514
pinis-gini-apps Dec 17, 2024
3c23e5c
add logs popup to alerts table jobs drilldown
pinis-gini-apps Dec 18, 2024
273f1cd
add missing copyright
pinis-gini-apps Dec 18, 2024
abb421c
merge with ML-8103
pinis-gini-apps Dec 19, 2024
2b0e609
add AlertsDetailsMetrics component
pinis-gini-apps Dec 19, 2024
f2b2f61
code refactoring
pinis-gini-apps Dec 19, 2024
1b0cd0e
merge with development
pinis-gini-apps Dec 21, 2024
2f18c56
fix getAlertIdentifier id, add alertId url param to alerts route
pinis-gini-apps Dec 21, 2024
1530da2
merge with ML-8103
pinis-gini-apps Dec 22, 2024
7a3a0b9
add basic expandable row logic to alerts table
pinis-gini-apps Dec 23, 2024
431d106
add DetailsAlertsMetrics to expended row
pinis-gini-apps Dec 24, 2024
02e6178
complete alerts endpoints logic
pinis-gini-apps Dec 25, 2024
1fbc096
merge with development
pinis-gini-apps Dec 25, 2024
d6456bb
fix github comments, add missing value.hidden to AlertsTableRow
pinis-gini-apps Dec 26, 2024
898f31e
fix css issues
pinis-gini-apps Dec 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/common/TabsSlider/TabsSlider.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ const TabsSlider = ({
className={tabClassName}
data-tab={tab.id}
to={generateUrlFromRouterPath(
`${window.location.pathname?.replace(/^$|([^/]+$)/, tab.id)}${location.search ?? ''}`
`${window.location.pathname?.replace(/^$|([^/]+$)/, tab.id)}${location.search ?? ''}${tab.query ?? ''}`
)}
onClick={() => onSelectTab(tab)}
key={tab.id}
Expand Down
1 change: 1 addition & 0 deletions src/components/ActionBar/ActionBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ const ActionBar = ({
onChange={(dates, isPredefined, optionId) =>
handleDateChange(dates, isPredefined, optionId, input, formState)
}
timeFrameLimit={filtersConfig[DATES_FILTER].timeFrameLimit}
type="date-range-time"
withLabels
/>
Expand Down
11 changes: 7 additions & 4 deletions src/components/Alerts/Alerts.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,23 @@ import AlertsView from './AlertsView'

import { ALERTS_PAGE } from '../../constants'
import { createAlertRowData } from '../../utils/createAlertsContent'
import { getAlertsFiltersConfig, parseAlertsQueryParamsCallback } from './alerts.util'
import { generatePageData } from './alerts.util'
import {
getAlertsFiltersConfig,
generatePageData,
parseAlertsQueryParamsCallback
} from './alerts.util'
import { getJobLogs } from '../../utils/getJobLogs.util'
import projectsAction from '../../actions/projects'
import { useAlertsPageData } from '../../hooks/useAlertsPageData'
import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook'

const Alerts = () => {
const [selectedAlert, setSelectedAlert] = useState({})
const { id: projectId } = useParams()
const [, setProjectsRequestErrorMessage] = useState('')
const alertsStore = useSelector(state => state.alertsStore)
const filtersStore = useSelector(store => store.filtersStore)
const dispatch = useDispatch()
const { id: projectId } = useParams()
const params = useParams()

const isCrossProjects = useMemo(() => projectId === '*', [projectId])
Expand Down Expand Up @@ -93,7 +96,7 @@ const Alerts = () => {
)

const pageData = useMemo(
() => generatePageData(handleFetchJobLogs, selectedAlert),
() => generatePageData(selectedAlert, handleFetchJobLogs),
[handleFetchJobLogs, selectedAlert]
)

Expand Down
18 changes: 10 additions & 8 deletions src/components/Alerts/AlertsFilters.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import {
SEVERITY
} from '../../constants'

const AlertsFilters = ({ isCrossProjects }) => {
const AlertsFilters = ({ isAlertsPage, isCrossProjects }) => {
const form = useForm()
const {
values: { [ENTITY_TYPE]: entityType }
Expand Down Expand Up @@ -94,13 +94,15 @@ const AlertsFilters = ({ isCrossProjects }) => {
<FormSelect label="Project name" name={PROJECTS_FILTER} options={projectsList} />
</div>
)}
<div className="form-row">
<FormSelect
label="Entity type"
name={ENTITY_TYPE}
options={filterAlertsEntityTypeOptions}
/>
</div>
{isAlertsPage && (
<div className="form-row">
<FormSelect
label="Entity type"
name={ENTITY_TYPE}
options={filterAlertsEntityTypeOptions}
/>
</div>
)}

{(entityType === FILTER_ALL_ITEMS || entityType === MODEL_MONITORING_APPLICATION) && (
<div className="form-row">
Expand Down
65 changes: 43 additions & 22 deletions src/components/Alerts/AlertsView.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ illegal under applicable law, and the grant of the foregoing license
under the Apache 2.0 license is conditioned upon your compliance with
such restriction.
*/
import classNames from 'classnames'
import PropTypes from 'prop-types'

import ActionBar from '../ActionBar/ActionBar'
Expand All @@ -32,9 +33,12 @@ import { ALERTS_FILTERS, ALERTS_PAGE } from '../../constants'
import { getNoDataMessage } from '../../utils/getNoDataMessage'
import { getCloseDetailsAlertLink } from '../../utils/link-helper.util'

import './alerts.scss'

const AlertsView = ({
alertsFiltersConfig,
alertsStore,
isAlertsPage = true,
filters,
filtersStore,
handleCancel,
Expand All @@ -46,16 +50,22 @@ const AlertsView = ({
requestErrorMessage,
selectedAlert,
setSearchParams,
tableContent
selectedRowData,
tableContent,
toggleRow
}) => {
const content = classNames('content', !isAlertsPage && 'alerts-table__content')

return (
<>
<div className="content-wrapper">
<div className="content__header">
<Breadcrumbs />
</div>
<div className="content">
<div className="table-container">
{isAlertsPage && (
<div className="content__header">
<Breadcrumbs />
</div>
)}
<div className={content}>
<div className="table-container alerts-table__container">
<div className="content__action-bar-wrapper">
<ActionBar
autoRefreshIsStopped={true}
Expand All @@ -68,7 +78,7 @@ const AlertsView = ({
withRefreshButton
withoutExpandButton
>
<AlertsFilters isCrossProjects={isCrossProjects} />
<AlertsFilters isAlertsPage={isAlertsPage} isCrossProjects={isCrossProjects} />
</ActionBar>
</div>
{alertsStore.loading ? (
Expand All @@ -88,27 +98,36 @@ const AlertsView = ({
<>
<Table
actionsMenu={[]}
getCloseDetailsLink={() => getCloseDetailsAlertLink()} //TODO: the getCloseDetailsLink will be updated with ML-8368
getCloseDetailsLink={() => getCloseDetailsAlertLink()}
pageData={pageData}
retryRequest={handleRefreshWithFilters}
selectedItem={selectedAlert}
selectedItem={isAlertsPage ? selectedAlert : {}}
tableClassName="alerts-table"
handleCancel={handleCancel}
hideActionsMenu
tableHeaders={tableContent[0]?.content ?? []}
withActionMenu={false}
>
{tableContent.map((tableItem, index) => (
<AlertsTableRow
key={index}
hideActionsMenu
handleSelectItem={() => {}}
rowIndex={index}
rowItem={tableItem}
actionsMenu={[]}
selectedItem={selectedAlert}
/>
))}
{tableContent.map((tableItem, index) => {
const isRowSelected = tableItem?.data?.id === selectedAlert?.id && !isAlertsPage
const selectedRowClassName = `${isRowSelected ? 'alert-row__cell--expanded-selected-cell' : ''} `
return (
<AlertsTableRow
className={selectedRowClassName}
key={index}
hideActionsMenu
handleSelectItem={() => {}}
filters={filters}
isRowSelected={isRowSelected}
rowIndex={index}
rowItem={tableItem}
actionsMenu={[]}
toggleRow={toggleRow}
selectedItem={selectedAlert}
selectedRowData={selectedRowData}
/>
)
})}
</Table>
<Pagination
page={pageData.page}
Expand All @@ -128,15 +147,17 @@ AlertsView.propTypes = {
alertsStore: PropTypes.object.isRequired,
filters: PropTypes.object.isRequired,
filtersStore: PropTypes.object.isRequired,
handleCancel: PropTypes.func.isRequired,
handleCancel: PropTypes.func,
handleRefreshAlerts: PropTypes.func.isRequired,
handleRefreshWithFilters: PropTypes.func.isRequired,
isAlertsPage: PropTypes.bool,
isCrossProjects: PropTypes.bool.isRequired,
pageData: PropTypes.object.isRequired,
paginationConfigAlertsRef: PropTypes.object.isRequired,
requestErrorMessage: PropTypes.string.isRequired,
selectedAlert: PropTypes.object.isRequired,
setSearchParams: PropTypes.func.isRequired,
tableContent: PropTypes.arrayOf(PropTypes.object).isRequired
tableContent: PropTypes.arrayOf(PropTypes.object).isRequired,
toggleRow: PropTypes.func
}
export default AlertsView
21 changes: 8 additions & 13 deletions src/components/Alerts/alerts.scss
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
@import '~igz-controls/scss/variables';
@import 'src/scss/mixins';

$alertsRowHeight: $rowHeight;
$alertsHeaderRowHeight: $headerRowHeight;
$alertsRowHeightExtended: $rowHeightExtended;

.alerts-table {
@include rowsHeight($alertsHeaderRowHeight, $alertsRowHeight, $alertsRowHeightExtended);
}
min-width: 1120px;

&__metrics {
margin: 8px 12px;
}

:export {
alertsRowHeight: $alertsRowHeight;
alertsHeaderRowHeight: $alertsHeaderRowHeight;
alertsRowHeightExtended: $alertsRowHeightExtended;
&__content {
padding: 0;
}
}
14 changes: 8 additions & 6 deletions src/components/Alerts/alerts.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,17 @@ import {
import {
datePickerPastOptions,
getDatePickerFilterValue,
PAST_24_HOUR_DATE_OPTION
PAST_24_HOUR_DATE_OPTION,
TIME_FRAME_LIMITS
} from '../../utils/datePicker.util'

export const getAlertsFiltersConfig = () => {
export const getAlertsFiltersConfig = (timeFrameLimit = false) => {
return {
[NAME_FILTER]: { label: 'Alert Name:', initialValue: '' },
[DATES_FILTER]: {
label: 'Start time:',
initialValue: getDatePickerFilterValue(datePickerPastOptions, PAST_24_HOUR_DATE_OPTION)
initialValue: getDatePickerFilterValue(datePickerPastOptions, PAST_24_HOUR_DATE_OPTION),
timeFrameLimit: timeFrameLimit ? TIME_FRAME_LIMITS.MONTH : Infinity
},
[PROJECTS_FILTER]: { label: 'Project:', initialValue: FILTER_ALL_ITEMS, isModal: true },
[ENTITY_TYPE]: { label: 'Entity Type:', initialValue: FILTER_ALL_ITEMS, isModal: true },
Expand Down Expand Up @@ -86,7 +88,7 @@ export const parseAlertsQueryParamsCallback = (paramName, paramValue) => {
return paramValue
}

export const generatePageData = (handleFetchJobLogs, selectedAlert) => {
export const generatePageData = (selectedAlert, handleFetchJobLogs = () => {}) => {
return {
page: ALERTS_PAGE,
details: {
Expand All @@ -109,8 +111,8 @@ export const allProjectsOption = [
export const filterAlertsEntityTypeOptions = [
{ label: upperFirst(FILTER_ALL_ITEMS), id: FILTER_ALL_ITEMS },
{ label: upperFirst(JOB), id: JOB_KIND_JOB },
{ label: upperFirst(ENDPOINT), id: 'model-endpoint-result' },
{ label: upperFirst(APPLICATION), id: 'model-monitoring-application' }
{ label: upperFirst(ENDPOINT), id: MODEL_ENDPOINT_RESULT },
{ label: upperFirst(APPLICATION), id: MODEL_MONITORING_APPLICATION }
]

export const filterAlertsSeverityOptions = [
Expand Down
86 changes: 78 additions & 8 deletions src/components/DetailsAlerts/DetailsAlerts.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,86 @@ illegal under applicable law, and the grant of the foregoing license
under the Apache 2.0 license is conditioned upon your compliance with
such restriction.
*/
import React, { useCallback, useMemo, useState } from 'react'
import { useSelector } from 'react-redux'

import React from 'react'
import AlertsView from '../Alerts/AlertsView'

import { createAlertRowData } from '../../utils/createAlertsContent'
import {
generatePageData,
getAlertsFiltersConfig,
parseAlertsQueryParamsCallback
} from '../../components/Alerts/alerts.util'
import { useAlertsPageData } from '../../hooks/useAlertsPageData'
import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook'

const DetailsAlerts = () => {
const [selectedAlert, setSelectedAlert] = useState({})
const alertsStore = useSelector(state => state.alertsStore)
const filtersStore = useSelector(store => store.filtersStore)

const alertsFiltersConfig = useMemo(() => getAlertsFiltersConfig(true), [])

const alertsFilters = useFiltersFromSearchParams(
alertsFiltersConfig,
parseAlertsQueryParamsCallback
)

const {
handleRefreshAlerts,
paginatedAlerts,
paginationConfigAlertsRef,
requestErrorMessage,
refreshAlerts,
setAlerts,
setSearchParams
} = useAlertsPageData(alertsFilters, false)

const handleRefreshWithFilters = useCallback(
filters => {
setAlerts([])

return refreshAlerts(filters)
},
[refreshAlerts, setAlerts]
)

const tableContent = useMemo(() => {
return paginatedAlerts.map(alert => createAlertRowData(alert, false, true))
}, [paginatedAlerts])

const pageData = useMemo(() => generatePageData(selectedAlert), [selectedAlert])

const toggleRow = useCallback(
(e, item) => {
setSelectedAlert(prev => {
const selectedAlert = tableContent.find(({ data }) => data?.id === item?.id)
return prev?.id !== item.id ? selectedAlert?.data || {} : {}
})
},
[tableContent]
)

const DetailsAlerts = ({ selectedItem }) => {
return (
<div>
<h2>Alerts</h2>
<p>This tab shows alerts for the selected item.</p>
</div>
<AlertsView
alerts={paginatedAlerts}
alertsFiltersConfig={alertsFiltersConfig}
alertsStore={alertsStore}
filters={alertsFilters}
filtersStore={filtersStore}
handleRefreshAlerts={handleRefreshAlerts}
handleRefreshWithFilters={handleRefreshWithFilters}
isAlertsPage={false}
isCrossProjects={false}
pageData={pageData}
paginationConfigAlertsRef={paginationConfigAlertsRef}
requestErrorMessage={requestErrorMessage}
selectedAlert={selectedAlert}
setSearchParams={setSearchParams}
tableContent={tableContent}
toggleRow={toggleRow}
/>
)
}

export default DetailsAlerts
export default React.memo(DetailsAlerts)
Loading
Loading