add breadcrumbs

This commit is contained in:
Simon Larsen 2024-10-02 21:48:40 +01:00
parent ae79417fbc
commit e6b47d85d6
No known key found for this signature in database
GPG Key ID: 96C5DCA24769DBCA
6 changed files with 388 additions and 28 deletions

View File

@ -42,7 +42,7 @@ import ProbeMonitorResponse from "Common/Types/Probe/ProbeMonitorResponse";
import Typeof from "Common/Types/Typeof";
import MonitorMetricsByMinute from "Common/Models/AnalyticsModels/MonitorMetricsByMinute";
import Incident, {
TelemetryIncidentQuery,
TelemetryQuery,
} from "Common/Models/DatabaseModels/Incident";
import IncidentSeverity from "Common/Models/DatabaseModels/IncidentSeverity";
import IncidentStateTimeline from "Common/Models/DatabaseModels/IncidentStateTimeline";
@ -376,7 +376,7 @@ export default class MonitorResourceUtil {
}`,
);
let telemetryQuery: TelemetryIncidentQuery | undefined = undefined;
let telemetryQuery: TelemetryQuery | undefined = undefined;
if (dataToProcess && (dataToProcess as LogMonitorResponse).logQuery) {
telemetryQuery = {
@ -751,7 +751,7 @@ export default class MonitorResourceUtil {
Array<string>
>;
props: {
telemetryQuery?: TelemetryIncidentQuery | undefined;
telemetryQuery?: TelemetryQuery | undefined;
};
}): Promise<void> {
// criteria filters are met, now process the actions.

View File

@ -0,0 +1,37 @@
import PageMap from "../../Utils/PageMap";
import RouteMap, { RouteUtil } from "../../Utils/RouteMap";
import Route from "Common/Types/API/Route";
import ObjectID from "Common/Types/ObjectID";
import Link from "Common/UI/Components/Link/Link";
import Alert from "Common/Models/DatabaseModels/Alert";
import React, { FunctionComponent, ReactElement } from "react";
export interface ComponentProps {
alert: Alert;
onNavigateComplete?: (() => void) | undefined;
}
const AlertElement: FunctionComponent<ComponentProps> = (
props: ComponentProps,
): ReactElement => {
if (props.alert._id) {
return (
<Link
onNavigateComplete={props.onNavigateComplete}
className="hover:underline"
to={RouteUtil.populateRouteParams(
RouteMap[PageMap.INCIDENT_VIEW] as Route,
{
modelId: new ObjectID(props.alert._id as string),
},
)}
>
<span>{props.alert.title}</span>
</Link>
);
}
return <span>{props.alert.title}</span>;
};
export default AlertElement;

View File

@ -0,0 +1,288 @@
import LabelsElement from "../../Components/Label/Labels";
import DashboardNavigation from "../../Utils/Navigation";
import AlertElement from "./Alert";
import { Black } from "Common/Types/BrandColors";
import { JSONObject } from "Common/Types/JSON";
import FormValues from "Common/UI/Components/Forms/Types/FormValues";
import ConfirmModal from "Common/UI/Components/Modal/ConfirmModal";
import { ModalTableBulkDefaultActions } from "Common/UI/Components/ModelTable/BaseModelTable";
import ModelTable from "Common/UI/Components/ModelTable/ModelTable";
import Pill from "Common/UI/Components/Pill/Pill";
import FieldType from "Common/UI/Components/Types/FieldType";
import Query from "Common/Types/BaseDatabase/Query";
import Alert from "Common/Models/DatabaseModels/Alert";
import AlertSeverity from "Common/Models/DatabaseModels/AlertSeverity";
import AlertState from "Common/Models/DatabaseModels/AlertState";
import Label from "Common/Models/DatabaseModels/Label";
import Monitor from "Common/Models/DatabaseModels/Monitor";
import React, { FunctionComponent, ReactElement, useState } from "react";
import RouteMap, { RouteUtil } from "../../Utils/RouteMap";
import PageMap from "../../Utils/PageMap";
import MonitorElement from "../Monitor/Monitor";
export interface ComponentProps {
query?: Query<Alert> | undefined;
noItemsMessage?: string | undefined;
title?: string | undefined;
description?: string | undefined;
createInitialValues?: FormValues<Alert> | undefined;
disableCreate?: boolean | undefined;
}
const AlertsTable: FunctionComponent<ComponentProps> = (
props: ComponentProps,
): ReactElement => {
const [isLoading, setIsLoading] = useState<boolean>(true);
const [error, setError] = useState<string>("");
const [showAlertTemplateModal, setShowAlertTemplateModal] =
useState<boolean>(false);
const [initialValuesForAlert, setInitialValuesForAlert] =
useState<JSONObject>({});
return (
<>
<ModelTable<Alert>
name="Alerts"
bulkActions={{
buttons: [ModalTableBulkDefaultActions.Delete],
}}
onCreateEditModalClose={(): void => {
setInitialValuesForAlert({});
}}
modelType={Alert}
id="alerts-table"
isDeleteable={false}
showCreateForm={Object.keys(initialValuesForAlert).length > 0}
query={props.query || {}}
isEditable={false}
isCreateable={!props.disableCreate}
isViewable={true}
createInitialValues={
Object.keys(initialValuesForAlert).length > 0
? initialValuesForAlert
: props.createInitialValues
}
cardProps={{
title: props.title || "Alerts",
description:
props.description ||
"Here is a list of alerts for this project.",
}}
noItemsMessage={props.noItemsMessage || "No alerts found."}
showRefreshButton={true}
showViewIdButton={true}
viewPageRoute={RouteUtil.populateRouteParams(
RouteMap[PageMap.INCIDENTS]!,
)}
filters={[
{
title: "Alert ID",
type: FieldType.Text,
field: {
_id: true,
},
},
{
field: {
title: true,
},
title: "Title",
type: FieldType.Text,
},
{
field: {
alertSeverity: {
name: true,
},
},
title: "Severity",
type: FieldType.Entity,
filterEntityType: AlertSeverity,
filterQuery: {
projectId: DashboardNavigation.getProjectId()!,
},
filterDropdownField: {
label: "name",
value: "_id",
},
},
{
field: {
currentAlertState: {
name: true,
color: true,
},
},
title: "State",
type: FieldType.Entity,
filterEntityType: AlertState,
filterQuery: {
projectId: DashboardNavigation.getProjectId()!,
},
filterDropdownField: {
label: "name",
value: "_id",
},
},
{
field: {
monitor: {
name: true,
_id: true,
projectId: true,
},
},
title: "Monitor Affected",
type: FieldType.EntityArray,
filterEntityType: Monitor,
filterQuery: {
projectId: DashboardNavigation.getProjectId()!,
},
filterDropdownField: {
label: "name",
value: "_id",
},
},
{
field: {
createdAt: true,
},
title: "Created",
type: FieldType.Date,
},
{
field: {
labels: {
name: true,
},
},
title: "Labels",
type: FieldType.EntityArray,
filterEntityType: Label,
filterQuery: {
projectId: DashboardNavigation.getProjectId()!,
},
filterDropdownField: {
label: "name",
value: "_id",
},
},
]}
columns={[
{
field: {
title: true,
},
title: "Title",
type: FieldType.Element,
getElement: (item: Alert): ReactElement => {
return <AlertElement alert={item} />;
},
},
{
field: {
currentAlertState: {
name: true,
color: true,
},
},
title: "State",
type: FieldType.Entity,
getElement: (item: Alert): ReactElement => {
if (item["currentAlertState"]) {
return (
<Pill
isMinimal={true}
color={item.currentAlertState.color || Black}
text={item.currentAlertState.name || "Unknown"}
/>
);
}
return <></>;
},
},
{
field: {
alertSeverity: {
name: true,
color: true,
},
},
title: "Severity",
type: FieldType.Entity,
getElement: (item: Alert): ReactElement => {
if (item["alertSeverity"]) {
return (
<Pill
isMinimal={true}
color={item.alertSeverity.color || Black}
text={item.alertSeverity.name || "Unknown"}
/>
);
}
return <></>;
},
},
{
field: {
monitor: {
name: true,
_id: true,
projectId: true,
},
},
title: "Monitors Affected",
type: FieldType.EntityArray,
getElement: (item: Alert): ReactElement => {
return <MonitorElement monitor={item["monitor"]!} />;
},
},
{
field: {
createdAt: true,
},
title: "Created",
type: FieldType.DateTime,
},
{
field: {
labels: {
name: true,
color: true,
},
},
title: "Labels",
type: FieldType.EntityArray,
getElement: (item: Alert): ReactElement => {
return <LabelsElement labels={item["labels"] || []} />;
},
},
]}
/>
{error && (
<ConfirmModal
title={`Error`}
description={`${error}`}
submitButtonText={"Close"}
onSubmit={() => {
return setError("");
}}
/>
)}
</>
);
};
export default AlertsTable;

View File

@ -120,18 +120,7 @@ const AlertViewStateTimeline: FunctionComponent<PageComponentProps> = (
labelField: "name",
valueField: "_id",
},
},
{
field: {
shouldStatusPageSubscribersBeNotified: true,
},
title: "Notify Status Page Subscribers",
description: "Should status page subscribers be notified?",
fieldType: FormFieldSchemaType.Checkbox,
defaultValue: true,
required: false,
},
}
]}
showRefreshButton={true}
viewPageRoute={Navigation.getCurrentRoute()}
@ -223,14 +212,7 @@ const AlertViewStateTimeline: FunctionComponent<PageComponentProps> = (
</p>
);
},
},
{
field: {
shouldStatusPageSubscribersBeNotified: true,
},
title: "Subscribers Notified",
type: FieldType.Boolean,
},
}
]}
/>
{showViewLogsModal ? (

View File

@ -28,9 +28,7 @@ import BaseAPI from "Common/UI/Utils/API/API";
import GlobalEvent from "Common/UI/Utils/GlobalEvents";
import ModelAPI, { ListResult } from "Common/UI/Utils/ModelAPI/ModelAPI";
import Navigation from "Common/UI/Utils/Navigation";
import Incident, {
TelemetryIncidentQuery,
} from "Common/Models/DatabaseModels/Incident";
import Incident from "Common/Models/DatabaseModels/Incident";
import IncidentSeverity from "Common/Models/DatabaseModels/IncidentSeverity";
import IncidentState from "Common/Models/DatabaseModels/IncidentState";
import IncidentStateTimeline from "Common/Models/DatabaseModels/IncidentStateTimeline";
@ -48,6 +46,7 @@ import DashboardLogsViewer from "../../../Components/Logs/LogsViewer";
import TelemetryType from "Common/Types/Telemetry/TelemetryType";
import JSONFunctions from "Common/Types/JSONFunctions";
import TraceTable from "../../../Components/Traces/TraceTable";
import { TelemetryQuery } from "Common/Types/Telemetry/TelemetryQuery";
const IncidentView: FunctionComponent<
PageComponentProps
@ -63,7 +62,7 @@ const IncidentView: FunctionComponent<
const [isLoading, setIsLoading] = useState<boolean>(false);
const [telemetryQuery, setTelemetryQuery] =
useState<TelemetryIncidentQuery | null>(null);
useState<TelemetryQuery | null>(null);
const fetchData: PromiseVoidFunction = async (): Promise<void> => {
try {
@ -114,7 +113,7 @@ const IncidentView: FunctionComponent<
},
});
let telemetryQuery: TelemetryIncidentQuery | null = null;
let telemetryQuery: TelemetryQuery | null = null;
if (incident?.telemetryQuery) {
telemetryQuery = JSONFunctions.deserialize(

View File

@ -0,0 +1,54 @@
import PageMap from "../PageMap";
import { BuildBreadcrumbLinksByTitles } from "./Helper";
import Dictionary from "Common/Types/Dictionary";
import Link from "Common/Types/Link";
export function getAlertsBreadcrumbs(path: string): Array<Link> | undefined {
const breadcrumpLinksMap: Dictionary<Link[]> = {
...BuildBreadcrumbLinksByTitles(PageMap.ALERTS, [
"Project",
"Alerts",
]),
...BuildBreadcrumbLinksByTitles(PageMap.UNRESOLVED_ALERTS, [
"Project",
"Alerts",
"Active Alerts",
]),
...BuildBreadcrumbLinksByTitles(PageMap.ALERT_VIEW, [
"Project",
"Alerts",
"View Alert",
]),
...BuildBreadcrumbLinksByTitles(PageMap.ALERT_VIEW_STATE_TIMELINE, [
"Project",
"Alerts",
"View Alert",
"State Timeline",
]),
...BuildBreadcrumbLinksByTitles(PageMap.ALERT_VIEW_OWNERS, [
"Project",
"Alerts",
"View Alert",
"Owners",
]),
...BuildBreadcrumbLinksByTitles(PageMap.ALERT_INTERNAL_NOTE, [
"Project",
"Alerts",
"View Alert",
"Private Notes",
]),
...BuildBreadcrumbLinksByTitles(PageMap.ALERT_VIEW_CUSTOM_FIELDS, [
"Project",
"Alerts",
"View Alert",
"Custom Fields",
]),
...BuildBreadcrumbLinksByTitles(PageMap.ALERT_VIEW_DELETE, [
"Project",
"Alerts",
"View Alert",
"Delete Alert",
]),
};
return breadcrumpLinksMap[path];
}