@burdenoff/microfe-vibecontrols 2026.601.5 → 2026.601.6
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.
- package/dist/node_modules/@apollo/client/utilities/internal/getMainDefinition.js +17 -0
- package/dist/node_modules/@apollo/client/utilities/internal/getMainDefinition.js.map +1 -0
- package/dist/pages/AgentGraphPage.js +65 -65
- package/dist/pages/AgentGraphPage.js.map +1 -1
- package/dist/pages/TargetsPage.js +105 -92
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/VibeCalendarPage.js +2 -1
- package/dist/pages/VibeCalendarPage.js.map +1 -1
- package/dist/providers/VibeControlsProvider.js +147 -113
- package/dist/providers/VibeControlsProvider.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { newInvariantError as e } from "../invariant/index.js";
|
|
2
|
+
import { checkDocument as t } from "./checkDocument.js";
|
|
3
|
+
//#region node_modules/@apollo/client/utilities/internal/getMainDefinition.js
|
|
4
|
+
function n(n) {
|
|
5
|
+
t(n);
|
|
6
|
+
let r;
|
|
7
|
+
for (let e of n.definitions) {
|
|
8
|
+
if (e.kind === "OperationDefinition") return e;
|
|
9
|
+
e.kind === "FragmentDefinition" && !r && (r = e);
|
|
10
|
+
}
|
|
11
|
+
if (r) return r;
|
|
12
|
+
throw e(12);
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { n as getMainDefinition };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=getMainDefinition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getMainDefinition.js","names":[],"sources":["../../../../../../node_modules/@apollo/client/utilities/internal/getMainDefinition.js"],"sourcesContent":["import { newInvariantError } from \"@apollo/client/utilities/invariant\";\nimport { checkDocument } from \"./checkDocument.js\";\n/**\n * Returns the first operation definition from a GraphQL document. The function\n * prioritizes operation definitions over fragment definitions, which makes it\n * suitable for documents that may contain both. If no operation definition is\n * found, the first fragment definition will be returned. If no definitions are\n * found, an error is thrown.\n *\n * @remarks\n *\n * Use this function when you need to perform more advanced tasks with the main\n * definition AST node. If you want to determine when a document is a specific\n * operation type, prefer the `isQueryOperation`, `isMutationOperation`, and\n * `isSubscriptionOperation` utility functions instead.\n *\n * @param queryDoc - The GraphQL document to extract the definition from\n * @returns The main operation or fragment definition AST node\n *\n * @example\n *\n * ```ts\n * import { gql } from \"@apollo/client\";\n * import { getMainDefinition } from \"@apollo/client/utilities\";\n *\n * const query = gql`\n * query GetUser($id: ID!) {\n * user(id: $id) {\n * name\n * email\n * }\n * }\n * `;\n *\n * const definition = getMainDefinition(query);\n * ```\n *\n * @throws When the document contains no operation or fragment definitions\n */\nexport function getMainDefinition(queryDoc) {\n checkDocument(queryDoc);\n let fragmentDefinition;\n for (let definition of queryDoc.definitions) {\n if (definition.kind === \"OperationDefinition\") {\n return definition;\n }\n if (definition.kind === \"FragmentDefinition\" && !fragmentDefinition) {\n // we do this because we want to allow multiple fragment definitions\n // to precede an operation definition.\n fragmentDefinition = definition;\n }\n }\n if (fragmentDefinition) {\n return fragmentDefinition;\n }\n throw newInvariantError(12);\n}\n//# sourceMappingURL=getMainDefinition.js.map\n"],"x_google_ignoreList":[0],"mappings":";;;AAuCA,SAAgB,EAAkB,GAAU;AACxC,GAAc,EAAS;CACvB,IAAI;AACJ,MAAK,IAAI,KAAc,EAAS,aAAa;AACzC,MAAI,EAAW,SAAS,sBACpB,QAAO;AAEX,EAAI,EAAW,SAAS,wBAAwB,CAAC,MAG7C,IAAqB;;AAG7B,KAAI,EACA,QAAO;AAEX,OAAM,EAAkB,GAAG"}
|
|
@@ -6,26 +6,26 @@ import { LoadingState as c } from "../components/shared/LoadingState.js";
|
|
|
6
6
|
import { ErrorState as l } from "../components/shared/ErrorState.js";
|
|
7
7
|
import { EmptyState as u } from "../components/shared/EmptyState.js";
|
|
8
8
|
import { GetHelpButton as d } from "../components/shared/GetHelpButton.js";
|
|
9
|
-
import { SearchableSelect as
|
|
9
|
+
import { SearchableSelect as f } from "../components/shared/SearchableSelect.js";
|
|
10
10
|
import "../components/shared/index.js";
|
|
11
|
-
import { VIBE_PERMISSIONS as
|
|
11
|
+
import { VIBE_PERMISSIONS as ee } from "../constants/permissions.js";
|
|
12
12
|
import { AgentGraphView as p } from "../components/graph/AgentGraphView.js";
|
|
13
|
-
import { useCallback as m, useMemo as
|
|
14
|
-
import { useI18n as
|
|
15
|
-
import { GitBranch as
|
|
16
|
-
import { usePermissions as
|
|
17
|
-
import { Fragment as
|
|
18
|
-
import { MotionPage as
|
|
13
|
+
import { useCallback as m, useMemo as te, useState as h } from "react";
|
|
14
|
+
import { useI18n as g } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
15
|
+
import { GitBranch as _, Loader2 as v, Network as y } from "lucide-react";
|
|
16
|
+
import { usePermissions as b } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
17
|
+
import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
18
|
+
import { MotionPage as w } from "@burdenoff/fe-libs/shared/motion";
|
|
19
19
|
//#region src/pages/AgentGraphPage.tsx
|
|
20
|
-
function
|
|
21
|
-
let { workspaceId:
|
|
22
|
-
let r =
|
|
20
|
+
function T() {
|
|
21
|
+
let { workspaceId: T } = i(), E = a(), { t: D } = g(), { hasPermission: O, isLoading: k, permissions: A } = b(), [j, M] = h(null), N = m((e, t, n) => {
|
|
22
|
+
let r = D(e, n), i = r === e ? t : r;
|
|
23
23
|
return n ? Object.entries(n).reduce((e, [t, n]) => e.replace(`{{${t}}}`, String(n)), i) : i;
|
|
24
|
-
}, [
|
|
25
|
-
variables: { workspaceId:
|
|
26
|
-
skip: !
|
|
24
|
+
}, [D]), { agents: P } = o(), { data: F } = n({
|
|
25
|
+
variables: { workspaceId: T ?? "" },
|
|
26
|
+
skip: !T,
|
|
27
27
|
fetchPolicy: "cache-and-network"
|
|
28
|
-
}), I = F?.targets?.items ?? [], L =
|
|
28
|
+
}), I = F?.targets?.items ?? [], L = te(() => {
|
|
29
29
|
let e = P.map((e) => ({
|
|
30
30
|
value: e.id,
|
|
31
31
|
label: N("agentGraph.scopeAgentPrefix", "Agent: {{name}}", { name: e.name })
|
|
@@ -38,97 +38,97 @@ function E() {
|
|
|
38
38
|
P,
|
|
39
39
|
I,
|
|
40
40
|
N
|
|
41
|
-
]), [R, z] =
|
|
41
|
+
]), [R, z] = h(""), { data: B } = e({ skip: !T }), V = B?.agentConnectionConfig.permissions ?? [], H = B?.agentConnectionConfig.scopes ?? [], { data: U, previousData: W, loading: G, error: K, refetch: q } = t({
|
|
42
42
|
variables: {
|
|
43
|
-
workspaceId:
|
|
43
|
+
workspaceId: T || "",
|
|
44
44
|
rootAgentId: j || void 0
|
|
45
45
|
},
|
|
46
|
-
skip: !
|
|
47
|
-
}),
|
|
46
|
+
skip: !T
|
|
47
|
+
}), J = U?.agentGraph ?? W?.agentGraph, Y = J?.targets ?? [], X = J?.connections ?? [], Z = G, ne = Z && !J, Q = Z && !!J, [$] = r(), re = m((e, t) => {
|
|
48
48
|
if (e === "target") {
|
|
49
|
-
|
|
49
|
+
E(`/agents?${new URLSearchParams({
|
|
50
50
|
tab: "targets",
|
|
51
51
|
selectedTargetId: t
|
|
52
52
|
}).toString()}`);
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
}, [
|
|
57
|
-
$({ variables: {
|
|
55
|
+
E(`/agents/${t}`);
|
|
56
|
+
}, [E]), ie = m(async (e, t, n) => {
|
|
57
|
+
await $({ variables: {
|
|
58
58
|
connectionId: e,
|
|
59
59
|
input: {
|
|
60
60
|
permissions: t,
|
|
61
61
|
scopes: n
|
|
62
62
|
}
|
|
63
|
-
} });
|
|
64
|
-
}, [$]);
|
|
65
|
-
return
|
|
63
|
+
} }), await q();
|
|
64
|
+
}, [q, $]);
|
|
65
|
+
return k ? /* @__PURE__ */ S("div", {
|
|
66
66
|
className: "flex items-center justify-center min-h-[400px]",
|
|
67
|
-
children: /* @__PURE__ */
|
|
67
|
+
children: /* @__PURE__ */ S("p", {
|
|
68
68
|
className: "text-text-secondary",
|
|
69
69
|
children: "Loading permissions…"
|
|
70
70
|
})
|
|
71
|
-
}) : A && (A.permissionStrings?.length ?? 0) > 0 && !
|
|
71
|
+
}) : A && (A.permissionStrings?.length ?? 0) > 0 && !O(ee.AGENT_READ) ? /* @__PURE__ */ S("div", {
|
|
72
72
|
className: "flex items-center justify-center min-h-[400px]",
|
|
73
|
-
children: /* @__PURE__ */
|
|
73
|
+
children: /* @__PURE__ */ C("div", {
|
|
74
74
|
className: "text-center space-y-2",
|
|
75
|
-
children: [/* @__PURE__ */
|
|
75
|
+
children: [/* @__PURE__ */ S("h2", {
|
|
76
76
|
className: "text-lg font-semibold text-foreground",
|
|
77
77
|
children: "Access Denied"
|
|
78
|
-
}), /* @__PURE__ */
|
|
78
|
+
}), /* @__PURE__ */ S("p", {
|
|
79
79
|
className: "text-sm text-text-secondary",
|
|
80
80
|
children: "You don't have permission to access this page."
|
|
81
81
|
})]
|
|
82
82
|
})
|
|
83
|
-
}) : /* @__PURE__ */ w
|
|
84
|
-
/* @__PURE__ */
|
|
83
|
+
}) : /* @__PURE__ */ C(w, { children: [
|
|
84
|
+
/* @__PURE__ */ S(s, {
|
|
85
85
|
title: N("nav.agentGraph", "Agent Graph"),
|
|
86
86
|
description: N("agentGraph.description", "Visualize and manage connections between targets and agents.")
|
|
87
87
|
}),
|
|
88
|
-
|
|
89
|
-
!
|
|
88
|
+
ne && /* @__PURE__ */ S(c, { message: N("agentGraph.loading", "Loading agent graph...") }),
|
|
89
|
+
!Z && K && Y.length === 0 && /* @__PURE__ */ S(l, {
|
|
90
90
|
title: N("agentGraph.failedLoad", "Failed to load agent graph"),
|
|
91
91
|
message: K.message
|
|
92
92
|
}),
|
|
93
|
-
!
|
|
94
|
-
icon: /* @__PURE__ */
|
|
93
|
+
!Z && !K && Y.length === 0 && !R && /* @__PURE__ */ S(u, {
|
|
94
|
+
icon: /* @__PURE__ */ S(y, { className: "size-8 text-text-secondary" }),
|
|
95
95
|
title: N("agentGraph.noTargetsConnected", "No targets connected"),
|
|
96
96
|
description: N("agentGraph.noTargetsDescription", "Register an agent on a target to start visualizing your infrastructure topology."),
|
|
97
|
-
action: /* @__PURE__ */
|
|
97
|
+
action: /* @__PURE__ */ S(d, { prompt: "What is the Agent Graph in VibeControls and what does it show?" })
|
|
98
98
|
}),
|
|
99
|
-
(
|
|
100
|
-
/* @__PURE__ */
|
|
99
|
+
(Y.length > 0 || R || Q) && /* @__PURE__ */ C(x, { children: [
|
|
100
|
+
/* @__PURE__ */ C("div", {
|
|
101
101
|
className: "flex items-center gap-3 mt-4",
|
|
102
102
|
children: [
|
|
103
|
-
/* @__PURE__ */
|
|
103
|
+
/* @__PURE__ */ C("div", {
|
|
104
104
|
className: "flex items-center gap-2",
|
|
105
105
|
children: [
|
|
106
|
-
/* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ S(_, {
|
|
107
107
|
size: 16,
|
|
108
108
|
className: "text-text-tertiary"
|
|
109
109
|
}),
|
|
110
|
-
/* @__PURE__ */
|
|
110
|
+
/* @__PURE__ */ S("span", {
|
|
111
111
|
className: "text-sm font-medium text-text-secondary",
|
|
112
112
|
children: N("agentGraph.countSummary", "{{targets}} targets, {{connections}} connections", {
|
|
113
|
-
targets:
|
|
114
|
-
connections:
|
|
113
|
+
targets: Y.length,
|
|
114
|
+
connections: X.length
|
|
115
115
|
})
|
|
116
116
|
}),
|
|
117
|
-
Q && /* @__PURE__ */
|
|
117
|
+
Q && /* @__PURE__ */ C("span", {
|
|
118
118
|
role: "status",
|
|
119
119
|
"aria-live": "polite",
|
|
120
120
|
className: "inline-flex items-center gap-1.5 rounded-full border border-border-default bg-bg-surface px-2.5 py-1 text-xs font-medium text-text-secondary",
|
|
121
|
-
children: [/* @__PURE__ */
|
|
121
|
+
children: [/* @__PURE__ */ S(v, { className: "size-3.5 animate-spin text-action-primary-bg" }), N("agentGraph.refreshing", "Refreshing graph...")]
|
|
122
122
|
})
|
|
123
123
|
]
|
|
124
124
|
}),
|
|
125
|
-
/* @__PURE__ */
|
|
126
|
-
/* @__PURE__ */
|
|
125
|
+
/* @__PURE__ */ S("div", { className: "flex-1" }),
|
|
126
|
+
/* @__PURE__ */ C("div", {
|
|
127
127
|
className: "flex items-center gap-2",
|
|
128
|
-
children: [/* @__PURE__ */
|
|
128
|
+
children: [/* @__PURE__ */ S("label", {
|
|
129
129
|
className: "text-xs font-medium text-text-secondary",
|
|
130
130
|
children: N("agentGraph.scopeLabel", "Scope:")
|
|
131
|
-
}), /* @__PURE__ */
|
|
131
|
+
}), /* @__PURE__ */ S(f, {
|
|
132
132
|
value: R,
|
|
133
133
|
onChange: (e) => {
|
|
134
134
|
z(e), e.startsWith("target:") ? M(null) : M(e || null);
|
|
@@ -136,41 +136,41 @@ function E() {
|
|
|
136
136
|
options: L,
|
|
137
137
|
placeholder: N("agentGraph.scopeAll", "All targets & agents"),
|
|
138
138
|
clearable: !0,
|
|
139
|
-
disabled:
|
|
139
|
+
disabled: Z,
|
|
140
140
|
dropdownAlign: "right"
|
|
141
141
|
})]
|
|
142
142
|
})
|
|
143
143
|
]
|
|
144
144
|
}),
|
|
145
|
-
!
|
|
145
|
+
!Z && K && /* @__PURE__ */ S(l, {
|
|
146
146
|
title: N("agentGraph.failedRefresh", "Failed to refresh agent graph"),
|
|
147
147
|
message: K.message
|
|
148
148
|
}),
|
|
149
|
-
!
|
|
150
|
-
icon: /* @__PURE__ */
|
|
149
|
+
!Z && Y.length === 0 && R && /* @__PURE__ */ S(u, {
|
|
150
|
+
icon: /* @__PURE__ */ S(y, { className: "size-8 text-text-secondary" }),
|
|
151
151
|
title: N("agentGraph.noScopeResults", "No results for this scope"),
|
|
152
152
|
description: N("agentGraph.noScopeDescription", "No targets match the selected scope. Clear the filter to view all targets.")
|
|
153
153
|
}),
|
|
154
|
-
(
|
|
154
|
+
(Y.length > 0 || Q) && /* @__PURE__ */ C("div", {
|
|
155
155
|
className: "mt-4 relative",
|
|
156
156
|
style: {
|
|
157
157
|
height: "calc(100vh - 280px)",
|
|
158
158
|
minHeight: "400px"
|
|
159
159
|
},
|
|
160
160
|
"aria-busy": Q,
|
|
161
|
-
children: [/* @__PURE__ */
|
|
162
|
-
targets:
|
|
163
|
-
connections:
|
|
164
|
-
onUpdatePermissions:
|
|
161
|
+
children: [/* @__PURE__ */ S(p, {
|
|
162
|
+
targets: Y,
|
|
163
|
+
connections: X,
|
|
164
|
+
onUpdatePermissions: ie,
|
|
165
165
|
availablePermissions: V,
|
|
166
166
|
availableScopes: H,
|
|
167
|
-
onNodeClick:
|
|
167
|
+
onNodeClick: re,
|
|
168
168
|
fullHeight: !0
|
|
169
|
-
}), Q && /* @__PURE__ */
|
|
169
|
+
}), Q && /* @__PURE__ */ S("div", {
|
|
170
170
|
className: "absolute inset-0 z-10 flex items-center justify-center bg-bg-surface/60 backdrop-blur-[1px]",
|
|
171
|
-
children: /* @__PURE__ */
|
|
171
|
+
children: /* @__PURE__ */ C("div", {
|
|
172
172
|
className: "inline-flex items-center gap-2 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-secondary shadow-md",
|
|
173
|
-
children: [/* @__PURE__ */
|
|
173
|
+
children: [/* @__PURE__ */ S(v, { className: "size-4 animate-spin text-action-primary-bg" }), /* @__PURE__ */ S("span", { children: R ? N("agentGraph.loadingScope", "Applying selected scope...") : N("agentGraph.refreshing", "Refreshing graph...") })]
|
|
174
174
|
})
|
|
175
175
|
})]
|
|
176
176
|
})
|
|
@@ -178,6 +178,6 @@ function E() {
|
|
|
178
178
|
] });
|
|
179
179
|
}
|
|
180
180
|
//#endregion
|
|
181
|
-
export {
|
|
181
|
+
export { T as AgentGraphPage };
|
|
182
182
|
|
|
183
183
|
//# sourceMappingURL=AgentGraphPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentGraphPage.js","names":[],"sources":["../../src/pages/AgentGraphPage.tsx"],"sourcesContent":["/**\n * Agent Graph Page — Dedicated full-page view of the agent connection graph.\n *\n * Shows targets as group nodes with agents inside (sub-flows) and\n * connections as directed edges. Supports root-node scoping and\n * RBAC permission editing.\n */\n\nimport { useState, useMemo, useCallback } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport { GitBranch, Loader2, Network } from 'lucide-react';\nimport {\n PageHeader,\n SearchableSelect,\n LoadingState,\n ErrorState,\n EmptyState,\n GetHelpButton,\n} from '@/components/shared';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport {\n useGetAgentGraphQuery,\n useUpdateConnectionPermissionsMutation,\n useAgentConnectionConfigQuery,\n useListTargetsQuery,\n type ListTargetsQuery,\n} from '@/generated/wspace-operations';\n\ntype TargetItem = NonNullable<ListTargetsQuery['targets']['items'][number]>;\nimport { AgentGraphView } from '@/components/graph/AgentGraphView';\n\nexport function AgentGraphPage() {\n const { workspaceId } = useVibeControls();\n const navigate = useVibeNavigate();\n const { t } = useI18n();\n const { hasPermission, isLoading: permissionsLoading, permissions } = usePermissions();\n const [rootAgentId, setRootAgentId] = useState<string | null>(null);\n\n const tr = useCallback(\n (key: string, fallback: string, params?: Record<string, string | number>): string => {\n const translated = t(key, params);\n const template = translated === key ? fallback : translated;\n\n if (!params) return template;\n\n return Object.entries(params).reduce(\n (acc, [paramKey, paramValue]) => acc.replace(`{{${paramKey}}}`, String(paramValue)),\n template\n );\n },\n [t]\n );\n\n // Use cached initial data for agents; fetch targets directly\n const { agents: cachedAgents } = useCachedInitialData();\n const { data: targetsData } = useListTargetsQuery({\n variables: { workspaceId: workspaceId ?? '' },\n skip: !workspaceId,\n fetchPolicy: 'cache-and-network',\n });\n const cachedTargets = targetsData?.targets?.items ?? [];\n const scopeOptions = useMemo(() => {\n const agentOpts = cachedAgents.map((a) => ({\n value: a.id,\n label: tr('agentGraph.scopeAgentPrefix', 'Agent: {{name}}', { name: a.name }),\n }));\n const targetOpts = cachedTargets.map((tgt: TargetItem) => ({\n value: `target:${tgt.id}`,\n label: tr('agentGraph.scopeTargetPrefix', 'Target: {{name}}', { name: tgt.name }),\n }));\n return [...targetOpts, ...agentOpts];\n }, [cachedAgents, cachedTargets, tr]);\n\n const [scopeValue, setScopeValue] = useState<string>('');\n\n const { data: connectionConfigData } = useAgentConnectionConfigQuery({\n skip: !workspaceId,\n });\n\n const availablePermissions = connectionConfigData?.agentConnectionConfig.permissions ?? [];\n const availableScopes = connectionConfigData?.agentConnectionConfig.scopes ?? [];\n\n const {\n data: graphData,\n previousData,\n loading,\n error,\n } = useGetAgentGraphQuery({\n variables: {\n workspaceId: workspaceId || '',\n rootAgentId: rootAgentId || undefined,\n },\n skip: !workspaceId,\n });\n\n const resolvedAgentGraph = graphData?.agentGraph ?? previousData?.agentGraph;\n const graphTargets = resolvedAgentGraph?.targets ?? [];\n const graphConnections = resolvedAgentGraph?.connections ?? [];\n const isGraphLoading = loading;\n // Covers first load (including first scoped load) when no prior graph snapshot exists.\n const isInitialLoad = isGraphLoading && !resolvedAgentGraph;\n const isRefreshingGraph = isGraphLoading && Boolean(resolvedAgentGraph);\n\n const [updateConnectionPerms] = useUpdateConnectionPermissionsMutation();\n\n const handleNodeNavigate = useCallback(\n (nodeType: 'target' | 'agent', id: string) => {\n if (nodeType === 'target') {\n const targetParams = new URLSearchParams({\n tab: 'targets',\n selectedTargetId: id,\n });\n navigate(`/agents?${targetParams.toString()}`);\n return;\n }\n navigate(`/agents/${id}`);\n },\n [navigate]\n );\n\n const handleUpdatePermissions = useCallback(\n (connectionId: string, permissions: string[], scopes: string[]) => {\n void updateConnectionPerms({\n variables: { connectionId, input: { permissions, scopes } },\n });\n },\n [updateConnectionPerms]\n );\n\n if (permissionsLoading)\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <p className=\"text-text-secondary\">Loading permissions…</p>\n </div>\n );\n if (\n permissions &&\n (permissions.permissionStrings?.length ?? 0) > 0 &&\n !hasPermission(VIBE_PERMISSIONS.AGENT_READ)\n )\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">Access Denied</h2>\n <p className=\"text-sm text-text-secondary\">\n You don't have permission to access this page.\n </p>\n </div>\n </div>\n );\n\n return (\n <MotionPage>\n <PageHeader\n title={tr('nav.agentGraph', 'Agent Graph')}\n description={tr(\n 'agentGraph.description',\n 'Visualize and manage connections between targets and agents.'\n )}\n />\n\n {isInitialLoad && (\n <LoadingState message={tr('agentGraph.loading', 'Loading agent graph...')} />\n )}\n\n {/* Non-fatal error: show banner but don't hide graph if data is available */}\n {!isGraphLoading && error && graphTargets.length === 0 && (\n <ErrorState\n title={tr('agentGraph.failedLoad', 'Failed to load agent graph')}\n message={error.message}\n />\n )}\n\n {!isGraphLoading && !error && graphTargets.length === 0 && !scopeValue && (\n <EmptyState\n icon={<Network className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.noTargetsConnected', 'No targets connected')}\n description={tr(\n 'agentGraph.noTargetsDescription',\n 'Register an agent on a target to start visualizing your infrastructure topology.'\n )}\n action={\n <GetHelpButton prompt=\"What is the Agent Graph in VibeControls and what does it show?\" />\n }\n />\n )}\n\n {/* Scope controls + graph: shown whenever we have data, or when a scope filter is\n active (so the user can always clear the filter and recover the full view) */}\n {(graphTargets.length > 0 || scopeValue || isRefreshingGraph) && (\n <>\n {/* Filters — always rendered so user can clear an active scope filter */}\n <div className=\"flex items-center gap-3 mt-4\">\n <div className=\"flex items-center gap-2\">\n <GitBranch size={16} className=\"text-text-tertiary\" />\n <span className=\"text-sm font-medium text-text-secondary\">\n {tr('agentGraph.countSummary', '{{targets}} targets, {{connections}} connections', {\n targets: graphTargets.length,\n connections: graphConnections.length,\n })}\n </span>\n\n {isRefreshingGraph && (\n <span\n role=\"status\"\n aria-live=\"polite\"\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default bg-bg-surface px-2.5 py-1 text-xs font-medium text-text-secondary\"\n >\n <Loader2 className=\"size-3.5 animate-spin text-action-primary-bg\" />\n {tr('agentGraph.refreshing', 'Refreshing graph...')}\n </span>\n )}\n </div>\n <div className=\"flex-1\" />\n <div className=\"flex items-center gap-2\">\n <label className=\"text-xs font-medium text-text-secondary\">\n {tr('agentGraph.scopeLabel', 'Scope:')}\n </label>\n <SearchableSelect\n value={scopeValue}\n onChange={(v: string) => {\n setScopeValue(v);\n // If selecting a target, clear rootAgentId; if agent, set it\n if (v.startsWith('target:')) {\n setRootAgentId(null);\n } else {\n setRootAgentId(v || null);\n }\n }}\n options={scopeOptions}\n placeholder={tr('agentGraph.scopeAll', 'All targets & agents')}\n clearable\n disabled={isGraphLoading}\n dropdownAlign=\"right\"\n />\n </div>\n </div>\n\n {!isGraphLoading && error && (\n <ErrorState\n title={tr('agentGraph.failedRefresh', 'Failed to refresh agent graph')}\n message={error.message}\n />\n )}\n\n {!isGraphLoading && graphTargets.length === 0 && scopeValue && (\n <EmptyState\n icon={<Network className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.noScopeResults', 'No results for this scope')}\n description={tr(\n 'agentGraph.noScopeDescription',\n 'No targets match the selected scope. Clear the filter to view all targets.'\n )}\n />\n )}\n\n {(graphTargets.length > 0 || isRefreshingGraph) && (\n <div\n className=\"mt-4 relative\"\n style={{ height: 'calc(100vh - 280px)', minHeight: '400px' }}\n aria-busy={isRefreshingGraph}\n >\n <AgentGraphView\n targets={\n graphTargets as Array<{\n id: string;\n name: string;\n type: string;\n status: string;\n host?: string | null;\n agents: Array<{ id: string; name: string; version: string; isActive: boolean }>;\n }>\n }\n connections={\n graphConnections as Array<{\n id: string;\n protocol: string;\n status: string;\n permissions?: string[];\n scopes?: string[];\n label?: string | null;\n description?: string | null;\n sourceAgent: { id: string; name: string };\n target: { id: string; name: string; type: string };\n }>\n }\n onUpdatePermissions={handleUpdatePermissions}\n availablePermissions={availablePermissions}\n availableScopes={availableScopes}\n onNodeClick={handleNodeNavigate}\n fullHeight\n />\n {isRefreshingGraph && (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center bg-bg-surface/60 backdrop-blur-[1px]\">\n <div className=\"inline-flex items-center gap-2 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-secondary shadow-md\">\n <Loader2 className=\"size-4 animate-spin text-action-primary-bg\" />\n <span>\n {scopeValue\n ? tr('agentGraph.loadingScope', 'Applying selected scope...')\n : tr('agentGraph.refreshing', 'Refreshing graph...')}\n </span>\n </div>\n </div>\n )}\n </div>\n )}\n </>\n )}\n </MotionPage>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AgentGraphPage.js","names":[],"sources":["../../src/pages/AgentGraphPage.tsx"],"sourcesContent":["/**\n * Agent Graph Page — Dedicated full-page view of the agent connection graph.\n *\n * Shows targets as group nodes with agents inside (sub-flows) and\n * connections as directed edges. Supports root-node scoping and\n * RBAC permission editing.\n */\n\nimport { useState, useMemo, useCallback } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport { GitBranch, Loader2, Network } from 'lucide-react';\nimport {\n PageHeader,\n SearchableSelect,\n LoadingState,\n ErrorState,\n EmptyState,\n GetHelpButton,\n} from '@/components/shared';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport {\n useGetAgentGraphQuery,\n useUpdateConnectionPermissionsMutation,\n useAgentConnectionConfigQuery,\n useListTargetsQuery,\n type ListTargetsQuery,\n} from '@/generated/wspace-operations';\n\ntype TargetItem = NonNullable<ListTargetsQuery['targets']['items'][number]>;\nimport { AgentGraphView } from '@/components/graph/AgentGraphView';\n\nexport function AgentGraphPage() {\n const { workspaceId } = useVibeControls();\n const navigate = useVibeNavigate();\n const { t } = useI18n();\n const { hasPermission, isLoading: permissionsLoading, permissions } = usePermissions();\n const [rootAgentId, setRootAgentId] = useState<string | null>(null);\n\n const tr = useCallback(\n (key: string, fallback: string, params?: Record<string, string | number>): string => {\n const translated = t(key, params);\n const template = translated === key ? fallback : translated;\n\n if (!params) return template;\n\n return Object.entries(params).reduce(\n (acc, [paramKey, paramValue]) => acc.replace(`{{${paramKey}}}`, String(paramValue)),\n template\n );\n },\n [t]\n );\n\n // Use cached initial data for agents; fetch targets directly\n const { agents: cachedAgents } = useCachedInitialData();\n const { data: targetsData } = useListTargetsQuery({\n variables: { workspaceId: workspaceId ?? '' },\n skip: !workspaceId,\n fetchPolicy: 'cache-and-network',\n });\n const cachedTargets = targetsData?.targets?.items ?? [];\n const scopeOptions = useMemo(() => {\n const agentOpts = cachedAgents.map((a) => ({\n value: a.id,\n label: tr('agentGraph.scopeAgentPrefix', 'Agent: {{name}}', { name: a.name }),\n }));\n const targetOpts = cachedTargets.map((tgt: TargetItem) => ({\n value: `target:${tgt.id}`,\n label: tr('agentGraph.scopeTargetPrefix', 'Target: {{name}}', { name: tgt.name }),\n }));\n return [...targetOpts, ...agentOpts];\n }, [cachedAgents, cachedTargets, tr]);\n\n const [scopeValue, setScopeValue] = useState<string>('');\n\n const { data: connectionConfigData } = useAgentConnectionConfigQuery({\n skip: !workspaceId,\n });\n\n const availablePermissions = connectionConfigData?.agentConnectionConfig.permissions ?? [];\n const availableScopes = connectionConfigData?.agentConnectionConfig.scopes ?? [];\n\n const {\n data: graphData,\n previousData,\n loading,\n error,\n refetch,\n } = useGetAgentGraphQuery({\n variables: {\n workspaceId: workspaceId || '',\n rootAgentId: rootAgentId || undefined,\n },\n skip: !workspaceId,\n });\n\n const resolvedAgentGraph = graphData?.agentGraph ?? previousData?.agentGraph;\n const graphTargets = resolvedAgentGraph?.targets ?? [];\n const graphConnections = resolvedAgentGraph?.connections ?? [];\n const isGraphLoading = loading;\n // Covers first load (including first scoped load) when no prior graph snapshot exists.\n const isInitialLoad = isGraphLoading && !resolvedAgentGraph;\n const isRefreshingGraph = isGraphLoading && Boolean(resolvedAgentGraph);\n\n const [updateConnectionPerms] = useUpdateConnectionPermissionsMutation();\n\n const handleNodeNavigate = useCallback(\n (nodeType: 'target' | 'agent', id: string) => {\n if (nodeType === 'target') {\n const targetParams = new URLSearchParams({\n tab: 'targets',\n selectedTargetId: id,\n });\n navigate(`/agents?${targetParams.toString()}`);\n return;\n }\n navigate(`/agents/${id}`);\n },\n [navigate]\n );\n\n const handleUpdatePermissions = useCallback(\n async (connectionId: string, permissions: string[], scopes: string[]) => {\n await updateConnectionPerms({\n variables: { connectionId, input: { permissions, scopes } },\n });\n await refetch();\n },\n [refetch, updateConnectionPerms]\n );\n\n if (permissionsLoading)\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <p className=\"text-text-secondary\">Loading permissions…</p>\n </div>\n );\n if (\n permissions &&\n (permissions.permissionStrings?.length ?? 0) > 0 &&\n !hasPermission(VIBE_PERMISSIONS.AGENT_READ)\n )\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">Access Denied</h2>\n <p className=\"text-sm text-text-secondary\">\n You don't have permission to access this page.\n </p>\n </div>\n </div>\n );\n\n return (\n <MotionPage>\n <PageHeader\n title={tr('nav.agentGraph', 'Agent Graph')}\n description={tr(\n 'agentGraph.description',\n 'Visualize and manage connections between targets and agents.'\n )}\n />\n\n {isInitialLoad && (\n <LoadingState message={tr('agentGraph.loading', 'Loading agent graph...')} />\n )}\n\n {/* Non-fatal error: show banner but don't hide graph if data is available */}\n {!isGraphLoading && error && graphTargets.length === 0 && (\n <ErrorState\n title={tr('agentGraph.failedLoad', 'Failed to load agent graph')}\n message={error.message}\n />\n )}\n\n {!isGraphLoading && !error && graphTargets.length === 0 && !scopeValue && (\n <EmptyState\n icon={<Network className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.noTargetsConnected', 'No targets connected')}\n description={tr(\n 'agentGraph.noTargetsDescription',\n 'Register an agent on a target to start visualizing your infrastructure topology.'\n )}\n action={\n <GetHelpButton prompt=\"What is the Agent Graph in VibeControls and what does it show?\" />\n }\n />\n )}\n\n {/* Scope controls + graph: shown whenever we have data, or when a scope filter is\n active (so the user can always clear the filter and recover the full view) */}\n {(graphTargets.length > 0 || scopeValue || isRefreshingGraph) && (\n <>\n {/* Filters — always rendered so user can clear an active scope filter */}\n <div className=\"flex items-center gap-3 mt-4\">\n <div className=\"flex items-center gap-2\">\n <GitBranch size={16} className=\"text-text-tertiary\" />\n <span className=\"text-sm font-medium text-text-secondary\">\n {tr('agentGraph.countSummary', '{{targets}} targets, {{connections}} connections', {\n targets: graphTargets.length,\n connections: graphConnections.length,\n })}\n </span>\n\n {isRefreshingGraph && (\n <span\n role=\"status\"\n aria-live=\"polite\"\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default bg-bg-surface px-2.5 py-1 text-xs font-medium text-text-secondary\"\n >\n <Loader2 className=\"size-3.5 animate-spin text-action-primary-bg\" />\n {tr('agentGraph.refreshing', 'Refreshing graph...')}\n </span>\n )}\n </div>\n <div className=\"flex-1\" />\n <div className=\"flex items-center gap-2\">\n <label className=\"text-xs font-medium text-text-secondary\">\n {tr('agentGraph.scopeLabel', 'Scope:')}\n </label>\n <SearchableSelect\n value={scopeValue}\n onChange={(v: string) => {\n setScopeValue(v);\n // If selecting a target, clear rootAgentId; if agent, set it\n if (v.startsWith('target:')) {\n setRootAgentId(null);\n } else {\n setRootAgentId(v || null);\n }\n }}\n options={scopeOptions}\n placeholder={tr('agentGraph.scopeAll', 'All targets & agents')}\n clearable\n disabled={isGraphLoading}\n dropdownAlign=\"right\"\n />\n </div>\n </div>\n\n {!isGraphLoading && error && (\n <ErrorState\n title={tr('agentGraph.failedRefresh', 'Failed to refresh agent graph')}\n message={error.message}\n />\n )}\n\n {!isGraphLoading && graphTargets.length === 0 && scopeValue && (\n <EmptyState\n icon={<Network className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.noScopeResults', 'No results for this scope')}\n description={tr(\n 'agentGraph.noScopeDescription',\n 'No targets match the selected scope. Clear the filter to view all targets.'\n )}\n />\n )}\n\n {(graphTargets.length > 0 || isRefreshingGraph) && (\n <div\n className=\"mt-4 relative\"\n style={{ height: 'calc(100vh - 280px)', minHeight: '400px' }}\n aria-busy={isRefreshingGraph}\n >\n <AgentGraphView\n targets={\n graphTargets as Array<{\n id: string;\n name: string;\n type: string;\n status: string;\n host?: string | null;\n agents: Array<{ id: string; name: string; version: string; isActive: boolean }>;\n }>\n }\n connections={\n graphConnections as Array<{\n id: string;\n protocol: string;\n status: string;\n permissions?: string[];\n scopes?: string[];\n label?: string | null;\n description?: string | null;\n sourceAgent: { id: string; name: string };\n target: { id: string; name: string; type: string };\n }>\n }\n onUpdatePermissions={handleUpdatePermissions}\n availablePermissions={availablePermissions}\n availableScopes={availableScopes}\n onNodeClick={handleNodeNavigate}\n fullHeight\n />\n {isRefreshingGraph && (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center bg-bg-surface/60 backdrop-blur-[1px]\">\n <div className=\"inline-flex items-center gap-2 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-secondary shadow-md\">\n <Loader2 className=\"size-4 animate-spin text-action-primary-bg\" />\n <span>\n {scopeValue\n ? tr('agentGraph.loadingScope', 'Applying selected scope...')\n : tr('agentGraph.refreshing', 'Refreshing graph...')}\n </span>\n </div>\n </div>\n )}\n </div>\n )}\n </>\n )}\n </MotionPage>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,IAAiB;CAC/B,IAAM,EAAE,mBAAgB,GAAiB,EACnC,IAAW,GAAiB,EAC5B,EAAE,SAAM,GAAS,EACjB,EAAE,kBAAe,WAAW,GAAoB,mBAAgB,GAAgB,EAChF,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAE7D,IAAK,GACR,GAAa,GAAkB,MAAqD;EACnF,IAAM,IAAa,EAAE,GAAK,EAAO,EAC3B,IAAW,MAAe,IAAM,IAAW;AAIjD,SAFK,IAEE,OAAO,QAAQ,EAAO,CAAC,QAC3B,GAAK,CAAC,GAAU,OAAgB,EAAI,QAAQ,KAAK,EAAS,KAAK,OAAO,EAAW,CAAC,EACnF,EACD,GALmB;IAOtB,CAAC,EAAE,CACJ,EAGK,EAAE,QAAQ,MAAiB,GAAsB,EACjD,EAAE,MAAM,MAAgB,EAAoB;EAChD,WAAW,EAAE,aAAa,KAAe,IAAI;EAC7C,MAAM,CAAC;EACP,aAAa;EACd,CAAC,EACI,IAAgB,GAAa,SAAS,SAAS,EAAE,EACjD,IAAe,SAAc;EACjC,IAAM,IAAY,EAAa,KAAK,OAAO;GACzC,OAAO,EAAE;GACT,OAAO,EAAG,+BAA+B,mBAAmB,EAAE,MAAM,EAAE,MAAM,CAAC;GAC9E,EAAE;AAKH,SAAO,CAAC,GAJW,EAAc,KAAK,OAAqB;GACzD,OAAO,UAAU,EAAI;GACrB,OAAO,EAAG,gCAAgC,oBAAoB,EAAE,MAAM,EAAI,MAAM,CAAC;GAClF,EAAE,EACoB,GAAG,EAAU;IACnC;EAAC;EAAc;EAAe;EAAG,CAAC,EAE/B,CAAC,GAAY,KAAiB,EAAiB,GAAG,EAElD,EAAE,MAAM,MAAyB,EAA8B,EACnE,MAAM,CAAC,GACR,CAAC,EAEI,IAAuB,GAAsB,sBAAsB,eAAe,EAAE,EACpF,IAAkB,GAAsB,sBAAsB,UAAU,EAAE,EAE1E,EACJ,MAAM,GACN,iBACA,YACA,UACA,eACE,EAAsB;EACxB,WAAW;GACT,aAAa,KAAe;GAC5B,aAAa,KAAe,KAAA;GAC7B;EACD,MAAM,CAAC;EACR,CAAC,EAEI,IAAqB,GAAW,cAAc,GAAc,YAC5D,IAAe,GAAoB,WAAW,EAAE,EAChD,IAAmB,GAAoB,eAAe,EAAE,EACxD,IAAiB,GAEjB,KAAgB,KAAkB,CAAC,GACnC,IAAoB,KAAkB,EAAQ,GAE9C,CAAC,KAAyB,GAAwC,EAElE,KAAqB,GACxB,GAA8B,MAAe;AAC5C,MAAI,MAAa,UAAU;AAKzB,KAAS,WAJY,IAAI,gBAAgB;IACvC,KAAK;IACL,kBAAkB;IACnB,CAAC,CAC+B,UAAU,GAAG;AAC9C;;AAEF,IAAS,WAAW,IAAK;IAE3B,CAAC,EAAS,CACX,EAEK,KAA0B,EAC9B,OAAO,GAAsB,GAAuB,MAAqB;AAIvE,EAHA,MAAM,EAAsB,EAC1B,WAAW;GAAE;GAAc,OAAO;IAAE;IAAa;IAAQ;GAAE,EAC5D,CAAC,EACF,MAAM,GAAS;IAEjB,CAAC,GAAS,EAAsB,CACjC;AAwBD,QAtBI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,KAAD;GAAG,WAAU;aAAsB;GAAwB,CAAA;EACvD,CAAA,GAGR,MACC,EAAY,mBAAmB,UAAU,KAAK,KAC/C,CAAC,EAAc,GAAiB,WAAW,GAGzC,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,MAAD;IAAI,WAAU;cAAwC;IAAkB,CAAA,EACxE,kBAAC,KAAD;IAAG,WAAU;cAA8B;IAEvC,CAAA,CACA;;EACF,CAAA,GAIR,kBAAC,GAAD,EAAA,UAAA;EACE,kBAAC,GAAD;GACE,OAAO,EAAG,kBAAkB,cAAc;GAC1C,aAAa,EACX,0BACA,+DACD;GACD,CAAA;EAED,MACC,kBAAC,GAAD,EAAc,SAAS,EAAG,sBAAsB,yBAAyB,EAAI,CAAA;EAI9E,CAAC,KAAkB,KAAS,EAAa,WAAW,KACnD,kBAAC,GAAD;GACE,OAAO,EAAG,yBAAyB,6BAA6B;GAChE,SAAS,EAAM;GACf,CAAA;EAGH,CAAC,KAAkB,CAAC,KAAS,EAAa,WAAW,KAAK,CAAC,KAC1D,kBAAC,GAAD;GACE,MAAM,kBAAC,GAAD,EAAS,WAAU,8BAA+B,CAAA;GACxD,OAAO,EAAG,iCAAiC,uBAAuB;GAClE,aAAa,EACX,mCACA,mFACD;GACD,QACE,kBAAC,GAAD,EAAe,QAAO,kEAAmE,CAAA;GAE3F,CAAA;GAKF,EAAa,SAAS,KAAK,KAAc,MACzC,kBAAA,GAAA,EAAA,UAAA;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,GAAD;QAAW,MAAM;QAAI,WAAU;QAAuB,CAAA;OACtD,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAG,2BAA2B,oDAAoD;SACjF,SAAS,EAAa;SACtB,aAAa,EAAiB;SAC/B,CAAC;QACG,CAAA;OAEN,KACC,kBAAC,QAAD;QACE,MAAK;QACL,aAAU;QACV,WAAU;kBAHZ,CAKE,kBAAC,GAAD,EAAS,WAAU,gDAAiD,CAAA,EACnE,EAAG,yBAAyB,sBAAsB,CAC9C;;OAEL;;KACN,kBAAC,OAAD,EAAK,WAAU,UAAW,CAAA;KAC1B,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,SAAD;OAAO,WAAU;iBACd,EAAG,yBAAyB,SAAS;OAChC,CAAA,EACR,kBAAC,GAAD;OACE,OAAO;OACP,WAAW,MAAc;AAGvB,QAFA,EAAc,EAAE,EAEZ,EAAE,WAAW,UAAU,GACzB,EAAe,KAAK,GAEpB,EAAe,KAAK,KAAK;;OAG7B,SAAS;OACT,aAAa,EAAG,uBAAuB,uBAAuB;OAC9D,WAAA;OACA,UAAU;OACV,eAAc;OACd,CAAA,CACE;;KACF;;GAEL,CAAC,KAAkB,KAClB,kBAAC,GAAD;IACE,OAAO,EAAG,4BAA4B,gCAAgC;IACtE,SAAS,EAAM;IACf,CAAA;GAGH,CAAC,KAAkB,EAAa,WAAW,KAAK,KAC/C,kBAAC,GAAD;IACE,MAAM,kBAAC,GAAD,EAAS,WAAU,8BAA+B,CAAA;IACxD,OAAO,EAAG,6BAA6B,4BAA4B;IACnE,aAAa,EACX,iCACA,6EACD;IACD,CAAA;IAGF,EAAa,SAAS,KAAK,MAC3B,kBAAC,OAAD;IACE,WAAU;IACV,OAAO;KAAE,QAAQ;KAAuB,WAAW;KAAS;IAC5D,aAAW;cAHb,CAKE,kBAAC,GAAD;KACE,SACE;KASF,aACE;KAYF,qBAAqB;KACC;KACL;KACjB,aAAa;KACb,YAAA;KACA,CAAA,EACD,KACC,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAS,WAAU,8CAA+C,CAAA,EAClE,kBAAC,QAAD,EAAA,UACG,IACG,EAAG,2BAA2B,6BAA6B,GAC3D,EAAG,yBAAyB,sBAAsB,EACjD,CAAA,CACH;;KACF,CAAA,CAEJ;;GAEP,EAAA,CAAA;EAEM,EAAA,CAAA"}
|