Skip to content

Commit

Permalink
Merge pull request #222 from rajnandan1/release/3.0.4
Browse files Browse the repository at this point in the history
Release/3.0.4
  • Loading branch information
rajnandan1 authored Jan 25, 2025
2 parents 9ed3558 + 46c1a39 commit 5f33c02
Show file tree
Hide file tree
Showing 12 changed files with 144 additions and 23 deletions.
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ RUN npm install && npm cache clean --force
# Copy the rest of the application code
COPY . .

# remove dir src/routes/(docs)
RUN rm -rf src/routes/\(docs\)

# Ensure /app/uploads and /app/database have rw permissions
RUN mkdir -p /app/uploads /app/database && \
chmod -R 777 /app/uploads /app/database
Expand Down
4 changes: 2 additions & 2 deletions docs/home.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Kener - A Sveltekit NodeJS Status Page System
description: Kener is an open-source Node.js status page tool, designed to make service monitoring and incident handling a breeze. It offers a sleek and user-friendly interface that simplifies tracking service outages and improves how we communicate during incidents.
title: Kener Documentation
description: Kener is a feature-rich and modern status page system built with SvelteKit and NodeJS. It is open-source and free to use.
---

# Kener - A Feature Rich & Modern Status Page
Expand Down
2 changes: 1 addition & 1 deletion docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ description: Roadmap for Kener

~~Handle uploaded images for docker containers~~

Introduce sitemap.xml
~~Introduce sitemap.xml~~

~~Migrate from moment to date-fns for status page~~ (moment remains in dashboard. Will remove later)

