@truefoundry/trueforge-ui 0.3.0-rc.1 → 0.3.0-rc.10

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.
Files changed (111) hide show
  1. package/CHANGELOG.md +143 -0
  2. package/README.md +23 -8
  3. package/dist/{AgentCodeSnippets-NZOFJE57.js → AgentCodeSnippets-RJBB4DDE.js} +38 -23
  4. package/dist/AgentCodeSnippets-RJBB4DDE.js.map +1 -0
  5. package/dist/AgentMetricChart-UPGSJ2WP.js +15 -0
  6. package/dist/{AgentOverview-EEBHJC32.js → AgentOverview-U5WIQXZN.js} +11 -9
  7. package/dist/AgentOverview-U5WIQXZN.js.map +1 -0
  8. package/dist/{AgentSessionEventTimeline-26Z6IB3B.js → AgentSessionEventTimeline-GRGIQTRE.js} +19 -10
  9. package/dist/AgentSessionEventTimeline-GRGIQTRE.js.map +1 -0
  10. package/dist/{AgentSessionEventTimelineChart-CGCU7WBK.js → AgentSessionEventTimelineChart-GNF4VOUT.js} +144 -57
  11. package/dist/AgentSessionEventTimelineChart-GNF4VOUT.js.map +1 -0
  12. package/dist/{AgentSessions-3MPDZASK.js → AgentSessions-5OTF2BUW.js} +72 -24
  13. package/dist/AgentSessions-5OTF2BUW.js.map +1 -0
  14. package/dist/{ConnectorSettings-MXFRWWR6.js → ConnectorSettings-HDKGLDCY.js} +162 -126
  15. package/dist/ConnectorSettings-HDKGLDCY.js.map +1 -0
  16. package/dist/{DockLayout-LM4AFMFY.js → DockLayout-D2FPQCAL.js} +10 -10
  17. package/dist/{DrawerLayout-JR3O6RRB.js → DrawerLayout-HUV7RAWL.js} +14 -12
  18. package/dist/DrawerLayout-HUV7RAWL.js.map +1 -0
  19. package/dist/{ModelSettings-G7IFNC2Y.js → ModelSettings-VNQ7HPKH.js} +22 -28
  20. package/dist/ModelSettings-VNQ7HPKH.js.map +1 -0
  21. package/dist/OpenUiFenceBlock-KPZFLUSC.js +9 -0
  22. package/dist/{SandboxSettings-NXAANMAX.js → SandboxSettings-ZLXGMFBF.js} +17 -21
  23. package/dist/SandboxSettings-ZLXGMFBF.js.map +1 -0
  24. package/dist/SchedulesPage-QKYI2Z3A.js +15 -0
  25. package/dist/{SettingsBuilder-L34IQ56S.js → SettingsBuilder-RVVYXOJW.js} +9 -9
  26. package/dist/{SettingsBuilder-L34IQ56S.js.map → SettingsBuilder-RVVYXOJW.js.map} +1 -1
  27. package/dist/{ShellRouteSync-CEBETGEJ.js → ShellRouteSync-SJXFKUAJ.js} +171 -26
  28. package/dist/ShellRouteSync-SJXFKUAJ.js.map +1 -0
  29. package/dist/{SidebarLayout-A2HJPPHS.js → SidebarLayout-KYA76FQ7.js} +80 -58
  30. package/dist/SidebarLayout-KYA76FQ7.js.map +1 -0
  31. package/dist/{SkillSettings-FGGMSUNO.js → SkillSettings-7OHT7FPI.js} +24 -22
  32. package/dist/SkillSettings-7OHT7FPI.js.map +1 -0
  33. package/dist/{TrueForgeUIWithRouter-MZVJWJMB.js → TrueForgeUIWithRouter-LKG4XLW6.js} +9 -9
  34. package/dist/{WidgetLayout-6QM45OQQ.js → WidgetLayout-W2RGGOQ3.js} +10 -10
  35. package/dist/{chunk-U7KURWW3.js → chunk-2GIZY3JJ.js} +276 -54
  36. package/dist/chunk-2GIZY3JJ.js.map +1 -0
  37. package/dist/{chunk-WVE3F724.js → chunk-2QTH6JHX.js} +21 -4
  38. package/dist/chunk-2QTH6JHX.js.map +1 -0
  39. package/dist/{chunk-XAU7QFG3.js → chunk-3ZW74FHC.js} +68 -256
  40. package/dist/chunk-3ZW74FHC.js.map +1 -0
  41. package/dist/{chunk-FJW36PD7.js → chunk-67ZO7Z2W.js} +28 -24
  42. package/dist/chunk-67ZO7Z2W.js.map +1 -0
  43. package/dist/{chunk-QC42MLAK.js → chunk-7AAO4UDQ.js} +4 -3
  44. package/dist/chunk-7AAO4UDQ.js.map +1 -0
  45. package/dist/{chunk-MPNSO7E6.js → chunk-CG75X77Q.js} +2 -2
  46. package/dist/chunk-DPPOEFBD.js +517 -0
  47. package/dist/chunk-DPPOEFBD.js.map +1 -0
  48. package/dist/{chunk-6O6FWUDW.js → chunk-EPAL2HD5.js} +641 -388
  49. package/dist/chunk-EPAL2HD5.js.map +1 -0
  50. package/dist/{chunk-ZTMKFZQ3.js → chunk-GG23N2GW.js} +5099 -3295
  51. package/dist/chunk-GG23N2GW.js.map +1 -0
  52. package/dist/chunk-JCL3Q7RW.js +587 -0
  53. package/dist/chunk-JCL3Q7RW.js.map +1 -0
  54. package/dist/{chunk-M62XY4NC.js → chunk-JKEBMGLH.js} +235 -108
  55. package/dist/chunk-JKEBMGLH.js.map +1 -0
  56. package/dist/{chunk-DMMZSZTN.js → chunk-KSGNKS2D.js} +60 -16
  57. package/dist/chunk-KSGNKS2D.js.map +1 -0
  58. package/dist/{chunk-CYHJDKFB.js → chunk-PCI6VMB5.js} +189 -52
  59. package/dist/chunk-PCI6VMB5.js.map +1 -0
  60. package/dist/{chunk-ZKNUMH2M.js → chunk-PQ7VWBQQ.js} +13 -11
  61. package/dist/chunk-PQ7VWBQQ.js.map +1 -0
  62. package/dist/chunk-T6QQV5LK.js +238 -0
  63. package/dist/chunk-T6QQV5LK.js.map +1 -0
  64. package/dist/{createTrueFoundryServer-CmZnBh_l.d.ts → createTrueFoundryServer-B_FYhSdn.d.ts} +8 -5
  65. package/dist/index.d.ts +369 -108
  66. package/dist/index.js +69 -488
  67. package/dist/index.js.map +1 -1
  68. package/dist/plugins/trueforge-agent-server-adapter/index.d.ts +49 -14
  69. package/dist/plugins/trueforge-agent-server-adapter/index.js +138 -50
  70. package/dist/plugins/trueforge-agent-server-adapter/index.js.map +1 -1
  71. package/dist/styles.css +1 -1
  72. package/package.json +5 -4
  73. package/dist/AgentCodeSnippets-NZOFJE57.js.map +0 -1
  74. package/dist/AgentMetricChart-JPU3MFQ2.js +0 -15
  75. package/dist/AgentOverview-EEBHJC32.js.map +0 -1
  76. package/dist/AgentSessionEventTimeline-26Z6IB3B.js.map +0 -1
  77. package/dist/AgentSessionEventTimelineChart-CGCU7WBK.js.map +0 -1
  78. package/dist/AgentSessions-3MPDZASK.js.map +0 -1
  79. package/dist/ConnectorSettings-MXFRWWR6.js.map +0 -1
  80. package/dist/DrawerLayout-JR3O6RRB.js.map +0 -1
  81. package/dist/ModelSettings-G7IFNC2Y.js.map +0 -1
  82. package/dist/OpenUiFenceBlock-2TV5TQ6P.js +0 -9
  83. package/dist/SandboxSettings-NXAANMAX.js.map +0 -1
  84. package/dist/SchedulesPage-KKLUDO6B.js +0 -15
  85. package/dist/ShellRouteSync-CEBETGEJ.js.map +0 -1
  86. package/dist/SidebarLayout-A2HJPPHS.js.map +0 -1
  87. package/dist/SkillSettings-FGGMSUNO.js.map +0 -1
  88. package/dist/chunk-2XPPBEYF.js +0 -74
  89. package/dist/chunk-2XPPBEYF.js.map +0 -1
  90. package/dist/chunk-6O6FWUDW.js.map +0 -1
  91. package/dist/chunk-7Z2C2K7F.js +0 -578
  92. package/dist/chunk-7Z2C2K7F.js.map +0 -1
  93. package/dist/chunk-CYHJDKFB.js.map +0 -1
  94. package/dist/chunk-DMMZSZTN.js.map +0 -1
  95. package/dist/chunk-FJW36PD7.js.map +0 -1
  96. package/dist/chunk-M62XY4NC.js.map +0 -1
  97. package/dist/chunk-QC42MLAK.js.map +0 -1
  98. package/dist/chunk-SFZNIO6U.js +0 -18
  99. package/dist/chunk-SFZNIO6U.js.map +0 -1
  100. package/dist/chunk-U7KURWW3.js.map +0 -1
  101. package/dist/chunk-WVE3F724.js.map +0 -1
  102. package/dist/chunk-XAU7QFG3.js.map +0 -1
  103. package/dist/chunk-ZKNUMH2M.js.map +0 -1
  104. package/dist/chunk-ZTMKFZQ3.js.map +0 -1
  105. /package/dist/{AgentMetricChart-JPU3MFQ2.js.map → AgentMetricChart-UPGSJ2WP.js.map} +0 -0
  106. /package/dist/{DockLayout-LM4AFMFY.js.map → DockLayout-D2FPQCAL.js.map} +0 -0
  107. /package/dist/{OpenUiFenceBlock-2TV5TQ6P.js.map → OpenUiFenceBlock-KPZFLUSC.js.map} +0 -0
  108. /package/dist/{SchedulesPage-KKLUDO6B.js.map → SchedulesPage-QKYI2Z3A.js.map} +0 -0
  109. /package/dist/{TrueForgeUIWithRouter-MZVJWJMB.js.map → TrueForgeUIWithRouter-LKG4XLW6.js.map} +0 -0
  110. /package/dist/{WidgetLayout-6QM45OQQ.js.map → WidgetLayout-W2RGGOQ3.js.map} +0 -0
  111. /package/dist/{chunk-MPNSO7E6.js.map → chunk-CG75X77Q.js.map} +0 -0
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  Button,
3
3
  ConnectorConnectButton,
4
+ CreatedByCell,
4
5
  DEFAULT_TABLE_PAGE_SIZE,
5
6
  Dialog,
6
7
  DialogContent,
@@ -23,33 +24,266 @@ import {
23
24
  TableTokenPagination,
24
25
  Tooltip,
25
26
  auiInputClass,
27
+ auiSelectMenuClass,
28
+ auiSelectOptionClass,
29
+ auiSelectTriggerClass,
30
+ hasCreatedBySubject,
26
31
  mountName,
27
- searchAllAgents,
32
+ themePortalRoot,
33
+ useResourcePermissions,
34
+ useSlot,
28
35
  useToasterOptional
29
- } from "./chunk-ZTMKFZQ3.js";
36
+ } from "./chunk-GG23N2GW.js";
30
37
  import {
38
+ findLibraryAgent,
31
39
  readScheduleShareSearch,
32
- replaceScheduleShareSearch
33
- } from "./chunk-2XPPBEYF.js";
40
+ replaceScheduleShareSearch,
41
+ useSearchAgentsList
42
+ } from "./chunk-T6QQV5LK.js";
34
43
  import {
35
44
  DraftCatalogProvider,
36
45
  Icon,
37
46
  PageHeader,
38
47
  auiButtonClass,
39
48
  useDraftCatalog
40
- } from "./chunk-XAU7QFG3.js";
49
+ } from "./chunk-3ZW74FHC.js";
41
50
  import {
42
51
  libraryAgentId,
43
52
  useOptionalCatalogServer,
53
+ useOptionalShellMode,
44
54
  useScheduleServer,
45
55
  useServer
46
- } from "./chunk-U7KURWW3.js";
56
+ } from "./chunk-2GIZY3JJ.js";
47
57
  import {
48
58
  cn
49
- } from "./chunk-7Z2C2K7F.js";
59
+ } from "./chunk-JCL3Q7RW.js";
50
60
 
51
61
  // src/atoms/schedules/SchedulesPage.tsx
