Skip to content

Commit

Permalink
Incident management improvements (#304)
Browse files Browse the repository at this point in the history
* feat: Add multiple filters for listing alerts

* add asset_name and status to multiple filters search

* feat: Add asset_name and status filters to multiple filters search

* refactor: update precommit order

* chore: update dependencies in frontend

* chore: add pnpm lock file

* refactor: remove package.json from backend

* chore: update precommit

* refactor: update badge component style

* feat: add badge style on alert asset component

* feat: add assets badges on alert card

* refactor: sigma actions box style

* added tags to multiple filters

* feat: add new alerts filters handler

* feat: add new alert filters api

* feat: update alerts filters handler

* add distinct to sql queries

* removed commented out code

* refactor: incident-management alert types

* feat: improvements on DX and UX

* feat: now list info-bar is clickable

* refactor: lint and format

* precommit fixes

---------

Co-authored-by: Davide Di Modica <webmaster.ddm@gmail.com>
  • Loading branch information
taylorwalton and Linko91 authored Sep 24, 2024
1 parent 50513ef commit d578e6d
Show file tree
Hide file tree
Showing 31 changed files with 13,975 additions and 1,740 deletions.
5 changes: 0 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,6 @@ repos:
- id: flake8
name: Check project styling

- repo: https://github.com/pre-commit/mirrors-prettier
rev: "v3.0.0"
hooks:
- id: prettier

- repo: https://github.com/pre-commit/mirrors-eslint
rev: v9.11.0
hooks:
Expand Down
44 changes: 44 additions & 0 deletions backend/app/incidents/routes/db_operations.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import io
from typing import List
from typing import Optional

from fastapi import APIRouter
Expand Down Expand Up @@ -604,17 +605,48 @@ async def list_alerts_multiple_filters_endpoint(
alert_title: Optional[str] = Query(None),
customer_code: Optional[str] = Query(None),
source: Optional[str] = Query(None),
asset_name: Optional[str] = Query(None),
status: Optional[str] = Query(None),
tags: Optional[List[str]] = Query(None),
page: int = Query(1, ge=1),
page_size: int = Query(25, ge=1),
order: str = Query("desc", regex="^(asc|desc)$"),
db: AsyncSession = Depends(get_db),
):
"""
Endpoint to list alerts with multiple filters.
Parameters:
- assigned_to (str, optional): Filter by assigned user.
- alert_title (str, optional): Filter by alert title.
- customer_code (str, optional): Filter by customer code.
- source (str, optional): Filter by source.
- asset_name (str, optional): Filter by asset name.
- status (str, optional): Filter by status.
- tags (List[str], optional): Filter by tags.
- page (int, default=1): Page number.
- page_size (int, default=25): Number of alerts per page.
- order (str, default='desc'): Sorting order ('asc' or 'desc').
- db (AsyncSession): Database session.
Returns:
- alerts (List[AlertOut]): List of alerts matching the filters.
- total (int): Total number of alerts matching the filters.
- open (int): Number of open alerts matching the filters.
- in_progress (int): Number of alerts in progress matching the filters.
- closed (int): Number of closed alerts matching the filters.
- success (bool): Indicates if the operation was successful.
- message (str): Success message.
"""
return AlertOutResponse(
alerts=await list_alerts_multiple_filters(
assigned_to=assigned_to,
alert_title=alert_title,
customer_code=customer_code,
source=source,
asset_name=asset_name,
status=status,
tags=tags,
db=db,
page=page,
page_size=page_size,
Expand All @@ -625,27 +657,39 @@ async def list_alerts_multiple_filters_endpoint(
alert_title=alert_title,
customer_code=customer_code,
source=source,
asset_name=asset_name,
status=status,
tags=tags,
db=db,
),
open=await alerts_open_multiple_filters(
assigned_to=assigned_to,
alert_title=alert_title,
customer_code=customer_code,
source=source,
asset_name=asset_name,
status=status,
tags=tags,
db=db,
),
in_progress=await alerts_in_progress_multiple_filters(
assigned_to=assigned_to,
alert_title=alert_title,
customer_code=customer_code,
source=source,
asset_name=asset_name,
status=status,
tags=tags,
db=db,
),
closed=await alerts_closed_multiple_filters(
assigned_to=assigned_to,
alert_title=alert_title,
customer_code=customer_code,
source=source,
asset_name=asset_name,
status=status,
tags=tags,
db=db,
),
success=True,
Expand Down
86 changes: 82 additions & 4 deletions backend/app/incidents/services/db_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from sqlalchemy import asc
from sqlalchemy import delete
from sqlalchemy import desc
from sqlalchemy import distinct
from sqlalchemy import func
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
Expand Down Expand Up @@ -194,6 +195,9 @@ async def alerts_total_multiple_filters(
alert_title: Optional[str] = None,
customer_code: Optional[str] = None,
source: Optional[str] = None,
asset_name: Optional[str] = None,
status: Optional[str] = None,
tags: Optional[List[str]] = None,
) -> int:
# Build dynamic filters
filters = []
Expand All @@ -205,9 +209,22 @@ async def alerts_total_multiple_filters(
filters.append(Alert.customer_code == customer_code)
if source:
filters.append(Alert.source == source)
if asset_name:
filters.append(Asset.asset_name == asset_name)
if status:
filters.append(Alert.status == status)
if tags:
filters.append(AlertTag.tag.in_(tags))

# Build the query
query = select(func.count()).select_from(Alert).where(*filters)
query = (
select(func.count(distinct(Alert.id)))
.select_from(Alert)
.join(Asset, isouter=True)
.join(AlertToTag, isouter=True)
.join(AlertTag, AlertToTag.tag_id == AlertTag.id, isouter=True)
.where(*filters)
)

result = await db.execute(query)
total = result.scalar_one()
Expand All @@ -220,6 +237,9 @@ async def alerts_closed_multiple_filters(
alert_title: Optional[str] = None,
customer_code: Optional[str] = None,
source: Optional[str] = None,
asset_name: Optional[str] = None,
status: Optional[str] = None,
tags: Optional[List[str]] = None,
) -> int:
# Include the status filter
filters = [Alert.status == "CLOSED"]
Expand All @@ -231,8 +251,21 @@ async def alerts_closed_multiple_filters(
filters.append(Alert.customer_code == customer_code)
if source:
filters.append(Alert.source == source)
if asset_name:
filters.append(Asset.asset_name == asset_name)
if status:
filters.append(Alert.status == status)
if tags:
filters.append(AlertTag.tag.in_(tags))

query = select(func.count()).select_from(Alert).where(*filters)
query = (
select(func.count(distinct(Alert.id)))
.select_from(Alert)
.join(Asset, isouter=True)
.join(AlertToTag, isouter=True)
.join(AlertTag, AlertToTag.tag_id == AlertTag.id, isouter=True)
.where(*filters)
)

result = await db.execute(query)
closed_count = result.scalar_one()
Expand All @@ -245,6 +278,9 @@ async def alerts_in_progress_multiple_filters(
alert_title: Optional[str] = None,
customer_code: Optional[str] = None,
source: Optional[str] = None,
asset_name: Optional[str] = None,
status: Optional[str] = None,
tags: Optional[List[str]] = None,
) -> int:
filters = [Alert.status == "IN_PROGRESS"]
if assigned_to:
Expand All @@ -255,8 +291,21 @@ async def alerts_in_progress_multiple_filters(
filters.append(Alert.customer_code == customer_code)
if source:
filters.append(Alert.source == source)
if asset_name:
filters.append(Asset.asset_name == asset_name)
if status:
filters.append(Alert.status == status)
if tags:
filters.append(AlertTag.tag.in_(tags))

query = select(func.count()).select_from(Alert).where(*filters)
query = (
select(func.count(distinct(Alert.id)))
.select_from(Alert)
.join(Asset, isouter=True)
.join(AlertToTag, isouter=True)
.join(AlertTag, AlertToTag.tag_id == AlertTag.id, isouter=True)
.where(*filters)
)

result = await db.execute(query)
in_progress_count = result.scalar_one()
Expand All @@ -269,6 +318,9 @@ async def alerts_open_multiple_filters(
alert_title: Optional[str] = None,
customer_code: Optional[str] = None,
source: Optional[str] = None,
asset_name: Optional[str] = None,
status: Optional[str] = None,
tags: Optional[List[str]] = None,
) -> int:
filters = [Alert.status == "OPEN"]
if assigned_to:
Expand All @@ -279,8 +331,21 @@ async def alerts_open_multiple_filters(
filters.append(Alert.customer_code == customer_code)
if source:
filters.append(Alert.source == source)
if asset_name:
filters.append(Asset.asset_name == asset_name)
if status:
filters.append(Alert.status == status)
if tags:
filters.append(AlertTag.tag.in_(tags))

query = select(func.count()).select_from(Alert).where(*filters)
query = (
select(func.count(distinct(Alert.id)))
.select_from(Alert)
.join(Asset, isouter=True)
.join(AlertToTag, isouter=True)
.join(AlertTag, AlertToTag.tag_id == AlertTag.id, isouter=True)
.where(*filters)
)

result = await db.execute(query)
open_count = result.scalar_one()
Expand Down Expand Up @@ -1475,6 +1540,9 @@ async def list_alerts_multiple_filters(
alert_title: Optional[str] = None,
customer_code: Optional[str] = None,
source: Optional[str] = None,
asset_name: Optional[str] = None,
status: Optional[str] = None,
tags: Optional[List[str]] = None,
page: int = 1,
page_size: int = 25,
order: str = "desc",
Expand All @@ -1492,10 +1560,20 @@ async def list_alerts_multiple_filters(
filters.append(Alert.customer_code == customer_code)
if source:
filters.append(Alert.source == source)
if asset_name:
filters.append(Asset.asset_name == asset_name)
if status:
filters.append(Alert.status == status)
if tags:
filters.append(AlertTag.tag.in_(tags))

# Build the query with dynamic filters
query = (
select(Alert)
.distinct(Alert.id)
.join(Asset, isouter=True) # Join with Asset table
.join(AlertToTag, isouter=True) # Join with AlertToTag table
.join(AlertTag, AlertToTag.tag_id == AlertTag.id, isouter=True) # Join with AlertTag table
.where(*filters)
.options(
selectinload(Alert.comments),
Expand Down
Loading

0 comments on commit d578e6d

Please sign in to comment.