Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions web/build/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,35 @@
<meta charset="utf-8" />
<link rel="icon" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="/_app/immutable/entry/start.DhMbJzVq.js" rel="modulepreload">
<link href="/_app/immutable/chunks/BUohbZ8j.js" rel="modulepreload">
<link href="/_app/immutable/entry/start.mqu6JMFC.js" rel="modulepreload">
<link href="/_app/immutable/chunks/LO1tLVx8.js" rel="modulepreload">
<link href="/_app/immutable/chunks/DtfuHTUv.js" rel="modulepreload">
<link href="/_app/immutable/entry/app.D9IKs6iZ.js" rel="modulepreload">
<link href="/_app/immutable/entry/app.DunHNeNn.js" rel="modulepreload">
<link href="/_app/immutable/chunks/kNaey6uv.js" rel="modulepreload">
<link href="/_app/immutable/chunks/xihTtKlq.js" rel="modulepreload">
<link href="/_app/immutable/nodes/0.aF9dtSfR.js" rel="modulepreload">
<link href="/_app/immutable/nodes/0.CuwfkUmh.js" rel="modulepreload">
<link href="/_app/immutable/chunks/DKyKpwK7.js" rel="modulepreload">
<link href="/_app/immutable/chunks/5Qa-t89S.js" rel="modulepreload">
<link href="/_app/immutable/chunks/hKaPXkrQ.js" rel="modulepreload">
<link href="/_app/immutable/chunks/CCc3LmDV.js" rel="modulepreload">
<link href="/_app/immutable/chunks/J-rJHSB7.js" rel="modulepreload">
<link href="/_app/immutable/chunks/fe7zj1-L.js" rel="modulepreload">

<link href="/_app/immutable/assets/0.DtaeUL2f.css" rel="stylesheet">
<link href="/_app/immutable/assets/0.oHVnhF_W.css" rel="stylesheet">
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">
<script>
{
__sveltekit_1vybhoy = {
__sveltekit_2mvuzf = {
base: ""
};

const element = document.currentScript.parentElement;

Promise.all([
import("/_app/immutable/entry/start.DhMbJzVq.js"),
import("/_app/immutable/entry/app.D9IKs6iZ.js")
import("/_app/immutable/entry/start.mqu6JMFC.js"),
import("/_app/immutable/entry/app.DunHNeNn.js")
]).then(([kit, app]) => {
kit.start(app, element);
});
Expand Down
39 changes: 19 additions & 20 deletions web/src/routes/(dashboard)/rules/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { api, type Project, type AlertRule, type CreateAlertRule } from '$lib/api';
import { Badge } from '$lib/components/ui/badge/index.js';
import * as AlertDialog from '$lib/components/ui/alert-dialog/index.js';
import EmptyState from '$lib/components/EmptyState.svelte';
import { toast } from 'svelte-sonner';
import { Button } from '$lib/components/ui/button/index.js';
import { Card } from '$lib/components/ui/card/index.js';
Expand Down Expand Up @@ -127,12 +128,12 @@
</svelte:head>

<div class="p-4 lg:p-6 space-y-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<h1 class="text-2xl font-bold">Alert Rules</h1>
<div class="flex flex-wrap items-center justify-between gap-2">
<h1 class="text-2xl font-bold whitespace-nowrap">Alert Rules</h1>
<div class="flex items-center gap-2">
{#if projects.length > 1}
<select
class="h-9 rounded-md border border-input bg-background px-3 text-sm"
class="h-9 min-w-0 max-w-[190px] rounded-md border border-input bg-background px-3 text-sm"
value={selectedProject}
onchange={() => switchProject((event?.target as HTMLSelectElement).value)}
>
Expand All @@ -141,10 +142,10 @@
{/each}
</select>
{/if}
<Button onclick={() => (showForm = !showForm)} variant={showForm ? 'secondary' : 'default'}>
{showForm ? 'Cancel' : '+ New Rule'}
</Button>
</div>
<Button onclick={() => (showForm = !showForm)} variant={showForm ? 'secondary' : 'default'}>
{showForm ? 'Cancel' : '+ New Rule'}
</Button>
</div>

{#if error}
Expand Down Expand Up @@ -198,38 +199,36 @@
{#if loading}
<p class="text-muted-foreground">Loading rules...</p>
{:else if rules.length === 0 && !showForm}
<div class="flex flex-col items-center justify-center py-16 text-center">
<p class="text-lg font-medium text-muted-foreground">No alert rules yet</p>
<p class="text-sm text-muted-foreground mt-1">
Create a rule to get notified when errors match your conditions.
</p>
</div>
<EmptyState
title="No alert rules yet"
description="Create a rule to get notified when errors match your conditions."
/>
{:else}
<div class="space-y-3">
{#each rules as rule}
<Card class="p-4">
<div class="flex items-start justify-between">
<div class="space-y-1">
<div class="flex items-center gap-2">
<h3 class="font-medium">{rule.name}</h3>
<div class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
<div class="min-w-0 space-y-1">
<div class="flex flex-wrap items-center gap-2">
<h3 class="font-medium break-words">{rule.name}</h3>
<Badge variant={rule.enabled ? 'default' : 'secondary'}>
{rule.enabled ? 'Active' : 'Disabled'}
</Badge>
<Badge variant="outline">{rule.action_type}</Badge>
</div>
<p class="text-sm text-muted-foreground">
<p class="text-sm text-muted-foreground break-words">
Level: {JSON.stringify(rule.conditions?.level ?? 'any')}
{rule.conditions?.count_gte ? ` | Count ≥ ${rule.conditions.count_gte}` : ''}
{rule.conditions?.title_contains
? ` | Title contains "${rule.conditions.title_contains}"`
: ''}
</p>
<p class="text-xs text-muted-foreground">
<p class="text-xs text-muted-foreground break-all">
Cooldown: {rule.cooldown_seconds}s ·
{rule.action_config?.url || 'no webhook configured'}
</p>
</div>
<div class="flex gap-2">
<div class="flex gap-2 shrink-0">
<Button variant="outline" size="sm" onclick={() => handleToggle(rule)}>
{rule.enabled ? 'Disable' : 'Enable'}
</Button>
Expand Down
Loading