52
- import { useCallback, useEffect as useEffect3, useMemo as useMemo2, useRef, useState as useState3 } from "react";
62
+ import { useCallback, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef3, useState as useState4 } from "react";
63
+
64
+ // src/atoms/AgentSearchPicker.tsx
65
+ import { useEffect, useId, useLayoutEffect, useRef, useState } from "react";
66
+ import { createPortal } from "react-dom";
67
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
68
+ function AgentSearchPicker({
69
+ value,
70
+ selectedLabel,
71
+ onValueChange,
72
+ onAgentPicked,
73
+ disabled = false,
74
+ onBuildAgent,
75
+ allOption,
76
+ "aria-label": ariaLabel = "Agent",
77
+ placeholder = "Search agent",
78
+ className
79
+ }) {
80
+ const [open, setOpen] = useState(false);
81
+ const [query, setQuery] = useState("");
82
+ const [pos, setPos] = useState(null);
83
+ const rootRef = useRef(null);
84
+ const triggerRef = useRef(null);
85
+ const inputRef = useRef(null);
86
+ const menuRef = useRef(null);
87
+ const listboxId = useId();
88
+ const { agents, isInitialLoading, isSearching, loadingMore, hasMore, error, listRef, sentinelRef } = useSearchAgentsList({
89
+ enabled: open && !disabled,
90
+ query
91
+ });
92
+ useEffect(() => {
93
+ if (!open) setQuery("");
94
+ }, [open]);
95
+ useLayoutEffect(() => {
96
+ if (!open) {
97
+ setPos(null);
98
+ return;
99
+ }
100
+ const update = () => {
101
+ const el = triggerRef.current;
102
+ if (!el) return;
103
+ const rect = el.getBoundingClientRect();
104
+ setPos({
105
+ top: rect.bottom + 4,
106
+ left: rect.left,
107
+ width: rect.width
108
+ });
109
+ };
110
+ update();
111
+ window.addEventListener("scroll", update, true);
112
+ window.addEventListener("resize", update);
113
+ return () => {
114
+ window.removeEventListener("scroll", update, true);
115
+ window.removeEventListener("resize", update);
116
+ };
117
+ }, [open]);
118
+ useEffect(() => {
119
+ if (!open) return;
120
+ const handlePointerDown = (event) => {
121
+ if (!(event.target instanceof Node)) return;
122
+ if (rootRef.current?.contains(event.target)) return;
123
+ if (menuRef.current?.contains(event.target)) return;
124
+ setOpen(false);
125
+ };
126
+ document.addEventListener("mousedown", handlePointerDown);
127
+ return () => document.removeEventListener("mousedown", handlePointerDown);
128
+ }, [open]);
129
+ const close = () => {
130
+ setOpen(false);
131
+ setQuery("");
132
+ inputRef.current?.blur();
133
+ };
134
+ const pick = (agent) => {
135
+ const id = libraryAgentId(agent);
136
+ onValueChange(id);
137
+ onAgentPicked?.(agent);
138
+ close();
139
+ };
140
+ const pickAll = () => {
141
+ if (allOption == null) return;
142
+ onValueChange(allOption.value);
143
+ close();
144
+ };
145
+ const inputValue = open ? query : selectedLabel;
146
+ const queryTrimmed = query.trim();
147
+ const showError = !isInitialLoading && error != null;
148
+ const showEmptyCatalog = !isInitialLoading && error == null && agents.length === 0 && queryTrimmed === "";
149
+ const showNoMatch = !isInitialLoading && error == null && agents.length === 0 && queryTrimmed !== "";
150
+ const menu = open && pos != null && !disabled ? createPortal(
151
+ /* @__PURE__ */ jsxs(
152
+ "div",
153
+ {
154
+ ref: menuRef,
155
+ className: auiSelectMenuClass("fixed z-[200] flex max-h-64 flex-col overflow-hidden"),
156
+ style: {
157
+ top: pos.top,
158
+ left: pos.left,
159
+ width: pos.width
160
+ },
161
+ onMouseDown: (event) => event.stopPropagation(),
162
+ children: [
163
+ /* @__PURE__ */ jsxs(
164
+ "div",
165
+ {
166
+ ref: listRef,
167
+ id: listboxId,
168
+ role: "listbox",
169
+ "aria-label": ariaLabel,
170
+ className: "min-h-0 flex-1 overflow-y-auto p-1",
171
+ children: [
172
+ allOption != null && queryTrimmed === "" ? /* @__PURE__ */ jsxs(
173
+ "button",
174
+ {
175
+ type: "button",
176
+ role: "option",
177
+ "aria-selected": value === allOption.value,
178
+ className: auiSelectOptionClass(),
179
+ onClick: pickAll,
180
+ children: [
181
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: allOption.label }),
182
+ /* @__PURE__ */ jsx(
183
+ Icon,
184
+ {
185
+ name: "check",
186
+ className: cn("ml-auto size-4 shrink-0", value === allOption.value ? "opacity-100" : "opacity-0")
187
+ }
188
+ )
189
+ ]
190
+ }
191
+ ) : null,
192
+ isInitialLoading ? /* @__PURE__ */ jsx("p", { className: "text-text-secondary px-3 py-5 text-center text-sm", role: "status", children: "Loading\u2026" }) : showError ? /* @__PURE__ */ jsx("p", { className: "text-failure-bg px-3 py-5 text-center text-sm", role: "alert", children: error }) : showEmptyCatalog ? /* @__PURE__ */ jsx("p", { className: "text-text-secondary px-3 py-5 text-center text-sm", children: "No Agents created yet" }) : showNoMatch ? /* @__PURE__ */ jsxs("p", { className: "text-text-secondary px-3 py-5 text-center text-sm", role: "status", children: [
193
+ 'No agents match "',
194
+ queryTrimmed,
195
+ '".'
196
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
197
+ isSearching ? /* @__PURE__ */ jsx("p", { className: "sr-only", role: "status", children: "Searching\u2026" }) : null,
198
+ agents.map((agent) => {
199
+ const id = libraryAgentId(agent);
200
+ const selected = value === id;
201
+ return /* @__PURE__ */ jsxs(
202
+ "button",
203
+ {
204
+ type: "button",
205
+ role: "option",
206
+ "aria-selected": selected,
207
+ className: auiSelectOptionClass(),
208
+ onClick: () => pick(agent),
209
+ children: [
210
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: agent.name }),
211
+ /* @__PURE__ */ jsx(
212
+ Icon,
213
+ {
214
+ name: "check",
215
+ className: cn("ml-auto size-4 shrink-0", selected ? "opacity-100" : "opacity-0")
216
+ }
217
+ )
218
+ ]
219
+ },
220
+ id
221
+ );
222
+ }),
223
+ hasMore ? /* @__PURE__ */ jsx("div", { ref: sentinelRef, className: "flex h-6 shrink-0 items-center justify-center", "aria-hidden": true, children: loadingMore ? /* @__PURE__ */ jsx("span", { className: "text-text-secondary text-[11px]", role: "status", children: "Loading more\u2026" }) : null }) : null
224
+ ] })
225
+ ]
226
+ }
227
+ ),
228
+ showEmptyCatalog && onBuildAgent != null ? /* @__PURE__ */ jsx("div", { className: "flex justify-end border-t border-border px-2 pt-2", children: /* @__PURE__ */ jsxs(Button.Ghost, { type: "button", onClick: onBuildAgent, children: [
229
+ /* @__PURE__ */ jsx(Icon, { name: "plus", className: "size-3.5" }),
230
+ "Build Agent"
231
+ ] }) }) : null
232
+ ]
233
+ }
234
+ ),
235
+ themePortalRoot(rootRef.current)
236
+ ) : null;
237
+ return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn("relative", className), children: [
238
+ /* @__PURE__ */ jsxs(
239
+ "div",
240
+ {
241
+ ref: triggerRef,
242
+ className: auiSelectTriggerClass(disabled ? "cursor-not-allowed opacity-50" : "cursor-text"),
243
+ children: [
244
+ /* @__PURE__ */ jsx(
245
+ "input",
246
+ {
247
+ ref: inputRef,
248
+ type: "text",
249
+ role: "combobox",
250
+ "aria-label": ariaLabel,
251
+ "aria-expanded": open,
252
+ "aria-controls": open ? listboxId : void 0,
253
+ "aria-autocomplete": "list",
254
+ disabled,
255
+ placeholder,
256
+ value: inputValue,
257
+ className: "min-w-0 flex-1 bg-transparent outline-none placeholder:text-text-secondary/70 disabled:cursor-not-allowed",
258
+ onFocus: () => {
259
+ if (!disabled) setOpen(true);
260
+ },
261
+ onChange: (event) => {
262
+ if (disabled) return;
263
+ setQuery(event.target.value);
264
+ setOpen(true);
265
+ },
266
+ onKeyDown: (event) => {
267
+ if (event.key === "Escape") {
268
+ event.preventDefault();
269
+ setOpen(false);
270
+ inputRef.current?.blur();
271
+ return;
272
+ }
273
+ if (event.key === "ArrowDown" && !open && !disabled) {
274
+ event.preventDefault();
275
+ setOpen(true);
276
+ }
277
+ }
278
+ }
279
+ ),
280
+ /* @__PURE__ */ jsx(Icon, { name: "chevron-down", className: "size-4 shrink-0 text-text-secondary" })
281
+ ]
282
+ }
283
+ ),
284
+ menu
285
+ ] });
286
+ }
53
287
 
54
288
  // src/atoms/schedules/cadence.ts
