mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-01-18 18:38:07 +00:00
[Status Page] SSR
This commit is contained in:
parent
ffb7ba176c
commit
c095767f4a
6 changed files with 92 additions and 29 deletions
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"version": "1.15.1",
|
"version": "1.16.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"version": "1.15.1",
|
"version": "1.16.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "~1.2.36",
|
"@fortawesome/fontawesome-svg-core": "~1.2.36",
|
||||||
|
|
|
@ -1,11 +1,34 @@
|
||||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const cheerio = require("cheerio");
|
const cheerio = require("cheerio");
|
||||||
|
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||||
|
|
||||||
class StatusPage extends BeanModel {
|
class StatusPage extends BeanModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like this: { "test-uptime.kuma.pet": "default" }
|
||||||
|
* @type {{}}
|
||||||
|
*/
|
||||||
static domainMappingList = { };
|
static domainMappingList = { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Response} response
|
||||||
|
* @param {string} indexHTML
|
||||||
|
* @param {string} slug
|
||||||
|
*/
|
||||||
|
static async handleStatusPageResponse(response, indexHTML, slug) {
|
||||||
|
let statusPage = await R.findOne("status_page", " slug = ? ", [
|
||||||
|
slug
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (statusPage) {
|
||||||
|
response.send(StatusPage.renderHTML(indexHTML, statusPage));
|
||||||
|
} else {
|
||||||
|
response.status(404).send(UptimeKumaServer.getInstance().indexHTML);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SSR for status pages
|
* SSR for status pages
|
||||||
* @param {string} indexHTML
|
* @param {string} indexHTML
|
||||||
|
@ -14,6 +37,17 @@ class StatusPage extends BeanModel {
|
||||||
static renderHTML(indexHTML, statusPage) {
|
static renderHTML(indexHTML, statusPage) {
|
||||||
const $ = cheerio.load(indexHTML);
|
const $ = cheerio.load(indexHTML);
|
||||||
|
|
||||||
|
$("title").text(statusPage.title);
|
||||||
|
$("meta[name=description]").attr("content", statusPage.description.substring(0, 155));
|
||||||
|
|
||||||
|
if (statusPage.icon) {
|
||||||
|
$("link[rel=icon]")
|
||||||
|
.attr("href", statusPage.icon)
|
||||||
|
.removeAttr("type");
|
||||||
|
}
|
||||||
|
|
||||||
|
const head = $("head");
|
||||||
|
|
||||||
return $.root().html();
|
return $.root().html();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
server/routers/status-page-router.js
Normal file
26
server/routers/status-page-router.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
let express = require("express");
|
||||||
|
const apicache = require("../modules/apicache");
|
||||||
|
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||||
|
const StatusPage = require("../model/status_page");
|
||||||
|
|
||||||
|
let router = express.Router();
|
||||||
|
|
||||||
|
let cache = apicache.middleware;
|
||||||
|
const server = UptimeKumaServer.getInstance();
|
||||||
|
|
||||||
|
router.get("/status/:slug", cache("5 minutes"), async (request, response) => {
|
||||||
|
let slug = request.params.slug;
|
||||||
|
await StatusPage.handleStatusPageResponse(response, server.indexHTML, slug);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/status", cache("5 minutes"), async (request, response) => {
|
||||||
|
let slug = "default";
|
||||||
|
await StatusPage.handleStatusPageResponse(response, server.indexHTML, slug);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/status-page", cache("5 minutes"), async (request, response) => {
|
||||||
|
let slug = "default";
|
||||||
|
await StatusPage.handleStatusPageResponse(response, server.indexHTML, slug);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -124,6 +124,7 @@ const TwoFA = require("./2fa");
|
||||||
const StatusPage = require("./model/status_page");
|
const StatusPage = require("./model/status_page");
|
||||||
const { cloudflaredSocketHandler, autoStart: cloudflaredAutoStart, stop: cloudflaredStop } = require("./socket-handlers/cloudflared-socket-handler");
|
const { cloudflaredSocketHandler, autoStart: cloudflaredAutoStart, stop: cloudflaredStop } = require("./socket-handlers/cloudflared-socket-handler");
|
||||||
const { proxySocketHandler } = require("./socket-handlers/proxy-socket-handler");
|
const { proxySocketHandler } = require("./socket-handlers/proxy-socket-handler");
|
||||||
|
const apiRouter = require("./routers/api-router");
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
|
@ -148,22 +149,6 @@ let jwtSecret = null;
|
||||||
*/
|
*/
|
||||||
let needSetup = false;
|
let needSetup = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache Index HTML
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
let indexHTML = "";
|
|
||||||
|
|
||||||
try {
|
|
||||||
indexHTML = fs.readFileSync("./dist/index.html").toString();
|
|
||||||
} catch (e) {
|
|
||||||
// "dist/index.html" is not necessary for development
|
|
||||||
if (process.env.NODE_ENV !== "development") {
|
|
||||||
log.error("server", "Error: Cannot find 'dist/index.html', did you install correctly?");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
Database.init(args);
|
Database.init(args);
|
||||||
await initDatabase(testMode);
|
await initDatabase(testMode);
|
||||||
|
@ -179,14 +164,17 @@ try {
|
||||||
|
|
||||||
// Entry Page
|
// Entry Page
|
||||||
app.get("/", async (request, response) => {
|
app.get("/", async (request, response) => {
|
||||||
debug(`Request Domain: ${request.hostname}`);
|
log.debug("entry", `Request Domain: ${request.hostname}`);
|
||||||
|
|
||||||
if (request.hostname in StatusPage.domainMappingList) {
|
if (request.hostname in StatusPage.domainMappingList) {
|
||||||
debug("This is a status page domain");
|
log.debug("entry", "This is a status page domain");
|
||||||
// TODO
|
|
||||||
response.send(StatusPage.renderHTML(indexHTML));
|
let slug = StatusPage.domainMappingList[request.hostname];
|
||||||
|
await StatusPage.handleStatusPageResponse(response, server.indexHTML, slug);
|
||||||
|
|
||||||
} else if (exports.entryPage && exports.entryPage.startsWith("statusPage-")) {
|
} else if (exports.entryPage && exports.entryPage.startsWith("statusPage-")) {
|
||||||
response.redirect("/status/" + exports.entryPage.replace("statusPage-", ""));
|
response.redirect("/status/" + exports.entryPage.replace("statusPage-", ""));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
response.redirect("/dashboard");
|
response.redirect("/dashboard");
|
||||||
}
|
}
|
||||||
|
@ -228,12 +216,16 @@ try {
|
||||||
const apiRouter = require("./routers/api-router");
|
const apiRouter = require("./routers/api-router");
|
||||||
app.use(apiRouter);
|
app.use(apiRouter);
|
||||||
|
|
||||||
|
// Status Page Router
|
||||||
|
const statusPageRouter = require("./routers/status-page-router");
|
||||||
|
app.use(statusPageRouter);
|
||||||
|
|
||||||
// Universal Route Handler, must be at the end of all express routes.
|
// Universal Route Handler, must be at the end of all express routes.
|
||||||
app.get("*", async (_request, response) => {
|
app.get("*", async (_request, response) => {
|
||||||
if (_request.originalUrl.startsWith("/upload/")) {
|
if (_request.originalUrl.startsWith("/upload/")) {
|
||||||
response.status(404).send("File not found.");
|
response.status(404).send("File not found.");
|
||||||
} else {
|
} else {
|
||||||
response.send(indexHTML);
|
response.send(server.indexHTML);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,12 @@ class UptimeKumaServer {
|
||||||
httpServer = undefined;
|
httpServer = undefined;
|
||||||
io = undefined;
|
io = undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache Index HTML
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
indexHTML = "";
|
||||||
|
|
||||||
static getInstance(args) {
|
static getInstance(args) {
|
||||||
if (UptimeKumaServer.instance == null) {
|
if (UptimeKumaServer.instance == null) {
|
||||||
UptimeKumaServer.instance = new UptimeKumaServer(args);
|
UptimeKumaServer.instance = new UptimeKumaServer(args);
|
||||||
|
@ -55,6 +61,16 @@ class UptimeKumaServer {
|
||||||
this.httpServer = http.createServer(this.app);
|
this.httpServer = http.createServer(this.app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.indexHTML = fs.readFileSync("./dist/index.html").toString();
|
||||||
|
} catch (e) {
|
||||||
|
// "dist/index.html" is not necessary for development
|
||||||
|
if (process.env.NODE_ENV !== "development") {
|
||||||
|
log.error("server", "Error: Cannot find 'dist/index.html', did you install correctly?");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.io = new Server(this.httpServer);
|
this.io = new Server(this.httpServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@
|
||||||
<h1 class="mb-4 title-flex">
|
<h1 class="mb-4 title-flex">
|
||||||
<!-- Logo -->
|
<!-- Logo -->
|
||||||
<span class="logo-wrapper" @click="showImageCropUploadMethod">
|
<span class="logo-wrapper" @click="showImageCropUploadMethod">
|
||||||
<img :src="logoURL" alt class="logo me-2" :class="logoClass" @load="statusPageLogoLoaded" />
|
<img :src="logoURL" alt class="logo me-2" :class="logoClass" />
|
||||||
<font-awesome-icon v-if="enableEditMode" class="icon-upload" icon="upload" />
|
<font-awesome-icon v-if="enableEditMode" class="icon-upload" icon="upload" />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
@ -687,11 +687,6 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
statusPageLogoLoaded(eventPayload) {
|
|
||||||
// Remark: may not work in dev, due to CORS
|
|
||||||
favicon.image(eventPayload.target);
|
|
||||||
},
|
|
||||||
|
|
||||||
createIncident() {
|
createIncident() {
|
||||||
this.enableEditIncidentMode = true;
|
this.enableEditIncidentMode = true;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue