@burdenoff/microfe-botmanor 2026.1027.3 → 2026.1029.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.
@@ -0,0 +1,95 @@
1
+ import { formatRelativeTime as e } from "../utils/formatters.js";
2
+ import { BOTMANOR_PERMISSIONS as t } from "../permissions/botmanorPermissions.js";
3
+ import { BotmanorPermissionGate as n } from "../permissions/useBotmanorPermissions.js";
4
+ import { Button as r } from "./Button.js";
5
+ import "../permissions/index.js";
6
+ import { Card as i, CardContent as a, CardDescription as o, CardHeader as s, CardTitle as c } from "./Card.js";
7
+ import { Badge as l } from "./Badge.js";
8
+ import { useApplyRetention as u, useRetentionStatus as d } from "../hooks/useRetention.js";
9
+ import "../hooks/index.js";
10
+ import { jsx as f, jsxs as p } from "react/jsx-runtime";
11
+ import { Archive as m, RefreshCw as h } from "lucide-react";
12
+ import { toast as g } from "sonner";
13
+ //#region src/botlit/components/RetentionStatusPanel.tsx
14
+ function _(e, t) {
15
+ return e == null ? "Kept for the life of the workspace" : e === 0 ? t : `${e} day${e === 1 ? "" : "s"}`;
16
+ }
17
+ var v = () => {
18
+ let { data: v, loading: y, error: b, refetch: x } = d(), { apply: S, loading: C } = u(), w = async () => {
19
+ try {
20
+ let e = await S();
21
+ e.status === "COMPLETED" ? g.success(`Retention applied: ${e.executionsPurged} run payloads and ${e.a2aMessagesPurged} agent messages erased`) : g.error(e.errorMessage ?? "The retention pass failed");
22
+ } catch (e) {
23
+ g.error(e instanceof Error ? e.message : "Failed to apply retention");
24
+ }
25
+ await x();
26
+ };
27
+ if (b) return null;
28
+ let T = v?.recentRuns[0];
29
+ return /* @__PURE__ */ p(i, {
30
+ "data-testid": "retention-status-panel",
31
+ children: [/* @__PURE__ */ f(s, {
32
+ className: "pb-2",
33
+ children: /* @__PURE__ */ p("div", {
34
+ className: "flex flex-wrap items-start justify-between gap-3",
35
+ children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ p(c, {
36
+ className: "flex items-center gap-2 text-base",
37
+ children: [/* @__PURE__ */ f(m, { size: 18 }), "Data retention"]
38
+ }), /* @__PURE__ */ p(o, { children: [
39
+ "Active retention policies are enforced every hour. When a workspace is deleted, its BotManor data is erased after",
40
+ " ",
41
+ v ? `${v.endOfTermErasureGraceDays} days` : "the grace period",
42
+ "."
43
+ ] })] }), /* @__PURE__ */ f(n, {
44
+ permission: t.POLICY_UPDATE,
45
+ children: /* @__PURE__ */ f(r, {
46
+ variant: "outline",
47
+ size: "sm",
48
+ leftIcon: /* @__PURE__ */ f(h, { size: 14 }),
49
+ onClick: () => void w(),
50
+ isLoading: C,
51
+ disabled: y || !v || v.activePolicyCount === 0,
52
+ children: "Apply now"
53
+ })
54
+ })]
55
+ })
56
+ }), /* @__PURE__ */ f(a, { children: y && !v ? /* @__PURE__ */ f("div", { className: "h-16 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }) : v ? /* @__PURE__ */ p("div", {
57
+ className: "grid grid-cols-1 sm:grid-cols-3 gap-4 text-sm",
58
+ children: [
59
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
60
+ className: "text-text-secondary",
61
+ children: "Run inputs and outputs"
62
+ }), /* @__PURE__ */ f("p", {
63
+ className: "font-medium",
64
+ "data-testid": "retention-execution-days",
65
+ children: _(v.executionDataRetentionDays, "Erased when the run ends")
66
+ })] }),
67
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
68
+ className: "text-text-secondary",
69
+ children: "Assistant conversations"
70
+ }), /* @__PURE__ */ f("p", {
71
+ className: "font-medium",
72
+ "data-testid": "retention-conversation-days",
73
+ children: _(v.conversationRetentionDays, "Erased when the run ends")
74
+ })] }),
75
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
76
+ className: "text-text-secondary",
77
+ children: "Last pass"
78
+ }), T ? /* @__PURE__ */ p("p", {
79
+ className: "font-medium flex flex-wrap items-center gap-2",
80
+ children: [/* @__PURE__ */ f("span", { children: e(T.finishedAt) }), /* @__PURE__ */ f(l, {
81
+ variant: T.status === "COMPLETED" ? "success" : "destructive",
82
+ children: T.status === "COMPLETED" ? `${T.executionsPurged + T.a2aMessagesPurged} erased` : "Failed"
83
+ })]
84
+ }) : /* @__PURE__ */ f("p", {
85
+ className: "font-medium",
86
+ children: v.activePolicyCount === 0 ? "No active retention policy" : "Not run yet"
87
+ })] })
88
+ ]
89
+ }) : null })]
90
+ });
91
+ };
92
+ //#endregion
93
+ export { v as RetentionStatusPanel };
94
+
95
+ //# sourceMappingURL=RetentionStatusPanel.js.map
@@ -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"}
@@ -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"}
@@ -13,25 +13,26 @@ import { Input as m } from "../components/Input.js";
13
13
  import { ErrorState as h } from "../components/ErrorState.js";
