Skip to content

Commit

Permalink
feat: add more fields options give alteast 3 options to select
Browse files Browse the repository at this point in the history
  • Loading branch information
rajesh-jonnalagadda committed Sep 29, 2024
1 parent 29fdff4 commit 4e49eb0
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 78 deletions.
100 changes: 47 additions & 53 deletions keep-ui/app/alerts/quality/alert-quality-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Provider, ProvidersResponse } from "app/providers/providers";
import { TabGroup, TabList, Tab } from "@tremor/react";
import { GenericFilters } from "@/components/filters/GenericFilters";
import { useSearchParams } from "next/navigation";
import { AlertKnownKeys } from "../models";

const tabs = [
{ name: "All", value: "alltime" },
Expand All @@ -28,20 +29,7 @@ const ALERT_QUALITY_FILTERS = [
value: "",
name: "Last received",
},
{
type: "select",
key: "fields",
value: "",
name: "Field",
options: [
{ value: "product", label: "Product" },
{ value: "department", label: "Department" },
{ value: "assignee", label: "Affected users" },
{ value: "service", label: "Service" },
],
only_one: true,
},
]
];

export const FilterTabs = ({
tabs,
Expand Down Expand Up @@ -93,8 +81,8 @@ const QualityTable = ({
providersMeta: ProvidersResponse | undefined;
alertsQualityMetrics: Record<string, Record<string, any>> | undefined;
isDashBoard?: boolean;
setFields: (fields: string|string[]|Record<string, string>) => void,
fieldsValue: string|string[]|Record<string, string>,
setFields: (fields: string | string[] | Record<string, string>) => void;
fieldsValue: string | string[] | Record<string, string>;
}) => {
const [pagination, setPagination] = useState<Pagination>({
limit: 10,
Expand All @@ -103,16 +91,12 @@ const QualityTable = ({
const customFieldFilter = {
type: "select",
key: "fields",
value: fieldsValue,
value: isDashBoard ? fieldsValue : "",
name: "Field",
options: [
{ value: "product", label: "Product" },
{ value: "department", label: "Department" },
{ value: "assignee", label: "Affected users" },
{ value: "service", label: "Service" },
],
only_one: true,
searchParamsNotNeed: true,
options: AlertKnownKeys.map((key) => ({ value: key, label: key })),
// only_one: true,
searchParamsNotNeed: isDashBoard,
can_select: 3,
setFilter: setFields,
};
const searchParams = useSearchParams();
Expand Down Expand Up @@ -141,7 +125,9 @@ const QualityTable = ({

return value;
}
const fields = toArray(params?.["fields"] || fieldsValue as string || []) as string[];
const fields = toArray(
params?.["fields"] || (fieldsValue as string | string[]) || []
) as string[];
const [tab, setTab] = useState(0);

const handlePaginationChange = (newLimit: number, newOffset: number) => {
Expand All @@ -168,11 +154,6 @@ const QualityTable = ({
accessorKey: "alertsCorrelatedToIncidentsPercentage",
cell: (info: any) => `${info.getValue().toFixed(2)}%`,
},
{
header: "% of Alerts Having Severity",
accessorKey: "alertsWithSeverityPercentage",
cell: (info: any) => `${info.getValue().toFixed(2)}%`,
},
];

// Add dynamic columns based on the fields
Expand Down Expand Up @@ -236,7 +217,8 @@ const QualityTable = ({
field.charAt(0).toUpperCase() + field.slice(1)
}Percentage`
] = totalAlertsReceived
? ((alertQuality?.[`${field}_count`] ?? 0) / totalAlertsReceived) * 100
? ((alertQuality?.[`${field}_count`] ?? 0) / totalAlertsReceived) *
100
: 0;
return acc;
}, {} as Record<string, number>);
Expand All @@ -254,15 +236,26 @@ const QualityTable = ({
}, [tab, providersMeta, alertsQualityMetrics, fields]);

return (
<div className="h-full p-2">
{!isDashBoard && <h1 className="text-lg font-semibold text-gray-800 dark:text-gray-100 mb-4">
Alert Quality Dashboard
</h1>}
<div className="flex justify-between items-end mb-4 h-[10%]">
<FilterTabs tabs={tabs} setTab={setTab} tab={tab} />
<GenericFilters filters={isDashBoard ? [customFieldFilter]: ALERT_QUALITY_FILTERS} />
<div
className={`flex flex-col gap-2 p-2 px-4 ${isDashBoard ? "h-[90%]" : ""}`}
>
<div>
{!isDashBoard && (
<h1 className="text-lg font-semibold text-gray-800 dark:text-gray-100 mb-4">
Alert Quality Dashboard
</h1>
)}
<div className="flex justify-between items-end mb-4">
<FilterTabs tabs={tabs} setTab={setTab} tab={tab} />
<GenericFilters
filters={
isDashBoard
? [customFieldFilter]
: [...ALERT_QUALITY_FILTERS, customFieldFilter]
}
/>
</div>
</div>
<div className="h-[90%]">
{finalData && (
<GenericTable
data={finalData}
Expand All @@ -277,26 +270,27 @@ const QualityTable = ({
}}
/>
)}
</div>
</div>
);
};

const AlertQuality = ({isDashBoard}:{isDashBoard?:boolean}) => {
const [fieldsValue, setFieldsValue] = useState<string|string[]|Record<string, string>>('');
const AlertQuality = ({ isDashBoard }: { isDashBoard?: boolean }) => {
const [fieldsValue, setFieldsValue] = useState<
string | string[] | Record<string, string>
>("severity");
const { data: providersMeta } = useProviders();
const { data: alertsQualityMetrics, error } = useAlertQualityMetrics(isDashBoard ? fieldsValue as string : "");
const { data: alertsQualityMetrics, error } = useAlertQualityMetrics(
isDashBoard ? (fieldsValue as string) : ""
);

return (
<div className={`px-4 h-full`}>
<QualityTable
providersMeta={providersMeta}
alertsQualityMetrics={alertsQualityMetrics}
isDashBoard={isDashBoard}
setFields={setFieldsValue}
fieldsValue= {fieldsValue}
/>
</div>
<QualityTable
providersMeta={providersMeta}
alertsQualityMetrics={alertsQualityMetrics}
isDashBoard={isDashBoard}
setFields={setFieldsValue}
fieldsValue={fieldsValue}
/>
);
};

Expand Down
58 changes: 40 additions & 18 deletions keep-ui/components/filters/GenericFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Filter = {
only_one?: boolean;
searchParamsNotNeed?: boolean;
setFilter?: (value: string | string[] | Record<string, string>) => void;
can_select?: number;
};

interface FiltersProps {
Expand All @@ -31,6 +32,7 @@ interface PopoverContentProps {
filterKey: string;
type: string;
only_one?: boolean;
can_select?: number;
}

function toArray(value: string | string[]) {
Expand All @@ -46,11 +48,13 @@ function toArray(value: string | string[]) {
function CustomSelect({
filter,
only_one,
handleSelect
handleSelect,
can_select,
}: {
filter: Filter | null;
handleSelect: (value: string | string[]) => void;
only_one?: boolean;
can_select?: number;
}) {
const filterKey = filter?.key || "";
const [selectedOptions, setSelectedOptions] = useState<Set<string>>(
Expand All @@ -62,7 +66,7 @@ function CustomSelect({
useEffect(() => {
if (filter) {
setSelectedOptions(new Set(toArray(filter.value as string | string[])));
setLocalFilter({...filter});
setLocalFilter({ ...filter });
}
}, [filter, filter?.value]);

Expand All @@ -71,18 +75,22 @@ function CustomSelect({
let updatedOptions = new Set(prev);
if (only_one) {
updatedOptions.clear();
}
if (checked) {
updatedOptions.add(option);
}
if (
checked &&
(!can_select || (can_select && updatedOptions.size < can_select))
) {
updatedOptions.add(option);
} else {
updatedOptions.delete(option);
}
let newValues = Array.from(updatedOptions)
setLocalFilter((prev)=>{
if(prev){
let newValues = Array.from(updatedOptions);
setLocalFilter((prev) => {
if (prev) {
return {
...prev, value: newValues
}
...prev,
value: newValues,
};
}
return prev;
});
Expand All @@ -95,11 +103,24 @@ function CustomSelect({
return null;
}

const name = `${filterKey?.charAt(0)?.toUpperCase() + filterKey?.slice(1)}`;

return (
<>
<div>
<span className="text-gray-400 text-sm">
Select {filterKey?.charAt(0)?.toUpperCase() + filterKey?.slice(1)}
Select {`${can_select ? `${can_select} ${name}` : name}`}
</span>
{can_select && (
<span
className={`text-xs text-gray-400 ${
selectedOptions.size >= can_select
? "text-red-500"
: "text-green-600"
}`}
>
({selectedOptions.size}/{can_select})
</span>
)}
<ul className="flex flex-col mt-3 max-h-96 overflow-auto">
{localFilter.options?.map((option) => (
<li key={option.value}>
Expand All @@ -117,7 +138,7 @@ function CustomSelect({
</li>
))}
</ul>
</>
</div>
);
}

Expand Down Expand Up @@ -155,7 +176,6 @@ function CustomDate({
const endDate = end || start;
const endOfDayDate = endDate ? endOfDay(endDate) : end;


setDateRange({ from: start ?? undefined, to: endOfDayDate ?? undefined });
handleDate(start, endOfDayDate);
};
Expand Down Expand Up @@ -187,11 +207,11 @@ const PopoverContent: React.FC<PopoverContentProps> = ({
filterKey,
type,
only_one,
can_select,
}) => {
// Initialize local state for selected options
const filter = filterRef.current?.find((filter) => filter.key === filterKey);


const handleSelect = (value: string | string[]) => {
if (filter) {
filter.value = value;
Expand Down Expand Up @@ -221,6 +241,7 @@ const PopoverContent: React.FC<PopoverContentProps> = ({
filter={filter ?? null}
handleSelect={handleSelect}
only_one={only_one}
can_select={can_select}
/>
);
case "date":
Expand Down Expand Up @@ -266,15 +287,15 @@ export const GenericFilters: React.FC<FiltersProps> = ({ filters }) => {
}
}
}
if((newParams?.toString() || "") !== searchParamString){
if ((newParams?.toString() || "") !== searchParamString) {
router.push(`${pathname}?${newParams.toString()}`);
}
for (const { key, value } of filterRef.current) {
const filter = filterRef.current.find(
(filter) => filter.key === key && filter.searchParamsNotNeed
);
if (filter) {
let newValue = Array.isArray(value) && value.length ==0 ? "" : value;
let newValue = Array.isArray(value) && value.length == 0 ? "" : value;
if (filter.setFilter) {
filter.setFilter(newValue || "");
}
Expand Down Expand Up @@ -335,7 +356,7 @@ export const GenericFilters: React.FC<FiltersProps> = ({ filters }) => {
return (
<div className="relative flex flex-col md:flex-row lg:flex-row gap-4 items-center">
{filters &&
filters?.map(({ key, type, name, icon, only_one }) => {
filters?.map(({ key, type, name, icon, only_one, can_select }) => {
//only type==select and date need popover i guess other text and textarea can be handled different. for now handling select and date
icon = icon ?? type === "date" ? MdOutlineDateRange : GoPlusCircle;
return (
Expand All @@ -349,6 +370,7 @@ export const GenericFilters: React.FC<FiltersProps> = ({ filters }) => {
filterKey={key}
type={type}
only_one={!!only_one}
can_select={can_select}
/>
}
onApply={() => setApply(true)}
Expand Down
20 changes: 17 additions & 3 deletions keep-ui/utils/hooks/useAlertQuality.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,34 @@ import useSWRImmutable from "swr/immutable";
import { useSearchParams } from "next/navigation";
import { useMemo } from "react";

export const useAlertQualityMetrics = (fields:string, options: SWRConfiguration = {}) => {
export const useAlertQualityMetrics = (
fields: string | string[],
options: SWRConfiguration = {}
) => {
const { data: session } = useSession();
const apiUrl = getApiURL();
const searchParams = useSearchParams();
``;
let filters = useMemo(() => {
let params = searchParams?.toString();
if (fields) {
params = params ? `${params}&fields=${fields}` : `fields=${fields}`;
fields = Array.isArray(fields) ? fields : [fields];
let fieldParams = new URLSearchParams("");
fields.forEach((field) => {
fieldParams.append("fields", field);
});
params = params
? `${params}&${fieldParams.toString()}`
: fieldParams.toString();
}
return params;
}, [fields, searchParams]);
// TODO: Proper type needs to be defined.
return useSWRImmutable<Record<string, Record<string, any>>>(
() => (session ? `${apiUrl}/alerts/quality/metrics${filters ? `?${filters}` : ""}` : null),
() =>
session
? `${apiUrl}/alerts/quality/metrics${filters ? `?${filters}` : ""}`
: null,
(url) => fetcher(url, session?.accessToken),
options
);
Expand Down
Loading

0 comments on commit 4e49eb0

Please sign in to comment.