Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ describe("ActivityLogItem", () => {
).toBeInTheDocument();
});

it("formats the run timestamp in the automation timezone", () => {
const run = createRun();
render(<ActivityLogItem run={run} timeZone="America/Los_Angeles" />);

expect(
screen.getByText(
(content) => content.includes("2:00 AM") && content.includes("PDT"),
),
).toBeInTheDocument();
});

it("renders as a link when conversation_id exists", () => {
const run = createRun({ conversation_id: "conv-abc123" });
render(<ActivityLogItem run={run} />);
Expand Down
49 changes: 35 additions & 14 deletions frontend/src/components/automations/detail/activity-log-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,36 @@ import { RunStatusBadge } from "./run-status-badge";

interface ActivityLogItemProps {
run: AutomationRun;
timeZone?: string;
}

function formatRunTimestamp(dateStr: string, locale: string): string {
const RUN_TIMESTAMP_OPTIONS: Intl.DateTimeFormatOptions = {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "2-digit",
};

function formatRunTimestamp(
dateStr: string,
locale: string,
timeZone?: string,
): string {
const date = new Date(dateStr);
return date.toLocaleDateString(locale, {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "2-digit",
});
const options: Intl.DateTimeFormatOptions = { ...RUN_TIMESTAMP_OPTIONS };

if (timeZone) {
options.timeZone = timeZone;
options.timeZoneName = "short";
}

try {
return date.toLocaleDateString(locale, options);
} catch {
return date.toLocaleDateString(locale, RUN_TIMESTAMP_OPTIONS);
}
}

function getConversationUrl(conversationId: string): string {
Expand All @@ -27,16 +45,19 @@ function getConversationUrl(conversationId: string): string {
return `https://${baseHost}/conversations/${conversationId}`;
}

export function ActivityLogItem({ run }: ActivityLogItemProps) {
export function ActivityLogItem({ run, timeZone }: ActivityLogItemProps) {
const { t, i18n } = useTranslation();
const hasConversation = !!run.conversation_id;
const runTimestamp = formatRunTimestamp(
run.started_at,
i18n.language,
timeZone,
);

const content = (
<>
<div className="flex items-center gap-3">
<span className="text-sm text-content">
{formatRunTimestamp(run.started_at, i18n.language)}
</span>
<span className="text-sm text-content">{runTimestamp}</span>
{!hasConversation && (
<span className="text-xs text-content-muted italic">
({t(I18nKey.AUTOMATIONS$DETAIL$NO_CONVERSATION)})
Expand All @@ -54,7 +75,7 @@ export function ActivityLogItem({ run }: ActivityLogItemProps) {
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-between px-5 py-3 transition-colors cursor-pointer hover:bg-surface-elevated focus:bg-surface-elevated focus:outline-none"
aria-label={`View conversation for run at ${formatRunTimestamp(run.started_at, i18n.language)}`}
aria-label={`View conversation for run at ${runTimestamp}`}
>
{content}
</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import { ActivityLogItem } from "./activity-log-item";

interface ActivityLogSectionProps {
automationId: string;
timeZone?: string;
}

const PAGE_SIZE = 20;

export function ActivityLogSection({ automationId }: ActivityLogSectionProps) {
export function ActivityLogSection({
automationId,
timeZone,
}: ActivityLogSectionProps) {
const { t } = useTranslation();
const [limit, setLimit] = useState(PAGE_SIZE);
const { data, isLoading } = useAutomationRuns(automationId, limit, 0);
Expand Down Expand Up @@ -56,7 +60,7 @@ export function ActivityLogSection({ automationId }: ActivityLogSectionProps) {
key={run.id}
className={index > 0 ? "border-t border-border" : ""}
>
<ActivityLogItem run={run} />
<ActivityLogItem run={run} timeZone={timeZone} />
</div>
))}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ export function ConfigurationSection({
}: ConfigurationSectionProps) {
const { t } = useTranslation();

const automationTimeZone = automation.trigger.timezone ?? automation.timezone;
let scheduleDisplay = automation.trigger.schedule ?? "";
if (automation.trigger.schedule_human) {
scheduleDisplay = automation.timezone
? `${automation.trigger.schedule_human} (${automation.timezone})`
scheduleDisplay = automationTimeZone
? `${automation.trigger.schedule_human} (${automationTimeZone})`
: automation.trigger.schedule_human;
}

Expand Down
7 changes: 6 additions & 1 deletion frontend/src/routes/automation-detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ export default function AutomationDetail() {
});
};

const automationTimeZone = automation.trigger.timezone ?? automation.timezone;

return (
<div className="flex flex-col gap-4">
<BackLink />
Expand All @@ -81,7 +83,10 @@ export default function AutomationDetail() {
createdAt={automation.created_at}
lastRunAt={automation.last_triggered_at}
/>
<ActivityLogSection automationId={automation.id} />
<ActivityLogSection
automationId={automation.id}
timeZone={automationTimeZone}
/>
<DeleteConfirmationModal
automationName={automation.name}
isOpen={showDeleteModal}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types/automation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface AutomationTrigger {
type: string;
schedule?: string;
schedule_human?: string;
timezone?: string;
}

export interface Automation {
Expand Down
Loading