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

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 (110) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +22 -7
  3. package/dist/{AgentCodeSnippets-NZOFJE57.js → AgentCodeSnippets-N546FNNS.js} +38 -23
  4. package/dist/AgentCodeSnippets-N546FNNS.js.map +1 -0
  5. package/dist/AgentMetricChart-YWJYVYYA.js +15 -0
  6. package/dist/{AgentOverview-EEBHJC32.js → AgentOverview-VF74XC7I.js} +7 -7
  7. package/dist/{AgentSessionEventTimeline-26Z6IB3B.js → AgentSessionEventTimeline-RFR6LQMY.js} +19 -10
  8. package/dist/AgentSessionEventTimeline-RFR6LQMY.js.map +1 -0
  9. package/dist/{AgentSessionEventTimelineChart-CGCU7WBK.js → AgentSessionEventTimelineChart-27CQF6FX.js} +144 -57
  10. package/dist/AgentSessionEventTimelineChart-27CQF6FX.js.map +1 -0
  11. package/dist/{AgentSessions-3MPDZASK.js → AgentSessions-4IVX2SGD.js} +36 -12
  12. package/dist/AgentSessions-4IVX2SGD.js.map +1 -0
  13. package/dist/{ConnectorSettings-MXFRWWR6.js → ConnectorSettings-R5VEP7BO.js} +162 -126
  14. package/dist/ConnectorSettings-R5VEP7BO.js.map +1 -0
  15. package/dist/{DockLayout-LM4AFMFY.js → DockLayout-F44RWGEY.js} +10 -10
  16. package/dist/{DrawerLayout-JR3O6RRB.js → DrawerLayout-SQ323AVM.js} +14 -12
  17. package/dist/DrawerLayout-SQ323AVM.js.map +1 -0
  18. package/dist/{ModelSettings-G7IFNC2Y.js → ModelSettings-6QLS63HM.js} +22 -28
  19. package/dist/ModelSettings-6QLS63HM.js.map +1 -0
  20. package/dist/OpenUiFenceBlock-4ROX3G4X.js +9 -0
  21. package/dist/{SandboxSettings-NXAANMAX.js → SandboxSettings-OLKDXIQS.js} +17 -21
  22. package/dist/SandboxSettings-OLKDXIQS.js.map +1 -0
  23. package/dist/SchedulesPage-TMOTK6DR.js +15 -0
  24. package/dist/{SettingsBuilder-L34IQ56S.js → SettingsBuilder-GISAH2WU.js} +8 -8
  25. package/dist/{ShellRouteSync-CEBETGEJ.js → ShellRouteSync-EN33DUQ7.js} +171 -26
  26. package/dist/ShellRouteSync-EN33DUQ7.js.map +1 -0
  27. package/dist/{SidebarLayout-A2HJPPHS.js → SidebarLayout-35K4AKTC.js} +80 -58
  28. package/dist/SidebarLayout-35K4AKTC.js.map +1 -0
  29. package/dist/{SkillSettings-FGGMSUNO.js → SkillSettings-JSX2BTII.js} +24 -22
  30. package/dist/SkillSettings-JSX2BTII.js.map +1 -0
  31. package/dist/{TrueForgeUIWithRouter-MZVJWJMB.js → TrueForgeUIWithRouter-6VCR7ES3.js} +9 -9
  32. package/dist/{WidgetLayout-6QM45OQQ.js → WidgetLayout-RKBSN2FZ.js} +10 -10
  33. package/dist/{chunk-ZTMKFZQ3.js → chunk-2O5EJ6QS.js} +4440 -3042
  34. package/dist/chunk-2O5EJ6QS.js.map +1 -0
  35. package/dist/chunk-6WCIL3H2.js +517 -0
  36. package/dist/chunk-6WCIL3H2.js.map +1 -0
  37. package/dist/{chunk-WVE3F724.js → chunk-73FQVITT.js} +21 -4
  38. package/dist/chunk-73FQVITT.js.map +1 -0
  39. package/dist/{chunk-QC42MLAK.js → chunk-7AAO4UDQ.js} +4 -3
  40. package/dist/chunk-7AAO4UDQ.js.map +1 -0
  41. package/dist/{chunk-CYHJDKFB.js → chunk-F5QVQIBH.js} +172 -46
  42. package/dist/chunk-F5QVQIBH.js.map +1 -0
  43. package/dist/{chunk-FJW36PD7.js → chunk-GIPFF6FZ.js} +28 -24
  44. package/dist/chunk-GIPFF6FZ.js.map +1 -0
  45. package/dist/{chunk-6O6FWUDW.js → chunk-GSJAYYLR.js} +233 -195
  46. package/dist/chunk-GSJAYYLR.js.map +1 -0
  47. package/dist/{chunk-MPNSO7E6.js → chunk-J5BPHEDT.js} +2 -2
  48. package/dist/chunk-KR7WYHVF.js +195 -0
  49. package/dist/chunk-KR7WYHVF.js.map +1 -0
  50. package/dist/{chunk-DMMZSZTN.js → chunk-LUG7E6BL.js} +60 -16
  51. package/dist/chunk-LUG7E6BL.js.map +1 -0
  52. package/dist/chunk-LXJMINS6.js +587 -0
  53. package/dist/chunk-LXJMINS6.js.map +1 -0
  54. package/dist/{chunk-U7KURWW3.js → chunk-PT4EENB3.js} +244 -52
  55. package/dist/chunk-PT4EENB3.js.map +1 -0
  56. package/dist/{chunk-XAU7QFG3.js → chunk-Q6TCT7ZJ.js} +68 -256
  57. package/dist/chunk-Q6TCT7ZJ.js.map +1 -0
  58. package/dist/{chunk-ZKNUMH2M.js → chunk-XLFOXQKZ.js} +13 -11
  59. package/dist/chunk-XLFOXQKZ.js.map +1 -0
  60. package/dist/{chunk-M62XY4NC.js → chunk-XY6LZQES.js} +235 -108
  61. package/dist/chunk-XY6LZQES.js.map +1 -0
  62. package/dist/{createTrueFoundryServer-CmZnBh_l.d.ts → createTrueFoundryServer-B_FYhSdn.d.ts} +8 -5
  63. package/dist/index.d.ts +316 -94
  64. package/dist/index.js +65 -488
  65. package/dist/index.js.map +1 -1
  66. package/dist/plugins/trueforge-agent-server-adapter/index.d.ts +36 -13
  67. package/dist/plugins/trueforge-agent-server-adapter/index.js +69 -34
  68. package/dist/plugins/trueforge-agent-server-adapter/index.js.map +1 -1
  69. package/dist/styles.css +1 -1
  70. package/package.json +4 -4
  71. package/dist/AgentCodeSnippets-NZOFJE57.js.map +0 -1
  72. package/dist/AgentMetricChart-JPU3MFQ2.js +0 -15
  73. package/dist/AgentSessionEventTimeline-26Z6IB3B.js.map +0 -1
  74. package/dist/AgentSessionEventTimelineChart-CGCU7WBK.js.map +0 -1
  75. package/dist/AgentSessions-3MPDZASK.js.map +0 -1
  76. package/dist/ConnectorSettings-MXFRWWR6.js.map +0 -1
  77. package/dist/DrawerLayout-JR3O6RRB.js.map +0 -1
  78. package/dist/ModelSettings-G7IFNC2Y.js.map +0 -1
  79. package/dist/OpenUiFenceBlock-2TV5TQ6P.js +0 -9
  80. package/dist/SandboxSettings-NXAANMAX.js.map +0 -1
  81. package/dist/SchedulesPage-KKLUDO6B.js +0 -15
  82. package/dist/ShellRouteSync-CEBETGEJ.js.map +0 -1
  83. package/dist/SidebarLayout-A2HJPPHS.js.map +0 -1
  84. package/dist/SkillSettings-FGGMSUNO.js.map +0 -1
  85. package/dist/chunk-2XPPBEYF.js +0 -74
  86. package/dist/chunk-2XPPBEYF.js.map +0 -1
  87. package/dist/chunk-6O6FWUDW.js.map +0 -1
  88. package/dist/chunk-7Z2C2K7F.js +0 -578
  89. package/dist/chunk-7Z2C2K7F.js.map +0 -1
  90. package/dist/chunk-CYHJDKFB.js.map +0 -1
  91. package/dist/chunk-DMMZSZTN.js.map +0 -1
  92. package/dist/chunk-FJW36PD7.js.map +0 -1
  93. package/dist/chunk-M62XY4NC.js.map +0 -1
  94. package/dist/chunk-QC42MLAK.js.map +0 -1
  95. package/dist/chunk-SFZNIO6U.js +0 -18
  96. package/dist/chunk-SFZNIO6U.js.map +0 -1
  97. package/dist/chunk-U7KURWW3.js.map +0 -1
  98. package/dist/chunk-WVE3F724.js.map +0 -1
  99. package/dist/chunk-XAU7QFG3.js.map +0 -1
  100. package/dist/chunk-ZKNUMH2M.js.map +0 -1
  101. package/dist/chunk-ZTMKFZQ3.js.map +0 -1
  102. /package/dist/{AgentMetricChart-JPU3MFQ2.js.map → AgentMetricChart-YWJYVYYA.js.map} +0 -0
  103. /package/dist/{AgentOverview-EEBHJC32.js.map → AgentOverview-VF74XC7I.js.map} +0 -0
  104. /package/dist/{DockLayout-LM4AFMFY.js.map → DockLayout-F44RWGEY.js.map} +0 -0
  105. /package/dist/{OpenUiFenceBlock-2TV5TQ6P.js.map → OpenUiFenceBlock-4ROX3G4X.js.map} +0 -0
  106. /package/dist/{SchedulesPage-KKLUDO6B.js.map → SchedulesPage-TMOTK6DR.js.map} +0 -0
  107. /package/dist/{SettingsBuilder-L34IQ56S.js.map → SettingsBuilder-GISAH2WU.js.map} +0 -0
  108. /package/dist/{TrueForgeUIWithRouter-MZVJWJMB.js.map → TrueForgeUIWithRouter-6VCR7ES3.js.map} +0 -0
  109. /package/dist/{WidgetLayout-6QM45OQQ.js.map → WidgetLayout-RKBSN2FZ.js.map} +0 -0
  110. /package/dist/{chunk-MPNSO7E6.js.map → chunk-J5BPHEDT.js.map} +0 -0
