Skip to content

Commit

Permalink
Notifications-improvements (#2318)
Browse files Browse the repository at this point in the history
* chore: add ability for a second details row with mantime react table

* fix: move resource to own row, to allow for long names

* refactor: reduce type scope for topology link inputs

* refactor: use query params for opening the notification modal

* feat: add link to notification rule

* fix: don't reload silences on dismiss modal

* refactor: anchor the silence edit form to url for open state
  • Loading branch information
mainawycliffe authored Oct 8, 2024
1 parent 4708ad9 commit fb607bd
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 28 deletions.
21 changes: 20 additions & 1 deletion src/api/services/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,13 @@ export const getNotificationSendHistory = async ({
};

export const getNotificationSendHistoryById = async (id: string) => {
const selectColumns = [
"*"
// `notification:notification_id(*,notification_type)`
].join(",");

const res = await IncidentCommander.get<NotificationSendHistoryApiResponse[]>(
`/notification_send_history_summary?id=eq.${id}`
`/notification_send_history_summary?id=eq.${id}&select=${selectColumns}`
);
return res.data?.[0];
};
Expand Down Expand Up @@ -154,6 +159,20 @@ export const getNotificationSilences = async ({
);
};

export const getNotificationSilencesByID = async (id: string) => {
const selectColumns = ["*"].join(",");

const res = await IncidentCommander.get<NotificationSilenceItem[] | null>(
`/notification_silences?select=${selectColumns}&order=created_at.desc&id=eq.${id}`,
{
headers: {
Prefer: "count=exact"
}
}
);
return res.data?.[0] ?? undefined;
};

export const deleteNotificationSilence = async (id: string) => {
return IncidentCommander.patch<NotificationSilenceItem>(
`/notification_silences?id=eq.${id}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import VerticalDescription from "@flanksource-ui/ui/description/VerticalDescript
import { formatDuration } from "@flanksource-ui/utils/date";
import clsx from "clsx";
import { useMemo } from "react";
import { Link } from "react-router-dom";
import NotificationResourceDisplay from "../NotificationResourceDisplay";
import { notificationSendHistoryStatus } from "../NotificationsStatusCell";

Expand Down Expand Up @@ -42,10 +43,12 @@ export default function NotificationDetails({
return (
<div className="flex flex-col gap-3 overflow-auto">
<div className="grid grid-cols-4 gap-3">
<VerticalDescription
label="Resource"
value={<NotificationResourceDisplay notification={notification} />}
/>
<div className="col-span-4">
<VerticalDescription
label="Resource"
value={<NotificationResourceDisplay notification={notification} />}
/>
</div>
<VerticalDescription
label="Age"
value={
Expand Down Expand Up @@ -91,6 +94,20 @@ export default function NotificationDetails({
{readableTime && (
<VerticalDescription label="Duration" value={readableTime} />
)}

<div className="col-span-2">
<VerticalDescription
label="Notification Rule"
value={
<Link
className="text-blue-500 hover:cursor-pointer hover:underline"
to={`/notifications/rules?id=${notification.notification_id}`}
>
Notification Rule
</Link>
}
/>
</div>
</div>

{notification.body && (
Expand Down
23 changes: 14 additions & 9 deletions src/components/Notifications/Rules/NotificationsRulesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { NotificationRules } from "@flanksource-ui/api/types/notifications";
import { Modal } from "@flanksource-ui/ui/Modal";
import MRTDataTable from "@flanksource-ui/ui/MRTDataTable/MRTDataTable";
import { useAtom } from "jotai";
import { useCallback, useState } from "react";
import { useCallback } from "react";
import { useSearchParams } from "react-router-dom";
import EditNotificationRules from "./EditNotificationRules";
import {
notificationMostCommonErrorAtom,
Expand All @@ -24,9 +25,10 @@ export default function NotificationsRulesTable({
pageCount,
totalRecordCount
}: NotificationsTableProps) {
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedNotificationId, setSelectedNotificationId] =
useState<string>();
const [searchParams, setSearchParams] = useSearchParams();

const selectedNotificationId = searchParams.get("id");

const [mostCommonErrorNotification, setMostCommonErrorNotification] = useAtom(
notificationMostCommonErrorAtom
);
Expand All @@ -38,10 +40,10 @@ export default function NotificationsRulesTable({
const onSelectNotification = useCallback(
(notification: NotificationRules) => {
const id = notification.id;
setSelectedNotificationId(id);
setIsModalOpen(true);
searchParams.set("id", id);
setSearchParams(searchParams);
},
[]
[searchParams, setSearchParams]
);

return (
Expand All @@ -68,8 +70,11 @@ export default function NotificationsRulesTable({
/>
{selectedNotificationId && (
<EditNotificationRules
isModalOpen={isModalOpen}
setIsModalOpen={setIsModalOpen}
isModalOpen={!!selectedNotificationId}
setIsModalOpen={() => {
searchParams.delete("id");
setSearchParams(searchParams);
}}
notificationId={selectedNotificationId}
refresh={refresh}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import NotificationSilenceForm from "./NotificationSilenceForm";
type EditNotificationSilenceModalProps = {
isOpen: boolean;
onClose: () => void;
onUpdate: () => void;
data: SilenceNotificationResponse;
};

export default function EditNotificationSilenceModal({
isOpen,
onClose,
data
onClose = () => {},
data,
onUpdate = () => {}
}: EditNotificationSilenceModalProps) {
return (
<Modal
Expand All @@ -24,7 +26,7 @@ export default function EditNotificationSilenceModal({
<NotificationSilenceForm
data={data}
footerClassName="bg-gray-100 p-4 flex flex-row justify-end gap-2"
onSuccess={() => onClose()}
onSuccess={onUpdate}
onCancel={onClose}
/>
</div>
Expand Down
34 changes: 27 additions & 7 deletions src/components/Notifications/SilenceNotificationsList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { deleteNotificationSilence } from "@flanksource-ui/api/services/notifications";
import {
deleteNotificationSilence,
getNotificationSilencesByID
} from "@flanksource-ui/api/services/notifications";
import { NotificationSilenceItemApiResponse } from "@flanksource-ui/api/types/notifications";
import { tables } from "@flanksource-ui/context/UserAccessContext/permissions";
import { Age } from "@flanksource-ui/ui/Age";
Expand All @@ -10,11 +13,12 @@ import { MRTCellProps } from "@flanksource-ui/ui/MRTDataTable/MRTCellProps";
import MRTDataTable from "@flanksource-ui/ui/MRTDataTable/MRTDataTable";
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
import { DotsVerticalIcon } from "@heroicons/react/solid";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { MRT_ColumnDef } from "mantine-react-table";
import { useState } from "react";
import { BiRepeat } from "react-icons/bi";
import { BsTrash } from "react-icons/bs";
import { useSearchParams } from "react-router-dom";
import { CheckLink } from "../Canary/HealthChecks/CheckLink";
import ConfigLink from "../Configs/ConfigLink/ConfigLink";
import { withAuthorizationAccessCheck } from "../Permissions/AuthorizationAccessCheck";
Expand Down Expand Up @@ -198,15 +202,26 @@ export default function SilenceNotificationsList({
recordCount,
refresh = () => {}
}: NotificationSendHistoryListProps) {
const [selectedNotificationSilence, setSelectedNotificationSilence] =
useState<NotificationSilenceItemApiResponse>();
const [searchParams, setSearchParams] = useSearchParams();

const selectedNotificationSilenceId = searchParams.get("id") ?? undefined;

const { data: selectedNotificationSilence } = useQuery({
queryKey: ["notification_silences", selectedNotificationSilenceId],
enabled: !!selectedNotificationSilenceId,
queryFn: async () =>
getNotificationSilencesByID(selectedNotificationSilenceId!)
});

return (
<>
<MRTDataTable
data={data}
columns={silenceNotificationListColumns}
onRowClick={(row) => setSelectedNotificationSilence(row)}
onRowClick={(row) => {
searchParams.set("id", row.id);
setSearchParams(searchParams);
}}
isLoading={isLoading}
manualPageCount={pageCount}
enableServerSidePagination={true}
Expand All @@ -215,10 +230,15 @@ export default function SilenceNotificationsList({
{selectedNotificationSilence && (
<EditNotificationSilenceModal
isOpen={!!selectedNotificationSilence}
onClose={() => {
setSelectedNotificationSilence(undefined);
onUpdate={() => {
searchParams.delete("id");
setSearchParams(searchParams);
refresh();
}}
onClose={() => {
searchParams.delete("id");
setSearchParams(searchParams);
}}
data={selectedNotificationSilence}
/>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/components/Topology/TopologyLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function TopologyLink({
linkClassName
}: {
topologyId?: string | undefined;
topology?: Topology;
topology?: Pick<Topology, "id" | "icon" | "name">;
viewType?: "link" | "label";
size?: "xl" | "lg" | "md" | "sm" | "xs";
className?: string;
Expand Down Expand Up @@ -77,7 +77,7 @@ function TopologyLinkLocal({
className = "mr-1 h-5 w-5 object-center",
linkClassName = "my-auto flex flex-row items-center hover:text-gray-500"
}: {
topology?: Component | undefined | null;
topology?: Pick<Component, "id" | "icon" | "name"> | undefined | null;
viewType?: "link" | "label";
size?: "xl" | "lg" | "md" | "sm" | "xs";
className?: string;
Expand Down
11 changes: 9 additions & 2 deletions src/ui/MRTDataTable/MRTDataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
MantineReactTable,
MRT_ColumnDef,
MRT_Row,
MRT_TableInstance,
useMantineReactTable
} from "mantine-react-table";
import useReactTablePaginationState from "../DataTable/Hooks/useReactTablePaginationState";
Expand All @@ -23,6 +24,10 @@ type MRTDataTableProps<T extends Record<string, any> = {}> = {
* pagination to determine the total number of pages.
*/
totalRowCount?: number;
renderDetailPanel?: (props: {
row: MRT_Row<T>;
table: MRT_TableInstance<T>;
}) => React.ReactNode;
};

export default function MRTDataTable<T extends Record<string, any> = {}>({
Expand All @@ -35,7 +40,8 @@ export default function MRTDataTable<T extends Record<string, any> = {}>({
enableServerSidePagination = false,
manualPageCount,
totalRowCount,
hiddenColumns = []
hiddenColumns = [],
renderDetailPanel
}: MRTDataTableProps<T>) {
const { pageIndex, pageSize, setPageIndex } = useReactTablePaginationState();
const [sortState, setSortState] = useReactTableSortState();
Expand Down Expand Up @@ -104,7 +110,8 @@ export default function MRTDataTable<T extends Record<string, any> = {}>({
},
mantinePaginationProps: {
rowsPerPageOptions: ["50", "100", "200"]
}
},
renderDetailPanel
});

return <MantineReactTable table={table} />;
Expand Down

0 comments on commit fb607bd

Please sign in to comment.