@burdenoff/microfe-botmanor 2026.1027.2 → 2026.1028.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/botlit/BotlitRoutes.js +142 -132
  2. package/dist/botlit/BotlitRoutes.js.map +1 -1
  3. package/dist/botlit/components/AgentApprovalPanel.js +144 -126
  4. package/dist/botlit/components/AgentApprovalPanel.js.map +1 -1
  5. package/dist/botlit/components/ModelRegistrationPanel.js +4 -4
  6. package/dist/botlit/components/RetentionStatusPanel.js +95 -0
  7. package/dist/botlit/components/RetentionStatusPanel.js.map +1 -0
  8. package/dist/botlit/components/VersionHistoryPanel.js +92 -83
  9. package/dist/botlit/components/VersionHistoryPanel.js.map +1 -1
  10. package/dist/botlit/hooks/index.js +1 -0
  11. package/dist/botlit/hooks/useRetention.js +31 -0
  12. package/dist/botlit/hooks/useRetention.js.map +1 -0
  13. package/dist/botlit/pages/A2AAgentDetailPage.js +212 -203
  14. package/dist/botlit/pages/A2AAgentDetailPage.js.map +1 -1
  15. package/dist/botlit/pages/A2ARegistryPage.js +129 -117
  16. package/dist/botlit/pages/A2ARegistryPage.js.map +1 -1
  17. package/dist/botlit/pages/AgentApprovalsPage.js +122 -110
  18. package/dist/botlit/pages/AgentApprovalsPage.js.map +1 -1
  19. package/dist/botlit/pages/AgentBuilderPage.js +18 -18
  20. package/dist/botlit/pages/AgentDetailPage.js +298 -273
  21. package/dist/botlit/pages/AgentDetailPage.js.map +1 -1
  22. package/dist/botlit/pages/AgentsListPage.js +145 -121
  23. package/dist/botlit/pages/AgentsListPage.js.map +1 -1
  24. package/dist/botlit/pages/BotChannelsTab.js +238 -226
  25. package/dist/botlit/pages/BotChannelsTab.js.map +1 -1
  26. package/dist/botlit/pages/BotDetailPage.js +307 -288
  27. package/dist/botlit/pages/BotDetailPage.js.map +1 -1
  28. package/dist/botlit/pages/BotWorkflowTab.js +125 -116
  29. package/dist/botlit/pages/BotWorkflowTab.js.map +1 -1
  30. package/dist/botlit/pages/BotsListPage.js +159 -144
  31. package/dist/botlit/pages/BotsListPage.js.map +1 -1
  32. package/dist/botlit/pages/BucketsPage.js +279 -258
  33. package/dist/botlit/pages/BucketsPage.js.map +1 -1
  34. package/dist/botlit/pages/ChannelDetailPage.js +346 -328
  35. package/dist/botlit/pages/ChannelDetailPage.js.map +1 -1
  36. package/dist/botlit/pages/ChannelRoutesPage.js +10 -10
  37. package/dist/botlit/pages/ChannelsPage.js +163 -148
  38. package/dist/botlit/pages/ChannelsPage.js.map +1 -1
  39. package/dist/botlit/pages/DashboardPage.js +129 -114
  40. package/dist/botlit/pages/DashboardPage.js.map +1 -1
  41. package/dist/botlit/pages/ExecutionDetailPage.js +145 -139
  42. package/dist/botlit/pages/ExecutionDetailPage.js.map +1 -1
  43. package/dist/botlit/pages/ExecutionsPage.js +14 -14
  44. package/dist/botlit/pages/InstalledPackagesPage.js +245 -227
  45. package/dist/botlit/pages/InstalledPackagesPage.js.map +1 -1
  46. package/dist/botlit/pages/KnowledgeBaseDetailPage.js +168 -156
  47. package/dist/botlit/pages/KnowledgeBaseDetailPage.js.map +1 -1
  48. package/dist/botlit/pages/KnowledgeBasesPage.js +91 -79
  49. package/dist/botlit/pages/KnowledgeBasesPage.js.map +1 -1
  50. package/dist/botlit/pages/MCPServerDetailPage.js +200 -188
  51. package/dist/botlit/pages/MCPServerDetailPage.js.map +1 -1
  52. package/dist/botlit/pages/MCPServersPage.js +170 -155
  53. package/dist/botlit/pages/MCPServersPage.js.map +1 -1
  54. package/dist/botlit/pages/PoliciesPage.js +115 -104
  55. package/dist/botlit/pages/PoliciesPage.js.map +1 -1
  56. package/dist/botlit/pages/PolicyDetailPage.js +368 -324
  57. package/dist/botlit/pages/PolicyDetailPage.js.map +1 -1
  58. package/dist/botlit/pages/PromptStudioPage.js +106 -97
  59. package/dist/botlit/pages/PromptStudioPage.js.map +1 -1
  60. package/dist/botlit/pages/PromptTemplateDetailPage.js +359 -347
  61. package/dist/botlit/pages/PromptTemplateDetailPage.js.map +1 -1
  62. package/dist/botlit/pages/PromptTemplatesPage.js +127 -112
  63. package/dist/botlit/pages/PromptTemplatesPage.js.map +1 -1
  64. package/dist/botlit/pages/RetrievalProfileDetailPage.js +219 -210
  65. package/dist/botlit/pages/RetrievalProfileDetailPage.js.map +1 -1
  66. package/dist/botlit/pages/RetrievalProfilesPage.js +112 -103
  67. package/dist/botlit/pages/RetrievalProfilesPage.js.map +1 -1
  68. package/dist/botlit/pages/SettingsPage.js +264 -252
  69. package/dist/botlit/pages/SettingsPage.js.map +1 -1
  70. package/dist/botlit/pages/SkillDetailPage.js +235 -226
  71. package/dist/botlit/pages/SkillDetailPage.js.map +1 -1
  72. package/dist/botlit/pages/SkillsPage.js +115 -106
  73. package/dist/botlit/pages/SkillsPage.js.map +1 -1
  74. package/dist/botlit/pages/StorePackageDetailPage.js +194 -188
  75. package/dist/botlit/pages/StorePackageDetailPage.js.map +1 -1
  76. package/dist/botlit/pages/StorePage.js +161 -155
  77. package/dist/botlit/pages/StorePage.js.map +1 -1
  78. package/dist/botlit/permissions/PermissionRequired.js +45 -0
  79. package/dist/botlit/permissions/PermissionRequired.js.map +1 -0
  80. package/dist/botlit/permissions/botmanorPermissions.js +72 -0
  81. package/dist/botlit/permissions/botmanorPermissions.js.map +1 -0
  82. package/dist/botlit/permissions/index.js +3 -0
  83. package/dist/botlit/permissions/useBotmanorPermissions.js +19 -0
  84. package/dist/botlit/permissions/useBotmanorPermissions.js.map +1 -0
  85. package/dist/botlit/utils/policyConfig.js +67 -42
  86. package/dist/botlit/utils/policyConfig.js.map +1 -1
  87. package/dist/generated/global-types.js.map +1 -1
  88. package/dist/generated/wspace-operations.js +90 -54
  89. package/dist/generated/wspace-operations.js.map +1 -1
  90. package/dist/generated/wspace-types.js.map +1 -1
  91. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RetentionStatusPanel.js","names":[],"sources":["../../../src/botlit/components/RetentionStatusPanel.tsx"],"sourcesContent":["/**\n * Retention status panel (BOFF-9661)\n * @module botlit/components\n *\n * Shows the retention periods in force for the workspace (the shortest of its\n * ACTIVE retention policies), the end-of-term erasure grace period and the\n * most recent retention passes, and lets a policy editor run a pass now.\n */\n\nimport type { FC } from 'react';\nimport { toast } from 'sonner';\nimport { Archive, RefreshCw } from 'lucide-react';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from './Card';\nimport { Button } from './Button';\nimport { Badge } from './Badge';\nimport { useApplyRetention, useRetentionStatus } from '../hooks';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { BOTMANOR_PERMISSIONS, BotmanorPermissionGate } from '../permissions';\n\nfunction describePeriod(days: number | null | undefined, zeroLabel: string): string {\n if (days === null || days === undefined) return 'Kept for the life of the workspace';\n if (days === 0) return zeroLabel;\n return `${days} day${days === 1 ? '' : 's'}`;\n}\n\nexport const RetentionStatusPanel: FC = () => {\n const { data: status, loading, error, refetch } = useRetentionStatus();\n const { apply, loading: applying } = useApplyRetention();\n\n const handleApply = async () => {\n try {\n const run = await apply();\n if (run.status === 'COMPLETED') {\n toast.success(\n `Retention applied: ${run.executionsPurged} run payloads and ${run.a2aMessagesPurged} agent messages erased`\n );\n } else {\n toast.error(run.errorMessage ?? 'The retention pass failed');\n }\n } catch (applyError) {\n toast.error(applyError instanceof Error ? applyError.message : 'Failed to apply retention');\n }\n await refetch();\n };\n\n if (error) {\n return null;\n }\n\n const lastRun = status?.recentRuns[0];\n\n return (\n <Card data-testid=\"retention-status-panel\">\n <CardHeader className=\"pb-2\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Archive size={18} />\n Data retention\n </CardTitle>\n <CardDescription>\n Active retention policies are enforced every hour. When a workspace is deleted, its\n BotManor data is erased after{' '}\n {status ? `${status.endOfTermErasureGraceDays} days` : 'the grace period'}.\n </CardDescription>\n </div>\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.POLICY_UPDATE}>\n <Button\n variant=\"outline\"\n size=\"sm\"\n leftIcon={<RefreshCw size={14} />}\n onClick={() => void handleApply()}\n isLoading={applying}\n disabled={loading || !status || status.activePolicyCount === 0}\n >\n Apply now\n </Button>\n </BotmanorPermissionGate>\n </div>\n </CardHeader>\n <CardContent>\n {loading && !status ? (\n <div className=\"h-16 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\" />\n ) : status ? (\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4 text-sm\">\n <div>\n <p className=\"text-text-secondary\">Run inputs and outputs</p>\n <p className=\"font-medium\" data-testid=\"retention-execution-days\">\n {describePeriod(status.executionDataRetentionDays, 'Erased when the run ends')}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Assistant conversations</p>\n <p className=\"font-medium\" data-testid=\"retention-conversation-days\">\n {describePeriod(status.conversationRetentionDays, 'Erased when the run ends')}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Last pass</p>\n {lastRun ? (\n <p className=\"font-medium flex flex-wrap items-center gap-2\">\n <span>{formatRelativeTime(lastRun.finishedAt)}</span>\n <Badge variant={lastRun.status === 'COMPLETED' ? 'success' : 'destructive'}>\n {lastRun.status === 'COMPLETED'\n ? `${lastRun.executionsPurged + lastRun.a2aMessagesPurged} erased`\n : 'Failed'}\n </Badge>\n </p>\n ) : (\n <p className=\"font-medium\">\n {status.activePolicyCount === 0 ? 'No active retention policy' : 'Not run yet'}\n </p>\n )}\n </div>\n </div>\n ) : null}\n </CardContent>\n </Card>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AAmBA,SAAS,EAAe,GAAiC,GAA2B;AAGlF,QAFI,KAAS,OAAmC,uCAC5C,MAAS,IAAU,IAChB,GAAG,EAAK,MAAM,MAAS,IAAI,KAAK;;AAGzC,IAAa,UAAiC;CAC5C,IAAM,EAAE,MAAM,GAAQ,YAAS,UAAO,eAAY,GAAoB,EAChE,EAAE,UAAO,SAAS,MAAa,GAAmB,EAElD,IAAc,YAAY;AAC9B,MAAI;GACF,IAAM,IAAM,MAAM,GAAO;AACzB,GAAI,EAAI,WAAW,cACjB,EAAM,QACJ,sBAAsB,EAAI,iBAAiB,oBAAoB,EAAI,kBAAkB,wBACtF,GAED,EAAM,MAAM,EAAI,gBAAgB,4BAA4B;WAEvD,GAAY;AACnB,KAAM,MAAM,aAAsB,QAAQ,EAAW,UAAU,4BAA4B;;AAE7F,QAAM,GAAS;;AAGjB,KAAI,EACF,QAAO;CAGT,IAAM,IAAU,GAAQ,WAAW;AAEnC,QACE,kBAAC,GAAD;EAAM,eAAY;YAAlB,CACE,kBAAC,GAAD;GAAY,WAAU;aACpB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KAAW,WAAU;eAArB,CACE,kBAAC,GAAD,EAAS,MAAM,IAAM,CAAA,EAAA,iBAEX;QACZ,kBAAC,GAAD,EAAA,UAAA;KAAiB;KAEe;KAC7B,IAAS,GAAG,EAAO,0BAA0B,SAAS;KAAmB;KAC1D,EAAA,CAAA,CACd,EAAA,CAAA,EACN,kBAAC,GAAD;KAAwB,YAAY,EAAqB;eACvD,kBAAC,GAAD;MACE,SAAQ;MACR,MAAK;MACL,UAAU,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA;MACjC,eAAe,KAAK,GAAa;MACjC,WAAW;MACX,UAAU,KAAW,CAAC,KAAU,EAAO,sBAAsB;gBAC9D;MAEQ,CAAA;KACc,CAAA,CACrB;;GACK,CAAA,EACb,kBAAC,GAAD,EAAA,UACG,KAAW,CAAC,IACX,kBAAC,OAAD,EAAK,WAAU,+DAAgE,CAAA,GAC7E,IACF,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;KAAG,WAAU;eAAsB;KAA0B,CAAA,EAC7D,kBAAC,KAAD;KAAG,WAAU;KAAc,eAAY;eACpC,EAAe,EAAO,4BAA4B,2BAA2B;KAC5E,CAAA,CACA,EAAA,CAAA;IACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;KAAG,WAAU;eAAsB;KAA2B,CAAA,EAC9D,kBAAC,KAAD;KAAG,WAAU;KAAc,eAAY;eACpC,EAAe,EAAO,2BAA2B,2BAA2B;KAC3E,CAAA,CACA,EAAA,CAAA;IACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;KAAG,WAAU;eAAsB;KAAa,CAAA,EAC/C,IACC,kBAAC,KAAD;KAAG,WAAU;eAAb,CACE,kBAAC,QAAD,EAAA,UAAO,EAAmB,EAAQ,WAAW,EAAQ,CAAA,EACrD,kBAAC,GAAD;MAAO,SAAS,EAAQ,WAAW,cAAc,YAAY;gBAC1D,EAAQ,WAAW,cAChB,GAAG,EAAQ,mBAAmB,EAAQ,kBAAkB,WACxD;MACE,CAAA,CACN;SAEJ,kBAAC,KAAD;KAAG,WAAU;eACV,EAAO,sBAAsB,IAAI,+BAA+B;KAC/D,CAAA,CAEF,EAAA,CAAA;IACF;OACJ,MACQ,CAAA,CACT"}
@@ -1,141 +1,150 @@
1
1
  import { useTr as e } from "../../shared/hooks/useTr.js";
2
2
  import { useAgentVersions as t, usePublishAgentVersion as n, useRollbackAgentVersion as r } from "../hooks/useAgents.js";
3
3
  import { formatRelativeTime as i } from "../utils/formatters.js";
4
- import { Card as a, CardContent as o, CardDescription as s, CardHeader as c, CardTitle as l } from "./Card.js";
5
- import { Button as u } from "./Button.js";
6
- import { Badge as d } from "./Badge.js";
7
- import { useState as f } from "react";
8
- import { AlertDialog as p, AlertDialogAction as m, AlertDialogCancel as h, AlertDialogContent as g, AlertDialogDescription as _, AlertDialogFooter as v, AlertDialogHeader as y, AlertDialogTitle as b, Dialog as x, DialogContent as S, DialogDescription as C, DialogFooter as w, DialogHeader as T, DialogTitle as E, Textarea as D } from "@burdenoff/fe-libs/ui";
9
- import { jsx as O, jsxs as k } from "react/jsx-runtime";
10
- import { CheckCircle2 as A, History as j, Rocket as M, RotateCcw as N } from "lucide-react";
11
- import { toast as P } from "sonner";
4
+ import { BOTMANOR_PERMISSIONS as a } from "../permissions/botmanorPermissions.js";
5
+ import { BotmanorPermissionGate as o } from "../permissions/useBotmanorPermissions.js";
6
+ import { Button as s } from "./Button.js";
7
+ import "../permissions/index.js";
8
+ import { Card as c, CardContent as l, CardDescription as u, CardHeader as d, CardTitle as f } from "./Card.js";
9
+ import { Badge as p } from "./Badge.js";
10
+ import { useState as m } from "react";
11
+ import { AlertDialog as h, AlertDialogAction as g, AlertDialogCancel as _, AlertDialogContent as v, AlertDialogDescription as y, AlertDialogFooter as b, AlertDialogHeader as x, AlertDialogTitle as S, Dialog as ee, DialogContent as C, DialogDescription as w, DialogFooter as T, DialogHeader as E, DialogTitle as D, Textarea as O } from "@burdenoff/fe-libs/ui";
12
+ import { jsx as k, jsxs as A } from "react/jsx-runtime";
13
+ import { CheckCircle2 as j, History as M, Rocket as N, RotateCcw as P } from "lucide-react";
14
+ import { toast as F } from "sonner";
12
15
  //#region src/botlit/components/VersionHistoryPanel.tsx
13
- function F(e) {
16
+ function I(e) {
14
17
  return e === "DRAFT" ? "secondary" : e === "PUBLISHED" ? "success" : "outline";
15
18
  }
16
- var I = ({ agentId: I, draftVersionId: L, currentVersionId: ee, onChanged: R }) => {
17
- let z = e(), { data: B, loading: V, refetch: H } = t(I), [U, W] = n(), [G, K] = r(), [q, J] = f(!1), [Y, X] = f(""), [Z, Q] = f(null), $ = async () => {
18
- if (L) try {
19
- let e = await U({
20
- agentId: I,
21
- versionId: L,
22
- changelog: Y
19
+ var L = ({ agentId: L, draftVersionId: R, currentVersionId: te, onChanged: z }) => {
20
+ let B = e(), { data: V, loading: H, refetch: U } = t(L), [W, G] = n(), [K, q] = r(), [J, Y] = m(!1), [X, Z] = m(""), [Q, $] = m(null), ne = async () => {
21
+ if (R) try {
22
+ let e = await W({
23
+ agentId: L,
24
+ versionId: R,
25
+ changelog: X
23
26
  });
24
- P.success(`${z("botlit.agentDetail.versions.publishSuccessPrefix", "Published version")} ${e.version}`), J(!1), X(""), await H(), R?.();
27
+ F.success(`${B("botlit.agentDetail.versions.publishSuccessPrefix", "Published version")} ${e.version}`), Y(!1), Z(""), await U(), z?.();
25
28
  } catch (e) {
26
- P.error(e instanceof Error ? e.message : z("botlit.agentDetail.versions.publishError", "Failed to publish version"));
29
+ F.error(e instanceof Error ? e.message : B("botlit.agentDetail.versions.publishError", "Failed to publish version"));
27
30
  }
28
- }, te = async () => {
29
- if (Z) try {
30
- let e = await G({
31
- agentId: I,
32
- targetVersionId: Z.id
31
+ }, re = async () => {
32
+ if (Q) try {
33
+ let e = await K({
34
+ agentId: L,
35
+ targetVersionId: Q.id
33
36
  });
34
- P.success(`${z("botlit.agentDetail.versions.rollbackSuccessPrefix", "Rolled back to version")} ${Z.version} (${z("botlit.agentDetail.versions.rollbackSuccessSuffix", "now")} ${e.version})`), Q(null), await H(), R?.();
37
+ F.success(`${B("botlit.agentDetail.versions.rollbackSuccessPrefix", "Rolled back to version")} ${Q.version} (${B("botlit.agentDetail.versions.rollbackSuccessSuffix", "now")} ${e.version})`), $(null), await U(), z?.();
35
38
  } catch (e) {
36
- P.error(e instanceof Error ? e.message : z("botlit.agentDetail.versions.rollbackError", "Failed to roll back agent version"));
39
+ F.error(e instanceof Error ? e.message : B("botlit.agentDetail.versions.rollbackError", "Failed to roll back agent version"));
37
40
  }
38
41
  };
39
- return /* @__PURE__ */ k("div", {
42
+ return /* @__PURE__ */ A("div", {
40
43
  className: "space-y-6",
41
44
  children: [
42
- /* @__PURE__ */ k(a, { children: [/* @__PURE__ */ k(c, {
45
+ /* @__PURE__ */ A(c, { children: [/* @__PURE__ */ A(d, {
43
46
  className: "flex flex-row items-start justify-between gap-4",
44
- children: [/* @__PURE__ */ k("div", { children: [/* @__PURE__ */ k(l, {
47
+ children: [/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ A(f, {
45
48
  className: "flex items-center gap-2",
46
- children: [/* @__PURE__ */ O(j, { size: 18 }), z("botlit.agentDetail.versions.title", "Version History")]
47
- }), /* @__PURE__ */ O(s, { children: z("botlit.agentDetail.versions.description", "Every published configuration change, with a diff-able changelog. Publish the current draft or roll back to any prior version.") })] }), L && /* @__PURE__ */ O(u, {
48
- leftIcon: /* @__PURE__ */ O(M, { size: 16 }),
49
- onClick: () => J(!0),
50
- children: z("botlit.agentDetail.versions.publishDraft", "Publish Draft")
49
+ children: [/* @__PURE__ */ k(M, { size: 18 }), B("botlit.agentDetail.versions.title", "Version History")]
50
+ }), /* @__PURE__ */ k(u, { children: B("botlit.agentDetail.versions.description", "Every published configuration change, with a diff-able changelog. Publish the current draft or roll back to any prior version.") })] }), R && /* @__PURE__ */ k(o, {
51
+ permission: a.AGENT_PUBLISH,
52
+ children: /* @__PURE__ */ k(s, {
53
+ leftIcon: /* @__PURE__ */ k(N, { size: 16 }),
54
+ onClick: () => Y(!0),
55
+ children: B("botlit.agentDetail.versions.publishDraft", "Publish Draft")
56
+ })
51
57
  })]
52
- }), /* @__PURE__ */ O(o, { children: V ? /* @__PURE__ */ O("div", { className: "h-32 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }) : B.length === 0 ? /* @__PURE__ */ O("p", {
58
+ }), /* @__PURE__ */ k(l, { children: H ? /* @__PURE__ */ k("div", { className: "h-32 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }) : V.length === 0 ? /* @__PURE__ */ k("p", {
53
59
  className: "text-text-secondary",
54
- children: z("botlit.agentDetail.versions.empty", "No version history yet.")
55
- }) : /* @__PURE__ */ O("ul", {
60
+ children: B("botlit.agentDetail.versions.empty", "No version history yet.")
61
+ }) : /* @__PURE__ */ k("ul", {
56
62
  className: "space-y-3",
57
- children: B.map((e) => {
58
- let t = e.id === ee, n = e.status !== "DRAFT" && !t;
59
- return /* @__PURE__ */ k("li", {
63
+ children: V.map((e) => {
64
+ let t = e.id === te, n = e.status !== "DRAFT" && !t;
65
+ return /* @__PURE__ */ A("li", {
60
66
  className: "flex items-start justify-between gap-4 p-4 border border-border-subtle rounded-lg",
61
- children: [/* @__PURE__ */ k("div", {
67
+ children: [/* @__PURE__ */ A("div", {
62
68
  className: "space-y-1 min-w-0",
63
69
  children: [
64
- /* @__PURE__ */ k("div", {
70
+ /* @__PURE__ */ A("div", {
65
71
  className: "flex items-center gap-2 flex-wrap",
66
72
  children: [
67
- /* @__PURE__ */ k("span", {
73
+ /* @__PURE__ */ A("span", {
68
74
  className: "font-mono font-medium",
69
75
  children: ["v", e.version]
70
76
  }),
71
- /* @__PURE__ */ O(d, {
72
- variant: F(e.status),
77
+ /* @__PURE__ */ k(p, {
78
+ variant: I(e.status),
73
79
  children: e.status
74
80
  }),
75
- t && /* @__PURE__ */ k(d, {
81
+ t && /* @__PURE__ */ A(p, {
76
82
  variant: "outline",
77
83
  className: "flex items-center gap-1",
78
- children: [/* @__PURE__ */ O(A, { size: 12 }), z("botlit.agentDetail.versions.liveNow", "Live now")]
84
+ children: [/* @__PURE__ */ k(j, { size: 12 }), B("botlit.agentDetail.versions.liveNow", "Live now")]
79
85
  })
80
86
  ]
81
87
  }),
82
- /* @__PURE__ */ O("p", {
88
+ /* @__PURE__ */ k("p", {
83
89
  className: "text-sm text-text-secondary break-words",
84
- children: e.changelog || z("botlit.agentDetail.versions.noChangelog", "No description")
90
+ children: e.changelog || B("botlit.agentDetail.versions.noChangelog", "No description")
85
91
  }),
86
- /* @__PURE__ */ O("p", {
92
+ /* @__PURE__ */ k("p", {
87
93
  className: "text-xs text-text-secondary",
88
- children: e.status === "DRAFT" ? `${z("botlit.agentDetail.versions.updated", "Updated")} ${i(e.createdAt)}` : `${z("botlit.agentDetail.versions.published", "Published")} ${i(e.publishedAt ?? e.createdAt)}`
94
+ children: e.status === "DRAFT" ? `${B("botlit.agentDetail.versions.updated", "Updated")} ${i(e.createdAt)}` : `${B("botlit.agentDetail.versions.published", "Published")} ${i(e.publishedAt ?? e.createdAt)}`
89
95
  })
90
96
  ]
91
- }), n && /* @__PURE__ */ O(u, {
92
- variant: "outline",
93
- size: "sm",
94
- leftIcon: /* @__PURE__ */ O(N, { size: 14 }),
95
- onClick: () => Q(e),
96
- children: z("botlit.agentDetail.versions.rollback", "Roll back")
97
+ }), n && /* @__PURE__ */ k(o, {
98
+ permission: a.AGENT_ROLLBACK,
99
+ children: /* @__PURE__ */ k(s, {
100
+ variant: "outline",
101
+ size: "sm",
102
+ leftIcon: /* @__PURE__ */ k(P, { size: 14 }),
103
+ onClick: () => $(e),
104
+ children: B("botlit.agentDetail.versions.rollback", "Roll back")
105
+ })
97
106
  })]
98
107
  }, e.id);
99
108
  })
100
109
  }) })] }),
101
- /* @__PURE__ */ O(x, {
102
- open: q,
103
- onOpenChange: J,
104
- children: /* @__PURE__ */ k(S, { children: [
105
- /* @__PURE__ */ k(T, { children: [/* @__PURE__ */ O(E, { children: z("botlit.agentDetail.versions.publishDialog.title", "Publish this version") }), /* @__PURE__ */ O(C, { children: z("botlit.agentDetail.versions.publishDialog.description", "This makes the draft's prompt, model, tools, and policy settings live for the agent. Describe what changed.") })] }),
106
- /* @__PURE__ */ O(D, {
107
- value: Y,
108
- onChange: (e) => X(e.target.value),
109
- placeholder: z("botlit.agentDetail.versions.publishDialog.placeholder", "e.g. Tightened the system prompt and switched to gpt-4o"),
110
+ /* @__PURE__ */ k(ee, {
111
+ open: J,
112
+ onOpenChange: Y,
113
+ children: /* @__PURE__ */ A(C, { children: [
114
+ /* @__PURE__ */ A(E, { children: [/* @__PURE__ */ k(D, { children: B("botlit.agentDetail.versions.publishDialog.title", "Publish this version") }), /* @__PURE__ */ k(w, { children: B("botlit.agentDetail.versions.publishDialog.description", "This makes the draft's prompt, model, tools, and policy settings live for the agent. Describe what changed.") })] }),
115
+ /* @__PURE__ */ k(O, {
116
+ value: X,
117
+ onChange: (e) => Z(e.target.value),
118
+ placeholder: B("botlit.agentDetail.versions.publishDialog.placeholder", "e.g. Tightened the system prompt and switched to gpt-4o"),
110
119
  rows: 4
111
120
  }),
112
- /* @__PURE__ */ k(w, { children: [/* @__PURE__ */ O(u, {
121
+ /* @__PURE__ */ A(T, { children: [/* @__PURE__ */ k(s, {
113
122
  variant: "outline",
114
- onClick: () => J(!1),
115
- children: z("botlit.common.cancel", "Cancel")
116
- }), /* @__PURE__ */ O(u, {
117
- isLoading: W.loading,
118
- onClick: () => void $(),
119
- children: z("botlit.agentDetail.versions.publishDialog.confirm", "Publish")
123
+ onClick: () => Y(!1),
124
+ children: B("botlit.common.cancel", "Cancel")
125
+ }), /* @__PURE__ */ k(s, {
126
+ isLoading: G.loading,
127
+ onClick: () => void ne(),
128
+ children: B("botlit.agentDetail.versions.publishDialog.confirm", "Publish")
120
129
  })] })
121
130
  ] })
122
131
  }),
123
- /* @__PURE__ */ O(p, {
124
- open: Z !== null,
125
- onOpenChange: (e) => !e && Q(null),
126
- children: /* @__PURE__ */ k(g, { children: [/* @__PURE__ */ k(y, { children: [/* @__PURE__ */ O(b, { children: z("botlit.agentDetail.versions.rollbackDialog.title", "Roll back to this version?") }), /* @__PURE__ */ O(_, { children: Z && `${z("botlit.agentDetail.versions.rollbackDialog.descriptionPrefix", "This immediately restores the agent to version")} ${Z.version}${z("botlit.agentDetail.versions.rollbackDialog.descriptionSuffix", ". The current live config is kept in history and can be restored the same way.")}` })] }), /* @__PURE__ */ k(v, { children: [/* @__PURE__ */ O(h, {
127
- onClick: () => Q(null),
128
- children: z("botlit.common.cancel", "Cancel")
129
- }), /* @__PURE__ */ O(m, {
130
- disabled: K.loading,
131
- onClick: () => void te(),
132
- children: z("botlit.agentDetail.versions.rollbackDialog.confirm", "Roll back")
132
+ /* @__PURE__ */ k(h, {
133
+ open: Q !== null,
134
+ onOpenChange: (e) => !e && $(null),
135
+ children: /* @__PURE__ */ A(v, { children: [/* @__PURE__ */ A(x, { children: [/* @__PURE__ */ k(S, { children: B("botlit.agentDetail.versions.rollbackDialog.title", "Roll back to this version?") }), /* @__PURE__ */ k(y, { children: Q && `${B("botlit.agentDetail.versions.rollbackDialog.descriptionPrefix", "This immediately restores the agent to version")} ${Q.version}${B("botlit.agentDetail.versions.rollbackDialog.descriptionSuffix", ". The current live config is kept in history and can be restored the same way.")}` })] }), /* @__PURE__ */ A(b, { children: [/* @__PURE__ */ k(_, {
136
+ onClick: () => $(null),
137
+ children: B("botlit.common.cancel", "Cancel")
138
+ }), /* @__PURE__ */ k(g, {
139
+ disabled: q.loading,
140
+ onClick: () => void re(),
141
+ children: B("botlit.agentDetail.versions.rollbackDialog.confirm", "Roll back")
133
142
  })] })] })
134
143
  })
135
144
  ]
136
145
  });
137
146
  };
138
147
  //#endregion
139
- export { I as VersionHistoryPanel };
148
+ export { L as VersionHistoryPanel };
140
149
 
141
150
  //# sourceMappingURL=VersionHistoryPanel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"VersionHistoryPanel.js","names":[],"sources":["../../../src/botlit/components/VersionHistoryPanel.tsx"],"sourcesContent":["/**\n * Version History Panel (BOFF-4381)\n * @module botlit/components\n *\n * Real, discoverable UI for agent versioning: shows the full version\n * history (draft/published/historical), lets a workspace admin publish the\n * current draft with a changelog, and roll back to any prior published\n * version with a confirmation step.\n */\n\nimport { useState, type FC } from 'react';\nimport { History, Rocket, RotateCcw, CheckCircle2 } from 'lucide-react';\nimport { toast } from 'sonner';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from './Card';\nimport { Button } from './Button';\nimport { Badge } from './Badge';\nimport {\n useAgentVersions,\n usePublishAgentVersion,\n useRollbackAgentVersion,\n type AgentVersionRecord,\n} from '../hooks/useAgents';\nimport { formatRelativeTime } from '../utils/formatters';\n\ninterface VersionHistoryPanelProps {\n agentId: string;\n /** The agent's current draft version id (if any) — enables the Publish action. */\n draftVersionId?: string | null;\n /** The agent's current live (published) version id — hidden from the rollback list. */\n currentVersionId?: string | null;\n /** Called after a successful publish or rollback so the caller can refetch the agent itself. */\n onChanged?: () => void;\n}\n\nfunction versionStatusVariant(\n status: AgentVersionRecord['status']\n): 'secondary' | 'success' | 'outline' {\n if (status === 'DRAFT') return 'secondary';\n if (status === 'PUBLISHED') return 'success';\n return 'outline';\n}\n\nexport const VersionHistoryPanel: FC<VersionHistoryPanelProps> = ({\n agentId,\n draftVersionId,\n currentVersionId,\n onChanged,\n}) => {\n const t = useTr();\n\n const { data: versions, loading, refetch } = useAgentVersions(agentId);\n const [publishAgentVersion, publishState] = usePublishAgentVersion();\n const [rollbackAgentVersion, rollbackState] = useRollbackAgentVersion();\n\n const [publishOpen, setPublishOpen] = useState(false);\n const [changelogDraft, setChangelogDraft] = useState('');\n const [rollbackTarget, setRollbackTarget] = useState<AgentVersionRecord | null>(null);\n\n const handlePublish = async (): Promise<void> => {\n if (!draftVersionId) return;\n try {\n const published = await publishAgentVersion({\n agentId,\n versionId: draftVersionId,\n changelog: changelogDraft,\n });\n toast.success(\n `${t('botlit.agentDetail.versions.publishSuccessPrefix', 'Published version')} ${published.version}`\n );\n setPublishOpen(false);\n setChangelogDraft('');\n await refetch();\n onChanged?.();\n } catch (err: unknown) {\n toast.error(\n err instanceof Error\n ? err.message\n : t('botlit.agentDetail.versions.publishError', 'Failed to publish version')\n );\n }\n };\n\n const handleRollback = async (): Promise<void> => {\n if (!rollbackTarget) return;\n try {\n const restored = await rollbackAgentVersion({ agentId, targetVersionId: rollbackTarget.id });\n toast.success(\n `${t('botlit.agentDetail.versions.rollbackSuccessPrefix', 'Rolled back to version')} ${rollbackTarget.version} (${t('botlit.agentDetail.versions.rollbackSuccessSuffix', 'now')} ${restored.version})`\n );\n setRollbackTarget(null);\n await refetch();\n onChanged?.();\n } catch (err: unknown) {\n toast.error(\n err instanceof Error\n ? err.message\n : t('botlit.agentDetail.versions.rollbackError', 'Failed to roll back agent version')\n );\n }\n };\n\n return (\n <div className=\"space-y-6\">\n <Card>\n <CardHeader className=\"flex flex-row items-start justify-between gap-4\">\n <div>\n <CardTitle className=\"flex items-center gap-2\">\n <History size={18} />\n {t('botlit.agentDetail.versions.title', 'Version History')}\n </CardTitle>\n <CardDescription>\n {t(\n 'botlit.agentDetail.versions.description',\n 'Every published configuration change, with a diff-able changelog. Publish the current draft or roll back to any prior version.'\n )}\n </CardDescription>\n </div>\n {draftVersionId && (\n <Button leftIcon={<Rocket size={16} />} onClick={() => setPublishOpen(true)}>\n {t('botlit.agentDetail.versions.publishDraft', 'Publish Draft')}\n </Button>\n )}\n </CardHeader>\n <CardContent>\n {loading ? (\n <div className=\"h-32 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\" />\n ) : versions.length === 0 ? (\n <p className=\"text-text-secondary\">\n {t('botlit.agentDetail.versions.empty', 'No version history yet.')}\n </p>\n ) : (\n <ul className=\"space-y-3\">\n {versions.map((version) => {\n const isCurrent = version.id === currentVersionId;\n const canRollback = version.status !== 'DRAFT' && !isCurrent;\n return (\n <li\n key={version.id}\n className=\"flex items-start justify-between gap-4 p-4 border border-border-subtle rounded-lg\"\n >\n <div className=\"space-y-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className=\"font-mono font-medium\">v{version.version}</span>\n <Badge variant={versionStatusVariant(version.status)}>\n {version.status}\n </Badge>\n {isCurrent && (\n <Badge variant=\"outline\" className=\"flex items-center gap-1\">\n <CheckCircle2 size={12} />\n {t('botlit.agentDetail.versions.liveNow', 'Live now')}\n </Badge>\n )}\n </div>\n <p className=\"text-sm text-text-secondary break-words\">\n {version.changelog ||\n t('botlit.agentDetail.versions.noChangelog', 'No description')}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {version.status === 'DRAFT'\n ? `${t('botlit.agentDetail.versions.updated', 'Updated')} ${formatRelativeTime(version.createdAt)}`\n : `${t('botlit.agentDetail.versions.published', 'Published')} ${formatRelativeTime(version.publishedAt ?? version.createdAt)}`}\n </p>\n </div>\n {canRollback && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n leftIcon={<RotateCcw size={14} />}\n onClick={() => setRollbackTarget(version)}\n >\n {t('botlit.agentDetail.versions.rollback', 'Roll back')}\n </Button>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </CardContent>\n </Card>\n\n {/* Publish dialog */}\n <Dialog open={publishOpen} onOpenChange={setPublishOpen}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>\n {t('botlit.agentDetail.versions.publishDialog.title', 'Publish this version')}\n </DialogTitle>\n <DialogDescription>\n {t(\n 'botlit.agentDetail.versions.publishDialog.description',\n \"This makes the draft's prompt, model, tools, and policy settings live for the agent. Describe what changed.\"\n )}\n </DialogDescription>\n </DialogHeader>\n <Textarea\n value={changelogDraft}\n onChange={(e) => setChangelogDraft(e.target.value)}\n placeholder={t(\n 'botlit.agentDetail.versions.publishDialog.placeholder',\n 'e.g. Tightened the system prompt and switched to gpt-4o'\n )}\n rows={4}\n />\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setPublishOpen(false)}>\n {t('botlit.common.cancel', 'Cancel')}\n </Button>\n <Button isLoading={publishState.loading} onClick={() => void handlePublish()}>\n {t('botlit.agentDetail.versions.publishDialog.confirm', 'Publish')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {/* Rollback confirmation */}\n <AlertDialog\n open={rollbackTarget !== null}\n onOpenChange={(open) => !open && setRollbackTarget(null)}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>\n {t('botlit.agentDetail.versions.rollbackDialog.title', 'Roll back to this version?')}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {rollbackTarget &&\n `${t('botlit.agentDetail.versions.rollbackDialog.descriptionPrefix', 'This immediately restores the agent to version')} ${rollbackTarget.version}${t('botlit.agentDetail.versions.rollbackDialog.descriptionSuffix', '. The current live config is kept in history and can be restored the same way.')}`}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel onClick={() => setRollbackTarget(null)}>\n {t('botlit.common.cancel', 'Cancel')}\n </AlertDialogCancel>\n <AlertDialogAction\n disabled={rollbackState.loading}\n onClick={() => void handleRollback()}\n >\n {t('botlit.agentDetail.versions.rollbackDialog.confirm', 'Roll back')}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"VersionHistoryPanel.js","names":[],"sources":["../../../src/botlit/components/VersionHistoryPanel.tsx"],"sourcesContent":["/**\n * Version History Panel (BOFF-4381)\n * @module botlit/components\n *\n * Real, discoverable UI for agent versioning: shows the full version\n * history (draft/published/historical), lets a workspace admin publish the\n * current draft with a changelog, and roll back to any prior published\n * version with a confirmation step.\n */\n\nimport { useState, type FC } from 'react';\nimport { History, Rocket, RotateCcw, CheckCircle2 } from 'lucide-react';\nimport { toast } from 'sonner';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from './Card';\nimport { Button } from './Button';\nimport { Badge } from './Badge';\nimport {\n useAgentVersions,\n usePublishAgentVersion,\n useRollbackAgentVersion,\n type AgentVersionRecord,\n} from '../hooks/useAgents';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { BOTMANOR_PERMISSIONS, BotmanorPermissionGate } from '../permissions';\n\ninterface VersionHistoryPanelProps {\n agentId: string;\n /** The agent's current draft version id (if any) — enables the Publish action. */\n draftVersionId?: string | null;\n /** The agent's current live (published) version id — hidden from the rollback list. */\n currentVersionId?: string | null;\n /** Called after a successful publish or rollback so the caller can refetch the agent itself. */\n onChanged?: () => void;\n}\n\nfunction versionStatusVariant(\n status: AgentVersionRecord['status']\n): 'secondary' | 'success' | 'outline' {\n if (status === 'DRAFT') return 'secondary';\n if (status === 'PUBLISHED') return 'success';\n return 'outline';\n}\n\nexport const VersionHistoryPanel: FC<VersionHistoryPanelProps> = ({\n agentId,\n draftVersionId,\n currentVersionId,\n onChanged,\n}) => {\n const t = useTr();\n\n const { data: versions, loading, refetch } = useAgentVersions(agentId);\n const [publishAgentVersion, publishState] = usePublishAgentVersion();\n const [rollbackAgentVersion, rollbackState] = useRollbackAgentVersion();\n\n const [publishOpen, setPublishOpen] = useState(false);\n const [changelogDraft, setChangelogDraft] = useState('');\n const [rollbackTarget, setRollbackTarget] = useState<AgentVersionRecord | null>(null);\n\n const handlePublish = async (): Promise<void> => {\n if (!draftVersionId) return;\n try {\n const published = await publishAgentVersion({\n agentId,\n versionId: draftVersionId,\n changelog: changelogDraft,\n });\n toast.success(\n `${t('botlit.agentDetail.versions.publishSuccessPrefix', 'Published version')} ${published.version}`\n );\n setPublishOpen(false);\n setChangelogDraft('');\n await refetch();\n onChanged?.();\n } catch (err: unknown) {\n toast.error(\n err instanceof Error\n ? err.message\n : t('botlit.agentDetail.versions.publishError', 'Failed to publish version')\n );\n }\n };\n\n const handleRollback = async (): Promise<void> => {\n if (!rollbackTarget) return;\n try {\n const restored = await rollbackAgentVersion({ agentId, targetVersionId: rollbackTarget.id });\n toast.success(\n `${t('botlit.agentDetail.versions.rollbackSuccessPrefix', 'Rolled back to version')} ${rollbackTarget.version} (${t('botlit.agentDetail.versions.rollbackSuccessSuffix', 'now')} ${restored.version})`\n );\n setRollbackTarget(null);\n await refetch();\n onChanged?.();\n } catch (err: unknown) {\n toast.error(\n err instanceof Error\n ? err.message\n : t('botlit.agentDetail.versions.rollbackError', 'Failed to roll back agent version')\n );\n }\n };\n\n return (\n <div className=\"space-y-6\">\n <Card>\n <CardHeader className=\"flex flex-row items-start justify-between gap-4\">\n <div>\n <CardTitle className=\"flex items-center gap-2\">\n <History size={18} />\n {t('botlit.agentDetail.versions.title', 'Version History')}\n </CardTitle>\n <CardDescription>\n {t(\n 'botlit.agentDetail.versions.description',\n 'Every published configuration change, with a diff-able changelog. Publish the current draft or roll back to any prior version.'\n )}\n </CardDescription>\n </div>\n {draftVersionId && (\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.AGENT_PUBLISH}>\n <Button leftIcon={<Rocket size={16} />} onClick={() => setPublishOpen(true)}>\n {t('botlit.agentDetail.versions.publishDraft', 'Publish Draft')}\n </Button>\n </BotmanorPermissionGate>\n )}\n </CardHeader>\n <CardContent>\n {loading ? (\n <div className=\"h-32 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\" />\n ) : versions.length === 0 ? (\n <p className=\"text-text-secondary\">\n {t('botlit.agentDetail.versions.empty', 'No version history yet.')}\n </p>\n ) : (\n <ul className=\"space-y-3\">\n {versions.map((version) => {\n const isCurrent = version.id === currentVersionId;\n const canRollback = version.status !== 'DRAFT' && !isCurrent;\n return (\n <li\n key={version.id}\n className=\"flex items-start justify-between gap-4 p-4 border border-border-subtle rounded-lg\"\n >\n <div className=\"space-y-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className=\"font-mono font-medium\">v{version.version}</span>\n <Badge variant={versionStatusVariant(version.status)}>\n {version.status}\n </Badge>\n {isCurrent && (\n <Badge variant=\"outline\" className=\"flex items-center gap-1\">\n <CheckCircle2 size={12} />\n {t('botlit.agentDetail.versions.liveNow', 'Live now')}\n </Badge>\n )}\n </div>\n <p className=\"text-sm text-text-secondary break-words\">\n {version.changelog ||\n t('botlit.agentDetail.versions.noChangelog', 'No description')}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {version.status === 'DRAFT'\n ? `${t('botlit.agentDetail.versions.updated', 'Updated')} ${formatRelativeTime(version.createdAt)}`\n : `${t('botlit.agentDetail.versions.published', 'Published')} ${formatRelativeTime(version.publishedAt ?? version.createdAt)}`}\n </p>\n </div>\n {canRollback && (\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.AGENT_ROLLBACK}>\n <Button\n variant=\"outline\"\n size=\"sm\"\n leftIcon={<RotateCcw size={14} />}\n onClick={() => setRollbackTarget(version)}\n >\n {t('botlit.agentDetail.versions.rollback', 'Roll back')}\n </Button>\n </BotmanorPermissionGate>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </CardContent>\n </Card>\n\n {/* Publish dialog */}\n <Dialog open={publishOpen} onOpenChange={setPublishOpen}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>\n {t('botlit.agentDetail.versions.publishDialog.title', 'Publish this version')}\n </DialogTitle>\n <DialogDescription>\n {t(\n 'botlit.agentDetail.versions.publishDialog.description',\n \"This makes the draft's prompt, model, tools, and policy settings live for the agent. Describe what changed.\"\n )}\n </DialogDescription>\n </DialogHeader>\n <Textarea\n value={changelogDraft}\n onChange={(e) => setChangelogDraft(e.target.value)}\n placeholder={t(\n 'botlit.agentDetail.versions.publishDialog.placeholder',\n 'e.g. Tightened the system prompt and switched to gpt-4o'\n )}\n rows={4}\n />\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setPublishOpen(false)}>\n {t('botlit.common.cancel', 'Cancel')}\n </Button>\n <Button isLoading={publishState.loading} onClick={() => void handlePublish()}>\n {t('botlit.agentDetail.versions.publishDialog.confirm', 'Publish')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {/* Rollback confirmation */}\n <AlertDialog\n open={rollbackTarget !== null}\n onOpenChange={(open) => !open && setRollbackTarget(null)}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>\n {t('botlit.agentDetail.versions.rollbackDialog.title', 'Roll back to this version?')}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {rollbackTarget &&\n `${t('botlit.agentDetail.versions.rollbackDialog.descriptionPrefix', 'This immediately restores the agent to version')} ${rollbackTarget.version}${t('botlit.agentDetail.versions.rollbackDialog.descriptionSuffix', '. The current live config is kept in history and can be restored the same way.')}`}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel onClick={() => setRollbackTarget(null)}>\n {t('botlit.common.cancel', 'Cancel')}\n </AlertDialogCancel>\n <AlertDialogAction\n disabled={rollbackState.loading}\n onClick={() => void handleRollback()}\n >\n {t('botlit.agentDetail.versions.rollbackDialog.confirm', 'Roll back')}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -8,6 +8,7 @@ import "./useA2A.js";
8
8
  import "./useRetrievalProfiles.js";
9
9
  import "./useChannels.js";
10
10
  import "./usePolicies.js";
11
+ import "./useRetention.js";
11
12
  import "./useSkills.js";
12
13
  import "./usePromptTemplates.js";
13
14
  import "./useExecutions.js";
@@ -0,0 +1,31 @@
1
+ import { ApplyBotmanorRetentionDocument as e, BotmanorRetentionStatusDocument as t } from "../../generated/wspace-operations.js";
2
+ import { useWorkspaceId as n, useWorkspaceMutation as r, useWorkspaceQuery as i } from "./internal/workspaceGateway.js";
3
+ //#region src/botlit/hooks/useRetention.ts
4
+ var a = {};
5
+ function o() {
6
+ return i({
7
+ document: t,
8
+ variables: a,
9
+ select: (e) => e?.botmanorRetentionStatus ?? null,
10
+ fallback: null,
11
+ enabled: !!n(),
12
+ errorMessage: "Failed to load retention status"
13
+ });
14
+ }
15
+ function s() {
16
+ let [t, n] = r({
17
+ document: e,
18
+ variables: () => ({}),
19
+ select: (e) => e?.applyBotmanorRetention,
20
+ errorMessage: "Failed to apply retention"
21
+ });
22
+ return {
23
+ apply: t,
24
+ loading: n.loading,
25
+ error: n.error
26
+ };
27
+ }
28
+ //#endregion
29
+ export { s as useApplyRetention, o as useRetentionStatus };
30
+
31
+ //# sourceMappingURL=useRetention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRetention.js","names":[],"sources":["../../../src/botlit/hooks/useRetention.ts"],"sourcesContent":["/**\n * Retention hooks (BOFF-9661)\n * @module botlit/hooks\n *\n * Reads the retention settings in force for the workspace and its recent\n * retention passes, and runs a pass on demand. Retention itself is enforced\n * hourly by wspace-botmanor-svc; `applyBotmanorRetention` only runs it now.\n */\n\nimport {\n ApplyBotmanorRetentionDocument,\n BotmanorRetentionStatusDocument,\n type ApplyBotmanorRetentionMutation,\n type BotmanorRetentionStatusQuery,\n} from '../../generated/wspace-operations';\nimport {\n useWorkspaceId,\n useWorkspaceMutation,\n useWorkspaceQuery,\n type QueryResult,\n} from './internal/workspaceGateway';\n\nconst NO_VARIABLES: Record<string, unknown> = {};\n\nexport interface RetentionRunRecord {\n id: string;\n trigger: string;\n status: string;\n executionDataRetentionDays?: number | null;\n conversationRetentionDays?: number | null;\n executionsPurged: number;\n a2aMessagesPurged: number;\n errorMessage?: string | null;\n startedAt: string;\n finishedAt: string;\n}\n\nexport interface RetentionStatusRecord {\n executionDataRetentionDays?: number | null;\n conversationRetentionDays?: number | null;\n activePolicyCount: number;\n endOfTermErasureGraceDays: number;\n recentRuns: RetentionRunRecord[];\n}\n\nexport function useRetentionStatus(): QueryResult<RetentionStatusRecord | null> {\n const workspaceId = useWorkspaceId();\n return useWorkspaceQuery<BotmanorRetentionStatusQuery, RetentionStatusRecord | null>({\n document: BotmanorRetentionStatusDocument,\n // No arguments: the workspace comes from the gateway-verified token.\n variables: NO_VARIABLES,\n select: (data) => data?.botmanorRetentionStatus ?? null,\n fallback: null,\n enabled: Boolean(workspaceId),\n errorMessage: 'Failed to load retention status',\n });\n}\n\nexport function useApplyRetention() {\n const [apply, state] = useWorkspaceMutation<\n ApplyBotmanorRetentionMutation,\n void,\n RetentionRunRecord\n >({\n document: ApplyBotmanorRetentionDocument,\n variables: () => ({}),\n select: (data) => data?.applyBotmanorRetention,\n errorMessage: 'Failed to apply retention',\n });\n return { apply, loading: state.loading, error: state.error };\n}\n"],"mappings":";;;AAsBA,IAAM,IAAwC,EAAE;AAuBhD,SAAgB,IAAgE;AAE9E,QAAO,EAA8E;EACnF,UAAU;EAEV,WAAW;EACX,SAAS,MAAS,GAAM,2BAA2B;EACnD,UAAU;EACV,SAAS,EAPS,GAAgB;EAQlC,cAAc;EACf,CAAC;;AAGJ,SAAgB,IAAoB;CAClC,IAAM,CAAC,GAAO,KAAS,EAIrB;EACA,UAAU;EACV,kBAAkB,EAAE;EACpB,SAAS,MAAS,GAAM;EACxB,cAAc;EACf,CAAC;AACF,QAAO;EAAE;EAAO,SAAS,EAAM;EAAS,OAAO,EAAM;EAAO"}