Polish issue monitor UI review nits

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-05-01 21:22:46 -05:00
1 parent 1ee6280877
commit ee4f397610
5 files changed
+47 -29

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 180 KiB

+1 -13
View File
@@ -1,20 +1,8 @@
import type { Issue } from "@paperclipai/shared";
import { Button } from "@/components/ui/button";
import { formatMonitorOffset } from "@/lib/issue-monitor";
import { formatDateTime } from "@/lib/utils";
function formatMonitorOffset(nextCheckAt: Date | string): string {
const deltaMs = new Date(nextCheckAt).getTime() - Date.now();
const absMinutes = Math.round(Math.abs(deltaMs) / 60_000);
if (absMinutes <= 0) return "now";
if (absMinutes < 60) return deltaMs >= 0 ? `in ${absMinutes}m` : `${absMinutes}m ago`;
const absHours = Math.round(absMinutes / 60);
if (absHours < 24) return deltaMs >= 0 ? `in ${absHours}h` : `${absHours}h ago`;
const absDays = Math.round(absHours / 24);
return deltaMs >= 0 ? `in ${absDays}d` : `${absDays}d ago`;
}
function resolveScheduledMonitor(issue: Issue) {
const nextCheckAt =
issue.monitorNextCheckAt?.toISOString() ??
+4 -16
View File
@@ -25,6 +25,7 @@ import { getRecentProjectIds, trackRecentProject } from "../lib/recent-projects"
import { orderItemsBySelectedAndRecent } from "../lib/recent-selections";
import { formatAssigneeUserLabel } from "../lib/assignees";
import { buildExecutionPolicy, stageParticipantValues } from "../lib/issue-execution-policy";
import { formatMonitorOffset } from "../lib/issue-monitor";
import { StatusIcon } from "./StatusIcon";
import { PriorityIcon } from "./PriorityIcon";
import { Identity } from "./Identity";
@@ -126,19 +127,6 @@ function toDateTimeLocalValue(value: string | null | undefined) {
return new Date(date.getTime() - offsetMs).toISOString().slice(0, 16);
}
function formatMonitorOffset(nextCheckAt: Date | string): string {
const deltaMs = new Date(nextCheckAt).getTime() - Date.now();
const absMinutes = Math.round(Math.abs(deltaMs) / 60_000);
if (absMinutes <= 0) return "now";
if (absMinutes < 60) return deltaMs >= 0 ? `in ${absMinutes}m` : `${absMinutes}m ago`;
const absHours = Math.round(absMinutes / 60);
if (absHours < 24) return deltaMs >= 0 ? `in ${absHours}h` : `${absHours}h ago`;
const absDays = Math.round(absHours / 24);
return deltaMs >= 0 ? `in ${absDays}d` : `${absDays}d ago`;
}
interface IssuePropertiesProps {
issue: Issue;
childIssues?: Issue[];
@@ -540,12 +528,12 @@ export function IssueProperties({
if (issue.executionPolicy?.monitor?.nextCheckAt) {
return `Next check ${formatDate(new Date(issue.executionPolicy.monitor.nextCheckAt))}`;
}
if (issue.monitorLastTriggeredAt) {
return `Last triggered ${timeAgo(issue.monitorLastTriggeredAt)}`;
}
if (issue.executionState?.monitor?.status === "cleared") {
return "Cleared";
}
if (issue.monitorLastTriggeredAt) {
return `Last triggered ${timeAgo(issue.monitorLastTriggeredAt)}`;
}
return "Not scheduled";
})();
const monitorNextCheckAt = issue.executionPolicy?.monitor?.nextCheckAt ?? null;
+12
View File
@@ -0,0 +1,12 @@
export function formatMonitorOffset(nextCheckAt: Date | string): string {
const deltaMs = new Date(nextCheckAt).getTime() - Date.now();
const absMinutes = Math.round(Math.abs(deltaMs) / 60_000);
if (absMinutes <= 0) return "now";
if (absMinutes < 60) return deltaMs >= 0 ? `in ${absMinutes}m` : `${absMinutes}m ago`;
const absHours = Math.round(absMinutes / 60);
if (absHours < 24) return deltaMs >= 0 ? `in ${absHours}h` : `${absHours}h ago`;
const absDays = Math.round(absHours / 24);
return deltaMs >= 0 ? `in ${absDays}d` : `${absDays}d ago`;
}
@@ -91,6 +91,36 @@ const clearedIssue: Issue = {
executionPolicy: {
...(baseIssue.executionPolicy ?? { mode: "normal", commentRequired: true, stages: [] }),
},
executionState: {
...(baseIssue.executionState ?? {
status: "pending",
currentStageId: null,
currentStageIndex: null,
currentStageType: null,
currentParticipant: null,
returnAssignee: null,
reviewRequest: null,
completedStageIds: [],
lastDecisionId: null,
lastDecisionOutcome: null,
}),
monitor: {
status: "cleared",
nextCheckAt: null,
lastTriggeredAt: null,
attemptCount: 0,
notes: null,
scheduledBy: "board",
kind: null,
serviceName: null,
externalRef: null,
timeoutAt: null,
maxAttempts: null,
recoveryPolicy: null,
clearedAt: new Date(Date.now() - 60_000).toISOString(),
clearReason: "manual",
},
},
};
function MonitorSurfaceStories() {