clay-server 2.27.1 → 2.28.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -114,82 +114,103 @@ export function setupCreateModal() {
114
114
  }
115
115
  });
116
116
 
117
- // Recurrence button -> toggle dropdown
118
- document.getElementById("sched-create-recurrence-btn").addEventListener("click", function (e) {
119
- e.stopPropagation();
120
- var dd = document.getElementById("sched-create-recurrence-dropdown");
121
- var btn = document.getElementById("sched-create-recurrence-btn");
122
- // Close interval dropdown if open
123
- document.getElementById("sched-create-interval-dropdown").classList.add("hidden");
124
- if (dd) {
125
- var wasHidden = dd.classList.contains("hidden");
126
- dd.classList.toggle("hidden");
127
- if (wasHidden && btn) {
128
- var bRect = btn.getBoundingClientRect();
129
- var ddW = 280;
130
- var ddLeft = bRect.left;
131
- if (ddLeft + ddW > window.innerWidth - 10) ddLeft = window.innerWidth - ddW - 10;
132
- if (ddLeft < 10) ddLeft = 10;
133
- dd.style.left = ddLeft + "px";
134
- dd.style.top = (bRect.bottom + 4) + "px";
117
+ // Review checkbox toggle
118
+ var reviewCheck = document.getElementById("sched-review-check");
119
+ if (reviewCheck) {
120
+ reviewCheck.addEventListener("change", function () {
121
+ var countEl = document.getElementById("sched-review-count");
122
+ if (countEl) countEl.classList.toggle("hidden", !this.checked);
123
+ if (!this.checked) {
124
+ var iterInput = document.getElementById("sched-create-iterations");
125
+ if (iterInput) iterInput.value = "1";
135
126
  }
136
- }
127
+ updateTaskSubtitle();
128
+ });
129
+ }
130
+
131
+ // Iterations input change updates subtitle
132
+ var iterInputForSub = document.getElementById("sched-create-iterations");
133
+ if (iterInputForSub) {
134
+ iterInputForSub.addEventListener("change", function () { updateTaskSubtitle(); });
135
+ }
136
+
137
+ // updateTaskSubtitle is defined at module level (below)
138
+
139
+ // --- Repeat accordion toggle ---
140
+ document.getElementById("sched-accordion-repeat-header").addEventListener("click", function (e) {
141
+ e.stopPropagation();
142
+ var acc = document.getElementById("sched-accordion-repeat");
143
+ var body = document.getElementById("sched-accordion-repeat-body");
144
+ var isOpen = acc.classList.contains("open");
145
+ // Close interval accordion
146
+ document.getElementById("sched-accordion-interval").classList.remove("open");
147
+ document.getElementById("sched-accordion-interval-body").classList.add("hidden");
148
+ acc.classList.toggle("open", !isOpen);
149
+ body.classList.toggle("hidden", isOpen);
150
+ try { lucide.createIcons({ node: acc }); } catch (ex) {}
137
151
  });
138
152
 
139
- // --- Interval button + dropdown ---
140
- var intervalSnapshot = null;
141
- document.getElementById("sched-create-interval-btn").addEventListener("click", function (e) {
153
+ // --- Interval accordion toggle ---
154
+ document.getElementById("sched-accordion-interval-header").addEventListener("click", function (e) {
142
155
  e.stopPropagation();
143
- var dd = document.getElementById("sched-create-interval-dropdown");
144
- var btn = document.getElementById("sched-create-interval-btn");
145
- // Close recurrence dropdown if open
146
- document.getElementById("sched-create-recurrence-dropdown").classList.add("hidden");
147
- if (dd) {
148
- var wasHidden = dd.classList.contains("hidden");
149
- dd.classList.toggle("hidden");
150
- if (wasHidden && btn) {
151
- // Save snapshot for cancel
152
- intervalSnapshot = {
153
- interval: createInterval,
154
- custom: createIntervalCustom ? { value: createIntervalCustom.value, unit: createIntervalCustom.unit } : null,
155
- end: createIntervalEnd,
156
- endAfter: createIntervalEndAfter,
157
- endTime: createIntervalEndTime
158
- };
159
- var bRect = btn.getBoundingClientRect();
160
- var ddW = 220;
161
- var ddLeft = bRect.left;
162
- if (ddLeft + ddW > window.innerWidth - 10) ddLeft = window.innerWidth - ddW - 10;
163
- if (ddLeft < 10) ddLeft = 10;
164
- dd.style.left = ddLeft + "px";
165
- dd.style.top = (bRect.bottom + 4) + "px";
166
- // Auto-apply custom interval when opening
167
- if (createInterval === "none") {
168
- applyInlineInterval();
169
- }
170
- }
171
- }
156
+ var acc = document.getElementById("sched-accordion-interval");
157
+ var body = document.getElementById("sched-accordion-interval-body");
158
+ var isOpen = acc.classList.contains("open");
159
+ // Close repeat accordion
160
+ document.getElementById("sched-accordion-repeat").classList.remove("open");
161
+ document.getElementById("sched-accordion-repeat-body").classList.add("hidden");
162
+ acc.classList.toggle("open", !isOpen);
163
+ body.classList.toggle("hidden", isOpen);
164
+ try { lucide.createIcons({ node: acc }); } catch (ex) {}
172
165
  });
173
166
 
174
- // Interval Cancel button - revert to snapshot
175
- document.getElementById("sched-interval-cancel").addEventListener("click", function (e) {
167
+ // --- Clear buttons ---
168
+ document.getElementById("sched-accordion-repeat-clear").addEventListener("click", function (e) {
176
169
  e.stopPropagation();
177
- if (intervalSnapshot) {
178
- createInterval = intervalSnapshot.interval;
179
- createIntervalCustom = intervalSnapshot.custom;
180
- createIntervalEnd = intervalSnapshot.end;
181
- createIntervalEndAfter = intervalSnapshot.endAfter;
182
- createIntervalEndTime = intervalSnapshot.endTime;
183
- updateIntervalBtn();
184
- }
185
- document.getElementById("sched-create-interval-dropdown").classList.add("hidden");
170
+ createRecurrence = "none";
171
+ createCustomConfirmed = false;
172
+ // Reset controls
173
+ document.getElementById("sched-custom-interval").value = "1";
174
+ document.getElementById("sched-custom-unit").value = "week";
175
+ var dowSection = document.getElementById("sched-custom-dow-section");
176
+ if (dowSection) dowSection.style.display = "";
177
+ var dowBtns = document.querySelectorAll("#sched-custom-dow-row .sched-dow-btn");
178
+ for (var d = 0; d < dowBtns.length; d++) dowBtns[d].classList.remove("active");
179
+ document.getElementById("sched-custom-end").value = "never";
180
+ document.getElementById("sched-custom-end-label").textContent = "Never";
181
+ var dateBtn3 = document.getElementById("sched-custom-end-date-btn");
182
+ if (dateBtn3) dateBtn3.classList.add("hidden");
183
+ var afterWrap3 = document.getElementById("sched-custom-end-after-wrap");
184
+ if (afterWrap3) afterWrap3.classList.add("hidden");
185
+ var calPanel3 = document.getElementById("sched-custom-end-calendar");
186
+ if (calPanel3) calPanel3.classList.add("hidden");
187
+ // Collapse and update
188
+ document.getElementById("sched-accordion-repeat").classList.remove("open");
189
+ document.getElementById("sched-accordion-repeat-body").classList.add("hidden");
190
+ updateRecurrenceBtn();
186
191
  });
187
192
 
188
- // Interval OK button - accept and close
189
- document.getElementById("sched-interval-ok").addEventListener("click", function (e) {
193
+ document.getElementById("sched-accordion-interval-clear").addEventListener("click", function (e) {
190
194
  e.stopPropagation();
191
- applyInlineInterval();
192
- document.getElementById("sched-create-interval-dropdown").classList.add("hidden");
195
+ createInterval = "none";
196
+ createIntervalCustom = null;
197
+ createIntervalEnd = "allday";
198
+ createIntervalEndAfter = 5;
199
+ createIntervalEndTime = "";
200
+ // Reset controls
201
+ document.getElementById("sched-interval-custom-value").value = "10";
202
+ var segs = document.querySelectorAll(".sched-interval-seg");
203
+ for (var s = 0; s < segs.length; s++) segs[s].classList.toggle("active", segs[s].dataset.unit === "minute");
204
+ var iendOpts2 = document.querySelectorAll(".sched-interval-end-opt");
205
+ for (var ie2 = 0; ie2 < iendOpts2.length; ie2++) iendOpts2[ie2].classList.toggle("active", iendOpts2[ie2].dataset.iend === "allday");
206
+ var iAfterRow = document.getElementById("sched-interval-end-after-row");
207
+ if (iAfterRow) iAfterRow.classList.add("hidden");
208
+ var iUntilRow = document.getElementById("sched-interval-end-until-row");
209
+ if (iUntilRow) iUntilRow.classList.add("hidden");
210
+ // Collapse and update
211
+ document.getElementById("sched-accordion-interval").classList.remove("open");
212
+ document.getElementById("sched-accordion-interval-body").classList.add("hidden");
213
+ updateIntervalBtn();
193
214
  });
194
215
 
195
216
  // Interval custom input
@@ -255,23 +276,33 @@ export function setupCreateModal() {
255
276
  });
256
277
  }
257
278
 
258
- // Custom repeat: cancel
259
- document.getElementById("sched-custom-cancel").addEventListener("click", function (e) {
260
- e.stopPropagation();
261
- document.getElementById("sched-create-recurrence-dropdown").classList.add("hidden");
262
- });
263
-
264
- // Custom repeat: unit change
279
+ // Custom repeat: unit change (applies immediately)
265
280
  document.getElementById("sched-custom-unit").addEventListener("change", function () {
266
281
  var dowSection = document.getElementById("sched-custom-dow-section");
267
282
  if (dowSection) dowSection.style.display = this.value === "week" ? "" : "none";
283
+ createRecurrence = "custom";
284
+ createCustomConfirmed = true;
285
+ updateRecurrenceBtn();
286
+ });
287
+
288
+ // Custom repeat: interval input (applies immediately)
289
+ document.getElementById("sched-custom-interval").addEventListener("change", function () {
290
+ createRecurrence = "custom";
291
+ createCustomConfirmed = true;
292
+ updateRecurrenceBtn();
268
293
  });
269
294
 
270
295
  // Custom repeat: DOW toggle
271
296
  var customDowBtns = document.querySelectorAll("#sched-custom-dow-row .sched-dow-btn");
272
297
  for (var i = 0; i < customDowBtns.length; i++) {
273
298
  (function (btn) {
274
- btn.addEventListener("click", function (e) { e.stopPropagation(); btn.classList.toggle("active"); });
299
+ btn.addEventListener("click", function (e) {
300
+ e.stopPropagation();
301
+ btn.classList.toggle("active");
302
+ createRecurrence = "custom";
303
+ createCustomConfirmed = true;
304
+ updateRecurrenceBtn();
305
+ });
275
306
  })(customDowBtns[i]);
276
307
  }
277
308
 
@@ -377,29 +408,6 @@ export function setupCreateModal() {
377
408
  if (createEndAfter < 1) { createEndAfter = 1; this.value = 1; }
378
409
  });
379
410
 
380
- // Custom repeat: OK
381
- document.getElementById("sched-custom-ok").addEventListener("click", function (e) {
382
- e.stopPropagation();
383
- createRecurrence = "custom";
384
- createCustomConfirmed = true;
385
- document.getElementById("sched-create-recurrence-dropdown").classList.add("hidden");
386
- updateRecurrenceBtn();
387
- });
388
-
389
- // Run mode toggle (single vs multi-round)
390
- var runModeContainer = createPopover.querySelector(".sched-create-run-mode");
391
- if (runModeContainer) {
392
- runModeContainer.addEventListener("click", function (e) {
393
- var btn = e.target.closest(".sched-run-mode-btn");
394
- if (!btn) return;
395
- var mode = btn.dataset.mode;
396
- var btns = runModeContainer.querySelectorAll(".sched-run-mode-btn");
397
- for (var i = 0; i < btns.length; i++) btns[i].classList.toggle("active", btns[i] === btn);
398
- var iterGroup = document.getElementById("sched-create-iter-group");
399
- if (iterGroup) iterGroup.classList.toggle("hidden", mode !== "multi");
400
- });
401
- }
402
-
403
411
  // Submit
404
412
  document.getElementById("sched-create-submit").addEventListener("click", function () { submitCreateSchedule(); });
405
413
 
@@ -492,10 +500,12 @@ export function setupCreateModal() {
492
500
  document.addEventListener("keydown", function (e) {
493
501
  var cp = configCtx.getCreatePopover();
494
502
  if (e.key === "Escape" && cp && !cp.classList.contains("hidden")) {
495
- // Close recurrence dropdown first if open
496
- var dd = document.getElementById("sched-create-recurrence-dropdown");
497
- if (dd && !dd.classList.contains("hidden")) {
498
- dd.classList.add("hidden");
503
+ // Close open accordions first
504
+ var openAcc = cp.querySelector(".sched-accordion.open");
505
+ if (openAcc) {
506
+ openAcc.classList.remove("open");
507
+ var openBody = openAcc.querySelector(".sched-accordion-body");
508
+ if (openBody) openBody.classList.add("hidden");
499
509
  return;
500
510
  }
501
511
  closeCreateModal();
@@ -503,11 +513,50 @@ export function setupCreateModal() {
503
513
  });
504
514
  }
505
515
 
516
+ function updateTaskSubtitle() {
517
+ var sub = document.getElementById("sched-accordion-task-subtitle");
518
+ if (!sub) return;
519
+ var taskLabel = document.getElementById("sched-create-task-label");
520
+ var taskName = (taskLabel && taskLabel.textContent !== "Select a task") ? taskLabel.textContent : null;
521
+ var check = document.getElementById("sched-review-check");
522
+ var iterInput = document.getElementById("sched-create-iterations");
523
+ var iters = iterInput ? (parseInt(iterInput.value, 10) || 1) : 1;
524
+ if (!taskName) {
525
+ sub.textContent = "What to run";
526
+ } else if (check && check.checked && iters > 1) {
527
+ sub.textContent = taskName + " - review " + iters + "x";
528
+ } else {
529
+ sub.textContent = taskName + " - run once";
530
+ }
531
+ }
532
+
506
533
  function updateRecurrenceBtn() {
507
- var btn = document.getElementById("sched-create-recurrence-btn");
508
- if (btn) {
509
- btn.classList.toggle("has-recurrence", createRecurrence !== "none");
534
+ var acc = document.getElementById("sched-accordion-repeat");
535
+ var hasVal = createRecurrence !== "none";
536
+ if (acc) {
537
+ acc.classList.toggle("has-value", hasVal);
538
+ }
539
+ var clearBtn = document.getElementById("sched-accordion-repeat-clear");
540
+ if (clearBtn) clearBtn.classList.toggle("hidden", !hasVal);
541
+ // Update subtitle with summary or default description
542
+ var sub = document.getElementById("sched-accordion-repeat-subtitle");
543
+ if (!sub) return;
544
+ if (createRecurrence === "none" || !createCustomConfirmed) {
545
+ sub.textContent = "Which days to run";
546
+ return;
547
+ }
548
+ var interval = document.getElementById("sched-custom-interval").value || "1";
549
+ var unit = document.getElementById("sched-custom-unit").value || "week";
550
+ var summary = "Every " + interval + " " + unit;
551
+ if (unit === "week") {
552
+ var activeDow = document.querySelectorAll("#sched-custom-dow-row .sched-dow-btn.active");
553
+ if (activeDow.length > 0) {
554
+ var days = [];
555
+ for (var di = 0; di < activeDow.length; di++) days.push(activeDow[di].textContent);
556
+ summary += " on " + days.join(", ");
557
+ }
510
558
  }
559
+ sub.textContent = summary;
511
560
  }
512
561
 
513
562
  /**
@@ -542,17 +591,29 @@ function enforceMinTime() {
542
591
  }
543
592
 
544
593
  function updateIntervalBtn() {
545
- var btn = document.getElementById("sched-create-interval-btn");
546
- if (btn) {
547
- btn.classList.toggle("has-recurrence", createInterval !== "none");
594
+ var acc = document.getElementById("sched-accordion-interval");
595
+ var hasVal = createInterval !== "none";
596
+ if (acc) {
597
+ acc.classList.toggle("has-value", hasVal);
548
598
  }
599
+ var clearBtn = document.getElementById("sched-accordion-interval-clear");
600
+ if (clearBtn) clearBtn.classList.toggle("hidden", !hasVal);
549
601
  // Show/hide interval end conditions section
550
602
  var endSection = document.getElementById("sched-interval-end-section");
551
603
  if (endSection) {
552
604
  endSection.classList.toggle("hidden", createInterval === "none");
553
605
  }
554
- // Always show time picker (start time is needed even with interval)
555
- // Update skip-if-running visibility
606
+ // Update subtitle
607
+ var sub = document.getElementById("sched-accordion-interval-subtitle");
608
+ if (sub) {
609
+ if (createInterval === "none" || !createIntervalCustom) {
610
+ sub.textContent = "How often within each day";
611
+ } else {
612
+ var v = createIntervalCustom.value || 10;
613
+ var u = createIntervalCustom.unit === "hour" ? "hrs" : "min";
614
+ sub.textContent = "Every " + v + " " + u;
615
+ }
616
+ }
556
617
  updateRecurrenceBtn();
557
618
  }
558
619
 
@@ -633,6 +694,7 @@ export function applyDraggedTask() {
633
694
  if (taskHidden) taskHidden.value = dragState.draggedTaskId;
634
695
  if (taskLabel) taskLabel.textContent = dragState.draggedTaskName || dragState.draggedTaskId;
635
696
  if (taskBtn) { taskBtn.classList.add("has-value"); taskBtn.classList.remove("invalid"); }
697
+ updateTaskSubtitle();
636
698
  // Mark the matching item as selected in the dropdown list
637
699
  var taskListEl = document.getElementById("sched-create-task-list");
638
700
  if (taskListEl) {
@@ -689,8 +751,16 @@ export function openCreateModalWithRecord(rec, anchorEl) {
689
751
  var titleInput = document.getElementById("sched-create-title");
690
752
  if (titleInput) titleInput.value = rec.name || "";
691
753
 
754
+ // Show description row only if the record already has one
755
+ var descRow = document.getElementById("sched-create-desc-row");
692
756
  var descInput = document.getElementById("sched-create-desc");
693
- if (descInput) descInput.value = rec.description || "";
757
+ if (rec.description) {
758
+ if (descInput) descInput.value = rec.description;
759
+ if (descRow) descRow.classList.remove("hidden");
760
+ } else {
761
+ if (descInput) descInput.value = "";
762
+ if (descRow) descRow.classList.add("hidden");
763
+ }
694
764
 
695
765
  // Set color
696
766
  if (rec.color) {
@@ -707,18 +777,14 @@ export function openCreateModalWithRecord(rec, anchorEl) {
707
777
  var skipRunningEl = document.getElementById("sched-skip-running");
708
778
  if (skipRunningEl) skipRunningEl.checked = rec.skipIfRunning !== false;
709
779
 
710
- // Set run mode and iterations
711
- var editRunMode = (rec.maxIterations && rec.maxIterations > 1) ? "multi" : "single";
712
- var editRunBtns = createPopover.querySelectorAll(".sched-run-mode-btn");
713
- for (var rb = 0; rb < editRunBtns.length; rb++) {
714
- editRunBtns[rb].classList.toggle("active", editRunBtns[rb].dataset.mode === editRunMode);
715
- }
716
- var editIterGroup = document.getElementById("sched-create-iter-group");
717
- if (editIterGroup) editIterGroup.classList.toggle("hidden", editRunMode !== "multi");
718
- if (rec.maxIterations && rec.maxIterations > 1) {
719
- var iterInput = document.getElementById("sched-create-iterations");
720
- if (iterInput) iterInput.value = rec.maxIterations;
721
- }
780
+ // Set iterations + review checkbox
781
+ var hasReview = rec.maxIterations && rec.maxIterations > 1;
782
+ var iterInput = document.getElementById("sched-create-iterations");
783
+ if (iterInput) iterInput.value = hasReview ? rec.maxIterations : 3;
784
+ var reviewCheckEdit = document.getElementById("sched-review-check");
785
+ if (reviewCheckEdit) reviewCheckEdit.checked = hasReview;
786
+ var reviewCountEdit = document.getElementById("sched-review-count");
787
+ if (reviewCountEdit) reviewCountEdit.classList.toggle("hidden", !hasReview);
722
788
 
723
789
  // Set linked task
724
790
  if (rec.linkedTaskId) {
@@ -735,12 +801,14 @@ export function openCreateModalWithRecord(rec, anchorEl) {
735
801
  }
736
802
  if (taskLabel2) taskLabel2.textContent = taskName;
737
803
  if (taskBtn) { taskBtn.classList.add("has-value"); taskBtn.classList.remove("invalid"); }
804
+ // (no accordion to update)
738
805
  if (taskListEl) {
739
806
  var items = taskListEl.querySelectorAll(".sched-create-task-item");
740
807
  for (var k = 0; k < items.length; k++) {
741
808
  items[k].classList.toggle("selected", items[k].dataset.taskId === rec.linkedTaskId);
742
809
  }
743
810
  }
811
+ updateTaskSubtitle();
744
812
  }
745
813
 
746
814
  // Restore interval from cron
@@ -872,15 +940,15 @@ export function openCreateModal(date, hour, anchorEl) {
872
940
  // Reset form
873
941
  document.getElementById("sched-create-title").value = "";
874
942
  document.getElementById("sched-create-desc").value = "";
943
+ var descRowReset = document.getElementById("sched-create-desc-row");
944
+ if (descRowReset) descRowReset.classList.add("hidden");
875
945
  var iterReset = document.getElementById("sched-create-iterations");
876
946
  if (iterReset) iterReset.value = "3";
877
- // Reset run mode to single
878
- var runModeBtns = createPopover.querySelectorAll(".sched-run-mode-btn");
879
- for (var rm = 0; rm < runModeBtns.length; rm++) {
880
- runModeBtns[rm].classList.toggle("active", runModeBtns[rm].dataset.mode === "single");
881
- }
882
- var iterGroup = document.getElementById("sched-create-iter-group");
883
- if (iterGroup) iterGroup.classList.add("hidden");
947
+ var reviewCheck = document.getElementById("sched-review-check");
948
+ if (reviewCheck) reviewCheck.checked = false;
949
+ var reviewCount = document.getElementById("sched-review-count");
950
+ if (reviewCount) reviewCount.classList.add("hidden");
951
+ // (task is always visible, no accordion reset needed)
884
952
 
885
953
  // Reset color
886
954
  var colorDot = document.getElementById("sched-create-color-dot");
@@ -904,34 +972,36 @@ export function openCreateModal(date, hour, anchorEl) {
904
972
  if (taskListEl) {
905
973
  taskListEl.classList.add("hidden");
906
974
  var tasks = records.filter(function (r) { return r.source !== "ralph" && r.source !== "schedule"; });
975
+ var html = "";
907
976
  if (tasks.length === 0) {
908
- taskListEl.innerHTML = '<div class="sched-create-task-empty">No tasks available</div>';
977
+ html = '<div class="sched-create-task-empty">No tasks available</div>';
909
978
  } else {
910
- var html = "";
911
979
  for (var i = 0; i < tasks.length; i++) {
912
980
  html += '<div class="sched-create-task-item" data-task-id="' + configCtx.esc(tasks[i].id) + '">' + configCtx.esc(tasks[i].name || tasks[i].id) + '</div>';
913
981
  }
914
- taskListEl.innerHTML = html;
915
- // Bind click handlers
916
- var items = taskListEl.querySelectorAll(".sched-create-task-item");
917
- for (var j = 0; j < items.length; j++) {
918
- (function (item) {
919
- item.addEventListener("click", function (e) {
920
- e.stopPropagation();
921
- var id = item.dataset.taskId;
922
- var name = item.textContent;
923
- if (taskHidden) taskHidden.value = id;
924
- if (taskLabel) taskLabel.textContent = name;
925
- if (taskBtn) { taskBtn.classList.add("has-value"); taskBtn.classList.remove("invalid"); }
926
- // Update selected state
927
- var all = taskListEl.querySelectorAll(".sched-create-task-item");
928
- for (var k = 0; k < all.length; k++) {
929
- all[k].classList.toggle("selected", all[k] === item);
930
- }
931
- taskListEl.classList.add("hidden");
932
- });
933
- })(items[j]);
934
- }
982
+ }
983
+ taskListEl.innerHTML = html;
984
+ // Bind click handlers
985
+ var items = taskListEl.querySelectorAll(".sched-create-task-item");
986
+ for (var j = 0; j < items.length; j++) {
987
+ (function (item) {
988
+ item.addEventListener("click", function (e) {
989
+ e.stopPropagation();
990
+ var id = item.dataset.taskId;
991
+ var name = item.textContent;
992
+ if (taskHidden) taskHidden.value = id;
993
+ if (taskLabel) taskLabel.textContent = name;
994
+ if (taskBtn) { taskBtn.classList.add("has-value"); taskBtn.classList.remove("invalid"); }
995
+ // (no accordion to update)
996
+ // Update selected state
997
+ var all = taskListEl.querySelectorAll(".sched-create-task-item");
998
+ for (var k = 0; k < all.length; k++) {
999
+ all[k].classList.toggle("selected", all[k] === item);
1000
+ }
1001
+ taskListEl.classList.add("hidden");
1002
+ updateTaskSubtitle();
1003
+ });
1004
+ })(items[j]);
935
1005
  }
936
1006
  }
937
1007
 
@@ -972,8 +1042,9 @@ export function openCreateModal(date, hour, anchorEl) {
972
1042
  createCustomConfirmed = false;
973
1043
  updateRecurrenceBtn();
974
1044
 
975
- // Reset interval
976
- document.getElementById("sched-create-interval-dropdown").classList.add("hidden");
1045
+ // Reset interval accordion
1046
+ document.getElementById("sched-accordion-interval").classList.remove("open");
1047
+ document.getElementById("sched-accordion-interval-body").classList.add("hidden");
977
1048
  var timeInput = document.getElementById("sched-create-time");
978
1049
  if (timeInput) timeInput.style.display = "";
979
1050
 
@@ -993,8 +1064,9 @@ export function openCreateModal(date, hour, anchorEl) {
993
1064
 
994
1065
  updateIntervalBtn();
995
1066
 
996
- // Reset custom panel
997
- document.getElementById("sched-create-recurrence-dropdown").classList.add("hidden");
1067
+ // Reset repeat accordion
1068
+ document.getElementById("sched-accordion-repeat").classList.remove("open");
1069
+ document.getElementById("sched-accordion-repeat-body").classList.add("hidden");
998
1070
  document.getElementById("sched-custom-interval").value = "1";
999
1071
  document.getElementById("sched-custom-unit").value = "week";
1000
1072
  document.getElementById("sched-custom-dow-section").style.display = "";
@@ -1105,8 +1177,15 @@ function updateRecurrenceLabels(date) {
1105
1177
  export function closeCreateModal() {
1106
1178
  var createPopover = configCtx.getCreatePopover();
1107
1179
  if (createPopover) createPopover.classList.add("hidden");
1108
- var dd = document.getElementById("sched-create-recurrence-dropdown");
1109
- if (dd) dd.classList.add("hidden");
1180
+ // Collapse accordions
1181
+ var accRepeat = document.getElementById("sched-accordion-repeat");
1182
+ if (accRepeat) { accRepeat.classList.remove("open"); }
1183
+ var accRepeatBody = document.getElementById("sched-accordion-repeat-body");
1184
+ if (accRepeatBody) accRepeatBody.classList.add("hidden");
1185
+ var accInterval = document.getElementById("sched-accordion-interval");
1186
+ if (accInterval) { accInterval.classList.remove("open"); }
1187
+ var accIntervalBody = document.getElementById("sched-accordion-interval-body");
1188
+ if (accIntervalBody) accIntervalBody.classList.add("hidden");
1110
1189
  var pal = document.getElementById("sched-create-color-palette");
1111
1190
  if (pal) pal.classList.add("hidden");
1112
1191
  var tl = document.getElementById("sched-create-task-list");
@@ -1385,7 +1464,8 @@ function submitCreateSchedule() {
1385
1464
  var ctx = configCtx.ctx;
1386
1465
  ctx.requireClayRalph(function () {
1387
1466
  var createPopover = configCtx.getCreatePopover();
1388
- var description = document.getElementById("sched-create-desc").value.trim();
1467
+ var descInput = document.getElementById("sched-create-desc");
1468
+ var description = descInput ? descInput.value.trim() : "";
1389
1469
  var datePicker = document.getElementById("sched-create-date-picker");
1390
1470
  var dateVal = datePicker ? datePicker.value : document.getElementById("sched-create-date").value;
1391
1471
  var timeVal = document.getElementById("sched-create-time").value || "09:00";
@@ -1439,10 +1519,9 @@ function submitCreateSchedule() {
1439
1519
  var skipRunningEl = document.getElementById("sched-skip-running");
1440
1520
  var skipIfRunning = skipRunningEl ? skipRunningEl.checked : true;
1441
1521
 
1442
- var activeRunMode = createPopover.querySelector(".sched-run-mode-btn.active");
1443
- var runMode = activeRunMode ? activeRunMode.dataset.mode : "single";
1522
+ var reviewCheckSubmit = document.getElementById("sched-review-check");
1444
1523
  var maxIterations = 1;
1445
- if (runMode === "multi") {
1524
+ if (reviewCheckSubmit && reviewCheckSubmit.checked) {
1446
1525
  var iterInput = document.getElementById("sched-create-iterations");
1447
1526
  maxIterations = iterInput ? (parseInt(iterInput.value, 10) || 3) : 3;
1448
1527
  if (maxIterations < 2) maxIterations = 2;
@@ -43,19 +43,21 @@ export function handleLoopRegistryUpdated(msg) {
43
43
  }
44
44
  }
45
45
 
46
+ // Cache last-received file content for edit mode
47
+ export var _lastFiles = { id: null, prompt: "", judge: "", settings: null };
48
+
46
49
  export function handleLoopRegistryFiles(msg) {
47
50
  if (!histCtx.isPanelOpen() || histCtx.getCurrentMode() !== "detail") return;
48
51
  if (msg.id !== histCtx.getSelectedTaskId()) return;
52
+ _lastFiles = { id: msg.id, prompt: msg.prompt || "", judge: msg.judge || "", settings: msg.settings || null };
49
53
  var bodyEl = document.getElementById("scheduler-detail-body");
50
54
  if (!bodyEl) return;
51
55
  var contentDetailEl = histCtx.getContentDetailEl();
52
56
  var activeTab = contentDetailEl ? contentDetailEl.querySelector(".scheduler-detail-tab.active") : null;
53
57
  var tab = activeTab ? activeTab.dataset.tab : "prompt";
54
- if (tab === "prompt") {
55
- bodyEl.innerHTML = msg.prompt ? '<div class="md-content">' + renderMarkdown(msg.prompt) + '</div>' : '<div class="scheduler-empty">No PROMPT.md found</div>';
56
- } else if (tab === "judge") {
57
- bodyEl.innerHTML = msg.judge ? '<div class="md-content">' + renderMarkdown(msg.judge) + '</div>' : '<div class="scheduler-empty">No JUDGE.md found</div>';
58
- }
58
+ var content = tab === "prompt" ? _lastFiles.prompt : _lastFiles.judge;
59
+ var fileLabel = tab === "prompt" ? "PROMPT.md" : "JUDGE.md";
60
+ renderFileView(bodyEl, tab, content, fileLabel, msg.id);
59
61
  // Disable "Run now" if PROMPT.md is missing
60
62
  var runBtn = contentDetailEl ? contentDetailEl.querySelector('[data-action="run"]') : null;
61
63
  if (runBtn) {
@@ -65,6 +67,56 @@ export function handleLoopRegistryFiles(msg) {
65
67
  }
66
68
  }
67
69
 
70
+ function renderFileView(bodyEl, tab, content, fileLabel, recId) {
71
+ if (content) {
72
+ bodyEl.innerHTML = '<div class="scheduler-file-toolbar"><button class="scheduler-file-edit-btn" title="Edit"><i data-lucide="pencil"></i> Edit</button></div>' +
73
+ '<div class="md-content">' + renderMarkdown(content) + '</div>';
74
+ } else {
75
+ bodyEl.innerHTML = '<div class="scheduler-file-toolbar"><button class="scheduler-file-edit-btn" title="Edit"><i data-lucide="pencil"></i> Edit</button></div>' +
76
+ '<div class="scheduler-empty">No ' + fileLabel + ' found</div>';
77
+ }
78
+ if (typeof lucide !== "undefined") lucide.createIcons({ attrs: { class: "lucide" } });
79
+ var editBtn = bodyEl.querySelector(".scheduler-file-edit-btn");
80
+ if (editBtn) {
81
+ editBtn.addEventListener("click", function () {
82
+ renderFileEdit(bodyEl, tab, content, recId);
83
+ });
84
+ }
85
+ }
86
+
87
+ function renderFileEdit(bodyEl, tab, content, recId) {
88
+ bodyEl.innerHTML = '<div class="scheduler-file-toolbar">' +
89
+ '<button class="scheduler-file-save-btn" title="Save"><i data-lucide="check"></i> Save</button>' +
90
+ '<button class="scheduler-file-cancel-btn" title="Cancel"><i data-lucide="x"></i> Cancel</button>' +
91
+ '</div>' +
92
+ '<textarea class="scheduler-file-editor">' + escapeHtml(content) + '</textarea>';
93
+ if (typeof lucide !== "undefined") lucide.createIcons({ attrs: { class: "lucide" } });
94
+ var ta = bodyEl.querySelector(".scheduler-file-editor");
95
+ if (ta) ta.focus();
96
+ var saveBtn = bodyEl.querySelector(".scheduler-file-save-btn");
97
+ if (saveBtn) {
98
+ saveBtn.addEventListener("click", function () {
99
+ var newContent = ta.value;
100
+ var data = { type: "loop_registry_save_files", id: recId };
101
+ if (tab === "prompt") data.prompt = newContent;
102
+ else data.judge = newContent;
103
+ histCtx.send(data);
104
+ });
105
+ }
106
+ var cancelBtn = bodyEl.querySelector(".scheduler-file-cancel-btn");
107
+ if (cancelBtn) {
108
+ cancelBtn.addEventListener("click", function () {
109
+ var fileLabel = tab === "prompt" ? "PROMPT.md" : "JUDGE.md";
110
+ renderFileView(bodyEl, tab, _lastFiles[tab], fileLabel, recId);
111
+ });
112
+ }
113
+ }
114
+
115
+ function escapeHtml(str) {
116
+ if (!str) return "";
117
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
118
+ }
119
+
68
120
  export function handleScheduleRunStarted(msg) {
69
121
  if (histCtx.isPanelOpen()) histCtx.render();
70
122
  }