mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
feat: add SEO support and favicon handling for Status Page
This commit is contained in:
@@ -87,6 +87,97 @@ export default class StatusPageAPI extends BaseAPI<
|
||||
public constructor() {
|
||||
super(StatusPage, StatusPageService);
|
||||
|
||||
|
||||
// get title, description of the page. This is used for SEO.
|
||||
this.router.get(
|
||||
`${new this.entityType().getCrudApiPath()?.toString()}/:statusPageId`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
const statusPageId: ObjectID = new ObjectID(
|
||||
req.params["statusPageId"] as string,
|
||||
);
|
||||
|
||||
const statusPage: StatusPage | null =
|
||||
await StatusPageService.findOneBy({
|
||||
query: {
|
||||
_id: statusPageId,
|
||||
},
|
||||
select: {
|
||||
pageTitle: true,
|
||||
pageDescription: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!statusPage) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new NotFoundException("Status Page not found"),
|
||||
);
|
||||
}
|
||||
|
||||
return Response.sendJsonObjectResponse(req, res, {
|
||||
title: statusPage.pageTitle,
|
||||
description: statusPage.pageDescription,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// favicon api.
|
||||
this.router.get(
|
||||
`${new this.entityType().getCrudApiPath()?.toString()}/favicon/:statusPageId`,
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
const statusPageId: ObjectID = new ObjectID(
|
||||
req.params["statusPageId"] as string,
|
||||
);
|
||||
|
||||
const statusPage: StatusPage | null =
|
||||
await StatusPageService.findOneBy({
|
||||
query: {
|
||||
_id: statusPageId,
|
||||
},
|
||||
select: {
|
||||
faviconFile: {
|
||||
file: true,
|
||||
_id: true,
|
||||
type: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!statusPage) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new NotFoundException("Status Page not found"),
|
||||
);
|
||||
}
|
||||
|
||||
if(!statusPage.faviconFile) {
|
||||
// return default favicon.
|
||||
return Response.sendFileByPath(
|
||||
req,
|
||||
res,
|
||||
`/usr/src/Common/UI/Images/favicon/status-green.png`,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return Response.sendFileResponse(
|
||||
req,
|
||||
res,
|
||||
statusPage.faviconFile!,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// confirm subscription api
|
||||
this.router.get(
|
||||
`${new this.entityType()
|
||||
|
||||
@@ -142,6 +142,10 @@ export interface InitFuctionOptions {
|
||||
port?: Port | undefined;
|
||||
isFrontendApp?: boolean;
|
||||
statusOptions: StatusAPIOptions;
|
||||
getVariablesToRenderIndexPage?: (
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
) => Promise<JSONObject>;
|
||||
}
|
||||
|
||||
type InitFunction = (
|
||||
@@ -200,9 +204,30 @@ const init: InitFunction = async (
|
||||
},
|
||||
);
|
||||
|
||||
app.get("/*", (_req: ExpressRequest, res: ExpressResponse) => {
|
||||
app.get("/*", async (_req: ExpressRequest, res: ExpressResponse) => {
|
||||
|
||||
|
||||
let variables: JSONObject = {};
|
||||
|
||||
if(data.getVariablesToRenderIndexPage) {
|
||||
try {
|
||||
const variablesToRenderIndexPage: JSONObject =
|
||||
await data.getVariablesToRenderIndexPage(
|
||||
_req,
|
||||
res,
|
||||
);
|
||||
variables = {
|
||||
...variables,
|
||||
...variablesToRenderIndexPage,
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
return res.render("/usr/src/app/views/index.ejs", {
|
||||
enableGoogleTagManager: IsBillingEnabled || false,
|
||||
...variables,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
BIN
Common/UI/Images/favicon/status-green.png
Normal file
BIN
Common/UI/Images/favicon/status-green.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
@@ -19,6 +19,13 @@ const init: PromiseVoidFunction = async (): Promise<void> => {
|
||||
liveCheck: async () => {},
|
||||
readyCheck: async () => {},
|
||||
},
|
||||
getVariablesToRenderIndexPage: async (_req, _res) => {
|
||||
return {
|
||||
title: "Status Page",
|
||||
description: "Status Page",
|
||||
faviconUrl: "/favicon.ico",
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// add default routes
|
||||
|
||||
@@ -20,13 +20,11 @@ import JSONWebTokenData from "Common/Types/JsonWebTokenData";
|
||||
import Link from "Common/Types/Link";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
import ErrorMessage from "Common/UI/Components/ErrorMessage/ErrorMessage";
|
||||
import { ImageFunctions } from "Common/UI/Components/Image/Image";
|
||||
import PageLoader from "Common/UI/Components/Loader/PageLoader";
|
||||
import MasterPage from "Common/UI/Components/MasterPage/MasterPage";
|
||||
import JSONWebToken from "Common/UI/Utils/JsonWebToken";
|
||||
import LocalStorage from "Common/UI/Utils/LocalStorage";
|
||||
import Navigation from "Common/UI/Utils/Navigation";
|
||||
import File from "Common/Models/DatabaseModels/File";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
ReactElement,
|
||||
@@ -181,15 +179,6 @@ const DashboardMasterPage: FunctionComponent<ComponentProps> = (
|
||||
|
||||
setStatusPage(statusPage);
|
||||
|
||||
// setfavicon.
|
||||
const favIcon: File | undefined = statusPage.faviconFile;
|
||||
if (favIcon && favIcon.file) {
|
||||
const link: any = document.createElement("link");
|
||||
link.rel = "icon";
|
||||
(document as any).getElementsByTagName("head")[0].appendChild(link);
|
||||
link.href = ImageFunctions.getImageURL(favIcon);
|
||||
}
|
||||
|
||||
// setcss.
|
||||
const css: string | null = statusPage.customCSS || null;
|
||||
if (css) {
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<meta name="slack-app-id" content="ACVBMTPJQ">
|
||||
<meta name="description" content="OneUptime — the complete open-source observability platform.">
|
||||
<meta name="description" content="<%= typeof description !== 'undefined' ? description : 'Status Page shows real-time status of all of our services.' %>">
|
||||
<script src="/status-page/env.js"></script>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="icon" type="image/png" href="<%= typeof faviconUrl !== 'undefined' ? faviconUrl : '/status-page/assets/images/favicon.png' %>">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
* {
|
||||
@@ -47,7 +48,9 @@
|
||||
}
|
||||
</style>
|
||||
<script src="/status-page/assets/js/tailwind-3.4.5.js"></script>
|
||||
<title>Status Page</title>
|
||||
<title><%= typeof title !== 'undefined' ? title : 'Status Page' %></title>
|
||||
|
||||
|
||||
<% if(typeof enableGoogleTagManager !== 'undefined' ? enableGoogleTagManager : false){ %>
|
||||
<!-- Google Tag Manager -->
|
||||
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||
@@ -59,19 +62,6 @@
|
||||
<% } %>
|
||||
|
||||
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
</head>
|
||||
<body class="h-full bg-gray-50">
|
||||
<% if(typeof enableGoogleTagManager !== 'undefined' ? enableGoogleTagManager : false){ %>
|
||||
|
||||
Reference in New Issue
Block a user