14
14
  import { usePolicies as g } from "../hooks/usePolicies.js";
15
15
  import "../hooks/index.js";
16
- import { useState as _ } from "react";
17
- import { GlassCard as v, PagePurpose as y } from "@burdenoff/fe-libs/ui";
18
- import { jsx as b, jsxs as x } from "react/jsx-runtime";
19
- import { Link as S } from "react-router";
20
- import { AlertTriangle as C, Clock as w, Database as T, DollarSign as E, Filter as D, MessageSquare as O, Plus as k, Search as A, Shield as j, Trash2 as M, Wrench as N } from "lucide-react";
16
+ import { RetentionStatusPanel as _ } from "../components/RetentionStatusPanel.js";
17
+ import { useState as v } from "react";
18
+ import { GlassCard as y, PagePurpose as b } from "@burdenoff/fe-libs/ui";
19
+ import { jsx as x, jsxs as S } from "react/jsx-runtime";
20
+ import { Link as C } from "react-router";
21
+ import { AlertTriangle as w, Clock as T, Database as E, DollarSign as D, Filter as O, MessageSquare as k, Plus as A, Search as j, Shield as M, Trash2 as N, Wrench as P } from "lucide-react";
21
22
  //#region src/botlit/pages/PoliciesPage.tsx
22
- var P = ({ type: e, className: t }) => {
23
+ var F = ({ type: e, className: t }) => {
23
24
  switch (e) {
24
- case "CONTENT": return /* @__PURE__ */ b(C, { className: t });
25
- case "TOOL": return /* @__PURE__ */ b(N, { className: t });
26
- case "DATA": return /* @__PURE__ */ b(T, { className: t });
27
- case "RESPONSE": return /* @__PURE__ */ b(O, { className: t });
28
- case "BUDGET": return /* @__PURE__ */ b(E, { className: t });
29
- case "RATE_LIMIT": return /* @__PURE__ */ b(w, { className: t });
30
- case "RETENTION": return /* @__PURE__ */ b(M, { className: t });
31
- default: return /* @__PURE__ */ b(j, { className: t });
25
+ case "CONTENT": return /* @__PURE__ */ x(w, { className: t });
26
+ case "TOOL": return /* @__PURE__ */ x(P, { className: t });
27
+ case "DATA": return /* @__PURE__ */ x(E, { className: t });
28
+ case "RESPONSE": return /* @__PURE__ */ x(k, { className: t });
29
+ case "BUDGET": return /* @__PURE__ */ x(D, { className: t });
30
+ case "RATE_LIMIT": return /* @__PURE__ */ x(T, { className: t });
31
+ case "RETENTION": return /* @__PURE__ */ x(N, { className: t });
32
+ default: return /* @__PURE__ */ x(M, { className: t });
32
33
  }
33
34
  };
34
- function F(e) {
35
+ function I(e) {
35
36
  return {
36
37
  CONTENT: e("botlit.policies.typeLabel.CONTENT", "Content Safety"),
37
38
  TOOL: e("botlit.policies.typeLabel.TOOL", "Tool Access"),
@@ -42,35 +43,36 @@ function F(e) {
42
43
  RETENTION: e("botlit.policies.typeLabel.RETENTION", "Data Retention")
43
44
  };
44
45
  }
45
- var I = () => {
46
- let C = e(), { getPath: w } = t(), [T, E] = _(""), [O, M] = _(null), { data: N, loading: I, error: L, refetch: R } = g({ search: T }), z = F(C), B = O ? N.filter((e) => e.type === O) : N;
47
- return /* @__PURE__ */ b(a, {
48
- title: C("botlit.policies.title", "Policies & Guardrails"),
49
- description: C("botlit.policies.description", "Configure safety rules, access controls, and operational limits"),
50
- actions: /* @__PURE__ */ b(i, {
46
+ var L = () => {
47
+ let w = e(), { getPath: T } = t(), [E, D] = v(""), [k, N] = v(null), { data: P, loading: L, error: R, refetch: z } = g({ search: E }), B = I(w), V = k ? P.filter((e) => e.type === k) : P;
48
+ return /* @__PURE__ */ x(a, {
49
+ title: w("botlit.policies.title", "Policies & Guardrails"),
50
+ description: w("botlit.policies.description", "Configure safety rules, access controls, and operational limits"),
51
+ actions: /* @__PURE__ */ x(i, {
51
52
  permission: r.POLICY_CREATE,
52
- children: /* @__PURE__ */ b(o, {
53
- leftIcon: /* @__PURE__ */ b(k, { size: 16 }),
54
- children: /* @__PURE__ */ b(S, {
55
- to: w("policies/new"),
56
- children: C("botlit.policies.actions.createPolicy", "Create Policy")
53
+ children: /* @__PURE__ */ x(o, {
54
+ leftIcon: /* @__PURE__ */ x(A, { size: 16 }),
55
+ children: /* @__PURE__ */ x(C, {
56
+ to: T("policies/new"),
57
+ children: w("botlit.policies.actions.createPolicy", "Create Policy")
57
58
  })
58
59
  })
59
60
  }),
60
- children: /* @__PURE__ */ x("div", {
61
+ children: /* @__PURE__ */ S("div", {
61
62
  className: "space-y-6",
62
63
  children: [
63
- /* @__PURE__ */ b(y, {
64
- icon: /* @__PURE__ */ b(j, { size: 18 }),
65
- children: C("botlit.policies.purpose", "Policies are the guardrails that keep your agents safe and within budget. Each policy enforces one kind of rule — blocking harmful content or PII, restricting which tools an agent may call, capping token spend, or rate-limiting requests. Define policies here and attach them to agents so every execution stays compliant and predictable.")
64
+ /* @__PURE__ */ x(b, {
65
+ icon: /* @__PURE__ */ x(M, { size: 18 }),
66
+ children: w("botlit.policies.purpose", "Policies are the guardrails that keep your agents safe and within budget. Each policy enforces one kind of rule — blocking harmful content or PII, restricting which tools an agent may call, capping token spend, or rate-limiting requests. Define policies here and attach them to agents so every execution stays compliant and predictable.")
66
67
  }),
67
- /* @__PURE__ */ x("div", {
68
+ /* @__PURE__ */ x(_, {}),
69
+ /* @__PURE__ */ S("div", {
68
70
  className: "flex flex-wrap gap-2",
69
- children: [/* @__PURE__ */ b(o, {
70
- variant: O === null ? "default" : "outline",
71
+ children: [/* @__PURE__ */ x(o, {
72
+ variant: k === null ? "default" : "outline",
71
73
  size: "sm",
72
- onClick: () => M(null),
73
- children: C("botlit.store.filters.all", "All")
74
+ onClick: () => N(null),
75
+ children: w("botlit.store.filters.all", "All")
74
76
  }), [
75
77
  "CONTENT",
76
78
  "TOOL",
@@ -79,34 +81,34 @@ var I = () => {
79
81
  "BUDGET",
80
82
  "RATE_LIMIT",
81
83
  "RETENTION"
82
- ].map((e) => /* @__PURE__ */ b(o, {
83
- variant: O === e ? "default" : "outline",
84
+ ].map((e) => /* @__PURE__ */ x(o, {
85
+ variant: k === e ? "default" : "outline",
84
86
  size: "sm",
85
- onClick: () => M(e),
86
- leftIcon: /* @__PURE__ */ b(P, {
87
+ onClick: () => N(e),
88
+ leftIcon: /* @__PURE__ */ x(F, {
87
89
  type: e,
88
90
  className: "h-4 w-4"
89
91
  }),
90
- children: z[e]
92
+ children: B[e]
91
93
  }, e))]
92
94
  }),
93
- /* @__PURE__ */ x("div", {
95
+ /* @__PURE__ */ S("div", {
94
96
  className: "flex items-center gap-4",
95
- children: [/* @__PURE__ */ x("div", {
97
+ children: [/* @__PURE__ */ S("div", {
96
98
  className: "relative flex-1 max-w-md",
97
- children: [/* @__PURE__ */ b(A, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ b(m, {
98
- placeholder: C("botlit.policies.searchPlaceholder", "Search policies..."),
99
- value: T,
100
- onChange: (e) => E(e.target.value),
99
+ children: [/* @__PURE__ */ x(j, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ x(m, {
100
+ placeholder: w("botlit.policies.searchPlaceholder", "Search policies..."),
101
+ value: E,
102
+ onChange: (e) => D(e.target.value),
101
103
  className: "pl-9"
102
104
  })]
103
- }), /* @__PURE__ */ b(o, {
105
+ }), /* @__PURE__ */ x(o, {
104
106
  variant: "outline",
105
- leftIcon: /* @__PURE__ */ b(D, { size: 16 }),
106
- children: C("botlit.policies.actions.moreFilters", "More Filters")
107
+ leftIcon: /* @__PURE__ */ x(O, { size: 16 }),
108
+ children: w("botlit.policies.actions.moreFilters", "More Filters")
107
109
  })]
108
110
  }),
109
- I ? /* @__PURE__ */ b("div", {
111
+ L ? /* @__PURE__ */ x("div", {
110
112
  className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",
111
113
  children: [
112
114
  1,
@@ -115,47 +117,47 @@ var I = () => {
115
117
  4,
116
118
  5,
117
119
  6
118
- ].map((e) => /* @__PURE__ */ b("div", { className: "h-40 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }, e))
119
- }) : L ? /* @__PURE__ */ b(h, {
120
+ ].map((e) => /* @__PURE__ */ x("div", { className: "h-40 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }, e))
121
+ }) : R ? /* @__PURE__ */ x(h, {
120
122
  resource: "policies",
121
- error: L,
122
- onRetry: () => void R()
123
- }) : B.length > 0 ? /* @__PURE__ */ b("div", {
123
+ error: R,
124
+ onRetry: () => void z()
125
+ }) : V.length > 0 ? /* @__PURE__ */ x("div", {
124
126
  className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",
125
- children: B.map((e) => /* @__PURE__ */ b(S, {
126
- to: w(`policies/${e.id}`),
127
- children: /* @__PURE__ */ x(s, {
127
+ children: V.map((e) => /* @__PURE__ */ x(C, {
128
+ to: T(`policies/${e.id}`),
129
+ children: /* @__PURE__ */ S(s, {
128
130
  className: "h-full hover:border-primary/50 transition-colors cursor-pointer",
129
- children: [/* @__PURE__ */ b(l, {
131
+ children: [/* @__PURE__ */ x(l, {
130
132
  className: "pb-2",
131
- children: /* @__PURE__ */ x("div", {
133
+ children: /* @__PURE__ */ S("div", {
132
134
  className: "flex items-start justify-between",
133
- children: [/* @__PURE__ */ x("div", {
135
+ children: [/* @__PURE__ */ S("div", {
134
136
  className: "flex items-center gap-3",
135
- children: [/* @__PURE__ */ b("div", {
137
+ children: [/* @__PURE__ */ x("div", {
136
138
  className: `p-2 rounded-lg ${e.type === "CONTENT" ? "bg-status-error-bg-subtle" : e.type === "TOOL" ? "bg-status-info-bg-subtle" : e.type === "BUDGET" ? "bg-status-warning-bg-subtle" : "bg-action-primary-bg/10"}`,
137
- children: /* @__PURE__ */ b(P, {
139
+ children: /* @__PURE__ */ x(F, {
138
140
  type: e.type,
139
141
  className: `h-5 w-5 ${e.type === "CONTENT" ? "text-status-error-text" : e.type === "TOOL" ? "text-status-info-text" : e.type === "BUDGET" ? "text-status-warning-text" : "text-primary"}`
140
142
  })
141
- }), /* @__PURE__ */ b("div", { children: /* @__PURE__ */ b(u, {
143
+ }), /* @__PURE__ */ x("div", { children: /* @__PURE__ */ x(u, {
142
144
  className: "text-base",
143
145
  children: e.name
144
146
  }) })]
145
- }), /* @__PURE__ */ b(f, { status: e.status })]
147
+ }), /* @__PURE__ */ x(f, { status: e.status })]
146
148
  })
147
- }), /* @__PURE__ */ b(c, { children: /* @__PURE__ */ x("div", {
149
+ }), /* @__PURE__ */ x(c, { children: /* @__PURE__ */ S("div", {
148
150
  className: "space-y-3",
149
- children: [/* @__PURE__ */ b("p", {
151
+ children: [/* @__PURE__ */ x("p", {
150
152
  className: "text-sm text-text-secondary line-clamp-2",
151
153
  children: e.description
152
- }), /* @__PURE__ */ x("div", {
154
+ }), /* @__PURE__ */ S("div", {
153
155
  className: "flex items-center justify-between",
154
- children: [/* @__PURE__ */ b(d, {
156
+ children: [/* @__PURE__ */ x(d, {
155
157
  variant: "outline",
156
158
  className: "text-xs",
157
- children: z[e.type]
158
- }), /* @__PURE__ */ b("span", {
159
+ children: B[e.type]
160
+ }), /* @__PURE__ */ x("span", {
159
161
  className: "text-xs text-text-secondary",
160
162
  children: n(e.createdAt)
161
163
  })]
@@ -163,65 +165,65 @@ var I = () => {
163
165
  }) })]
164
166
  })
165
167
  }, e.id))
166
- }) : /* @__PURE__ */ b(p, {
168
+ }) : /* @__PURE__ */ x(p, {
167
169
  illustration: "empty-generic",
168
- title: O ? C("botlit.policies.empty.titleNoType", "No {{type}} policies", { type: z[O] }) : C("botlit.policies.empty.title", "No policies"),
169
- description: C("botlit.policies.empty.description", "Create policies to enforce safety rules and operational limits across your agents."),
170
- action: /* @__PURE__ */ b(i, {
170
+ title: k ? w("botlit.policies.empty.titleNoType", "No {{type}} policies", { type: B[k] }) : w("botlit.policies.empty.title", "No policies"),
171
+ description: w("botlit.policies.empty.description", "Create policies to enforce safety rules and operational limits across your agents."),
172
+ action: /* @__PURE__ */ x(i, {
171
173
  permission: r.POLICY_CREATE,
172
- children: /* @__PURE__ */ b(o, {
173
- leftIcon: /* @__PURE__ */ b(k, { size: 16 }),
174
- children: /* @__PURE__ */ b(S, {
175
- to: w("policies/new"),
176
- children: C("botlit.policies.actions.createPolicy", "Create Policy")
174
+ children: /* @__PURE__ */ x(o, {
175
+ leftIcon: /* @__PURE__ */ x(A, { size: 16 }),
176
+ children: /* @__PURE__ */ x(C, {
177
+ to: T("policies/new"),
178
+ children: w("botlit.policies.actions.createPolicy", "Create Policy")
177
179
  })
178
180
  })
179
181
  })
180
182
  }),
181
- /* @__PURE__ */ x(v, {
183
+ /* @__PURE__ */ S(y, {
182
184
  treatment: "glass",
183
185
  glow: !0,
184
186
  className: "p-6",
185
- children: [/* @__PURE__ */ x("div", {
187
+ children: [/* @__PURE__ */ S("div", {
186
188
  className: "mb-4",
187
- children: [/* @__PURE__ */ b("h2", {
189
+ children: [/* @__PURE__ */ x("h2", {
188
190
  className: "text-lg font-semibold tracking-tight text-text-primary",
189
- children: C("botlit.policies.overview.title", "Policy Types")
190
- }), /* @__PURE__ */ b("p", {
191
+ children: w("botlit.policies.overview.title", "Policy Types")
192
+ }), /* @__PURE__ */ x("p", {
191
193
  className: "text-sm text-text-secondary",
192
- children: C("botlit.policies.overview.description", "Different policy types control different aspects of agent behavior")
194
+ children: w("botlit.policies.overview.description", "Different policy types control different aspects of agent behavior")
193
195
  })]
194
- }), /* @__PURE__ */ b("div", {
196
+ }), /* @__PURE__ */ x("div", {
195
197
  className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4",
196
198
  children: [
197
199
  {
198
200
  type: "CONTENT",
199
- desc: C("botlit.policies.overview.contentDescription", "Detect and block harmful content, jailbreaks, and PII")
201
+ desc: w("botlit.policies.overview.contentDescription", "Detect and block harmful content, jailbreaks, and PII")
200
202
  },
201
203
  {
202
204
  type: "TOOL",
203
- desc: C("botlit.policies.overview.toolDescription", "Control which tools agents can access and use")
205
+ desc: w("botlit.policies.overview.toolDescription", "Control which tools agents can access and use")
204
206
  },
205
207
  {
206
208
  type: "BUDGET",
207
- desc: C("botlit.policies.overview.budgetDescription", "Set token limits and cost caps per execution")
209
+ desc: w("botlit.policies.overview.budgetDescription", "Set token limits and cost caps per execution")
208
210
  },
209
211
  {
210
212
  type: "RATE_LIMIT",
211
- desc: C("botlit.policies.overview.rateLimitDescription", "Limit request frequency to prevent abuse")
213
+ desc: w("botlit.policies.overview.rateLimitDescription", "Limit request frequency to prevent abuse")
212
214
  }
213
- ].map((e) => /* @__PURE__ */ x("div", {
215
+ ].map((e) => /* @__PURE__ */ S("div", {
214
216
  className: "p-4 border border-border-subtle rounded-lg",
215
- children: [/* @__PURE__ */ x("div", {
217
+ children: [/* @__PURE__ */ S("div", {
216
218
  className: "flex items-center gap-2 mb-2",
217
- children: [/* @__PURE__ */ b(P, {
219
+ children: [/* @__PURE__ */ x(F, {
218
220
  type: e.type,
219
221
  className: "h-5 w-5 text-primary"
220
- }), /* @__PURE__ */ b("span", {
222
+ }), /* @__PURE__ */ x("span", {
221
223
  className: "font-medium",
222
- children: z[e.type]
224
+ children: B[e.type]
223
225
  })]
224
- }), /* @__PURE__ */ b("p", {
226
+ }), /* @__PURE__ */ x("p", {
225
227
  className: "text-sm text-text-secondary",
226
228
  children: e.desc
227
229
  })]
@@ -233,6 +235,6 @@ var I = () => {
233
235
  });
234
236
  };
235
237
  //#endregion
236
- export { I as PoliciesPage };
238
+ export { L as PoliciesPage };
237
239
 
238
240
  //# sourceMappingURL=PoliciesPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PoliciesPage.js","names":[],"sources":["../../../src/botlit/pages/PoliciesPage.tsx"],"sourcesContent":["/**\n * Policies Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { Link } from 'react-router';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport {\n Plus,\n Search as SearchIcon,\n Filter,\n Shield,\n Wrench,\n Database,\n MessageSquare,\n DollarSign,\n Clock,\n Trash2,\n AlertTriangle,\n} from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input } from '../components/Input';\nimport { Badge, StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorState } from '../components/ErrorState';\nimport { usePolicies, type PolicyRecord } from '../hooks';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { PolicyType } from '../types';\nimport { BOTMANOR_PERMISSIONS, BotmanorPermissionGate } from '../permissions';\n\nconst PolicyTypeIcon: FC<{ type: string; className?: string }> = ({ type, className }) => {\n switch (type) {\n case 'CONTENT':\n return <AlertTriangle className={className} />;\n case 'TOOL':\n return <Wrench className={className} />;\n case 'DATA':\n return <Database className={className} />;\n case 'RESPONSE':\n return <MessageSquare className={className} />;\n case 'BUDGET':\n return <DollarSign className={className} />;\n case 'RATE_LIMIT':\n return <Clock className={className} />;\n case 'RETENTION':\n return <Trash2 className={className} />;\n default:\n return <Shield className={className} />;\n }\n};\n\nfunction usePolicyTypeLabel(t: ReturnType<typeof useTr>): Record<string, string> {\n return {\n CONTENT: t('botlit.policies.typeLabel.CONTENT', 'Content Safety'),\n TOOL: t('botlit.policies.typeLabel.TOOL', 'Tool Access'),\n DATA: t('botlit.policies.typeLabel.DATA', 'Data Access'),\n // New key: the platform i18n store already holds a row for the old\n // `typeLabel.RESPONSE` key (\"Response Format\") and that row wins.\n RESPONSE: t('botlit.policies.typeLabel.RESPONSE_MODELS', 'Response & Models'),\n BUDGET: t('botlit.policies.typeLabel.BUDGET', 'Budget Limits'),\n RATE_LIMIT: t('botlit.policies.typeLabel.RATE_LIMIT', 'Rate Limiting'),\n RETENTION: t('botlit.policies.typeLabel.RETENTION', 'Data Retention'),\n };\n}\n\nexport const PoliciesPage: FC = () => {\n const t = useTr();\n const { getPath } = useBotlit();\n const [search, setSearch] = useState('');\n const [selectedType, setSelectedType] = useState<PolicyType | null>(null);\n const { data: policies, loading, error, refetch } = usePolicies({ search });\n const policyTypeLabel = usePolicyTypeLabel(t);\n\n const filteredPolicies = selectedType\n ? policies.filter((policy) => policy.type === selectedType)\n : policies;\n\n const policyTypes: PolicyType[] = [\n 'CONTENT',\n 'TOOL',\n 'DATA',\n 'RESPONSE',\n 'BUDGET',\n 'RATE_LIMIT',\n 'RETENTION',\n ];\n\n return (\n <PageLayout\n title={t('botlit.policies.title', 'Policies & Guardrails')}\n description={t(\n 'botlit.policies.description',\n 'Configure safety rules, access controls, and operational limits'\n )}\n actions={\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.POLICY_CREATE}>\n <Button leftIcon={<Plus size={16} />}>\n <Link to={getPath('policies/new')}>\n {t('botlit.policies.actions.createPolicy', 'Create Policy')}\n </Link>\n </Button>\n </BotmanorPermissionGate>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Shield size={18} />}>\n {t(\n 'botlit.policies.purpose',\n 'Policies are the guardrails that keep your agents safe and within budget. Each policy enforces one kind of rule — blocking harmful content or PII, restricting which tools an agent may call, capping token spend, or rate-limiting requests. Define policies here and attach them to agents so every execution stays compliant and predictable.'\n )}\n </PagePurpose>\n\n {/* Policy Type Filters */}\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant={selectedType === null ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setSelectedType(null)}\n >\n {t('botlit.store.filters.all', 'All')}\n </Button>\n {policyTypes.map((type) => (\n <Button\n key={type}\n variant={selectedType === type ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setSelectedType(type)}\n leftIcon={<PolicyTypeIcon type={type} className=\"h-4 w-4\" />}\n >\n {policyTypeLabel[type]}\n </Button>\n ))}\n </div>\n\n {/* Search */}\n <div className=\"flex items-center gap-4\">\n <div className=\"relative flex-1 max-w-md\">\n <SearchIcon className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder={t('botlit.policies.searchPlaceholder', 'Search policies...')}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <Button variant=\"outline\" leftIcon={<Filter size={16} />}>\n {t('botlit.policies.actions.moreFilters', 'More Filters')}\n </Button>\n </div>\n\n {/* Policies List */}\n {loading ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {[1, 2, 3, 4, 5, 6].map((i) => (\n <div\n key={i}\n className=\"h-40 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\"\n />\n ))}\n </div>\n ) : error ? (\n <ErrorState resource=\"policies\" error={error} onRetry={() => void refetch()} />\n ) : filteredPolicies.length > 0 ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredPolicies.map((policy: PolicyRecord) => (\n <Link key={policy.id} to={getPath(`policies/${policy.id}`)}>\n <Card className=\"h-full hover:border-primary/50 transition-colors cursor-pointer\">\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div\n className={`p-2 rounded-lg ${\n policy.type === 'CONTENT'\n ? 'bg-status-error-bg-subtle'\n : policy.type === 'TOOL'\n ? 'bg-status-info-bg-subtle'\n : policy.type === 'BUDGET'\n ? 'bg-status-warning-bg-subtle'\n : 'bg-action-primary-bg/10'\n }`}\n >\n <PolicyTypeIcon\n type={policy.type}\n className={`h-5 w-5 ${\n policy.type === 'CONTENT'\n ? 'text-status-error-text'\n : policy.type === 'TOOL'\n ? 'text-status-info-text'\n : policy.type === 'BUDGET'\n ? 'text-status-warning-text'\n : 'text-primary'\n }`}\n />\n </div>\n <div>\n <CardTitle className=\"text-base\">{policy.name}</CardTitle>\n </div>\n </div>\n <StatusBadge status={policy.status} />\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n <p className=\"text-sm text-text-secondary line-clamp-2\">\n {policy.description}\n </p>\n\n {/* Type Badge */}\n <div className=\"flex items-center justify-between\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {policyTypeLabel[policy.type]}\n </Badge>\n <span className=\"text-xs text-text-secondary\">\n {formatRelativeTime(policy.createdAt)}\n </span>\n </div>\n </div>\n </CardContent>\n </Card>\n </Link>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n title={\n selectedType\n ? t('botlit.policies.empty.titleNoType', 'No {{type}} policies', {\n type: policyTypeLabel[selectedType],\n })\n : t('botlit.policies.empty.title', 'No policies')\n }\n description={t(\n 'botlit.policies.empty.description',\n 'Create policies to enforce safety rules and operational limits across your agents.'\n )}\n action={\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.POLICY_CREATE}>\n <Button leftIcon={<Plus size={16} />}>\n <Link to={getPath('policies/new')}>\n {t('botlit.policies.actions.createPolicy', 'Create Policy')}\n </Link>\n </Button>\n </BotmanorPermissionGate>\n }\n />\n )}\n\n {/* Policy Types Guide */}\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <div className=\"mb-4\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary\">\n {t('botlit.policies.overview.title', 'Policy Types')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'botlit.policies.overview.description',\n 'Different policy types control different aspects of agent behavior'\n )}\n </p>\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4\">\n {[\n {\n type: 'CONTENT' as PolicyType,\n desc: t(\n 'botlit.policies.overview.contentDescription',\n 'Detect and block harmful content, jailbreaks, and PII'\n ),\n },\n {\n type: 'TOOL' as PolicyType,\n desc: t(\n 'botlit.policies.overview.toolDescription',\n 'Control which tools agents can access and use'\n ),\n },\n {\n type: 'BUDGET' as PolicyType,\n desc: t(\n 'botlit.policies.overview.budgetDescription',\n 'Set token limits and cost caps per execution'\n ),\n },\n {\n type: 'RATE_LIMIT' as PolicyType,\n desc: t(\n 'botlit.policies.overview.rateLimitDescription',\n 'Limit request frequency to prevent abuse'\n ),\n },\n ].map((item) => (\n <div key={item.type} className=\"p-4 border border-border-subtle rounded-lg\">\n <div className=\"flex items-center gap-2 mb-2\">\n <PolicyTypeIcon type={item.type} className=\"h-5 w-5 text-primary\" />\n <span className=\"font-medium\">{policyTypeLabel[item.type]}</span>\n </div>\n <p className=\"text-sm text-text-secondary\">{item.desc}</p>\n </div>\n ))}\n </div>\n </GlassCard>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"PoliciesPage.js","names":[],"sources":["../../../src/botlit/pages/PoliciesPage.tsx"],"sourcesContent":["/**\n * Policies Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { Link } from 'react-router';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport {\n Plus,\n Search as SearchIcon,\n Filter,\n Shield,\n Wrench,\n Database,\n MessageSquare,\n DollarSign,\n Clock,\n Trash2,\n AlertTriangle,\n} from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input } from '../components/Input';\nimport { Badge, StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorState } from '../components/ErrorState';\nimport { usePolicies, type PolicyRecord } from '../hooks';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { PolicyType } from '../types';\nimport { BOTMANOR_PERMISSIONS, BotmanorPermissionGate } from '../permissions';\nimport { RetentionStatusPanel } from '../components/RetentionStatusPanel';\n\nconst PolicyTypeIcon: FC<{ type: string; className?: string }> = ({ type, className }) => {\n switch (type) {\n case 'CONTENT':\n return <AlertTriangle className={className} />;\n case 'TOOL':\n return <Wrench className={className} />;\n case 'DATA':\n return <Database className={className} />;\n case 'RESPONSE':\n return <MessageSquare className={className} />;\n case 'BUDGET':\n return <DollarSign className={className} />;\n case 'RATE_LIMIT':\n return <Clock className={className} />;\n case 'RETENTION':\n return <Trash2 className={className} />;\n default:\n return <Shield className={className} />;\n }\n};\n\nfunction usePolicyTypeLabel(t: ReturnType<typeof useTr>): Record<string, string> {\n return {\n CONTENT: t('botlit.policies.typeLabel.CONTENT', 'Content Safety'),\n TOOL: t('botlit.policies.typeLabel.TOOL', 'Tool Access'),\n DATA: t('botlit.policies.typeLabel.DATA', 'Data Access'),\n // New key: the platform i18n store already holds a row for the old\n // `typeLabel.RESPONSE` key (\"Response Format\") and that row wins.\n RESPONSE: t('botlit.policies.typeLabel.RESPONSE_MODELS', 'Response & Models'),\n BUDGET: t('botlit.policies.typeLabel.BUDGET', 'Budget Limits'),\n RATE_LIMIT: t('botlit.policies.typeLabel.RATE_LIMIT', 'Rate Limiting'),\n RETENTION: t('botlit.policies.typeLabel.RETENTION', 'Data Retention'),\n };\n}\n\nexport const PoliciesPage: FC = () => {\n const t = useTr();\n const { getPath } = useBotlit();\n const [search, setSearch] = useState('');\n const [selectedType, setSelectedType] = useState<PolicyType | null>(null);\n const { data: policies, loading, error, refetch } = usePolicies({ search });\n const policyTypeLabel = usePolicyTypeLabel(t);\n\n const filteredPolicies = selectedType\n ? policies.filter((policy) => policy.type === selectedType)\n : policies;\n\n const policyTypes: PolicyType[] = [\n 'CONTENT',\n 'TOOL',\n 'DATA',\n 'RESPONSE',\n 'BUDGET',\n 'RATE_LIMIT',\n 'RETENTION',\n ];\n\n return (\n <PageLayout\n title={t('botlit.policies.title', 'Policies & Guardrails')}\n description={t(\n 'botlit.policies.description',\n 'Configure safety rules, access controls, and operational limits'\n )}\n actions={\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.POLICY_CREATE}>\n <Button leftIcon={<Plus size={16} />}>\n <Link to={getPath('policies/new')}>\n {t('botlit.policies.actions.createPolicy', 'Create Policy')}\n </Link>\n </Button>\n </BotmanorPermissionGate>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Shield size={18} />}>\n {t(\n 'botlit.policies.purpose',\n 'Policies are the guardrails that keep your agents safe and within budget. Each policy enforces one kind of rule — blocking harmful content or PII, restricting which tools an agent may call, capping token spend, or rate-limiting requests. Define policies here and attach them to agents so every execution stays compliant and predictable.'\n )}\n </PagePurpose>\n\n <RetentionStatusPanel />\n\n {/* Policy Type Filters */}\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant={selectedType === null ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setSelectedType(null)}\n >\n {t('botlit.store.filters.all', 'All')}\n </Button>\n {policyTypes.map((type) => (\n <Button\n key={type}\n variant={selectedType === type ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setSelectedType(type)}\n leftIcon={<PolicyTypeIcon type={type} className=\"h-4 w-4\" />}\n >\n {policyTypeLabel[type]}\n </Button>\n ))}\n </div>\n\n {/* Search */}\n <div className=\"flex items-center gap-4\">\n <div className=\"relative flex-1 max-w-md\">\n <SearchIcon className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder={t('botlit.policies.searchPlaceholder', 'Search policies...')}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <Button variant=\"outline\" leftIcon={<Filter size={16} />}>\n {t('botlit.policies.actions.moreFilters', 'More Filters')}\n </Button>\n </div>\n\n {/* Policies List */}\n {loading ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {[1, 2, 3, 4, 5, 6].map((i) => (\n <div\n key={i}\n className=\"h-40 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\"\n />\n ))}\n </div>\n ) : error ? (\n <ErrorState resource=\"policies\" error={error} onRetry={() => void refetch()} />\n ) : filteredPolicies.length > 0 ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredPolicies.map((policy: PolicyRecord) => (\n <Link key={policy.id} to={getPath(`policies/${policy.id}`)}>\n <Card className=\"h-full hover:border-primary/50 transition-colors cursor-pointer\">\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div\n className={`p-2 rounded-lg ${\n policy.type === 'CONTENT'\n ? 'bg-status-error-bg-subtle'\n : policy.type === 'TOOL'\n ? 'bg-status-info-bg-subtle'\n : policy.type === 'BUDGET'\n ? 'bg-status-warning-bg-subtle'\n : 'bg-action-primary-bg/10'\n }`}\n >\n <PolicyTypeIcon\n type={policy.type}\n className={`h-5 w-5 ${\n policy.type === 'CONTENT'\n ? 'text-status-error-text'\n : policy.type === 'TOOL'\n ? 'text-status-info-text'\n : policy.type === 'BUDGET'\n ? 'text-status-warning-text'\n : 'text-primary'\n }`}\n />\n </div>\n <div>\n <CardTitle className=\"text-base\">{policy.name}</CardTitle>\n </div>\n </div>\n <StatusBadge status={policy.status} />\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n <p className=\"text-sm text-text-secondary line-clamp-2\">\n {policy.description}\n </p>\n\n {/* Type Badge */}\n <div className=\"flex items-center justify-between\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {policyTypeLabel[policy.type]}\n </Badge>\n <span className=\"text-xs text-text-secondary\">\n {formatRelativeTime(policy.createdAt)}\n </span>\n </div>\n </div>\n </CardContent>\n </Card>\n </Link>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n title={\n selectedType\n ? t('botlit.policies.empty.titleNoType', 'No {{type}} policies', {\n type: policyTypeLabel[selectedType],\n })\n : t('botlit.policies.empty.title', 'No policies')\n }\n description={t(\n 'botlit.policies.empty.description',\n 'Create policies to enforce safety rules and operational limits across your agents.'\n )}\n action={\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.POLICY_CREATE}>\n <Button leftIcon={<Plus size={16} />}>\n <Link to={getPath('policies/new')}>\n {t('botlit.policies.actions.createPolicy', 'Create Policy')}\n </Link>\n </Button>\n </BotmanorPermissionGate>\n }\n />\n )}\n\n {/* Policy Types Guide */}\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <div className=\"mb-4\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary\">\n {t('botlit.policies.overview.title', 'Policy Types')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'botlit.policies.overview.description',\n 'Different policy types control different aspects of agent behavior'\n )}\n </p>\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4\">\n {[\n {\n type: 'CONTENT' as PolicyType,\n desc: t(\n 'botlit.policies.overview.contentDescription',\n 'Detect and block harmful content, jailbreaks, and PII'\n ),\n },\n {\n type: 'TOOL' as PolicyType,\n desc: t(\n 'botlit.policies.overview.toolDescription',\n 'Control which tools agents can access and use'\n ),\n },\n {\n type: 'BUDGET' as PolicyType,\n desc: t(\n 'botlit.policies.overview.budgetDescription',\n 'Set token limits and cost caps per execution'\n ),\n },\n {\n type: 'RATE_LIMIT' as PolicyType,\n desc: t(\n 'botlit.policies.overview.rateLimitDescription',\n 'Limit request frequency to prevent abuse'\n ),\n },\n ].map((item) => (\n <div key={item.type} className=\"p-4 border border-border-subtle rounded-lg\">\n <div className=\"flex items-center gap-2 mb-2\">\n <PolicyTypeIcon type={item.type} className=\"h-5 w-5 text-primary\" />\n <span className=\"font-medium\">{policyTypeLabel[item.type]}</span>\n </div>\n <p className=\"text-sm text-text-secondary\">{item.desc}</p>\n </div>\n ))}\n </div>\n </GlassCard>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}