Skip to content

Commit

Permalink
Impl [Projects Alerts] Add “Alerts Table” (#2908)
Browse files Browse the repository at this point in the history
  • Loading branch information
pinis-gini-apps authored Dec 5, 2024
1 parent a034b73 commit 5ba4f95
Show file tree
Hide file tree
Showing 18 changed files with 1,292 additions and 111 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"final-form-arrays": "^3.1.0",
"fs-extra": "^10.0.0",
"identity-obj-proxy": "^3.0.0",
"iguazio.dashboard-react-controls": "2.2.7",
"iguazio.dashboard-react-controls": "2.2.8",
"is-wsl": "^1.1.0",
"js-base64": "^2.5.2",
"js-yaml": "^4.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ const FeatureVectors = lazyRetry(
const ProjectsJobsMonitoring = lazyRetry(
() => import('./components/ProjectsJobsMonitoring/ProjectsJobsMonitoring')
)
const ProjectsAlerts = lazyRetry(() => import('./components/ProjectsAlerts/ProjectsAlerts'))
const ProjectsAlerts = lazyRetry(() => import('./components/Alerts/Alerts'))
const JobsMonitoring = lazyRetry(
() => import('./components/ProjectsJobsMonitoring/JobsMonitoring/JobsMonitoring')
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,29 @@ 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 { useCallback, useMemo } from 'react'

import ProjectAlertsView from './ProjectsAlertsView'

import { getAlertsFiltersConfig, parseAlertsQueryParamsCallback } from './alerts.util'
import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook'

const ProjectsAlerts = () => {
const alertsFiltersConfig = useMemo(() => getAlertsFiltersConfig(), [])

const alertsFilters = useFiltersFromSearchParams(
alertsFiltersConfig,
parseAlertsQueryParamsCallback
)

const refreshAlertsCallback = useCallback(() => {}, [])

return (
<ProjectAlertsView
filters={alertsFilters}
alertsFiltersConfig={alertsFiltersConfig}
refreshAlertsCallback={refreshAlertsCallback}
/>
)
import { mainHttpClient } from '../httpClient'

const alertsApi = {
getAlerts: (project, filters, config = {}) => {
// TODO:ML-8514 update newConfig
const newConfig = {
...config,
params: {
...config.params
}
}
return mainHttpClient.get(`/projects/${project}/alert-activations`, newConfig)
},
getAlert: (project, alertName, config) => {
// TODO:ML-8514 update newConfig
const newConfig = {
...config,
params: {
...config.params
}
}
return mainHttpClient.get('/projects/{project}/alerts/{alertName}/activations', newConfig)
}
}

export default ProjectsAlerts
export default alertsApi
137 changes: 137 additions & 0 deletions src/components/Alerts/Alerts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
Copyright 2019 Iguazio Systems Ltd.
Licensed under the Apache License, Version 2.0 (the "License") with
an addition restriction as set forth herein. You may not use this
file except in compliance with the License. You may obtain a copy of
the License at http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
In addition, you may not use the software for any purposes that are
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 { useCallback, useMemo, useRef, useState } from 'react'
import { useParams, useSearchParams } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'

import AlertsView from './AlertsView'

import { getAlertsFiltersConfig, parseAlertsQueryParamsCallback } from './alerts.util'
import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook'

import { fetchAlerts } from '../../reducers/alertsReducer'
import { useVirtualization } from '../../hooks/useVirtualization.hook'
import { createAlertRowData } from '../../utils/createAlertsContent'
import { useInitialTableFetch } from '../../hooks/useInitialTableFetch.hook'

import cssVariables from './alerts.scss'

const Alerts = () => {
const [alerts, setAlerts] = useState([])
const [requestErrorMessage, setRequestErrorMessage] = useState('')
const [selectedAlert] = useState({})
const [selectedRowData] = useState({})
const params = useParams()
const [, setSearchParams] = useSearchParams()
const dispatch = useDispatch()
const alertsStore = useSelector(state => state.alertsStore)
const filtersStore = useSelector(store => store.filtersStore)

const abortControllerRef = useRef(new AbortController())

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

const alertsFilters = useFiltersFromSearchParams(
alertsFiltersConfig,
parseAlertsQueryParamsCallback
)

const fetchData = useCallback(
filters => {
abortControllerRef.current = new AbortController()
dispatch(
fetchAlerts({
project: params.id,
filters,
config: {
ui: {
controller: abortControllerRef.current,
setRequestErrorMessage
},
params: {
format: 'minimal'
}
}
})
)
.unwrap()
.then(alerts => {
if (alerts?.length > 0) {
setAlerts(alerts)
} else {
setAlerts([])
}
})
},
[dispatch, params.id]
)

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

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

return fetchData(filters)
},
[fetchData]
)

useInitialTableFetch({
fetchData,
filters: alertsFilters
})

const virtualizationConfig = useVirtualization({
rowsData: {
content: tableContent,
expandedRowsData: selectedRowData,
selectedItem: selectedAlert
},
heightData: {
headerRowHeight: cssVariables.$alertsHeaderRowHeight,
rowHeight: cssVariables.$alertsRowHeight,
rowHeightExtended: cssVariables.$alertsRowHeightExtended
},
activateTableScroll: true
})

return (
<AlertsView
alerts={alerts}
alertsFiltersConfig={alertsFiltersConfig}
alertsStore={alertsStore}
actionsMenu={() => []} // TODO
filters={alertsFilters}
filtersStore={filtersStore}
pageData={{}} //TODO
refreshAlertsCallback={refreshAlertsCallback}
requestErrorMessage={requestErrorMessage}
selectedAlert={selectedAlert}
setSearchParams={setSearchParams}
tableContent={tableContent}
virtualizationConfig={virtualizationConfig}
/>
)
}

export default Alerts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ 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 { useMemo } from 'react'
import { useCallback, useEffect, useMemo } from 'react'

import { truncate } from 'lodash'
import { truncate, upperFirst } from 'lodash'
import { useForm, useFormState } from 'react-final-form'
import { useSelector } from 'react-redux'

import StatusFilter from '../../common/StatusFilter/StatusFilter'
import { FormSelect, FormInput } from 'igz-controls/components'
import { FormOnChange } from 'iguazio.dashboard-react-controls/dist/components'

Expand All @@ -45,12 +46,11 @@ import {
FILTER_ALL_ITEMS,
JOB,
JOB_NAME,
PROJECT_FILTER,
PROJECTS_FILTER,
SEVERITY
} from '../../constants'
import StatusFilter from '../../common/StatusFilter/StatusFilter'

const ProjectsAlertsFilters = () => {
const AlertsFilters = () => {
const form = useForm()
const {
values: { [ENTITY_TYPE]: entityType }
Expand All @@ -67,14 +67,30 @@ const ProjectsAlertsFilters = () => {
}))
}, [projectStore.projectsNames.data])

