diff --git a/apps/status-page/src/app/(public)/client.tsx b/apps/status-page/src/app/(public)/client.tsx
index eb305fee7..c31d2d913 100644
--- a/apps/status-page/src/app/(public)/client.tsx
+++ b/apps/status-page/src/app/(public)/client.tsx
@@ -352,7 +352,10 @@ function ThemePlaygroundEvents({
))}
) : null}
-
+
diff --git a/apps/status-page/src/app/(status-page)/[domain]/(public)/events/(list)/page.tsx b/apps/status-page/src/app/(status-page)/[domain]/(public)/events/(list)/page.tsx
index 04a7fb97f..89900e219 100644
--- a/apps/status-page/src/app/(status-page)/[domain]/(public)/events/(list)/page.tsx
+++ b/apps/status-page/src/app/(status-page)/[domain]/(public)/events/(list)/page.tsx
@@ -88,6 +88,7 @@ export default function Page() {
) : null}
diff --git a/apps/status-page/src/app/(status-page)/[domain]/(public)/events/(view)/report/[id]/page.tsx b/apps/status-page/src/app/(status-page)/[domain]/(public)/events/(view)/report/[id]/page.tsx
index 8557d45cc..bdd8db626 100644
--- a/apps/status-page/src/app/(status-page)/[domain]/(public)/events/(view)/report/[id]/page.tsx
+++ b/apps/status-page/src/app/(status-page)/[domain]/(public)/events/(view)/report/[id]/page.tsx
@@ -68,7 +68,10 @@ export default function ReportPage() {
))}
) : null}
-
+
diff --git a/apps/status-page/src/app/(status-page)/[domain]/(public)/page.tsx b/apps/status-page/src/app/(status-page)/[domain]/(public)/page.tsx
index 601a52e1d..b617d2e88 100644
--- a/apps/status-page/src/app/(status-page)/[domain]/(public)/page.tsx
+++ b/apps/status-page/src/app/(status-page)/[domain]/(public)/page.tsx
@@ -144,8 +144,10 @@ export default function Page() {
diff --git a/apps/status-page/src/components/status-page/status-events.tsx b/apps/status-page/src/components/status-page/status-events.tsx
index cbc7a2163..03cd2f8a2 100644
--- a/apps/status-page/src/components/status-page/status-events.tsx
+++ b/apps/status-page/src/components/status-page/status-events.tsx
@@ -8,10 +8,12 @@ import {
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
+import { usePathnamePrefix } from "@/hooks/use-pathname-prefix";
import { formatDate, formatDateRange, formatDateTime } from "@/lib/formatter";
import { cn } from "@/lib/utils";
import { formatDistanceStrict } from "date-fns";
-import { Check } from "lucide-react";
+import { Check, ChevronRight } from "lucide-react";
+import Link from "next/link";
import { status } from "./messages";
export function StatusEventGroup({
@@ -171,52 +173,70 @@ export function StatusEventTimelineReport({
className,
updates,
withDot = true,
+ maxUpdates,
+ reportId,
...props
}: React.ComponentProps<"div"> & {
// TODO: remove unused props
+ reportId: number;
updates: {
date: Date;
message: string;
status: "investigating" | "identified" | "monitoring" | "resolved";
}[];
withDot?: boolean;
+ maxUpdates?: number;
}) {
+ const prefix = usePathnamePrefix();
+ const sortedUpdates = [...updates].sort(
+ (a, b) => b.date.getTime() - a.date.getTime(),
+ );
+ const hasMoreUpdates = maxUpdates && sortedUpdates.length > maxUpdates;
+ const displayedUpdates = maxUpdates
+ ? sortedUpdates.slice(0, maxUpdates)
+ : sortedUpdates;
+
return (
{/* NOTE: make sure they are sorted by date */}
- {updates
- .sort((a, b) => b.date.getTime() - a.date.getTime())
- .map((update, index) => {
- const updateDate = new Date(update.date);
- let durationText: string | undefined;
+ {displayedUpdates.map((update, index) => {
+ const updateDate = new Date(update.date);
+ let durationText: string | undefined;
- if (index === 0) {
- const startedAt = new Date(updates[updates.length - 1].date);
- const duration = formatDistanceStrict(startedAt, updateDate);
+ if (index === 0) {
+ const startedAt = new Date(
+ sortedUpdates[sortedUpdates.length - 1].date,
+ );
+ const duration = formatDistanceStrict(startedAt, updateDate);
- if (duration !== "0 seconds" && update.status === "resolved") {
- durationText = `(in ${duration})`;
- }
- } else {
- const lastUpdateDate = new Date(updates[index - 1].date);
- const timeFromLast = formatDistanceStrict(
- updateDate,
- lastUpdateDate,
- );
- durationText = `(${timeFromLast} earlier)`;
+ if (duration !== "0 seconds" && update.status === "resolved") {
+ durationText = `(in ${duration})`;
}
+ } else {
+ const lastUpdateDate = new Date(displayedUpdates[index - 1].date);
+ const timeFromLast = formatDistanceStrict(updateDate, lastUpdateDate);
+ durationText = `(${timeFromLast} earlier)`;
+ }
- return (
-
- );
- })}
+ return (
+
+ );
+ })}
+ {hasMoreUpdates && (
+
+ )}
);
}
@@ -278,6 +298,37 @@ function StatusEventTimelineReportUpdate({
);
}
+function StatusEventTimelineReadMore({
+ href,
+ withDot = true,
+}: {
+ href: string;
+ withDot?: boolean;
+}) {
+ return (
+
+
+
+ {withDot ? (
+
+ ) : null}
+
+ View full report
+
+
+
+
+
+ );
+}
+
export function StatusEventTimelineMaintenance({
maintenance,
withDot = true,
diff --git a/apps/status-page/src/components/status-page/status-feed.tsx b/apps/status-page/src/components/status-page/status-feed.tsx
index 0955b3b24..77058abf8 100644
--- a/apps/status-page/src/components/status-page/status-feed.tsx
+++ b/apps/status-page/src/components/status-page/status-feed.tsx
@@ -126,7 +126,10 @@ export function StatusFeed({
))}
)}
-
+
diff --git a/apps/workflows/src/incident/index.ts b/apps/workflows/src/incident/index.ts
index c31d6d378..251c21e95 100644
--- a/apps/workflows/src/incident/index.ts
+++ b/apps/workflows/src/incident/index.ts
@@ -1,5 +1,5 @@
import { schema } from "@openstatus/db";
-import { and, eq, inArray, isNotNull, isNull, ne } from "drizzle-orm";
+import { and, eq, inArray, isNull, ne } from "drizzle-orm";
import { Hono } from "hono";
import { env } from "../env";
import { db } from "../lib/db";
@@ -19,11 +19,7 @@ incidentRoute.get("/cleanup", async (c) => {
const unresolvedIncidentMonitorIds = db
.select({ monitorId: schema.incidentTable.monitorId })
.from(schema.incidentTable)
- .where(
- and(
- isNull(schema.incidentTable.resolvedAt),
- ),
- );
+ .where(and(isNull(schema.incidentTable.resolvedAt)));
const activeMonitorsWithUnresolvedIncidents = await db
.select({ id: schema.monitor.id })