mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-10-03 08:03:28 +00:00
Part of the domain-reorg adoption (build plan step C6): fork content,
upstream layout. git mv's all 80 pure-rename files from the move-map
(agent-scoped components/lib -> ui/src/features/{agents,automations,
reviews,settings}/...), including ported/ splitting into
features/agents/experiments/ (still-unintegrated desktop-host ports)
and features/agents/components/chat/ (CloudPromptBar, CodeBlock,
DiffView, Logo, Markdown, ReplyCard, ShellCommand, ToolExecution --
files actually wired into the live dashboard). Fork-diverged files
(PlanReview.tsx, WorkflowApprovalCard.tsx, AgentsSidebar.tsx,
SidebarFilterMenu.tsx, AgentGitPanel.tsx, AutomationEditor.tsx,
DiffView.tsx, CloudPromptBar.tsx) keep fork content -- verified via
diff that only import lines changed.
Rewrote @/components/agents and @/lib/agents imports across all 54
importer files plus the moved files' own internal imports (grep-driven,
85-entry alias map covering every old->new path pair). Two hazards
caught only by the build gate (not tsc, since both files sit under the
new experiments/** tsconfig exclude): ui/src/lib/notifications.ts had
a relative `./agents/types` import (no `@/` alias) that the grep missed;
and features/agents/experiments/index.ts's barrel re-export of the
messages module needed to switch from an `@/` alias to a relative
import (`../components/messages`) after landing inside the newly
tsconfig-excluded experiments/ directory -- vite-tsconfig-paths failed
to resolve it at build time even though tsc stayed silent.
AgentPromptBar.tsx (the 2-line CloudPromptBar re-export shim) moves to
features/agents/components/ with its export path retargeted at
CloudPromptBar's new chat/ location -- a D/A pair, not a content loss,
since the import-path edit drops it below git's rename-similarity
threshold. ported/index.ts is the same D/A story for the same reason.
Swapped the 8-file ported/ exclude lists in tsconfig.json and
eslint.config.js for the single `src/features/agents/experiments/**`
glob (upstream's simplification, no behavior change). Deleted
ui/pnpm-workspace.yaml (lockfile hygiene -- bun stays the toolchain).
Gates: bunx tsc --noEmit (clean), bun run build (clean after the two
notifications.ts / experiments-index.ts fixes above), bun run test
(33/33), and the full Playwright E2E suite against the real langgraph
dev server + built dashboard (9/9).
75 lines
1.8 KiB
TypeScript
75 lines
1.8 KiB
TypeScript
type MessageTimestampProps = {
|
|
timestamp: string;
|
|
startedAt?: string;
|
|
align?: "left" | "right";
|
|
className?: string;
|
|
};
|
|
|
|
const timeFormatter = new Intl.DateTimeFormat(undefined, {
|
|
hour: "numeric",
|
|
minute: "2-digit",
|
|
second: "2-digit",
|
|
});
|
|
|
|
const datedTimeFormatter = new Intl.DateTimeFormat(undefined, {
|
|
month: "short",
|
|
day: "numeric",
|
|
hour: "numeric",
|
|
minute: "2-digit",
|
|
second: "2-digit",
|
|
});
|
|
|
|
const fullFormatter = new Intl.DateTimeFormat(undefined, {
|
|
dateStyle: "medium",
|
|
timeStyle: "medium",
|
|
});
|
|
|
|
function parseTimestamp(value?: string | null): Date | null {
|
|
if (!value) return null;
|
|
const date = new Date(value);
|
|
return Number.isNaN(date.getTime()) ? null : date;
|
|
}
|
|
|
|
function isSameLocalDay(a: Date, b: Date): boolean {
|
|
return (
|
|
a.getFullYear() === b.getFullYear() &&
|
|
a.getMonth() === b.getMonth() &&
|
|
a.getDate() === b.getDate()
|
|
);
|
|
}
|
|
|
|
function shortTimestamp(date: Date): string {
|
|
return isSameLocalDay(date, new Date())
|
|
? timeFormatter.format(date)
|
|
: datedTimeFormatter.format(date);
|
|
}
|
|
|
|
export function MessageTimestamp({
|
|
timestamp,
|
|
startedAt,
|
|
align = "left",
|
|
className = "",
|
|
}: MessageTimestampProps) {
|
|
const date = parseTimestamp(timestamp);
|
|
if (!date) return null;
|
|
|
|
const startDate = parseTimestamp(startedAt);
|
|
const title =
|
|
startDate && Math.abs(date.getTime() - startDate.getTime()) >= 1000
|
|
? `Started ${fullFormatter.format(startDate)} · Last updated ${fullFormatter.format(date)}`
|
|
: fullFormatter.format(date);
|
|
|
|
return (
|
|
<div
|
|
className={`flex ${align === "right" ? "justify-end" : "justify-start"} ${className}`}
|
|
>
|
|
<time
|
|
dateTime={date.toISOString()}
|
|
title={title}
|
|
className="text-[11px] leading-4 text-[color:var(--ui-text-dim)] tabular-nums select-none"
|
|
>
|
|
{shortTimestamp(date)}
|
|
</time>
|
|
</div>
|
|
);
|
|
}
|