From 8af38fb054fddca1c43807ba1f3d8c00ef4e797c Mon Sep 17 00:00:00 2001
From: Dotta <34892728+cryppadotta@users.noreply.github.com>
Date: Mon, 11 May 2026 13:24:48 -0500
Subject: [PATCH] Revert "fix(ui): prevent lossy cron rewrites + redesign
routine triggers tab" (#5725)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Thinking Path
> - Paperclip orchestrates AI agents through visible, governable task
and routine workflows.
> - Routines are the recurring-work surface where operators configure
schedules, runs, and activity.
> - PR #3569 moved routine operational tabs into the right-hand
properties panel while also redesigning the routine trigger editor.
> - The current product request is to remove that routine properties
right-tab change for now and come back to it later.
> - The cleanest way to do that is a direct revert of #3569 on top of
current `master`, which already includes the #5703 revert.
> - This pull request restores the pre-#3569 routine trigger/detail
behavior and removes the right-tab properties-panel routine layout.
> - The benefit is a simple, reviewable rollback with no schema or API
changes.
## What Changed
- Reverted #3569: `fix(ui): prevent lossy cron rewrites + redesign
routine triggers tab`.
- Restored the previous `RoutineDetail` inline tabs and trigger editing
flow.
- Restored the earlier `ScheduleEditor` implementation.
- Removed the UI components and tests introduced by #3569:
`ConfirmDialog`, `TriggerDialog`, `TriggerListCard`, and
`ScheduleEditor.test.ts`.
## Verification
- `git diff --check origin/master..HEAD`
- `pnpm vitest run ui/src/pages/Routines.test.tsx
ui/src/components/RoutineHistoryTab.test.tsx`
- `pnpm --filter @paperclipai/ui typecheck`
Notes:
- `pnpm install --frozen-lockfile` was run in the clean worktree before
verification. It completed with known workspace bin-link warnings for
`paperclip-plugin-dev-server` because the plugin SDK `dist/dev-cli.js`
has not been built in that fresh worktree.
- `Routines.test.tsx` emitted existing Radix dialog accessibility
warnings during the test run; the tests passed.
### Screenshots
This is a direct revert of #3569. The visual state after this PR
corresponds to the old screenshot from #3569, and the state being
removed corresponds to the new/right-panel screenshots from #3569.
| Before this revert | After this revert |
| --- | --- |
| | |
Right-hand properties panel state removed by this revert:
## Risks
- Low technical risk: this is a clean Git revert of a UI-only PR.
- Product risk: #3569 also fixed lossy cron editing and added broader
schedule presets, so this rollback intentionally removes those
improvements along with the right-tab routine layout.
- Follow-up risk: if we want only the schedule-editor fixes back later,
they should be reintroduced separately from the routine properties-panel
layout.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5 coding agent, tool-enabled with local shell and
GitHub CLI access. Context window size was not exposed in this session.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
Co-authored-by: Paperclip
---
ui/src/components/ConfirmDialog.tsx | 57 --
ui/src/components/ScheduleEditor.test.ts | 166 ---
ui/src/components/ScheduleEditor.tsx | 1194 +++++-----------------
ui/src/components/TriggerDialog.tsx | 268 -----
ui/src/components/TriggerListCard.tsx | 139 ---
ui/src/pages/RoutineDetail.tsx | 707 +++++++------
6 files changed, 630 insertions(+), 1901 deletions(-)
delete mode 100644 ui/src/components/ConfirmDialog.tsx
delete mode 100644 ui/src/components/ScheduleEditor.test.ts
delete mode 100644 ui/src/components/TriggerDialog.tsx
delete mode 100644 ui/src/components/TriggerListCard.tsx
diff --git a/ui/src/components/ConfirmDialog.tsx b/ui/src/components/ConfirmDialog.tsx
deleted file mode 100644
index 3a8ed9a5..00000000
--- a/ui/src/components/ConfirmDialog.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import { Button } from "@/components/ui/button";
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTitle,
-} from "@/components/ui/dialog";
-
-interface ConfirmDialogProps {
- open: boolean;
- onOpenChange: (open: boolean) => void;
- title: string;
- description?: string;
- confirmLabel?: string;
- cancelLabel?: string;
- destructive?: boolean;
- onConfirm: () => void;
- busy?: boolean;
-}
-
-export function ConfirmDialog({
- open,
- onOpenChange,
- title,
- description,
- confirmLabel = "Confirm",
- cancelLabel = "Cancel",
- destructive,
- onConfirm,
- busy,
-}: ConfirmDialogProps) {
- return (
-
- );
-}
diff --git a/ui/src/components/ScheduleEditor.test.ts b/ui/src/components/ScheduleEditor.test.ts
deleted file mode 100644
index e0f8853a..00000000
--- a/ui/src/components/ScheduleEditor.test.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-import { describe, expect, it } from "vitest";
-import {
- describeSchedule,
- getScheduleEditorPresetForTest,
- hasSingleMinuteAcrossTimesForTest,
- parseCronToPreset,
- roundTripCronForTest,
-} from "./ScheduleEditor";
-
-describe("parseCronToPreset", () => {
- describe("simple single-value crons map to presets", () => {
- it("maps `* * * * *` to every_minute", () => {
- expect(parseCronToPreset("* * * * *").preset).toBe("every_minute");
- });
-
- it("maps `0 * * * *` to every_hour", () => {
- const parsed = parseCronToPreset("0 * * * *");
- expect(parsed.preset).toBe("every_hour");
- expect(parsed.minute).toBe("0");
- });
-
- it("maps `0 9 * * *` to every_day at 09:00", () => {
- const parsed = parseCronToPreset("0 9 * * *");
- expect(parsed.preset).toBe("every_day");
- expect(parsed.hour).toBe("9");
- expect(parsed.minute).toBe("0");
- });
-
- it("maps `0 9 * * 1-5` to weekdays", () => {
- const parsed = parseCronToPreset("0 9 * * 1-5");
- expect(parsed.preset).toBe("weekdays");
- expect(parsed.hour).toBe("9");
- });
-
- it("maps `0 9 * * 1` to weekly on Monday", () => {
- const parsed = parseCronToPreset("0 9 * * 1");
- expect(parsed.preset).toBe("weekly");
- expect(parsed.dayOfWeek).toBe("1");
- expect(parsed.hour).toBe("9");
- });
-
- it("maps `0 9 1 * *` to monthly on the 1st", () => {
- const parsed = parseCronToPreset("0 9 1 * *");
- expect(parsed.preset).toBe("monthly");
- expect(parsed.dayOfMonth).toBe("1");
- expect(parsed.hour).toBe("9");
- });
- });
-
- describe("complex crons round-trip via custom preset (regression: comma lists were silently coerced into every_day)", () => {
- it("routes comma-separated hours to custom", () => {
- // Regression: `0 9,13,17 * * *` used to be parsed as `every_day` with
- // hour `"9,13,17"`, which the hour