const getFieldsToReset = useCallback(entityType => {
const fieldsByType = {
[FILTER_ALL_ITEMS]: [ENTITY_ID],
[APPLICATION]: [ENTITY_ID],
[JOB]: [JOB_NAME],
[ENDPOINT]: [ENDPOINT_APPLICATION, ENDPOINT_RESULT]
}
const allFields = [ENTITY_ID, JOB_NAME, ENDPOINT_APPLICATION, ENDPOINT_RESULT]

return allFields.filter(field => !(fieldsByType[entityType] ?? []).includes(field))
}, [])

useEffect(() => {
getFieldsToReset(entityType).forEach(field => form.change(field, ''))
}, [entityType, form, getFieldsToReset])

const handleInputChange = (value, inputName) => {
form.change(inputName, value || '')
}

return (
<>
<div className="form-row">
<FormSelect label="Project name" name={PROJECT_FILTER} options={projectsList} />
<FormSelect label="Project name" name={PROJECTS_FILTER} options={projectsList} />
</div>
<div className="form-row">
<FormSelect
Expand All @@ -86,13 +102,13 @@ const ProjectsAlertsFilters = () => {

{(entityType === FILTER_ALL_ITEMS || entityType === APPLICATION) && (
<div className="form-row">
<FormInput label="Endpoint ID" name={ENTITY_ID} placeholder="Search by ID" />
<FormInput label="Entity ID" name={ENTITY_ID} placeholder="Search by ID" />
<FormOnChange handler={value => handleInputChange(value, ENTITY_ID)} name={ENTITY_ID} />
</div>
)}
{entityType === JOB && (
<div className="form-row">
<FormInput label="Job" name={JOB_NAME} placeholder="Search by job name" />
<FormInput label={upperFirst(JOB)} name={JOB_NAME} placeholder="Search by job name" />
<FormOnChange handler={value => handleInputChange(value, JOB_NAME)} name={JOB_NAME} />
</div>
)}
Expand Down Expand Up @@ -132,4 +148,4 @@ const ProjectsAlertsFilters = () => {
)
}

export default ProjectsAlertsFilters
export default AlertsFilters
Loading

0 comments on commit 5ba4f95

Please sign in to comment.