mirror of
https://github.com/rajnandan1/kener.git
synced 2026-03-13 14:29:57 -05:00
added feature requested in Issue #45
This commit is contained in:
@@ -143,7 +143,8 @@ const apiCall = async (envSecrets, url, method, headers, body, timeout, monitorE
|
||||
statusCode = data.status;
|
||||
resp = data.data;
|
||||
} catch (err) {
|
||||
if (err.message.startsWith("timeout of") && err.message.endsWith("exceeded")) {
|
||||
|
||||
if (err.message.startsWith("timeout of") && err.message.endsWith("exceeded")) {
|
||||
timeoutError = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { FOLDER, FOLDER_MONITOR, FOLDER_SITE, API_TIMEOUT } from "./constants.js
|
||||
import { IsValidURL, IsValidHTTPMethod, LoadMonitorsPath, LoadSitePath } from "./tool.js";
|
||||
import { GetAllGHLabels, CreateGHLabel } from "./github.js";
|
||||
import { Minuter } from "./cron-minute.js";
|
||||
import axios from "axios";
|
||||
let monitors = [];
|
||||
let site = {};
|
||||
const envSecrets = [];
|
||||
@@ -71,20 +72,20 @@ const Startup = async () => {
|
||||
}
|
||||
|
||||
if(hasAPI) {
|
||||
let url = monitor.api.url;
|
||||
let method = monitor.api.method;
|
||||
let headers = monitor.api.headers;
|
||||
let evaluator = monitor.api.eval;
|
||||
let body = monitor.api.body;
|
||||
let timeout = monitor.api.timeout;
|
||||
//url
|
||||
if (!!url) {
|
||||
let url = monitor.api.url;
|
||||
let method = monitor.api.method;
|
||||
let headers = monitor.api.headers;
|
||||
let evaluator = monitor.api.eval;
|
||||
let body = monitor.api.body;
|
||||
let timeout = monitor.api.timeout;
|
||||
//url
|
||||
if (!!url) {
|
||||
if (!IsValidURL(url)) {
|
||||
console.log("url is not valid");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
if (!!method) {
|
||||
if (!!method) {
|
||||
if (!IsValidHTTPMethod(method)) {
|
||||
console.log("method is not valid");
|
||||
process.exit(1);
|
||||
@@ -94,20 +95,20 @@ const Startup = async () => {
|
||||
method = "GET";
|
||||
}
|
||||
monitors[i].api.method = method;
|
||||
//headers
|
||||
if (headers === undefined || headers === null) {
|
||||
//headers
|
||||
if (headers === undefined || headers === null) {
|
||||
monitors[i].api.headers = undefined;
|
||||
} else {
|
||||
//check if headers is a valid json
|
||||
try {
|
||||
JSON.parse(headers);
|
||||
JSON.parse(JSON.stringify(headers));
|
||||
} catch (error) {
|
||||
console.log("headers is not valid ");
|
||||
console.log("headers are not valid. Quiting");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
//eval
|
||||
if (evaluator === undefined || evaluator === null) {
|
||||
//eval
|
||||
if (evaluator === undefined || evaluator === null) {
|
||||
monitors[i].api.eval = defaultEval;
|
||||
} else {
|
||||
let evalResp = eval(evaluator + `(200, 1000, "")`);
|
||||
@@ -116,27 +117,52 @@ const Startup = async () => {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
//body
|
||||
if (body === undefined || body === null) {
|
||||
//body
|
||||
if (body === undefined || body === null) {
|
||||
monitors[i].api.body = undefined;
|
||||
} else {
|
||||
//check if body is a valid string
|
||||
if (typeof body !== "string") {
|
||||
console.log("body is not valid should be a string");
|
||||
process.exit(1);
|
||||
}
|
||||
if (typeof body !== "string") {
|
||||
console.log("body is not valid should be a string");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
//timeout
|
||||
if (timeout === undefined || timeout === null) {
|
||||
//timeout
|
||||
if (timeout === undefined || timeout === null) {
|
||||
monitors[i].api.timeout = API_TIMEOUT;
|
||||
} else {
|
||||
//check if timeout is a valid number
|
||||
if (isNaN(timeout) || timeout < 0) {
|
||||
//check if timeout is a valid number
|
||||
if (isNaN(timeout) || timeout < 0) {
|
||||
console.log("timeout is not valid ");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//add a description to the monitor if it is website using api.url and method = GET and headers == undefined
|
||||
//call the it to see if recevied content-type is text/html
|
||||
//if yes, append to description
|
||||
if ((headers === undefined || headers === null) && url !== undefined && method === "GET") {
|
||||
|
||||
try {
|
||||
const response = await axios({
|
||||
method: "GET",
|
||||
url: url,
|
||||
timeout: API_TIMEOUT,
|
||||
});
|
||||
if (response.headers["content-type"].includes("text/html")) {
|
||||
let link = `<a href="${url}" class="font-medium underline underline-offset-4" target="_blank">${url}</a>`;
|
||||
if(monitors[i].description === undefined) {
|
||||
monitors[i].description = link;
|
||||
} else {
|
||||
monitors[i].description = monitors[i].description?.trim() + " " + link;
|
||||
}
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
monitors[i].path0Day = `${FOLDER}/${folderName}.0day.utc.json`;
|
||||
monitors[i].hasAPI = hasAPI;
|
||||
|
||||
@@ -345,7 +345,7 @@
|
||||
transition: transform 0.1s ease-in;
|
||||
cursor: pointer;
|
||||
}
|
||||
.oneline:hover {
|
||||
.oneline:hover {
|
||||
transform: scaleY(1.2);
|
||||
}
|
||||
|
||||
@@ -356,7 +356,7 @@
|
||||
|
||||
.show-hover {
|
||||
display: none;
|
||||
top: 30px;
|
||||
top: 40px;
|
||||
padding: 0px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@@ -2,85 +2,128 @@
|
||||
import Monitor from "$lib/components/monitor.svelte";
|
||||
import * as Card from "$lib/components/ui/card";
|
||||
import { Button, buttonVariants } from "$lib/components/ui/button";
|
||||
import Incident from "$lib/components/incident.svelte";
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
export let data;
|
||||
let hasActiveIncidents = data.openIncidents.length > 0;
|
||||
|
||||
const imports = {
|
||||
incident: () => import("$lib/components/incident.svelte"),
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="mt-32"></div>
|
||||
{#if data.site.hero}
|
||||
<section class="mx-auto mb-8 flex w-full max-w-4xl flex-1 flex-col items-start justify-center">
|
||||
<div class="mx-auto max-w-screen-xl px-4 lg:flex lg:items-center">
|
||||
<div class="blurry-bg mx-auto max-w-3xl text-center">
|
||||
{#if data.site.hero.image}
|
||||
<img src="{data.site.hero.image}" class="m-auto h-16 w-16" alt="" srcset="" />
|
||||
{/if} {#if data.site.hero.title}
|
||||
<h1 class="bg-gradient-to-r from-green-300 via-blue-500 to-purple-600 bg-clip-text text-5xl font-extrabold leading-snug text-transparent">{data.site.hero.title}</h1>
|
||||
{/if} {#if data.site.hero.subtitle}
|
||||
<p class="mx-auto mt-4 max-w-xl sm:text-xl">{data.site.hero.subtitle}</p>
|
||||
{/if}
|
||||
<section
|
||||
class="mx-auto mb-8 flex w-full max-w-4xl flex-1 flex-col items-start justify-center"
|
||||
>
|
||||
<div class="mx-auto max-w-screen-xl px-4 lg:flex lg:items-center">
|
||||
<div class="blurry-bg mx-auto max-w-3xl text-center">
|
||||
{#if data.site.hero.image}
|
||||
<img
|
||||
src={data.site.hero.image}
|
||||
class="m-auto h-16 w-16"
|
||||
alt=""
|
||||
srcset=""
|
||||
/>
|
||||
{/if}
|
||||
{#if data.site.hero.title}
|
||||
<h1
|
||||
class="bg-gradient-to-r from-green-300 via-blue-500 to-purple-600 bg-clip-text text-5xl font-extrabold leading-snug text-transparent"
|
||||
>
|
||||
{data.site.hero.title}
|
||||
</h1>
|
||||
{/if}
|
||||
{#if data.site.hero.subtitle}
|
||||
<p class="mx-auto mt-4 max-w-xl sm:text-xl">
|
||||
{data.site.hero.subtitle}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{/if} {#if hasActiveIncidents}
|
||||
<section class="mx-auto mb-4 flex w-full max-w-[890px] flex-1 flex-col items-start justify-center bg-transparent" id="">
|
||||
<div class="grid w-full grid-cols-2 gap-4">
|
||||
<div class="col-span-2 text-center md:col-span-1 md:text-left">
|
||||
<Badge variant="outline">Ongoing Incidents</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="mx-auto mb-8 flex w-full max-w-[890px] flex-1 flex-col items-start justify-center backdrop-blur-[2px]" id="">
|
||||
{#each data.openIncidents as incident, i} {#await imports["incident"]() then module}
|
||||
<svelte:component this="{module.default}" {incident} state="close" variant="title+body+comments+monitor" monitor="{incident.monitor}" />
|
||||
{/await} {/each}
|
||||
</section>
|
||||
{/if} {#if data.monitors.length > 0}
|
||||
<section class="mx-auto mb-4 flex w-full max-w-[890px] flex-1 flex-col items-start justify-center bg-transparent" id="">
|
||||
<div class="grid w-full grid-cols-2 gap-4">
|
||||
<div class="col-span-2 text-center md:col-span-1 md:text-left">
|
||||
<Badge class="" variant="outline"> Availability per Component </Badge>
|
||||
</div>
|
||||
<div class="col-span-2 text-center md:col-span-1 md:text-right">
|
||||
<Badge variant="outline">
|
||||
<span class="bg-api-up mr-1 inline-flex h-[8px] w-[8px] rounded-full opacity-75"></span>
|
||||
<span class="mr-3">UP</span>
|
||||
|
||||
<span class="bg-api-degraded mr-1 inline-flex h-[8px] w-[8px] rounded-full opacity-75"></span>
|
||||
<span class="mr-3">DEGRADED</span>
|
||||
|
||||
<span class="bg-api-down mr-1 inline-flex h-[8px] w-[8px] rounded-full opacity-75"></span>
|
||||
<span class="mr-3">DOWN</span>
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="mx-auto mb-8 flex w-full max-w-[890px] flex-1 flex-col items-start justify-center backdrop-blur-[2px]">
|
||||
<Card.Root>
|
||||
<Card.Content class="monitors-card p-0">
|
||||
{#each data.monitors as monitor}
|
||||
<Monitor {monitor} localTz="{data.localTz}" />
|
||||
{/each}
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</section>
|
||||
{/if} {#if data.site.categories}
|
||||
<section class="mx-auto mb-8 w-full max-w-[890px] backdrop-blur-[2px]">
|
||||
<h2 class="mb-2 mt-2 px-2 text-xl font-semibold">Other Monitors</h2>
|
||||
{#each data.site.categories as category}
|
||||
<Card.Root class="mb-2 w-full">
|
||||
<Card.Header>
|
||||
<Card.Title>{category.name}</Card.Title>
|
||||
<Card.Description class="relative pr-[100px]">
|
||||
{#if category.description} {category.description} {/if}
|
||||
<a href="/category-{category.name}" class="{buttonVariants({ variant: 'secondary', })} absolute -top-4 right-2"> View </a>
|
||||
</Card.Description>
|
||||
</Card.Header>
|
||||
</Card.Root>
|
||||
{/each}
|
||||
</section>
|
||||
</section>
|
||||
{/if}
|
||||
{#if hasActiveIncidents}
|
||||
<section
|
||||
class="mx-auto mb-4 flex w-full max-w-[890px] flex-1 flex-col items-start justify-center bg-transparent"
|
||||
id=""
|
||||
>
|
||||
<div class="grid w-full grid-cols-2 gap-4">
|
||||
<div class="col-span-2 text-center md:col-span-1 md:text-left">
|
||||
<Badge variant="outline">Ongoing Incidents</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
class="mx-auto mb-8 flex w-full max-w-[890px] flex-1 flex-col items-start justify-center backdrop-blur-[2px]"
|
||||
id=""
|
||||
>
|
||||
{#each data.openIncidents as incident, i}
|
||||
<Incident {incident} state="close" variant="title+body+comments+monitor" monitor="{incident.monitor}" />
|
||||
{/each}
|
||||
</section>
|
||||
{/if}
|
||||
{#if data.monitors.length > 0}
|
||||
<section
|
||||
class="mx-auto mb-4 flex w-full max-w-[890px] flex-1 flex-col items-start justify-center bg-transparent"
|
||||
id=""
|
||||
>
|
||||
<div class="grid w-full grid-cols-2 gap-4">
|
||||
<div class="col-span-2 text-center md:col-span-1 md:text-left">
|
||||
<Badge class="" variant="outline">
|
||||
Availability per Component
|
||||
</Badge>
|
||||
</div>
|
||||
<div class="col-span-2 text-center md:col-span-1 md:text-right">
|
||||
<Badge variant="outline">
|
||||
<span
|
||||
class="bg-api-up mr-1 inline-flex h-[8px] w-[8px] rounded-full opacity-75"
|
||||
></span>
|
||||
<span class="mr-3">UP</span>
|
||||
|
||||
<span
|
||||
class="bg-api-degraded mr-1 inline-flex h-[8px] w-[8px] rounded-full opacity-75"
|
||||
></span>
|
||||
<span class="mr-3">DEGRADED</span>
|
||||
|
||||
<span
|
||||
class="bg-api-down mr-1 inline-flex h-[8px] w-[8px] rounded-full opacity-75"
|
||||
></span>
|
||||
<span class="mr-3">DOWN</span>
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
class="mx-auto mb-8 flex w-full max-w-[890px] flex-1 flex-col items-start justify-center backdrop-blur-[2px]"
|
||||
>
|
||||
<Card.Root>
|
||||
<Card.Content class="monitors-card p-0">
|
||||
{#each data.monitors as monitor}
|
||||
<Monitor {monitor} localTz={data.localTz} />
|
||||
{/each}
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</section>
|
||||
{/if}
|
||||
{#if data.site.categories}
|
||||
<section class="mx-auto mb-8 w-full max-w-[890px] backdrop-blur-[2px]">
|
||||
<h2 class="mb-2 mt-2 px-2 text-xl font-semibold">Other Monitors</h2>
|
||||
{#each data.site.categories as category}
|
||||
<Card.Root class="mb-2 w-full">
|
||||
<Card.Header>
|
||||
<Card.Title>{category.name}</Card.Title>
|
||||
<Card.Description class="relative pr-[100px]">
|
||||
{#if category.description}
|
||||
{category.description}
|
||||
{/if}
|
||||
<a
|
||||
href="/category-{category.name}"
|
||||
class="{buttonVariants({
|
||||
variant: 'secondary',
|
||||
})} absolute -top-4 right-2"
|
||||
>
|
||||
View
|
||||
</a>
|
||||
</Card.Description>
|
||||
</Card.Header>
|
||||
</Card.Root>
|
||||
{/each}
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user