mirror of
https://github.com/rajnandan1/kener.git
synced 2026-06-23 04:10:22 +00:00
updated ui
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="dark dark:bg-background">
|
||||
<html lang="en" >
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" id="kener-app-favicon" href="/kener.png" />
|
||||
|
||||
+7
-7
@@ -82,10 +82,10 @@ section {
|
||||
}
|
||||
.show-hover {
|
||||
display: none;
|
||||
top: -30px;
|
||||
padding: 4px 8px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
top: 30px;
|
||||
padding: 0px;
|
||||
/* width: 100%; */
|
||||
text-align: left;
|
||||
}
|
||||
.show-hover div {
|
||||
/* border-radius: 40px; */
|
||||
@@ -106,7 +106,7 @@ section {
|
||||
background-color: #00dfa2;
|
||||
}
|
||||
.text-api-up {
|
||||
color: #00dfa2;
|
||||
color: #0aca97;
|
||||
}
|
||||
.bgg-api-up {
|
||||
background: linear-gradient(to right, rgba(187, 219, 243, 0) 0%, rgba(0, 223, 162, 0.5) 50%, rgba(187, 219, 243, 0) 100%);
|
||||
@@ -124,7 +124,7 @@ section {
|
||||
background-color: rgba(100, 100, 100, .4);
|
||||
}
|
||||
.text-api-nodata {
|
||||
color: #f1f5f8;
|
||||
color: #b8bcbe;
|
||||
}
|
||||
.bgg-api-down {
|
||||
background: linear-gradient(to right, rgba(187, 219, 243, 0) 0%, rgba(246, 50, 50, 0.5) 50%, rgba(187, 219, 243, 0) 100%);
|
||||
@@ -160,7 +160,7 @@ section {
|
||||
}
|
||||
.today-sq-div {
|
||||
cursor: pointer;
|
||||
padding-bottom: 20px;
|
||||
/* padding-bottom: 20px; */
|
||||
}
|
||||
.today-sq {
|
||||
position: relative;
|
||||
|
||||
+116
-101
@@ -7,7 +7,7 @@
|
||||
import { Skeleton } from "$lib/components/ui/skeleton";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import axios from "axios";
|
||||
import { ArrowDown, ArrowUp, ArrowRight, BadgeCheck, Dot } from "lucide-svelte";
|
||||
import { ArrowDown, ArrowUp, ArrowRight, BadgeCheck, Dot, PackageCheck, Check, BadgeInfo } from "lucide-svelte";
|
||||
import { buttonVariants } from "$lib/components/ui/button";
|
||||
import * as Alert from "$lib/components/ui/alert";
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
|
||||
export let monitor;
|
||||
let loading90 = true;
|
||||
let todayDD = getTodayDD()
|
||||
let todayDD = getTodayDD();
|
||||
|
||||
let uptime90Day = "0";
|
||||
let uptime0Day = "0";
|
||||
let dailyUps = 0;
|
||||
@@ -81,7 +82,6 @@
|
||||
dailyDown = res.data.dailyDown;
|
||||
dailyDegraded = res.data.dailyDegraded;
|
||||
|
||||
|
||||
|
||||
loading90 = false;
|
||||
};
|
||||
@@ -91,108 +91,123 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<section class="mx-auto backdrop-blur-[2px] mb-8 flex w-full max-w-[770px] flex-1 flex-col items-start justify-center">
|
||||
<section class="mx-auto backdrop-blur-[2px] mb-8 flex w-full max-w-[880px] flex-1 flex-col items-start justify-center">
|
||||
<Card.Root class="w-full">
|
||||
<Card.Header>
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div class="col-span-3 md:col-span-2 relative {!!monitor.image?'pl-11':''}">
|
||||
{#if monitor.image}
|
||||
<img src="{monitor.image}" class="w-8 h-8 left-0 top-[1px] absolute" alt="" srcset="">
|
||||
{/if}
|
||||
<Card.Title>
|
||||
{monitor.name}
|
||||
</Card.Title>
|
||||
{#if monitor.description}
|
||||
<Card.Description class="mt-1">
|
||||
{monitor.description}
|
||||
</Card.Description>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="col-span-3 md:col-span-1 md:text-right">
|
||||
{#if monitor.hasActiveIncident}
|
||||
<a href="incident/{monitor.folderName}">
|
||||
|
||||
<a href="/incident/{monitor.folderName}#active_incident" class="{buttonVariants({ variant: "outline" })} relative">
|
||||
<span class="animate-ping absolute -right-[2px] -top-[2px] w-[8px] h-[8px] inline-flex rounded-full h-3 w-3 bg-red-500 opacity-75"></span>
|
||||
Ongoing Incident
|
||||
</a>
|
||||
</a>
|
||||
{:else if _90Day[todayDD] && _90Day[todayDD].cssClass == statusObj.DOWN}
|
||||
<p class="text-destructive mt-3 text-sm font-semibold">
|
||||
Down for {_90Day[todayDD].DOWN} minutes
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Separator class="mb-4 mt-1" />
|
||||
<Card.Content>
|
||||
<div class="grid grid-cols-3 gap-4 mb-4">
|
||||
<div class="col-span-3 sm:col-span-2 text-left">
|
||||
<Button class="h-9 px-4 py-2 w-48 rounded-full sm:w-auto" variant="{view != '90day' ? 'ghost' : ''}" on:click="{(e) => {switchView('90day')}}">90 Day</Button>
|
||||
<Button class="h-9 px-4 py-2 w-48 rounded-full sm:w-auto" variant="{view != '0day' ? 'ghost' : ''}" on:click="{(e) => {switchView('0day')}}">Today</Button>
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-1 sm:text-right">
|
||||
|
||||
<a href="/incident/{monitor.folderName}#past_incident" class={buttonVariants({ variant: "ghost" })}>
|
||||
Past Incidents <ArrowRight size="{16}" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if view == "90day"}
|
||||
<div>
|
||||
{#if loading90}
|
||||
<Skeleton class="w-[720px] h-[40px] mt-4" />
|
||||
{:else}
|
||||
<div class="uptime90Day text-sm font-semibold mb-1 text-center">
|
||||
Uptime for 90 Day is {uptime90Day}% / {avgLatency90Day} ms AVG latency
|
||||
</div>
|
||||
<div class="chart-status relative">
|
||||
<div class="flex flex-wrap">
|
||||
{#each Object.entries(_90Day) as [ts, bar]}
|
||||
<div class="h-[40px] w-[8px] rounded-sm oneline">
|
||||
<div class="h-[40px] bg-{bar.cssClass} w-[6px] rounded-sm mr-[2px]"></div>
|
||||
</div>
|
||||
<div class="absolute show-hover text-sm bg-background">
|
||||
<div class="bgg-{bar.cssClass}">{bar.timestamp} / {bar.message} / {bar.uptimePercentage}% up / {bar.avgLatency} ms AVG latency</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="uptime90Day mb-1 text-sm font-semibold text-center">
|
||||
Uptime for today is {uptime0Day}% / {avgLatency0Day} ms AVG latency
|
||||
</div>
|
||||
<div class="flex flex-wrap today-sq-div mt-[45px]">
|
||||
{#each Object.entries(_0Day) as [ts, bar] }
|
||||
<div data-index="{bar.index}" class="h-[10px] bg-{bar.cssClass} w-[10px] today-sq m-[1px]" >
|
||||
|
||||
{#if bar.index == 0}
|
||||
<div class="arrow start text-sm">
|
||||
Midnight
|
||||
<ArrowDown size="{16}" />
|
||||
</div>
|
||||
{/if}
|
||||
{#if bar.index == minuteFromMidnightTillNow}
|
||||
<div class="arrow end text-sm">
|
||||
<ArrowUp size="{16}" />
|
||||
Now
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="hidden relative">
|
||||
<div data-index="{bar.index}" class="w-[300px] pb-2 pr-1 pl-1 text-sm text-center rounded font-semibold message bg-black text-white border ">
|
||||
<span class="text-{bar.cssClass} text-xl">•</span> {bar.timestamp} / {bar.status} / {bar.latency} ms
|
||||
<div class="grid grid-cols-12 gap-4">
|
||||
<div class="col-span-12 md:col-span-4">
|
||||
<div class="pt-3">
|
||||
<div class="scroll-m-20 text-2xl font-semibold tracking-tight">
|
||||
{#if monitor.image}
|
||||
<img src="{monitor.image}" class="w-6 h-6 inline" alt="" srcset="">
|
||||
{/if}
|
||||
{monitor.name}
|
||||
{#if monitor.description}
|
||||
<HoverCard.Root>
|
||||
<HoverCard.Trigger>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide inline lucide-info"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>
|
||||
</HoverCard.Trigger>
|
||||
<HoverCard.Content>
|
||||
{monitor.description}
|
||||
</HoverCard.Content>
|
||||
</HoverCard.Root>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{#if !loading90}
|
||||
<div class="pt-2">
|
||||
{#if view == "90day"}
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Uptime for <span class="text-foreground font-semibold">90 Day</span> is {uptime90Day}% and avg latency is {avgLatency90Day} ms
|
||||
</p>
|
||||
{:else}
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Uptime for <span class="text-foreground font-semibold">Today</span> is {uptime0Day}% and avg latency is {avgLatency0Day} ms
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="col-span-12 md:col-span-8 pt-4">
|
||||
{#if loading90}
|
||||
<Skeleton class="w-full h-[40px] mt-[7px]" />
|
||||
{:else}
|
||||
<div class="grid grid-cols-12 ">
|
||||
<div class="col-span-12 md:col-span-4 mt-2 h-[38px]">
|
||||
<a href="javascript:void(0);" on:click="{(e) => {switchView('90day')}}">
|
||||
<Badge variant="{view != '90day' ? 'outline' : ''}">
|
||||
90 Day
|
||||
</Badge>
|
||||
</a>
|
||||
<a href="javascript:void(0);" on:click="{(e) => {switchView('0day')}}">
|
||||
<Badge variant="{view != '0day' ? 'outline' : ''}" >
|
||||
Today
|
||||
</Badge>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<div class="col-span-12 md:col-span-8 text-right h-[38px]">
|
||||
|
||||
{#if monitor.hasActiveIncident}
|
||||
<a href="/incident/{monitor.folderName}#active_incident" class="{buttonVariants({ variant: "outline" })} relative">
|
||||
<span class="animate-ping absolute -right-[2px] -top-[2px] w-[8px] h-[8px] inline-flex rounded-full bg-red-500 opacity-75"></span>
|
||||
Ongoing Incident
|
||||
</a>
|
||||
{:else if _90Day[todayDD]}
|
||||
<div class="text-api-up text-sm font-semibold mt-[12px] text-{_90Day[todayDD].cssClass}">
|
||||
{_90Day[todayDD].message}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-12">
|
||||
{#if view == "90day"}
|
||||
<div class="chart-status relative mt-1 col-span-12">
|
||||
<div class="flex flex-wrap">
|
||||
{#each Object.entries(_90Day) as [ts, bar]}
|
||||
<div class="h-[30px] w-[6px] rounded-sm oneline">
|
||||
<div class="h-[30px] bg-{bar.cssClass} w-[4px] rounded-sm mr-[2px]"></div>
|
||||
</div>
|
||||
<div class="absolute show-hover text-sm bg-background">
|
||||
<div class="text-{bar.cssClass} font-semibold" >
|
||||
{#if bar.message != "No Data"}
|
||||
{bar.timestamp} / {bar.uptimePercentage}% up / {bar.avgLatency} ms AVG latency
|
||||
{:else}
|
||||
{bar.timestamp} / {bar.message}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="chart-status relative mt-1 col-span-12">
|
||||
<div class="flex flex-wrap today-sq-div ">
|
||||
{#each Object.entries(_0Day) as [ts, bar] }
|
||||
<div data-index="{bar.index}" class="h-[10px] bg-{bar.cssClass} w-[10px] today-sq m-[1px]" >
|
||||
|
||||
</div>
|
||||
<div class="hidden relative">
|
||||
<div data-index="{bar.index}" class="w-[300px] pb-2 pr-1 pl-1 text-sm text-center rounded font-semibold message bg-black text-white border ">
|
||||
<span class="text-{bar.cssClass} text-xl">•</span> {bar.timestamp} / {bar.status} / {bar.latency} ms
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="col-span-12 text-right ">
|
||||
<a href="/incident/{monitor.folderName}#past_incident" class="-mr-4 {buttonVariants({ variant: 'link' })}">
|
||||
Past Incidents <ArrowRight size="{16}" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</section>
|
||||
|
||||
@@ -40,6 +40,7 @@ export async function POST({ request }) {
|
||||
let dailyLatencyBuildUp = [];
|
||||
const now = moment.tz(tz);
|
||||
let minuteFromMidnightTillNow = now.diff(now.clone().startOf("day"), "minutes");
|
||||
const midnight90DaysAgo = now.clone().subtract(90, "days").startOf("day");
|
||||
for (let i = 0; i <= minuteFromMidnightTillNow; i++) {
|
||||
let eachMin = moment.tz(tz).startOf("day").add(i, "minutes").format("YYYY-MM-DD HH:mm:00");
|
||||
_0Day[eachMin] = {
|
||||
@@ -50,6 +51,20 @@ export async function POST({ request }) {
|
||||
index: i,
|
||||
};
|
||||
}
|
||||
for (let i = 0; i <= 90; i++) {
|
||||
let eachDay = midnight90DaysAgo.clone().add(i, "days").format("YYYY-MM-DD");
|
||||
_90Day[eachDay] = {
|
||||
timestamp: eachDay,
|
||||
UP: 0,
|
||||
DEGRADED: 0,
|
||||
DOWN: 0,
|
||||
uptimePercentage: 0,
|
||||
avgLatency: 0,
|
||||
latency: 0,
|
||||
cssClass: statusObj.NO_DATA,
|
||||
message: "No Data",
|
||||
};
|
||||
}
|
||||
|
||||
let day0 = JSON.parse(fs.readFileSync(payload.day0, "utf8"));
|
||||
|
||||
@@ -63,30 +78,19 @@ export async function POST({ request }) {
|
||||
let latency = element.latency;
|
||||
|
||||
//90 Day data
|
||||
if (_90Day[day] === undefined) {
|
||||
_90Day[day] = {
|
||||
timestamp: day,
|
||||
UP: status == "UP" ? 1 : 0,
|
||||
DEGRADED: status == "DEGRADED" ? 1 : 0,
|
||||
DOWN: status == "DOWN" ? 1 : 0,
|
||||
latency: latency,
|
||||
avgLatency: latency,
|
||||
};
|
||||
} else {
|
||||
let d = _90Day[day];
|
||||
_90Day[day] = {
|
||||
timestamp: day,
|
||||
UP: status == "UP" ? d.UP + 1 : d.UP,
|
||||
DEGRADED: status == "DEGRADED" ? d.DEGRADED + 1 : d.DEGRADED,
|
||||
DOWN: status == "DOWN" ? d.DOWN + 1 : d.DOWN,
|
||||
latency: d.latency + latency,
|
||||
avgLatency: ((d.latency + latency) / (d.UP + d.DEGRADED + d.DOWN + 1)).toFixed(0),
|
||||
};
|
||||
}
|
||||
let d = _90Day[day];
|
||||
_90Day[day] = {
|
||||
timestamp: day,
|
||||
UP: status == "UP" ? d.UP + 1 : d.UP,
|
||||
DEGRADED: status == "DEGRADED" ? d.DEGRADED + 1 : d.DEGRADED,
|
||||
DOWN: status == "DOWN" ? d.DOWN + 1 : d.DOWN,
|
||||
latency: d.latency + latency,
|
||||
avgLatency: ((d.latency + latency) / (d.UP + d.DEGRADED + d.DOWN + 1)).toFixed(0),
|
||||
};
|
||||
_90Day[day].uptimePercentage = parseUptime(_90Day[day].UP + _90Day[day].DEGRADED, _90Day[day].UP + _90Day[day].DEGRADED + _90Day[day].DOWN);
|
||||
|
||||
let cssClass = statusObj.UP;
|
||||
let message = "0 Issues";
|
||||
let message = "OK";
|
||||
|
||||
if (_90Day[day].DEGRADED > 0) {
|
||||
cssClass = statusObj.DEGRADED;
|
||||
@@ -119,6 +123,7 @@ export async function POST({ request }) {
|
||||
for (const key in _90Day) {
|
||||
if (Object.hasOwnProperty.call(_90Day, key)) {
|
||||
const element = _90Day[key];
|
||||
if(element.message == "No Data") continue;
|
||||
percentage90DaysBuildUp.push(parseFloat(element.uptimePercentage));
|
||||
latency90DaysBuildUp.push(parseFloat(element.avgLatency));
|
||||
}
|
||||
|
||||
@@ -54,8 +54,7 @@
|
||||
<div class="bg-white pt-6 p-0 md:p-10">
|
||||
<article
|
||||
id="markdown"
|
||||
class="prose prose-stone max-w-none prose-code:bg-gray-200 prose-code:px-[0.3rem] prose-code:py-[0.2rem] prose-code:font-mono prose-code:text-sm prose-code:rounded prose-code:font-mono"
|
||||
>
|
||||
class="prose prose-stone max-w-none prose-code:bg-gray-200 prose-code:px-[0.3rem] prose-code:py-[0.2rem] prose-code:font-mono prose-code:text-sm prose-code:rounded">
|
||||
{@html html}
|
||||
</article>
|
||||
</div>
|
||||
|
||||
@@ -34,14 +34,19 @@
|
||||
<Card.Description> {moment(incident.created_at).format("MMMM Do YYYY, h:mm:ss a")} </Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
{@html incident.body} {#if incident.comments.length > 0}
|
||||
<div class="prose prose-stone max-w-none prose-code:bg-gray-200 prose-code:px-[0.3rem] prose-code:py-[0.2rem] prose-code:font-mono prose-code:text-sm prose-code:rounded">
|
||||
{@html incident.body}
|
||||
</div>
|
||||
{#if incident.comments.length > 0}
|
||||
<div class="ml-4 mt-8">
|
||||
<ol class="relative border-s border-secondary">
|
||||
{#each incident.comments as comment}
|
||||
<li class="mb-10 ms-4">
|
||||
<div class="absolute w-3 h-3 rounded-full mt-1.5 -start-1.5 border border-secondary bg-secondary border-secondary"></div>
|
||||
<div class="absolute w-3 h-3 rounded-full mt-1.5 -start-1.5 border bg-secondary border-secondary"></div>
|
||||
<time class="mb-1 text-sm font-normal leading-none text-muted-foreground"> {moment(comment.created_at).format("MMMM Do YYYY, h:mm:ss a")} </time>
|
||||
<div class="mb-4 text-base font-normal wysiwyg">{@html comment.body}</div>
|
||||
<div class="mb-4 text-base font-normal wysiwyg prose prose-stone max-w-none prose-code:bg-gray-200 prose-code:px-[0.3rem] prose-code:py-[0.2rem] prose-code:font-mono prose-code:text-sm prose-code:rounded">
|
||||
{@html comment.body}
|
||||
</div>
|
||||
</li>
|
||||
{/each}
|
||||
</ol>
|
||||
@@ -85,14 +90,17 @@
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content>
|
||||
<Card.Content>
|
||||
{@html incident.body} {#if incident.comments.length > 0}
|
||||
<div class="prose prose-stone max-w-none prose-code:bg-gray-200 prose-code:px-[0.3rem] prose-code:py-[0.2rem] prose-code:font-mono prose-code:text-sm prose-code:rounded">
|
||||
{@html incident.body}
|
||||
</div>
|
||||
{#if incident.comments.length > 0}
|
||||
<div class="ml-4 mt-8">
|
||||
<ol class="relative border-s border-secondary">
|
||||
{#each incident.comments as comment}
|
||||
<li class="mb-10 ms-4">
|
||||
<div class="absolute w-3 h-3 rounded-full mt-1.5 -start-1.5 border border-secondary bg-secondary border-secondary"></div>
|
||||
<div class="absolute w-3 h-3 rounded-full mt-1.5 -start-1.5 border border-secondary bg-secondary"></div>
|
||||
<time class="mb-1 text-sm font-normal leading-none text-muted-foreground"> {moment(comment.created_at).format("MMMM Do YYYY, h:mm:ss a")} </time>
|
||||
<div class="mb-4 wysiwyg text-base font-normal">{@html comment.body}</div>
|
||||
<div class="mb-4 wysiwyg text-base font-normal prose prose-stone max-w-none prose-code:bg-gray-200 prose-code:px-[0.3rem] prose-code:py-[0.2rem] prose-code:font-mono prose-code:text-sm prose-code:rounded">{@html comment.body}</div>
|
||||
</li>
|
||||
{/each}
|
||||
</ol>
|
||||
|
||||
Reference in New Issue
Block a user