${unsafeHTML(
ServiceRow.MD.render(this.service.description),
@@ -198,27 +260,13 @@ export class ServiceRow extends Component {
const now = new Date();
const bars = Array.from({ length: 90 }, (_, i) => {
const day = new Date(now.getTime() - (89 - i) * 86400000);
- if ((this.service.started?.getTime() ?? 0) > day.getTime()) {
- return html`
-
- `;
- }
- const notices = this.noticesForDay(day);
- if (notices.length === 0) {
- return html`
-
- `;
- }
- const worst = notices.reduce((w, n) => n.impact > w.impact ? n : w);
- return html`
-
- `;
+ day.setHours(0, 0, 0, 0);
+ return ServiceRow.bar(day, this.noticesForDay(day), this.service.started);
});
return html`
${bars}
diff --git a/src/components/pages/HomePage.ts b/src/components/pages/HomePage.ts
index b9aded2..7c4f4b7 100644
--- a/src/components/pages/HomePage.ts
+++ b/src/components/pages/HomePage.ts
@@ -68,7 +68,7 @@ export class HomePage extends Page {
for (const i of incidents) {
const incident = new Incident(
i.id,
- i.name.default,
+ typeof i.name === "string" ? i.name : i.name.default,
i.components,
i.updates.map((u) =>
new NoticeUpdate(
@@ -96,7 +96,7 @@ export class HomePage extends Page {
for (const m of maintenances) {
const maintenance = new Maintenance(
m.id,
- m.name.default,
+ typeof m.name === "string" ? m.name : m.name.default,
m.components,
m.updates.map((u) =>
new NoticeUpdate(
@@ -108,7 +108,11 @@ export class HomePage extends Page {
),
Maintenance.parseStatus(m.status),
new Date(m.start),
- new Date(m.resolved),
+ new Date(
+ m.resolved === null
+ ? new Date(m.start).getTime() + (m.duration * 60000)
+ : m.resolved,
+ ),
);
this.notices.push(maintenance);
diff --git a/src/models/Notice.ts b/src/models/Notice.ts
index 2ac6148..094889a 100644
--- a/src/models/Notice.ts
+++ b/src/models/Notice.ts
@@ -13,7 +13,7 @@ export abstract class Notice {
public readonly ended: Date | null;
public readonly impact: ServiceStatus;
- public constructor(
+ protected constructor(
id: string,
name: string,
components: BaseComponent[],
@@ -35,7 +35,20 @@ export abstract class Notice {
this.impact = impact;
}
- public get duration(): number {
- return (this.ended?.getTime() ?? Date.now()) - this.started.getTime();
+ public duration(day?: Date): number {
+ if (day === undefined) {
+ return (this.ended?.getTime() ?? Date.now()) - this.started.getTime();
+ }
+
+ const dayStart = new Date(day);
+ dayStart.setHours(0, 0, 0, 0);
+ const nextDayStart = new Date(dayStart);
+ nextDayStart.setDate(dayStart.getDate() + 1);
+
+ return Math.max(
+ 0,
+ Math.min(this.ended?.getTime() ?? Date.now(), nextDayStart.getTime()) -
+ Math.max(this.started.getTime(), dayStart.getTime()),
+ );
}
}
diff --git a/vercel.json b/vercel.json
index 2136ba2..837af16 100644
--- a/vercel.json
+++ b/vercel.json
@@ -11,7 +11,7 @@
"headers": [
{
"key": "Content-Security-Policy",
- "value": "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self' https://wsrv.nl; connect-src 'self' https://api.instatus.com;"
+ "value": "default-src 'none'; script-src 'self'; style-src 'self'; style-src-attr 'unsafe-inline'; img-src 'self' https://wsrv.nl; connect-src 'self' https://api.instatus.com;"
},
{
"key": "Cache-Control",