@@ -24,29 +24,32 @@ import {
24
24
  Tooltip,
25
25
  auiInputClass,
26
26
  mountName,
27
- searchAllAgents,
27
+ useResourcePermissions,
28
+ useSlot,
28
29
  useToasterOptional
29
- } from "./chunk-ZTMKFZQ3.js";
30
+ } from "./chunk-2O5EJ6QS.js";
30
31
  import {
31
32
  readScheduleShareSearch,
32
- replaceScheduleShareSearch
33
- } from "./chunk-2XPPBEYF.js";
33
+ replaceScheduleShareSearch,
34
+ searchAllAgents
35
+ } from "./chunk-KR7WYHVF.js";
34
36
  import {
35
37
  DraftCatalogProvider,
36
38
  Icon,
37
39
  PageHeader,
38
40
  auiButtonClass,
39
41
  useDraftCatalog
40
- } from "./chunk-XAU7QFG3.js";
42
+ } from "./chunk-Q6TCT7ZJ.js";
41
43
  import {
42
44
  libraryAgentId,
43
45
  useOptionalCatalogServer,
46
+ useOptionalShellMode,
44
47
  useScheduleServer,
45
48
  useServer
46
- } from "./chunk-U7KURWW3.js";
49
+ } from "./chunk-PT4EENB3.js";
47
50
  import {
48
51
  cn
49
- } from "./chunk-7Z2C2K7F.js";
52
+ } from "./chunk-LXJMINS6.js";
50
53
 
