mirror of
https://github.com/rajnandan1/kener.git
synced 2026-08-07 07:14:56 +00:00
Merge pull request #799 from lokiee0/feat/795-monitoring-status-filter
Feat/795 monitoring status filter
This commit is contained in:
@@ -12,16 +12,16 @@ env:
|
|||||||
DOCKERHUB_IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}
|
DOCKERHUB_IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}
|
||||||
GITHUB_IMAGE_NAME: ${{ github.repository }}
|
GITHUB_IMAGE_NAME: ${{ github.repository }}
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: main-docker-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push-main:
|
build-and-push-main:
|
||||||
name: Build and push main Docker images (with docs)
|
name: Build and push main Docker images (with docs)
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
variant: [debian, alpine]
|
variant: [debian, alpine]
|
||||||
|
concurrency:
|
||||||
|
group: main-docker-${{ github.ref }}-${{ matrix.variant }}
|
||||||
|
cancel-in-progress: true
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { TimestampStatusCount } from "$lib/server/types/db";
|
import type { TimestampStatusCount } from "$lib/server/types/db";
|
||||||
import GC, { PAGE_STATUS_MESSAGES, type StatusType } from "$lib/global-constants";
|
import GC, { PAGE_STATUS_MESSAGES } from "$lib/global-constants";
|
||||||
|
import type { StatusType } from "$lib/types/status";
|
||||||
|
|
||||||
function ParseLatency(latencyMs: number): string {
|
function ParseLatency(latencyMs: number): string {
|
||||||
if (!!!latencyMs) {
|
if (!!!latencyMs) {
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { isMonitoringStatus } from "./global-constants.js";
|
||||||
|
|
||||||
|
describe("isMonitoringStatus", () => {
|
||||||
|
it("accepts only statuses supported by the monitoring filter", () => {
|
||||||
|
expect(isMonitoringStatus("UP")).toBe(true);
|
||||||
|
expect(isMonitoringStatus("DOWN")).toBe(true);
|
||||||
|
expect(isMonitoringStatus("DEGRADED")).toBe(true);
|
||||||
|
expect(isMonitoringStatus("MAINTENANCE")).toBe(false);
|
||||||
|
expect(isMonitoringStatus("")).toBe(false);
|
||||||
|
expect(isMonitoringStatus("invalid")).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,9 +1,15 @@
|
|||||||
|
import type { MonitoringStatus } from "$lib/types/status.js";
|
||||||
|
|
||||||
// Badge styles supported by badge-maker
|
// Badge styles supported by badge-maker
|
||||||
export const BADGE_STYLES = ["flat", "plastic", "flat-square", "for-the-badge", "social"] as const;
|
export const BADGE_STYLES = ["flat", "plastic", "flat-square", "for-the-badge", "social"] as const;
|
||||||
export type BadgeStyle = (typeof BADGE_STYLES)[number];
|
export type BadgeStyle = (typeof BADGE_STYLES)[number];
|
||||||
|
|
||||||
// Status types
|
// Status types
|
||||||
export type StatusType = "UP" | "DOWN" | "DEGRADED" | "MAINTENANCE" | "NO_DATA";
|
export const MONITORING_STATUSES = ["UP", "DOWN", "DEGRADED"] as const satisfies readonly MonitoringStatus[];
|
||||||
|
|
||||||
|
export function isMonitoringStatus(value: unknown): value is MonitoringStatus {
|
||||||
|
return typeof value === "string" && MONITORING_STATUSES.includes(value as MonitoringStatus);
|
||||||
|
}
|
||||||
|
|
||||||
// Incident states
|
// Incident states
|
||||||
export type IncidentState = "INVESTIGATING" | "IDENTIFIED" | "MONITORING" | "RESOLVED";
|
export type IncidentState = "INVESTIGATING" | "IDENTIFIED" | "MONITORING" | "RESOLVED";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { json, error } from "@sveltejs/kit";
|
|||||||
import type { APIServerRequest } from "$lib/server/types/api-server";
|
import type { APIServerRequest } from "$lib/server/types/api-server";
|
||||||
import db from "$lib/server/db/db";
|
import db from "$lib/server/db/db";
|
||||||
import { GetMinuteStartNowTimestampUTC } from "$lib/server/tool";
|
import { GetMinuteStartNowTimestampUTC } from "$lib/server/tool";
|
||||||
import type { StatusType } from "$lib/global-constants";
|
import type { StatusType } from "$lib/types/status";
|
||||||
import type { TimestampStatusCount } from "$lib/server/types/db";
|
import type { TimestampStatusCount } from "$lib/server/types/db";
|
||||||
import { buildMonitorBarResponse } from "./shared";
|
import { buildMonitorBarResponse } from "./shared";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import db from "$lib/server/db/db";
|
import db from "$lib/server/db/db";
|
||||||
import GC, { type StatusType } from "$lib/global-constants";
|
import GC from "$lib/global-constants";
|
||||||
|
import type { StatusType } from "$lib/types/status";
|
||||||
import type { MonitorRecord, TimestampStatusCount } from "$lib/server/types/db";
|
import type { MonitorRecord, TimestampStatusCount } from "$lib/server/types/db";
|
||||||
import { UptimeCalculator } from "$lib/server/tool";
|
import { UptimeCalculator } from "$lib/server/tool";
|
||||||
import type { MonitorBarResponse } from "./get";
|
import type { MonitorBarResponse } from "./get";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { json, error } from "@sveltejs/kit";
|
|||||||
import type { APIServerRequest } from "$lib/server/types/api-server";
|
import type { APIServerRequest } from "$lib/server/types/api-server";
|
||||||
import db from "$lib/server/db/db";
|
import db from "$lib/server/db/db";
|
||||||
import { GetMinuteStartNowTimestampUTC } from "$lib/server/tool";
|
import { GetMinuteStartNowTimestampUTC } from "$lib/server/tool";
|
||||||
import type { StatusType } from "$lib/global-constants";
|
import type { StatusType } from "$lib/types/status";
|
||||||
import GC from "$lib/global-constants";
|
import GC from "$lib/global-constants";
|
||||||
import type { MonitorBarResponse } from "$lib/server/api-server/monitor-bar/get";
|
import type { MonitorBarResponse } from "$lib/server/api-server/monitor-bar/get";
|
||||||
import { buildMonitorBarResponseFromRawData } from "$lib/server/api-server/monitor-bar/shared";
|
import { buildMonitorBarResponseFromRawData } from "$lib/server/api-server/monitor-bar/shared";
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import type { MonitorFilter } from "../db/repositories/base.js";
|
|||||||
import db from "../db/db.js";
|
import db from "../db/db.js";
|
||||||
import type { PaginationInput } from "../../types/common.js";
|
import type { PaginationInput } from "../../types/common.js";
|
||||||
import GC, { getBadgeStyle, type BadgeStyle } from "../../global-constants.js";
|
import GC, { getBadgeStyle, type BadgeStyle } from "../../global-constants.js";
|
||||||
|
import type { MonitoringStatus } from "../../types/status.js";
|
||||||
import { makeBadge } from "badge-maker";
|
import { makeBadge } from "badge-maker";
|
||||||
import { ErrorSvg } from "../../anywhere.js";
|
import { ErrorSvg } from "../../anywhere.js";
|
||||||
import { GetLastMonitoringValue, SetLastHeartbeat, DeleteMonitorCaches } from "../cache/setGet.js";
|
import { GetLastMonitoringValue, SetLastHeartbeat, DeleteMonitorCaches } from "../cache/setGet.js";
|
||||||
@@ -490,7 +491,7 @@ export const GetStatusCountsByInterval = async (
|
|||||||
export const GetMonitoringDataPaginated = async (
|
export const GetMonitoringDataPaginated = async (
|
||||||
page: number,
|
page: number,
|
||||||
limit: number,
|
limit: number,
|
||||||
filter?: { monitor_tag?: string; start_time?: number; end_time?: number },
|
filter?: { monitor_tag?: string; status?: MonitoringStatus; start_time?: number; end_time?: number },
|
||||||
): Promise<{ data: MonitoringData[]; total: number }> => {
|
): Promise<{ data: MonitoringData[]; total: number }> => {
|
||||||
const data = await db.getMonitoringDataPaginated(page, limit, filter);
|
const data = await db.getMonitoringDataPaginated(page, limit, filter);
|
||||||
const countResult = await db.getMonitoringDataCount(filter);
|
const countResult = await db.getMonitoringDataCount(filter);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { Knex as KnexType } from "knex";
|
import type { Knex as KnexType } from "knex";
|
||||||
import { BaseRepository } from "./base.js";
|
import { BaseRepository } from "./base.js";
|
||||||
import GC from "../../../global-constants.js";
|
import GC from "../../../global-constants.js";
|
||||||
|
import type { MonitoringStatus } from "../../../types/status.js";
|
||||||
import { GetMinuteStartNowTimestampUTC } from "../../tool.js";
|
import { GetMinuteStartNowTimestampUTC } from "../../tool.js";
|
||||||
import type {
|
import type {
|
||||||
MonitoringData,
|
MonitoringData,
|
||||||
@@ -82,7 +83,7 @@ export class MonitoringRepository extends BaseRepository {
|
|||||||
async getMonitoringDataPaginated(
|
async getMonitoringDataPaginated(
|
||||||
page: number,
|
page: number,
|
||||||
limit: number,
|
limit: number,
|
||||||
filter?: { monitor_tag?: string; start_time?: number; end_time?: number },
|
filter?: { monitor_tag?: string; status?: MonitoringStatus; start_time?: number; end_time?: number },
|
||||||
): Promise<MonitoringData[]> {
|
): Promise<MonitoringData[]> {
|
||||||
let query = this.knex("monitoring_data").select("*");
|
let query = this.knex("monitoring_data").select("*");
|
||||||
|
|
||||||
@@ -90,6 +91,10 @@ export class MonitoringRepository extends BaseRepository {
|
|||||||
query = query.where("monitor_tag", filter.monitor_tag);
|
query = query.where("monitor_tag", filter.monitor_tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filter?.status) {
|
||||||
|
query = query.where("status", filter.status);
|
||||||
|
}
|
||||||
|
|
||||||
if (filter?.start_time) {
|
if (filter?.start_time) {
|
||||||
query = query.where("timestamp", ">=", filter.start_time);
|
query = query.where("timestamp", ">=", filter.start_time);
|
||||||
}
|
}
|
||||||
@@ -106,6 +111,7 @@ export class MonitoringRepository extends BaseRepository {
|
|||||||
|
|
||||||
async getMonitoringDataCount(filter?: {
|
async getMonitoringDataCount(filter?: {
|
||||||
monitor_tag?: string;
|
monitor_tag?: string;
|
||||||
|
status?: MonitoringStatus;
|
||||||
start_time?: number;
|
start_time?: number;
|
||||||
end_time?: number;
|
end_time?: number;
|
||||||
}): Promise<{ count: number }> {
|
}): Promise<{ count: number }> {
|
||||||
@@ -115,6 +121,10 @@ export class MonitoringRepository extends BaseRepository {
|
|||||||
query = query.where("monitor_tag", filter.monitor_tag);
|
query = query.where("monitor_tag", filter.monitor_tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filter?.status) {
|
||||||
|
query = query.where("status", filter.status);
|
||||||
|
}
|
||||||
|
|
||||||
if (filter?.start_time) {
|
if (filter?.start_time) {
|
||||||
query = query.where("timestamp", ">=", filter.start_time);
|
query = query.where("timestamp", ">=", filter.start_time);
|
||||||
}
|
}
|
||||||
@@ -476,7 +486,7 @@ export class MonitoringRepository extends BaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteMonitorDataByTag(tag?: string, start?: number, end?: number): Promise<number> {
|
async deleteMonitorDataByTag(tag?: string, start?: number, end?: number, status?: MonitoringStatus): Promise<number> {
|
||||||
const query = this.knex("monitoring_data");
|
const query = this.knex("monitoring_data");
|
||||||
if (tag) {
|
if (tag) {
|
||||||
query.where("monitor_tag", tag);
|
query.where("monitor_tag", tag);
|
||||||
@@ -487,6 +497,9 @@ export class MonitoringRepository extends BaseRepository {
|
|||||||
if (end !== undefined) {
|
if (end !== undefined) {
|
||||||
query.where("timestamp", "<=", end);
|
query.where("timestamp", "<=", end);
|
||||||
}
|
}
|
||||||
|
if (status) {
|
||||||
|
query.where("status", status);
|
||||||
|
}
|
||||||
return await query.del();
|
return await query.del();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ export * from "$lib/types/api";
|
|||||||
export * from "$lib/types/monitor";
|
export * from "$lib/types/monitor";
|
||||||
export * from "$lib/types/result";
|
export * from "$lib/types/result";
|
||||||
export * from "$lib/types/common";
|
export * from "$lib/types/common";
|
||||||
|
export * from "$lib/types/status";
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export type MonitoringStatus = "UP" | "DOWN" | "DEGRADED";
|
||||||
|
export type StatusType = MonitoringStatus | "MAINTENANCE" | "NO_DATA";
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import { GetMonitors, GetLatestMonitoringData, GetLatestStatusActiveAll } from "$lib/server/controllers/controller.js";
|
import { GetMonitors, GetLatestMonitoringData, GetLatestStatusActiveAll } from "$lib/server/controllers/controller.js";
|
||||||
import StatusColor, { type StatusColors } from "$lib/color.js";
|
import StatusColor, { type StatusColors } from "$lib/color.js";
|
||||||
import { ErrorSvg } from "$lib/anywhere.js";
|
import { ErrorSvg } from "$lib/anywhere.js";
|
||||||
import GC, { type StatusType } from "$lib/global-constants.js";
|
import GC from "$lib/global-constants.js";
|
||||||
|
import type { StatusType } from "$lib/types/status.js";
|
||||||
import { GetLastMonitoringValue } from "$lib/server/cache/setGet.js";
|
import { GetLastMonitoringValue } from "$lib/server/cache/setGet.js";
|
||||||
import type { RequestHandler } from "./$types";
|
import type { RequestHandler } from "./$types";
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import { format } from "date-fns";
|
|||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import db from "$lib/server/db/db";
|
import db from "$lib/server/db/db";
|
||||||
import GC from "$lib/global-constants.js";
|
import GC, { isMonitoringStatus } from "$lib/global-constants.js";
|
||||||
|
import type { MonitoringStatus } from "$lib/types/status.js";
|
||||||
import {
|
import {
|
||||||
CreateUpdateMonitor,
|
CreateUpdateMonitor,
|
||||||
UpdateMonitoringData,
|
UpdateMonitoringData,
|
||||||
@@ -219,7 +220,14 @@ export async function POST({ request, cookies }) {
|
|||||||
} else if (action == "deleteMonitor") {
|
} else if (action == "deleteMonitor") {
|
||||||
resp = await DeleteMonitorCompletelyUsingTag(data.tag);
|
resp = await DeleteMonitorCompletelyUsingTag(data.tag);
|
||||||
} else if (action == "deleteMonitorData") {
|
} else if (action == "deleteMonitorData") {
|
||||||
await db.deleteMonitorDataByTag(data.tag || undefined, data.start, data.end);
|
let status: MonitoringStatus | undefined;
|
||||||
|
if (data.status !== undefined && data.status !== null && data.status !== "ALL") {
|
||||||
|
if (!isMonitoringStatus(data.status)) {
|
||||||
|
return json({ error: "Invalid monitoring status" }, { status: 400 });
|
||||||
|
}
|
||||||
|
status = data.status;
|
||||||
|
}
|
||||||
|
await db.deleteMonitorDataByTag(data.tag || undefined, data.start, data.end, status);
|
||||||
resp = { success: true };
|
resp = { success: true };
|
||||||
} else if (action == "cloneMonitor") {
|
} else if (action == "cloneMonitor") {
|
||||||
resp = await CloneMonitor({
|
resp = await CloneMonitor({
|
||||||
@@ -245,10 +253,16 @@ export async function POST({ request, cookies }) {
|
|||||||
} else if (action == "getMonitoringDataPaginated") {
|
} else if (action == "getMonitoringDataPaginated") {
|
||||||
const page = parseInt(String(data.page)) || 1;
|
const page = parseInt(String(data.page)) || 1;
|
||||||
const limit = parseInt(String(data.limit)) || 50;
|
const limit = parseInt(String(data.limit)) || 50;
|
||||||
const filter: { monitor_tag?: string; start_time?: number; end_time?: number } = {};
|
const filter: { monitor_tag?: string; status?: MonitoringStatus; start_time?: number; end_time?: number } = {};
|
||||||
if (data.monitor_tag && data.monitor_tag !== "ALL") {
|
if (data.monitor_tag && data.monitor_tag !== "ALL") {
|
||||||
filter.monitor_tag = data.monitor_tag;
|
filter.monitor_tag = data.monitor_tag;
|
||||||
}
|
}
|
||||||
|
if (data.status !== undefined && data.status !== null && data.status !== "ALL") {
|
||||||
|
if (!isMonitoringStatus(data.status)) {
|
||||||
|
return json({ error: "Invalid monitoring status" }, { status: 400 });
|
||||||
|
}
|
||||||
|
filter.status = data.status;
|
||||||
|
}
|
||||||
if (data.start_time) {
|
if (data.start_time) {
|
||||||
filter.start_time = parseInt(String(data.start_time));
|
filter.start_time = parseInt(String(data.start_time));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
import { toast } from "svelte-sonner";
|
import { toast } from "svelte-sonner";
|
||||||
import { resolve } from "$app/paths";
|
import { resolve } from "$app/paths";
|
||||||
import clientResolver from "$lib/client/resolver.js";
|
import clientResolver from "$lib/client/resolver.js";
|
||||||
|
import GC, { isMonitoringStatus } from "$lib/global-constants";
|
||||||
|
import type { MonitoringStatus } from "$lib/types/status.js";
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
interface MonitoringData {
|
interface MonitoringData {
|
||||||
@@ -35,6 +37,8 @@
|
|||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StatusFilter = "ALL" | MonitoringStatus;
|
||||||
|
|
||||||
// Helper to format datetime as YYYY-MM-DDTHH:mm for datetime-local input
|
// Helper to format datetime as YYYY-MM-DDTHH:mm for datetime-local input
|
||||||
function formatDateTimeForInput(date: Date): string {
|
function formatDateTimeForInput(date: Date): string {
|
||||||
return format(date, "yyyy-MM-dd'T'HH:mm");
|
return format(date, "yyyy-MM-dd'T'HH:mm");
|
||||||
@@ -68,12 +72,14 @@
|
|||||||
let pageNo = $state(1);
|
let pageNo = $state(1);
|
||||||
let showFilters = $state(false);
|
let showFilters = $state(false);
|
||||||
let monitorTagFilter = $state("ALL");
|
let monitorTagFilter = $state("ALL");
|
||||||
|
let statusFilter = $state<StatusFilter>("ALL");
|
||||||
let startDateTime = $state(formatDateTimeForInput(yesterday));
|
let startDateTime = $state(formatDateTimeForInput(yesterday));
|
||||||
let endDateTime = $state(formatDateTimeForInput(now));
|
let endDateTime = $state(formatDateTimeForInput(now));
|
||||||
const limit = 50;
|
const limit = 50;
|
||||||
|
|
||||||
const hasActiveFilters = $derived(
|
const hasActiveFilters = $derived(
|
||||||
monitorTagFilter !== "ALL" ||
|
monitorTagFilter !== "ALL" ||
|
||||||
|
statusFilter !== "ALL" ||
|
||||||
startDateTime !== formatDateTimeForInput(yesterday) ||
|
startDateTime !== formatDateTimeForInput(yesterday) ||
|
||||||
endDateTime !== formatDateTimeForInput(now)
|
endDateTime !== formatDateTimeForInput(now)
|
||||||
);
|
);
|
||||||
@@ -113,6 +119,7 @@
|
|||||||
|
|
||||||
function clearFilters() {
|
function clearFilters() {
|
||||||
monitorTagFilter = "ALL";
|
monitorTagFilter = "ALL";
|
||||||
|
statusFilter = "ALL";
|
||||||
startDateTime = formatDateTimeForInput(yesterday);
|
startDateTime = formatDateTimeForInput(yesterday);
|
||||||
endDateTime = formatDateTimeForInput(now);
|
endDateTime = formatDateTimeForInput(now);
|
||||||
pageNo = 1;
|
pageNo = 1;
|
||||||
@@ -139,6 +146,7 @@
|
|||||||
action: "deleteMonitorData",
|
action: "deleteMonitorData",
|
||||||
data: {
|
data: {
|
||||||
tag: monitorTagFilter === "ALL" ? "" : monitorTagFilter,
|
tag: monitorTagFilter === "ALL" ? "" : monitorTagFilter,
|
||||||
|
status: statusFilter === "ALL" ? undefined : statusFilter,
|
||||||
start: startTs,
|
start: startTs,
|
||||||
end: endTs
|
end: endTs
|
||||||
}
|
}
|
||||||
@@ -189,12 +197,14 @@
|
|||||||
page: number;
|
page: number;
|
||||||
limit: number;
|
limit: number;
|
||||||
monitor_tag: string;
|
monitor_tag: string;
|
||||||
|
status: StatusFilter;
|
||||||
start_time?: number;
|
start_time?: number;
|
||||||
end_time?: number;
|
end_time?: number;
|
||||||
} = {
|
} = {
|
||||||
page: pageNo,
|
page: pageNo,
|
||||||
limit,
|
limit,
|
||||||
monitor_tag: monitorTagFilter
|
monitor_tag: monitorTagFilter,
|
||||||
|
status: statusFilter
|
||||||
};
|
};
|
||||||
|
|
||||||
if (startDateTime) {
|
if (startDateTime) {
|
||||||
@@ -241,6 +251,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleStatusChange(value: string | undefined) {
|
||||||
|
if (value === "ALL" || isMonitoringStatus(value)) {
|
||||||
|
statusFilter = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pagination
|
// Pagination
|
||||||
function goToPage(page: number) {
|
function goToPage(page: number) {
|
||||||
pageNo = page;
|
pageNo = page;
|
||||||
@@ -304,6 +320,20 @@
|
|||||||
</Select.Content>
|
</Select.Content>
|
||||||
</Select.Root>
|
</Select.Root>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<span class="text-muted-foreground text-xs font-medium">Status</span>
|
||||||
|
<Select.Root type="single" value={statusFilter} onValueChange={handleStatusChange}>
|
||||||
|
<Select.Trigger class="w-36" aria-label="Status">
|
||||||
|
{statusFilter === "ALL" ? "All Statuses" : statusFilter}
|
||||||
|
</Select.Trigger>
|
||||||
|
<Select.Content>
|
||||||
|
<Select.Item value="ALL">All Statuses</Select.Item>
|
||||||
|
<Select.Item value={GC.UP}>UP</Select.Item>
|
||||||
|
<Select.Item value={GC.DOWN}>DOWN</Select.Item>
|
||||||
|
<Select.Item value={GC.DEGRADED}>DEGRADED</Select.Item>
|
||||||
|
</Select.Content>
|
||||||
|
</Select.Root>
|
||||||
|
</div>
|
||||||
<Button size="sm" onclick={applyFilters}>
|
<Button size="sm" onclick={applyFilters}>
|
||||||
<SearchIcon class="size-4" />
|
<SearchIcon class="size-4" />
|
||||||
Search
|
Search
|
||||||
@@ -437,11 +467,16 @@
|
|||||||
<AlertDialog.Header>
|
<AlertDialog.Header>
|
||||||
<AlertDialog.Title>Delete Monitoring Data</AlertDialog.Title>
|
<AlertDialog.Title>Delete Monitoring Data</AlertDialog.Title>
|
||||||
<AlertDialog.Description>
|
<AlertDialog.Description>
|
||||||
|
This will delete monitoring data for
|
||||||
{#if monitorTagFilter === "ALL"}
|
{#if monitorTagFilter === "ALL"}
|
||||||
This will delete monitoring data for <strong>all monitors</strong> from {startDateTime} to {endDateTime}.
|
<strong>all monitors</strong>
|
||||||
{:else}
|
{:else}
|
||||||
This will delete monitoring data for <strong>{monitorTagFilter}</strong> from {startDateTime} to {endDateTime}.
|
<strong>{monitorTagFilter}</strong>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if statusFilter !== "ALL"}
|
||||||
|
with status <strong>{statusFilter}</strong>
|
||||||
|
{/if}
|
||||||
|
from {startDateTime} to {endDateTime}.
|
||||||
This action cannot be undone.
|
This action cannot be undone.
|
||||||
</AlertDialog.Description>
|
</AlertDialog.Description>
|
||||||
</AlertDialog.Header>
|
</AlertDialog.Header>
|
||||||
|
|||||||
Reference in New Issue
Block a user