Skip to content

Commit

Permalink
feat: parse filters from query string
Browse files Browse the repository at this point in the history
  • Loading branch information
MattKetmo committed Dec 10, 2024
1 parent caeb462 commit a3bad8c
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 7 deletions.
12 changes: 8 additions & 4 deletions src/components/alerts/template.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useEffect, useState } from 'react'
import { notFound } from 'next/navigation'
import { useQueryState } from 'nuqs'
import { parseAsArrayOf, useQueryState } from 'nuqs'
import { ListFilter, LoaderCircle, RefreshCcw, TriangleAlert } from 'lucide-react'
import { ViewConfig } from '@/config/types'
import { useAlerts } from '@/contexts/alerts'
Expand All @@ -13,8 +13,8 @@ import { Alert } from '@/types/alertmanager'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
import { AlertGroups } from './alert-groups'
import { AlertModal } from './alert-modal'
import { Group } from './types'
import { alertFilter, alertSort } from './utils'
import { Group, LabelFilter } from './types'
import { alertFilter, alertSort, parseAsFilter } from './utils'
import {
Select,
SelectContent,
Expand All @@ -41,6 +41,7 @@ export function AlertsTemplate(props: Props) {
const [flattenedAlerts, setFlattenedAlerts] = useState<Alert[]>([])
const [view, setView] = useState<ViewConfig | null>(null)
const [alertGroups, setAlertGroups] = useState<Group[]>([])
const [filters] = useQueryState('filters', parseAsArrayOf(parseAsFilter, ';'))

useHotkeys('r', () => refreshAlerts(), []);

Expand All @@ -55,10 +56,13 @@ export function AlertsTemplate(props: Props) {

const groupBy = group !== '' ? group : view.groupBy

// Merge view filters with query filters
const alertFilters = view.filters.concat(filters || [])

// Flatten, filter & sort alerts
const flatAlerts = Object.values(alerts).
reduce((acc, val) => acc.concat(val), []).
filter(alertFilter(view.filters))
filter(alertFilter(alertFilters))
flatAlerts.sort(alertSort)

setFlattenedAlerts(flatAlerts)
Expand Down
4 changes: 2 additions & 2 deletions src/components/alerts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export type Filter = (alert: Alert) => boolean
export type LabelFilter = {
label: string
value: string | string[]
exclude?: boolean
regex?: boolean
exclude: boolean
regex: boolean
}
45 changes: 45 additions & 0 deletions src/components/alerts/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,53 @@
import { Alert } from "@/types/alertmanager"
import { LabelFilter } from "./types"
import { createParser } from "nuqs"

const showOnlyActive = true

const filterRegex = /(?<label>\w+)(?<pattern>|!=|=~|!~|=)(?<value>[^!=~]+)/

export function parseFilter(filterStr: string): LabelFilter {
const match = filterStr.match(filterRegex)

const label = match?.groups?.label || ''
const regex = match?.groups?.pattern === '=~' || match?.groups?.pattern === '!~'
const exclude = match?.groups?.pattern === '!=' || match?.groups?.pattern === '!~'

let value: string | string[] = match?.groups?.value || ''
if (typeof value === 'string' && value.includes(',')) {
value = value.split(',')
}

return { label, exclude, regex, value }
}

export function filterToString(filter: LabelFilter): string {
const label = filter.label
const value = Array.isArray(filter.value) ? filter.value.join(',') : filter.value

if (filter.regex && filter.exclude) {
return `${label}!~${value}`
}
if (filter.regex) {
return `${label}=~${value}`
}
if (filter.exclude) {
return `${label}!=${value}`
}

return `${label}=${value}`
}

// Custom nuqs parser
export const parseAsFilter = createParser<LabelFilter>({
parse(queryValue) {
return parseFilter(queryValue)
},
serialize(value) {
return filterToString(value)
}
})

export function flattenAlerts(alerts: Record<string, Alert[]>): Alert[] {
return Object.values(alerts).reduce((acc, val) => acc.concat(val), [])
}
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "ES2017",
"target": "ES2018",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
Expand Down

0 comments on commit a3bad8c

Please sign in to comment.