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

Feat: alert history timeline remaining subtasks except graphs #5720

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
41b2b79
feat: alert history basic tabs and fitlers UI
ahmadshaheer Aug 7, 2024
d6af80e
feat: route based tabs for alert history and overview and improve the…
ahmadshaheer Aug 7, 2024
08c8a2e
feat: implement timeline table sorting
ahmadshaheer Aug 19, 2024
9241acd
chore: add initial count to see more and alert labels
ahmadshaheer Aug 19, 2024
fd7ec9b
chore: move PaginationInfoText component to /periscope
ahmadshaheer Aug 19, 2024
8e71d57
chore: implement top contributor rows using Ant Table
ahmadshaheer Aug 19, 2024
ced75ef
feat: top contributors view all
ahmadshaheer Aug 19, 2024
fd40d85
fix: hide border for last row and prevent layout shift in top contrib…
ahmadshaheer Aug 19, 2024
39ce337
feat: properly display duration in average resolution time
ahmadshaheer Aug 19, 2024
c6156c4
fix: properly display normal alert rule state
ahmadshaheer Aug 19, 2024
89b7347
feat: add/remove view all top contributors param to url on opening/cl…
ahmadshaheer Aug 19, 2024
77f8304
feat: calculate start and end time from relative time and add/remove …
ahmadshaheer Aug 19, 2024
bee4d43
fix: fix console warnings
ahmadshaheer Aug 20, 2024
ce89e4b
fix: enable timeline table query only if start and end times exist
ahmadshaheer Aug 20, 2024
cf008c2
feat: handle enable/disable alert rule toggle request
ahmadshaheer Aug 20, 2024
c2bd076
chore: replace string values with constants
ahmadshaheer Aug 20, 2024
48cf928
fix: hide stats card if only past data is available + remove unnecess…
ahmadshaheer Aug 20, 2024
7b224ff
fix: redirect configure alert rule to alert overview tab
ahmadshaheer Aug 21, 2024
fe2b986
fix: display total triggers in timeline chart wrapper based on API re…
ahmadshaheer Aug 21, 2024
88df039
fix: choosing the same relative time doesn't udpate start and end time
ahmadshaheer Aug 21, 2024
2f9cc1d
Feat: total triggered and avg. resolution time graph (#5750)
ahmadshaheer Aug 27, 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
4 changes: 4 additions & 0 deletions frontend/src/api/alerts/patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ const patch = async (
payload: response.data.data,
};
} catch (error) {
if (window.location.href.includes('alerts/history')) {
throw error as AxiosError;
}

return ErrorResponseHandler(error as AxiosError);
}
};
Expand Down
33 changes: 33 additions & 0 deletions frontend/src/api/alerts/timelineGraph.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { AlertRuleTimelineGraphResponsePayload } from 'types/api/alerts/def';
import { GetTimelineGraphRequestProps } from 'types/api/alerts/timelineGraph';

const timelineGraph = async (
props: GetTimelineGraphRequestProps,
): Promise<
SuccessResponse<AlertRuleTimelineGraphResponsePayload> | ErrorResponse
> => {
try {
const response = await axios.post(
`/rules/${props.id}/history/overall_status`,
{
start: props.start,
end: props.end,
},
);

return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};

export default timelineGraph;
1 change: 1 addition & 0 deletions frontend/src/api/alerts/timelineTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const timelineTable = async (
offset: props.offset,
limit: props.limit,
order: props.order,
state: props.state,
// TODO(shaheer): implement filters
filters: props.filters,
});
Expand Down
9 changes: 6 additions & 3 deletions frontend/src/components/AlertDetailsFilters/Filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import './filters.styles.scss';