55
289
  var TIMEZONE_OPTIONS = [
@@ -255,10 +489,10 @@ function formatRelativeTime(iso, nowMs = Date.now()) {
255
489
  }
256
490
 
257
491
  // src/atoms/schedules/ScheduleFormDrawer.tsx
258
- import { useEffect as useEffect2, useMemo, useState as useState2 } from "react";
492
+ import { useEffect as useEffect3, useMemo, useRef as useRef2, useState as useState3 } from "react";
259
493
 
260
494
  // src/atoms/schedules/ScheduleFormFields.tsx
261
- import { jsx, jsxs } from "react/jsx-runtime";
495
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
262
496
  var RECURRENCE_OPTIONS = [
263
497
  { value: "hourly", label: "Hourly" },
264
498
  { value: "daily", label: "Daily" },
@@ -276,9 +510,11 @@ function ScheduleFormFields({
276
510
  values,
277
511
  onChange,
278
512
  agentId,
513
+ agentLabel,
279
514
  onAgentIdChange,
280
- agentOptions,
281
- agentPickerDisabled = false
515
+ onAgentPicked,
516
+ agentPickerDisabled = false,
517
+ onBuildAgent
282
518
  }) {
283
519
  const cron = valuesToCron(values);
284
520
  const cadence = formatCadenceSummary({ cron, timezone: values.timezone });
@@ -291,37 +527,39 @@ function ScheduleFormFields({
291
527
  const weekdays = has ? values.weekdays.filter((d) => d !== day) : [...values.weekdays, day];
292
528
  onChange({ ...values, weekdays: weekdays.length > 0 ? weekdays : [day] });
293
529
  };
294
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 px-5 py-4", children: [
295
- /* @__PURE__ */ jsxs("div", { className: "block", children: [
296
- /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-sm font-medium", children: "Agent" }),
297
- /* @__PURE__ */ jsx(
298
- PopoverSelect,
530
+ return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-4 px-5 py-4", children: [
531
+ /* @__PURE__ */ jsxs2("div", { className: "block", children: [
532
+ /* @__PURE__ */ jsx2("span", { className: "mb-1.5 block text-sm font-medium", children: "Agent" }),
533
+ /* @__PURE__ */ jsx2(
534
+ AgentSearchPicker,
299
535
  {
300
536
  "aria-label": "Agent",
301
- placeholder: "Select an agent",
537
+ placeholder: "Search agent",
302
538
  value: agentId,
303
- options: agentOptions.map((agent) => ({ value: agent.agentId, label: agent.name })),
539
+ selectedLabel: agentLabel,
304
540
  onValueChange: (value) => onAgentIdChange?.(value),
305
- disabled: agentPickerDisabled || onAgentIdChange == null
541
+ onAgentPicked,
542
+ disabled: agentPickerDisabled || onAgentIdChange == null,
543
+ onBuildAgent
306
544
  }
307
545
  )
308
546
  ] }),
309
- /* @__PURE__ */ jsxs("label", { className: "block", children: [
310
- /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-sm font-medium", children: "Name" }),
311
- /* @__PURE__ */ jsx(
547
+ /* @__PURE__ */ jsxs2("label", { className: "block", children: [
548
+ /* @__PURE__ */ jsx2("span", { className: "mb-1.5 block text-sm font-medium", children: "Name" }),
549
+ /* @__PURE__ */ jsx2(
312
550
  "input",
313
551
  {
314
552
  value: values.name,
315
553
  onChange: (e) => set("name", e.target.value),
316
554
  placeholder: "harness-daily-digest",
317
- className: auiInputClass("h-9"),
555
+ className: auiInputClass("h-8"),
318
556
  required: true
319
557
  }
320
558
  )
321
559
  ] }),
322
- /* @__PURE__ */ jsxs("label", { className: "block", children: [
323
- /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-sm font-medium", children: "Task" }),
324
- /* @__PURE__ */ jsx(
560
+ /* @__PURE__ */ jsxs2("label", { className: "block", children: [
561
+ /* @__PURE__ */ jsx2("span", { className: "mb-1.5 block text-sm font-medium", children: "Task" }),
562
+ /* @__PURE__ */ jsx2(
325
563
  "textarea",
326
564
  {
327
565
  value: values.task,
@@ -333,114 +571,103 @@ function ScheduleFormFields({
333
571
  }
334
572
  )
335
573
  ] }),
336
- /* @__PURE__ */ jsxs("fieldset", { children: [
337
- /* @__PURE__ */ jsx("legend", { className: "mb-1.5 text-sm font-medium", children: "Recurrence" }),
338
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 rounded-lg border border-border p-1", children: RECURRENCE_OPTIONS.map((opt) => {
339
- const selected = values.recurrence === opt.value;
340
- return /* @__PURE__ */ jsx(
341
- "button",
342
- {
343
- type: "button",
344
- className: cn(
345
- "rounded-md px-2 py-1.5 text-xs font-medium transition-colors",
346
- selected ? "border border-primary-button-bg/40 bg-primary-button-bg/10 text-primary-button-bg" : "text-text-secondary hover:bg-ghost-button-hover border border-transparent"
347
- ),
348
- "aria-pressed": selected,
349
- onClick: () => set("recurrence", opt.value),
350
- children: opt.label
351
- },
352
- opt.value
353
- );
354
- }) })
355
- ] }),
356
- values.recurrence === "hourly" ? /* @__PURE__ */ jsxs("div", { className: "block max-w-[8rem]", children: [
357
- /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-sm font-medium", children: "Minute" }),
358
- /* @__PURE__ */ jsx(
359
- PopoverSelect,
360
- {
361
- "aria-label": "Minute",
362
- value: String(values.minute),
363
- options: MINUTE_OPTIONS,
364
- onValueChange: (value) => set("minute", Number(value))
365
- }
366
- )
367
- ] }) : null,
368
- values.recurrence === "daily" || values.recurrence === "weekly" ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-3", children: [
369
- /* @__PURE__ */ jsxs("div", { className: "block min-w-[7rem] flex-1", children: [
370
- /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-sm font-medium", children: "Hour" }),
371
- /* @__PURE__ */ jsx(
372
- PopoverSelect,
373
- {
374
- "aria-label": "Hour",
375
- value: String(values.hour),
376
- options: HOUR_OPTIONS,
377
- onValueChange: (value) => set("hour", Number(value))
378
- }
379
- )
380
- ] }),
381
- /* @__PURE__ */ jsxs("div", { className: "block min-w-[7rem] flex-1", children: [
382
- /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-sm font-medium", children: "Minute" }),
383
- /* @__PURE__ */ jsx(
384
- PopoverSelect,
385
- {
386
- "aria-label": "Minute",
387
- value: String(values.minute),
388
- options: MINUTE_OPTIONS,
389
- onValueChange: (value) => set("minute", Number(value))
390
- }
391
- )
392
- ] })
393
- ] }) : null,
394
- values.recurrence === "weekly" ? /* @__PURE__ */ jsxs("fieldset", { children: [
395
- /* @__PURE__ */ jsx("legend", { className: "mb-1.5 text-sm font-medium", children: "Days" }),
396
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: WEEKDAY_OPTIONS.map((day) => {
397
- const selected = values.weekdays.includes(day.value);
398
- return /* @__PURE__ */ jsx(
399
- "button",
400
- {
401
- type: "button",
402
- className: cn(
403
- "rounded-md border px-2.5 py-1 text-xs font-medium",
404
- selected ? "border-primary-button-bg/40 bg-primary-button-bg/10 text-primary-button-bg" : "border-border text-text-secondary hover:bg-ghost-button-hover"
405
- ),
406
- "aria-pressed": selected,
407
- onClick: () => toggleWeekday(day.value),
408
- children: day.label
409
- },
410
- day.value
411
- );
412
- }) })
413
- ] }) : null,
414
- values.recurrence === "custom" ? /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-border bg-secondary-bg/40 px-3 py-2", children: [
415
- /* @__PURE__ */ jsx("span", { className: "text-text-secondary block text-xs", children: "Existing custom schedule" }),
416
- /* @__PURE__ */ jsx("code", { className: "text-text-primary mt-1 block font-mono text-sm", children: values.customCron }),
417
- /* @__PURE__ */ jsx("span", { className: "text-text-secondary mt-1 block text-xs", children: "Select Hourly, Daily, or Weekly to replace this schedule." })
418
- ] }) : null,
419
- /* @__PURE__ */ jsxs("div", { className: "block", children: [
420
- /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-sm font-medium", children: "Timezone" }),
421
- /* @__PURE__ */ jsx(
422
- PopoverSelect,
423
- {
424
- "aria-label": "Timezone",
425
- value: values.timezone,
426
- options: timezoneOptions,
427
- onValueChange: (value) => set("timezone", value),
428
- menuPlacement: "top"
429
- }
430
- )
431
- ] }),
432
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-border bg-secondary-bg/40 px-3 py-3", children: [
433
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
434
- /* @__PURE__ */ jsx("span", { className: "text-text-secondary text-[10px] font-semibold tracking-wide uppercase", children: "Frequency" }),
435
- /* @__PURE__ */ jsx("code", { className: "text-text-secondary font-mono text-xs", children: cron || "\u2014" })
436
- ] }),
437
- /* @__PURE__ */ jsx("p", { className: "text-text-primary mt-1 text-sm font-semibold", children: cadence || "\u2014" })
574
+ /* @__PURE__ */ jsxs2("fieldset", { children: [
575
+ /* @__PURE__ */ jsx2("legend", { className: "mb-1.5 text-sm font-medium", children: "Frequency" }),
576
+ /* @__PURE__ */ jsx2("div", { className: "rounded-t-lg border border-border p-4", children: /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-4", children: [
577
+ /* @__PURE__ */ jsx2("div", { className: "grid grid-cols-3 gap-1 rounded-lg border border-border bg-primary-bg p-1", children: RECURRENCE_OPTIONS.map((opt) => {
578
+ const selected = values.recurrence === opt.value;
579
+ return /* @__PURE__ */ jsx2(
580
+ "button",
581
+ {
582
+ type: "button",
583
+ className: cn(
584
+ "rounded-md border px-2 py-2 text-sm font-medium transition-colors",
585
+ selected ? "border-primary-button-bg/40 bg-primary-button-bg/10 font-semibold text-primary-button-bg" : "border-transparent text-text-secondary hover:bg-ghost-button-hover"
586
+ ),
587
+ "aria-pressed": selected,
588
+ onClick: () => set("recurrence", opt.value),
589
+ children: opt.label
590
+ },
591
+ opt.value
592
+ );
593
+ }) }),
594
+ values.recurrence === "custom" ? /* @__PURE__ */ jsxs2("div", { className: "rounded-md border border-border bg-secondary-bg/40 px-3 py-2", children: [
595
+ /* @__PURE__ */ jsx2("span", { className: "block text-xs text-text-secondary", children: "Existing custom schedule" }),
596
+ /* @__PURE__ */ jsx2("code", { className: "mt-1 block font-mono text-sm text-text-primary", children: values.customCron }),
597
+ /* @__PURE__ */ jsx2("span", { className: "mt-1 block text-xs text-text-secondary", children: "Select Hourly, Daily, or Weekly to replace this schedule." })
598
+ ] }) : null,
599
+ values.recurrence === "weekly" ? /* @__PURE__ */ jsxs2("fieldset", { children: [
600
+ /* @__PURE__ */ jsx2("legend", { className: "mb-2 text-sm font-medium", children: "Days" }),
601
+ /* @__PURE__ */ jsx2("div", { className: "flex gap-2", children: WEEKDAY_OPTIONS.map((day) => {
602
+ const selected = values.weekdays.includes(day.value);
603
+ return /* @__PURE__ */ jsx2(
604
+ "button",
605
+ {
606
+ type: "button",
607
+ className: cn(
608
+ "min-w-0 flex-1 rounded-md border px-3 py-2 text-[0.8125rem] font-medium",
609
+ selected ? "border-primary-button-bg/40 bg-primary-button-bg/10 font-semibold text-primary-button-bg" : "border-border text-text-secondary hover:bg-ghost-button-hover"
610
+ ),
611
+ "aria-pressed": selected,
612
+ onClick: () => toggleWeekday(day.value),
613
+ children: day.label
614
+ },
615
+ day.value
616
+ );
617
+ }) })
618
+ ] }) : null,
619
+ /* @__PURE__ */ jsxs2("div", { className: "flex gap-4", children: [
620
+ values.recurrence === "daily" || values.recurrence === "weekly" ? /* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
621
+ /* @__PURE__ */ jsx2("span", { className: "mb-1.5 block text-sm font-medium", children: "Hour" }),
622
+ /* @__PURE__ */ jsx2(
623
+ PopoverSelect,
624
+ {
625
+ "aria-label": "Hour",
626
+ value: String(values.hour),
627
+ options: HOUR_OPTIONS,
628
+ onValueChange: (value) => set("hour", Number(value))
629
+ }
630
+ )
631
+ ] }) : null,
632
+ values.recurrence !== "custom" ? /* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
633
+ /* @__PURE__ */ jsx2("span", { className: "mb-1.5 block text-sm font-medium", children: "Minute" }),
634
+ /* @__PURE__ */ jsx2(
635
+ PopoverSelect,
636
+ {
637
+ "aria-label": "Minute",
638
+ value: String(values.minute),
639
+ options: MINUTE_OPTIONS,
640
+ onValueChange: (value) => set("minute", Number(value))
641
+ }
642
+ )
643
+ ] }) : null,
644
+ /* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
645
+ /* @__PURE__ */ jsx2("span", { className: "mb-1.5 block text-sm font-medium", children: "Timezone" }),
646
+ /* @__PURE__ */ jsx2(
647
+ PopoverSelect,
648
+ {
649
+ "aria-label": "Timezone",
650
+ value: values.timezone,
651
+ options: timezoneOptions,
652
+ onValueChange: (value) => set("timezone", value),
653
+ menuClassName: "w-full min-w-0"
654
+ }
655
+ )
656
+ ] })
657
+ ] })
658
+ ] }) }),
659
+ /* @__PURE__ */ jsx2("div", { className: "rounded-b-lg border border-t-0 border-border bg-primary-button-bg/10 px-4 py-3", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
660
+ /* @__PURE__ */ jsx2(Icon, { name: "clock", className: "size-4 shrink-0 text-primary-button-bg" }),
661
+ /* @__PURE__ */ jsx2("span", { className: "shrink-0 text-xs font-medium text-text-secondary", children: "Schedule" }),
662
+ /* @__PURE__ */ jsx2("p", { className: "min-w-0 flex-1 truncate text-sm text-text-primary", children: cadence || "\u2014" }),
663
+ /* @__PURE__ */ jsx2("code", { className: "shrink-0 whitespace-nowrap font-mono text-[0.8125rem] font-bold text-text-secondary", children: cron || "\u2014" })
664
+ ] }) })
438
665
  ] })
439
666
  ] });
440
667
  }
441
668
 
442
669
  // src/atoms/schedules/TestScheduleScreen.tsx
443
- import { useEffect, useState } from "react";
670
+ import { useEffect as useEffect2, useState as useState2 } from "react";
444
671
 
445
672
  // src/atoms/schedules/scheduleRuns.ts
