Skip to content

Commit

Permalink
feat(ui): alerts table search polish (keephq#2675)
Browse files Browse the repository at this point in the history
Co-authored-by: Tal <[email protected]>
  • Loading branch information
Kiryous and talboren authored Nov 28, 2024
1 parent 9e860e8 commit f7f4bb2
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 132 deletions.
1 change: 1 addition & 0 deletions keep-ui/app/(keep)/alerts/alert-presets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ export default function AlertPresets({
<div className="space-y-2">
<div className="flex items-center gap-2">
<TextInput
// TODO: don't show error until user tries to save
error={!presetName}
errorMessage="Preset name is required"
placeholder={
Expand Down
8 changes: 4 additions & 4 deletions keep-ui/app/(keep)/alerts/alert-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,9 @@ export function AlertTable({

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

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

{/* Main content area - uses flex-grow to fill remaining space */}
<div className="flex-grow overflow-hidden px-4 pb-4">
<div className="flex-grow px-4 pb-4">
<div className="h-full flex gap-6">
{/* Facets sidebar */}
<div className="w-32 min-w-[12rem] overflow-y-auto">
Expand Down
252 changes: 124 additions & 128 deletions keep-ui/app/(keep)/alerts/alerts-rules-builder.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useRef, useState } from "react";
import Modal from "components/ui/Modal";
import { Button, Textarea, Badge } from "@tremor/react";
import { Button, Textarea } from "@tremor/react";
import QueryBuilder, {
Field,
Operator,
Expand All @@ -19,14 +19,16 @@ import {
reverseSeverityMapping,
} from "./models";
import { XMarkIcon, TrashIcon } from "@heroicons/react/24/outline";
import { FiSave } from "react-icons/fi";
import { TbDatabaseImport } from "react-icons/tb";
import Select, { components, MenuListProps } from "react-select";

import { IoSearchOutline } from "react-icons/io5";
import { FiExternalLink } from "react-icons/fi";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { toast } from "react-toastify";
import { CornerDownLeft } from "lucide-react";
import { Link } from "@/components/ui";
import { DocumentTextIcon } from "@heroicons/react/24/outline";

const staticOptions = [
{ value: 'severity > "info"', label: 'severity > "info"' },
Expand Down Expand Up @@ -493,8 +495,8 @@ export const AlertsRulesBuilder = ({
operators: getOperators(id),
}))
: customFields
? customFields
: [];
? customFields
: [];

const onImportSQL = () => {
setImportSQLOpen(true);
Expand Down Expand Up @@ -551,35 +553,107 @@ export const AlertsRulesBuilder = ({
};

return (
<div className="flex flex-col gap-y-2 w-full justify-end">
<Modal
isOpen={isGUIOpen}
onClose={() => setIsGUIOpen(false)}
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"
title="Query Builder"
>
<div className="space-y-2 pt-4">
<div className="max-h-96 overflow-auto">
<QueryBuilder
query={query}
onQueryChange={(newQuery) => setQuery(newQuery)}
fields={fields}
addRuleToNewGroups
showCombinatorsBetweenRules={false}
/>
<>
<div className="flex flex-col gap-y-2 w-full justify-end">
{/* Docs */}
<div className="flex flex-wrap items-start gap-x-2">
<div className="flex flex-wrap gap-2 items-center relative flex-grow">
{/* Textarea and error message container */}
<div className="flex-grow relative" ref={wrapperRef}>
<Textarea
ref={textAreaRef}
rows={1}
className="resize-none overflow-hidden w-full pr-9 min-h-[38px]" // Padding for clear button and height to match the button height
value={celRules}
onValueChange={onValueChange}
onKeyDown={handleKeyDown}
placeholder='Use CEL to filter your alerts e.g. source.contains("kibana").'
error={!isValidCEL}
onFocus={() => setShowSuggestions(true)}
/>
{celRules && (
<button
onClick={handleClearInput}
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
>
<XMarkIcon className="h-4 w-4" />
</button>
)}
{showSuggestions && (
<div className="absolute z-10 w-full">
<Select
options={staticOptions}
onChange={handleSelectChange}
menuIsOpen={true}
components={minimal ? undefined : customComponents}
onBlur={() => setShowSuggestions(false)}
styles={customStyles}
/>
</div>
)}
{!isValidCEL && (
<div className="text-red-500 text-sm absolute bottom-0 left-0 transform translate-y-full">
Invalid Common Expression Logic expression.
</div>
)}
<div className="flex items-center justify-between pt-1 px-2">
<Link
href="https://docs.keephq.dev/overview/presets"
target="_blank"
rel="noreferrer noopener"
className="text-xs text-tremor-muted"
icon={DocumentTextIcon}
>
CEL Documentation
</Link>
<span className="text-xs text-gray-400">
<CornerDownLeft className="h-3 w-3 mr-1 inline-block" />
Enter to apply
</span>
</div>
</div>
</div>
<div className="inline-flex justify-end">

{/* Buttons next to the Textarea */}
{showSqlImport && (
<Button
color="orange"
onClick={onGenerateQuery}
disabled={!query.rules.length}
variant="secondary"
type="button"
onClick={onImportSQL}
icon={TbDatabaseImport}
size="sm"
tooltip="Import from SQL"
>
Generate Query
Import from SQL
</Button>
</div>
)}
{showSave && (
<Button
color="orange"
size="sm"
disabled={!celRules.length}
onClick={() => validateAndOpenSaveModal(celRules)}
tooltip="Save current filter as a preset"
>
Save
</Button>
)}
{selectedPreset &&
selectedPreset.name &&
selectedPreset?.name !== "deleted" &&
selectedPreset?.name !== "feed" &&
selectedPreset?.name !== "dismissed" &&
deletePreset && (
<Button
icon={TrashIcon}
color="orange"
title="Delete preset"
onClick={async () => await deletePreset(selectedPreset!.id!)}
></Button>
)}
</div>
</Modal>

</div>
{/* Import SQL */}
<Modal
isOpen={isImportSQLOpen}
Expand Down Expand Up @@ -608,111 +682,33 @@ export const AlertsRulesBuilder = ({
</div>
</Modal>

{/* Docs */}
<div className="flex flex-wrap items-center gap-x-2">
<div className="flex flex-wrap gap-2 items-center relative flex-grow">
{/* CEL badge and (i) icon container */}
<div className="flex items-center space-x-2">
<Badge
key={"cel"}
size="md"
className="cursor-pointer"
color="orange"
tooltip="Click for documentation"
onClick={() =>
window.open(
"https://docs.keephq.dev/overview/presets",
"_blank"
)
}
>
CEL
</Badge>
</div>

{/* Textarea and error message container */}
<div className="flex-grow relative" ref={wrapperRef}>
<Textarea
ref={textAreaRef}
rows={1}
className="resize-none overflow-hidden w-full pr-40" // Provide enough padding to the right
value={celRules}
onValueChange={onValueChange}
onKeyDown={handleKeyDown}
placeholder='Use CEL to filter your alerts e.g. source.contains("kibana").'
error={!isValidCEL}
onFocus={() => setShowSuggestions(true)}
<Modal
isOpen={isGUIOpen}
onClose={() => setIsGUIOpen(false)}
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"
title="Query Builder"
>
<div className="space-y-2 pt-4">
<div className="max-h-96 overflow-auto">
<QueryBuilder
query={query}
onQueryChange={(newQuery) => setQuery(newQuery)}
fields={fields}
addRuleToNewGroups
showCombinatorsBetweenRules={false}
/>
{showSuggestions && (
<div className="absolute z-10 w-full">
<Select
options={staticOptions}
onChange={handleSelectChange}
menuIsOpen={true}
components={minimal ? undefined : customComponents}
onBlur={() => setShowSuggestions(false)}
styles={customStyles}
/>
</div>
)}
{!isValidCEL && (
<div className="text-red-500 text-sm absolute bottom-0 left-0 transform translate-y-full">
Invalid Common Expression Logic expression.
</div>
)}
{celRules && (
<button
onClick={handleClearInput}
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
>
<XMarkIcon className="h-4 w-4" />
</button>
)}
<Badge
size="md"
</div>
<div className="inline-flex justify-end">
<Button
color="orange"
className="absolute right-2 top-1/2 transform -translate-y-1/2" // Position to the far right inside the padding area
onClick={onGenerateQuery}
disabled={!query.rules.length}
>
Enter to apply
</Badge>
Generate Query
</Button>
</div>
</div>

{/* Buttons next to the Textarea */}
{showSave && (
<Button
icon={FiSave}
color="orange"
size="sm"
disabled={!celRules.length}
onClick={() => validateAndOpenSaveModal(celRules)}
tooltip="Save current filter as a view"
/>
)}
{selectedPreset &&
selectedPreset.name &&
selectedPreset?.name !== "deleted" &&
selectedPreset?.name !== "feed" &&
selectedPreset?.name !== "dismissed" &&
deletePreset && (
<Button
icon={TrashIcon}
color="orange"
title="Delete preset"
onClick={async () => await deletePreset(selectedPreset!.id!)}
></Button>
)}
{showSqlImport && (
<Button
color="orange"
type="button"
onClick={onImportSQL}
icon={TbDatabaseImport}
size="sm"
tooltip="Import from SQL"
/>
)}
</div>
</div>
</Modal>
</>
);
};

0 comments on commit f7f4bb2

Please sign in to comment.