51
54
  // src/atoms/schedules/SchedulesPage.tsx
52
55
  import { useCallback, useEffect as useEffect3, useMemo as useMemo2, useRef, useState as useState3 } from "react";
@@ -278,7 +281,9 @@ function ScheduleFormFields({
278
281
  agentId,
279
282
  onAgentIdChange,
280
283
  agentOptions,
281
- agentPickerDisabled = false
284
+ agentOptionsLoaded = true,
285
+ agentPickerDisabled = false,
286
+ onBuildAgent
282
287
  }) {
283
288
  const cron = valuesToCron(values);
284
289
  const cadence = formatCadenceSummary({ cron, timezone: values.timezone });
@@ -302,7 +307,12 @@ function ScheduleFormFields({
302
307
  value: agentId,
303
308
  options: agentOptions.map((agent) => ({ value: agent.agentId, label: agent.name })),
304
309
  onValueChange: (value) => onAgentIdChange?.(value),
305
- disabled: agentPickerDisabled || onAgentIdChange == null
310
+ disabled: agentPickerDisabled || onAgentIdChange == null,
311
+ emptyContent: agentOptionsLoaded ? /* @__PURE__ */ jsx("p", { className: "text-text-secondary px-3 py-5 text-center text-sm", children: "No Agents created yet" }) : null,
312
+ footer: agentOptionsLoaded && agentOptions.length === 0 && 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: [
313
+ /* @__PURE__ */ jsx(Icon, { name: "plus", className: "size-3.5" }),
314
+ "Build Agent"
315
+ ] }) }) : null
306
316
  }
307
317
  )
308
318
  ] }),
@@ -314,7 +324,7 @@ function ScheduleFormFields({
314
324
  value: values.name,
315
325
  onChange: (e) => set("name", e.target.value),
316
326
  placeholder: "harness-daily-digest",
317
- className: auiInputClass("h-9"),
327
+ className: auiInputClass("h-8"),
318
328
  required: true
319
329
  }
320
330
  )
@@ -334,107 +344,96 @@ function ScheduleFormFields({
334
344
  )
335
345
  ] }),
336
346
  /* @__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" })
347
+ /* @__PURE__ */ jsx("legend", { className: "mb-1.5 text-sm font-medium", children: "Frequency" }),
348
+ /* @__PURE__ */ jsx("div", { className: "rounded-t-lg border border-border p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
349
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 rounded-lg border border-border bg-primary-bg p-1", children: RECURRENCE_OPTIONS.map((opt) => {
350
+ const selected = values.recurrence === opt.value;
351
+ return /* @__PURE__ */ jsx(
352
+ "button",
353
+ {
354
+ type: "button",
355
+ className: cn(
356
+ "rounded-md border px-2 py-2 text-sm font-medium transition-colors",
357
+ 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"
358
+ ),
359
+ "aria-pressed": selected,
360
+ onClick: () => set("recurrence", opt.value),
361
+ children: opt.label
362
+ },
363
+ opt.value
364
+ );
365
+ }) }),
366
+ values.recurrence === "custom" ? /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-border bg-secondary-bg/40 px-3 py-2", children: [
367
+ /* @__PURE__ */ jsx("span", { className: "block text-xs text-text-secondary", children: "Existing custom schedule" }),
368
+ /* @__PURE__ */ jsx("code", { className: "mt-1 block font-mono text-sm text-text-primary", children: values.customCron }),
369
+ /* @__PURE__ */ jsx("span", { className: "mt-1 block text-xs text-text-secondary", children: "Select Hourly, Daily, or Weekly to replace this schedule." })
370
+ ] }) : null,
371
+ values.recurrence === "weekly" ? /* @__PURE__ */ jsxs("fieldset", { children: [
372
+ /* @__PURE__ */ jsx("legend", { className: "mb-2 text-sm font-medium", children: "Days" }),
373
+ /* @__PURE__ */ jsx("div", { className: "flex gap-2", children: WEEKDAY_OPTIONS.map((day) => {
374
+ const selected = values.weekdays.includes(day.value);
375
+ return /* @__PURE__ */ jsx(
376
+ "button",
377
+ {
378
+ type: "button",
379
+ className: cn(
380
+ "min-w-0 flex-1 rounded-md border px-3 py-2 text-[0.8125rem] font-medium",
381
+ 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"
382
+ ),
383
+ "aria-pressed": selected,
384
+ onClick: () => toggleWeekday(day.value),
385
+ children: day.label
386
+ },
387
+ day.value
388
+ );
389
+ }) })
390
+ ] }) : null,
391
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
392
+ values.recurrence === "daily" || values.recurrence === "weekly" ? /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
393
+ /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-sm font-medium", children: "Hour" }),
394
+ /* @__PURE__ */ jsx(
395
+ PopoverSelect,
396
+ {
397
+ "aria-label": "Hour",
398
+ value: String(values.hour),
399
+ options: HOUR_OPTIONS,
400
+ onValueChange: (value) => set("hour", Number(value))
401
+ }
402
+ )
403
+ ] }) : null,
404
+ values.recurrence !== "custom" ? /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
405
+ /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-sm font-medium", children: "Minute" }),
406
+ /* @__PURE__ */ jsx(
407
+ PopoverSelect,
408
+ {
409
+ "aria-label": "Minute",
410
+ value: String(values.minute),
411
+ options: MINUTE_OPTIONS,
412
+ onValueChange: (value) => set("minute", Number(value))
413
+ }
414
+ )
415
+ ] }) : null,
416
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
417
+ /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-sm font-medium", children: "Timezone" }),
418
+ /* @__PURE__ */ jsx(
419
+ PopoverSelect,
420
+ {
421
+ "aria-label": "Timezone",
422
+ value: values.timezone,
423
+ options: timezoneOptions,
424
+ onValueChange: (value) => set("timezone", value),
425
+ menuClassName: "w-full min-w-0"
426
+ }
427
+ )
428
+ ] })
429
+ ] })
430
+ ] }) }),
431
+ /* @__PURE__ */ jsx("div", { className: "rounded-b-lg border border-t-0 border-border bg-primary-button-bg/10 px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
432
+ /* @__PURE__ */ jsx(Icon, { name: "clock", className: "size-4 shrink-0 text-primary-button-bg" }),
433
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs font-medium text-text-secondary", children: "Schedule" }),
434
+ /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 truncate text-sm text-text-primary", children: cadence || "\u2014" }),
435
+ /* @__PURE__ */ jsx("code", { className: "shrink-0 whitespace-nowrap font-mono text-[0.8125rem] font-bold text-text-secondary", children: cron || "\u2014" })
436
+ ] }) })
438
437
  ] })