Expand Down
5 changes: 5 additions & 0 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import dotenv from "dotenv";
dotenv.config();
import express from "express";
import Startup from "./src/lib/server/startup.js";
import { GetSiteMap } from "./src/lib/server/controllers/controller.js";
import fs from "fs-extra";
import knex from "knex";
import knexOb from "./knexfile.js";
Expand All @@ -24,6 +25,10 @@ app.use((req, res, next) => {
app.get(base + "/healthcheck", (req, res) => {
res.end("ok");
});
app.get(base + "/sitemap.xml", async (req, res) => {
res.header("Content-Type", "application/xml");
res.send(await GetSiteMap());
});
//part /uploads server static files from static/uploads

//set env variable for upload path
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kener",
"version": "3.0.3",
"version": "3.0.4",
"private": false,
"license": "MIT",
"description": "Kener: An open-source Node.js status page application for real-time service monitoring, incident management, and customizable reporting. Simplify service outage tracking, enhance incident communication, and ensure a seamless user experience.",
Expand Down
5 changes: 1 addition & 4 deletions src/lib/components/shareMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,7 @@
{l(lang, "Embed")}
</h2>
<p class="mb-1 text-xs text-muted-foreground">
{@html l(
lang,
"Embed this moni2tor using &#x3C;script&#x3E; or &#x3C;iframe&#x3E; in your app."
)}
{l(lang, "Embed this monitor using &#x3C;script&#x3E; or &#x3C;iframe&#x3E; in your app.")}
</p>
<div class="mb-4 grid grid-cols-2 gap-2">
<div class="col-span-1">
Expand Down
12 changes: 2 additions & 10 deletions src/lib/i18n/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,15 @@ const fdm = function (duration, locale) {
};

const l = function (sessionLangMap, key, args = {}) {
const keys = key.split(".");
let obj = sessionLangMap;

for (const keyPart of keys) {
obj = obj?.[keyPart];
if (!obj) {
break;
}
}
let obj = sessionLangMap[key];

// Replace placeholders in the string using the args object
if (obj && typeof obj === "string") {
obj = obj.replace(/%\w+/g, (placeholder) => {
const argKey = placeholder.slice(1); // Remove the `%` to get the key
return args[argKey] !== undefined ? args[argKey] : placeholder;
});
}

return obj || key;
};
const summaryTime = function (summaryStatus) {
Expand Down
91 changes: 91 additions & 0 deletions src/lib/server/controllers/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import db from "../db/db.js";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import crypto from "crypto";
import { format, subMonths, addMonths, startOfMonth } from "date-fns";

const saltRounds = 10;
const DUMMY_SECRET = "DUMMY_SECRET";
Expand Down Expand Up @@ -805,3 +806,93 @@ export const IsLoggedInSession = async (cookies) => {
user: userDB
};
};

export const GetSiteMap = async (cookies) => {
let siteMapData = [];
let siteURLData = await GetSiteDataByKey("siteURL");
let categories = await GetSiteDataByKey("categories");
let navs = await GetSiteDataByKey("nav");
if (!!siteURLData) {
siteMapData.push({
url: siteURLData,
lastmod: new Date().toISOString(),
priority: 1
});
}

//get today's date in January-2025 format date-fns
const today = format(new Date(), "MMMM-yyyy");
//last month
const lastMonth = format(subMonths(new Date(), 1), "MMMM-yyyy", { addMonths: -1 });
const nextMonth = format(addMonths(new Date(), 1), "MMMM-yyyy", { addMonths: -1 });

siteMapData.push({
url: siteURLData + "/incidents/" + today,
lastmod: startOfMonth(new Date()).toISOString(),
priority: 0.9
});
siteMapData.push({
url: siteURLData + "/incidents/" + lastMonth,
lastmod: startOfMonth(new Date()).toISOString(),
priority: 0.9
});
siteMapData.push({
url: siteURLData + "/incidents/" + nextMonth,
lastmod: startOfMonth(new Date()).toISOString(),
priority: 0.9
});

if (!!categories) {
for (let i = 0; i < categories.length; i++) {
if (categories[i].name !== "Home") {
siteMapData.push({
url: siteURLData + "?category=" + categories[i].name,
lastmod: new Date().toISOString(),
priority: 0.9
});
}
}
}
if (!!navs) {
for (let i = 0; i < navs.length; i++) {
if (navs[i].url.startsWith(siteURLData)) {
siteMapData.push({
url: navs[i].url,
lastmod: new Date().toISOString(),
priority: 0.9
});
} else if (navs[i].url.startsWith("/")) {
siteMapData.push({
url: siteURLData + navs[i].url,
lastmod: new Date().toISOString(),
priority: 0.9
});
}
}
}

let monitors = await GetMonitors({ status: "ACTIVE" });

for (let i = 0; i < monitors.length; i++) {
siteMapData.push({
url: siteURLData + "?monitor=" + monitors[i].tag,
lastmod: new Date(monitors[i].updated_at).toISOString(),
priority: 0.8
});
}

return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${siteMapData
.map(
(page) => `
<url>
<loc>${page.url}</loc>
<lastmod>${page.lastmod}</lastmod>
<priority>${page.priority}</priority>
</url>
`
)
.join("")}
</urlset>`;
};
3 changes: 2 additions & 1 deletion src/routes/(docs)/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@

<svelte:window on:pagechange={pageChange} on:rightbar={updateTableOfContents} />
<svelte:head>
<title>Kener Documentation</title>
<link rel="icon" id="kener-app-favicon" href="{base}/logo96.png" />

<!-- Google tag (gtag.js) -->
Expand Down Expand Up @@ -86,7 +87,7 @@
<img src="https://kener.ing/logo.png" class="h-8 w-8" alt="" />
<span class="text-xl font-medium">Kener Documentation</span>
<span class="me-2 rounded border px-2.5 py-0.5 text-xs font-medium">
v3.0.3
v3.0.4
</span>
</a>
</div>
Expand Down
19 changes: 18 additions & 1 deletion src/routes/(kener)/+page.server.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export async function load({ parent, url }) {
const requiredCategory = query.get("category") || "Home";
const parentData = await parent();
const siteData = parentData.site;
let pageTitle = siteData.title;
let pageDescription = "";
monitors = SortMonitor(siteData.monitorSort, monitors);
const monitorsActive = [];
for (let i = 0; i < monitors.length; i++) {
Expand Down Expand Up @@ -50,6 +52,19 @@ export async function load({ parent, url }) {
//if not home page
let isCategoryPage = !!query.get("category") && query.get("category") !== "Home";
let isMonitorPage = !!query.get("monitor");
if (isMonitorPage && monitorsActive.length > 0) {
pageTitle = monitorsActive[0].name + " - " + pageTitle;
pageDescription = monitorsActive[0].description;
}
//if category page
if (isCategoryPage) {
let allCategories = siteData.categories;
let selectedCategory = allCategories.find((category) => category.name === requiredCategory);
if (selectedCategory) {
pageTitle = selectedCategory.name + " - " + pageTitle;
pageDescription = selectedCategory.description;
}
}
if (isCategoryPage || isMonitorPage) {
let eligibleTags = monitorsActive.map((monitor) => monitor.tag);
//filter incidents that have monitor_tag in monitors
Expand Down Expand Up @@ -90,6 +105,8 @@ export async function load({ parent, url }) {
unresolvedIncidents: allOpenIncidents,
categoryName: requiredCategory,
isCategoryPage: isCategoryPage,
isMonitorPage: isMonitorPage
isMonitorPage: isMonitorPage,
pageTitle: pageTitle,
pageDescription: pageDescription
};
}
14 changes: 11 additions & 3 deletions src/routes/(kener)/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,23 @@
if (data.isCategoryPage) {
let category = data.site.categories.find((e) => e.name == data.categoryName);
data.site.hero.title = category.name;
data.site.hero.subtitle = category.description;
if (!!category) {
data.site.hero.title = category.name;
data.site.hero.subtitle = category.description;
}
}
onMount(() => {
pageLoaded = true;
});
</script>

<svelte:head>
<title>{data.pageTitle}</title>
{#if !!data.pageDescription}
<meta name="description" content={data.pageDescription} />
{/if}
</svelte:head>
<div class="mt-12"></div>
{#if data.site.hero && !data.isMonitorPage}
<section
Expand Down Expand Up @@ -183,7 +191,7 @@
window.location.href = `?category=${category.name}`;
}}
>
<Card.Root class="hover:bg-secondary">
<Card.Root class="mb-4 hover:bg-secondary">
<Card.Header class="bounce-right relative w-full cursor-pointer px-4 ">
<Card.Title class="w-full ">
{category.name}
Expand Down
7 changes: 7 additions & 0 deletions src/routes/(kener)/incidents/[month]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@
let sortedIncidentSmartDates = Object.keys(incidentSmartDates).sort((a, b) => a - b);
</script>

<svelte:head>
<title>
{f(parse(data.thisMonthName, "MMMM-yyyy", new Date()), "MMMM, yyyy", selectedLang)}
{l(data.lang, "Incident Updates")} |
{data.site.title}
</title>
</svelte:head>
<div class="mt-12"></div>
<section class="mx-auto my-2 flex w-full max-w-[655px] flex-1 flex-col items-start justify-center">
<Button
Expand Down

0 comments on commit 5f33c02

Please sign in to comment.