import { Button } from 'antd';
import { QueryParams } from 'constants/query';
import { RelativeTimeMap } from 'container/TopNav/DateTimeSelection/config';
import DateTimeSelector from 'container/TopNav/DateTimeSelectionV2';
import useUrlQuery from 'hooks/useUrlQuery';
import { Undo } from 'lucide-react';
Expand All @@ -10,18 +11,20 @@ import { useHistory } from 'react-router-dom';
export function Filters(): JSX.Element {
const urlQuery = useUrlQuery();
const history = useHistory();
const relativeTime = urlQuery.get(QueryParams.relativeTime);

const handleFiltersReset = (): void => {
urlQuery.delete(QueryParams.relativeTime);

urlQuery.set(QueryParams.relativeTime, RelativeTimeMap['30min']);
urlQuery.delete(QueryParams.startTime);
urlQuery.delete(QueryParams.endTime);
history.replace({
pathname: history.location.pathname,
search: `?${urlQuery.toString()}`,
});
};
return (
<div className="filters">
{urlQuery.has(QueryParams.relativeTime) && (
{relativeTime !== RelativeTimeMap['30min'] && (
<Button
type="default"
className="reset-button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,10 @@
background: var(--Ink-300, #16181d);
border: 1px solid var(--Slate-400, #1d212d);
}

.lightMode {
.reset-button {
background: var(--bg-vanilla-100);
border-color: var(--bg-vanilla-300);
}
}
5 changes: 5 additions & 0 deletions frontend/src/constants/reactQueryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ export const REACT_QUERY_KEY = {
GET_FEATURES_FLAGS: 'GET_FEATURES_FLAGS',
DELETE_DASHBOARD: 'DELETE_DASHBOARD',
LOGS_PIPELINE_PREVIEW: 'LOGS_PIPELINE_PREVIEW',
ALERT_RULE_DETAILS: 'ALERT_RULE_DETAILS',
ALERT_RULE_STATS: 'ALERT_RULE_STATS',
ALERT_RULE_TOP_CONTRIBUTORS: 'ALERT_RULE_TOP_CONTRIBUTORS',
ALERT_RULE_TIMELINE_TABLE: 'ALERT_RULE_TIMELINE_TABLE',
ALERT_RULE_TIMELINE_GRAPH: 'ALERT_RULE_TIMELINE_GRAPH',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.alert-popover {
cursor: pointer;
}
122 changes: 97 additions & 25 deletions frontend/src/container/AlertHistory/AlertPopover/AlertPopover.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,113 @@
import './AlertPopover.styles.scss';

import { Popover } from 'antd';
import LogsIcon from 'assets/AlertHistory/LogsIcon';
import ROUTES from 'constants/routes';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { DraftingCompass } from 'lucide-react';
import React from 'react';
import { Link } from 'react-router-dom';

type Props = { children: React.ReactNode };
type Props = {
children: React.ReactNode;
relatedTracesLink?: string;
relatedLogsLink?: string;
};

function PopoverContent(): JSX.Element {
function PopoverContent({
relatedTracesLink,
relatedLogsLink,
}: {
relatedTracesLink?: Props['relatedTracesLink'];
relatedLogsLink?: Props['relatedLogsLink'];
}): JSX.Element {
const isDarkMode = useIsDarkMode();
return (
<div className="contributor-row-popover-buttons">
<div className="contributor-row-popover-buttons__button">
<div className="icon">
<LogsIcon />
</div>
<div className="text">View Logs</div>
</div>
<div className="contributor-row-popover-buttons__button">
<div className="icon">
<DraftingCompass size={14} color="var(--text-vanilla-400)" />
</div>
<div className="text">View Traces</div>
</div>
{!!relatedTracesLink && (
<Link
to={`${ROUTES.LOGS_EXPLORER}?${relatedTracesLink}`}
className="contributor-row-popover-buttons__button"
>
<div className="icon">
<LogsIcon />
</div>
<div className="text">View Logs</div>
</Link>
)}
{!!relatedLogsLink && (
<Link
to={`${ROUTES.TRACES_EXPLORER}?${relatedLogsLink}`}
className="contributor-row-popover-buttons__button"
>
<div className="icon">
<DraftingCompass
size={14}
color={isDarkMode ? 'var(--bg-vanilla-400)' : 'var(--text-ink-400'}
/>
</div>
<div className="text">View Traces</div>
</Link>
)}
</div>
);
}
function AlertPopover({ children }: Props): JSX.Element {
PopoverContent.defaultProps = {
relatedTracesLink: '',
relatedLogsLink: '',
};

function AlertPopover({
children,
relatedTracesLink,
relatedLogsLink,
}: Props): JSX.Element {
return (
<Popover
showArrow={false}
placement="bottom"
color="linear-gradient(139deg, rgba(18, 19, 23, 1) 0%, rgba(18, 19, 23, 1) 98.68%)"
destroyTooltipOnHide
content={<PopoverContent />}
trigger="click"
>
{children}
</Popover>
<div className="alert-popover">
<Popover
showArrow={false}
placement="bottom"
color="linear-gradient(139deg, rgba(18, 19, 23, 1) 0%, rgba(18, 19, 23, 1) 98.68%)"
destroyTooltipOnHide
content={
<PopoverContent
relatedTracesLink={relatedTracesLink}
relatedLogsLink={relatedLogsLink}
/>
}
trigger="click"
>
{children}
</Popover>
</div>
);
}

AlertPopover.defaultProps = {
relatedTracesLink: '',
relatedLogsLink: '',
};

type ConditionalAlertPopoverProps = {
relatedTracesLink: string;
relatedLogsLink: string;
children: React.ReactNode;
};
export function ConditionalAlertPopover({
children,
relatedTracesLink,
relatedLogsLink,
}: ConditionalAlertPopoverProps): JSX.Element {
if (relatedTracesLink || relatedLogsLink) {
return (
<AlertPopover
relatedTracesLink={relatedTracesLink}
relatedLogsLink={relatedLogsLink}
>
{children}
</AlertPopover>
);
}
return <div>{children}</div>;
}
export default AlertPopover;
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import { AlertRuleStats } from 'types/api/alerts/def';
import { formatTime } from 'utils/timeUtils';

import StatsCard from '../StatsCard/StatsCard';

type TotalTriggeredCardProps = {
currentAvgResolutionTime: AlertRuleStats['currentAvgResolutionTime'];
pastAvgResolutionTime: AlertRuleStats['pastAvgResolutionTime'];
timeSeries: AlertRuleStats['currentAvgResolutionTimeSeries']['values'];
};

function AverageResolutionCard({
currentAvgResolutionTime,
pastAvgResolutionTime,
timeSeries,
}: TotalTriggeredCardProps): JSX.Element {
return (
<StatsCard
displayValue={formatTime(currentAvgResolutionTime)}
totalCurrentCount={currentAvgResolutionTime}
totalPastCount={pastAvgResolutionTime}
title="Avg. Resolution Time"
timeSeries={timeSeries}
/>
);
}
Expand Down
11 changes: 8 additions & 3 deletions frontend/src/container/AlertHistory/Statistics/Statistics.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import './statistics.styles.scss';

import { useState } from 'react';
import { AlertRuleStats } from 'types/api/alerts/def';

import StatsCardsRenderer from './StatsCardsRenderer/StatsCardsRenderer';
import TopContributorsRenderer from './TopContributorsRenderer/TopContributorsRenderer';

function Statistics(): JSX.Element {
const [totalCurrentTriggers, setTotalCurrentTriggers] = useState(0);
function Statistics({
setTotalCurrentTriggers,
totalCurrentTriggers,
}: {
setTotalCurrentTriggers: (value: number) => void;
totalCurrentTriggers: AlertRuleStats['totalCurrentTriggers'];
}): JSX.Element {
return (
<div className="statistics">
<StatsCardsRenderer setTotalCurrentTriggers={setTotalCurrentTriggers} />
Expand Down
Loading
Loading