439
438
  ] });
440
439
  }
@@ -525,7 +524,7 @@ function ScheduleStatusBadge({ status }) {
525
524
  {
526
525
  className: cn(
527
526
  "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"
527
+ 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
528
  ),
530
529
  children: [
531
530
  /* @__PURE__ */ jsx4(
@@ -533,7 +532,7 @@ function ScheduleStatusBadge({ status }) {
533
532
  {
534
533
  className: cn(
535
534
  "size-1.5 shrink-0 rounded-full",
536
- active ? "bg-emerald-600 dark:bg-emerald-400" : "bg-text-secondary"
535
+ active ? "bg-emerald-600 dark:bg-emerald-400" : "bg-amber-600 dark:bg-amber-400"
537
536
  ),
538
537
  "aria-hidden": true
539
538
  }
@@ -592,13 +591,13 @@ function TestScheduleScreen({ schedule, agentName, mcpMounts, onEditConfiguratio
592
591
  /* @__PURE__ */ jsxs4("section", { className: "overflow-hidden rounded-lg border border-border bg-card-bg", children: [
593
592
  /* @__PURE__ */ jsx5(DetailRow, { label: "Agent", children: agentName }),
594
593
  /* @__PURE__ */ jsx5(DetailRow, { label: "Name", children: schedule.name }),
594
+ /* @__PURE__ */ jsx5(DetailRow, { label: "Status", children: /* @__PURE__ */ jsx5(ScheduleStatusBadge, { status: schedule.status }) }),
595
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: [
596
+ /* @__PURE__ */ jsx5(DetailRow, { label: "Frequency", children: /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center justify-end gap-1.5", children: [
597
597
  /* @__PURE__ */ jsx5("span", { children: cadence }),
598
598
  /* @__PURE__ */ jsx5("code", { className: "text-text-secondary font-mono text-xs", children: schedule.cron })
599
599
  ] }) }),
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: [
600
+ /* @__PURE__ */ jsx5("div", { className: "flex justify-end px-3 py-2.5", children: /* @__PURE__ */ jsxs4(Button.Secondary, { type: "button", size: "small", onClick: onEditConfiguration, children: [
602
601
  /* @__PURE__ */ jsx5(Icon, { name: "pencil", className: "size-3.5" }),
603
602
  "Edit Configuration"
604
603
  ] }) })
@@ -629,19 +628,10 @@ function TestScheduleScreen({ schedule, agentName, mcpMounts, onEditConfiguratio
629
628
  /* @__PURE__ */ jsxs4("section", { className: "overflow-hidden rounded-lg border border-border bg-card-bg", children: [
630
629
  /* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between gap-2 border-b border-border px-3 py-2", children: [
631
630
  /* @__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
- )
631
+ /* @__PURE__ */ jsxs4(Button.Primary, { type: "button", disabled: running, size: "small", onClick: () => void handleRunTest(), children: [
632
+ /* @__PURE__ */ jsx5(Icon, { name: running ? "loader" : "play", className: cn("size-3.5", running && "animate-spin") }),
633
+ "Run Test"
634
+ ] })
645
635
  ] }),
646
636
  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
637
  /* @__PURE__ */ jsx5(ScheduleRunChip, { run: lastTestRun }),
@@ -666,10 +656,12 @@ function ScheduleFormDrawerBody({
666
656
  }) {
667
657
  const scheduleServer = useScheduleServer();
668
658
  const server = useServer();
659
+ const shell = useOptionalShellMode();
669
660
  const toaster = useToasterOptional();
670
661
  const [form, setForm] = useState2(defaultScheduleFormValues);
671
662
  const [agentId, setAgentId] = useState2(initialAgentId);
672
663
  const [agents, setAgents] = useState2([]);
664
+ const [agentsLoaded, setAgentsLoaded] = useState2(false);
673
665
  const [view, setView] = useState2({ kind: "form" });
674
666
  const [saving, setSaving] = useState2(false);
675
667
  const [activating, setActivating] = useState2(false);
@@ -677,12 +669,19 @@ function ScheduleFormDrawerBody({
677
669
  const savedFromCreate = view.kind === "form" ? view.saved : view.schedule;
678
670
  const isExternalEdit = mode === "edit" && view.kind === "form" && view.saved == null && schedule != null;
679
671
  const isCreatedEdit = view.kind === "form" && view.saved != null;
672
+ const isInitialCreate = mode === "create" && view.kind === "form" && view.saved == null;
673
+ const { allows: allowsAgent } = useResourcePermissions({
674
+ resourceType: "agent",
675
+ resourceIds: agentId.length === 0 ? [] : [agentId]
676
+ });
680
677
  useEffect2(() => {
681
678
  if (!open) return;
682
679
  let cancelled = false;
680
+ setAgentsLoaded(false);
683
681
  void searchAllAgents(server).then((rows) => {
684
682
  if (cancelled) return;
685
683
  setAgents(rows);
684
+ setAgentsLoaded(true);
686
685
  }).catch(() => void 0);
687
686
  return () => {
688
687
  cancelled = true;
@@ -729,8 +728,8 @@ function ScheduleFormDrawerBody({
729
728
  }, [selectedAgent]);
730
729
  const canSubmit = useMemo(() => {
731
730
  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]);
731
+ return form.name.trim().length > 0 && form.task.trim().length > 0 && cron.length > 0 && agentId.length > 0 && (!isInitialCreate || allowsAgent(agentId, "USE"));
732
+ }, [agentId, allowsAgent, form, isInitialCreate]);
734
733
  const enterTestView = (saved) => {
735
734
  setView({ kind: "test", schedule: saved });
736
735
  setForm(
@@ -831,24 +830,14 @@ function ScheduleFormDrawerBody({
831
830
  if (view.kind === "test") {
832
831
  footer = /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
833
832
  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
- )
833
+ /* @__PURE__ */ jsx6(Button.Secondary, { type: "button", className: "w-full", disabled: activating, onClick: () => void handleActivate(), children: "Activate Schedule" })
845
834
  ] });
846
835
  } else {
847
836
  footer = /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
848
837
  error != null ? /* @__PURE__ */ jsx6("p", { className: "text-failure-bg text-sm", children: error }) : null,
849
838
  /* @__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" })
839
+ /* @__PURE__ */ jsx6(Button.Secondary, { type: "button", onClick: () => onOpenChange(false), disabled: saving, children: "Cancel" }),
840
+ /* @__PURE__ */ jsx6(Button.Primary, { type: "submit", form: "schedule-form", disabled: !canSubmit || saving, children: "Save" })
852
841
  ] })
853
842
  ] });
854
843
  }
@@ -860,7 +849,7 @@ function ScheduleFormDrawerBody({
860
849
  title,
861
850
  description,
862
851
  anchor: "right",
863
- size: "lg",
852
+ size: "xl",
864
853
  headerIcon: /* @__PURE__ */ jsx6("span", { className: "text-primary-button-bg inline-flex size-8 items-center justify-center", children: /* @__PURE__ */ jsx6(
865
854
  Icon,
866
855
  {
@@ -888,7 +877,12 @@ function ScheduleFormDrawerBody({
888
877
  agentId,
889
878
  onAgentIdChange: isExternalEdit || isCreatedEdit ? void 0 : setAgentId,
890
879
  agentOptions,
891
- agentPickerDisabled: isExternalEdit || isCreatedEdit
880
+ agentOptionsLoaded: agentsLoaded,
881
+ agentPickerDisabled: isExternalEdit || isCreatedEdit,
882
+ onBuildAgent: mode === "create" && shell?.isComposerEnabled === true ? () => {
883
+ onOpenChange(false);
884
+ shell.openAgentBuilder();
885
+ } : void 0
892
886
  }
893
887
  ) })
894
888
  }
@@ -927,29 +921,41 @@ function filtersFromSearch(search) {
927
921
  agentFilter: share.agent ?? "all"
928
922
  };
929
923
  }
924
+ function initialDrawerState(agentId) {
925
+ const share = readScheduleShareSearch(window.location.search);
926
+ if (!share.isNew) return { kind: "closed" };
927
+ const initialAgentId = agentId ?? share.agent;
928
+ return {
929
+ kind: "create",
930
+ ...initialAgentId == null ? {} : { agentId: initialAgentId }
931
+ };
932
+ }
930
933
  function ScheduleRowActions({
931
934
  schedule,
932
935
  running,
936
+ canManage,
937
+ canDelete,
933
938
  onRunNow,
934
939
  onEdit,
935
940
  onTogglePause,
936
941
  onDelete
937
942
  }) {
943
+ const PermissionGuard = useSlot("PermissionGuard");
938
944
  return /* @__PURE__ */ jsxs6("div", { className: "inline-flex items-center justify-end gap-1.5", children: [
939
- /* @__PURE__ */ jsxs6(
940
- "button",
945
+ /* @__PURE__ */ jsx8(PermissionGuard, { allowed: canManage, children: /* @__PURE__ */ jsxs6(
946
+ Button.Secondary,
941
947
  {
942
948
  type: "button",
943
949
  disabled: running,
944
950
  "aria-label": `Run now ${schedule.name}`,
945
- className: auiButtonClass({ variant: "outline", size: "sm" }),
951
+ size: "large",
946
952
  onClick: onRunNow,
947
953
  children: [
948
954
  /* @__PURE__ */ jsx8(Icon, { name: running ? "loader" : "play", className: cn("size-3.5", running && "animate-spin") }),
949
955
  "Run now"
950
956
  ]
951
957
  }
952
- ),
958
+ ) }),
953
959
  /* @__PURE__ */ jsxs6(
954
960
  DropdownMenu,
955
961
  {
@@ -960,32 +966,36 @@ function ScheduleRowActions({
960
966
  type: "button",
961
967
  className: auiButtonClass({ variant: "ghost", size: "icon" }),
962
968
  "aria-label": `Actions for ${schedule.name}`,
963
- children: /* @__PURE__ */ jsx8(Icon, { name: "ellipsis", className: "size-4" })
969
+ children: /* @__PURE__ */ jsx8(Icon, { name: "ellipsis" })
964
970
  }
965
971
  ),
966
972
  children: [
967
- /* @__PURE__ */ jsxs6(DropdownMenuItem, { onClick: onEdit, children: [
973
+ /* @__PURE__ */ jsx8(PermissionGuard, { allowed: canManage, children: /* @__PURE__ */ jsxs6(DropdownMenuItem, { onClick: onEdit, children: [
968
974
  /* @__PURE__ */ jsx8(Icon, { name: "pencil", className: "size-3.5" }),
969
975
  "Edit"
970
- ] }),
971
- /* @__PURE__ */ jsxs6(DropdownMenuItem, { onClick: onTogglePause, children: [
976
+ ] }) }),
977
+ /* @__PURE__ */ jsx8(PermissionGuard, { allowed: canManage, children: /* @__PURE__ */ jsxs6(DropdownMenuItem, { onClick: onTogglePause, children: [
972
978
  /* @__PURE__ */ jsx8(Icon, { name: schedule.status === "active" ? "pause" : "play", className: "size-3.5" }),
973
979
  schedule.status === "active" ? "Pause" : "Resume"
974
- ] }),
975
- /* @__PURE__ */ jsxs6(DropdownMenuItem, { className: "text-failure-bg focus:text-failure-bg", onClick: onDelete, children: [
980
+ ] }) }),
981
+ /* @__PURE__ */ jsx8(PermissionGuard, { allowed: canDelete, children: /* @__PURE__ */ jsxs6(DropdownMenuItem, { className: "text-failure-bg focus:text-failure-bg", onClick: onDelete, children: [
976
982
  /* @__PURE__ */ jsx8(Icon, { name: "trash", className: "size-3.5" }),
977
983
  "Delete"
978
- ] })
984
+ ] }) })
979
985
  ]
980
986
  }
981
987
  )
982
988
  ] });
983
989
  }
984
- function SchedulesPage() {
990
+ function SchedulesPage({ agentId }) {
985
991
  const scheduleServer = useScheduleServer();
986
992
  const server = useServer();
987
993
  const toaster = useToasterOptional();
988
994
  const [schedules, setSchedules] = useState3([]);
995
+ const { allows } = useResourcePermissions({
996
+ resourceType: "schedule",
997
+ resourceIds: schedules.map((schedule) => schedule.id)
998
+ });
989
999
  const [runsByScheduleId, setRunsByScheduleId] = useState3({});
990
1000
  const [runsLoading, setRunsLoading] = useState3(false);
991
1001
  const [runningScheduleIds, setRunningScheduleIds] = useState3(() => /* @__PURE__ */ new Set());
@@ -996,8 +1006,20 @@ function SchedulesPage() {
996
1006
  const [statusFilter, setStatusFilter] = useState3(
997
1007
  () => filtersFromSearch(window.location.search).statusFilter
998
1008
  );
999
- const [agentFilter, setAgentFilter] = useState3(() => filtersFromSearch(window.location.search).agentFilter);
1000
- const [drawer, setDrawer] = useState3({ kind: "closed" });
1009
+ const [agentFilter, setAgentFilter] = useState3(
1010
+ () => agentId ?? filtersFromSearch(window.location.search).agentFilter
1011
+ );
1012
+ const permissionAgentId = agentId ?? (agentFilter === "all" ? null : agentFilter);
1013
+ const permissionAgentIds = useMemo2(
1014
+ () => permissionAgentId == null ? agentOptions.map((option) => option.agentId) : [permissionAgentId],
1015
+ [agentOptions, permissionAgentId]
1016
+ );
1017
+ const { allows: allowsAgent } = useResourcePermissions({
1018
+ resourceType: "agent",
1019
+ resourceIds: permissionAgentIds
1020
+ });
1021
+ const canCreateSchedule = server.permissions == null || (permissionAgentId == null ? agentOptions.some((option) => allowsAgent(option.agentId, "USE")) : allowsAgent(permissionAgentId, "USE"));
1022
+ const [drawer, setDrawer] = useState3(() => initialDrawerState(agentId));
1001
1023
  const [pendingDelete, setPendingDelete] = useState3(null);
1002
1024
  const [pageSize, setPageSize] = useState3(() => clampPageSize(DEFAULT_TABLE_PAGE_SIZE));
1003
1025
  const [pageToken, setPageToken] = useState3(void 0);
@@ -1033,7 +1055,7 @@ function SchedulesPage() {
1033
1055
  [scheduleServer]
1034
1056
  );
1035
1057
  const loadSchedules = useCallback(
1036
- async ({ token, size, agentId }) => {
1058
+ async ({ token, size, agentId: agentId2 }) => {
1037
1059
  const gen = ++loadGenRef.current;
1038
1060
  setLoading(true);
1039
1061
  setError(null);
@@ -1041,7 +1063,7 @@ function SchedulesPage() {
1041
1063
  const page = await scheduleServer.listSchedules({
1042
1064
  limit: clampPageSize(size),
1043
1065
  ...token === void 0 || token === "" ? {} : { pageToken: token },
1044
- ...agentId === "all" ? {} : { agentIds: [agentId] }
1066
+ ...agentId2 === "all" ? {} : { agentIds: [agentId2] }
1045
1067
  });
1046
1068
  if (gen !== loadGenRef.current) return;
1047
1069
  setSchedules(page.data);
@@ -1063,29 +1085,34 @@ function SchedulesPage() {
1063
1085
  const resetToFirstPage = useCallback(
1064
1086
  (next) => {
1065
1087
  const size = next?.size ?? pageSize;
1066
- const agentId = next?.agentId ?? agentFilter;
1088
+ const agentId2 = next?.agentId ?? agentFilter;
1067
1089
  setPageToken(void 0);
1068
1090
  setPrevTokenStack([]);
1069
- void loadSchedules({ token: void 0, size, agentId });
1091
+ void loadSchedules({ token: void 0, size, agentId: agentId2 });
1070
1092
  },
1071
1093
  [agentFilter, loadSchedules, pageSize]
1072
1094
  );
1073
1095
  useEffect3(() => {
1074
1096
  replaceScheduleShareSearch({
1075
- agent: agentFilter === "all" ? null : agentFilter,
1097
+ agent: agentId === void 0 && agentFilter !== "all" ? agentFilter : null,
1076
1098
  status: statusFilter === "all" ? null : statusFilter,
1077
1099
  q: nameQuery.trim().length === 0 ? null : nameQuery
1078
1100
  });
1079
- }, [agentFilter, statusFilter, nameQuery]);
1101
+ }, [agentFilter, agentId, statusFilter, nameQuery]);
1102
+ useEffect3(() => {
1103
+ if (agentId === void 0) return;
1104
+ setAgentFilter((current) => {
1105
+ if (current === agentId) return current;
1106
+ setPageToken(void 0);
1107
+ setPrevTokenStack([]);
1108
+ return agentId;
1109
+ });
1110
+ }, [agentId]);
1080
1111
  useEffect3(() => {
1081
1112
  if (didConsumeIsNewRef.current) return;
1082
1113
  const share = readScheduleShareSearch(window.location.search);
1083
1114
  if (!share.isNew) return;
1084
1115
  didConsumeIsNewRef.current = true;
1085
- setDrawer({
1086
- kind: "create",
1087
- ...share.agent != null ? { agentId: share.agent } : {}
1088
- });
1089
1116
  replaceScheduleShareSearch({ isNew: null });
1090
1117
  }, []);
1091
1118
  useEffect3(() => {
@@ -1094,17 +1121,18 @@ function SchedulesPage() {
1094
1121
  setNameQuery(next.nameQuery);
1095
1122
  setStatusFilter(next.statusFilter);
1096
1123
  setAgentFilter((current) => {
1097
- if (current === next.agentFilter) return current;
1124
+ const nextAgentFilter = agentId ?? next.agentFilter;
1125
+ if (current === nextAgentFilter) return current;
1098
1126
  setPageToken(void 0);
1099
1127
  setPrevTokenStack([]);
1100
- return next.agentFilter;
1128
+ return nextAgentFilter;
1101
1129
  });
1102
1130
  };
1103
1131
  window.addEventListener("popstate", syncFromUrl);
1104
1132
  return () => {
1105
1133
  window.removeEventListener("popstate", syncFromUrl);
1106
1134
  };
1107
- }, []);
1135
+ }, [agentId]);
1108
1136
  useEffect3(() => {
1109
1137
  void loadSchedules({ token: pageToken, size: pageSize, agentId: agentFilter });
1110
1138
  }, [agentFilter, pageSize, pageToken, loadSchedules]);
@@ -1135,6 +1163,7 @@ function SchedulesPage() {
1135
1163
  }, [schedules, nameQuery, statusFilter]);
1136
1164
  const hasPageNav = prevTokenStack.length > 0 || nextPageToken != null;
1137
1165
  const handleTogglePause = async (schedule) => {
1166
+ if (!allows(schedule.id, "MANAGE")) return;
1138
1167
  const nextStatus = schedule.status === "active" ? "paused" : "active";
1139
1168
  try {
1140
1169
  await scheduleServer.updateSchedule({ ...schedule, status: nextStatus });
@@ -1144,6 +1173,7 @@ function SchedulesPage() {
1144
1173
  }
1145
1174
  };
1146
1175
  const handleRunNow = async (schedule) => {
1176
+ if (!allows(schedule.id, "MANAGE")) return;
1147
1177
  setRunningScheduleIds((prev) => new Set(prev).add(schedule.id));
1148
1178
  try {
1149
1179
  await scheduleServer.createScheduleRun({ scheduleId: schedule.id });
@@ -1161,6 +1191,7 @@ function SchedulesPage() {
1161
1191
  }
1162
1192
  };
1163
1193
  const handleDelete = async (schedule) => {
1194
+ if (!allows(schedule.id, "DELETE")) return;
1164
1195
  setPendingDelete(null);
1165
1196
  try {
1166
1197
  await scheduleServer.deleteSchedule({ id: schedule.id });
@@ -1185,7 +1216,7 @@ function SchedulesPage() {
1185
1216
  /* @__PURE__ */ jsx8(
1186
1217
  PageHeader,
1187
1218
  {
1188
- title: "Scheduled Agents",
1219
+ title: agentId === void 0 ? "Scheduled Agents" : void 0,
1189
1220
  end: /* @__PURE__ */ jsxs6(Fragment, { children: [
1190
1221
  /* @__PURE__ */ jsx8("div", { className: "w-full sm:w-56", children: /* @__PURE__ */ jsx8(SearchInput_default, { query: nameQuery, setQuery: setNameQuery, placeholder: "Search schedules by name" }) }),
1191
1222
  /* @__PURE__ */ jsx8(
@@ -1198,7 +1229,7 @@ function SchedulesPage() {
1198
1229
  "aria-label": "Filter by status"
1199
1230
  }
1200
1231
  ),
1201
- /* @__PURE__ */ jsx8(
1232
+ agentId === void 0 ? /* @__PURE__ */ jsx8(
1202
1233
  PopoverSelect,
1203
1234
  {
1204
1235
  value: agentFilter,
@@ -1214,12 +1245,13 @@ function SchedulesPage() {
1214
1245
  className: "sm:w-40",
1215
1246
  "aria-label": "Filter by agent"
1216
1247
  }
1217
- ),
1248
+ ) : null,
1218
1249
  /* @__PURE__ */ jsxs6(
1219
- Button,
1250
+ Button.Primary,
1220
1251
  {
1221
1252
  type: "button",
1222
- onClick: () => setDrawer({
1253
+ disabled: !canCreateSchedule,
1254
+ onClick: () => canCreateSchedule && setDrawer({
1223
1255
  kind: "create",
1224
1256
  agentId: agentFilter !== "all" ? agentFilter : void 0
1225
1257
  }),
@@ -1232,7 +1264,7 @@ function SchedulesPage() {
1232
1264
  ] })
1233
1265
  }
1234
1266
  ),
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: [
1267
+ /* @__PURE__ */ jsx8("div", { className: "min-h-0 flex-1 overflow-auto px-4 py-4", 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
1268
  /* @__PURE__ */ jsx8(EmptyScreen, { title: "No Schedules Found", description: "No schedules match your filters.", className: "flex-1" }),
1237
1269
  hasPageNav ? /* @__PURE__ */ jsx8(
1238
1270
  TableTokenPagination,
@@ -1252,12 +1284,12 @@ function SchedulesPage() {
1252
1284
  }
1253
1285
  }
1254
1286
  ) : null
1255
- ] }) : /* @__PURE__ */ jsxs6("div", { className: "rounded-lg border border-border", children: [
1287
+ ] }) : /* @__PURE__ */ jsxs6("div", { className: "overflow-hidden rounded-lg border border-border", children: [
1256
1288
  /* @__PURE__ */ jsxs6(Table, { className: "min-w-[48rem]", children: [
1257
1289
  /* @__PURE__ */ jsx8(TableHeader, { children: /* @__PURE__ */ jsxs6(TableRow, { className: "hover:bg-transparent", children: [
1258
1290
  /* @__PURE__ */ jsx8(TableHead, { children: "Name" }),
1259
1291
  /* @__PURE__ */ jsx8(TableHead, { children: "Agent" }),
1260
- /* @__PURE__ */ jsx8(TableHead, { children: "Cadence" }),
1292
+ /* @__PURE__ */ jsx8(TableHead, { children: "Frequency" }),
1261
1293
  /* @__PURE__ */ jsx8(TableHead, { children: "Status" }),
1262
1294
  /* @__PURE__ */ jsx8(TableHead, { children: "Last 5 runs" }),
1263
1295
  /* @__PURE__ */ jsx8(TableHead, { children: /* @__PURE__ */ jsx8("span", { className: "sr-only", children: "Actions" }) })
@@ -1266,15 +1298,7 @@ function SchedulesPage() {
1266
1298
  const cadence = formatCadenceSummary({ cron: schedule.cron, timezone: schedule.timezone });
1267
1299
  const agentLabel = schedule.agentName ?? agentNameById.get(schedule.agentId) ?? schedule.agentId;
1268
1300
  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
- ) }),
1301
+ /* @__PURE__ */ jsx8(TableCell, { className: "text-text-primary font-medium", children: /* @__PURE__ */ jsx8("span", { className: "text-left !no-underline", children: schedule.name }) }),
1278
1302
  /* @__PURE__ */ jsx8(TableCell, { children: agentLabel }),
1279
1303
  /* @__PURE__ */ jsx8(TableCell, { children: cadence }),
1280
1304
  /* @__PURE__ */ jsx8(TableCell, { children: /* @__PURE__ */ jsx8(ScheduleStatusBadge, { status: schedule.status }) }),
@@ -1284,10 +1308,16 @@ function SchedulesPage() {
1284
1308
  {
1285
1309
  schedule,
1286
1310
  running: runningScheduleIds.has(schedule.id),
1311
+ canManage: allows(schedule.id, "MANAGE"),
1312
+ canDelete: allows(schedule.id, "DELETE"),
1287
1313
  onRunNow: () => void handleRunNow(schedule),
1288
- onEdit: () => setDrawer({ kind: "edit", schedule }),
1314
+ onEdit: () => {
1315
+ if (allows(schedule.id, "MANAGE")) setDrawer({ kind: "edit", schedule });
1316
+ },
1289
1317
  onTogglePause: () => void handleTogglePause(schedule),
1290
- onDelete: () => setPendingDelete(schedule)
1318
+ onDelete: () => {
1319
+ if (allows(schedule.id, "DELETE")) setPendingDelete(schedule);
1320
+ }
1291
1321
  }
1292
1322
  ) })
1293
1323
  ] }, schedule.id);
@@ -1355,8 +1385,16 @@ function SchedulesPage() {
1355
1385
  ] })
1356
1386
  ] }) }),
1357
1387
  /* @__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" })
1388
+ /* @__PURE__ */ jsx8(Button.Secondary, { type: "button", onClick: () => setPendingDelete(null), children: "Cancel" }),
1389
+ /* @__PURE__ */ jsx8(
1390
+ Button.Destructive,
1391
+ {
1392
+ type: "button",
1393
+ disabled: !allows(pendingDelete.id, "DELETE"),
1394
+ onClick: () => void handleDelete(pendingDelete),
1395
+ children: "Delete"
1396
+ }
1397
+ )
1360
1398
  ] })
1361
1399
  ]
1362
1400
  }
@@ -1373,4 +1411,4 @@ export {
1373
1411
  ScheduleLastRunsCell,
1374
1412
  SchedulesPage
1375
1413
  };
1376
- //# sourceMappingURL=chunk-6O6FWUDW.js.map
1414
+ //# sourceMappingURL=chunk-GSJAYYLR.js.map