Skip to content

Commit f7f4bb2

Browse files
Kiryoustalboren
andauthored
feat(ui): alerts table search polish (keephq#2675)
Co-authored-by: Tal <[email protected]>
1 parent 9e860e8 commit f7f4bb2

File tree

3 files changed

+129
-132
lines changed

3 files changed

+129
-132
lines changed

keep-ui/app/(keep)/alerts/alert-presets.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ export default function AlertPresets({
371371
<div className="space-y-2">
372372
<div className="flex items-center gap-2">
373373
<TextInput
374+
// TODO: don't show error until user tries to save
374375
error={!presetName}
375376
errorMessage="Preset name is required"
376377
placeholder={

keep-ui/app/(keep)/alerts/alert-table.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,9 @@ export function AlertTable({
273273

274274
return (
275275
// Add h-screen to make it full height and remove the default flex-col gap
276-
<div className="h-screen flex flex-col">
276+
<div className="h-screen flex flex-col gap-4">
277277
{/* Add padding to account for any top nav/header */}
278-
<div className="pt-4 px-4 flex-none">
278+
<div className="px-4 flex-none">
279279
<TitleAndFilters
280280
table={table}
281281
alerts={alerts}
@@ -285,7 +285,7 @@ export function AlertTable({
285285
</div>
286286

287287
{/* Make actions/presets section fixed height */}
288-
<div className="h-12 px-4 flex-none">
288+
<div className="h-14 px-4 flex-none">
289289
{selectedRowIds.length ? (
290290
<AlertActions
291291
selectedRowIds={selectedRowIds}
@@ -310,7 +310,7 @@ export function AlertTable({
310310
</div>
311311

312312
{/* Main content area - uses flex-grow to fill remaining space */}
313-
<div className="flex-grow overflow-hidden px-4 pb-4">
313+
<div className="flex-grow px-4 pb-4">
314314
<div className="h-full flex gap-6">
315315
{/* Facets sidebar */}
316316
<div className="w-32 min-w-[12rem] overflow-y-auto">

keep-ui/app/(keep)/alerts/alerts-rules-builder.tsx

+124-128
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useCallback, useEffect, useRef, useState } from "react";
22
import Modal from "components/ui/Modal";
3-
import { Button, Textarea, Badge } from "@tremor/react";
3+
import { Button, Textarea } from "@tremor/react";
44
import QueryBuilder, {
55
Field,
66
Operator,
@@ -19,14 +19,16 @@ import {
1919
reverseSeverityMapping,
2020
} from "./models";
2121
import { XMarkIcon, TrashIcon } from "@heroicons/react/24/outline";
22-
import { FiSave } from "react-icons/fi";
2322
import { TbDatabaseImport } from "react-icons/tb";
2423
import Select, { components, MenuListProps } from "react-select";
2524

2625
import { IoSearchOutline } from "react-icons/io5";
2726
import { FiExternalLink } from "react-icons/fi";
2827
import { usePathname, useRouter, useSearchParams } from "next/navigation";
2928
import { toast } from "react-toastify";
29+
import { CornerDownLeft } from "lucide-react";
30+
import { Link } from "@/components/ui";
31+
import { DocumentTextIcon } from "@heroicons/react/24/outline";
3032

3133
const staticOptions = [
3234
{ value: 'severity > "info"', label: 'severity > "info"' },
@@ -493,8 +495,8 @@ export const AlertsRulesBuilder = ({
493495
operators: getOperators(id),
494496
}))
495497
: customFields
496-
? customFields
497-
: [];
498+
? customFields
499+
: [];
498500

499501
const onImportSQL = () => {
500502
setImportSQLOpen(true);
@@ -551,35 +553,107 @@ export const AlertsRulesBuilder = ({
551553
};
552554

553555
return (
554-
<div className="flex flex-col gap-y-2 w-full justify-end">
555-
<Modal
556-
isOpen={isGUIOpen}
557-
onClose={() => setIsGUIOpen(false)}
558-
className="w-[50%] max-w-screen-2xl max-h-[710px] transform overflow-auto ring-tremor bg-white p-6 text-left align-middle shadow-tremor transition-all rounded-xl"
559-
title="Query Builder"
560-
>
561-
<div className="space-y-2 pt-4">
562-
<div className="max-h-96 overflow-auto">
563-
<QueryBuilder
564-
query={query}
565-
onQueryChange={(newQuery) => setQuery(newQuery)}
566-
fields={fields}
567-
addRuleToNewGroups
568-
showCombinatorsBetweenRules={false}
569-
/>
556+
<>
557+
<div className="flex flex-col gap-y-2 w-full justify-end">
558+
{/* Docs */}
559+
<div className="flex flex-wrap items-start gap-x-2">
560+
<div className="flex flex-wrap gap-2 items-center relative flex-grow">
561+
{/* Textarea and error message container */}
562+
<div className="flex-grow relative" ref={wrapperRef}>
563+
<Textarea
564+
ref={textAreaRef}
565+
rows={1}
566+
className="resize-none overflow-hidden w-full pr-9 min-h-[38px]" // Padding for clear button and height to match the button height
567+
value={celRules}
568+
onValueChange={onValueChange}
569+
onKeyDown={handleKeyDown}
570+
placeholder='Use CEL to filter your alerts e.g. source.contains("kibana").'
571+
error={!isValidCEL}
572+
onFocus={() => setShowSuggestions(true)}
573+
/>
574+
{celRules && (
575+
<button
576+
onClick={handleClearInput}
577+
className="absolute top-0 right-0 w-9 h-[38px] flex items-center justify-center text-gray-400 hover:text-gray-600" // Position to the left of the Enter to apply badge
578+
>
579+
<XMarkIcon className="h-4 w-4" />
580+
</button>
581+
)}
582+
{showSuggestions && (
583+
<div className="absolute z-10 w-full">
584+
<Select
585+
options={staticOptions}
586+
onChange={handleSelectChange}
587+
menuIsOpen={true}
588+
components={minimal ? undefined : customComponents}
589+
onBlur={() => setShowSuggestions(false)}
590+
styles={customStyles}
591+
/>
592+
</div>
593+
)}
594+
{!isValidCEL && (
595+
<div className="text-red-500 text-sm absolute bottom-0 left-0 transform translate-y-full">
596+
Invalid Common Expression Logic expression.
597+
</div>
598+
)}
599+
<div className="flex items-center justify-between pt-1 px-2">
600+
<Link
601+
href="https://docs.keephq.dev/overview/presets"
602+
target="_blank"
603+
rel="noreferrer noopener"
604+
className="text-xs text-tremor-muted"
605+
icon={DocumentTextIcon}
606+
>
607+
CEL Documentation
608+
</Link>
609+
<span className="text-xs text-gray-400">
610+
<CornerDownLeft className="h-3 w-3 mr-1 inline-block" />
611+
Enter to apply
612+
</span>
613+
</div>
614+
</div>
570615
</div>
571-
<div className="inline-flex justify-end">
616+
617+
{/* Buttons next to the Textarea */}
618+
{showSqlImport && (
572619
<Button
573620
color="orange"
574-
onClick={onGenerateQuery}
575-
disabled={!query.rules.length}
621+
variant="secondary"
622+
type="button"
623+
onClick={onImportSQL}
624+
icon={TbDatabaseImport}
625+
size="sm"
626+
tooltip="Import from SQL"
576627
>
577-
Generate Query
628+
Import from SQL
578629
</Button>
579-
</div>
630+
)}
631+
{showSave && (
632+
<Button
633+
color="orange"
634+
size="sm"
635+
disabled={!celRules.length}
636+
onClick={() => validateAndOpenSaveModal(celRules)}
637+
tooltip="Save current filter as a preset"
638+
>
639+
Save
640+
</Button>
641+
)}
642+
{selectedPreset &&
643+
selectedPreset.name &&
644+
selectedPreset?.name !== "deleted" &&
645+
selectedPreset?.name !== "feed" &&
646+
selectedPreset?.name !== "dismissed" &&
647+
deletePreset && (
648+
<Button
649+
icon={TrashIcon}
650+
color="orange"
651+
title="Delete preset"
652+
onClick={async () => await deletePreset(selectedPreset!.id!)}
653+
></Button>
654+
)}
580655
</div>
581-
</Modal>
582-
656+
</div>
583657
{/* Import SQL */}
584658
<Modal
585659
isOpen={isImportSQLOpen}
@@ -608,111 +682,33 @@ export const AlertsRulesBuilder = ({
608682
</div>
609683
</Modal>
610684

611-
{/* Docs */}
612-
<div className="flex flex-wrap items-center gap-x-2">
613-
<div className="flex flex-wrap gap-2 items-center relative flex-grow">
614-
{/* CEL badge and (i) icon container */}
615-
<div className="flex items-center space-x-2">
616-
<Badge
617-
key={"cel"}
618-
size="md"
619-
className="cursor-pointer"
620-
color="orange"
621-
tooltip="Click for documentation"
622-
onClick={() =>
623-
window.open(
624-
"https://docs.keephq.dev/overview/presets",
625-
"_blank"
626-
)
627-
}
628-
>
629-
CEL
630-
</Badge>
631-
</div>
632-
633-
{/* Textarea and error message container */}
634-
<div className="flex-grow relative" ref={wrapperRef}>
635-
<Textarea
636-
ref={textAreaRef}
637-
rows={1}
638-
className="resize-none overflow-hidden w-full pr-40" // Provide enough padding to the right
639-
value={celRules}
640-
onValueChange={onValueChange}
641-
onKeyDown={handleKeyDown}
642-
placeholder='Use CEL to filter your alerts e.g. source.contains("kibana").'
643-
error={!isValidCEL}
644-
onFocus={() => setShowSuggestions(true)}
685+
<Modal
686+
isOpen={isGUIOpen}
687+
onClose={() => setIsGUIOpen(false)}
688+
className="w-[50%] max-w-screen-2xl max-h-[710px] transform overflow-auto ring-tremor bg-white p-6 text-left align-middle shadow-tremor transition-all rounded-xl"
689+
title="Query Builder"
690+
>
691+
<div className="space-y-2 pt-4">
692+
<div className="max-h-96 overflow-auto">
693+
<QueryBuilder
694+
query={query}
695+
onQueryChange={(newQuery) => setQuery(newQuery)}
696+
fields={fields}
697+
addRuleToNewGroups
698+
showCombinatorsBetweenRules={false}
645699
/>
646-
{showSuggestions && (
647-
<div className="absolute z-10 w-full">
648-
<Select
649-
options={staticOptions}
650-
onChange={handleSelectChange}
651-
menuIsOpen={true}
652-
components={minimal ? undefined : customComponents}
653-
onBlur={() => setShowSuggestions(false)}
654-
styles={customStyles}
655-
/>
656-
</div>
657-
)}
658-
{!isValidCEL && (
659-
<div className="text-red-500 text-sm absolute bottom-0 left-0 transform translate-y-full">
660-
Invalid Common Expression Logic expression.
661-
</div>
662-
)}
663-
{celRules && (
664-
<button
665-
onClick={handleClearInput}
666-
className="absolute right-36 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600" // Position to the left of the Enter to apply badge
667-
>
668-
<XMarkIcon className="h-4 w-4" />
669-
</button>
670-
)}
671-
<Badge
672-
size="md"
700+
</div>
701+
<div className="inline-flex justify-end">
702+
<Button
673703
color="orange"
674-
className="absolute right-2 top-1/2 transform -translate-y-1/2" // Position to the far right inside the padding area
704+
onClick={onGenerateQuery}
705+
disabled={!query.rules.length}
675706
>
676-
Enter to apply
677-
</Badge>
707+
Generate Query
708+
</Button>
678709
</div>
679710
</div>
680-
681-
{/* Buttons next to the Textarea */}
682-
{showSave && (
683-
<Button
684-
icon={FiSave}
685-
color="orange"
686-
size="sm"
687-
disabled={!celRules.length}
688-
onClick={() => validateAndOpenSaveModal(celRules)}
689-
tooltip="Save current filter as a view"
690-
/>
691-
)}
692-
{selectedPreset &&
693-
selectedPreset.name &&
694-
selectedPreset?.name !== "deleted" &&
695-
selectedPreset?.name !== "feed" &&
696-
selectedPreset?.name !== "dismissed" &&
697-
deletePreset && (
698-
<Button
699-
icon={TrashIcon}
700-
color="orange"
701-
title="Delete preset"
702-
onClick={async () => await deletePreset(selectedPreset!.id!)}
703-
></Button>
704-
)}
705-
{showSqlImport && (
706-
<Button
707-
color="orange"
708-
type="button"
709-
onClick={onImportSQL}
710-
icon={TbDatabaseImport}
711-
size="sm"
712-
tooltip="Import from SQL"
713-
/>
714-
)}
715-
</div>
716-
</div>
711+
</Modal>
712+
</>
717713
);
718714
};

0 commit comments

Comments
 (0)