You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
2.6 KiB
TypeScript

import Caprover, { Application } from "../services/Caprover";
import Layout, { html } from "../ui/Layout";
const OLD_PERIOD_IN_DAYS = 60;
const ApplicationOverview = (application: Application) => {
const deployedAt = application.lastDeployedAt.toLocaleDateString("fr-FR");
return html`<tr>
<td>${application.name}</td>
<td>
<details>
<summary>
<code>${application.imageName}</code>
</summary>
<pre style="user-select: all;">${application.toString()}</pre>
</details>
</td>
<td>
${application.isOlderThan(OLD_PERIOD_IN_DAYS)
? `<mark>${deployedAt}</mark>`
: deployedAt}
</td>
<td>
${application.dockerImage
? `<a href="${application.dockerImage.hubUrl}/tags">
<img height="32" width="32" src="https://cdn.simpleicons.org/docker" alt="Docker hub"/>
</a>`
: ""}
</td>
</tr> `;
};
type Sort = { field: string; order: "asc" | "desc" };
const Page = (applications: Application[], currentSort: Sort) => {
const sortLink = (field: string, title: string) => {
let url = `?sort=${field}`;
let className = "";
if (currentSort.field === field) {
className = "current";
title += currentSort.order === "asc" ? " ▲" : " ▼";
url += `&order=${currentSort.order === "asc" ? "desc" : "asc"}`;
}
return `<a href="${url}" class="${className}">${title}</a>`;
};
return html`<div>
<h1>Applications</h1>
<a href="/applications/update" class="button">Update applications now!</a>
<table>
<thead>
<tr>
<th>${sortLink("name", "Name")}</th>
<th>Deployment</th>
<th>${sortLink("deployed", "Last deployed")}</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
${applications.map((app) => ApplicationOverview(app)).join("")}
</tbody>
</table>
</div>`;
};
export default async (req: Request, caprover: Caprover): Promise<Response> => {
const applications = await caprover.getApps();
const sort: Sort = {
field: new URL(req.url).searchParams.get("sort") ?? "name",
order:
new URL(req.url).searchParams.get("order") === "desc" ? "desc" : "asc",
};
if (sort.field === "name") {
applications.sort((a, b) => a.name.localeCompare(b.name));
} else if (sort.field === "deployed") {
applications.sort(
(a, b) => a.lastDeployedAt.getTime() - b.lastDeployedAt.getTime()
);
}
if (sort.order === "desc") {
applications.reverse();
}
return new Response(Layout(Page(applications, sort)), {
headers: { "Content-Type": "text/html" },
});
};