Skip to content

Commit

Permalink
feat: split incidents UI (#2881)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kiryous authored Dec 24, 2024
1 parent 4f769f0 commit 130023a
Show file tree
Hide file tree
Showing 34 changed files with 702 additions and 725 deletions.
3 changes: 1 addition & 2 deletions keep-ui/app/(keep)/alerts/alert-associate-incident-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Modal from "@/components/ui/Modal";
import { Button, Divider, Title } from "@tremor/react";
import Select from "@/components/ui/Select";
import { CreateOrUpdateIncidentForm } from "@/features/create-or-update-incident";
import { FormEvent, useCallback, useEffect, useState } from "react";
import { toast } from "react-toastify";
Expand All @@ -12,7 +11,7 @@ import Loading from "@/app/(keep)/loading";
import { AlertDto } from "@/entities/alerts/model";
import { getIncidentName } from "@/entities/incidents/lib/utils";
import { useApi } from "@/shared/lib/hooks/useApi";
import { showErrorToast } from "@/shared/ui";
import { Select, showErrorToast } from "@/shared/ui";

interface AlertAssociateIncidentModalProps {
isOpen: boolean;
Expand Down
43 changes: 1 addition & 42 deletions keep-ui/app/(keep)/alerts/alert-change-status-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import { Button, Title, Subtitle } from "@tremor/react";
import Modal from "@/components/ui/Modal";
import Select, {
CSSObjectWithLabel,
ControlProps,
OptionProps,
GroupBase,
} from "react-select";
import { useState } from "react";
import { AlertDto, Status } from "@/entities/alerts/model";
import { toast } from "react-toastify";
Expand All @@ -18,7 +12,7 @@ import {
} from "@heroicons/react/24/outline";
import { useAlerts } from "utils/hooks/useAlerts";
import { useApi } from "@/shared/lib/hooks/useApi";
import { showErrorToast } from "@/shared/ui";
import { Select, showErrorToast } from "@/shared/ui";

import { useRevalidateMultiple } from "@/shared/lib/state-utils";

Expand All @@ -30,40 +24,6 @@ const statusIcons = {
[Status.Pending]: <QuestionMarkCircleIcon className="w-4 h-4 mr-2" />,
};

const customSelectStyles = {
control: (
base: CSSObjectWithLabel,
state: ControlProps<
{ value: Status; label: JSX.Element },
false,
GroupBase<{ value: Status; label: JSX.Element }>
>
) => ({
...base,
borderColor: state.isFocused ? "orange" : base.borderColor,
boxShadow: state.isFocused ? "0 0 0 1px orange" : base.boxShadow,
"&:hover": {
borderColor: "orange",
},
}),
option: (
base: CSSObjectWithLabel,
{
isFocused,
}: OptionProps<
{ value: Status; label: JSX.Element },
false,
GroupBase<{ value: Status; label: JSX.Element }>
>
) => ({
...base,
backgroundColor: isFocused ? "rgba(255,165,0,0.1)" : base.backgroundColor,
"&:hover": {
backgroundColor: "rgba(255,165,0,0.2)",
},
}),
};

interface Props {
alert: AlertDto | null | undefined;
handleClose: () => void;
Expand Down Expand Up @@ -147,7 +107,6 @@ export default function AlertChangeStatusModal({
onChange={(option) => setSelectedStatus(option?.value || null)}
placeholder="Select new status"
className="ml-2"
styles={customSelectStyles}
/>
</div>
</Subtitle>
Expand Down
35 changes: 2 additions & 33 deletions keep-ui/app/(keep)/alerts/alert-pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,11 @@ import {
TableCellsIcon,
} from "@heroicons/react/16/solid";
import { Button, Text } from "@tremor/react";
import {
StylesConfig,
SingleValueProps,
components,
GroupBase,
} from "react-select";
import Select from "react-select";
import { SingleValueProps, components, GroupBase } from "react-select";
import { AlertDto } from "@/entities/alerts/model";
import { Table } from "@tanstack/react-table";
import { useAlerts } from "utils/hooks/useAlerts";
import { Select } from "@/shared/ui";

interface Props {
presetName: string;
Expand All @@ -29,31 +24,6 @@ interface OptionType {
label: string;
}

const customStyles: StylesConfig<OptionType, false, GroupBase<OptionType>> = {
control: (provided, state) => ({
...provided,
borderColor: state.isFocused ? "orange" : "rgb(229 231 235)",
borderRadius: "0.5rem",
"&:hover": { borderColor: "orange" },
boxShadow: state.isFocused ? "0 0 0 1px orange" : provided.boxShadow,
}),
singleValue: (provided) => ({
...provided,
display: "flex",
alignItems: "center",
}),
menu: (provided) => ({
...provided,
color: "orange",
}),
option: (provided, state) => ({
...provided,
backgroundColor: state.isSelected ? "orange" : provided.backgroundColor,
"&:hover": { backgroundColor: state.isSelected ? "orange" : "#f5f5f5" },
color: state.isSelected ? "white" : provided.color,
}),
};

const SingleValue = ({
children,
...props
Expand Down Expand Up @@ -82,7 +52,6 @@ export default function AlertPagination({
</Text>
<div className="flex gap-1">
<Select
styles={customStyles}
components={{ SingleValue }}
value={{
value: table.getState().pagination.pageSize.toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import Modal from "@/components/ui/Modal";
import { useProviders } from "utils/hooks/useProviders";
import ImageWithFallback from "@/components/ImageWithFallback";
import { useAlerts } from "utils/hooks/useAlerts";
import Select from "@/components/ui/Select";
import { useApi } from "@/shared/lib/hooks/useApi";
import { KeepApiError } from "@/shared/api";
import { Select } from "@/shared/ui";

import { useRevalidateMultiple } from "@/shared/lib/state-utils";

Expand Down
22 changes: 2 additions & 20 deletions keep-ui/app/(keep)/alerts/alerts-rules-builder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import {
} from "@/entities/alerts/model";
import { XMarkIcon, TrashIcon } from "@heroicons/react/24/outline";
import { TbDatabaseImport } from "react-icons/tb";
import Select, { components, MenuListProps } from "react-select";
import { components, MenuListProps } from "react-select";
import { Select } from "@/shared/ui";

import { IoSearchOutline } from "react-icons/io5";
import { FiExternalLink } from "react-icons/fi";
Expand Down Expand Up @@ -114,24 +115,6 @@ const customComponents = {
MenuList: CustomMenuList,
};

// Define the styles for react-select
const customStyles = {
option: (provided: any, state: any) => ({
...provided,
color: state.isFocused ? "black" : "black",
backgroundColor: state.isFocused ? "rgba(255, 165, 0, 0.4)" : "white", // Orange with opacity
cursor: "pointer",
display: "flex",
alignItems: "center", // Align items in the center vertically
}),
menu: (provided: any) => ({
...provided,
margin: 0, // Remove the margin around the dropdown menu
borderRadius: "0", // Optional: Align with the border-radius of the Textarea if necessary
}),
// You can add more style customizations for other parts of the Select here if needed
};

// Culled from: https://stackoverflow.com/a/54372020/12627235
const getAllMatches = (pattern: RegExp, string: string) =>
// make sure string is a String, and make sure pattern has the /g flag
Expand Down Expand Up @@ -608,7 +591,6 @@ export const AlertsRulesBuilder = ({
menuIsOpen={true}
components={minimal ? undefined : customComponents}
onBlur={() => setShowSuggestions(false)}
styles={customStyles}
/>
</div>
)}
Expand Down
19 changes: 8 additions & 11 deletions keep-ui/app/(keep)/deduplication/DeduplicationSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ import {
import { IoMdClose } from "react-icons/io";
import { DeduplicationRule } from "@/app/(keep)/deduplication/models";
import { useDeduplicationFields } from "utils/hooks/useDeduplicationRules";
import { GroupBase } from "react-select";
import Select from "@/components/ui/Select";
import MultiSelect from "@/components/ui/MultiSelect";
import { Select } from "@/shared/ui";
import {
ExclamationTriangleIcon,
InformationCircleIcon,
Expand Down Expand Up @@ -194,11 +192,8 @@ const DeduplicationSidebar: React.FC<DeduplicationSidebarProps> = ({
<div>
<Dialog.Title className="text-3xl font-bold" as={Title}>
{selectedDeduplicationRule
? "Edit Deduplication Rule"
: "Add Deduplication Rule"}
<Badge className="ml-4" color="orange">
Beta
</Badge>
? `Edit ${selectedDeduplicationRule.name}`
: "Add deduplication rule"}
{selectedDeduplicationRule?.default && (
<Badge className="ml-2" color="orange">
Default Rule
Expand Down Expand Up @@ -304,7 +299,7 @@ const DeduplicationSidebar: React.FC<DeduplicationSidebarProps> = ({
control={control}
rules={{ required: "Provider is required" }}
render={({ field }) => (
<Select<ProviderOption, false, GroupBase<ProviderOption>>
<Select
{...field}
isDisabled={!!selectedDeduplicationRule?.default}
options={alertProviders.map((provider) => ({
Expand Down Expand Up @@ -378,8 +373,9 @@ const DeduplicationSidebar: React.FC<DeduplicationSidebarProps> = ({
required: "At least one fingerprint field is required",
}}
render={({ field }) => (
<MultiSelect
<Select
{...field}
isMulti
options={availableFields.map((fieldName) => ({
value: fieldName,
label: fieldName,
Expand Down Expand Up @@ -452,8 +448,9 @@ const DeduplicationSidebar: React.FC<DeduplicationSidebarProps> = ({
name="ignore_fields"
control={control}
render={({ field }) => (
<MultiSelect
<Select
{...field}
isMulti
options={availableFields.map((fieldName) => ({
value: fieldName,
label: fieldName,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Button } from "@/components/ui";
import { useIncidentActions } from "@/entities/incidents/model/useIncidentActions";
import { SplitIncidentAlertsModal } from "@/features/split-incident-alerts";
import { useState } from "react";
import { LiaUnlinkSolid } from "react-icons/lia";

export function IncidentAlertsActions({
incidentId,
selectedFingerprints,
resetAlertsSelection,
}: {
incidentId: string;
selectedFingerprints: string[];
resetAlertsSelection: () => void;
}) {
const [isSplitModalOpen, setIsSplitModalOpen] = useState(false);
const { unlinkAlertsFromIncident } = useIncidentActions();

return (
<>
<div className="flex gap-2 justify-end">
<Button
variant="primary"
onClick={() => setIsSplitModalOpen(true)}
disabled={selectedFingerprints.length === 0}
>
Split
</Button>
<Button
variant="destructive"
icon={LiaUnlinkSolid}
onClick={async () => {
await unlinkAlertsFromIncident(incidentId, selectedFingerprints);
resetAlertsSelection();
}}
disabled={selectedFingerprints.length === 0}
>
Unlink
</Button>
</div>
{isSplitModalOpen && (
<SplitIncidentAlertsModal
sourceIncidentId={incidentId}
alertFingerprints={selectedFingerprints}
handleClose={() => setIsSplitModalOpen(false)}
onSuccess={resetAlertsSelection}
/>
)}
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use client";

import { TableBody, TableCell, TableRow } from "@tremor/react";
import type { Table as ReactTable } from "@tanstack/react-table";
import { AlertDto } from "@/entities/alerts/model";
import { getCommonPinningStylesAndClassNames } from "@/shared/ui";
import Skeleton from "react-loading-skeleton";
import "react-loading-skeleton/dist/skeleton.css";

export function IncidentAlertsTableBodySkeleton({
table,
pageSize,
}: {
table: ReactTable<AlertDto>;
pageSize: number;
}) {
return (
<TableBody>
{Array(pageSize)
.fill("")
.map((_, index) => (
<TableRow key={`row-${index}`}>
{table.getVisibleFlatColumns().map((column) => {
const { style, className } = getCommonPinningStylesAndClassNames(
column,
table.getState().columnPinning.left?.length,
table.getState().columnPinning.right?.length
);
return (
<TableCell
key={`cell-${column.id}-${index}`}
className={className}
style={style}
>
<Skeleton />
</TableCell>
);
})}
</TableRow>
))}
</TableBody>
);
}
Loading

0 comments on commit 130023a

Please sign in to comment.