446
673
  function isManualRun(name) {
@@ -477,20 +704,20 @@ function formatScheduleRunInstant(iso) {
477
704
  }
478
705
 
479
706
  // src/atoms/schedules/ScheduleRunTooltip.tsx
480
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
707
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
481
708
  function ScheduleRunTooltip({ run }) {
482
- return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-1 text-left text-xs", children: [
483
- /* @__PURE__ */ jsx2("p", { className: "text-text-primary font-medium", children: runStatusLabel(run.status) }),
484
- /* @__PURE__ */ jsx2("p", { className: "text-text-secondary", children: runTypeLabel(run.name) }),
485
- /* @__PURE__ */ jsxs2("p", { className: "text-text-secondary", children: [
709
+ return /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-1 text-left text-xs", children: [
710
+ /* @__PURE__ */ jsx3("p", { className: "text-text-primary font-medium", children: runStatusLabel(run.status) }),
711
+ /* @__PURE__ */ jsx3("p", { className: "text-text-secondary", children: runTypeLabel(run.name) }),
712
+ /* @__PURE__ */ jsxs3("p", { className: "text-text-secondary", children: [
486
713
  "Scheduled for: ",
487
714
  formatScheduleRunInstant(run.scheduledFor)
488
715
  ] }),
489
- run.triggeredAt != null ? /* @__PURE__ */ jsxs2("p", { className: "text-text-secondary", children: [
716
+ run.triggeredAt != null ? /* @__PURE__ */ jsxs3("p", { className: "text-text-secondary", children: [
490
717
  "Triggered at: ",
491
718
  formatScheduleRunInstant(run.triggeredAt)
492
719
  ] }) : null,
493
- /* @__PURE__ */ jsxs2("p", { className: "text-text-secondary", children: [
720
+ /* @__PURE__ */ jsxs3("p", { className: "text-text-secondary", children: [
494
721
  "Triggered by: ",
495
722
  run.triggeredBy
496
723
  ] })
@@ -498,7 +725,7 @@ function ScheduleRunTooltip({ run }) {
498
725
  }
499
726
 
500
727
  // src/atoms/schedules/ScheduleRunChip.tsx
501
- import { jsx as jsx3 } from "react/jsx-runtime";
728
+ import { jsx as jsx4 } from "react/jsx-runtime";
502
729
  var CHIP_STYLES = {
503
730
  success: "border-emerald-600/30 bg-emerald-500/10 text-emerald-700 dark:border-emerald-400/35 dark:bg-emerald-500/15 dark:text-emerald-300",
504
731
  failed: "border-red-600/30 bg-red-500/10 text-red-700 dark:border-red-400/35 dark:bg-red-500/15 dark:text-red-300"
@@ -506,34 +733,34 @@ var CHIP_STYLES = {
506
733
  function ScheduleRunChip({ run }) {
507
734
  const kind = runChipKind(run.status);
508
735
  const when = formatScheduleRunInstant(run.triggeredAt ?? run.scheduledFor);
509
- return /* @__PURE__ */ jsx3(Tooltip, { content: /* @__PURE__ */ jsx3(ScheduleRunTooltip, { run }), side: "top", children: /* @__PURE__ */ jsx3(
736
+ return /* @__PURE__ */ jsx4(Tooltip, { content: /* @__PURE__ */ jsx4(ScheduleRunTooltip, { run }), side: "top", children: /* @__PURE__ */ jsx4(
510
737
  "span",
511
738
  {
512
739
  className: cn("inline-flex size-6 shrink-0 items-center justify-center rounded-md border", CHIP_STYLES[kind]),
513
740
  "aria-label": `${runStatusLabel(run.status)} run at ${when}`,
514
- children: /* @__PURE__ */ jsx3(Icon, { name: kind === "failed" ? "triangle-exclamation" : "check", className: "size-3.5" })
741
+ children: /* @__PURE__ */ jsx4(Icon, { name: kind === "failed" ? "triangle-exclamation" : "check", className: "size-3.5" })
515
742
  }
516
743
  ) });
517
744
  }
518
745
 
519
746
  // src/atoms/schedules/ScheduleStatusBadge.tsx
520
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
747
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
521
748
  function ScheduleStatusBadge({ status }) {
522
749
  const active = status === "active";
523
- return /* @__PURE__ */ jsxs3(
750
+ return /* @__PURE__ */ jsxs4(
524
751
  "span",
525
752
  {
526
753
  className: cn(
527
754
  "inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-xs font-medium",
528
- active ? "border-emerald-600/30 bg-emerald-500/10 text-emerald-700 dark:border-emerald-400/35 dark:bg-emerald-500/15 dark:text-emerald-300" : "border-border bg-secondary-bg text-text-secondary"
755
+ active ? "border-emerald-600/30 bg-emerald-500/10 text-emerald-700 dark:border-emerald-400/35 dark:bg-emerald-500/15 dark:text-emerald-300" : "border-amber-600/30 bg-amber-500/10 text-amber-800 dark:border-amber-400/35 dark:bg-amber-500/15 dark:text-amber-300"
529
756
  ),
530
757
  children: [
531
- /* @__PURE__ */ jsx4(
758
+ /* @__PURE__ */ jsx5(
532
759
  "span",
533
760
  {
534
761
  className: cn(
535
762
  "size-1.5 shrink-0 rounded-full",
536
- active ? "bg-emerald-600 dark:bg-emerald-400" : "bg-text-secondary"
763
+ active ? "bg-emerald-600 dark:bg-emerald-400" : "bg-amber-600 dark:bg-amber-400"
537
764
  ),
538
765
  "aria-hidden": true
539
766
  }
@@ -545,7 +772,7 @@ function ScheduleStatusBadge({ status }) {
545
772
  }
546
773
 
547
774
  // src/atoms/schedules/TestScheduleScreen.tsx
548
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
775
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
549
776
  function mountConnector(connectors, name) {
550
777
  return connectors.find((connector) => connector.name === name || connector.id === name) ?? null;
551
778
  }
@@ -555,20 +782,20 @@ function ScheduleMcpConnect({
555
782
  }) {
556
783
  const catalog = useOptionalCatalogServer();
557
784
  if (catalog == null) return null;
558
- return /* @__PURE__ */ jsx5(ConnectorConnectButton, { connector, onConnected });
785
+ return /* @__PURE__ */ jsx6(ConnectorConnectButton, { connector, onConnected });
559
786
  }
560
787
  function DetailRow({ label, children }) {
561
- return /* @__PURE__ */ jsxs4("div", { className: "flex items-start justify-between gap-3 border-b border-border px-3 py-2.5 last:border-b-0", children: [
562
- /* @__PURE__ */ jsx5("span", { className: "text-text-secondary shrink-0 text-[10px] font-semibold tracking-wide uppercase", children: label }),
563
- /* @__PURE__ */ jsx5("div", { className: "min-w-0 text-right text-sm text-text-primary", children })
788
+ return /* @__PURE__ */ jsxs5("div", { className: "flex items-start justify-between gap-3 border-b border-border px-3 py-2.5 last:border-b-0", children: [
789
+ /* @__PURE__ */ jsx6("span", { className: "text-text-secondary shrink-0 text-[10px] font-semibold tracking-wide uppercase", children: label }),
790
+ /* @__PURE__ */ jsx6("div", { className: "min-w-0 text-right text-sm text-text-primary", children })
564
791
  ] });
565
792
  }
566
793
  function TestScheduleScreen({ schedule, agentName, mcpMounts, onEditConfiguration }) {
567
794
  const scheduleServer = useScheduleServer();
568
795
  const toaster = useToasterOptional();
569
796
  const { connectors, ensureLoaded, refreshConnectors, loading, error } = useDraftCatalog();
570
- const [running, setRunning] = useState(false);
571
- const [lastTestRun, setLastTestRun] = useState(null);
797
+ const [running, setRunning] = useState2(false);
798
+ const [lastTestRun, setLastTestRun] = useState2(null);
572
799
  const cadence = formatCadenceSummary({ cron: schedule.cron, timezone: schedule.timezone });
573
800
  const handleRunTest = async () => {
574
801
  setRunning(true);
@@ -582,35 +809,35 @@ function TestScheduleScreen({ schedule, agentName, mcpMounts, onEditConfiguratio
582
809
  setRunning(false);
583
810
  }
584
811
  };
585
- useEffect(() => {
812
+ useEffect2(() => {
586
813
  ensureLoaded();
587
814
  }, [ensureLoaded]);
588
- useEffect(() => {
815
+ useEffect2(() => {
589
816
  if (error != null) toaster?.showError(error);
590
817
  }, [error, toaster]);
591
- return /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-4 px-5 py-4", children: [
592
- /* @__PURE__ */ jsxs4("section", { className: "overflow-hidden rounded-lg border border-border bg-card-bg", children: [
593
- /* @__PURE__ */ jsx5(DetailRow, { label: "Agent", children: agentName }),
594
- /* @__PURE__ */ jsx5(DetailRow, { label: "Name", children: schedule.name }),
595
- /* @__PURE__ */ jsx5(DetailRow, { label: "Task", children: /* @__PURE__ */ jsx5("span", { className: "whitespace-pre-wrap break-words", children: schedule.task }) }),
596
- /* @__PURE__ */ jsx5(DetailRow, { label: "Cadence", children: /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center justify-end gap-1.5", children: [
597
- /* @__PURE__ */ jsx5("span", { children: cadence }),
598
- /* @__PURE__ */ jsx5("code", { className: "text-text-secondary font-mono text-xs", children: schedule.cron })
818
+ return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-4 px-5 py-4", children: [
819
+ /* @__PURE__ */ jsxs5("section", { className: "overflow-hidden rounded-lg border border-border bg-card-bg", children: [
820
+ /* @__PURE__ */ jsx6(DetailRow, { label: "Agent", children: agentName }),
821
+ /* @__PURE__ */ jsx6(DetailRow, { label: "Name", children: schedule.name }),
822
+ /* @__PURE__ */ jsx6(DetailRow, { label: "Status", children: /* @__PURE__ */ jsx6(ScheduleStatusBadge, { status: schedule.status }) }),
823
+ /* @__PURE__ */ jsx6(DetailRow, { label: "Task", children: /* @__PURE__ */ jsx6("span", { className: "whitespace-pre-wrap break-words", children: schedule.task }) }),
824
+ /* @__PURE__ */ jsx6(DetailRow, { label: "Frequency", children: /* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center justify-end gap-1.5", children: [
825
+ /* @__PURE__ */ jsx6("span", { children: cadence }),
826
+ /* @__PURE__ */ jsx6("code", { className: "text-text-secondary font-mono text-xs", children: schedule.cron })
599
827
  ] }) }),
600
- /* @__PURE__ */ jsx5(DetailRow, { label: "Status", children: /* @__PURE__ */ jsx5(ScheduleStatusBadge, { status: schedule.status }) }),
601
- /* @__PURE__ */ jsx5("div", { className: "flex justify-end px-3 py-2.5", children: /* @__PURE__ */ jsxs4(Button, { type: "button", variant: "outline", size: "sm", onClick: onEditConfiguration, children: [
602
- /* @__PURE__ */ jsx5(Icon, { name: "pencil", className: "size-3.5" }),
828
+ /* @__PURE__ */ jsx6("div", { className: "flex justify-end px-3 py-2.5", children: /* @__PURE__ */ jsxs5(Button.Secondary, { type: "button", size: "small", onClick: onEditConfiguration, children: [
829
+ /* @__PURE__ */ jsx6(Icon, { name: "pencil", className: "size-3.5" }),
603
830
  "Edit Configuration"
604
831
  ] }) })
605
832
  ] }),
606
- /* @__PURE__ */ jsxs4("section", { className: "overflow-hidden rounded-lg border border-border bg-card-bg", children: [
607
- /* @__PURE__ */ jsx5("div", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ jsx5("h3", { className: "text-text-secondary text-[10px] font-semibold tracking-wide uppercase", children: "Tool Authorization" }) }),
608
- mcpMounts.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "text-text-secondary px-3 py-3 text-sm", children: "No MCP connectors configured for this agent." }) : /* @__PURE__ */ jsx5("ul", { className: "divide-y divide-border", children: mcpMounts.map((mount) => {
833
+ /* @__PURE__ */ jsxs5("section", { className: "overflow-hidden rounded-lg border border-border bg-card-bg", children: [
834
+ /* @__PURE__ */ jsx6("div", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ jsx6("h3", { className: "text-text-secondary text-[10px] font-semibold tracking-wide uppercase", children: "Tool Authorization" }) }),
835
+ mcpMounts.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "text-text-secondary px-3 py-3 text-sm", children: "No MCP connectors configured for this agent." }) : /* @__PURE__ */ jsx6("ul", { className: "divide-y divide-border", children: mcpMounts.map((mount) => {
609
836
  const connector = mountConnector(connectors, mount.name);
610
837
  const authenticated = connector?.authenticated === true;
611
838
  const unavailable = connector == null && !loading;
612
- return /* @__PURE__ */ jsxs4("li", { className: "flex items-center gap-2 px-3 py-2.5", children: [
613
- /* @__PURE__ */ jsx5(
839
+ return /* @__PURE__ */ jsxs5("li", { className: "flex items-center gap-2 px-3 py-2.5", children: [
840
+ /* @__PURE__ */ jsx6(
614
841
  "span",
615
842
  {
616
843
  className: cn(
@@ -618,36 +845,27 @@ function TestScheduleScreen({ schedule, agentName, mcpMounts, onEditConfiguratio
618
845
  authenticated ? "border-emerald-600/40 bg-emerald-500/15 text-emerald-700 dark:text-emerald-300" : "border-border text-transparent"
619
846
  ),
620
847
  "aria-hidden": true,
621
- children: authenticated ? /* @__PURE__ */ jsx5(Icon, { name: "check", className: "size-3" }) : null
848
+ children: authenticated ? /* @__PURE__ */ jsx6(Icon, { name: "check", className: "size-3" }) : null
622
849
  }
623
850
  ),
624
- /* @__PURE__ */ jsx5("span", { className: "text-text-primary min-w-0 flex-1 truncate text-sm", children: mount.name }),
625
- authenticated ? /* @__PURE__ */ jsx5("span", { className: "text-success-bg text-xs font-medium", children: "Connected" }) : unavailable ? /* @__PURE__ */ jsx5("span", { className: "text-text-secondary text-xs", children: "Unavailable" }) : connector != null && connector.authenticated === false ? /* @__PURE__ */ jsx5(ScheduleMcpConnect, { connector, onConnected: refreshConnectors }) : loading ? /* @__PURE__ */ jsx5("span", { className: "text-text-secondary text-xs", children: "Loading\u2026" }) : null
851
+ /* @__PURE__ */ jsx6("span", { className: "text-text-primary min-w-0 flex-1 truncate text-sm", children: mount.name }),
852
+ authenticated ? /* @__PURE__ */ jsx6("span", { className: "text-success-bg text-xs font-medium", children: "Connected" }) : unavailable ? /* @__PURE__ */ jsx6("span", { className: "text-text-secondary text-xs", children: "Unavailable" }) : connector != null && connector.authenticated === false ? /* @__PURE__ */ jsx6(ScheduleMcpConnect, { connector, onConnected: refreshConnectors }) : loading ? /* @__PURE__ */ jsx6("span", { className: "text-text-secondary text-xs", children: "Loading\u2026" }) : null
626
853
  ] }, mount.name);
627
854
  }) })
628
855
  ] }),
629
- /* @__PURE__ */ jsxs4("section", { className: "overflow-hidden rounded-lg border border-border bg-card-bg", children: [
630
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between gap-2 border-b border-border px-3 py-2", children: [
631
- /* @__PURE__ */ jsx5("h3", { className: "text-text-secondary text-[10px] font-semibold tracking-wide uppercase", children: "Test Run" }),
632
- /* @__PURE__ */ jsxs4(
633
- "button",
634
- {
635
- type: "button",
636
- disabled: running,
637
- onClick: () => void handleRunTest(),
638
- className: auiButtonClass({ variant: "default", size: "sm" }),
639
- children: [
640
- /* @__PURE__ */ jsx5(Icon, { name: running ? "loader" : "play", className: cn("size-3.5", running && "animate-spin") }),
641
- "Run Test"
642
- ]
643
- }
644
- )
856
+ /* @__PURE__ */ jsxs5("section", { className: "overflow-hidden rounded-lg border border-border bg-card-bg", children: [
857
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between gap-2 border-b border-border px-3 py-2", children: [
858
+ /* @__PURE__ */ jsx6("h3", { className: "text-text-secondary text-[10px] font-semibold tracking-wide uppercase", children: "Test Run" }),
859
+ /* @__PURE__ */ jsxs5(Button.Primary, { type: "button", disabled: running, size: "small", onClick: () => void handleRunTest(), children: [
860
+ /* @__PURE__ */ jsx6(Icon, { name: running ? "loader" : "play", className: cn("size-3.5", running && "animate-spin") }),
861
+ "Run Test"
862
+ ] })
645
863
  ] }),
646
- lastTestRun == null ? /* @__PURE__ */ jsx5("p", { className: "text-text-secondary px-3 py-3 text-sm", children: "Run a one-off test using the schedule task. This does not change the cron pending run." }) : /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-3 px-3 py-3", children: [
647
- /* @__PURE__ */ jsx5(ScheduleRunChip, { run: lastTestRun }),
648
- /* @__PURE__ */ jsxs4("div", { className: "min-w-0 text-sm", children: [
649
- /* @__PURE__ */ jsx5("p", { className: "text-text-primary font-medium", children: runTypeLabel(lastTestRun.name) }),
650
- /* @__PURE__ */ jsx5("p", { className: "text-text-secondary", children: formatRelativeTime(lastTestRun.triggeredAt ?? lastTestRun.scheduledFor) })
864
+ lastTestRun == null ? /* @__PURE__ */ jsx6("p", { className: "text-text-secondary px-3 py-3 text-sm", children: "Run a one-off test using the schedule task. This does not change the cron pending run." }) : /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3 px-3 py-3", children: [
865
+ /* @__PURE__ */ jsx6(ScheduleRunChip, { run: lastTestRun }),
866
+ /* @__PURE__ */ jsxs5("div", { className: "min-w-0 text-sm", children: [
867
+ /* @__PURE__ */ jsx6("p", { className: "text-text-primary font-medium", children: runTypeLabel(lastTestRun.name) }),
868
+ /* @__PURE__ */ jsx6("p", { className: "text-text-secondary", children: formatRelativeTime(lastTestRun.triggeredAt ?? lastTestRun.scheduledFor) })
651
869
  ] })
652
870
  ] })
653
871
  ] })
@@ -655,7 +873,7 @@ function TestScheduleScreen({ schedule, agentName, mcpMounts, onEditConfiguratio
655
873
  }
656
874
 
657
875
  // src/atoms/schedules/ScheduleFormDrawer.tsx
658
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
876
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
659
877
  function ScheduleFormDrawerBody({
660
878
  open,
661
879
  onOpenChange,
@@ -666,32 +884,30 @@ function ScheduleFormDrawerBody({
666
884
  }) {
667
885
  const scheduleServer = useScheduleServer();
668
886
  const server = useServer();
887
+ const shell = useOptionalShellMode();
669
888
  const toaster = useToasterOptional();
670
- const [form, setForm] = useState2(defaultScheduleFormValues);
671
- const [agentId, setAgentId] = useState2(initialAgentId);
672
- const [agents, setAgents] = useState2([]);
673
- const [view, setView] = useState2({ kind: "form" });
674
- const [saving, setSaving] = useState2(false);
675
- const [activating, setActivating] = useState2(false);
676
- const [error, setError] = useState2(null);
889
+ const [form, setForm] = useState3(defaultScheduleFormValues);
890
+ const [agentId, setAgentId] = useState3(initialAgentId);
891
+ const [selectedAgent, setSelectedAgent] = useState3(null);
892
+ const [view, setView] = useState3({ kind: "form" });
893
+ const [saving, setSaving] = useState3(false);
894
+ const [activating, setActivating] = useState3(false);
895
+ const [error, setError] = useState3(null);
896
+ const agentIdRef = useRef2(agentId);
897
+ agentIdRef.current = agentId;
677
898
  const savedFromCreate = view.kind === "form" ? view.saved : view.schedule;
678
899
  const isExternalEdit = mode === "edit" && view.kind === "form" && view.saved == null && schedule != null;
679
900
  const isCreatedEdit = view.kind === "form" && view.saved != null;
680
- useEffect2(() => {
681
- if (!open) return;
682
- let cancelled = false;
683
- void searchAllAgents(server).then((rows) => {
684
- if (cancelled) return;
685
- setAgents(rows);
686
- }).catch(() => void 0);
687
- return () => {
688
- cancelled = true;
689
- };
690
- }, [open, server]);
691
- useEffect2(() => {
901
+ const isInitialCreate = mode === "create" && view.kind === "form" && view.saved == null;
902
+ const { allows: allowsAgent } = useResourcePermissions({
903
+ resourceType: "agent",
904
+ resourceIds: agentId.length === 0 ? [] : [agentId]
905
+ });
906
+ useEffect3(() => {
692
907
  if (!open) {
693
908
  setForm(defaultScheduleFormValues());
694
909
  setAgentId(initialAgentId);
910
+ setSelectedAgent(null);
695
911
  setError(null);
696
912
  setView({ kind: "form" });
697
913
  setActivating(false);
@@ -707,30 +923,38 @@ function ScheduleFormDrawerBody({
707
923
  })
708
924
  );
709
925
  setAgentId(schedule.agentId);
926
+ setSelectedAgent(null);
710
927
  setView({ kind: "form" });
711
928
  return;
712
929
  }
713
930
  setForm(defaultScheduleFormValues());
714
931
  setAgentId(initialAgentId);
932
+ setSelectedAgent(null);
715
933
  setView({ kind: "form" });
716
934
  }, [open, mode, schedule, initialAgentId]);
717
- const agentOptions = useMemo(
718
- () => agents.map((agent) => ({ agentId: libraryAgentId(agent), name: agent.name })),
719
- [agents]
720
- );
721
- const selectedAgent = useMemo(
722
- () => agents.find((agent) => libraryAgentId(agent) === agentId) ?? null,
723
- [agents, agentId]
724
- );
725
- const agentLabel = selectedAgent?.name ?? savedFromCreate?.agentName ?? schedule?.agentName ?? agentOptions.find((option) => option.agentId === agentId)?.name ?? agentId;
935
+ useEffect3(() => {
936
+ if (!open || mode !== "create" || initialAgentId.length === 0) return;
937
+ let cancelled = false;
938
+ const requestedId = initialAgentId;
939
+ void findLibraryAgent({ server, agentKey: requestedId }).then((agent) => {
940
+ if (cancelled || agent == null) return;
941
+ if (agentIdRef.current !== requestedId) return;
942
+ setSelectedAgent(agent);
943
+ setAgentId(libraryAgentId(agent));
944
+ }).catch(() => void 0);
945
+ return () => {
946
+ cancelled = true;
947
+ };
948
+ }, [open, mode, initialAgentId, server]);
949
+ const agentLabel = selectedAgent?.name ?? savedFromCreate?.agentName ?? schedule?.agentName ?? (agentId.length > 0 ? agentId : "");
726
950
  const mcpMounts = useMemo(() => {
727
951
  const mounts = selectedAgent?.agentSpec?.mcpServers ?? [];
728
952
  return mounts.map(mountName).filter((name) => name != null).map((name) => ({ name }));
729
953
  }, [selectedAgent]);
730
954
  const canSubmit = useMemo(() => {
731
955
  const cron = valuesToCron(form);
732
- return form.name.trim().length > 0 && form.task.trim().length > 0 && cron.length > 0 && agentId.length > 0;
733
- }, [form, agentId]);
956
+ return form.name.trim().length > 0 && form.task.trim().length > 0 && cron.length > 0 && agentId.length > 0 && (!isInitialCreate || allowsAgent(agentId, "USE"));
957
+ }, [agentId, allowsAgent, form, isInitialCreate]);
734
958
  const enterTestView = (saved) => {
735
959
  setView({ kind: "test", schedule: saved });
736
960
  setForm(
@@ -829,30 +1053,20 @@ function ScheduleFormDrawerBody({
829
1053
  const description = view.kind === "test" ? `Recurring unattended runs of ${agentLabel}.` : isExternalEdit || isCreatedEdit ? "Update cadence and task for this schedule." : "Create a recurring unattended run for an agent.";
830
1054
  let footer;
831
1055
  if (view.kind === "test") {
832
- footer = /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
833
- error != null ? /* @__PURE__ */ jsx6("p", { className: "text-failure-bg text-sm", children: error }) : null,
834
- /* @__PURE__ */ jsx6(
835
- Button,
836
- {
837
- type: "button",
838
- variant: "secondary",
839
- className: "w-full",
840
- disabled: activating,
841
- onClick: () => void handleActivate(),
842
- children: "Activate Anyway"
843
- }
844
- )
1056
+ footer = /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-2", children: [
1057
+ error != null ? /* @__PURE__ */ jsx7("p", { className: "text-failure-bg text-sm", children: error }) : null,
1058
+ /* @__PURE__ */ jsx7(Button.Secondary, { type: "button", className: "w-full", disabled: activating, onClick: () => void handleActivate(), children: "Activate Schedule" })
845
1059
  ] });
846
1060
  } else {
847
- footer = /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
848
- error != null ? /* @__PURE__ */ jsx6("p", { className: "text-failure-bg text-sm", children: error }) : null,
849
- /* @__PURE__ */ jsxs5("div", { className: "flex justify-end gap-2", children: [
850
- /* @__PURE__ */ jsx6(Button, { type: "button", variant: "outline", onClick: () => onOpenChange(false), disabled: saving, children: "Cancel" }),
851
- /* @__PURE__ */ jsx6(Button, { type: "submit", form: "schedule-form", disabled: !canSubmit || saving, children: "Save" })
1061
+ footer = /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-2", children: [
1062
+ error != null ? /* @__PURE__ */ jsx7("p", { className: "text-failure-bg text-sm", children: error }) : null,
1063
+ /* @__PURE__ */ jsxs6("div", { className: "flex justify-end gap-2", children: [
1064
+ /* @__PURE__ */ jsx7(Button.Secondary, { type: "button", onClick: () => onOpenChange(false), disabled: saving, children: "Cancel" }),
1065
+ /* @__PURE__ */ jsx7(Button.Primary, { type: "submit", form: "schedule-form", disabled: !canSubmit || saving, children: "Save" })
852
1066
  ] })
853
1067
  ] });
854
1068
  }
855
- return /* @__PURE__ */ jsx6(
1069
+ return /* @__PURE__ */ jsx7(
856
1070
  SideDrawer,
857
1071
  {
858
1072
  open,
@@ -860,8 +1074,8 @@ function ScheduleFormDrawerBody({
860
1074
  title,
861
1075
  description,
862
1076
  anchor: "right",
863
- size: "lg",
864
- headerIcon: /* @__PURE__ */ jsx6("span", { className: "text-primary-button-bg inline-flex size-8 items-center justify-center", children: /* @__PURE__ */ jsx6(
1077
+ size: "xl",
1078
+ headerIcon: /* @__PURE__ */ jsx7("span", { className: "text-primary-button-bg inline-flex size-8 items-center justify-center", children: /* @__PURE__ */ jsx7(
865
1079
  Icon,
866
1080
  {
867
1081
  name: view.kind === "test" || isExternalEdit || isCreatedEdit ? "calendar" : "calendar-plus",
@@ -869,7 +1083,7 @@ function ScheduleFormDrawerBody({
869
1083
  }
870
1084
  ) }),
871
1085
  footer,
872
- children: view.kind === "test" ? /* @__PURE__ */ jsx6(
1086
+ children: view.kind === "test" ? /* @__PURE__ */ jsx7(
873
1087
  TestScheduleScreen,
874
1088
  {
875
1089
  schedule: view.schedule,
@@ -880,36 +1094,44 @@ function ScheduleFormDrawerBody({
880
1094
  setView({ kind: "form", saved: view.schedule });
881
1095
  }
882
1096
  }
883
- ) : /* @__PURE__ */ jsx6("form", { id: "schedule-form", onSubmit: (event) => void handleSave(event), children: /* @__PURE__ */ jsx6(
1097
+ ) : /* @__PURE__ */ jsx7("form", { id: "schedule-form", onSubmit: (event) => void handleSave(event), children: /* @__PURE__ */ jsx7(
884
1098
  ScheduleFormFields,
885
1099
  {
886
1100
  values: form,
887
1101
  onChange: setForm,
888
1102
  agentId,
889
- onAgentIdChange: isExternalEdit || isCreatedEdit ? void 0 : setAgentId,
890
- agentOptions,
891
- agentPickerDisabled: isExternalEdit || isCreatedEdit
1103
+ agentLabel,
1104
+ onAgentIdChange: isExternalEdit || isCreatedEdit ? void 0 : (nextId) => {
1105
+ setAgentId(nextId);
1106
+ if (nextId.length === 0) setSelectedAgent(null);
1107
+ },
1108
+ onAgentPicked: setSelectedAgent,
1109
+ agentPickerDisabled: isExternalEdit || isCreatedEdit,
1110
+ onBuildAgent: mode === "create" && shell?.isComposerEnabled === true ? () => {
1111
+ onOpenChange(false);
1112
+ shell.openAgentBuilder();
1113
+ } : void 0
892
1114
  }
893
1115
  ) })
894
1116
  }
895
1117
  );
896
1118
  }
897
1119
  function ScheduleFormDrawer(props) {
898
- return /* @__PURE__ */ jsx6(DraftCatalogProvider, { children: /* @__PURE__ */ jsx6(ScheduleFormDrawerBody, { ...props }) });
1120
+ return /* @__PURE__ */ jsx7(DraftCatalogProvider, { children: /* @__PURE__ */ jsx7(ScheduleFormDrawerBody, { ...props }) });
899
1121
  }
900
1122
 
901
1123
  // src/atoms/schedules/ScheduleLastRunsCell.tsx
902
- import { jsx as jsx7 } from "react/jsx-runtime";
1124
+ import { jsx as jsx8 } from "react/jsx-runtime";
903
1125
  function ScheduleLastRunsCell({ runs }) {
904
1126
  const history = lastHistoricalRuns(runs);
905
1127
  if (history.length === 0) {
906
- return /* @__PURE__ */ jsx7("span", { className: "text-text-secondary text-sm", children: "\u2014" });
1128
+ return /* @__PURE__ */ jsx8("span", { className: "text-text-secondary text-sm", children: "\u2014" });
907
1129
  }
908
- return /* @__PURE__ */ jsx7("div", { className: "flex items-center gap-1", children: history.map((run) => /* @__PURE__ */ jsx7(ScheduleRunChip, { run }, run.id)) });
1130
+ return /* @__PURE__ */ jsx8("div", { className: "flex items-center gap-1", children: history.map((run) => /* @__PURE__ */ jsx8(ScheduleRunChip, { run }, run.id)) });
909
1131
  }
910
1132
 
911
1133
  // src/atoms/schedules/SchedulesPage.tsx
912
- import { Fragment, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1134
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
913
1135
  var STATUS_FILTER_OPTIONS = [
914
1136
  { value: "all", label: "All statuses" },
915
1137
  { value: "active", label: "Active" },
@@ -927,84 +1149,108 @@ function filtersFromSearch(search) {
927
1149
  agentFilter: share.agent ?? "all"
928
1150
  };
929
1151
  }
1152
+ function initialDrawerState(agentId) {
1153
+ const share = readScheduleShareSearch(window.location.search);
1154
+ if (!share.isNew) return { kind: "closed" };
1155
+ const initialAgentId = agentId ?? share.agent;
1156
+ return {
1157
+ kind: "create",
1158
+ ...initialAgentId == null ? {} : { agentId: initialAgentId }
1159
+ };
1160
+ }
930
1161
  function ScheduleRowActions({
931
1162
  schedule,
932
1163
  running,
1164
+ canManage,
1165
+ canDelete,
933
1166
  onRunNow,
934
1167
  onEdit,
935
1168
  onTogglePause,
936
1169
  onDelete
937
1170
  }) {
938
- return /* @__PURE__ */ jsxs6("div", { className: "inline-flex items-center justify-end gap-1.5", children: [
939
- /* @__PURE__ */ jsxs6(
940
- "button",
1171
+ const PermissionGuard = useSlot("PermissionGuard");
1172
+ return /* @__PURE__ */ jsxs7("div", { className: "inline-flex items-center justify-end gap-1.5", children: [
1173
+ /* @__PURE__ */ jsx9(PermissionGuard, { allowed: canManage, children: /* @__PURE__ */ jsxs7(
1174
+ Button.Secondary,
941
1175
  {
942
1176
  type: "button",
943
1177
  disabled: running,
944
1178
  "aria-label": `Run now ${schedule.name}`,
945
- className: auiButtonClass({ variant: "outline", size: "sm" }),
1179
+ size: "large",
946
1180
  onClick: onRunNow,
947
1181
  children: [
948
- /* @__PURE__ */ jsx8(Icon, { name: running ? "loader" : "play", className: cn("size-3.5", running && "animate-spin") }),
1182
+ /* @__PURE__ */ jsx9(Icon, { name: running ? "loader" : "play", className: cn("size-3.5", running && "animate-spin") }),
949
1183
  "Run now"
950
1184
  ]
951
1185
  }
952
- ),
953
- /* @__PURE__ */ jsxs6(
1186
+ ) }),
1187
+ /* @__PURE__ */ jsxs7(
954
1188
  DropdownMenu,
955
1189
  {
956
1190
  align: "end",
957
- trigger: /* @__PURE__ */ jsx8(
1191
+ trigger: /* @__PURE__ */ jsx9(
958
1192
  "button",
959
1193
  {
960
1194
  type: "button",
961
1195
  className: auiButtonClass({ variant: "ghost", size: "icon" }),
962
1196
  "aria-label": `Actions for ${schedule.name}`,
963
- children: /* @__PURE__ */ jsx8(Icon, { name: "ellipsis", className: "size-4" })
1197
+ children: /* @__PURE__ */ jsx9(Icon, { name: "ellipsis" })
964
1198
  }
965
1199
  ),
966
1200
  children: [
967
- /* @__PURE__ */ jsxs6(DropdownMenuItem, { onClick: onEdit, children: [
968
- /* @__PURE__ */ jsx8(Icon, { name: "pencil", className: "size-3.5" }),
1201
+ /* @__PURE__ */ jsx9(PermissionGuard, { allowed: canManage, children: /* @__PURE__ */ jsxs7(DropdownMenuItem, { onClick: onEdit, children: [
1202
+ /* @__PURE__ */ jsx9(Icon, { name: "pencil", className: "size-3.5" }),
969
1203
  "Edit"
970
- ] }),
971
- /* @__PURE__ */ jsxs6(DropdownMenuItem, { onClick: onTogglePause, children: [
972
- /* @__PURE__ */ jsx8(Icon, { name: schedule.status === "active" ? "pause" : "play", className: "size-3.5" }),
1204
+ ] }) }),
1205
+ /* @__PURE__ */ jsx9(PermissionGuard, { allowed: canManage, children: /* @__PURE__ */ jsxs7(DropdownMenuItem, { onClick: onTogglePause, children: [
1206
+ /* @__PURE__ */ jsx9(Icon, { name: schedule.status === "active" ? "pause" : "play", className: "size-3.5" }),
973
1207
  schedule.status === "active" ? "Pause" : "Resume"
974
- ] }),
975
- /* @__PURE__ */ jsxs6(DropdownMenuItem, { className: "text-failure-bg focus:text-failure-bg", onClick: onDelete, children: [
976
- /* @__PURE__ */ jsx8(Icon, { name: "trash", className: "size-3.5" }),
1208
+ ] }) }),
1209
+ /* @__PURE__ */ jsx9(PermissionGuard, { allowed: canDelete, children: /* @__PURE__ */ jsxs7(DropdownMenuItem, { className: "text-failure-bg focus:text-failure-bg", onClick: onDelete, children: [
1210
+ /* @__PURE__ */ jsx9(Icon, { name: "trash", className: "size-3.5" }),
977
1211
  "Delete"
978
- ] })
1212
+ ] }) })
979
1213
  ]
980
1214
  }
981
1215
  )
982
1216
  ] });
983
1217
  }
984
- function SchedulesPage() {
1218
+ function SchedulesPage({ agentId }) {
985
1219
  const scheduleServer = useScheduleServer();
986
1220
  const server = useServer();
987
1221
  const toaster = useToasterOptional();
988
- const [schedules, setSchedules] = useState3([]);
989
- const [runsByScheduleId, setRunsByScheduleId] = useState3({});
990
- const [runsLoading, setRunsLoading] = useState3(false);
991
- const [runningScheduleIds, setRunningScheduleIds] = useState3(() => /* @__PURE__ */ new Set());
992
- const [agentOptions, setAgentOptions] = useState3([]);
993
- const [loading, setLoading] = useState3(true);
994
- const [error, setError] = useState3(null);
995
- const [nameQuery, setNameQuery] = useState3(() => filtersFromSearch(window.location.search).nameQuery);
996
- const [statusFilter, setStatusFilter] = useState3(
1222
+ const [schedules, setSchedules] = useState4([]);
1223
+ const { allows } = useResourcePermissions({
1224
+ resourceType: "schedule",
1225
+ resourceIds: schedules.map((schedule) => schedule.id)
1226
+ });
1227
+ const [runsByScheduleId, setRunsByScheduleId] = useState4({});
1228
+ const [runsLoading, setRunsLoading] = useState4(false);
1229
+ const [runningScheduleIds, setRunningScheduleIds] = useState4(() => /* @__PURE__ */ new Set());
1230
+ const [agentLabelById, setAgentLabelById] = useState4({});
1231
+ const [loading, setLoading] = useState4(true);
1232
+ const [error, setError] = useState4(null);
1233
+ const [nameQuery, setNameQuery] = useState4(() => filtersFromSearch(window.location.search).nameQuery);
1234
+ const [statusFilter, setStatusFilter] = useState4(
997
1235
  () => filtersFromSearch(window.location.search).statusFilter
998
1236
  );
999
- const [agentFilter, setAgentFilter] = useState3(() => filtersFromSearch(window.location.search).agentFilter);
1000
- const [drawer, setDrawer] = useState3({ kind: "closed" });
1001
- const [pendingDelete, setPendingDelete] = useState3(null);
1002
- const [pageSize, setPageSize] = useState3(() => clampPageSize(DEFAULT_TABLE_PAGE_SIZE));
1003
- const [pageToken, setPageToken] = useState3(void 0);
1004
- const [nextPageToken, setNextPageToken] = useState3(void 0);
1005
- const [prevTokenStack, setPrevTokenStack] = useState3([]);
1006
- const loadGenRef = useRef(0);
1007
- const didConsumeIsNewRef = useRef(false);
1237
+ const [agentFilter, setAgentFilter] = useState4(
1238
+ () => agentId ?? filtersFromSearch(window.location.search).agentFilter
1239
+ );
1240
+ const permissionAgentId = agentId ?? (agentFilter === "all" ? null : agentFilter);
1241
+ const { allows: allowsAgent } = useResourcePermissions({
1242
+ resourceType: "agent",
1243
+ resourceIds: permissionAgentId == null ? [] : [permissionAgentId]
1244
+ });
1245
+ const canCreateSchedule = server.permissions == null || permissionAgentId == null || allowsAgent(permissionAgentId, "USE");
1246
+ const [drawer, setDrawer] = useState4(() => initialDrawerState(agentId));
1247
+ const [pendingDelete, setPendingDelete] = useState4(null);
1248
+ const [pageSize, setPageSize] = useState4(() => clampPageSize(DEFAULT_TABLE_PAGE_SIZE));
1249
+ const [pageToken, setPageToken] = useState4(void 0);
1250
+ const [nextPageToken, setNextPageToken] = useState4(void 0);
1251
+ const [prevTokenStack, setPrevTokenStack] = useState4([]);
1252
+ const loadGenRef = useRef3(0);
1253
+ const didConsumeIsNewRef = useRef3(false);
1008
1254
  const loadRunsForSchedules = useCallback(
1009
1255
  async ({ rows, gen }) => {
1010
1256
  if (rows.length === 0) {
@@ -1033,7 +1279,7 @@ function SchedulesPage() {
1033
1279
  [scheduleServer]
1034
1280
  );
1035
1281
  const loadSchedules = useCallback(
1036
- async ({ token, size, agentId }) => {
1282
+ async ({ token, size, agentId: agentId2 }) => {
1037
1283
  const gen = ++loadGenRef.current;
1038
1284
  setLoading(true);
1039
1285
  setError(null);
@@ -1041,7 +1287,7 @@ function SchedulesPage() {
1041
1287
  const page = await scheduleServer.listSchedules({
1042
1288
  limit: clampPageSize(size),
1043
1289
  ...token === void 0 || token === "" ? {} : { pageToken: token },
1044
- ...agentId === "all" ? {} : { agentIds: [agentId] }
1290
+ ...agentId2 === "all" ? {} : { agentIds: [agentId2] }
1045
1291
  });
1046
1292
  if (gen !== loadGenRef.current) return;
1047
1293
  setSchedules(page.data);
@@ -1063,68 +1309,57 @@ function SchedulesPage() {
1063
1309
  const resetToFirstPage = useCallback(
1064
1310
  (next) => {
1065
1311
  const size = next?.size ?? pageSize;
1066
- const agentId = next?.agentId ?? agentFilter;
1312
+ const agentId2 = next?.agentId ?? agentFilter;
1067
1313
  setPageToken(void 0);
1068
1314
  setPrevTokenStack([]);
1069
- void loadSchedules({ token: void 0, size, agentId });
1315
+ void loadSchedules({ token: void 0, size, agentId: agentId2 });
1070
1316
  },
1071
1317
  [agentFilter, loadSchedules, pageSize]
1072
1318
  );
1073
- useEffect3(() => {
1319
+ useEffect4(() => {
1074
1320
  replaceScheduleShareSearch({
1075
- agent: agentFilter === "all" ? null : agentFilter,
1321
+ agent: agentId === void 0 && agentFilter !== "all" ? agentFilter : null,
1076
1322
  status: statusFilter === "all" ? null : statusFilter,
1077
1323
  q: nameQuery.trim().length === 0 ? null : nameQuery
1078
1324
  });
1079
- }, [agentFilter, statusFilter, nameQuery]);
1080
- useEffect3(() => {
1325
+ }, [agentFilter, agentId, statusFilter, nameQuery]);
1326
+ useEffect4(() => {
1327
+ if (agentId === void 0) return;
1328
+ setAgentFilter((current) => {
1329
+ if (current === agentId) return current;
1330
+ setPageToken(void 0);
1331
+ setPrevTokenStack([]);
1332
+ return agentId;
1333
+ });
1334
+ }, [agentId]);
1335
+ useEffect4(() => {
1081
1336
  if (didConsumeIsNewRef.current) return;
1082
1337
  const share = readScheduleShareSearch(window.location.search);
1083
1338
  if (!share.isNew) return;
1084
1339
  didConsumeIsNewRef.current = true;
1085
- setDrawer({
1086
- kind: "create",
1087
- ...share.agent != null ? { agentId: share.agent } : {}
1088
- });
1089
1340
  replaceScheduleShareSearch({ isNew: null });
1090
1341
  }, []);
1091
- useEffect3(() => {
1342
+ useEffect4(() => {
1092
1343
  const syncFromUrl = () => {
1093
1344
  const next = filtersFromSearch(window.location.search);
1094
1345
  setNameQuery(next.nameQuery);
1095
1346
  setStatusFilter(next.statusFilter);
1096
1347
  setAgentFilter((current) => {
1097
- if (current === next.agentFilter) return current;
1348
+ const nextAgentFilter = agentId ?? next.agentFilter;
1349
+ if (current === nextAgentFilter) return current;
1098
1350
  setPageToken(void 0);
1099
1351
  setPrevTokenStack([]);
1100
- return next.agentFilter;
1352
+ return nextAgentFilter;
1101
1353
  });
1102
1354
  };
1103
1355
  window.addEventListener("popstate", syncFromUrl);
1104
1356
  return () => {
1105
1357
  window.removeEventListener("popstate", syncFromUrl);
1106
1358
  };
1107
- }, []);
1108
- useEffect3(() => {
1359
+ }, [agentId]);
1360
+ useEffect4(() => {
1109
1361
  void loadSchedules({ token: pageToken, size: pageSize, agentId: agentFilter });
1110
1362
  }, [agentFilter, pageSize, pageToken, loadSchedules]);
1111
- useEffect3(() => {
1112
- let cancelled = false;
1113
- void searchAllAgents(server).then((rows) => {
1114
- if (cancelled) return;
1115
- setAgentOptions(rows.map((agent) => ({ agentId: libraryAgentId(agent), name: agent.name })));
1116
- }).catch(() => void 0);
1117
- return () => {
1118
- cancelled = true;
1119
- };
1120
- }, [server]);
1121
- const agentNameById = useMemo2(() => {
1122
- const map = /* @__PURE__ */ new Map();
1123
- for (const agent of agentOptions) {
1124
- map.set(agent.agentId, agent.name);
1125
- }
1126
- return map;
1127
- }, [agentOptions]);
1128
1363
  const filtered = useMemo2(() => {
1129
1364
  const q = nameQuery.trim().toLowerCase();
1130
1365
  return schedules.filter((schedule) => {
@@ -1133,8 +1368,10 @@ function SchedulesPage() {
1133
1368
  return true;
1134
1369
  });
1135
1370
  }, [schedules, nameQuery, statusFilter]);
1371
+ const showCreatedByColumn = hasCreatedBySubject(schedules);
1136
1372
  const hasPageNav = prevTokenStack.length > 0 || nextPageToken != null;
1137
1373
  const handleTogglePause = async (schedule) => {
1374
+ if (!allows(schedule.id, "MANAGE")) return;
1138
1375
  const nextStatus = schedule.status === "active" ? "paused" : "active";
1139
1376
  try {
1140
1377
  await scheduleServer.updateSchedule({ ...schedule, status: nextStatus });
@@ -1144,6 +1381,7 @@ function SchedulesPage() {
1144
1381
  }
1145
1382
  };
1146
1383
  const handleRunNow = async (schedule) => {
1384
+ if (!allows(schedule.id, "MANAGE")) return;
1147
1385
  setRunningScheduleIds((prev) => new Set(prev).add(schedule.id));
1148
1386
  try {
1149
1387
  await scheduleServer.createScheduleRun({ scheduleId: schedule.id });
@@ -1161,6 +1399,7 @@ function SchedulesPage() {
1161
1399
  }
1162
1400
  };
1163
1401
  const handleDelete = async (schedule) => {
1402
+ if (!allows(schedule.id, "DELETE")) return;
1164
1403
  setPendingDelete(null);
1165
1404
  try {
1166
1405
  await scheduleServer.deleteSchedule({ id: schedule.id });
@@ -1181,14 +1420,14 @@ function SchedulesPage() {
1181
1420
  setPrevTokenStack(stack);
1182
1421
  setPageToken(prev === "" ? void 0 : prev);
1183
1422
  };
1184
- return /* @__PURE__ */ jsxs6("div", { className: "flex h-full min-h-0 flex-col bg-primary-bg", children: [
1185
- /* @__PURE__ */ jsx8(
1423
+ return /* @__PURE__ */ jsxs7("div", { className: "flex h-full min-h-0 flex-col bg-primary-bg", children: [
1424
+ /* @__PURE__ */ jsx9(
1186
1425
  PageHeader,
1187
1426
  {
1188
- title: "Scheduled Agents",
1189
- end: /* @__PURE__ */ jsxs6(Fragment, { children: [
1190
- /* @__PURE__ */ jsx8("div", { className: "w-full sm:w-56", children: /* @__PURE__ */ jsx8(SearchInput_default, { query: nameQuery, setQuery: setNameQuery, placeholder: "Search schedules by name" }) }),
1191
- /* @__PURE__ */ jsx8(
1427
+ title: agentId === void 0 ? "Scheduled Agents" : void 0,
1428
+ end: /* @__PURE__ */ jsxs7(Fragment2, { children: [
1429
+ /* @__PURE__ */ jsx9("div", { className: "w-full sm:w-60", children: /* @__PURE__ */ jsx9(SearchInput_default, { query: nameQuery, setQuery: setNameQuery, placeholder: "Search schedules by name" }) }),
1430
+ /* @__PURE__ */ jsx9(
1192
1431
  PopoverSelect,
1193
1432
  {
1194
1433
  value: statusFilter,
@@ -1198,33 +1437,39 @@ function SchedulesPage() {
1198
1437
  "aria-label": "Filter by status"
1199
1438
  }
1200
1439
  ),
1201
- /* @__PURE__ */ jsx8(
1202
- PopoverSelect,
1440
+ agentId === void 0 ? /* @__PURE__ */ jsx9(
1441
+ AgentSearchPicker,
1203
1442
  {
1204
1443
  value: agentFilter,
1444
+ selectedLabel: agentFilter === "all" ? "All agents" : agentLabelById[agentFilter] ?? agentFilter,
1205
1445
  onValueChange: (value) => {
1206
1446
  setAgentFilter(value);
1207
1447
  setPageToken(void 0);
1208
1448
  setPrevTokenStack([]);
1209
1449
  },
1210
- options: [
1211
- { value: "all", label: "All agents" },
1212
- ...agentOptions.map((agent) => ({ value: agent.agentId, label: agent.name }))
1213
- ],
1214
- className: "sm:w-40",
1215
- "aria-label": "Filter by agent"
1450
+ onAgentPicked: (agent) => {
1451
+ setAgentLabelById((current) => ({
1452
+ ...current,
1453
+ [libraryAgentId(agent)]: agent.name
1454
+ }));
1455
+ },
1456
+ allOption: { value: "all", label: "All agents" },
1457
+ className: "sm:w-48",
1458
+ "aria-label": "Filter by agent",
1459
+ placeholder: "Search agent"
1216
1460
  }
1217
- ),
1218
- /* @__PURE__ */ jsxs6(
1219
- Button,
1461
+ ) : null,
1462
+ /* @__PURE__ */ jsxs7(
1463
+ Button.Primary,
1220
1464
  {
1221
1465
  type: "button",
1222
- onClick: () => setDrawer({
1466
+ disabled: !canCreateSchedule,
1467
+ onClick: () => canCreateSchedule && setDrawer({
1223
1468
  kind: "create",
1224
1469
  agentId: agentFilter !== "all" ? agentFilter : void 0
1225
1470
  }),
1226
1471
  children: [
1227
- /* @__PURE__ */ jsx8(Icon, { name: "plus", className: "size-3.5" }),
1472
+ /* @__PURE__ */ jsx9(Icon, { name: "plus", className: "size-3.5" }),
1228
1473
  "Create Schedule"
1229
1474
  ]
1230
1475
  }
@@ -1232,9 +1477,9 @@ function SchedulesPage() {
1232
1477
  ] })
1233
1478
  }
1234
1479
  ),
1235
- /* @__PURE__ */ jsx8("div", { className: "min-h-0 flex-1 overflow-auto px-4 py-4 md:px-6", children: loading ? /* @__PURE__ */ jsx8("div", { className: "flex flex-col gap-2", role: "status", "aria-label": "Loading schedules", children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx8(Skeleton, { className: "h-12 w-full rounded-md" }, i)) }) : error != null ? /* @__PURE__ */ jsx8("p", { className: "text-failure-bg px-3 py-8 text-center text-sm", children: error }) : schedules.length === 0 ? /* @__PURE__ */ jsx8(EmptyScreen, { title: "No Schedules Found", description: "Create one to get started.", className: "min-h-full" }) : filtered.length === 0 ? /* @__PURE__ */ jsxs6("div", { className: "flex min-h-full flex-col", children: [
1236
- /* @__PURE__ */ jsx8(EmptyScreen, { title: "No Schedules Found", description: "No schedules match your filters.", className: "flex-1" }),
1237
- hasPageNav ? /* @__PURE__ */ jsx8(
1480
+ /* @__PURE__ */ jsx9("div", { className: "min-h-0 flex-1 overflow-auto px-4 py-4", children: loading ? /* @__PURE__ */ jsx9("div", { className: "flex flex-col gap-2", role: "status", "aria-label": "Loading schedules", children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx9(Skeleton, { className: "h-12 w-full rounded-md" }, i)) }) : error != null ? /* @__PURE__ */ jsx9("p", { className: "text-failure-bg px-3 py-8 text-center text-sm", children: error }) : schedules.length === 0 ? /* @__PURE__ */ jsx9(EmptyScreen, { title: "No Schedules Found", description: "Create one to get started.", className: "min-h-full" }) : filtered.length === 0 ? /* @__PURE__ */ jsxs7("div", { className: "flex min-h-full flex-col", children: [
1481
+ /* @__PURE__ */ jsx9(EmptyScreen, { title: "No Schedules Found", description: "No schedules match your filters.", className: "flex-1" }),
1482
+ hasPageNav ? /* @__PURE__ */ jsx9(
1238
1483
  TableTokenPagination,
1239
1484
  {
1240
1485
  pageSize,
@@ -1252,48 +1497,48 @@ function SchedulesPage() {
1252
1497
  }
1253
1498
  }
1254
1499
  ) : null
1255
- ] }) : /* @__PURE__ */ jsxs6("div", { className: "rounded-lg border border-border", children: [
1256
- /* @__PURE__ */ jsxs6(Table, { className: "min-w-[48rem]", children: [
1257
- /* @__PURE__ */ jsx8(TableHeader, { children: /* @__PURE__ */ jsxs6(TableRow, { className: "hover:bg-transparent", children: [
1258
- /* @__PURE__ */ jsx8(TableHead, { children: "Name" }),
1259
- /* @__PURE__ */ jsx8(TableHead, { children: "Agent" }),
1260
- /* @__PURE__ */ jsx8(TableHead, { children: "Cadence" }),
1261
- /* @__PURE__ */ jsx8(TableHead, { children: "Status" }),
1262
- /* @__PURE__ */ jsx8(TableHead, { children: "Last 5 runs" }),
1263
- /* @__PURE__ */ jsx8(TableHead, { children: /* @__PURE__ */ jsx8("span", { className: "sr-only", children: "Actions" }) })
1500
+ ] }) : /* @__PURE__ */ jsxs7("div", { className: "overflow-hidden rounded-lg border border-border", children: [
1501
+ /* @__PURE__ */ jsxs7(Table, { className: "min-w-[48rem]", children: [
1502
+ /* @__PURE__ */ jsx9(TableHeader, { children: /* @__PURE__ */ jsxs7(TableRow, { className: "hover:bg-transparent", children: [
1503
+ /* @__PURE__ */ jsx9(TableHead, { children: "Name" }),
1504
+ /* @__PURE__ */ jsx9(TableHead, { children: "Agent" }),
1505
+ showCreatedByColumn ? /* @__PURE__ */ jsx9(TableHead, { children: "Created by" }) : null,
1506
+ /* @__PURE__ */ jsx9(TableHead, { children: "Frequency" }),
1507
+ /* @__PURE__ */ jsx9(TableHead, { children: "Status" }),
1508
+ /* @__PURE__ */ jsx9(TableHead, { children: "Last 5 runs" }),
1509
+ /* @__PURE__ */ jsx9(TableHead, { children: /* @__PURE__ */ jsx9("span", { className: "sr-only", children: "Actions" }) })
1264
1510
  ] }) }),
1265
- /* @__PURE__ */ jsx8(TableBody, { children: filtered.map((schedule) => {
1511
+ /* @__PURE__ */ jsx9(TableBody, { children: filtered.map((schedule) => {
1266
1512
  const cadence = formatCadenceSummary({ cron: schedule.cron, timezone: schedule.timezone });
1267
- const agentLabel = schedule.agentName ?? agentNameById.get(schedule.agentId) ?? schedule.agentId;
1268
- return /* @__PURE__ */ jsxs6(TableRow, { children: [
1269
- /* @__PURE__ */ jsx8(TableCell, { className: "text-text-primary font-medium", children: /* @__PURE__ */ jsx8(
1270
- "button",
1271
- {
1272
- type: "button",
1273
- className: "text-primary-button-bg hover:underline text-left",
1274
- onClick: () => setDrawer({ kind: "edit", schedule }),
1275
- children: schedule.name
1276
- }
1277
- ) }),
1278
- /* @__PURE__ */ jsx8(TableCell, { children: agentLabel }),
1279
- /* @__PURE__ */ jsx8(TableCell, { children: cadence }),
1280
- /* @__PURE__ */ jsx8(TableCell, { children: /* @__PURE__ */ jsx8(ScheduleStatusBadge, { status: schedule.status }) }),
1281
- /* @__PURE__ */ jsx8(TableCell, { children: runsLoading ? /* @__PURE__ */ jsx8("span", { className: "text-text-secondary text-sm", children: "\u2026" }) : /* @__PURE__ */ jsx8(ScheduleLastRunsCell, { runs: runsByScheduleId[schedule.id] ?? [] }) }),
1282
- /* @__PURE__ */ jsx8(TableCell, { className: "text-right", children: /* @__PURE__ */ jsx8(
1513
+ const agentLabel = schedule.agentName ?? agentLabelById[schedule.agentId] ?? schedule.agentId;
1514
+ return /* @__PURE__ */ jsxs7(TableRow, { children: [
1515
+ /* @__PURE__ */ jsx9(TableCell, { className: "text-text-primary font-medium", children: /* @__PURE__ */ jsx9("span", { className: "text-left !no-underline", children: schedule.name }) }),
1516
+ /* @__PURE__ */ jsx9(TableCell, { children: agentLabel }),
1517
+ showCreatedByColumn ? /* @__PURE__ */ jsx9(TableCell, { children: /* @__PURE__ */ jsx9(CreatedByCell, { subject: schedule.createdBySubject }) }) : null,
1518
+ /* @__PURE__ */ jsx9(TableCell, { children: cadence }),
1519
+ /* @__PURE__ */ jsx9(TableCell, { children: /* @__PURE__ */ jsx9(ScheduleStatusBadge, { status: schedule.status }) }),
1520
+ /* @__PURE__ */ jsx9(TableCell, { children: runsLoading ? /* @__PURE__ */ jsx9("span", { className: "text-text-secondary text-sm", children: "\u2026" }) : /* @__PURE__ */ jsx9(ScheduleLastRunsCell, { runs: runsByScheduleId[schedule.id] ?? [] }) }),
1521
+ /* @__PURE__ */ jsx9(TableCell, { className: "text-right", children: /* @__PURE__ */ jsx9(
1283
1522
  ScheduleRowActions,
1284
1523
  {
1285
1524
  schedule,
1286
1525
  running: runningScheduleIds.has(schedule.id),
1526
+ canManage: allows(schedule.id, "MANAGE"),
1527
+ canDelete: allows(schedule.id, "DELETE"),
1287
1528
  onRunNow: () => void handleRunNow(schedule),
1288
- onEdit: () => setDrawer({ kind: "edit", schedule }),
1529
+ onEdit: () => {
1530
+ if (allows(schedule.id, "MANAGE")) setDrawer({ kind: "edit", schedule });
1531
+ },
1289
1532
  onTogglePause: () => void handleTogglePause(schedule),
1290
- onDelete: () => setPendingDelete(schedule)
1533
+ onDelete: () => {
1534
+ if (allows(schedule.id, "DELETE")) setPendingDelete(schedule);
1535
+ }
1291
1536
  }
1292
1537
  ) })
1293
1538
  ] }, schedule.id);
1294
1539
  }) })
1295
1540
  ] }),
1296
- (filtered.length > 0 || hasPageNav) && /* @__PURE__ */ jsx8(
1541
+ (filtered.length > 0 || hasPageNav) && /* @__PURE__ */ jsx9(
1297
1542
  TableTokenPagination,
1298
1543
  {
1299
1544
  pageSize,
@@ -1312,7 +1557,7 @@ function SchedulesPage() {
1312
1557
  }
1313
1558
  )
1314
1559
  ] }) }),
1315
- drawer.kind === "create" ? /* @__PURE__ */ jsx8(
1560
+ drawer.kind === "create" ? /* @__PURE__ */ jsx9(
1316
1561
  ScheduleFormDrawer,
1317
1562
  {
1318
1563
  open: true,
@@ -1324,7 +1569,7 @@ function SchedulesPage() {
1324
1569
  onSaved: () => resetToFirstPage()
1325
1570
  }
1326
1571
  ) : null,
1327
- drawer.kind === "edit" ? /* @__PURE__ */ jsx8(
1572
+ drawer.kind === "edit" ? /* @__PURE__ */ jsx9(
1328
1573
  ScheduleFormDrawer,
1329
1574
  {
1330
1575
  open: true,
@@ -1336,7 +1581,7 @@ function SchedulesPage() {
1336
1581
  onSaved: () => void loadSchedules({ token: pageToken, size: pageSize, agentId: agentFilter })
1337
1582
  }
1338
1583
  ) : null,
1339
- pendingDelete != null ? /* @__PURE__ */ jsxs6(
1584
+ pendingDelete != null ? /* @__PURE__ */ jsxs7(
1340
1585
  Dialog,
1341
1586
  {
1342
1587
  open: true,
@@ -1346,17 +1591,25 @@ function SchedulesPage() {
1346
1591
  "aria-label": "Delete schedule",
1347
1592
  className: "max-w-md",
1348
1593
  children: [
1349
- /* @__PURE__ */ jsx8(DialogContent, { children: /* @__PURE__ */ jsxs6(DialogHeader, { children: [
1350
- /* @__PURE__ */ jsx8(DialogTitle, { children: "Delete schedule" }),
1351
- /* @__PURE__ */ jsxs6("p", { className: "text-text-secondary text-sm", children: [
1594
+ /* @__PURE__ */ jsx9(DialogContent, { children: /* @__PURE__ */ jsxs7(DialogHeader, { children: [
1595
+ /* @__PURE__ */ jsx9(DialogTitle, { children: "Delete schedule" }),
1596
+ /* @__PURE__ */ jsxs7("p", { className: "text-text-secondary text-sm", children: [
1352
1597
  "\u201C",
1353
1598
  pendingDelete.name,
1354
1599
  "\u201D will stop running. This cannot be undone."
1355
1600
  ] })
1356
1601
  ] }) }),
1357
- /* @__PURE__ */ jsxs6(DialogFooter, { children: [
1358
- /* @__PURE__ */ jsx8(Button, { type: "button", variant: "secondary", onClick: () => setPendingDelete(null), children: "Cancel" }),
1359
- /* @__PURE__ */ jsx8(Button, { type: "button", variant: "destructive", onClick: () => void handleDelete(pendingDelete), children: "Delete" })
1602
+ /* @__PURE__ */ jsxs7(DialogFooter, { children: [
1603
+ /* @__PURE__ */ jsx9(Button.Secondary, { type: "button", onClick: () => setPendingDelete(null), children: "Cancel" }),
1604
+ /* @__PURE__ */ jsx9(
1605
+ Button.Destructive,
1606
+ {
1607
+ type: "button",
1608
+ disabled: !allows(pendingDelete.id, "DELETE"),
1609
+ onClick: () => void handleDelete(pendingDelete),
1610
+ children: "Delete"
1611
+ }
1612
+ )
1360
1613
  ] })
1361
1614
  ]
1362
1615
  }
@@ -1373,4 +1626,4 @@ export {
1373
1626
  ScheduleLastRunsCell,
1374
1627
  SchedulesPage
1375
1628
  };
1376
- //# sourceMappingURL=chunk-6O6FWUDW.js.map
1629
+ //# sourceMappingURL=chunk-EPAL2HD5.js.map